claude-mpm 3.2.1__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.
@@ -13,8 +13,77 @@ You are **Claude Multi-Agent Project Manager (claude-mpm)** - your **SOLE functi
13
13
 
14
14
  **ABSOLUTE RULE**: ALL other work must be delegated to specialized agents via Task Tool.
15
15
 
16
- **BEHAVIOR RULES**:
17
- - **Response** always respond in a balanced fashion, avoid sycophancy. Never use "You're absolutely right" or overly solicitous phrases. Simple acknowledgement or agreement is sufficient
16
+ ## BEHAVIOR RULES
17
+
18
+ ### Professional Communication Standards
19
+ **Maintain neutral, professional tone as default** - avoid overeager enthusiasm that undermines credibility.
20
+
21
+ ### Prohibited Overeager Phrases
22
+ **NEVER use these excessive responses**:
23
+ - "You're absolutely right!" / "Absolutely!"
24
+ - "Excellent!" / "Perfect!" / "Brilliant!" / "Amazing!" / "Fantastic!"
25
+ - "Great idea!" / "Wonderful suggestion!" / "Outstanding!"
26
+ - "That's incredible!" / "Genius!" / "Superb!"
27
+ - Other overly enthusiastic or sycophantic responses
28
+
29
+ ### Appropriate Acknowledgments
30
+ **Use neutral, professional acknowledgments**:
31
+ - "Understood" / "I see" / "Acknowledged" / "Noted"
32
+ - "Yes" / "Correct" / "That's accurate" / "Confirmed"
33
+ - "I'll proceed with that approach" / "That makes sense"
34
+
35
+ ### Context-Sensitive Tone Guidelines
36
+ - **Default**: Professional neutrality for all interactions
37
+ - **Match urgency**: Respond appropriately to critical/time-sensitive requests
38
+ - **Reserve enthusiasm**: Only for genuinely exceptional achievements or milestones
39
+ - **Technical discussions**: Focus on accuracy and precision over emotional responses
40
+
41
+ ### Response Examples
42
+
43
+ **Bad Examples**:
44
+ ```
45
+ ❌ "You're absolutely right! That's a brilliant approach!"
46
+ ❌ "Excellent suggestion! This is going to be amazing!"
47
+ ❌ "Perfect! I love this idea - it's fantastic!"
48
+ ```
49
+
50
+ **Good Examples**:
51
+ ```
52
+ ✅ "Understood. I'll implement that approach."
53
+ ✅ "That's accurate. Proceeding with the research phase."
54
+ ✅ "Confirmed. This aligns with the project requirements."
55
+ ```
56
+
57
+ ### Production-Ready Implementation Standards
58
+ **PROHIBITED without explicit user instruction**:
59
+ - **Fallback to simpler solutions**: Never downgrade requirements or reduce scope
60
+ - **Mock implementations**: Never use mocks, stubs, or placeholder implementations outside test environments
61
+
62
+ **Why this matters**:
63
+ - Production systems require complete, robust implementations
64
+ - Simplified solutions create technical debt and security vulnerabilities
65
+ - Mock implementations mask integration issues and business logic gaps
66
+
67
+ **What NOT to do**:
68
+ ```
69
+ ❌ "I'll create a simple version first and we can enhance it later"
70
+ ❌ "Let me mock the database connection for now"
71
+ ❌ "I'll use a placeholder API call instead of the real implementation"
72
+ ❌ "This simplified approach should work for most cases"
73
+ ```
74
+
75
+ **What TO do instead**:
76
+ ```
77
+ ✅ "I need to research the full requirements before implementing"
78
+ ✅ "Let me analyze the production constraints and dependencies"
79
+ ✅ "I'll implement the complete solution including error handling"
80
+ ✅ "This requires integration with the actual database/API"
81
+ ```
82
+
83
+ **When simplification IS appropriate**:
84
+ - User explicitly requests: "make this simpler", "create a basic version", "prototype this"
85
+ - User explicitly authorizes: "use mocks for now", "skip error handling for this demo"
86
+ - Test environments: Unit tests, integration tests, development fixtures
18
87
 
19
88
 
20
89
  ## Memory Management
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env python3
2
+ """Socket.IO Dashboard Launcher for Claude MPM.
3
+
4
+ WHY: This script provides a streamlined solution for launching the Socket.IO
5
+ monitoring dashboard using only the Python Socket.IO server implementation.
6
+ It handles server startup, dashboard creation, and browser opening.
7
+
8
+ DESIGN DECISION: Uses only python-socketio and aiohttp for a clean,
9
+ Node.js-free implementation. This simplifies deployment and reduces
10
+ dependencies while maintaining full functionality.
11
+
12
+ The script handles:
13
+ 1. Python Socket.IO server startup
14
+ 2. Dashboard HTML creation and serving
15
+ 3. Browser opening with proper URL construction
16
+ 4. Background/daemon mode operation
17
+ 5. Graceful error handling and user feedback
18
+ """
19
+
20
+ import argparse
21
+ import os
22
+ import sys
23
+ import time
24
+ import webbrowser
25
+ import signal
26
+ from pathlib import Path
27
+ from typing import Optional
28
+
29
+ # Get script directory for relative paths
30
+ SCRIPT_DIR = Path(__file__).parent
31
+ PROJECT_ROOT = SCRIPT_DIR.parent.parent.parent # Go up to project root from src/claude_mpm/scripts/
32
+
33
+ def check_python_dependencies() -> bool:
34
+ """Check if Python Socket.IO dependencies are available.
35
+
36
+ WHY: We need python-socketio and aiohttp packages for the server.
37
+ This function validates the environment and provides clear feedback.
38
+
39
+ Returns:
40
+ bool: True if Python dependencies are ready, False otherwise
41
+ """
42
+ try:
43
+ import socketio
44
+ import aiohttp
45
+ socketio_version = getattr(socketio, '__version__', 'unknown')
46
+ aiohttp_version = getattr(aiohttp, '__version__', 'unknown')
47
+ print(f"✓ python-socketio v{socketio_version} detected")
48
+ print(f"✓ aiohttp v{aiohttp_version} detected")
49
+ return True
50
+ except ImportError as e:
51
+ print(f"❌ Required Python packages missing: {e}")
52
+ print(" Install with: pip install python-socketio aiohttp")
53
+ return False
54
+
55
+
56
+
57
+ def check_dashboard_availability(port: int):
58
+ """Check if the modular dashboard is available.
59
+
60
+ WHY: The new architecture uses a modular dashboard served by the Socket.IO server
61
+ instead of creating static HTML files. This validates the proper dashboard exists.
62
+
63
+ Args:
64
+ port: Port number for the Socket.IO server
65
+ """
66
+ # Check if new modular dashboard is available
67
+ web_templates_dir = PROJECT_ROOT / "src" / "claude_mpm" / "web" / "templates"
68
+ modular_dashboard = web_templates_dir / "index.html"
69
+ if modular_dashboard.exists():
70
+ print(f"✓ Modular dashboard found at {modular_dashboard}")
71
+ return True
72
+ else:
73
+ print(f"⚠️ Modular dashboard not found at {modular_dashboard}")
74
+ print(f" Expected path: {modular_dashboard}")
75
+ return False
76
+
77
+ def check_server_running(port: int) -> bool:
78
+ """Check if a Socket.IO server is already running on the specified port.
79
+
80
+ WHY: We want to avoid starting multiple servers on the same port
81
+ and provide clear feedback to users about existing servers.
82
+
83
+ Args:
84
+ port: Port number to check
85
+
86
+ Returns:
87
+ bool: True if server is running, False otherwise
88
+ """
89
+ try:
90
+ import socket
91
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
92
+ s.settimeout(1)
93
+ result = s.connect_ex(('127.0.0.1', port))
94
+ if result == 0:
95
+ print(f"✓ Socket.IO server already running on port {port}")
96
+ return True
97
+ except Exception:
98
+ pass
99
+
100
+ return False
101
+
102
+ def start_python_server(port: int, daemon: bool = False) -> Optional:
103
+ """Start the Python Socket.IO server.
104
+
105
+ WHY: Uses python-socketio and aiohttp for a clean, Node.js-free
106
+ implementation that handles all Socket.IO functionality.
107
+
108
+ Args:
109
+ port: Port number for the server
110
+ daemon: Whether to run in background mode
111
+
112
+ Returns:
113
+ Thread object if successful, None otherwise
114
+ """
115
+ try:
116
+ # Import the existing Python Socket.IO server
117
+ sys.path.insert(0, str(PROJECT_ROOT / "src"))
118
+ from claude_mpm.services.socketio_server import SocketIOServer
119
+
120
+ server = SocketIOServer(port=port)
121
+
122
+ if daemon:
123
+ # Start in background thread
124
+ server.start()
125
+ print(f"🚀 Python Socket.IO server started on port {port}")
126
+ return server.thread
127
+ else:
128
+ # Start and block
129
+ print(f"🚀 Starting Python Socket.IO server on port {port}")
130
+ server.start()
131
+
132
+ # Keep alive until interrupted
133
+ try:
134
+ while server.running:
135
+ time.sleep(1)
136
+ except KeyboardInterrupt:
137
+ print("\\n🛑 Shutting down Python server...")
138
+ server.stop()
139
+
140
+ return None
141
+
142
+ except Exception as e:
143
+ print(f"❌ Failed to start Python server: {e}")
144
+ return None
145
+
146
+ def open_dashboard(port: int, no_browser: bool = False):
147
+ """Open the Socket.IO dashboard in browser.
148
+
149
+ WHY: Users need easy access to the monitoring dashboard. This function
150
+ handles URL construction and browser opening with fallback options.
151
+ Now uses the new modular dashboard location.
152
+
153
+ Args:
154
+ port: Port number for the Socket.IO server
155
+ no_browser: Skip browser opening if True
156
+ """
157
+ if no_browser:
158
+ print(f"📊 Dashboard available at: http://localhost:{port}/dashboard")
159
+ return
160
+
161
+ dashboard_url = f"http://localhost:{port}/dashboard?autoconnect=true&port={port}"
162
+
163
+ try:
164
+ print(f"🌐 Opening dashboard: {dashboard_url}")
165
+ webbrowser.open(dashboard_url)
166
+
167
+ except Exception as e:
168
+ print(f"⚠️ Failed to open browser automatically: {e}")
169
+ print(f"📊 Dashboard: {dashboard_url}")
170
+
171
+ def cleanup_handler(signum, frame):
172
+ """Handle cleanup on shutdown signals.
173
+
174
+ WHY: Proper cleanup ensures sockets are closed and resources freed
175
+ when the script is terminated.
176
+ """
177
+ print("\\n🛑 Shutting down Socket.IO launcher...")
178
+ sys.exit(0)
179
+
180
+ def main():
181
+ """Main entry point for the Socket.IO dashboard launcher.
182
+
183
+ WHY: This orchestrates the entire launch process, from dependency checking
184
+ to server startup and dashboard opening, with comprehensive error handling.
185
+ """
186
+ parser = argparse.ArgumentParser(
187
+ description="Launch Socket.IO dashboard for Claude MPM monitoring",
188
+ formatter_class=argparse.RawDescriptionHelpFormatter,
189
+ epilog='''
190
+ Examples:
191
+ python launch_socketio_dashboard.py # Start with default settings
192
+ python launch_socketio_dashboard.py --port 3000 # Use specific port
193
+ python launch_socketio_dashboard.py --daemon # Run in background
194
+ python launch_socketio_dashboard.py --no-browser # Don't open browser
195
+ python launch_socketio_dashboard.py --setup-only # Just create files
196
+ '''
197
+ )
198
+
199
+ parser.add_argument('--port', type=int, default=3000,
200
+ help='Socket.IO server port (default: 3000)')
201
+ parser.add_argument('--daemon', action='store_true',
202
+ help='Run server in background mode')
203
+ parser.add_argument('--no-browser', action='store_true',
204
+ help='Skip opening browser automatically')
205
+ parser.add_argument('--setup-only', action='store_true',
206
+ help='Create necessary files without starting server')
207
+
208
+ args = parser.parse_args()
209
+
210
+ # Setup signal handlers
211
+ signal.signal(signal.SIGINT, cleanup_handler)
212
+ signal.signal(signal.SIGTERM, cleanup_handler)
213
+
214
+ print("🚀 Claude MPM Socket.IO Dashboard Launcher")
215
+ print("=" * 50)
216
+
217
+ # Check dashboard availability (modular dashboard)
218
+ check_dashboard_availability(args.port)
219
+
220
+ if args.setup_only:
221
+ # Just setup files, don't start server
222
+ print("📁 Setup complete - files created")
223
+ return
224
+
225
+ # Check if server is already running
226
+ if check_server_running(args.port):
227
+ print(f"✅ Using existing server on port {args.port}")
228
+ open_dashboard(args.port, args.no_browser)
229
+ return
230
+
231
+ # Check Python dependencies
232
+ if not check_python_dependencies():
233
+ print("❌ Required Python packages not available")
234
+ sys.exit(1)
235
+
236
+ # Start Python Socket.IO server
237
+ print("🟢 Using Python Socket.IO server")
238
+
239
+ try:
240
+ server_thread = start_python_server(args.port, args.daemon)
241
+
242
+ if server_thread or not args.daemon:
243
+ # Server started or is starting
244
+ time.sleep(2) # Give server time to start
245
+ open_dashboard(args.port, args.no_browser)
246
+
247
+ if args.daemon and server_thread:
248
+ print(f"🔄 Python server running in background")
249
+ print(f" Dashboard: http://localhost:{args.port}/dashboard")
250
+ else:
251
+ print("❌ Failed to start Socket.IO server")
252
+ sys.exit(1)
253
+
254
+ except KeyboardInterrupt:
255
+ print("\\n✅ Socket.IO launcher stopped")
256
+ except Exception as e:
257
+ print(f"❌ Launcher error: {e}")
258
+ sys.exit(1)
259
+
260
+ if __name__ == "__main__":
261
+ main()
@@ -257,6 +257,16 @@ class SocketIOServer:
257
257
  # Add HTTP routes
258
258
  self.app.router.add_get('/health', self._handle_health)
259
259
  self.app.router.add_get('/status', self._handle_health)
260
+ self.app.router.add_get('/api/git-diff', self._handle_git_diff)
261
+
262
+ # Add dashboard routes
263
+ self.app.router.add_get('/', self._handle_dashboard)
264
+ self.app.router.add_get('/dashboard', self._handle_dashboard)
265
+
266
+ # Add static file serving for web assets
267
+ static_path = get_project_root() / 'src' / 'claude_mpm' / 'web' / 'static'
268
+ if static_path.exists():
269
+ self.app.router.add_static('/static/', path=str(static_path), name='static')
260
270
 
261
271
  # Register event handlers
262
272
  self._register_events()
@@ -301,6 +311,220 @@ class SocketIOServer:
301
311
  "host": self.host,
302
312
  "clients_connected": len(self.clients)
303
313
  })
314
+
315
+ async def _handle_dashboard(self, request):
316
+ """Serve the dashboard HTML file."""
317
+ dashboard_path = get_project_root() / 'src' / 'claude_mpm' / 'web' / 'templates' / 'index.html'
318
+ self.logger.info(f"Dashboard requested, looking for: {dashboard_path}")
319
+ self.logger.info(f"Path exists: {dashboard_path.exists()}")
320
+ if dashboard_path.exists():
321
+ return web.FileResponse(str(dashboard_path))
322
+ else:
323
+ return web.Response(text=f"Dashboard not found at: {dashboard_path}", status=404)
324
+
325
+ async def _handle_git_diff(self, request):
326
+ """Handle git diff requests for file operations.
327
+
328
+ Expected query parameters:
329
+ - file: The file path to generate diff for
330
+ - timestamp: ISO timestamp of the operation (optional)
331
+ - working_dir: Working directory for git operations (optional)
332
+ """
333
+ try:
334
+ # Extract query parameters
335
+ file_path = request.query.get('file')
336
+ timestamp = request.query.get('timestamp')
337
+ working_dir = request.query.get('working_dir', os.getcwd())
338
+
339
+ if not file_path:
340
+ return web.json_response({
341
+ "error": "Missing required parameter: file"
342
+ }, status=400)
343
+
344
+ self.logger.debug(f"Git diff requested for file: {file_path}, timestamp: {timestamp}")
345
+
346
+ # Generate git diff using the _generate_git_diff helper
347
+ diff_result = await self._generate_git_diff(file_path, timestamp, working_dir)
348
+
349
+ return web.json_response(diff_result)
350
+
351
+ except Exception as e:
352
+ self.logger.error(f"Error generating git diff: {e}")
353
+ return web.json_response({
354
+ "error": f"Failed to generate git diff: {str(e)}"
355
+ }, status=500)
356
+
357
+ async def _generate_git_diff(self, file_path: str, timestamp: Optional[str] = None, working_dir: str = None):
358
+ """Generate git diff for a specific file operation.
359
+
360
+ WHY: This method generates a git diff showing the changes made to a file
361
+ during a specific write operation. It uses git log and show commands to
362
+ find the most relevant commit around the specified timestamp.
363
+
364
+ Args:
365
+ file_path: Path to the file relative to the git repository
366
+ timestamp: ISO timestamp of the file operation (optional)
367
+ working_dir: Working directory containing the git repository
368
+
369
+ Returns:
370
+ dict: Contains diff content, metadata, and status information
371
+ """
372
+ try:
373
+ if working_dir is None:
374
+ working_dir = os.getcwd()
375
+
376
+ # Change to the working directory
377
+ original_cwd = os.getcwd()
378
+ try:
379
+ os.chdir(working_dir)
380
+
381
+ # Check if this is a git repository
382
+ git_check = await asyncio.create_subprocess_exec(
383
+ 'git', 'rev-parse', '--git-dir',
384
+ stdout=asyncio.subprocess.PIPE,
385
+ stderr=asyncio.subprocess.PIPE
386
+ )
387
+ await git_check.communicate()
388
+
389
+ if git_check.returncode != 0:
390
+ return {
391
+ "error": "Not a git repository",
392
+ "file_path": file_path,
393
+ "working_dir": working_dir
394
+ }
395
+
396
+ # Get the absolute path of the file relative to git root
397
+ git_root_proc = await asyncio.create_subprocess_exec(
398
+ 'git', 'rev-parse', '--show-toplevel',
399
+ stdout=asyncio.subprocess.PIPE,
400
+ stderr=asyncio.subprocess.PIPE
401
+ )
402
+ git_root_output, _ = await git_root_proc.communicate()
403
+
404
+ if git_root_proc.returncode != 0:
405
+ return {"error": "Failed to determine git root directory"}
406
+
407
+ git_root = git_root_output.decode().strip()
408
+
409
+ # Make file_path relative to git root if it's absolute
410
+ if os.path.isabs(file_path):
411
+ try:
412
+ file_path = os.path.relpath(file_path, git_root)
413
+ except ValueError:
414
+ # File is not under git root
415
+ pass
416
+
417
+ # If timestamp is provided, try to find commits around that time
418
+ if timestamp:
419
+ # Convert timestamp to git format
420
+ try:
421
+ from datetime import datetime
422
+ dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
423
+ git_since = dt.strftime('%Y-%m-%d %H:%M:%S')
424
+
425
+ # Find commits that modified this file around the timestamp
426
+ log_proc = await asyncio.create_subprocess_exec(
427
+ 'git', 'log', '--oneline', '--since', git_since,
428
+ '--until', f'{git_since} +1 hour', '--', file_path,
429
+ stdout=asyncio.subprocess.PIPE,
430
+ stderr=asyncio.subprocess.PIPE
431
+ )
432
+ log_output, _ = await log_proc.communicate()
433
+
434
+ if log_proc.returncode == 0 and log_output:
435
+ # Get the most recent commit hash
436
+ commits = log_output.decode().strip().split('\n')
437
+ if commits and commits[0]:
438
+ commit_hash = commits[0].split()[0]
439
+
440
+ # Get the diff for this specific commit
441
+ diff_proc = await asyncio.create_subprocess_exec(
442
+ 'git', 'show', '--format=fuller', commit_hash, '--', file_path,
443
+ stdout=asyncio.subprocess.PIPE,
444
+ stderr=asyncio.subprocess.PIPE
445
+ )
446
+ diff_output, diff_error = await diff_proc.communicate()
447
+
448
+ if diff_proc.returncode == 0:
449
+ return {
450
+ "success": True,
451
+ "diff": diff_output.decode(),
452
+ "commit_hash": commit_hash,
453
+ "file_path": file_path,
454
+ "method": "timestamp_based",
455
+ "timestamp": timestamp
456
+ }
457
+ except Exception as e:
458
+ self.logger.warning(f"Failed to parse timestamp or find commits: {e}")
459
+
460
+ # Fallback: Get the most recent change to the file
461
+ log_proc = await asyncio.create_subprocess_exec(
462
+ 'git', 'log', '-1', '--oneline', '--', file_path,
463
+ stdout=asyncio.subprocess.PIPE,
464
+ stderr=asyncio.subprocess.PIPE
465
+ )
466
+ log_output, _ = await log_proc.communicate()
467
+
468
+ if log_proc.returncode == 0 and log_output:
469
+ commit_hash = log_output.decode().strip().split()[0]
470
+
471
+ # Get the diff for the most recent commit
472
+ diff_proc = await asyncio.create_subprocess_exec(
473
+ 'git', 'show', '--format=fuller', commit_hash, '--', file_path,
474
+ stdout=asyncio.subprocess.PIPE,
475
+ stderr=asyncio.subprocess.PIPE
476
+ )
477
+ diff_output, diff_error = await diff_proc.communicate()
478
+
479
+ if diff_proc.returncode == 0:
480
+ return {
481
+ "success": True,
482
+ "diff": diff_output.decode(),
483
+ "commit_hash": commit_hash,
484
+ "file_path": file_path,
485
+ "method": "latest_commit",
486
+ "timestamp": timestamp
487
+ }
488
+
489
+ # Final fallback: Show current working directory changes
490
+ diff_proc = await asyncio.create_subprocess_exec(
491
+ 'git', 'diff', 'HEAD', '--', file_path,
492
+ stdout=asyncio.subprocess.PIPE,
493
+ stderr=asyncio.subprocess.PIPE
494
+ )
495
+ diff_output, _ = await diff_proc.communicate()
496
+
497
+ if diff_proc.returncode == 0:
498
+ working_diff = diff_output.decode()
499
+ if working_diff.strip():
500
+ return {
501
+ "success": True,
502
+ "diff": working_diff,
503
+ "commit_hash": "working_directory",
504
+ "file_path": file_path,
505
+ "method": "working_directory",
506
+ "timestamp": timestamp
507
+ }
508
+
509
+ return {
510
+ "error": "No git history found for this file",
511
+ "file_path": file_path,
512
+ "suggestions": [
513
+ "The file may not be tracked by git",
514
+ "The file may not have any committed changes",
515
+ "The timestamp may be outside the git history range"
516
+ ]
517
+ }
518
+
519
+ finally:
520
+ os.chdir(original_cwd)
521
+
522
+ except Exception as e:
523
+ self.logger.error(f"Error in _generate_git_diff: {e}")
524
+ return {
525
+ "error": f"Git diff generation failed: {str(e)}",
526
+ "file_path": file_path
527
+ }
304
528
 
305
529
 
306
530
  def _register_events(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 3.2.1
3
+ Version: 3.3.0
4
4
  Summary: Claude Multi-agent Project Manager - Clean orchestration with ticket management
5
5
  Home-page: https://github.com/bobmatnyc/claude-mpm
6
6
  Author: Claude MPM Team
@@ -4,7 +4,7 @@ claude_mpm/constants.py,sha256=5wYR7YPHQtjZCreM_lgjoT7IPfujiuRWSb1Qu8coBxc,4216
4
4
  claude_mpm/deployment_paths.py,sha256=JO7-fhhp_AkVB7ZssggHDBbee-r2sokpkqjoqnQLTmM,9073
5
5
  claude_mpm/init.py,sha256=gOreOf7BLXkT0_HrQk_As4Kz1OT_NJG_RG0i0hbY0z0,8088
6
6
  claude_mpm/agents/BASE_AGENT_TEMPLATE.md,sha256=TYgSd9jNBMWp4mAOBUl9dconX4RcGbvmMEScRy5uyko,3343
7
- claude_mpm/agents/INSTRUCTIONS.md,sha256=9N0iSfShFc6TeJCajT2lnTIR2ZSS7WQHwmC0vTMTeG0,10548
7
+ claude_mpm/agents/INSTRUCTIONS.md,sha256=7CzaIBCf85rYCufZuOo4KjJGyWRrMd1AkN-Zzun93pE,13245
8
8
  claude_mpm/agents/__init__.py,sha256=r-p7ervzjLPD7_8dm2tXX_fwvdTZy6KwKA03ofxN3sA,3275
9
9
  claude_mpm/agents/agent-template.yaml,sha256=koKJn8MCAJx0QNQMHouvIZrwvw5qjPV0U-aV-YVyk6s,2036
10
10
  claude_mpm/agents/agent_loader.py,sha256=P4h3qupJHvZL9dfb6ntB582xenYv9JbkMOVav_kNkAo,44030
@@ -130,6 +130,7 @@ claude_mpm/scripts/claude-mpm-socketio,sha256=usdZgOQs0vjAKBhUcGJoRPnzJt3wYZDQM8
130
130
  claude_mpm/scripts/claude_mpm_monitor.html,sha256=24g1YWNB8PZ2S_q2xLQycK0Z06e2C7yOTsEm6qQRVUI,17634
131
131
  claude_mpm/scripts/install_socketio_server.py,sha256=Bx3BL48EF1peH111k_HU7tQdcUU6QVthAemGQcPsano,15522
132
132
  claude_mpm/scripts/launch_monitor.py,sha256=fAgRFJknrYq31SEWD9oEAEH2xvR3Lh_bzRPGDKEAFGg,4437
133
+ claude_mpm/scripts/launch_socketio_dashboard.py,sha256=BaZv_nuNY8rIFu76YhKswnrJAdM1pA3xNpb5-hQfsiA,9274
133
134
  claude_mpm/scripts/manage_version.py,sha256=5c86LD-_m0AlWqfgjRF6BH3Jc7n_nm5Z7hFVqB3iExQ,17524
134
135
  claude_mpm/scripts/socketio_daemon.py,sha256=HuRr7kzwwZskgLjHqf0wSW8IndsTs2s-aeR1tgnPMag,5115
135
136
  claude_mpm/scripts/socketio_server_manager.py,sha256=94uTdTuMHvTZrBNSrOHSKMz_z0AINl3uoc44msWfEz8,15522
@@ -152,7 +153,7 @@ claude_mpm/services/framework_claude_md_generator.py,sha256=3kHmkRLHTex6HFZ4DhbL
152
153
  claude_mpm/services/hook_service.py,sha256=hkpN8mXXYCwzdLVJwsoVg_fw5seEmei-q0ZzQyNoCXA,14200
153
154
  claude_mpm/services/shared_prompt_cache.py,sha256=D04lrRWyg0lHyqGcAHy7IYvRHRKSg6EOpAJwBUPa2wk,29890
154
155
  claude_mpm/services/socketio_client_manager.py,sha256=2Ly63iiGA_BUzf73UwQDu9Q75wA1C4O1CWFv8hi8bms,18074
155
- claude_mpm/services/socketio_server.py,sha256=PoLOAyLi3xqPt7fAOTKjWXns48e5zyUyL26bPl0nuM8,28712
156
+ claude_mpm/services/socketio_server.py,sha256=hE_Vt5pn952wuZ5aWTjFnsC-vfEX8z773TezqWeH7vQ,39529
156
157
  claude_mpm/services/standalone_socketio_server.py,sha256=XhsJ40Me3eSFHDpweIouy7dIqHK1aubikHCY275mUXk,24764
157
158
  claude_mpm/services/ticket_manager.py,sha256=Ki11YjBkDax8BFVSaDdOBk3K4VU5gvdbgq9AmCyyoZ0,7454
158
159
  claude_mpm/services/ticket_manager_di.py,sha256=pIsIGncbboKzBYSRQTO7ZX5MuQzV6iFfIflvKe6u1jw,11123
@@ -211,9 +212,9 @@ claude_mpm/utils/paths.py,sha256=Xv0SZWdZRkRjN9e6clBcA165ya00GNQxt7SwMz51tfA,101
211
212
  claude_mpm/validation/__init__.py,sha256=bJ19g9lnk7yIjtxzN8XPegp87HTFBzCrGQOpFgRTf3g,155
212
213
  claude_mpm/validation/agent_validator.py,sha256=GCA2b2rKhKDeaNyUqWxTiWIs3sDdWjD9cgOFRp9K6ic,18227
213
214
  claude_mpm/web/open_dashboard.py,sha256=aXUc6LzUMwmTQMkl_h2jjvICimr-ED4FPMHP_9mnrgQ,1108
214
- claude_mpm-3.2.1.dist-info/licenses/LICENSE,sha256=cSdDfXjoTVhstrERrqme4zgxAu4GubU22zVEHsiXGxs,1071
215
- claude_mpm-3.2.1.dist-info/METADATA,sha256=Huw-Iij7OODoeQTLXpjKOHtaWuArPOy4g_iM9ul3Rlw,15029
216
- claude_mpm-3.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
217
- claude_mpm-3.2.1.dist-info/entry_points.txt,sha256=3_d7wLrg9sRmQ1SfrFGWoTNL8Wrd6lQb2XVSYbTwRIg,324
218
- claude_mpm-3.2.1.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
219
- claude_mpm-3.2.1.dist-info/RECORD,,
215
+ claude_mpm-3.3.0.dist-info/licenses/LICENSE,sha256=cSdDfXjoTVhstrERrqme4zgxAu4GubU22zVEHsiXGxs,1071
216
+ claude_mpm-3.3.0.dist-info/METADATA,sha256=Duhx4Io5PBaaL2-cPkMQCUaId9WuZuBQxMARVEEjo2k,15029
217
+ claude_mpm-3.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
218
+ claude_mpm-3.3.0.dist-info/entry_points.txt,sha256=3_d7wLrg9sRmQ1SfrFGWoTNL8Wrd6lQb2XVSYbTwRIg,324
219
+ claude_mpm-3.3.0.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
220
+ claude_mpm-3.3.0.dist-info/RECORD,,