claude-mpm 5.6.36__py3-none-any.whl → 5.6.37__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
- 5.6.36
1
+ 5.6.37
claude_mpm/cli/startup.py CHANGED
@@ -13,6 +13,44 @@ import sys
13
13
  from pathlib import Path
14
14
 
15
15
 
16
+ def cleanup_user_level_hooks() -> None:
17
+ """Remove stale user-level hooks directory.
18
+
19
+ WHY: claude-mpm previously deployed hooks to ~/.claude/hooks/claude-mpm/
20
+ (user-level). This is now deprecated in favor of project-level hooks
21
+ configured in .claude/settings.local.json. Stale user-level hooks can
22
+ cause conflicts and confusion.
23
+
24
+ DESIGN DECISION: Runs early in startup, before project hook sync.
25
+ Non-blocking - failures are logged at debug level but don't prevent startup.
26
+ """
27
+ import shutil
28
+
29
+ user_hooks_dir = Path.home() / ".claude" / "hooks" / "claude-mpm"
30
+
31
+ if not user_hooks_dir.exists():
32
+ return
33
+
34
+ try:
35
+ from ..core.logger import get_logger
36
+
37
+ logger = get_logger("startup")
38
+ logger.debug(f"Removing stale user-level hooks directory: {user_hooks_dir}")
39
+
40
+ shutil.rmtree(user_hooks_dir)
41
+
42
+ logger.debug("User-level hooks cleanup complete")
43
+ except Exception as e:
44
+ # Non-critical - log but don't fail startup
45
+ try:
46
+ from ..core.logger import get_logger
47
+
48
+ logger = get_logger("startup")
49
+ logger.debug(f"Failed to cleanup user-level hooks (non-fatal): {e}")
50
+ except Exception: # nosec B110
51
+ pass # Avoid any errors in error handling
52
+
53
+
16
54
  def sync_hooks_on_startup(quiet: bool = False) -> bool:
17
55
  """Ensure hooks are up-to-date on startup.
18
56
 
@@ -20,7 +58,12 @@ def sync_hooks_on_startup(quiet: bool = False) -> bool:
20
58
  Reinstalling hooks ensures the hook format matches the current code.
21
59
 
22
60
  DESIGN DECISION: Shows brief status message on success for user awareness.
23
- Failures are logged but don't prevent startup to ensure claude-mpm remains functional.
61
+ Failures are logged but don't prevent startup to ensure claude-mpm
62
+ remains functional.
63
+
64
+ Workflow:
65
+ 1. Cleanup stale user-level hooks (~/.claude/hooks/claude-mpm/)
66
+ 2. Reinstall project-level hooks to .claude/settings.local.json
24
67
 
25
68
  Args:
26
69
  quiet: If True, suppress all output (used internally)
@@ -28,6 +71,9 @@ def sync_hooks_on_startup(quiet: bool = False) -> bool:
28
71
  Returns:
29
72
  bool: True if hooks were synced successfully, False otherwise
30
73
  """
74
+ # Step 1: Cleanup stale user-level hooks first
75
+ cleanup_user_level_hooks()
76
+
31
77
  try:
32
78
  from ..hooks.claude_hooks.installer import HookInstaller
33
79
 
@@ -1386,6 +1432,28 @@ def auto_install_chrome_devtools_on_startup():
1386
1432
  # Continue execution - chrome-devtools installation failure shouldn't block startup
1387
1433
 
1388
1434
 
1435
+ def sync_deployment_on_startup(force_sync: bool = False) -> None:
1436
+ """Consolidated deployment block: hooks + agents.
1437
+
1438
+ WHY: Groups all deployment tasks into a single logical block for clarity.
1439
+ This ensures hooks and agents are deployed together before other services.
1440
+
1441
+ Order:
1442
+ 1. Hook cleanup (remove ~/.claude/hooks/claude-mpm/)
1443
+ 2. Hook reinstall (update .claude/settings.local.json)
1444
+ 3. Agent sync from remote Git sources
1445
+
1446
+ Args:
1447
+ force_sync: Force download even if cache is fresh (bypasses ETag).
1448
+ """
1449
+ # Step 1-2: Hooks (cleanup + reinstall handled by sync_hooks_on_startup)
1450
+ sync_hooks_on_startup() # Shows "Syncing Claude Code hooks... ✓"
1451
+
1452
+ # Step 3: Agents from remote sources
1453
+ sync_remote_agents_on_startup(force_sync=force_sync)
1454
+ show_agent_summary() # Display agent counts after deployment
1455
+
1456
+
1389
1457
  def run_background_services(force_sync: bool = False):
1390
1458
  """
1391
1459
  Initialize all background services on startup.
@@ -1401,19 +1469,15 @@ def run_background_services(force_sync: bool = False):
1401
1469
  Args:
1402
1470
  force_sync: Force download even if cache is fresh (bypasses ETag).
1403
1471
  """
1404
- # Sync hooks early to ensure up-to-date configuration
1405
- # RATIONALE: Hooks should be synced before other services to fix stale configs
1406
- # This is fast (<100ms) and non-blocking, so it doesn't delay startup
1407
- sync_hooks_on_startup() # Shows "Syncing Claude Code hooks... ✓"
1472
+ # Consolidated deployment block: hooks + agents
1473
+ # RATIONALE: Hooks and agents are deployed together before other services
1474
+ # This ensures the deployment phase is complete before configuration checks
1475
+ sync_deployment_on_startup(force_sync=force_sync)
1408
1476
 
1409
1477
  initialize_project_registry()
1410
1478
  check_mcp_auto_configuration()
1411
1479
  verify_mcp_gateway_startup()
1412
1480
  check_for_updates_async()
1413
- sync_remote_agents_on_startup(
1414
- force_sync=force_sync
1415
- ) # Sync agents from remote sources
1416
- show_agent_summary() # Display agent counts after deployment
1417
1481
 
1418
1482
  # Skills deployment order (precedence: remote > bundled)
1419
1483
  # 1. Deploy bundled skills first (base layer from package)
@@ -17,7 +17,7 @@ import subprocess # nosec B404 - subprocess used for safe claude CLI version ch
17
17
  import uuid
18
18
  from datetime import datetime, timezone
19
19
  from pathlib import Path
20
- from typing import Any, Callable, Optional
20
+ from typing import Any, Optional
21
21
 
22
22
  # Import _log helper to avoid stderr writes (which cause hook errors)
23
23
  try:
@@ -109,25 +109,6 @@ def _get_config() -> Optional[Any]:
109
109
  return _config
110
110
 
111
111
 
112
- # Autotodos function (for pending todos injection)
113
- _get_pending_todos_fn: Optional[Callable] = None
114
- _get_pending_todos_loaded = False
115
-
116
-
117
- def _get_pending_todos_func() -> Optional[Callable]:
118
- """Get get_pending_todos function with lazy loading."""
119
- global _get_pending_todos_fn, _get_pending_todos_loaded
120
- if not _get_pending_todos_loaded:
121
- try:
122
- from claude_mpm.cli.commands.autotodos import get_pending_todos
123
-
124
- _get_pending_todos_fn = get_pending_todos
125
- except ImportError:
126
- _get_pending_todos_fn = None
127
- _get_pending_todos_loaded = True
128
- return _get_pending_todos_fn
129
-
130
-
131
112
  # Delegation detector (for anti-pattern detection)
132
113
  _delegation_detector: Optional[Any] = None
133
114
  _delegation_detector_loaded = False
@@ -186,7 +167,6 @@ class EventHandlers:
186
167
  config: Optional[Any] = None,
187
168
  delegation_detector: Optional[Any] = None,
188
169
  event_log: Optional[Any] = None,
189
- get_pending_todos_fn: Optional[Callable] = None,
190
170
  ):
191
171
  """Initialize with reference to the main hook handler and optional services.
192
172
 
@@ -196,7 +176,6 @@ class EventHandlers:
196
176
  config: Optional Config for autotodos configuration
197
177
  delegation_detector: Optional DelegationDetector for anti-pattern detection
198
178
  event_log: Optional EventLog for PM violation logging
199
- get_pending_todos_fn: Optional function to get pending todos
200
179
  """
201
180
  self.hook_handler = hook_handler
202
181
 
@@ -205,7 +184,6 @@ class EventHandlers:
205
184
  self._config = config
206
185
  self._delegation_detector = delegation_detector
207
186
  self._event_log = event_log
208
- self._get_pending_todos_fn = get_pending_todos_fn
209
187
 
210
188
  @property
211
189
  def log_manager(self) -> Optional[Any]:
@@ -235,18 +213,6 @@ class EventHandlers:
235
213
  return self._event_log
236
214
  return _get_event_log_service()
237
215
 
238
- def get_pending_todos(
239
- self, max_todos: int = 10, working_dir: Optional[Path] = None
240
- ) -> list:
241
- """Get pending todos (using injected function or lazy loaded)."""
242
- fn = self._get_pending_todos_fn or _get_pending_todos_func()
243
- if fn is None:
244
- return []
245
- try:
246
- return fn(max_todos=max_todos, working_dir=working_dir)
247
- except Exception:
248
- return []
249
-
250
216
  def handle_user_prompt_fast(self, event):
251
217
  """Handle user prompt with comprehensive data capture.
252
218
 
@@ -1119,7 +1085,9 @@ class EventHandlers:
1119
1085
  - Provides visibility into new conversation sessions
1120
1086
  - Enables tracking of session lifecycle and duration
1121
1087
  - Useful for monitoring concurrent sessions and resource usage
1122
- - Auto-inject pending autotodos if enabled in config
1088
+
1089
+ NOTE: This handler is intentionally lightweight - only event monitoring.
1090
+ All initialization/deployment logic runs in MPM CLI startup, not here.
1123
1091
  """
1124
1092
  session_id = event.get("session_id", "")
1125
1093
  working_dir = event.get("cwd", "")
@@ -1133,35 +1101,6 @@ class EventHandlers:
1133
1101
  "hook_event_name": "SessionStart",
1134
1102
  }
1135
1103
 
1136
- # Auto-inject pending autotodos if enabled
1137
- # Uses injected config and get_pending_todos or lazy-loaded instances
1138
- config = self.config
1139
- if config is not None:
1140
- try:
1141
- auto_inject_enabled = config.get(
1142
- "autotodos.auto_inject_on_startup", True
1143
- )
1144
- max_todos = config.get("autotodos.max_todos_per_session", 10)
1145
-
1146
- if auto_inject_enabled:
1147
- # Pass working directory from event to avoid Path.cwd() issues
1148
- working_dir_param = None
1149
- if working_dir:
1150
- working_dir_param = Path(working_dir)
1151
-
1152
- pending_todos = self.get_pending_todos(
1153
- max_todos=max_todos, working_dir=working_dir_param
1154
- )
1155
- if pending_todos:
1156
- session_start_data["pending_autotodos"] = pending_todos
1157
- session_start_data["autotodos_count"] = len(pending_todos)
1158
- _log(
1159
- f" - Auto-injected {len(pending_todos)} pending autotodos"
1160
- )
1161
- except Exception as e: # nosec B110
1162
- # Auto-injection is optional - continue if it fails
1163
- _log(f" - Failed to auto-inject autotodos: {e}")
1164
-
1165
1104
  # Debug logging
1166
1105
  _log(f"Hook handler: Processing SessionStart - session: '{session_id}'")
1167
1106
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 5.6.36
3
+ Version: 5.6.37
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=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=8w2fPmwYmLDeFLO3SEO_SZLBkk7bAj4ayqWYafYZFvA,7
2
+ claude_mpm/VERSION,sha256=6wU_GWy-ocN_lZJMsDrvXWts8AcQ_8tGO-otGNlaDwg,7
3
3
  claude_mpm/__init__.py,sha256=AGfh00BHKvLYD-UVFw7qbKtl7NMRIzRXOWw7vEuZ-h4,2214
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=pz3lTrZZR5HhV3eZzYtIbtBwWo7iM6pkBHP_ixxmI6Y,6827
@@ -42,7 +42,7 @@ claude_mpm/cli/chrome_devtools_installer.py,sha256=efA_ZX1iR3oaJi3222079BQw6DEG8
42
42
  claude_mpm/cli/executor.py,sha256=eerqDVszBfTm8N2FgreLr-132Jb9BVZGNrrukvb_b-I,15106
43
43
  claude_mpm/cli/helpers.py,sha256=CypEhw0tbNH6_GzVTaQdi4w7ThCWO43Ep92YbJzPR4I,3638
44
44
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
45
- claude_mpm/cli/startup.py,sha256=4nKyk0UqVSBsiF-gnk7TnYn3pebB146c79xffo75bhA,68170
45
+ claude_mpm/cli/startup.py,sha256=yqq44doFdcrR8f1pCPOAeLG-3kzmdWHaMEmk_uAhc5E,70361
46
46
  claude_mpm/cli/startup_display.py,sha256=KI4GZ0uVoK7FXeK5jsS4JAyaKaKf5rCkY3h5tNeEY7M,17209
47
47
  claude_mpm/cli/startup_logging.py,sha256=wHokzcCA0AJPxAqFrpY5PMOBh1iOhdhgP1gY1OvD0gY,29392
48
48
  claude_mpm/cli/utils.py,sha256=5e3v-ow1gd-5nlad9OWCsL-3SRJcPjBJ9HS3zygwkiQ,8988
@@ -429,7 +429,7 @@ claude_mpm/hooks/claude_hooks/__init__.py,sha256=b4mud_g3S-3itHY_Dzpbb_SmdMEcJwt
429
429
  claude_mpm/hooks/claude_hooks/auto_pause_handler.py,sha256=Fm8d_a0KJ1GBPPQ3xmQo-xp-j8xU2TGHTDohbySu0Cg,17184
430
430
  claude_mpm/hooks/claude_hooks/connection_pool.py,sha256=vpi-XbVf61GWhh85tHBzubbOgbJly_I-5-QmsleND2M,8658
431
431
  claude_mpm/hooks/claude_hooks/correlation_manager.py,sha256=3n-RxzqE8egG4max_NcpJgL9gzrBY6Ti529LrjleI1g,2033
432
- claude_mpm/hooks/claude_hooks/event_handlers.py,sha256=v1hRK_iWpYB03z5ScAyffLlSda0zA0YbW--32H4pxRY,52875
432
+ claude_mpm/hooks/claude_hooks/event_handlers.py,sha256=VJ4kY_GMZkVv8WBAII4GTfY4qxFgoKdXpMdhEbzt980,50344
433
433
  claude_mpm/hooks/claude_hooks/hook_handler.py,sha256=AH0z6D06bo02UGyEdYlzll2EcELl-gmt8D42MPqu_SU,30459
434
434
  claude_mpm/hooks/claude_hooks/hook_wrapper.sh,sha256=XYkdYtcM0nfnwYvMdyIFCasr80ry3uI5-fLYsLtDGw4,2214
435
435
  claude_mpm/hooks/claude_hooks/installer.py,sha256=SvIgxRMocQxnqNF3ZQfKH8zA-1b4lpiCA4vCI0vWOZI,38065
@@ -439,7 +439,7 @@ claude_mpm/hooks/claude_hooks/tool_analysis.py,sha256=3_o2PP9D7wEMwLriCtIBOw0cj2
439
439
  claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc,sha256=EGpgXqhPM0iRRZtCqHaLVQ6wDH42OH_M7Gt5GiFLyro,346
440
440
  claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc,sha256=lw3g7dHPcJ258xtcmbXOk-tCqVz0JAc5PZ10LUfG4Zo,20829
441
441
  claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc,sha256=SQX5iiP9bQZkLL-cj_2tlGH7lpAzarO0mYal7btj3tc,3521
442
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=NSsuyYiHY1rY6PPIceasOrzJ3f_qnvJnWimj3TbHuzk,51316
442
+ claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc,sha256=rUcbnsARIgWenNkPv8LlHJBXmxTOExqgcwtBaBfGzg4,49040
443
443
  claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc,sha256=NQtvV9vs1OMKQTZWRQrAie83y4Q61mJ-QFawC2GnsUQ,32799
444
444
  claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc,sha256=1llucgjrun0H6q8V8_BXTHtkTiYAwNGyptluhoIi7ss,11185
445
445
  claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc,sha256=E_pRoKx-mAB5gEv2_5TneMC_K10zj7FYCPwQPnPd88g,16228
@@ -1106,10 +1106,10 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
1106
1106
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
1107
1107
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
1108
1108
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
1109
- claude_mpm-5.6.36.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1110
- claude_mpm-5.6.36.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1111
- claude_mpm-5.6.36.dist-info/METADATA,sha256=SHCuSq8oW4Jz9yPooKmGv1QjjI4stqcyuyH-XNjBC3s,15245
1112
- claude_mpm-5.6.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1113
- claude_mpm-5.6.36.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1114
- claude_mpm-5.6.36.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1115
- claude_mpm-5.6.36.dist-info/RECORD,,
1109
+ claude_mpm-5.6.37.dist-info/licenses/LICENSE,sha256=ca3y_Rk4aPrbF6f62z8Ht5MJM9OAvbGlHvEDcj9vUQ4,3867
1110
+ claude_mpm-5.6.37.dist-info/licenses/LICENSE-FAQ.md,sha256=TxfEkXVCK98RzDOer09puc7JVCP_q_bN4dHtZKHCMcM,5104
1111
+ claude_mpm-5.6.37.dist-info/METADATA,sha256=9S9VFtM7YgENEHeksusZFEuIArHYOdUV2KTV0ut4T9E,15245
1112
+ claude_mpm-5.6.37.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1113
+ claude_mpm-5.6.37.dist-info/entry_points.txt,sha256=n-Uk4vwHPpuvu-g_I7-GHORzTnN_m6iyOsoLveKKD0E,228
1114
+ claude_mpm-5.6.37.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
1115
+ claude_mpm-5.6.37.dist-info/RECORD,,