claude-mpm 3.4.7__py3-none-any.whl → 3.4.9__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.
@@ -467,6 +467,7 @@ def _check_socketio_server_running(port, logger):
467
467
 
468
468
  DESIGN DECISION: We try multiple endpoints and connection methods to ensure
469
469
  robust detection. Some servers may be starting up and only partially ready.
470
+ Added retry logic to handle race conditions during server initialization.
470
471
 
471
472
  Args:
472
473
  port: Port number to check
@@ -483,34 +484,50 @@ def _check_socketio_server_running(port, logger):
483
484
  # First, do a basic TCP connection check
484
485
  try:
485
486
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
486
- s.settimeout(1.0)
487
+ s.settimeout(2.0) # Increased from 1.0s for slower connections
487
488
  result = s.connect_ex(('127.0.0.1', port))
488
489
  if result != 0:
489
- logger.debug(f"TCP connection to port {port} failed (not listening)")
490
+ logger.debug(f"TCP connection to port {port} failed (server not started yet)")
490
491
  return False
491
492
  except Exception as e:
492
493
  logger.debug(f"TCP socket check failed for port {port}: {e}")
493
494
  return False
494
495
 
495
- # If TCP connection succeeds, try HTTP health check
496
- try:
497
- response = urllib.request.urlopen(f'http://localhost:{port}/status', timeout=5)
498
-
499
- if response.getcode() == 200:
500
- content = response.read().decode()
501
- logger.debug(f"✅ Socket.IO server health check passed on port {port}")
502
- logger.debug(f"📄 Server response: {content[:100]}...")
503
- return True
504
- else:
505
- logger.debug(f"⚠️ HTTP response code {response.getcode()} from port {port}")
506
- return False
496
+ # If TCP connection succeeds, try HTTP health check with retries
497
+ # WHY: Even when TCP is accepting connections, the HTTP handler may not be ready
498
+ max_retries = 3
499
+ for retry in range(max_retries):
500
+ try:
501
+ response = urllib.request.urlopen(f'http://localhost:{port}/status', timeout=10) # Increased from 5s to 10s
507
502
 
508
- except urllib.error.HTTPError as e:
509
- logger.debug(f"⚠️ HTTP error {e.code} from server on port {port}")
510
- return False
511
- except urllib.error.URLError as e:
512
- logger.debug(f"⚠️ URL error connecting to port {port}: {e.reason}")
513
- return False
503
+ if response.getcode() == 200:
504
+ content = response.read().decode()
505
+ logger.debug(f"✅ Socket.IO server health check passed on port {port} (attempt {retry + 1})")
506
+ logger.debug(f"📄 Server response: {content[:100]}...")
507
+ return True
508
+ else:
509
+ logger.debug(f"⚠️ HTTP response code {response.getcode()} from port {port} (attempt {retry + 1})")
510
+ if retry < max_retries - 1:
511
+ time.sleep(0.5) # Brief pause before retry
512
+
513
+ except urllib.error.HTTPError as e:
514
+ logger.debug(f"⚠️ HTTP error {e.code} from server on port {port} (attempt {retry + 1})")
515
+ if retry < max_retries - 1 and e.code in [404, 503]: # Server starting but not ready
516
+ logger.debug("Server appears to be starting, retrying...")
517
+ time.sleep(0.5)
518
+ continue
519
+ return False
520
+ except urllib.error.URLError as e:
521
+ logger.debug(f"⚠️ URL error connecting to port {port} (attempt {retry + 1}): {e.reason}")
522
+ if retry < max_retries - 1:
523
+ logger.debug("Connection refused - server may still be initializing, retrying...")
524
+ time.sleep(0.5)
525
+ continue
526
+ return False
527
+
528
+ # All retries exhausted
529
+ logger.debug(f"Health check failed after {max_retries} attempts - server not fully ready")
530
+ return False
514
531
 
515
532
  except (ConnectionError, OSError) as e:
516
533
  logger.debug(f"🔌 Connection error checking port {port}: {e}")
@@ -569,13 +586,17 @@ def _start_standalone_socketio_server(port, logger):
569
586
  # 2. Event loop setup (~1s)
570
587
  # 3. aiohttp server binding (~2-5s)
571
588
  # 4. Socket.IO service initialization (~1-3s)
572
- # Total: up to 10 seconds for full readiness
573
- max_attempts = 20 # Increased from 10
574
- initial_delay = 0.5 # seconds
575
- max_delay = 2.0 # seconds
589
+ # Total: up to 15+ seconds for full readiness (especially on Python 3.13)
590
+ max_attempts = 30 # Increased from 20 to handle Python 3.13 slower initialization
591
+ initial_delay = 1.0 # Increased from 0.5s to give daemon more time to fork
592
+ max_delay = 3.0 # Increased from 2.0s for slower systems
576
593
 
577
594
  logger.info(f"Waiting up to {max_attempts * max_delay} seconds for server to be fully ready...")
578
595
 
596
+ # Give the daemon initial time to fork and start before checking
597
+ logger.debug("Allowing initial daemon startup time...")
598
+ time.sleep(0.5)
599
+
579
600
  for attempt in range(max_attempts):
580
601
  # Progressive delay - start fast, then slow down for socket binding
581
602
  if attempt < 5:
@@ -596,9 +617,14 @@ def _start_standalone_socketio_server(port, logger):
596
617
  else:
597
618
  logger.debug(f"Server not yet accepting connections on attempt {attempt + 1}")
598
619
 
599
- logger.error(f"❌ Socket.IO server failed to start properly on port {port} after {max_attempts} attempts")
600
- logger.error(f"💡 This may indicate a port conflict or dependency issue")
601
- logger.error(f"🔧 Try a different port with --websocket-port or check for conflicts")
620
+ logger.error(f"❌ Socket.IO server health check failed after {max_attempts} attempts ({max_attempts * max_delay:.1f}s)")
621
+ logger.warning(f"⏱️ Server may still be starting - initialization can take 15+ seconds on some systems")
622
+ logger.warning(f"💡 The daemon process might be running but not yet accepting HTTP connections")
623
+ logger.error(f"🔧 Troubleshooting steps:")
624
+ logger.error(f" - Wait a few more seconds and try again")
625
+ logger.error(f" - Check for port conflicts: lsof -i :{port}")
626
+ logger.error(f" - Try a different port with --websocket-port")
627
+ logger.error(f" - Verify dependencies: pip install python-socketio aiohttp")
602
628
  return False
603
629
 
604
630
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 3.4.7
3
+ Version: 3.4.9
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
@@ -43,7 +43,7 @@ claude_mpm/cli/commands/agents.py,sha256=FqqEQcfAfCxjz_E7fGQUtLznloJLz8fWQtnjQhk
43
43
  claude_mpm/cli/commands/info.py,sha256=ETL6jC08OTQVTPjs219Y0m3FzfKOUlI0-yI81AI8FXY,2990
44
44
  claude_mpm/cli/commands/memory.py,sha256=6jYD1bgfnWA0DvBpLJnZCPYMRoGAPBopAED8Qr-iIos,37357
45
45
  claude_mpm/cli/commands/monitor.py,sha256=80_tmSdfn_2cYpzxxPu9GnvFW0eixlSJ4wCqbn8VSCM,12407
46
- claude_mpm/cli/commands/run.py,sha256=j8kFTdx4fwCR400NH-I0ORMc76J62IxUeVDaaq_DG7E,28312
46
+ claude_mpm/cli/commands/run.py,sha256=Rv6RT2S9WN8KcqX5e9rtmALP8yiOSw8ojl_Qp7gugqg,30234
47
47
  claude_mpm/cli/commands/tickets.py,sha256=SXyGtHSyGJwTeJwDAHf7kRbdiG1DlZkXkod5UoNy7Ik,2150
48
48
  claude_mpm/cli/commands/ui.py,sha256=FhBQiOKW61cNduyryRu0UhC366d6o1eEkBgbPd7Au1w,1900
49
49
  claude_mpm/cli_module/__init__.py,sha256=CkMp4gzWKoZZF_qKyBDi2sQaZw_GLWZYLtKouv-4f8s,390
@@ -193,9 +193,9 @@ claude_mpm/utils/path_operations.py,sha256=6pLMnAWBVzHkgp6JyQHmHbGD-dWn-nX21yV4E
193
193
  claude_mpm/utils/paths.py,sha256=Xv0SZWdZRkRjN9e6clBcA165ya00GNQxt7SwMz51tfA,10153
194
194
  claude_mpm/validation/__init__.py,sha256=bJ19g9lnk7yIjtxzN8XPegp87HTFBzCrGQOpFgRTf3g,155
195
195
  claude_mpm/validation/agent_validator.py,sha256=GCA2b2rKhKDeaNyUqWxTiWIs3sDdWjD9cgOFRp9K6ic,18227
196
- claude_mpm-3.4.7.dist-info/licenses/LICENSE,sha256=cSdDfXjoTVhstrERrqme4zgxAu4GubU22zVEHsiXGxs,1071
197
- claude_mpm-3.4.7.dist-info/METADATA,sha256=tT9hiWd9pr90NS5y_UbVARexJZv7rFW09EdGSnwJttQ,6523
198
- claude_mpm-3.4.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
199
- claude_mpm-3.4.7.dist-info/entry_points.txt,sha256=3_d7wLrg9sRmQ1SfrFGWoTNL8Wrd6lQb2XVSYbTwRIg,324
200
- claude_mpm-3.4.7.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
201
- claude_mpm-3.4.7.dist-info/RECORD,,
196
+ claude_mpm-3.4.9.dist-info/licenses/LICENSE,sha256=cSdDfXjoTVhstrERrqme4zgxAu4GubU22zVEHsiXGxs,1071
197
+ claude_mpm-3.4.9.dist-info/METADATA,sha256=6pnWOA54pUJgoL2UxHpALQouGnq6ubiXkw633NzhHBw,6523
198
+ claude_mpm-3.4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
199
+ claude_mpm-3.4.9.dist-info/entry_points.txt,sha256=3_d7wLrg9sRmQ1SfrFGWoTNL8Wrd6lQb2XVSYbTwRIg,324
200
+ claude_mpm-3.4.9.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
201
+ claude_mpm-3.4.9.dist-info/RECORD,,