claude-mpm 4.2.34__py3-none-any.whl → 4.2.36__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.34
1
+ 4.2.36
@@ -143,14 +143,29 @@ class DaemonManager:
143
143
  Returns:
144
144
  True if port is available, False otherwise
145
145
  """
146
+ # Try to bind to the port using the same method as the actual server
147
+ # We only need to check if we can bind to at least one address family
146
148
  try:
149
+ # Try IPv4 first (most common)
147
150
  test_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
148
151
  test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
149
- test_sock.bind((self.host, self.port))
152
+
153
+ # Use 127.0.0.1 for localhost to match what the server does
154
+ bind_host = "127.0.0.1" if self.host == "localhost" else self.host
155
+ test_sock.bind((bind_host, self.port))
150
156
  test_sock.close()
151
157
  return True
152
158
  except OSError:
153
- return False
159
+ # IPv4 failed, try IPv6
160
+ try:
161
+ test_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
162
+ test_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
163
+ test_sock.bind(("::1", self.port))
164
+ test_sock.close()
165
+ return True
166
+ except:
167
+ # Both IPv4 and IPv6 failed - port is in use
168
+ return False
154
169
 
155
170
  def _kill_processes_on_port(self) -> bool:
156
171
  """Kill processes using the daemon port.
@@ -208,9 +223,32 @@ class DaemonManager:
208
223
  text=True, check=False,
209
224
  )
210
225
 
226
+ # Get full command to check if it's our monitor process
227
+ cmd_info = subprocess.run(
228
+ ["ps", "-p", str(pid), "-o", "command="],
229
+ capture_output=True,
230
+ text=True, check=False,
231
+ )
232
+
233
+ if cmd_info.returncode != 0:
234
+ continue
235
+
236
+ full_command = cmd_info.stdout.strip().lower()
211
237
  process_name = process_info.stdout.strip().lower()
212
- if "python" in process_name or "claude" in process_name:
213
- self.logger.info(f"Killing Python/Claude process {pid}")
238
+
239
+ # Check if this is our monitor/socketio process specifically
240
+ # Look for monitor, socketio, dashboard, or our specific port
241
+ is_monitor = any([
242
+ "monitor" in full_command,
243
+ "socketio" in full_command,
244
+ "dashboard" in full_command,
245
+ f"port={self.port}" in full_command,
246
+ f":{self.port}" in full_command,
247
+ "unified_monitor" in full_command,
248
+ ])
249
+
250
+ if is_monitor and "python" in process_name:
251
+ self.logger.info(f"Killing monitor process {pid}: {full_command[:100]}")
214
252
  os.kill(pid, signal.SIGTERM)
215
253
 
216
254
  # Wait briefly for graceful shutdown
@@ -227,10 +265,12 @@ class DaemonManager:
227
265
  except ProcessLookupError:
228
266
  pass # Process already dead
229
267
  else:
230
- self.logger.warning(
231
- f"Process {pid} ({process_name}) is not a Claude MPM process"
268
+ # Not a monitor process - log but don't fail
269
+ self.logger.info(
270
+ f"Skipping non-monitor process {pid} ({process_name})"
232
271
  )
233
- return False
272
+ # Continue to next PID - don't return False
273
+ continue
234
274
 
235
275
  except (ValueError, ProcessLookupError) as e:
236
276
  self.logger.debug(f"Error handling PID {pid_str}: {e}")
@@ -288,13 +328,16 @@ class DaemonManager:
288
328
  return False
289
329
 
290
330
  def _kill_claude_mpm_processes(self) -> bool:
291
- """Kill any claude-mpm monitor processes.
331
+ """Kill any claude-mpm monitor processes specifically.
332
+
333
+ This targets monitor/dashboard/socketio processes only,
334
+ NOT general Claude instances.
292
335
 
293
336
  Returns:
294
337
  True if successful, False on error
295
338
  """
296
339
  try:
297
- # Look for claude-mpm monitor processes
340
+ # Look for monitor-specific processes
298
341
  result = subprocess.run(["ps", "aux"], capture_output=True, text=True, check=False)
299
342
 
300
343
  if result.returncode != 0:
@@ -304,7 +347,12 @@ class DaemonManager:
304
347
  killed_any = False
305
348
 
306
349
  for line in lines:
307
- if "claude" in line.lower() and "monitor" in line.lower():
350
+ line_lower = line.lower()
351
+ # Only target monitor/dashboard/socketio processes
352
+ if any(["monitor" in line_lower and "claude" in line_lower,
353
+ "dashboard" in line_lower and "claude" in line_lower,
354
+ "socketio" in line_lower,
355
+ f":{self.port}" in line_lower and "python" in line_lower]):
308
356
  parts = line.split()
309
357
  if len(parts) > 1:
310
358
  try:
@@ -498,11 +546,12 @@ class DaemonManager:
498
546
 
499
547
  self.logger.info(f"Daemon process started with PID {os.getpid()}")
500
548
 
501
- # Report successful startup
502
- self._report_startup_success()
549
+ # DO NOT report success here - let the caller report after starting the service
550
+ # This prevents race conditions where we report success before the server starts
551
+ # self._report_startup_success() # REMOVED - caller must report
503
552
 
504
553
  # Note: Daemon process continues running
505
- # Caller is responsible for running the actual service
554
+ # Caller is responsible for running the actual service AND reporting status
506
555
  return True
507
556
 
508
557
  def stop_daemon(self, timeout: int = 10) -> bool:
@@ -238,7 +238,8 @@ class UnifiedMonitorServer:
238
238
  self.logger.info(f"Server running on http://{self.host}:{self.port}")
239
239
  except OSError as e:
240
240
  # Port binding error - make sure it's reported clearly
241
- if "Address already in use" in str(e) or "[Errno 48]" in str(e):
241
+ # Check for common port binding errors
242
+ if "Address already in use" in str(e) or "[Errno 48]" in str(e) or "[Errno 98]" in str(e):
242
243
  error_msg = f"Port {self.port} is already in use. Another process may be using this port."
243
244
  self.logger.error(error_msg)
244
245
  self.startup_error = error_msg
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.2.34
3
+ Version: 4.2.36
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=fG0IZzvJf9mDvrRPugPVez5Sy61s1t2jvQiJ6nH3Xm0,7
2
+ claude_mpm/VERSION,sha256=_8H8oebxvokQynjfzzqADPwrmT0PrJLlaKY4vdgLZIM,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
@@ -553,9 +553,9 @@ claude_mpm/services/memory/cache/shared_prompt_cache.py,sha256=crnYPUT8zcS7TvoE1
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
555
  claude_mpm/services/monitor/daemon.py,sha256=nkB_xslT4yxIiSVf2u6nGm56rYpkit0WDj4YPWr-osM,22961
556
- claude_mpm/services/monitor/daemon_manager.py,sha256=6ZYXgRhwurnPDXxFgk9msLoa7x7ccE64m93FwqWVJfs,24519
556
+ claude_mpm/services/monitor/daemon_manager.py,sha256=EiM0-Qfn6MD0GyME2lBNRj8Au33mUF6E2wOdJg4xTDk,27156
557
557
  claude_mpm/services/monitor/event_emitter.py,sha256=JzRLNg8PUJ5s3ulNnq_D4yqCPItvidJzu8DmFxriieQ,12224
558
- claude_mpm/services/monitor/server.py,sha256=m98Eyv9caxRywJ4JtAdOuv5EB__z7vd2hYRZPwcqFLg,28498
558
+ claude_mpm/services/monitor/server.py,sha256=aKweXs3saNuPDaPwuoJT9g6kYYHefSiLcGmLdHD6FYM,28579
559
559
  claude_mpm/services/monitor/handlers/__init__.py,sha256=jgPIf4IJVERm_tAeD9834tfx9IcxtlHj5r9rhEWpkfM,701
560
560
  claude_mpm/services/monitor/handlers/code_analysis.py,sha256=mHyI27Wp6WVmUBc0m0i991ogyFZBTvkrfR7Kf3EAk5U,11474
561
561
  claude_mpm/services/monitor/handlers/dashboard.py,sha256=uGBhb-6RG6u4WLipUXgdx7RCW-vb_qek5dIfHIwAC7o,9805
@@ -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.34.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
648
- claude_mpm-4.2.34.dist-info/METADATA,sha256=3QnG6eFgBqx7bZXZOn6dTp-PqyMK3GD-c17EbE4TN8o,14451
649
- claude_mpm-4.2.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
650
- claude_mpm-4.2.34.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
651
- claude_mpm-4.2.34.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
652
- claude_mpm-4.2.34.dist-info/RECORD,,
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,,