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 +1 -1
- claude_mpm/services/monitor/daemon.py +37 -10
- claude_mpm/services/monitor/daemon_manager.py +26 -4
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/RECORD +9 -9
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.36.dist-info → claude_mpm-4.2.38.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.2.
|
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
|
-
|
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
|
592
|
-
#
|
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.
|
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
|
-
#
|
605
|
-
|
606
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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,5 +1,5 @@
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=toytnNjkIKPgQaGwDqQdC1rpNTAdSEc6Vja50d7Ovug,4
|
2
|
-
claude_mpm/VERSION,sha256=
|
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=
|
556
|
-
claude_mpm/services/monitor/daemon_manager.py,sha256=
|
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.
|
648
|
-
claude_mpm-4.2.
|
649
|
-
claude_mpm-4.2.
|
650
|
-
claude_mpm-4.2.
|
651
|
-
claude_mpm-4.2.
|
652
|
-
claude_mpm-4.2.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|