claude-mpm 3.1.3__py3-none-any.whl → 3.3.0__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 (80) hide show
  1. claude_mpm/__init__.py +3 -3
  2. claude_mpm/__main__.py +0 -17
  3. claude_mpm/agents/INSTRUCTIONS.md +149 -17
  4. claude_mpm/agents/backups/INSTRUCTIONS.md +238 -0
  5. claude_mpm/agents/base_agent.json +1 -1
  6. claude_mpm/agents/templates/pm.json +25 -0
  7. claude_mpm/agents/templates/research.json +2 -1
  8. claude_mpm/cli/__init__.py +19 -23
  9. claude_mpm/cli/commands/__init__.py +3 -1
  10. claude_mpm/cli/commands/agents.py +7 -18
  11. claude_mpm/cli/commands/info.py +5 -10
  12. claude_mpm/cli/commands/memory.py +232 -0
  13. claude_mpm/cli/commands/run.py +501 -28
  14. claude_mpm/cli/commands/tickets.py +10 -17
  15. claude_mpm/cli/commands/ui.py +15 -37
  16. claude_mpm/cli/parser.py +91 -1
  17. claude_mpm/cli/utils.py +9 -28
  18. claude_mpm/config/socketio_config.py +256 -0
  19. claude_mpm/constants.py +9 -0
  20. claude_mpm/core/__init__.py +2 -2
  21. claude_mpm/core/agent_registry.py +4 -4
  22. claude_mpm/core/claude_runner.py +919 -0
  23. claude_mpm/core/config.py +21 -1
  24. claude_mpm/core/factories.py +1 -1
  25. claude_mpm/core/hook_manager.py +196 -0
  26. claude_mpm/core/pm_hook_interceptor.py +205 -0
  27. claude_mpm/core/service_registry.py +1 -1
  28. claude_mpm/core/simple_runner.py +323 -33
  29. claude_mpm/core/socketio_pool.py +582 -0
  30. claude_mpm/core/websocket_handler.py +233 -0
  31. claude_mpm/deployment_paths.py +261 -0
  32. claude_mpm/hooks/builtin/memory_hooks_example.py +67 -0
  33. claude_mpm/hooks/claude_hooks/hook_handler.py +667 -679
  34. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +9 -4
  35. claude_mpm/hooks/memory_integration_hook.py +312 -0
  36. claude_mpm/models/__init__.py +9 -91
  37. claude_mpm/orchestration/__init__.py +1 -1
  38. claude_mpm/scripts/claude-mpm-socketio +32 -0
  39. claude_mpm/scripts/claude_mpm_monitor.html +567 -0
  40. claude_mpm/scripts/install_socketio_server.py +407 -0
  41. claude_mpm/scripts/launch_monitor.py +132 -0
  42. claude_mpm/scripts/launch_socketio_dashboard.py +261 -0
  43. claude_mpm/scripts/manage_version.py +479 -0
  44. claude_mpm/scripts/socketio_daemon.py +181 -0
  45. claude_mpm/scripts/socketio_server_manager.py +428 -0
  46. claude_mpm/services/__init__.py +5 -0
  47. claude_mpm/services/agent_lifecycle_manager.py +76 -25
  48. claude_mpm/services/agent_memory_manager.py +684 -0
  49. claude_mpm/services/agent_modification_tracker.py +98 -17
  50. claude_mpm/services/agent_persistence_service.py +33 -13
  51. claude_mpm/services/agent_registry.py +82 -43
  52. claude_mpm/services/hook_service.py +362 -0
  53. claude_mpm/services/socketio_client_manager.py +474 -0
  54. claude_mpm/services/socketio_server.py +922 -0
  55. claude_mpm/services/standalone_socketio_server.py +631 -0
  56. claude_mpm/services/ticket_manager.py +4 -5
  57. claude_mpm/services/{ticket_manager_dependency_injection.py → ticket_manager_di.py} +12 -39
  58. claude_mpm/services/{legacy_ticketing_service.py → ticketing_service_original.py} +9 -16
  59. claude_mpm/services/version_control/semantic_versioning.py +9 -10
  60. claude_mpm/services/websocket_server.py +376 -0
  61. claude_mpm/utils/dependency_manager.py +211 -0
  62. claude_mpm/utils/import_migration_example.py +80 -0
  63. claude_mpm/utils/path_operations.py +0 -20
  64. claude_mpm/web/open_dashboard.py +34 -0
  65. {claude_mpm-3.1.3.dist-info → claude_mpm-3.3.0.dist-info}/METADATA +20 -9
  66. {claude_mpm-3.1.3.dist-info → claude_mpm-3.3.0.dist-info}/RECORD +71 -50
  67. claude_mpm-3.3.0.dist-info/entry_points.txt +7 -0
  68. claude_mpm/cli_old.py +0 -728
  69. claude_mpm/models/common.py +0 -41
  70. claude_mpm/models/lifecycle.py +0 -97
  71. claude_mpm/models/modification.py +0 -126
  72. claude_mpm/models/persistence.py +0 -57
  73. claude_mpm/models/registry.py +0 -91
  74. claude_mpm/security/__init__.py +0 -8
  75. claude_mpm/security/bash_validator.py +0 -393
  76. claude_mpm-3.1.3.dist-info/entry_points.txt +0 -4
  77. /claude_mpm/{cli_enhancements.py → experimental/cli_enhancements.py} +0 -0
  78. {claude_mpm-3.1.3.dist-info → claude_mpm-3.3.0.dist-info}/WHEEL +0 -0
  79. {claude_mpm-3.1.3.dist-info → claude_mpm-3.3.0.dist-info}/licenses/LICENSE +0 -0
  80. {claude_mpm-3.1.3.dist-info → claude_mpm-3.3.0.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,7 @@ WHY: This module provides terminal UI functionality for users who prefer a
5
5
  visual interface over command-line interaction.
6
6
  """
7
7
 
8
- from claude_mpm.utils.imports import safe_import
9
-
10
- # Import logger using safe_import pattern
11
- get_logger = safe_import('claude_mpm.core.logger', None, ['get_logger'])
8
+ from ...core.logger import get_logger
12
9
 
13
10
 
14
11
  def run_terminal_ui(args):
@@ -32,45 +29,26 @@ def run_terminal_ui(args):
32
29
 
33
30
  try:
34
31
  if ui_mode == 'terminal':
35
- # Try rich UI first using safe_import
36
- run_rich_ui = safe_import(
37
- '...ui.rich_terminal_ui',
38
- 'claude_mpm.ui.rich_terminal_ui',
39
- ['main']
40
- )
41
-
42
- if run_rich_ui:
32
+ # Try rich UI first
33
+ try:
34
+ from ...ui.rich_terminal_ui import main as run_rich_ui
43
35
  logger.info("Starting rich terminal UI...")
44
36
  run_rich_ui()
45
- else:
37
+ except ImportError:
46
38
  # Fallback to curses UI
47
39
  logger.info("Rich not available, falling back to curses UI...")
48
- TerminalUI = safe_import(
49
- '...ui.terminal_ui',
50
- 'claude_mpm.ui.terminal_ui',
51
- ['TerminalUI']
52
- )
53
- if TerminalUI:
54
- ui = TerminalUI()
55
- ui.run()
56
- else:
57
- logger.error("UI module not found")
58
- print("Error: Terminal UI requires 'curses' (built-in) or 'rich' (pip install rich)")
59
- return 1
60
- else:
61
- # Use curses UI explicitly
62
- TerminalUI = safe_import(
63
- '...ui.terminal_ui',
64
- 'claude_mpm.ui.terminal_ui',
65
- ['TerminalUI']
66
- )
67
- if TerminalUI:
40
+ from ...ui.terminal_ui import TerminalUI
68
41
  ui = TerminalUI()
69
42
  ui.run()
70
- else:
71
- logger.error("UI module not found")
72
- print("Error: Terminal UI not available")
73
- return 1
43
+ else:
44
+ # Use curses UI explicitly
45
+ from ...ui.terminal_ui import TerminalUI
46
+ ui = TerminalUI()
47
+ ui.run()
48
+ except ImportError as e:
49
+ logger.error(f"UI module not found: {e}")
50
+ print(f"Error: Terminal UI requires 'curses' (built-in) or 'rich' (pip install rich)")
51
+ return 1
74
52
  except Exception as e:
75
53
  logger.error(f"Error running terminal UI: {e}")
76
54
  print(f"Error: {e}")
claude_mpm/cli/parser.py CHANGED
@@ -14,7 +14,7 @@ import argparse
14
14
  from pathlib import Path
15
15
  from typing import Optional, List
16
16
 
17
- from ..constants import CLICommands, CLIPrefix, AgentCommands, LogLevel
17
+ from ..constants import CLICommands, CLIPrefix, AgentCommands, MemoryCommands, LogLevel
18
18
 
19
19
 
20
20
  def add_common_arguments(parser: argparse.ArgumentParser, version: str = None) -> None:
@@ -101,6 +101,24 @@ def add_run_arguments(parser: argparse.ArgumentParser) -> None:
101
101
  action="store_true",
102
102
  help="Disable deployment of Claude Code native agents"
103
103
  )
104
+ run_group.add_argument(
105
+ "--launch-method",
106
+ choices=["exec", "subprocess"],
107
+ default="exec",
108
+ help="Method to launch Claude: exec (replace process) or subprocess (child process)"
109
+ )
110
+ # Monitor options - consolidated monitoring and management interface
111
+ run_group.add_argument(
112
+ "--monitor",
113
+ action="store_true",
114
+ help="Enable monitoring and management interface with WebSocket server and dashboard (default port: 8765)"
115
+ )
116
+ run_group.add_argument(
117
+ "--websocket-port",
118
+ type=int,
119
+ default=8765,
120
+ help="WebSocket server port (default: 8765)"
121
+ )
104
122
 
105
123
  # Input/output options
106
124
  io_group = parser.add_argument_group('input/output options')
@@ -178,6 +196,24 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp
178
196
  action="store_true",
179
197
  help="Disable deployment of Claude Code native agents"
180
198
  )
199
+ run_group.add_argument(
200
+ "--launch-method",
201
+ choices=["exec", "subprocess"],
202
+ default="exec",
203
+ help="Method to launch Claude: exec (replace process) or subprocess (child process)"
204
+ )
205
+ # Monitor options - consolidated monitoring and management interface
206
+ run_group.add_argument(
207
+ "--monitor",
208
+ action="store_true",
209
+ help="Enable monitoring and management interface with WebSocket server and dashboard (default port: 8765)"
210
+ )
211
+ run_group.add_argument(
212
+ "--websocket-port",
213
+ type=int,
214
+ default=8765,
215
+ help="WebSocket server port (default: 8765)"
216
+ )
181
217
 
182
218
  # Input/output options
183
219
  io_group = parser.add_argument_group('input/output options (when no command specified)')
@@ -303,6 +339,60 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp
303
339
  help="Target directory (default: .claude/)"
304
340
  )
305
341
 
342
+ # Memory command with subcommands
343
+ memory_parser = subparsers.add_parser(
344
+ CLICommands.MEMORY.value,
345
+ help="Manage agent memory files"
346
+ )
347
+ add_common_arguments(memory_parser)
348
+
349
+ memory_subparsers = memory_parser.add_subparsers(
350
+ dest="memory_command",
351
+ help="Memory commands",
352
+ metavar="SUBCOMMAND"
353
+ )
354
+
355
+ # Status command
356
+ status_parser = memory_subparsers.add_parser(
357
+ MemoryCommands.STATUS.value,
358
+ help="Show memory file status"
359
+ )
360
+
361
+ # View command
362
+ view_parser = memory_subparsers.add_parser(
363
+ MemoryCommands.VIEW.value,
364
+ help="View agent memory file"
365
+ )
366
+ view_parser.add_argument(
367
+ "agent_id",
368
+ help="Agent ID to view memory for"
369
+ )
370
+
371
+ # Add command
372
+ add_parser = memory_subparsers.add_parser(
373
+ MemoryCommands.ADD.value,
374
+ help="Manually add learning to agent memory"
375
+ )
376
+ add_parser.add_argument(
377
+ "agent_id",
378
+ help="Agent ID to add learning to"
379
+ )
380
+ add_parser.add_argument(
381
+ "learning_type",
382
+ choices=["pattern", "error", "optimization", "preference", "context"],
383
+ help="Type of learning to add"
384
+ )
385
+ add_parser.add_argument(
386
+ "content",
387
+ help="Learning content to add"
388
+ )
389
+
390
+ # Clean command
391
+ clean_memory_parser = memory_subparsers.add_parser(
392
+ MemoryCommands.CLEAN.value,
393
+ help="Clean up old/unused memory files"
394
+ )
395
+
306
396
  return parser
307
397
 
308
398
 
claude_mpm/cli/utils.py CHANGED
@@ -10,10 +10,7 @@ import sys
10
10
  from pathlib import Path
11
11
  from typing import Optional
12
12
 
13
- from claude_mpm.utils.imports import safe_import
14
-
15
- # Import logger using safe_import pattern
16
- get_logger = safe_import('claude_mpm.core.logger', None, ['get_logger'])
13
+ from ..core.logger import get_logger
17
14
 
18
15
 
19
16
  def get_user_input(input_arg: Optional[str], logger) -> str:
@@ -62,17 +59,8 @@ def get_agent_versions_display() -> Optional[str]:
62
59
  Returns:
63
60
  Formatted string containing agent version information, or None if failed
64
61
  """
65
- # Import AgentDeploymentService using safe_import pattern
66
- AgentDeploymentService = safe_import(
67
- 'claude_mpm.services.agent_deployment',
68
- None,
69
- ['AgentDeploymentService']
70
- )
71
-
72
- if not AgentDeploymentService:
73
- return None
74
-
75
62
  try:
63
+ from ..services.agent_deployment import AgentDeploymentService
76
64
  deployment_service = AgentDeploymentService()
77
65
 
78
66
  # Get deployed agents
@@ -174,17 +162,10 @@ def ensure_directories() -> None:
174
162
  failing when they don't exist, we create them automatically for a better
175
163
  user experience.
176
164
  """
177
- # Import ensure_directories using safe_import pattern
178
- init_ensure_directories = safe_import(
179
- 'claude_mpm.init',
180
- None,
181
- ['ensure_directories']
182
- )
183
-
184
- if init_ensure_directories:
185
- try:
186
- init_ensure_directories()
187
- except Exception:
188
- # Continue even if initialization fails
189
- # The individual commands will handle missing directories as needed
190
- pass
165
+ try:
166
+ from ..init import ensure_directories as init_ensure_directories
167
+ init_ensure_directories()
168
+ except Exception:
169
+ # Continue even if initialization fails
170
+ # The individual commands will handle missing directories as needed
171
+ pass
@@ -0,0 +1,256 @@
1
+ """Socket.IO server configuration for different deployment scenarios.
2
+
3
+ This module provides configuration management for Socket.IO servers
4
+ across different deployment environments and installation methods.
5
+
6
+ WHY configuration management:
7
+ - Enables different settings for development vs production
8
+ - Supports multiple deployment scenarios (local, PyPI, Docker, etc.)
9
+ - Provides environment-specific defaults
10
+ - Allows runtime configuration overrides
11
+ """
12
+
13
+ import os
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+ from typing import Dict, Any, List, Optional
17
+
18
+
19
+ @dataclass
20
+ class SocketIOConfig:
21
+ """Configuration for Socket.IO server instances."""
22
+
23
+ # Server settings
24
+ host: str = "localhost"
25
+ port: int = 8765
26
+ server_id: Optional[str] = None
27
+
28
+ # Connection settings
29
+ cors_allowed_origins: str = "*" # Configure properly for production
30
+ ping_timeout: int = 60
31
+ ping_interval: int = 25
32
+ max_http_buffer_size: int = 1000000
33
+
34
+ # Compatibility settings
35
+ min_client_version: str = "0.7.0"
36
+ max_history_size: int = 10000
37
+
38
+ # Deployment settings
39
+ deployment_mode: str = "auto" # auto, standalone, embedded, client
40
+ auto_start: bool = True
41
+ persistent: bool = True
42
+
43
+ # Logging settings
44
+ log_level: str = "INFO"
45
+ log_to_file: bool = False
46
+ log_file_path: Optional[str] = None
47
+
48
+ # Health monitoring
49
+ health_check_interval: int = 30
50
+ max_connection_attempts: int = 3
51
+ reconnection_delay: int = 1
52
+
53
+ @classmethod
54
+ def from_env(cls) -> 'SocketIOConfig':
55
+ """Create configuration from environment variables."""
56
+ return cls(
57
+ host=os.getenv('CLAUDE_MPM_SOCKETIO_HOST', 'localhost'),
58
+ port=int(os.getenv('CLAUDE_MPM_SOCKETIO_PORT', '8765')),
59
+ server_id=os.getenv('CLAUDE_MPM_SOCKETIO_SERVER_ID'),
60
+ cors_allowed_origins=os.getenv('CLAUDE_MPM_SOCKETIO_CORS', '*'),
61
+ ping_timeout=int(os.getenv('CLAUDE_MPM_SOCKETIO_PING_TIMEOUT', '60')),
62
+ ping_interval=int(os.getenv('CLAUDE_MPM_SOCKETIO_PING_INTERVAL', '25')),
63
+ deployment_mode=os.getenv('CLAUDE_MPM_SOCKETIO_MODE', 'auto'),
64
+ auto_start=os.getenv('CLAUDE_MPM_SOCKETIO_AUTO_START', 'true').lower() == 'true',
65
+ persistent=os.getenv('CLAUDE_MPM_SOCKETIO_PERSISTENT', 'true').lower() == 'true',
66
+ log_level=os.getenv('CLAUDE_MPM_SOCKETIO_LOG_LEVEL', 'INFO'),
67
+ max_history_size=int(os.getenv('CLAUDE_MPM_SOCKETIO_HISTORY_SIZE', '10000'))
68
+ )
69
+
70
+ @classmethod
71
+ def for_development(cls) -> 'SocketIOConfig':
72
+ """Configuration optimized for development."""
73
+ return cls(
74
+ host="localhost",
75
+ port=8765,
76
+ deployment_mode="auto",
77
+ log_level="DEBUG",
78
+ ping_timeout=30,
79
+ ping_interval=10,
80
+ max_history_size=5000
81
+ )
82
+
83
+ @classmethod
84
+ def for_production(cls) -> 'SocketIOConfig':
85
+ """Configuration optimized for production."""
86
+ return cls(
87
+ host="0.0.0.0", # Bind to all interfaces in production
88
+ port=8765,
89
+ cors_allowed_origins="https://your-domain.com", # Restrict CORS
90
+ deployment_mode="standalone",
91
+ persistent=True,
92
+ log_level="INFO",
93
+ log_to_file=True,
94
+ log_file_path="/var/log/claude-mpm-socketio.log",
95
+ ping_timeout=120,
96
+ ping_interval=30,
97
+ max_history_size=20000
98
+ )
99
+
100
+ @classmethod
101
+ def for_docker(cls) -> 'SocketIOConfig':
102
+ """Configuration optimized for Docker deployment."""
103
+ return cls(
104
+ host="0.0.0.0",
105
+ port=8765,
106
+ deployment_mode="standalone",
107
+ persistent=True,
108
+ log_level="INFO",
109
+ ping_timeout=90,
110
+ ping_interval=25,
111
+ max_history_size=15000
112
+ )
113
+
114
+ def to_dict(self) -> Dict[str, Any]:
115
+ """Convert configuration to dictionary."""
116
+ return {
117
+ 'host': self.host,
118
+ 'port': self.port,
119
+ 'server_id': self.server_id,
120
+ 'cors_allowed_origins': self.cors_allowed_origins,
121
+ 'ping_timeout': self.ping_timeout,
122
+ 'ping_interval': self.ping_interval,
123
+ 'max_http_buffer_size': self.max_http_buffer_size,
124
+ 'min_client_version': self.min_client_version,
125
+ 'max_history_size': self.max_history_size,
126
+ 'deployment_mode': self.deployment_mode,
127
+ 'auto_start': self.auto_start,
128
+ 'persistent': self.persistent,
129
+ 'log_level': self.log_level,
130
+ 'log_to_file': self.log_to_file,
131
+ 'log_file_path': self.log_file_path,
132
+ 'health_check_interval': self.health_check_interval,
133
+ 'max_connection_attempts': self.max_connection_attempts,
134
+ 'reconnection_delay': self.reconnection_delay
135
+ }
136
+
137
+
138
+ class ConfigManager:
139
+ """Manages Socket.IO configuration across different environments."""
140
+
141
+ def __init__(self):
142
+ self.config_file_name = "socketio_config.json"
143
+ self.config_search_paths = [
144
+ Path.cwd() / self.config_file_name, # Current directory
145
+ Path.home() / ".claude-mpm" / self.config_file_name, # User home
146
+ Path("/etc/claude-mpm") / self.config_file_name, # System config
147
+ ]
148
+
149
+ def detect_environment(self) -> str:
150
+ """Detect the current deployment environment."""
151
+ # Check for Docker
152
+ if os.path.exists('/.dockerenv') or os.getenv('DOCKER_CONTAINER'):
153
+ return "docker"
154
+
155
+ # Check for production indicators
156
+ if os.getenv('ENVIRONMENT') == 'production' or os.getenv('NODE_ENV') == 'production':
157
+ return "production"
158
+
159
+ # Check if running from installed package
160
+ try:
161
+ import claude_mpm
162
+ pkg_path = Path(claude_mpm.__file__).parent
163
+ if 'site-packages' in str(pkg_path) or 'dist-packages' in str(pkg_path):
164
+ return "installed"
165
+ except ImportError:
166
+ pass
167
+
168
+ # Default to development
169
+ return "development"
170
+
171
+ def get_config(self, environment: str = None) -> SocketIOConfig:
172
+ """Get configuration for the specified environment."""
173
+ if environment is None:
174
+ environment = self.detect_environment()
175
+
176
+ # Start with environment-specific defaults
177
+ if environment == "production":
178
+ config = SocketIOConfig.for_production()
179
+ elif environment == "docker":
180
+ config = SocketIOConfig.for_docker()
181
+ elif environment == "development":
182
+ config = SocketIOConfig.for_development()
183
+ else:
184
+ config = SocketIOConfig()
185
+
186
+ # Override with environment variables
187
+ env_config = SocketIOConfig.from_env()
188
+ for field in config.__dataclass_fields__:
189
+ env_value = getattr(env_config, field)
190
+ if env_value != getattr(SocketIOConfig(), field): # Only if different from default
191
+ setattr(config, field, env_value)
192
+
193
+ # Override with config file if available
194
+ config_file_data = self._load_config_file()
195
+ if config_file_data:
196
+ for key, value in config_file_data.items():
197
+ if hasattr(config, key):
198
+ setattr(config, key, value)
199
+
200
+ return config
201
+
202
+ def _load_config_file(self) -> Optional[Dict[str, Any]]:
203
+ """Load configuration from file if available."""
204
+ import json
205
+
206
+ for config_path in self.config_search_paths:
207
+ if config_path.exists():
208
+ try:
209
+ with open(config_path, 'r') as f:
210
+ return json.load(f)
211
+ except Exception as e:
212
+ print(f"Warning: Failed to load config from {config_path}: {e}")
213
+
214
+ return None
215
+
216
+ def save_config(self, config: SocketIOConfig, path: str = None) -> bool:
217
+ """Save configuration to file."""
218
+ import json
219
+
220
+ if path is None:
221
+ # Use user config directory
222
+ config_dir = Path.home() / ".claude-mpm"
223
+ config_dir.mkdir(exist_ok=True)
224
+ path = config_dir / self.config_file_name
225
+
226
+ try:
227
+ with open(path, 'w') as f:
228
+ json.dump(config.to_dict(), f, indent=2)
229
+ return True
230
+ except Exception as e:
231
+ print(f"Error saving config to {path}: {e}")
232
+ return False
233
+
234
+
235
+ # Global configuration manager instance
236
+ _config_manager = ConfigManager()
237
+
238
+
239
+ def get_config(environment: str = None) -> SocketIOConfig:
240
+ """Get Socket.IO configuration for the current or specified environment."""
241
+ return _config_manager.get_config(environment)
242
+
243
+
244
+ def get_server_ports(config: SocketIOConfig) -> List[int]:
245
+ """Get list of ports to try for server discovery."""
246
+ base_port = config.port
247
+ return [base_port, base_port + 1, base_port + 2, base_port + 3, base_port + 4]
248
+
249
+
250
+ def get_discovery_hosts(config: SocketIOConfig) -> List[str]:
251
+ """Get list of hosts to try for server discovery."""
252
+ if config.host == "0.0.0.0":
253
+ # If server binds to all interfaces, try localhost and 127.0.0.1 for discovery
254
+ return ["localhost", "127.0.0.1"]
255
+ else:
256
+ return [config.host, "localhost", "127.0.0.1"]
claude_mpm/constants.py CHANGED
@@ -27,6 +27,7 @@ class CLICommands(str, Enum):
27
27
  INFO = "info"
28
28
  AGENTS = "agents"
29
29
  UI = "ui"
30
+ MEMORY = "memory"
30
31
 
31
32
  def with_prefix(self, prefix: CLIPrefix = CLIPrefix.MPM) -> str:
32
33
  """Get command with prefix."""
@@ -55,6 +56,14 @@ class AgentCommands(str, Enum):
55
56
  CLEAN = "clean"
56
57
 
57
58
 
59
+ class MemoryCommands(str, Enum):
60
+ """Memory subcommand constants."""
61
+ STATUS = "status"
62
+ VIEW = "view"
63
+ ADD = "add"
64
+ CLEAN = "clean"
65
+
66
+
58
67
  class CLIFlags(str, Enum):
59
68
  """CLI flag constants (without prefix)."""
60
69
  # Logging flags
@@ -1,6 +1,6 @@
1
1
  """Core components for Claude MPM."""
2
2
 
3
- from .simple_runner import SimpleClaudeRunner
3
+ from .claude_runner import ClaudeRunner
4
4
  from .mixins import LoggerMixin
5
5
 
6
6
  # Import config components if needed
@@ -24,7 +24,7 @@ except ImportError:
24
24
  pass
25
25
 
26
26
  __all__ = [
27
- "SimpleClaudeRunner",
27
+ "ClaudeRunner",
28
28
  "LoggerMixin",
29
29
  "Config",
30
30
  "ConfigAliases",
@@ -20,10 +20,10 @@ import importlib.util
20
20
  from datetime import datetime
21
21
  from dataclasses import dataclass
22
22
 
23
- from claude_mpm.utils.imports import safe_import
24
-
25
- # Import logger using safe_import pattern
26
- get_logger = safe_import('claude_mpm.core.logger', None, ['get_logger'])
23
+ try:
24
+ from ..core.logger import get_logger
25
+ except ImportError:
26
+ from core.logger import get_logger
27
27
 
28
28
 
29
29
  @dataclass