claude-mpm 4.2.24__py3-none-any.whl → 4.2.26__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,6 +13,7 @@ DESIGN DECISIONS:
13
13
  - Log file redirection for daemon mode
14
14
  """
15
15
 
16
+ import json
16
17
  import os
17
18
  import signal
18
19
  import socket
@@ -21,7 +22,6 @@ import tempfile
21
22
  import time
22
23
  from pathlib import Path
23
24
  from typing import Optional, Tuple
24
- import json
25
25
 
26
26
  from ....core.logging_config import get_logger
27
27
 
@@ -57,9 +57,11 @@ class DaemonLifecycle:
57
57
  try:
58
58
  # Clean up any existing asyncio event loops before forking
59
59
  self._cleanup_event_loops()
60
-
60
+
61
61
  # Create a temporary file for startup status communication
62
- with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.status') as f:
62
+ with tempfile.NamedTemporaryFile(
63
+ mode="w", delete=False, suffix=".status"
64
+ ) as f:
63
65
  self.startup_status_file = f.name
64
66
  f.write("starting")
65
67
 
@@ -91,7 +93,7 @@ class DaemonLifecycle:
91
93
 
92
94
  # Set up error logging before redirecting streams
93
95
  self._setup_early_error_logging()
94
-
96
+
95
97
  # Write PID file first (before stream redirection)
96
98
  try:
97
99
  self.write_pid_file()
@@ -106,7 +108,7 @@ class DaemonLifecycle:
106
108
  self._setup_signal_handlers()
107
109
 
108
110
  self.logger.info(f"Daemon process started with PID {os.getpid()}")
109
-
111
+
110
112
  # Report successful startup (after basic setup but before server start)
111
113
  self._report_startup_success()
112
114
  return True
@@ -366,83 +368,93 @@ class DaemonLifecycle:
366
368
 
367
369
  def _parent_wait_for_startup(self, child_pid: int, timeout: float = 10.0) -> bool:
368
370
  """Parent process waits for child daemon to report startup status.
369
-
371
+
370
372
  Args:
371
373
  child_pid: PID of the child process
372
374
  timeout: Maximum time to wait for startup
373
-
375
+
374
376
  Returns:
375
377
  True if child started successfully, False otherwise
376
378
  """
377
379
  import time
380
+
378
381
  start_time = time.time()
379
-
382
+
380
383
  # Wait for child to update status file
381
384
  while time.time() - start_time < timeout:
382
385
  try:
383
386
  # Check if status file exists and read it
384
387
  if self.startup_status_file and Path(self.startup_status_file).exists():
385
- with open(self.startup_status_file, 'r') as f:
388
+ with open(self.startup_status_file) as f:
386
389
  status = f.read().strip()
387
-
390
+
388
391
  if status == "success":
389
392
  # Child started successfully
390
393
  self._cleanup_status_file()
391
394
  return True
392
- elif status.startswith("error:"):
395
+ if status.startswith("error:"):
393
396
  # Child reported an error
394
397
  error_msg = status[6:] # Remove "error:" prefix
395
398
  self.logger.error(f"Daemon startup failed: {error_msg}")
396
- print(f"Error: Failed to start monitor daemon: {error_msg}", file=sys.stderr)
399
+ print(
400
+ f"Error: Failed to start monitor daemon: {error_msg}",
401
+ file=sys.stderr,
402
+ )
397
403
  self._cleanup_status_file()
398
404
  return False
399
- elif status == "starting":
405
+ if status == "starting":
400
406
  # Still starting, continue waiting
401
407
  pass
402
-
408
+
403
409
  # Also check if child process is still alive
404
410
  try:
405
411
  os.kill(child_pid, 0) # Check if process exists
406
412
  except ProcessLookupError:
407
413
  # Child process died
408
414
  self.logger.error("Child daemon process died during startup")
409
- print("Error: Monitor daemon process died during startup", file=sys.stderr)
415
+ print(
416
+ "Error: Monitor daemon process died during startup",
417
+ file=sys.stderr,
418
+ )
410
419
  self._cleanup_status_file()
411
420
  return False
412
-
421
+
413
422
  except Exception as e:
414
423
  self.logger.debug(f"Error checking startup status: {e}")
415
-
424
+
416
425
  time.sleep(0.1) # Check every 100ms
417
-
426
+
418
427
  # Timeout reached
419
428
  self.logger.error(f"Daemon startup timed out after {timeout} seconds")
420
- print(f"Error: Monitor daemon startup timed out after {timeout} seconds", file=sys.stderr)
429
+ print(
430
+ f"Error: Monitor daemon startup timed out after {timeout} seconds",
431
+ file=sys.stderr,
432
+ )
421
433
  self._cleanup_status_file()
422
434
  return False
423
-
435
+
424
436
  def _report_startup_success(self):
425
437
  """Report successful startup to parent process."""
426
438
  if self.startup_status_file:
427
439
  try:
428
- with open(self.startup_status_file, 'w') as f:
440
+ with open(self.startup_status_file, "w") as f:
429
441
  f.write("success")
430
442
  except Exception as e:
431
443
  self.logger.error(f"Failed to report startup success: {e}")
432
-
444
+
433
445
  def _report_startup_error(self, error_msg: str):
434
446
  """Report startup error to parent process.
435
-
447
+
436
448
  Args:
437
449
  error_msg: Error message to report
438
450
  """
439
451
  if self.startup_status_file:
440
452
  try:
441
- with open(self.startup_status_file, 'w') as f:
453
+ with open(self.startup_status_file, "w") as f:
442
454
  f.write(f"error:{error_msg}")
443
455
  except Exception:
444
456
  pass # Can't report if file write fails
445
-
457
+
446
458
  def _cleanup_status_file(self):
447
459
  """Clean up the temporary status file."""
448
460
  if self.startup_status_file:
@@ -452,10 +464,10 @@ class DaemonLifecycle:
452
464
  pass # Ignore cleanup errors
453
465
  finally:
454
466
  self.startup_status_file = None
455
-
467
+
456
468
  def _setup_early_error_logging(self):
457
469
  """Set up error logging before stream redirection.
458
-
470
+
459
471
  This ensures we can capture and report errors that occur during
460
472
  daemon initialization, especially port binding errors.
461
473
  """
@@ -465,27 +477,30 @@ class DaemonLifecycle:
465
477
  default_log = Path.home() / ".claude-mpm" / "monitor-daemon.log"
466
478
  default_log.parent.mkdir(parents=True, exist_ok=True)
467
479
  self.log_file = default_log
468
-
480
+
469
481
  # Configure logger to write to file immediately
470
482
  import logging
483
+
471
484
  file_handler = logging.FileHandler(self.log_file)
472
485
  file_handler.setLevel(logging.DEBUG)
473
486
  formatter = logging.Formatter(
474
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
487
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
475
488
  )
476
489
  file_handler.setFormatter(formatter)
477
490
  self.logger.addHandler(file_handler)
478
-
491
+
479
492
  except Exception as e:
480
493
  # If we can't set up logging, at least try to report the error
481
494
  self._report_startup_error(f"Failed to setup error logging: {e}")
482
-
483
- def verify_port_available(self, host: str = "localhost") -> Tuple[bool, Optional[str]]:
495
+
496
+ def verify_port_available(
497
+ self, host: str = "localhost"
498
+ ) -> Tuple[bool, Optional[str]]:
484
499
  """Verify that the port is available for binding.
485
-
500
+
486
501
  Args:
487
502
  host: Host to check port on
488
-
503
+
489
504
  Returns:
490
505
  Tuple of (is_available, error_message)
491
506
  """
@@ -498,57 +513,61 @@ class DaemonLifecycle:
498
513
  except OSError as e:
499
514
  error_msg = f"Port {self.port} is already in use or cannot be bound: {e}"
500
515
  return False, error_msg
501
-
516
+
502
517
  def is_our_service(self, host: str = "localhost") -> Tuple[bool, Optional[int]]:
503
518
  """Check if the service on the port is our Socket.IO service.
504
-
519
+
505
520
  This uses multiple detection methods:
506
521
  1. Check health endpoint for service signature
507
522
  2. Check Socket.IO namespace availability
508
523
  3. Check process ownership if PID file exists
509
-
524
+
510
525
  Args:
511
526
  host: Host to check
512
-
527
+
513
528
  Returns:
514
529
  Tuple of (is_ours, pid_if_found)
515
530
  """
516
531
  self.logger.debug(f"Checking if service on {host}:{self.port} is ours")
517
-
532
+
518
533
  try:
519
534
  # Method 1: Check health endpoint
520
- import urllib.request
521
535
  import urllib.error
522
-
536
+ import urllib.request
537
+
523
538
  health_url = f"http://{host}:{self.port}/health"
524
539
  self.logger.debug(f"Checking health endpoint: {health_url}")
525
-
540
+
526
541
  try:
527
542
  req = urllib.request.Request(health_url)
528
- req.add_header('User-Agent', 'claude-mpm-monitor')
529
-
543
+ req.add_header("User-Agent", "claude-mpm-monitor")
544
+
530
545
  with urllib.request.urlopen(req, timeout=3) as response:
531
546
  if response.status == 200:
532
547
  data = json.loads(response.read().decode())
533
548
  self.logger.debug(f"Health endpoint response: {data}")
534
-
549
+
535
550
  # Check for our service signature
536
551
  service_name = data.get("service")
537
552
  if service_name == "claude-mpm-monitor":
538
553
  # Try to get PID from response
539
554
  pid = data.get("pid")
540
555
  if pid:
541
- self.logger.info(f"Found our claude-mpm-monitor service via health endpoint, PID: {pid}")
556
+ self.logger.info(
557
+ f"Found our claude-mpm-monitor service via health endpoint, PID: {pid}"
558
+ )
542
559
  return True, pid
543
- else:
544
- # Service is ours but no PID in response
545
- # Try to get from PID file
546
- file_pid = self.get_pid()
547
- self.logger.info(f"Found our claude-mpm-monitor service via health endpoint, PID from file: {file_pid}")
548
- return True, file_pid
549
- else:
550
- self.logger.debug(f"Service name '{service_name}' does not match 'claude-mpm-monitor'")
551
-
560
+ # Service is ours but no PID in response
561
+ # Try to get from PID file
562
+ file_pid = self.get_pid()
563
+ self.logger.info(
564
+ f"Found our claude-mpm-monitor service via health endpoint, PID from file: {file_pid}"
565
+ )
566
+ return True, file_pid
567
+ self.logger.debug(
568
+ f"Service name '{service_name}' does not match 'claude-mpm-monitor'"
569
+ )
570
+
552
571
  except urllib.error.URLError as e:
553
572
  self.logger.debug(f"Health endpoint not accessible: {e}")
554
573
  except urllib.error.HTTPError as e:
@@ -557,7 +576,7 @@ class DaemonLifecycle:
557
576
  self.logger.debug(f"Health endpoint invalid JSON: {e}")
558
577
  except Exception as e:
559
578
  self.logger.debug(f"Health endpoint check failed: {e}")
560
-
579
+
561
580
  # Method 2: Check if PID file exists and process matches
562
581
  pid = self.get_pid()
563
582
  if pid:
@@ -566,116 +585,139 @@ class DaemonLifecycle:
566
585
  # Check if process exists
567
586
  os.kill(pid, 0)
568
587
  self.logger.debug(f"Process {pid} exists")
569
-
588
+
570
589
  # Process exists, check if it's using our port
571
590
  # This requires psutil for accurate port checking
572
591
  try:
573
592
  import psutil
593
+
574
594
  process = psutil.Process(pid)
575
-
595
+
576
596
  # Check process command line for our service
577
- cmdline = ' '.join(process.cmdline())
578
- if 'claude_mpm' in cmdline or 'claude-mpm' in cmdline:
579
- if 'monitor' in cmdline:
580
- self.logger.info(f"Found our claude-mpm monitor process via PID file, PID: {pid}")
597
+ cmdline = " ".join(process.cmdline())
598
+ if "claude_mpm" in cmdline or "claude-mpm" in cmdline:
599
+ if "monitor" in cmdline:
600
+ self.logger.info(
601
+ f"Found our claude-mpm monitor process via PID file, PID: {pid}"
602
+ )
581
603
  return True, pid
582
-
604
+
583
605
  # Also check if it's listening on our port
584
606
  connections = process.connections()
585
607
  for conn in connections:
586
- if conn.laddr.port == self.port and conn.status == 'LISTEN':
587
- self.logger.info(f"Found process {pid} listening on our port {self.port}")
608
+ if conn.laddr.port == self.port and conn.status == "LISTEN":
609
+ self.logger.info(
610
+ f"Found process {pid} listening on our port {self.port}"
611
+ )
588
612
  # Double-check it's a Python process (likely ours)
589
- if 'python' in process.name().lower():
590
- self.logger.info(f"Confirmed as Python process, assuming it's our service")
613
+ if "python" in process.name().lower():
614
+ self.logger.info(
615
+ "Confirmed as Python process, assuming it's our service"
616
+ )
591
617
  return True, pid
592
-
618
+
593
619
  except ImportError:
594
620
  # psutil not available, but we have a PID file and process exists
595
621
  # Assume it's ours since we manage the PID file
596
- self.logger.info(f"Found process with our PID file: {pid}, assuming it's ours (psutil not available)")
622
+ self.logger.info(
623
+ f"Found process with our PID file: {pid}, assuming it's ours (psutil not available)"
624
+ )
597
625
  return True, pid
598
626
  except psutil.NoSuchProcess:
599
627
  self.logger.debug(f"Process {pid} no longer exists")
600
628
  except psutil.AccessDenied:
601
629
  # Can't access process info, but it exists - likely ours
602
- self.logger.info(f"Process {pid} exists but access denied, assuming it's ours")
630
+ self.logger.info(
631
+ f"Process {pid} exists but access denied, assuming it's ours"
632
+ )
603
633
  return True, pid
604
634
  except Exception as e:
605
635
  self.logger.debug(f"Error checking process {pid}: {e}")
606
-
636
+
607
637
  except (OSError, ProcessLookupError):
608
638
  # Process doesn't exist
609
639
  self.logger.debug(f"Process {pid} does not exist")
610
640
  self._cleanup_stale_pid_file()
611
-
641
+
612
642
  # Method 3: Try Socket.IO connection to check namespace
613
643
  try:
614
644
  import socketio
645
+
615
646
  sio_client = socketio.Client()
616
-
647
+
617
648
  # Try to connect with a short timeout
618
649
  connected = False
650
+
619
651
  def on_connect():
620
652
  nonlocal connected
621
653
  connected = True
622
-
623
- sio_client.on('connect', on_connect)
624
-
654
+
655
+ sio_client.on("connect", on_connect)
656
+
625
657
  try:
626
- sio_client.connect(f'http://{host}:{self.port}', wait_timeout=2)
658
+ sio_client.connect(f"http://{host}:{self.port}", wait_timeout=2)
627
659
  if connected:
628
660
  # Successfully connected to Socket.IO
629
661
  sio_client.disconnect()
630
-
662
+
631
663
  # Check for orphaned process (no PID file but service running)
632
664
  try:
633
665
  # Try to find process using the port
634
666
  import psutil
635
- for proc in psutil.process_iter(['pid', 'name']):
667
+
668
+ for proc in psutil.process_iter(["pid", "name"]):
636
669
  try:
637
670
  for conn in proc.connections():
638
- if conn.laddr.port == self.port and conn.status == 'LISTEN':
671
+ if (
672
+ conn.laddr.port == self.port
673
+ and conn.status == "LISTEN"
674
+ ):
639
675
  # Found process listening on our port
640
- if 'python' in proc.name().lower():
641
- self.logger.debug(f"Found likely orphaned claude-mpm service on port {self.port}, PID: {proc.pid}")
676
+ if "python" in proc.name().lower():
677
+ self.logger.debug(
678
+ f"Found likely orphaned claude-mpm service on port {self.port}, PID: {proc.pid}"
679
+ )
642
680
  return True, proc.pid
643
681
  except (psutil.NoSuchProcess, psutil.AccessDenied):
644
682
  continue
645
683
  except ImportError:
646
684
  pass
647
-
685
+
648
686
  # Socket.IO service exists but can't determine if it's ours
649
- self.logger.debug(f"Found Socket.IO service on port {self.port}, but cannot confirm ownership")
687
+ self.logger.debug(
688
+ f"Found Socket.IO service on port {self.port}, but cannot confirm ownership"
689
+ )
650
690
  return False, None
651
-
691
+
652
692
  except Exception:
653
693
  pass
654
694
  finally:
655
695
  if sio_client.connected:
656
696
  sio_client.disconnect()
657
-
697
+
658
698
  except ImportError:
659
699
  # socketio not available
660
700
  pass
661
701
  except Exception as e:
662
702
  self.logger.debug(f"Error checking Socket.IO connection: {e}")
663
-
703
+
664
704
  # Method 4: Final fallback - if we have a PID file and can't definitively say it's NOT ours
665
705
  # This handles edge cases where the health endpoint might be temporarily unavailable
666
706
  if pid and self.pid_file.exists():
667
707
  try:
668
708
  # One more check - see if process exists
669
709
  os.kill(pid, 0)
670
- self.logger.info(f"PID file exists with valid process {pid}, assuming it's our stale service")
710
+ self.logger.info(
711
+ f"PID file exists with valid process {pid}, assuming it's our stale service"
712
+ )
671
713
  return True, pid
672
714
  except (OSError, ProcessLookupError):
673
715
  pass
674
-
716
+
675
717
  # No service detected or not ours
676
718
  self.logger.debug("Service not detected as ours")
677
719
  return False, None
678
-
720
+
679
721
  except Exception as e:
680
722
  self.logger.error(f"Error checking if service is ours: {e}", exc_info=True)
681
723
  return False, None
@@ -115,7 +115,9 @@ class UnifiedMonitorServer:
115
115
  time.sleep(0.1)
116
116
 
117
117
  if not self.running:
118
- error_msg = self.startup_error or "Server failed to start within timeout"
118
+ error_msg = (
119
+ self.startup_error or "Server failed to start within timeout"
120
+ )
119
121
  self.logger.error(error_msg)
120
122
  return False
121
123
 
@@ -231,7 +233,7 @@ class UnifiedMonitorServer:
231
233
  try:
232
234
  self.site = web.TCPSite(self.runner, self.host, self.port)
233
235
  await self.site.start()
234
-
236
+
235
237
  self.running = True
236
238
  self.logger.info(f"Server running on http://{self.host}:{self.port}")
237
239
  except OSError as e:
@@ -241,10 +243,9 @@ class UnifiedMonitorServer:
241
243
  self.logger.error(error_msg)
242
244
  self.startup_error = error_msg
243
245
  raise OSError(error_msg) from e
244
- else:
245
- self.logger.error(f"Failed to bind to {self.host}:{self.port}: {e}")
246
- self.startup_error = str(e)
247
- raise
246
+ self.logger.error(f"Failed to bind to {self.host}:{self.port}: {e}")
247
+ self.startup_error = str(e)
248
+ raise
248
249
 
249
250
  # Keep the server running
250
251
  while self.running:
@@ -312,12 +313,14 @@ class UnifiedMonitorServer:
312
313
  # Get version from VERSION file
313
314
  version = "1.0.0"
314
315
  try:
315
- version_file = Path(__file__).parent.parent.parent.parent.parent / "VERSION"
316
+ version_file = (
317
+ Path(__file__).parent.parent.parent.parent.parent / "VERSION"
318
+ )
316
319
  if version_file.exists():
317
320
  version = version_file.read_text().strip()
318
321
  except Exception:
319
322
  pass
320
-
323
+
321
324
  return web.json_response(
322
325
  {
323
326
  "status": "healthy",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.2.24
3
+ Version: 4.2.26
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
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=toytnNjkIKPgQaGwDqQdC1rpNTAdSEc6Vja50d7Ovug,4
2
- claude_mpm/VERSION,sha256=U4vIe-sZ-5Iumq-KW3abswP9PknmnEd-RswDftmED1g,7
2
+ claude_mpm/VERSION,sha256=SQgB6WkCfQ-PDwm6SAsbMLZRb40PTP081FhoVTi1sfg,7
3
3
  claude_mpm/__init__.py,sha256=lyTZAYGH4DTaFGLRNWJKk5Q5oTjzN5I6AXmfVX-Jff0,1512
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=I946iCQzIIPRZVVJ8aO7lA4euiyDnNw2IX7EelAOkIE,5915
@@ -54,7 +54,7 @@ claude_mpm/agents/templates/.claude-mpm/memories/README.md,sha256=vEiG7cPjHRZfwX
54
54
  claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md,sha256=KMZSJrQi-wHOwfl2C0m3A4PpC4QuBtDolAtVybGahKc,77
55
55
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md,sha256=UBm4BycXtdaa-_l1VCh0alTGGOUSsnCbpKwbFuI-mUY,2219
56
56
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md,sha256=oPvFSYFnmJ4TkbTe4AZnNHWaJMJ-xqZP2WM6scUKQKo,13089
57
- claude_mpm/cli/__init__.py,sha256=EbljSdUXNMUSPjXjvzKBkGfgTMwmWFLjRkGDJ0_eRjk,16247
57
+ claude_mpm/cli/__init__.py,sha256=yOUdP3WeyXyBL8eqp5YgcfFjUpUZx9PYpBc3FYFZeqs,16600
58
58
  claude_mpm/cli/__main__.py,sha256=WnVGBwe10InxuZjJRFdwuMF6Gh16aXox6zFgxr0sRXk,847
59
59
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
60
60
  claude_mpm/cli/startup_logging.py,sha256=CWu43ecTJLLT-YHRL94c783XljpR8GKydycGJ1JFuXI,23462
@@ -83,11 +83,12 @@ claude_mpm/cli/commands/mcp_pipx_config.py,sha256=sE62VD6Q1CcO2k1nlbIhHMfAJFQTZf
83
83
  claude_mpm/cli/commands/mcp_server_commands.py,sha256=-1G_2Y5ScTvzDd-kY8fTAao2H6FH7DnsLimleF1rVqQ,6197
84
84
  claude_mpm/cli/commands/mcp_tool_commands.py,sha256=q17GzlFT3JiLTrDqwPO2tz1-fKmPO5QU449syTnKTz4,1283
85
85
  claude_mpm/cli/commands/memory.py,sha256=Yzfs3_oiKciv3sfOoDm2lJL4M9idG7ARV3-sNw1ge_g,26186
86
- claude_mpm/cli/commands/monitor.py,sha256=K8TNtOsdsFgzr9VePELxFnNqZOGhL5a7XFbgOpNYq0g,9621
86
+ claude_mpm/cli/commands/monitor.py,sha256=Y4on91KW6Ye5NIglHnMVG8hhzw8ZRslBm1oMm6KC48s,9556
87
87
  claude_mpm/cli/commands/mpm_init.py,sha256=lO7N91ZHn_n18XbchUUcYoyme7L5NLcXVnhWm5F_Gq8,22367
88
88
  claude_mpm/cli/commands/mpm_init_handler.py,sha256=-pCB0XL3KipqGtnta8CC7Lg5TPMwstEhMFBcgF4aaa4,2919
89
89
  claude_mpm/cli/commands/run.py,sha256=qS3eolLiDrE8EXLQJioB6kL1ONr_l0c3OE3qMUJCqbA,43489
90
90
  claude_mpm/cli/commands/tickets.py,sha256=kl2dklTBnG3Y4jUUJ_PcEVsTx4CtVJfkGWboWBx_mQM,21234
91
+ claude_mpm/cli/commands/uninstall.py,sha256=l2FOgzQMJRVRSdg3npApkyKkZ7fNE5LgpAa2THyVVV8,5970
91
92
  claude_mpm/cli/interactive/__init__.py,sha256=vQqUCgPFvLYA1Vkq-5pnY7Ow3A-IgdM0SByfNL1ZLTk,433
92
93
  claude_mpm/cli/interactive/agent_wizard.py,sha256=ZaCIToc-IGT4gsBDWtDHzZU9QOd3VlSUkJgewoZmBF8,36199
93
94
  claude_mpm/cli/parsers/__init__.py,sha256=f0Fm1DDXorlVOZPLxUpjC-GIvLh01G-FZOK7TEV1L3I,1005
@@ -95,7 +96,7 @@ claude_mpm/cli/parsers/agent_manager_parser.py,sha256=E2BHHb9FusktHjcXo3qb13d8EH
95
96
  claude_mpm/cli/parsers/agents_parser.py,sha256=leyq8ugOZikNH_YWRolR7fTwJF1f3a_xPniGSzeqkSI,9065
96
97
  claude_mpm/cli/parsers/analyze_code_parser.py,sha256=cpJSMFbc3mqB4qrMBIEZiikzPekC2IQX-cjt9U2fHW4,5356
97
98
  claude_mpm/cli/parsers/analyze_parser.py,sha256=E00Ao0zwzbJPchs_AJt-aoQ7LQEtJPXRCNQ6Piivb4o,3908
98
- claude_mpm/cli/parsers/base_parser.py,sha256=X4ScS1KIX1ODlA6hELCcwEvI76dZDqsodDYuIRxMdRo,13461
99
+ claude_mpm/cli/parsers/base_parser.py,sha256=3BAUzITN1bUvJcXYP110zlzt-oURL1pxFzbTMQFuNRU,13647
99
100
  claude_mpm/cli/parsers/config_parser.py,sha256=wp6NbV8_p9txP28MXFcQrri0JDIfGFM7u4aJbYJXcYQ,2699
100
101
  claude_mpm/cli/parsers/configure_parser.py,sha256=cg3VXrnSqi9QLhMihJXeKDjtp1sS5jSHZNM_prgm0S4,4598
101
102
  claude_mpm/cli/parsers/dashboard_parser.py,sha256=JBCM6v_iZhADr_Fwtk_d3up9AOod1avMab-vkNE61gE,3460
@@ -298,7 +299,7 @@ claude_mpm/models/agent_definition.py,sha256=LC7EwihixF2Gw4QqOxiCNchsEzzyQJPR6Ag
298
299
  claude_mpm/models/agent_session.py,sha256=7YU9oklwqEDyH3PTKUQ52yh6N9C9eJX8GJKhxDCpDj0,19988
299
300
  claude_mpm/schemas/__init__.py,sha256=2SLpkojJq34KnwPkVxrsVmw_cEI66872i75QBT1C2To,446
300
301
  claude_mpm/scripts/__init__.py,sha256=IffMdVD99Pxyw85yluRa0VDPi4dRQecIWce764pcfZE,553
301
- claude_mpm/scripts/claude-hook-handler.sh,sha256=86Ywf4lHpF9wTXmxo3lhFmcFS0wk1G3cSyHA71N8imI,6552
302
+ claude_mpm/scripts/claude-hook-handler.sh,sha256=xe6dKubrjK1JDO0SJdc1-tA6C7YSb5YazhwKhOYBQvw,7905
302
303
  claude_mpm/scripts/launch_monitor.py,sha256=Q7hN4Wurw45veLWPSXk0WfvkKxQ1Snz7TjZsV_pNWQc,2418
303
304
  claude_mpm/scripts/mcp_server.py,sha256=_i9ydtI7AcO-Eb7gzbIDbcJY4PKRQRYNobB8eMailI4,2259
304
305
  claude_mpm/scripts/mcp_wrapper.py,sha256=PvfHJShcsQHGJZD-RN3RnwLOzemAKYZ2kW_QfTkGzkk,1105
@@ -313,6 +314,7 @@ claude_mpm/services/command_deployment_service.py,sha256=FxrHWuhvEaYL6PmjCN7Y0Tl
313
314
  claude_mpm/services/command_handler_service.py,sha256=LdKnujKUgrCYrvKvmCXaUMk7JGFJsyNeiKnDFdR8ox8,7031
314
315
  claude_mpm/services/event_aggregator.py,sha256=859FzkvOKL558Np42A8diVu8Hpa66AhKyhdQcEbBXoI,20201
315
316
  claude_mpm/services/exceptions.py,sha256=6l5lXX8j_JhZAgFVs7QoETvsEdzEbByvtAIDbr_JeNY,26439
317
+ claude_mpm/services/hook_installer_service.py,sha256=UoB3rdN3RTK6VHftEM-x4RtCxs55TBvpDf-auXeLceI,19710
316
318
  claude_mpm/services/hook_service.py,sha256=rZnMn_4qxX5g9KAn0IQdoG50WmySNfsTmfG0XHuRHXk,15737
317
319
  claude_mpm/services/memory_hook_service.py,sha256=pRlTClkRcw30Jhwbha4BC8IMdzKZxF8aWqf52JlntgY,11600
318
320
  claude_mpm/services/monitor_build_service.py,sha256=ggtkHcR7eKOMZjoVEA-1GzNdXhI-sh8z83PJXlozgZM,12141
@@ -432,7 +434,7 @@ claude_mpm/services/cli/memory_crud_service.py,sha256=ciN9Pl_12iDAqF9zPBWOzu-iXi
432
434
  claude_mpm/services/cli/memory_output_formatter.py,sha256=nbf7VsjGvH4e9fLv9c7PzjuO9COZhbK5P2fNZ79055w,24783
433
435
  claude_mpm/services/cli/session_manager.py,sha256=rla_Stbcvt93wa9G9MCMu9UqB3FLGqlPt_eN5lQb3Gg,16599
434
436
  claude_mpm/services/cli/startup_checker.py,sha256=efhuvu8ns5G16jcQ0nQZKVddmD2AktUEdlvjNcXjAuk,12232
435
- claude_mpm/services/cli/unified_dashboard_manager.py,sha256=3IRum9HH6IA4UQtTzD5l6rCngfxfqeqfTGzpKIpmZd8,12607
437
+ claude_mpm/services/cli/unified_dashboard_manager.py,sha256=4p8ubQhAXMezCVjd2sj_Q7D_AsDXtJJDQFD9BuvW838,12682
436
438
  claude_mpm/services/communication/__init__.py,sha256=b4qc7_Rqy4DE9q7BAUlfUZjoYG4uimAyUnE0irPcXyU,560
437
439
  claude_mpm/services/core/__init__.py,sha256=evEayLlBqJvxMZhrhuK6aagXmNrKGSj8Jm9OOxKzqvU,2195
438
440
  claude_mpm/services/core/base.py,sha256=iA-F7DgGp-FJIMvQTiHQ68RkG_k-AtUWlArJPMw6ZPk,7297
@@ -548,9 +550,9 @@ claude_mpm/services/memory/cache/__init__.py,sha256=6M6-P8ParyxX8vOgp_IxHgLMvacr
548
550
  claude_mpm/services/memory/cache/shared_prompt_cache.py,sha256=crnYPUT8zcS7TvoE1vW7pyaf4T77N5rJ1wUf_YQ2vvo,28704
549
551
  claude_mpm/services/memory/cache/simple_cache.py,sha256=qsTjbcsPxj-kNfaod9VN_uE5NioIwpfkUin_mMVUJCg,10218
550
552
  claude_mpm/services/monitor/__init__.py,sha256=X7gxSLUm9Fg_zEsX6LtCHP2ipF0qj6Emkun20h2So7g,745
551
- claude_mpm/services/monitor/daemon.py,sha256=9Cllm-jtVA85_qX1Z3TF-OwB5QZDzSfIvAcKhVQ65G8,21829
553
+ claude_mpm/services/monitor/daemon.py,sha256=pZqn_-1PBMf9gfIq8Zo55gXoXInB0gKNyOZpWGkdrxw,27731
552
554
  claude_mpm/services/monitor/event_emitter.py,sha256=JzRLNg8PUJ5s3ulNnq_D4yqCPItvidJzu8DmFxriieQ,12224
553
- claude_mpm/services/monitor/server.py,sha256=2-xLo14qFBZf5MDYwBxBhTrFCNnbu3tOS3eEu8vyddc,28476
555
+ claude_mpm/services/monitor/server.py,sha256=m98Eyv9caxRywJ4JtAdOuv5EB__z7vd2hYRZPwcqFLg,28498
554
556
  claude_mpm/services/monitor/handlers/__init__.py,sha256=jgPIf4IJVERm_tAeD9834tfx9IcxtlHj5r9rhEWpkfM,701
555
557
  claude_mpm/services/monitor/handlers/code_analysis.py,sha256=mHyI27Wp6WVmUBc0m0i991ogyFZBTvkrfR7Kf3EAk5U,11474
556
558
  claude_mpm/services/monitor/handlers/dashboard.py,sha256=uGBhb-6RG6u4WLipUXgdx7RCW-vb_qek5dIfHIwAC7o,9805
@@ -558,7 +560,7 @@ claude_mpm/services/monitor/handlers/file.py,sha256=p3C4wffl0GIcN00b-KkrmZ8F-Amd
558
560
  claude_mpm/services/monitor/handlers/hooks.py,sha256=dlrmyFu8WChlvn6-sND9DLjSbm5nrMfNZrAgoWN-2No,17582
559
561
  claude_mpm/services/monitor/management/__init__.py,sha256=mxaEFRgvvgV85gUpXu_DsnHtywihdP14EisvISAVZuQ,525
560
562
  claude_mpm/services/monitor/management/health.py,sha256=Wm92Cli_4cWD6B89KX_CdpAvvevuEaGB8Ah59ILhFww,3772
561
- claude_mpm/services/monitor/management/lifecycle.py,sha256=EClf8CK-kCLVb2iRo9uiGI2CAHFrii1Qe1i8xuWnhG4,27037
563
+ claude_mpm/services/monitor/management/lifecycle.py,sha256=WVs231EOEkMOx2ofWDdE8GdWazFS8NZ6xwi185szapI,27340
562
564
  claude_mpm/services/project/__init__.py,sha256=IUclN1L7ChHCNya7PJiVxu4nttxsrj3WRIpwyA1A_hw,512
563
565
  claude_mpm/services/project/analyzer.py,sha256=VHlLrP8-S5gr12w4Yzs7-6d7LWdJKISHPCFSG7SDiQU,38434
564
566
  claude_mpm/services/project/analyzer_refactored.py,sha256=USYEdPAhSoGPqZCpaT89Dw6ElFW_L1yXSURheQjAhLA,18243
@@ -639,9 +641,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=zgiwLqh_17WxHpySvUPH65pb4bzIeUGOAYUJ
639
641
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
640
642
  claude_mpm/validation/agent_validator.py,sha256=3Lo6LK-Mw9IdnL_bd3zl_R6FkgSVDYKUUM7EeVVD3jc,20865
641
643
  claude_mpm/validation/frontmatter_validator.py,sha256=u8g4Eyd_9O6ugj7Un47oSGh3kqv4wMkuks2i_CtWRvM,7028
642
- claude_mpm-4.2.24.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
643
- claude_mpm-4.2.24.dist-info/METADATA,sha256=gBePVzfdnH07tGtxu8dnaQwimTu90EqPI0hcpdIZnjM,14451
644
- claude_mpm-4.2.24.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
645
- claude_mpm-4.2.24.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
646
- claude_mpm-4.2.24.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
647
- claude_mpm-4.2.24.dist-info/RECORD,,
644
+ claude_mpm-4.2.26.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
645
+ claude_mpm-4.2.26.dist-info/METADATA,sha256=_oxZGDtNFYz4VX0vwQhEKz5cQFyw1bl3gcpiYXohypI,14451
646
+ claude_mpm-4.2.26.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
647
+ claude_mpm-4.2.26.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
648
+ claude_mpm-4.2.26.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
649
+ claude_mpm-4.2.26.dist-info/RECORD,,