claude-mpm 4.7.9__py3-none-any.whl → 4.7.11__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.7.9
1
+ 4.7.11
@@ -36,6 +36,7 @@ from .commands import ( # run_guarded_session is imported lazily to avoid loadi
36
36
  )
37
37
  from .commands.analyze_code import manage_analyze_code
38
38
  from .commands.dashboard import manage_dashboard
39
+ from .commands.upgrade import upgrade
39
40
  from .parser import create_parser, preprocess_args
40
41
  from .utils import ensure_directories, setup_logging
41
42
 
@@ -232,6 +233,9 @@ def main(argv: Optional[list] = None):
232
233
  # Re-enabled: MCP pre-warming is safe with subprocess daemon (v4.2.40)
233
234
  # The subprocess approach avoids fork() issues entirely
234
235
  _verify_mcp_gateway_startup()
236
+
237
+ # Check for updates (non-blocking, async)
238
+ _check_for_updates_async()
235
239
  else:
236
240
  # Still need directories for configure command to work
237
241
  ensure_directories()
@@ -544,6 +548,83 @@ def _verify_mcp_gateway_startup():
544
548
  # Continue execution - MCP gateway issues shouldn't block startup
545
549
 
546
550
 
551
+ def _check_for_updates_async():
552
+ """
553
+ Check for updates in background thread (non-blocking).
554
+
555
+ WHY: Users should be notified of new versions and have an easy way to upgrade
556
+ without manually checking PyPI/npm. This runs asynchronously on startup to avoid
557
+ blocking the CLI.
558
+
559
+ DESIGN DECISION: This is non-blocking and non-critical - failures are logged
560
+ but don't prevent startup. Only runs for pip/pipx/npm installations, skips
561
+ editable/development installations.
562
+ """
563
+
564
+ def run_update_check():
565
+ """Inner function to run in background thread."""
566
+ loop = None
567
+ try:
568
+ import asyncio
569
+
570
+ from ..core.logger import get_logger
571
+ from ..services.self_upgrade_service import SelfUpgradeService
572
+
573
+ logger = get_logger("upgrade_check")
574
+
575
+ # Create new event loop for this thread
576
+ loop = asyncio.new_event_loop()
577
+ asyncio.set_event_loop(loop)
578
+
579
+ # Create upgrade service and check for updates
580
+ upgrade_service = SelfUpgradeService()
581
+
582
+ # Skip for editable installs (development mode)
583
+ from ..services.self_upgrade_service import InstallationMethod
584
+
585
+ if upgrade_service.installation_method == InstallationMethod.EDITABLE:
586
+ logger.debug("Skipping version check for editable installation")
587
+ return
588
+
589
+ # Check and prompt for upgrade if available (non-blocking)
590
+ loop.run_until_complete(upgrade_service.check_and_prompt_on_startup())
591
+
592
+ except Exception as e:
593
+ # Non-critical - log but don't fail startup
594
+ try:
595
+ from ..core.logger import get_logger
596
+
597
+ logger = get_logger("upgrade_check")
598
+ logger.debug(f"Update check failed (non-critical): {e}")
599
+ except Exception:
600
+ pass # Avoid any errors in error handling
601
+ finally:
602
+ # Properly clean up event loop
603
+ if loop is not None:
604
+ try:
605
+ # Cancel all running tasks
606
+ pending = asyncio.all_tasks(loop)
607
+ for task in pending:
608
+ task.cancel()
609
+ # Wait for tasks to complete cancellation
610
+ if pending:
611
+ loop.run_until_complete(
612
+ asyncio.gather(*pending, return_exceptions=True)
613
+ )
614
+ except Exception:
615
+ pass # Ignore cleanup errors
616
+ finally:
617
+ loop.close()
618
+ # Clear the event loop reference to help with cleanup
619
+ asyncio.set_event_loop(None)
620
+
621
+ # Run update check in background thread to avoid blocking startup
622
+ import threading
623
+
624
+ update_check_thread = threading.Thread(target=run_update_check, daemon=True)
625
+ update_check_thread.start()
626
+
627
+
547
628
  def _ensure_run_attributes(args):
548
629
  """
549
630
  Ensure run command attributes exist when defaulting to run.
@@ -657,6 +738,7 @@ def _execute_command(command: str, args) -> int:
657
738
  CLICommands.CLEANUP.value: cleanup_memory,
658
739
  CLICommands.MCP.value: manage_mcp,
659
740
  CLICommands.DOCTOR.value: run_doctor,
741
+ CLICommands.UPGRADE.value: upgrade,
660
742
  "debug": manage_debug, # Add debug command
661
743
  "mpm-init": None, # Will be handled separately with lazy import
662
744
  }
@@ -0,0 +1,152 @@
1
+ """
2
+ Upgrade command implementation for claude-mpm.
3
+
4
+ WHY: This module provides a manual upgrade command that allows users to check
5
+ for and install the latest version of claude-mpm without waiting for the
6
+ automatic startup check.
7
+
8
+ DESIGN DECISIONS:
9
+ - Use BaseCommand for consistent CLI patterns
10
+ - Leverage SelfUpgradeService for upgrade functionality
11
+ - Support multiple installation methods (pip, pipx, npm)
12
+ - Skip editable/development installations (must upgrade manually)
13
+ - Provide clear feedback on available updates and upgrade progress
14
+ """
15
+
16
+ import asyncio
17
+
18
+ from ..shared import BaseCommand, CommandResult
19
+
20
+
21
+ class UpgradeCommand(BaseCommand):
22
+ """Upgrade command using shared utilities."""
23
+
24
+ def __init__(self):
25
+ super().__init__("upgrade")
26
+
27
+ def validate_args(self, args) -> str:
28
+ """Validate command arguments."""
29
+ # Upgrade command doesn't require specific validation
30
+ return None
31
+
32
+ def run(self, args) -> CommandResult:
33
+ """Execute the upgrade command."""
34
+ try:
35
+ from ...services.self_upgrade_service import (
36
+ InstallationMethod,
37
+ SelfUpgradeService,
38
+ )
39
+
40
+ # Create upgrade service
41
+ upgrade_service = SelfUpgradeService()
42
+
43
+ # Check installation method
44
+ if upgrade_service.installation_method == InstallationMethod.EDITABLE:
45
+ self.logger.info(
46
+ "Editable installation detected - upgrade must be done manually"
47
+ )
48
+ print("\n⚠️ Editable Installation Detected")
49
+ print(
50
+ "\nYou are running claude-mpm from an editable installation (development mode)."
51
+ )
52
+ print("To upgrade, run:")
53
+ print(" cd /path/to/claude-mpm")
54
+ print(" git pull")
55
+ print(" pip install -e .")
56
+ return CommandResult.success_result(
57
+ "Upgrade information provided for editable installation"
58
+ )
59
+
60
+ # Check for updates
61
+ print("\n🔍 Checking for updates...")
62
+ loop = asyncio.new_event_loop()
63
+ asyncio.set_event_loop(loop)
64
+ try:
65
+ update_info = loop.run_until_complete(
66
+ upgrade_service.check_for_update()
67
+ )
68
+ finally:
69
+ loop.close()
70
+
71
+ if not update_info or not update_info.get("update_available"):
72
+ print(
73
+ f"\n✅ You are already on the latest version (v{upgrade_service.current_version})"
74
+ )
75
+ return CommandResult.success_result("Already on latest version")
76
+
77
+ # Display update information
78
+ current = update_info["current"]
79
+ latest = update_info["latest"]
80
+ method = update_info.get("installation_method", "unknown")
81
+
82
+ print("\n🎉 New version available!")
83
+ print(f" Current: v{current}")
84
+ print(f" Latest: v{latest}")
85
+ print(f" Installation method: {method}")
86
+
87
+ # Check if --yes flag is set for non-interactive upgrade
88
+ force_upgrade = getattr(args, "yes", False) or getattr(args, "force", False)
89
+
90
+ if not force_upgrade:
91
+ # Prompt user for confirmation
92
+ if not upgrade_service.prompt_for_upgrade(update_info):
93
+ print("\n⏸️ Upgrade cancelled by user")
94
+ return CommandResult.success_result("Upgrade cancelled by user")
95
+
96
+ # Perform upgrade
97
+ success, message = upgrade_service.perform_upgrade(update_info)
98
+ print(f"\n{message}")
99
+
100
+ if success:
101
+ # Restart after successful upgrade
102
+ upgrade_service.restart_after_upgrade()
103
+ # Note: This line won't be reached as restart replaces process
104
+ return CommandResult.success_result(f"Upgraded to v{latest}")
105
+ return CommandResult.error_result("Upgrade failed")
106
+
107
+ except Exception as e:
108
+ self.logger.error(f"Error during upgrade: {e}", exc_info=True)
109
+ return CommandResult.error_result(f"Error during upgrade: {e}")
110
+
111
+
112
+ def add_upgrade_parser(subparsers):
113
+ """
114
+ Add upgrade command parser.
115
+
116
+ WHY: This command helps users check for and install the latest version of
117
+ claude-mpm without waiting for the automatic startup check.
118
+
119
+ Args:
120
+ subparsers: The subparser action object to add the upgrade command to
121
+ """
122
+ parser = subparsers.add_parser(
123
+ "upgrade",
124
+ help="Check for and install latest claude-mpm version",
125
+ description="Check for updates and upgrade claude-mpm to the latest version from PyPI/npm",
126
+ )
127
+
128
+ parser.add_argument(
129
+ "-y",
130
+ "--yes",
131
+ action="store_true",
132
+ help="Skip confirmation prompt and upgrade immediately if available",
133
+ )
134
+
135
+ parser.add_argument(
136
+ "--force",
137
+ action="store_true",
138
+ help="Force upgrade even if already on latest version (alias for --yes)",
139
+ )
140
+
141
+ return parser
142
+
143
+
144
+ def upgrade(args):
145
+ """
146
+ Main entry point for upgrade command.
147
+
148
+ This function maintains backward compatibility while using the new BaseCommand pattern.
149
+ """
150
+ command = UpgradeCommand()
151
+ result = command.execute(args)
152
+ return result.exit_code
@@ -423,6 +423,11 @@ def create_parser(
423
423
 
424
424
  add_doctor_parser(subparsers)
425
425
 
426
+ # Add upgrade command
427
+ from ..commands.upgrade import add_upgrade_parser
428
+
429
+ add_upgrade_parser(subparsers)
430
+
426
431
  # Add verify command for MCP service verification
427
432
  from ..commands.verify import add_parser as add_verify_parser
428
433
 
claude_mpm/constants.py CHANGED
@@ -44,6 +44,7 @@ class CLICommands(str, Enum):
44
44
  MCP = "mcp"
45
45
  DOCTOR = "doctor"
46
46
  DASHBOARD = "dashboard"
47
+ UPGRADE = "upgrade"
47
48
 
48
49
  def with_prefix(self, prefix: CLIPrefix = CLIPrefix.MPM) -> str:
49
50
  """Get command with prefix."""
@@ -40,9 +40,11 @@ class MemoryManager(IMemoryManager):
40
40
  4. Legacy format migration (e.g., PM.md -> PM_memories.md)
41
41
  5. Memory caching for performance
42
42
 
43
- Memory Loading Order:
44
- - User-level memories: ~/.claude-mpm/memories/ (global defaults)
45
- - Project-level memories: ./.claude-mpm/memories/ (overrides user)
43
+ Memory Scope:
44
+ - Project-level ONLY: ./.claude-mpm/memories/ (project-scoped isolation)
45
+ - User-level memories are NOT loaded to prevent cross-project contamination
46
+
47
+ Note: As of v4.7.10+, memories are strictly project-scoped for complete isolation.
46
48
  """
47
49
 
48
50
  def __init__(
@@ -279,7 +281,10 @@ class MemoryManager(IMemoryManager):
279
281
 
280
282
  def _load_actual_memories(self, deployed_agents: Set[str]) -> Dict[str, Any]:
281
283
  """
282
- Load actual memories from both user and project directories.
284
+ Load actual memories from project directory only.
285
+
286
+ Memories are project-scoped to ensure complete isolation between projects.
287
+ User-level memories are no longer supported to prevent cross-project contamination.
283
288
 
284
289
  Args:
285
290
  deployed_agents: Set of deployed agent names
@@ -287,32 +292,14 @@ class MemoryManager(IMemoryManager):
287
292
  Returns:
288
293
  Dictionary with actual_memories and agent_memories
289
294
  """
290
- # Define memory directories in priority order
291
- user_memories_dir = Path.home() / ".claude-mpm" / "memories"
295
+ # Define project memory directory (project-scoped only)
292
296
  project_memories_dir = Path.cwd() / ".claude-mpm" / "memories"
293
297
 
294
298
  # Dictionary to store aggregated memories
295
299
  pm_memories = []
296
300
  agent_memories_dict = {}
297
301
 
298
- # Load memories from user directory first
299
- if user_memories_dir.exists():
300
- self.logger.info(
301
- f"Loading user-level memory files from: {user_memories_dir}"
302
- )
303
- self._load_memories_from_directory(
304
- user_memories_dir,
305
- deployed_agents,
306
- pm_memories,
307
- agent_memories_dict,
308
- "user",
309
- )
310
- else:
311
- self.logger.debug(
312
- f"No user memories directory found at: {user_memories_dir}"
313
- )
314
-
315
- # Load memories from project directory (overrides user memories)
302
+ # Load memories from project directory only
316
303
  if project_memories_dir.exists():
317
304
  self.logger.info(
318
305
  f"Loading project-level memory files from: {project_memories_dir}"
@@ -0,0 +1,342 @@
1
+ """
2
+ Self-Upgrade Service
3
+ ====================
4
+
5
+ Handles version checking and self-upgrade functionality for claude-mpm.
6
+ Supports pip, pipx, and npm installations with automatic detection.
7
+
8
+ WHY: Users should be notified of updates and have an easy way to upgrade
9
+ without manually running installation commands.
10
+
11
+ DESIGN DECISIONS:
12
+ - Detects installation method (pip/pipx/npm/editable)
13
+ - Non-blocking version checks with caching
14
+ - Interactive upgrade prompts with confirmation
15
+ - Automatic restart after upgrade
16
+ - Graceful failure handling (never breaks existing installation)
17
+ """
18
+
19
+ import os
20
+ import subprocess
21
+ import sys
22
+ from datetime import datetime, timezone
23
+ from pathlib import Path
24
+ from typing import Dict, Optional, Tuple
25
+
26
+ from packaging import version
27
+
28
+ from ..core.logger import get_logger
29
+ from ..core.unified_paths import PathContext
30
+ from .mcp_gateway.utils.package_version_checker import PackageVersionChecker
31
+
32
+
33
+ class InstallationMethod:
34
+ """Installation method enumeration."""
35
+
36
+ PIP = "pip"
37
+ PIPX = "pipx"
38
+ NPM = "npm"
39
+ EDITABLE = "editable"
40
+ UNKNOWN = "unknown"
41
+
42
+
43
+ class SelfUpgradeService:
44
+ """
45
+ Service for checking and performing self-upgrades.
46
+
47
+ Capabilities:
48
+ - Detect current installation method
49
+ - Check PyPI/npm for latest version
50
+ - Prompt user for upgrade confirmation
51
+ - Execute upgrade command
52
+ - Restart after upgrade
53
+ """
54
+
55
+ def __init__(self):
56
+ """Initialize the self-upgrade service."""
57
+ self.logger = get_logger("SelfUpgradeService")
58
+ self.version_checker = PackageVersionChecker()
59
+ self.current_version = self._get_current_version()
60
+ self.installation_method = self._detect_installation_method()
61
+
62
+ def _get_current_version(self) -> str:
63
+ """
64
+ Get the current installed version.
65
+
66
+ Returns:
67
+ Version string (e.g., "4.7.10")
68
+ """
69
+ try:
70
+ from .. import __version__
71
+
72
+ return __version__
73
+ except ImportError:
74
+ # Fallback to VERSION file
75
+ try:
76
+ version_file = Path(__file__).parent.parent / "VERSION"
77
+ if version_file.exists():
78
+ return version_file.read_text().strip()
79
+ except Exception:
80
+ pass
81
+
82
+ return "unknown"
83
+
84
+ def _detect_installation_method(self) -> str:
85
+ """
86
+ Detect how claude-mpm was installed.
87
+
88
+ Returns:
89
+ Installation method constant
90
+ """
91
+ # Check for editable install
92
+ if PathContext.detect_deployment_context().name in [
93
+ "DEVELOPMENT",
94
+ "EDITABLE_INSTALL",
95
+ ]:
96
+ return InstallationMethod.EDITABLE
97
+
98
+ # Check for pipx by looking at executable path
99
+ executable = sys.executable
100
+ if "pipx" in executable:
101
+ return InstallationMethod.PIPX
102
+
103
+ # Check if npm wrapper is present
104
+ try:
105
+ result = subprocess.run(
106
+ ["npm", "list", "-g", "claude-mpm"],
107
+ check=False,
108
+ capture_output=True,
109
+ text=True,
110
+ timeout=5,
111
+ )
112
+ if result.returncode == 0 and "claude-mpm" in result.stdout:
113
+ return InstallationMethod.NPM
114
+ except Exception:
115
+ pass
116
+
117
+ # Default to pip
118
+ return InstallationMethod.PIP
119
+
120
+ async def check_for_update(
121
+ self, cache_ttl: Optional[int] = None
122
+ ) -> Optional[Dict[str, any]]:
123
+ """
124
+ Check if an update is available.
125
+
126
+ Args:
127
+ cache_ttl: Cache time-to-live in seconds (default: 24 hours)
128
+
129
+ Returns:
130
+ Dict with update info or None:
131
+ {
132
+ "current": "4.7.10",
133
+ "latest": "4.7.11",
134
+ "update_available": True,
135
+ "installation_method": "pipx",
136
+ "upgrade_command": "pipx upgrade claude-mpm"
137
+ }
138
+ """
139
+ if self.current_version == "unknown":
140
+ self.logger.warning("Cannot check for updates: version unknown")
141
+ return None
142
+
143
+ # Check PyPI for Python installations
144
+ if self.installation_method in [
145
+ InstallationMethod.PIP,
146
+ InstallationMethod.PIPX,
147
+ ]:
148
+ result = await self.version_checker.check_for_update(
149
+ "claude-mpm", self.current_version, cache_ttl
150
+ )
151
+ if result and result.get("update_available"):
152
+ result["installation_method"] = self.installation_method
153
+ result["upgrade_command"] = self._get_upgrade_command()
154
+ return result
155
+
156
+ # Check npm for npm installations
157
+ elif self.installation_method == InstallationMethod.NPM:
158
+ npm_version = await self._check_npm_version()
159
+ if npm_version:
160
+ current_ver = version.parse(self.current_version)
161
+ latest_ver = version.parse(npm_version)
162
+ if latest_ver > current_ver:
163
+ return {
164
+ "current": self.current_version,
165
+ "latest": npm_version,
166
+ "update_available": True,
167
+ "installation_method": InstallationMethod.NPM,
168
+ "upgrade_command": self._get_upgrade_command(),
169
+ "checked_at": datetime.now(timezone.utc).isoformat(),
170
+ }
171
+
172
+ return None
173
+
174
+ async def _check_npm_version(self) -> Optional[str]:
175
+ """
176
+ Check npm registry for latest version.
177
+
178
+ Returns:
179
+ Latest version string or None
180
+ """
181
+ try:
182
+ result = subprocess.run(
183
+ ["npm", "view", "claude-mpm", "version"],
184
+ check=False,
185
+ capture_output=True,
186
+ text=True,
187
+ timeout=10,
188
+ )
189
+ if result.returncode == 0:
190
+ return result.stdout.strip()
191
+ except Exception as e:
192
+ self.logger.debug(f"npm version check failed: {e}")
193
+
194
+ return None
195
+
196
+ def _get_upgrade_command(self) -> str:
197
+ """
198
+ Get the appropriate upgrade command for current installation method.
199
+
200
+ Returns:
201
+ Shell command string to upgrade claude-mpm
202
+ """
203
+ if self.installation_method == InstallationMethod.PIPX:
204
+ return "pipx upgrade claude-mpm"
205
+ if self.installation_method == InstallationMethod.NPM:
206
+ return "npm update -g claude-mpm"
207
+ if self.installation_method == InstallationMethod.PIP:
208
+ return f"{sys.executable} -m pip install --upgrade claude-mpm"
209
+ if self.installation_method == InstallationMethod.EDITABLE:
210
+ return "git pull && pip install -e ."
211
+ return "pip install --upgrade claude-mpm"
212
+
213
+ def prompt_for_upgrade(self, update_info: Dict[str, any]) -> bool:
214
+ """
215
+ Prompt user to upgrade.
216
+
217
+ Args:
218
+ update_info: Update information dict
219
+
220
+ Returns:
221
+ True if user confirms upgrade, False otherwise
222
+ """
223
+ current = update_info["current"]
224
+ latest = update_info["latest"]
225
+ method = update_info.get("installation_method", "unknown")
226
+
227
+ print("\n🎉 New version available!")
228
+ print(f" Current: v{current}")
229
+ print(f" Latest: v{latest}")
230
+ print(f" Installation method: {method}")
231
+ print(f"\nTo upgrade, run: {update_info['upgrade_command']}")
232
+
233
+ try:
234
+ response = input("\nWould you like to upgrade now? [y/N]: ").strip().lower()
235
+ return response in ["y", "yes"]
236
+ except (KeyboardInterrupt, EOFError):
237
+ print("\n")
238
+ return False
239
+
240
+ def perform_upgrade(self, update_info: Dict[str, any]) -> Tuple[bool, str]:
241
+ """
242
+ Perform the upgrade.
243
+
244
+ Args:
245
+ update_info: Update information dict
246
+
247
+ Returns:
248
+ Tuple of (success: bool, message: str)
249
+ """
250
+ command = update_info["upgrade_command"]
251
+
252
+ # Don't upgrade editable installs automatically
253
+ if self.installation_method == InstallationMethod.EDITABLE:
254
+ return (
255
+ False,
256
+ "Editable installation detected. Please update manually with: git pull && pip install -e .",
257
+ )
258
+
259
+ print("\n⏳ Upgrading claude-mpm...")
260
+ print(f" Running: {command}")
261
+
262
+ try:
263
+ # Execute upgrade command
264
+ result = subprocess.run(
265
+ command,
266
+ check=False,
267
+ shell=True,
268
+ capture_output=True,
269
+ text=True,
270
+ timeout=300, # 5 minutes
271
+ )
272
+
273
+ if result.returncode == 0:
274
+ return (True, f"✅ Successfully upgraded to v{update_info['latest']}")
275
+ error_msg = result.stderr or result.stdout or "Unknown error"
276
+ return (False, f"❌ Upgrade failed: {error_msg}")
277
+
278
+ except subprocess.TimeoutExpired:
279
+ return (False, "❌ Upgrade timed out")
280
+ except Exception as e:
281
+ return (False, f"❌ Upgrade failed: {e!s}")
282
+
283
+ def restart_after_upgrade(self) -> None:
284
+ """
285
+ Restart claude-mpm after a successful upgrade.
286
+
287
+ Preserves original command line arguments.
288
+ """
289
+ print("\n🔄 Restarting claude-mpm...")
290
+
291
+ try:
292
+ # Get current command line arguments
293
+ args = sys.argv[:]
294
+
295
+ # Replace current process with new one
296
+ if self.installation_method == InstallationMethod.PIPX:
297
+ # Use pipx run
298
+ os.execvp("pipx", ["pipx", "run", "claude-mpm", *args[1:]])
299
+ elif self.installation_method == InstallationMethod.NPM:
300
+ # Use npm executable
301
+ os.execvp("claude-mpm", args)
302
+ else:
303
+ # Use Python executable
304
+ os.execvp(sys.executable, [sys.executable, *args])
305
+
306
+ except Exception as e:
307
+ self.logger.error(f"Failed to restart: {e}")
308
+ print(f"\n⚠️ Restart failed: {e}")
309
+ print("Please restart claude-mpm manually.")
310
+
311
+ async def check_and_prompt_on_startup(
312
+ self, auto_upgrade: bool = False
313
+ ) -> Optional[Dict[str, any]]:
314
+ """
315
+ Check for updates on startup and optionally prompt user.
316
+
317
+ Args:
318
+ auto_upgrade: If True, upgrade without prompting (use with caution)
319
+
320
+ Returns:
321
+ Update info if available, None otherwise
322
+ """
323
+ # Skip for editable installs
324
+ if self.installation_method == InstallationMethod.EDITABLE:
325
+ return None
326
+
327
+ try:
328
+ update_info = await self.check_for_update()
329
+
330
+ if update_info and update_info.get("update_available"):
331
+ if auto_upgrade or self.prompt_for_upgrade(update_info):
332
+ success, message = self.perform_upgrade(update_info)
333
+ print(message)
334
+ if success:
335
+ self.restart_after_upgrade()
336
+
337
+ return update_info
338
+
339
+ except Exception as e:
340
+ self.logger.debug(f"Startup version check failed: {e}")
341
+
342
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.7.9
3
+ Version: 4.7.11
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,8 +1,8 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=7-IAGCtmvIwdixVQJDoq-zKnNOnvOHQb0ZEINbbBPJ4,6
2
+ claude_mpm/VERSION,sha256=8NJI62Tp7GTnD5qeEDJUZAnPvuDLKbXAbLj5maMHLnM,7
3
3
  claude_mpm/__init__.py,sha256=UCw6j9e_tZQ3kJtTqmdfNv7MHyw9nD1jkj80WurwM2g,2064
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
- claude_mpm/constants.py,sha256=cChN3myrAcF3jC-6DvHnBFTEnwlDk-TAsIXPvUZr_yw,5953
5
+ claude_mpm/constants.py,sha256=sLjJF6Kw7H4V9WWeaEYltM-77TgXqzEMX5vx4ukM5-0,5977
6
6
  claude_mpm/init.py,sha256=HFJR_JmTHa53FAhbGusm3P1iXT6VR6V7S-YJz4pOZ1Q,15967
7
7
  claude_mpm/ticket_wrapper.py,sha256=qe5xY579t7_7fK5nyeAfHN_fr7CXdeOD3jfXEc8-7yo,828
8
8
  claude_mpm/agents/BASE_AGENT_TEMPLATE.md,sha256=aK9qxS1FRpm_8VaB5GI2I6YA9Wr8dGHuea_txMFe44M,5524
@@ -64,7 +64,7 @@ claude_mpm/agents/templates/.claude-mpm/memories/README.md,sha256=vEiG7cPjHRZfwX
64
64
  claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md,sha256=KMZSJrQi-wHOwfl2C0m3A4PpC4QuBtDolAtVybGahKc,77
65
65
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md,sha256=UBm4BycXtdaa-_l1VCh0alTGGOUSsnCbpKwbFuI-mUY,2219
66
66
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md,sha256=oPvFSYFnmJ4TkbTe4AZnNHWaJMJ-xqZP2WM6scUKQKo,13089
67
- claude_mpm/cli/__init__.py,sha256=0qyZe1R_9I_GJdyIfF6GatbZUVcaclxtvglPjN7dAIA,26270
67
+ claude_mpm/cli/__init__.py,sha256=Ed8uPUqS5FmIAMxxIPxpo5JJX2ZWXIe5v-vx8K9jBEE,29373
68
68
  claude_mpm/cli/__main__.py,sha256=WnVGBwe10InxuZjJRFdwuMF6Gh16aXox6zFgxr0sRXk,847
69
69
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
70
70
  claude_mpm/cli/startup_logging.py,sha256=RTuyd6CbhiFQz7Z07LDDhK_ZAnZfuJ9B0NghVSntHFI,29390
@@ -102,6 +102,7 @@ claude_mpm/cli/commands/run.py,sha256=PB2H55piOPTy4yo4OBgbUCjMlcz9K79wbwpxQVc9m5
102
102
  claude_mpm/cli/commands/search.py,sha256=_0qbUnop8v758MHsB0fAop8FVxwygD59tec_-iN7pLE,9806
103
103
  claude_mpm/cli/commands/tickets.py,sha256=kl2dklTBnG3Y4jUUJ_PcEVsTx4CtVJfkGWboWBx_mQM,21234
104
104
  claude_mpm/cli/commands/uninstall.py,sha256=KGlVG6veEs1efLVjrZ3wSty7e1zVR9wpt-VXQA1RzWw,5945
105
+ claude_mpm/cli/commands/upgrade.py,sha256=NYMVONNlj78WHoQ6eyVInroE95AeQxUY2_TpjYFTdYE,5409
105
106
  claude_mpm/cli/commands/verify.py,sha256=wmu2UYINK15q2e34TdlTyamvtLDE7r3Oj_XT9zpT5Kk,3687
106
107
  claude_mpm/cli/interactive/__init__.py,sha256=vQqUCgPFvLYA1Vkq-5pnY7Ow3A-IgdM0SByfNL1ZLTk,433
107
108
  claude_mpm/cli/interactive/agent_wizard.py,sha256=v3nKcLusU49ewjCqvgUWsG35UGc82pC7_Uv-ZzAHZ-c,36201
@@ -110,7 +111,7 @@ claude_mpm/cli/parsers/agent_manager_parser.py,sha256=TQEIm638ELM4X_AAGcn6WrJxlt
110
111
  claude_mpm/cli/parsers/agents_parser.py,sha256=R-9ESNXdjqr5iCEIcmbb2EPvcswW9UfJzMj5bAkgI4U,9042
111
112
  claude_mpm/cli/parsers/analyze_code_parser.py,sha256=cpJSMFbc3mqB4qrMBIEZiikzPekC2IQX-cjt9U2fHW4,5356
112
113
  claude_mpm/cli/parsers/analyze_parser.py,sha256=E00Ao0zwzbJPchs_AJt-aoQ7LQEtJPXRCNQ6Piivb4o,3908
113
- claude_mpm/cli/parsers/base_parser.py,sha256=Wejn4lAo-rMUQVP13PAehE6NoqmH2AD50HLKDf3QAKM,14169
114
+ claude_mpm/cli/parsers/base_parser.py,sha256=iGYJ_-wIXkL4iVclJgrzQ2kz_of3CIqCwIM-FnFKEQI,14298
114
115
  claude_mpm/cli/parsers/config_parser.py,sha256=wp6NbV8_p9txP28MXFcQrri0JDIfGFM7u4aJbYJXcYQ,2699
115
116
  claude_mpm/cli/parsers/configure_parser.py,sha256=t3cwAQX3BfljDDRJH3i0LplpRprw5jdKcI9Uy3M8xtE,4382
116
117
  claude_mpm/cli/parsers/dashboard_parser.py,sha256=JBCM6v_iZhADr_Fwtk_d3up9AOod1avMab-vkNE61gE,3460
@@ -427,6 +428,7 @@ claude_mpm/services/project_port_allocator.py,sha256=L_EPuX_vGdv8vWWRVTpRk7F-v7u
427
428
  claude_mpm/services/recovery_manager.py,sha256=ptUYsguF6oKWnJnzPRSBuzUFVDXIcvsS3svT6MBTqCQ,25686
428
429
  claude_mpm/services/response_tracker.py,sha256=wBPgI5fH40xc7NHcCXQFOTPFTPSVbAZPqXIauXOJA5g,9575
429
430
  claude_mpm/services/runner_configuration_service.py,sha256=Qs84yrZfQv-DC0I2Xah1Qt9eunH4gS7LNMZ0mmymcqA,21311
431
+ claude_mpm/services/self_upgrade_service.py,sha256=PuzHFQ3fQx7I9rmINLWs86o2KVyr-1StolLR-xnkOrQ,11246
430
432
  claude_mpm/services/session_management_service.py,sha256=axGZXpexWcYGnOMt5o8UQnFJUN3aVyjXRpFAcFrNKeg,10060
431
433
  claude_mpm/services/session_manager.py,sha256=ElguSoiy725VWS2iEqtcn0dUPIRrQrrON74aUzrWjRE,5147
432
434
  claude_mpm/services/socketio_client_manager.py,sha256=cZjIsnoi2VPXFA-5pNhoz5Vv3qv0iuSTy510TgAJU4U,18179
@@ -546,7 +548,7 @@ claude_mpm/services/core/__init__.py,sha256=evEayLlBqJvxMZhrhuK6aagXmNrKGSj8Jm9O
546
548
  claude_mpm/services/core/base.py,sha256=iA-F7DgGp-FJIMvQTiHQ68RkG_k-AtUWlArJPMw6ZPk,7297
547
549
  claude_mpm/services/core/cache_manager.py,sha256=dBHvvI6M67kaxFtAubi4IsWfbDZSct1siyKHTmCIrW8,11567
548
550
  claude_mpm/services/core/interfaces.py,sha256=FbLhWiOUMlvBfqjYBCeoWgsmRscQGBKteRMW-BGz4hQ,1261
549
- claude_mpm/services/core/memory_manager.py,sha256=2m-BYrNwh1yFjvz1VGB_Ndl_dtSp1xhpBcATaBiJQu0,26642
551
+ claude_mpm/services/core/memory_manager.py,sha256=aajBuvBzTq0-EZrjnBjGRdUSaa6MpbfqHAtCePnn7aQ,26258
550
552
  claude_mpm/services/core/path_resolver.py,sha256=VtqiOEUlskAr9nRsaS9uXQSSjDD8dIrYfNML0zLY2zo,17764
551
553
  claude_mpm/services/core/service_container.py,sha256=3hDwFUahxFZnokPzwgXqBP9swvZhLztKQqwe9xEHgsw,18497
552
554
  claude_mpm/services/core/service_interfaces.py,sha256=dlNp0K4gaMcLiNSZxXjsL-kto6vipYw87pBuFK7oVNo,10770
@@ -786,9 +788,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
786
788
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
787
789
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
788
790
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
789
- claude_mpm-4.7.9.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
790
- claude_mpm-4.7.9.dist-info/METADATA,sha256=CKRPRgDYQjMEhisRDRh4swunx7DxHsVA022PufJ0t7Q,17517
791
- claude_mpm-4.7.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
792
- claude_mpm-4.7.9.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
793
- claude_mpm-4.7.9.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
794
- claude_mpm-4.7.9.dist-info/RECORD,,
791
+ claude_mpm-4.7.11.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
792
+ claude_mpm-4.7.11.dist-info/METADATA,sha256=xrQscwKCC7qPBxPTM3pLS0WWsrH6ale3r3620JQqids,17518
793
+ claude_mpm-4.7.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
794
+ claude_mpm-4.7.11.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
795
+ claude_mpm-4.7.11.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
796
+ claude_mpm-4.7.11.dist-info/RECORD,,