claude-mpm 3.1.3__py3-none-any.whl → 3.2.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 (79) hide show
  1. claude_mpm/__init__.py +3 -3
  2. claude_mpm/__main__.py +0 -17
  3. claude_mpm/agents/INSTRUCTIONS.md +81 -18
  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/manage_version.py +479 -0
  43. claude_mpm/scripts/socketio_daemon.py +181 -0
  44. claude_mpm/scripts/socketio_server_manager.py +428 -0
  45. claude_mpm/services/__init__.py +5 -0
  46. claude_mpm/services/agent_lifecycle_manager.py +76 -25
  47. claude_mpm/services/agent_memory_manager.py +684 -0
  48. claude_mpm/services/agent_modification_tracker.py +98 -17
  49. claude_mpm/services/agent_persistence_service.py +33 -13
  50. claude_mpm/services/agent_registry.py +82 -43
  51. claude_mpm/services/hook_service.py +362 -0
  52. claude_mpm/services/socketio_client_manager.py +474 -0
  53. claude_mpm/services/socketio_server.py +698 -0
  54. claude_mpm/services/standalone_socketio_server.py +631 -0
  55. claude_mpm/services/ticket_manager.py +4 -5
  56. claude_mpm/services/{ticket_manager_dependency_injection.py → ticket_manager_di.py} +12 -39
  57. claude_mpm/services/{legacy_ticketing_service.py → ticketing_service_original.py} +9 -16
  58. claude_mpm/services/version_control/semantic_versioning.py +9 -10
  59. claude_mpm/services/websocket_server.py +376 -0
  60. claude_mpm/utils/dependency_manager.py +211 -0
  61. claude_mpm/utils/import_migration_example.py +80 -0
  62. claude_mpm/utils/path_operations.py +0 -20
  63. claude_mpm/web/open_dashboard.py +34 -0
  64. {claude_mpm-3.1.3.dist-info → claude_mpm-3.2.1.dist-info}/METADATA +20 -9
  65. {claude_mpm-3.1.3.dist-info → claude_mpm-3.2.1.dist-info}/RECORD +70 -50
  66. claude_mpm-3.2.1.dist-info/entry_points.txt +7 -0
  67. claude_mpm/cli_old.py +0 -728
  68. claude_mpm/models/common.py +0 -41
  69. claude_mpm/models/lifecycle.py +0 -97
  70. claude_mpm/models/modification.py +0 -126
  71. claude_mpm/models/persistence.py +0 -57
  72. claude_mpm/models/registry.py +0 -91
  73. claude_mpm/security/__init__.py +0 -8
  74. claude_mpm/security/bash_validator.py +0 -393
  75. claude_mpm-3.1.3.dist-info/entry_points.txt +0 -4
  76. /claude_mpm/{cli_enhancements.py → experimental/cli_enhancements.py} +0 -0
  77. {claude_mpm-3.1.3.dist-info → claude_mpm-3.2.1.dist-info}/WHEEL +0 -0
  78. {claude_mpm-3.1.3.dist-info → claude_mpm-3.2.1.dist-info}/licenses/LICENSE +0 -0
  79. {claude_mpm-3.1.3.dist-info → claude_mpm-3.2.1.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
2
2
  # Claude Code hook wrapper for claude-mpm
3
3
 
4
4
  # Debug log (optional - comment out in production)
5
- # echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Wrapper called with args: $@" >> /tmp/hook-wrapper.log
5
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Wrapper called with args: $@" >> /tmp/hook-wrapper.log
6
6
 
7
7
  # Get the directory where this script is located
8
8
  SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
@@ -39,9 +39,14 @@ if [[ " $* " =~ " --logging DEBUG " ]] || [[ " $* " =~ " --debug " ]]; then
39
39
  export CLAUDE_MPM_LOG_LEVEL="DEBUG"
40
40
  fi
41
41
 
42
+ # Set Socket.IO configuration for hook events
43
+ export CLAUDE_MPM_SOCKETIO_PORT="8765"
44
+ export CLAUDE_MPM_HOOK_DEBUG="true"
45
+
42
46
  # Debug log (optional)
43
- # echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] PYTHONPATH: $PYTHONPATH" >> /tmp/hook-wrapper.log
44
- # echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Running: $PYTHON_CMD $SCRIPT_DIR/hook_handler.py" >> /tmp/hook-wrapper.log
47
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] PYTHONPATH: $PYTHONPATH" >> /tmp/hook-wrapper.log
48
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] Running: $PYTHON_CMD $SCRIPT_DIR/hook_handler.py" >> /tmp/hook-wrapper.log
49
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)] SOCKETIO_PORT: $CLAUDE_MPM_SOCKETIO_PORT" >> /tmp/hook-wrapper.log
45
50
 
46
- # Run the Python hook handler
51
+ # Run the Python hook handler (now optimized by default)
47
52
  exec "$PYTHON_CMD" "$SCRIPT_DIR/hook_handler.py" "$@"
@@ -0,0 +1,312 @@
1
+ """Memory integration hooks for automatic agent memory management.
2
+
3
+ WHY: Agents need to accumulate project-specific knowledge over time. These hooks
4
+ automatically inject agent memory before delegation and extract learnings after,
5
+ enabling agents to become more effective through experience.
6
+
7
+ DESIGN DECISION: We use explicit markers to extract structured learnings from
8
+ agent outputs because:
9
+ - It gives agents explicit control over what gets memorized
10
+ - The format is clear and unambiguous
11
+ - It's more reliable than pattern matching
12
+ - Agents can add multiple learnings in a single response
13
+ """
14
+
15
+ import re
16
+ from typing import Dict, Any, List
17
+ from claude_mpm.hooks.base_hook import PreDelegationHook, PostDelegationHook, HookContext, HookResult
18
+ from claude_mpm.services.agent_memory_manager import AgentMemoryManager
19
+ from claude_mpm.services.socketio_server import get_socketio_server
20
+ from claude_mpm.core.config import Config
21
+ from claude_mpm.core.logger import get_logger
22
+
23
+ logger = get_logger(__name__)
24
+
25
+
26
+ class MemoryPreDelegationHook(PreDelegationHook):
27
+ """Inject agent memory into delegation context.
28
+
29
+ WHY: Agents perform better when they have access to accumulated project knowledge.
30
+ This hook loads agent-specific memory and adds it to the delegation context,
31
+ allowing agents to apply learned patterns and avoid known mistakes.
32
+
33
+ DESIGN DECISION: Memory is injected as a clearly formatted section in the context
34
+ to ensure agents understand it's their accumulated knowledge, not current task info.
35
+ """
36
+
37
+ def __init__(self, config: Config = None):
38
+ """Initialize with optional config.
39
+
40
+ Args:
41
+ config: Optional Config object. If not provided, will create default Config.
42
+ """
43
+ super().__init__(name="memory_pre_delegation", priority=20)
44
+ self.config = config or Config()
45
+ self.memory_manager = AgentMemoryManager(self.config)
46
+
47
+ def execute(self, context: HookContext) -> HookResult:
48
+ """Add agent memory to delegation context.
49
+
50
+ WHY: By loading memory before delegation, agents can reference their
51
+ accumulated knowledge when performing tasks, leading to better outcomes.
52
+ """
53
+ try:
54
+ # Extract and normalize agent ID from context
55
+ agent_name = context.data.get('agent', '')
56
+ if not agent_name:
57
+ return HookResult(success=True, data=context.data, modified=False)
58
+
59
+ # Normalize agent ID (e.g., "Engineer Agent" -> "engineer")
60
+ agent_id = agent_name.lower().replace(' ', '_').replace('_agent', '').replace('agent', '').strip('_')
61
+
62
+ if agent_id:
63
+ # Load agent memory
64
+ memory_content = self.memory_manager.load_agent_memory(agent_id)
65
+
66
+ if memory_content and memory_content.strip():
67
+ # Get existing context data
68
+ delegation_context = context.data.get('context', {})
69
+ if isinstance(delegation_context, str):
70
+ # If context is a string, convert to dict
71
+ delegation_context = {'prompt': delegation_context}
72
+
73
+ # Add memory with clear formatting
74
+ memory_section = f"""
75
+ AGENT MEMORY - PROJECT-SPECIFIC KNOWLEDGE:
76
+ {memory_content}
77
+
78
+ INSTRUCTIONS: Review your memory above before proceeding. Apply learned patterns and avoid known mistakes.
79
+ """
80
+
81
+ # Add to context
82
+ delegation_context['agent_memory'] = memory_section
83
+
84
+ # Update the context data
85
+ updated_data = context.data.copy()
86
+ updated_data['context'] = delegation_context
87
+
88
+ logger.info(f"Injected memory for agent '{agent_id}'")
89
+
90
+ # Emit Socket.IO event for memory injected
91
+ try:
92
+ socketio_server = get_socketio_server()
93
+ # Calculate size of injected content
94
+ injected_size = len(memory_section.encode('utf-8'))
95
+ socketio_server.memory_injected(agent_id, injected_size)
96
+ except Exception as ws_error:
97
+ logger.debug(f"Socket.IO notification failed: {ws_error}")
98
+
99
+ return HookResult(
100
+ success=True,
101
+ data=updated_data,
102
+ modified=True,
103
+ metadata={'memory_injected': True, 'agent_id': agent_id}
104
+ )
105
+
106
+ return HookResult(success=True, data=context.data, modified=False)
107
+
108
+ except Exception as e:
109
+ logger.error(f"Memory injection failed: {e}")
110
+ # Don't fail the delegation if memory injection fails
111
+ return HookResult(
112
+ success=True,
113
+ data=context.data,
114
+ modified=False,
115
+ error=f"Memory injection failed: {str(e)}"
116
+ )
117
+
118
+
119
+ class MemoryPostDelegationHook(PostDelegationHook):
120
+ """Extract learnings from delegation results using explicit markers.
121
+
122
+ WHY: Agents produce valuable insights during task execution. This hook
123
+ extracts structured learnings from their outputs using explicit markers,
124
+ building up project-specific knowledge over time.
125
+
126
+ DESIGN DECISION: We use explicit markers to give agents full control over
127
+ what gets memorized. This is more reliable than pattern matching and allows
128
+ multiple learnings per response. Supports multiple trigger phrases for flexibility.
129
+
130
+ Supported formats:
131
+ # Add To Memory:
132
+ Type: pattern
133
+ Content: All services use dependency injection for flexibility
134
+ #
135
+
136
+ # Memorize:
137
+ Type: guideline
138
+ Content: Always validate input parameters before processing
139
+ #
140
+
141
+ # Remember:
142
+ Type: mistake
143
+ Content: Never hardcode configuration values
144
+ #
145
+ """
146
+
147
+ def __init__(self, config: Config = None):
148
+ """Initialize with optional config.
149
+
150
+ Args:
151
+ config: Optional Config object. If not provided, will create default Config.
152
+ """
153
+ super().__init__(name="memory_post_delegation", priority=80)
154
+ self.config = config or Config()
155
+ self.memory_manager = AgentMemoryManager(self.config)
156
+
157
+ # Map of supported types to memory sections
158
+ self.type_mapping = {
159
+ 'pattern': 'pattern', # Coding Patterns Learned
160
+ 'architecture': 'architecture', # Project Architecture
161
+ 'guideline': 'guideline', # Implementation Guidelines
162
+ 'mistake': 'mistake', # Common Mistakes to Avoid
163
+ 'strategy': 'strategy', # Effective Strategies
164
+ 'integration': 'integration', # Integration Points
165
+ 'performance': 'performance', # Performance Considerations
166
+ 'context': 'context' # Current Technical Context
167
+ }
168
+
169
+ def execute(self, context: HookContext) -> HookResult:
170
+ """Extract and store learnings from delegation result.
171
+
172
+ WHY: Capturing learnings immediately after task completion ensures we
173
+ don't lose valuable insights that agents discover during execution.
174
+ """
175
+ try:
176
+ # Check if auto-learning is enabled
177
+ if not self.config.get('memory.auto_learning', False):
178
+ return HookResult(success=True, data=context.data, modified=False)
179
+
180
+ # Extract agent ID
181
+ agent_name = context.data.get('agent', '')
182
+ if not agent_name:
183
+ return HookResult(success=True, data=context.data, modified=False)
184
+
185
+ # Normalize agent ID
186
+ agent_id = agent_name.lower().replace(' ', '_').replace('_agent', '').replace('agent', '').strip('_')
187
+
188
+ # Check if auto-learning is enabled for this specific agent
189
+ agent_overrides = self.config.get('memory.agent_overrides', {})
190
+ agent_config = agent_overrides.get(agent_id, {})
191
+ if 'auto_learning' in agent_config and not agent_config['auto_learning']:
192
+ return HookResult(success=True, data=context.data, modified=False)
193
+
194
+ # Extract result content
195
+ result = context.data.get('result', {})
196
+ if isinstance(result, dict):
197
+ result_text = result.get('content', '') or str(result)
198
+ else:
199
+ result_text = str(result)
200
+
201
+ if agent_id and result_text:
202
+ # Extract learnings using patterns
203
+ learnings = self._extract_learnings(result_text)
204
+
205
+ # Store each learning
206
+ learnings_stored = 0
207
+ for learning_type, items in learnings.items():
208
+ for item in items:
209
+ try:
210
+ self.memory_manager.add_learning(agent_id, learning_type, item)
211
+ learnings_stored += 1
212
+ except Exception as e:
213
+ logger.warning(f"Failed to store learning: {e}")
214
+
215
+ if learnings_stored > 0:
216
+ logger.info(f"Extracted {learnings_stored} learnings for agent '{agent_id}'")
217
+
218
+ return HookResult(
219
+ success=True,
220
+ data=context.data,
221
+ modified=False,
222
+ metadata={
223
+ 'learnings_extracted': learnings_stored,
224
+ 'agent_id': agent_id
225
+ }
226
+ )
227
+
228
+ return HookResult(success=True, data=context.data, modified=False)
229
+
230
+ except Exception as e:
231
+ logger.error(f"Learning extraction failed: {e}")
232
+ # Don't fail the delegation result if learning extraction fails
233
+ return HookResult(
234
+ success=True,
235
+ data=context.data,
236
+ modified=False,
237
+ error=f"Learning extraction failed: {str(e)}"
238
+ )
239
+
240
+ def _extract_learnings(self, text: str) -> Dict[str, List[str]]:
241
+ """Extract structured learnings from text using explicit markers.
242
+
243
+ WHY: We limit learnings to 100 characters to keep memory entries
244
+ concise and actionable. Longer entries tend to be less useful as
245
+ quick reference points.
246
+
247
+ DESIGN DECISION: Using explicit markers gives agents full control and makes
248
+ extraction reliable. We support multiple memory additions in a single response
249
+ and multiple trigger phrases (Add To Memory, Memorize, Remember) for flexibility.
250
+
251
+ Args:
252
+ text: The text to extract learnings from
253
+
254
+ Returns:
255
+ Dictionary mapping learning types to lists of extracted learnings
256
+ """
257
+ learnings = {learning_type: [] for learning_type in self.type_mapping.keys()}
258
+ seen_learnings = set() # Avoid duplicates
259
+
260
+ # Pattern to find memory blocks with multiple trigger phrases
261
+ # Matches: # Add To Memory: / # Memorize: / # Remember:\n...\n#
262
+ # Only matches complete blocks with proper closing markers
263
+ memory_pattern = r'#\s*(?:Add\s+To\s+Memory|Memorize|Remember):\s*\n((?:[^#](?:[^#]|#(?!\s*(?:Add\s+To\s+Memory|Memorize|Remember):))*?)?)\n\s*#\s*$'
264
+ matches = re.finditer(memory_pattern, text, re.MULTILINE | re.DOTALL | re.IGNORECASE)
265
+
266
+ for match in matches:
267
+ block_content = match.group(1).strip()
268
+ logger.debug(f"Found memory block: {block_content[:50]}...")
269
+
270
+ # Extract type and content from the block
271
+ type_match = re.search(r'Type:\s*(\w+)', block_content, re.IGNORECASE)
272
+ content_match = re.search(r'Content:\s*(.+)', block_content, re.IGNORECASE | re.DOTALL)
273
+
274
+ if type_match and content_match:
275
+ learning_type = type_match.group(1).lower().strip()
276
+ content = content_match.group(1).strip()
277
+
278
+ # Clean up multi-line content - take first line if multiple
279
+ if '\n' in content:
280
+ content = content.split('\n')[0].strip()
281
+
282
+ # Remove trailing punctuation
283
+ content = content.rstrip('.!?,;')
284
+
285
+ # Validate type is supported
286
+ if learning_type in self.type_mapping:
287
+ # Check content length (between 5 and 100 characters)
288
+ if content and 5 < len(content) <= 100:
289
+ # Normalize for duplicate detection
290
+ normalized = content.lower()
291
+ if normalized not in seen_learnings:
292
+ learnings[learning_type].append(content)
293
+ seen_learnings.add(normalized)
294
+ logger.debug(f"Extracted learning - Type: {learning_type}, Content: {content}")
295
+ else:
296
+ logger.debug(f"Skipping duplicate learning: {content}")
297
+ else:
298
+ logger.debug(f"Skipping learning - invalid length ({len(content)}): {content}")
299
+ else:
300
+ logger.warning(f"Unsupported learning type: {learning_type}. Supported types: {list(self.type_mapping.keys())}")
301
+ else:
302
+ logger.debug(f"Invalid memory block format - missing Type or Content")
303
+
304
+ # Log summary of extracted learnings
305
+ total_learnings = sum(len(items) for items in learnings.values())
306
+ if total_learnings > 0:
307
+ logger.info(f"Extracted {total_learnings} learnings from agent response")
308
+ for learning_type, items in learnings.items():
309
+ if items:
310
+ logger.debug(f" {learning_type}: {len(items)} items")
311
+
312
+ return learnings
@@ -1,106 +1,24 @@
1
1
  """
2
- Claude MPM Models Package
3
- =========================
2
+ Agent models package.
4
3
 
5
- Centralized data models for the Claude MPM system.
6
-
7
- WHY: This package centralizes all data models to:
8
- - Prevent circular imports
9
- - Reduce code duplication
10
- - Ensure consistent data structures
11
- - Make models easily discoverable
12
-
13
- DESIGN DECISION: Models are organized by domain:
14
- - agent_definition: Core agent behavior models
15
- - lifecycle: Agent lifecycle management models
16
- - modification: Change tracking models
17
- - persistence: Storage operation models
18
- - registry: Discovery and management models
19
- - common: Shared constants and enums
4
+ WHY: This package centralizes all data models used for agent management,
5
+ providing a single source of truth for data structures across the system.
20
6
  """
21
7
 
22
- # Agent definition models
23
8
  from .agent_definition import (
9
+ AgentDefinition,
10
+ AgentMetadata,
24
11
  AgentType,
25
12
  AgentSection,
26
- AgentPermissions,
27
13
  AgentWorkflow,
28
- AgentMetadata,
29
- AgentDefinition
30
- )
31
-
32
- # Lifecycle models
33
- from .lifecycle import (
34
- LifecycleOperation,
35
- LifecycleState,
36
- AgentLifecycleRecord,
37
- LifecycleOperationResult
38
- )
39
-
40
- # Modification models
41
- from .modification import (
42
- ModificationType,
43
- ModificationTier,
44
- AgentModification,
45
- ModificationHistory
46
- )
47
-
48
- # Persistence models
49
- from .persistence import (
50
- PersistenceStrategy,
51
- PersistenceOperation,
52
- PersistenceRecord
53
- )
54
-
55
- # Registry models
56
- from .registry import (
57
- AgentTier,
58
- AgentRegistryMetadata
59
- )
60
-
61
- # Common constants
62
- from .common import (
63
- AGENT_FILE_EXTENSIONS,
64
- AGENT_IGNORE_PATTERNS,
65
- CORE_AGENT_TYPES,
66
- SPECIALIZED_AGENT_TYPES,
67
- ALL_AGENT_TYPES
14
+ AgentPermissions
68
15
  )
69
16
 
70
17
  __all__ = [
71
- # Agent definition
18
+ 'AgentDefinition',
19
+ 'AgentMetadata',
72
20
  'AgentType',
73
21
  'AgentSection',
74
- 'AgentPermissions',
75
22
  'AgentWorkflow',
76
- 'AgentMetadata',
77
- 'AgentDefinition',
78
-
79
- # Lifecycle
80
- 'LifecycleOperation',
81
- 'LifecycleState',
82
- 'AgentLifecycleRecord',
83
- 'LifecycleOperationResult',
84
-
85
- # Modification
86
- 'ModificationType',
87
- 'ModificationTier',
88
- 'AgentModification',
89
- 'ModificationHistory',
90
-
91
- # Persistence
92
- 'PersistenceStrategy',
93
- 'PersistenceOperation',
94
- 'PersistenceRecord',
95
-
96
- # Registry
97
- 'AgentTier',
98
- 'AgentRegistryMetadata',
99
-
100
- # Common
101
- 'AGENT_FILE_EXTENSIONS',
102
- 'AGENT_IGNORE_PATTERNS',
103
- 'CORE_AGENT_TYPES',
104
- 'SPECIALIZED_AGENT_TYPES',
105
- 'ALL_AGENT_TYPES'
23
+ 'AgentPermissions'
106
24
  ]
@@ -1,6 +1,6 @@
1
1
  """Orchestration components for Claude MPM (legacy)."""
2
2
 
3
- # Most orchestration components have been simplified and moved to core.simple_runner
3
+ # Most orchestration components have been simplified and moved to core.claude_runner
4
4
  # This module is kept for backwards compatibility
5
5
 
6
6
  __all__ = []
@@ -0,0 +1,32 @@
1
+ #!/bin/bash
2
+ # Wrapper script for Socket.IO server daemon management.
3
+ #
4
+ # This script provides a simple command-line interface for managing
5
+ # the Socket.IO server daemon that powers the monitoring dashboard.
6
+ #
7
+ # Usage:
8
+ # claude-mpm-socketio start - Start the server daemon
9
+ # claude-mpm-socketio stop - Stop the server daemon
10
+ # claude-mpm-socketio restart - Restart the server daemon
11
+ # claude-mpm-socketio status - Check server status
12
+
13
+ # Get the directory where this script is located
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+
16
+ # Path to the Python daemon script
17
+ DAEMON_SCRIPT="${SCRIPT_DIR}/socketio_daemon.py"
18
+
19
+ # Check if the daemon script exists
20
+ if [ ! -f "$DAEMON_SCRIPT" ]; then
21
+ echo "Error: Socket.IO daemon script not found at $DAEMON_SCRIPT"
22
+ exit 1
23
+ fi
24
+
25
+ # Check if Python is available
26
+ if ! command -v python3 &> /dev/null; then
27
+ echo "Error: Python 3 is required but not found"
28
+ exit 1
29
+ fi
30
+
31
+ # Execute the Python daemon with all arguments
32
+ exec python3 "$DAEMON_SCRIPT" "$@"