claude-mpm 4.2.36__py3-none-any.whl → 4.2.38__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.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.2.36
1
+ 4.2.38
@@ -161,14 +161,16 @@ class UnifiedMonitorDaemon:
161
161
  self._wait_for_prewarm_completion()
162
162
 
163
163
  # Use daemon manager's daemonize which includes cleanup
164
- self.daemon_manager.startup_status_file = None # Reset status file
164
+ # DO NOT reset startup_status_file - it's needed for parent-child communication!
165
+ # self.daemon_manager.startup_status_file = None # BUG: This breaks communication
165
166
  success = self.daemon_manager.daemonize()
166
167
  if not success:
167
168
  return False
168
169
 
169
170
  # We're now in the daemon process
170
- # Update our PID references
171
+ # Update our PID references and status file
171
172
  self.lifecycle.pid_file = self.daemon_manager.pid_file
173
+ self.lifecycle.startup_status_file = self.daemon_manager.startup_status_file
172
174
 
173
175
  # Start the server in daemon mode
174
176
  try:
@@ -588,8 +590,8 @@ class UnifiedMonitorDaemon:
588
590
 
589
591
  start_time = time.time()
590
592
 
591
- # Get all non-daemon threads (pre-warm threads are daemon threads)
592
- # but we still want to give them a moment to complete
593
+ # Get all threads including daemon threads
594
+ # Pre-warm threads are daemon threads but we MUST wait for them
593
595
  active_threads = [
594
596
  t
595
597
  for t in threading.enumerate()
@@ -597,13 +599,38 @@ class UnifiedMonitorDaemon:
597
599
  ]
598
600
 
599
601
  if active_threads:
600
- self.logger.debug(
601
- f"Waiting for {len(active_threads)} threads to complete"
602
+ self.logger.info(
603
+ f"Waiting for {len(active_threads)} background threads to complete before forking"
602
604
  )
603
-
604
- # Wait briefly for threads to complete
605
- wait_time = min(timeout, 2.0) # Max 2 seconds for daemon threads
606
- time.sleep(wait_time)
605
+
606
+ # List thread names for debugging
607
+ thread_names = [t.name for t in active_threads]
608
+ self.logger.debug(f"Active threads: {thread_names}")
609
+
610
+ # Wait for threads to complete or timeout
611
+ while time.time() - start_time < timeout:
612
+ remaining_threads = [
613
+ t for t in active_threads if t.is_alive()
614
+ ]
615
+ if not remaining_threads:
616
+ self.logger.debug("All threads completed")
617
+ break
618
+
619
+ # Log remaining threads periodically
620
+ if int(time.time() - start_time) % 1 == 0:
621
+ self.logger.debug(f"{len(remaining_threads)} threads still active")
622
+
623
+ time.sleep(0.1)
624
+
625
+ # Final check
626
+ final_threads = [
627
+ t for t in threading.enumerate()
628
+ if t.is_alive() and t != threading.current_thread()
629
+ ]
630
+ if final_threads:
631
+ self.logger.warning(
632
+ f"Proceeding with {len(final_threads)} threads still active after {timeout}s wait"
633
+ )
607
634
 
608
635
  elapsed = time.time() - start_time
609
636
  self.logger.debug(f"Waited {elapsed:.2f}s for thread completion")
@@ -494,6 +494,13 @@ class DaemonManager:
494
494
  Returns:
495
495
  True if successful (in parent), doesn't return in child
496
496
  """
497
+ # Guard against re-entrant execution after fork
498
+ if hasattr(self, '_forking_in_progress'):
499
+ self.logger.error("CRITICAL: Detected re-entrant daemonize call after fork!")
500
+ return False
501
+
502
+ self._forking_in_progress = True
503
+
497
504
  try:
498
505
  # Clean up asyncio event loops before forking
499
506
  self._cleanup_event_loops()
@@ -509,6 +516,7 @@ class DaemonManager:
509
516
  pid = os.fork()
510
517
  if pid > 0:
511
518
  # Parent process - wait for child to confirm startup
519
+ del self._forking_in_progress # Clean up in parent
512
520
  return self._parent_wait_for_startup(pid)
513
521
 
514
522
  except OSError as e:
@@ -771,18 +779,32 @@ class DaemonManager:
771
779
 
772
780
  def _report_startup_success(self):
773
781
  """Report successful startup to parent process."""
774
- if self.startup_status_file and Path(self.startup_status_file).exists():
782
+ if self.startup_status_file:
775
783
  try:
784
+ # Don't check if file exists - we need to write to it regardless
785
+ # The parent created it and is waiting for us to update it
776
786
  with open(self.startup_status_file, "w") as f:
777
787
  f.write("success")
788
+ f.flush() # Ensure it's written immediately
789
+ os.fsync(f.fileno()) # Force write to disk
778
790
  except Exception as e:
779
- self.logger.error(f"Error reporting startup success: {e}")
791
+ # Logging might not work in daemon process after fork
792
+ pass
780
793
 
781
794
  def _report_startup_error(self, error: str):
782
795
  """Report startup error to parent process."""
783
- if self.startup_status_file and Path(self.startup_status_file).exists():
796
+ if self.startup_status_file:
784
797
  try:
798
+ # Don't check if file exists - we need to write to it regardless
785
799
  with open(self.startup_status_file, "w") as f:
786
800
  f.write(f"error:{error}")
801
+ f.flush() # Ensure it's written immediately
802
+ os.fsync(f.fileno()) # Force write to disk
787
803
  except Exception as e:
788
- self.logger.error(f"Error reporting startup error: {e}")
804
+ # Try to write error to a debug file since logging might not work
805
+ try:
806
+ with open("/tmp/daemon_debug_error.txt", "a") as debug:
807
+ debug.write(f"Error reporting error: {e}\n")
808
+ debug.write(f"Status file: {self.startup_status_file}\n")
809
+ except:
810
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.2.36
3
+ Version: 4.2.38
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=_8H8oebxvokQynjfzzqADPwrmT0PrJLlaKY4vdgLZIM,7
2
+ claude_mpm/VERSION,sha256=tEvkc0qwB7pmw9XnAqXZjl0vfeyZaLGgmuWBqEzbDpA,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
@@ -552,8 +552,8 @@ claude_mpm/services/memory/cache/__init__.py,sha256=6M6-P8ParyxX8vOgp_IxHgLMvacr
552
552
  claude_mpm/services/memory/cache/shared_prompt_cache.py,sha256=crnYPUT8zcS7TvoE1vW7pyaf4T77N5rJ1wUf_YQ2vvo,28704
553
553
  claude_mpm/services/memory/cache/simple_cache.py,sha256=qsTjbcsPxj-kNfaod9VN_uE5NioIwpfkUin_mMVUJCg,10218
554
554
  claude_mpm/services/monitor/__init__.py,sha256=X7gxSLUm9Fg_zEsX6LtCHP2ipF0qj6Emkun20h2So7g,745
555
- claude_mpm/services/monitor/daemon.py,sha256=nkB_xslT4yxIiSVf2u6nGm56rYpkit0WDj4YPWr-osM,22961
556
- claude_mpm/services/monitor/daemon_manager.py,sha256=EiM0-Qfn6MD0GyME2lBNRj8Au33mUF6E2wOdJg4xTDk,27156
555
+ claude_mpm/services/monitor/daemon.py,sha256=YwwxMaqgcEzbP9eRUbmHodkhiNgn0oU2g7xpHDhd00w,24310
556
+ claude_mpm/services/monitor/daemon_manager.py,sha256=0K0lhxNbPGIG6R_rS5B2r8OKJg2ZebVQuwSSDMN22bo,28237
557
557
  claude_mpm/services/monitor/event_emitter.py,sha256=JzRLNg8PUJ5s3ulNnq_D4yqCPItvidJzu8DmFxriieQ,12224
558
558
  claude_mpm/services/monitor/server.py,sha256=aKweXs3saNuPDaPwuoJT9g6kYYHefSiLcGmLdHD6FYM,28579
559
559
  claude_mpm/services/monitor/handlers/__init__.py,sha256=jgPIf4IJVERm_tAeD9834tfx9IcxtlHj5r9rhEWpkfM,701
@@ -644,9 +644,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=zgiwLqh_17WxHpySvUPH65pb4bzIeUGOAYUJ
644
644
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
645
645
  claude_mpm/validation/agent_validator.py,sha256=3Lo6LK-Mw9IdnL_bd3zl_R6FkgSVDYKUUM7EeVVD3jc,20865
646
646
  claude_mpm/validation/frontmatter_validator.py,sha256=u8g4Eyd_9O6ugj7Un47oSGh3kqv4wMkuks2i_CtWRvM,7028
647
- claude_mpm-4.2.36.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
648
- claude_mpm-4.2.36.dist-info/METADATA,sha256=bOjvBE3f3Nq7mhrnOeq8ih3gD6bUdetPTOcvVVOYuOU,14451
649
- claude_mpm-4.2.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
650
- claude_mpm-4.2.36.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
651
- claude_mpm-4.2.36.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
652
- claude_mpm-4.2.36.dist-info/RECORD,,
647
+ claude_mpm-4.2.38.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
648
+ claude_mpm-4.2.38.dist-info/METADATA,sha256=UOe_P7DOkvTJ45o4UP-jG8ntz5Or9h4brwce_hy26mc,14451
649
+ claude_mpm-4.2.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
650
+ claude_mpm-4.2.38.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
651
+ claude_mpm-4.2.38.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
652
+ claude_mpm-4.2.38.dist-info/RECORD,,