claude-mpm 4.2.24__py3-none-any.whl → 4.2.25__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.
@@ -23,6 +23,7 @@ from pathlib import Path
23
23
  from typing import Optional
24
24
 
25
25
  from ...core.logging_config import get_logger
26
+ from ..hook_installer_service import HookInstallerService
26
27
  from .management.health import HealthMonitor
27
28
  from .management.lifecycle import DaemonLifecycle
28
29
  from .server import UnifiedMonitorServer
@@ -59,9 +60,9 @@ class UnifiedMonitorDaemon:
59
60
 
60
61
  # Daemon management with port for verification
61
62
  self.lifecycle = DaemonLifecycle(
62
- pid_file=pid_file or self._get_default_pid_file(),
63
+ pid_file=pid_file or self._get_default_pid_file(),
63
64
  log_file=log_file,
64
- port=port
65
+ port=port,
65
66
  )
66
67
 
67
68
  # Core server
@@ -70,6 +71,9 @@ class UnifiedMonitorDaemon:
70
71
  # Health monitoring
71
72
  self.health_monitor = HealthMonitor(port=port)
72
73
 
74
+ # Hook installer service
75
+ self.hook_installer = HookInstallerService()
76
+
73
77
  # State
74
78
  self.running = False
75
79
  self.shutdown_event = threading.Event()
@@ -100,7 +104,7 @@ class UnifiedMonitorDaemon:
100
104
 
101
105
  def _start_daemon(self, force_restart: bool = False) -> bool:
102
106
  """Start as background daemon process.
103
-
107
+
104
108
  Args:
105
109
  force_restart: If True, restart existing service if it's ours
106
110
  """
@@ -109,14 +113,18 @@ class UnifiedMonitorDaemon:
109
113
  # Check if already running
110
114
  if self.lifecycle.is_running():
111
115
  existing_pid = self.lifecycle.get_pid()
112
-
116
+
113
117
  if force_restart:
114
118
  # Check if it's our service
115
- self.logger.debug(f"Checking if existing daemon (PID: {existing_pid}) is our service...")
119
+ self.logger.debug(
120
+ f"Checking if existing daemon (PID: {existing_pid}) is our service..."
121
+ )
116
122
  is_ours, detected_pid = self.lifecycle.is_our_service(self.host)
117
-
123
+
118
124
  if is_ours:
119
- self.logger.info(f"Force restarting our existing claude-mpm monitor daemon (PID: {detected_pid or existing_pid})")
125
+ self.logger.info(
126
+ f"Force restarting our existing claude-mpm monitor daemon (PID: {detected_pid or existing_pid})"
127
+ )
120
128
  # Stop the existing daemon
121
129
  if self.lifecycle.stop_daemon():
122
130
  # Wait a moment for port to be released
@@ -125,19 +133,27 @@ class UnifiedMonitorDaemon:
125
133
  self.logger.error("Failed to stop existing daemon for restart")
126
134
  return False
127
135
  else:
128
- self.logger.warning(f"Port {self.port} is in use by another service (PID: {existing_pid}). Cannot force restart.")
129
- self.logger.info("To restart the claude-mpm monitor, first stop the other service or use a different port.")
136
+ self.logger.warning(
137
+ f"Port {self.port} is in use by another service (PID: {existing_pid}). Cannot force restart."
138
+ )
139
+ self.logger.info(
140
+ "To restart the claude-mpm monitor, first stop the other service or use a different port."
141
+ )
130
142
  return False
131
143
  else:
132
144
  self.logger.warning(f"Daemon already running with PID {existing_pid}")
133
145
  return False
134
-
146
+
135
147
  # Check for orphaned processes (service running but no PID file)
136
148
  elif force_restart:
137
- self.logger.debug("No PID file found, checking for orphaned claude-mpm service...")
149
+ self.logger.debug(
150
+ "No PID file found, checking for orphaned claude-mpm service..."
151
+ )
138
152
  is_ours, pid = self.lifecycle.is_our_service(self.host)
139
153
  if is_ours and pid:
140
- self.logger.info(f"Found orphaned claude-mpm monitor service (PID: {pid}), force restarting")
154
+ self.logger.info(
155
+ f"Found orphaned claude-mpm monitor service (PID: {pid}), force restarting"
156
+ )
141
157
  # Try to kill the orphaned process
142
158
  try:
143
159
  os.kill(pid, signal.SIGTERM)
@@ -155,7 +171,7 @@ class UnifiedMonitorDaemon:
155
171
  except Exception as e:
156
172
  self.logger.error(f"Failed to kill orphaned process: {e}")
157
173
  return False
158
-
174
+
159
175
  # Verify port is available before forking
160
176
  port_available, error_msg = self.lifecycle.verify_port_available(self.host)
161
177
  if not port_available:
@@ -186,7 +202,7 @@ class UnifiedMonitorDaemon:
186
202
 
187
203
  def _start_foreground(self, force_restart: bool = False) -> bool:
188
204
  """Start in foreground mode.
189
-
205
+
190
206
  Args:
191
207
  force_restart: If True, restart existing service if it's ours
192
208
  """
@@ -195,14 +211,18 @@ class UnifiedMonitorDaemon:
195
211
  # Check if already running (check PID file even in foreground mode)
196
212
  if self.lifecycle.is_running():
197
213
  existing_pid = self.lifecycle.get_pid()
198
-
214
+
199
215
  if force_restart:
200
216
  # Check if it's our service
201
- self.logger.debug(f"Checking if existing daemon (PID: {existing_pid}) is our service...")
217
+ self.logger.debug(
218
+ f"Checking if existing daemon (PID: {existing_pid}) is our service..."
219
+ )
202
220
  is_ours, detected_pid = self.lifecycle.is_our_service(self.host)
203
-
221
+
204
222
  if is_ours:
205
- self.logger.info(f"Force restarting our existing claude-mpm monitor daemon (PID: {detected_pid or existing_pid})")
223
+ self.logger.info(
224
+ f"Force restarting our existing claude-mpm monitor daemon (PID: {detected_pid or existing_pid})"
225
+ )
206
226
  # Stop the existing daemon
207
227
  if self.lifecycle.stop_daemon():
208
228
  # Wait a moment for port to be released
@@ -211,21 +231,29 @@ class UnifiedMonitorDaemon:
211
231
  self.logger.error("Failed to stop existing daemon for restart")
212
232
  return False
213
233
  else:
214
- self.logger.warning(f"Port {self.port} is in use by another service (PID: {existing_pid}). Cannot force restart.")
215
- self.logger.info("To restart the claude-mpm monitor, first stop the other service or use a different port.")
234
+ self.logger.warning(
235
+ f"Port {self.port} is in use by another service (PID: {existing_pid}). Cannot force restart."
236
+ )
237
+ self.logger.info(
238
+ "To restart the claude-mpm monitor, first stop the other service or use a different port."
239
+ )
216
240
  return False
217
241
  else:
218
242
  self.logger.warning(
219
243
  f"Monitor daemon already running with PID {existing_pid}"
220
244
  )
221
245
  return False
222
-
246
+
223
247
  # Check for orphaned processes (service running but no PID file)
224
248
  elif force_restart:
225
- self.logger.debug("No PID file found, checking for orphaned claude-mpm service...")
249
+ self.logger.debug(
250
+ "No PID file found, checking for orphaned claude-mpm service..."
251
+ )
226
252
  is_ours, pid = self.lifecycle.is_our_service(self.host)
227
253
  if is_ours and pid:
228
- self.logger.info(f"Found orphaned claude-mpm monitor service (PID: {pid}), force restarting")
254
+ self.logger.info(
255
+ f"Found orphaned claude-mpm monitor service (PID: {pid}), force restarting"
256
+ )
229
257
  # Try to kill the orphaned process
230
258
  try:
231
259
  os.kill(pid, signal.SIGTERM)
@@ -271,6 +299,26 @@ class UnifiedMonitorDaemon:
271
299
  self.lifecycle._report_startup_error(error_msg)
272
300
  return False
273
301
 
302
+ # Check and install hooks if needed
303
+ try:
304
+ if not self.hook_installer.is_hooks_configured():
305
+ self.logger.info("Claude Code hooks not configured, installing...")
306
+ if self.hook_installer.install_hooks():
307
+ self.logger.info("Claude Code hooks installed successfully")
308
+ else:
309
+ # Don't fail startup if hook installation fails
310
+ # The monitor can still function without hooks
311
+ self.logger.warning(
312
+ "Failed to install Claude Code hooks. Monitor will run without hook integration."
313
+ )
314
+ else:
315
+ self.logger.info("Claude Code hooks are already configured")
316
+ except Exception as e:
317
+ # Don't fail startup if hook checking fails
318
+ self.logger.warning(
319
+ f"Error checking/installing hooks: {e}. Monitor will run without hook integration."
320
+ )
321
+
274
322
  # Start health monitoring
275
323
  self.health_monitor.start()
276
324
 
@@ -285,7 +333,7 @@ class UnifiedMonitorDaemon:
285
333
 
286
334
  self.running = True
287
335
  self.logger.info("Unified monitor daemon started successfully")
288
-
336
+
289
337
  # Report successful startup to parent (for daemon mode)
290
338
  if self.daemon_mode:
291
339
  self.lifecycle._report_startup_success()