claude-mpm 4.1.2__py3-none-any.whl → 4.1.4__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.
Files changed (87) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +16 -19
  3. claude_mpm/agents/MEMORY.md +21 -49
  4. claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +156 -0
  5. claude_mpm/agents/templates/api_qa.json +36 -116
  6. claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +42 -9
  7. claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +29 -6
  8. claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +34 -6
  9. claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +41 -9
  10. claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +30 -8
  11. claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +2 -2
  12. claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +29 -6
  13. claude_mpm/agents/templates/backup/research_memory_efficient.json +2 -2
  14. claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +41 -9
  15. claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +23 -7
  16. claude_mpm/agents/templates/code_analyzer.json +18 -36
  17. claude_mpm/agents/templates/data_engineer.json +43 -14
  18. claude_mpm/agents/templates/documentation.json +55 -74
  19. claude_mpm/agents/templates/engineer.json +57 -40
  20. claude_mpm/agents/templates/imagemagick.json +7 -2
  21. claude_mpm/agents/templates/memory_manager.json +1 -1
  22. claude_mpm/agents/templates/ops.json +36 -4
  23. claude_mpm/agents/templates/project_organizer.json +23 -71
  24. claude_mpm/agents/templates/qa.json +34 -2
  25. claude_mpm/agents/templates/refactoring_engineer.json +9 -5
  26. claude_mpm/agents/templates/research.json +36 -4
  27. claude_mpm/agents/templates/security.json +29 -2
  28. claude_mpm/agents/templates/ticketing.json +3 -3
  29. claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
  30. claude_mpm/agents/templates/version_control.json +28 -2
  31. claude_mpm/agents/templates/web_qa.json +38 -151
  32. claude_mpm/agents/templates/web_ui.json +2 -2
  33. claude_mpm/cli/commands/agent_manager.py +221 -1
  34. claude_mpm/cli/commands/agents.py +556 -1009
  35. claude_mpm/cli/commands/memory.py +248 -927
  36. claude_mpm/cli/commands/run.py +139 -484
  37. claude_mpm/cli/parsers/agent_manager_parser.py +34 -0
  38. claude_mpm/cli/startup_logging.py +76 -0
  39. claude_mpm/core/agent_registry.py +6 -10
  40. claude_mpm/core/framework_loader.py +205 -595
  41. claude_mpm/core/log_manager.py +49 -1
  42. claude_mpm/core/logging_config.py +2 -4
  43. claude_mpm/hooks/claude_hooks/event_handlers.py +7 -117
  44. claude_mpm/hooks/claude_hooks/hook_handler.py +91 -755
  45. claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
  46. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
  47. claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
  48. claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
  49. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  50. claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
  51. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  52. claude_mpm/services/agents/deployment/agent_deployment.py +42 -454
  53. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  54. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  55. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  56. claude_mpm/services/agents/memory/agent_memory_manager.py +42 -508
  57. claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
  58. claude_mpm/services/agents/memory/memory_file_service.py +103 -0
  59. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  60. claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
  61. claude_mpm/services/agents/registry/__init__.py +1 -1
  62. claude_mpm/services/cli/__init__.py +18 -0
  63. claude_mpm/services/cli/agent_cleanup_service.py +407 -0
  64. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  65. claude_mpm/services/cli/agent_listing_service.py +463 -0
  66. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  67. claude_mpm/services/cli/agent_validation_service.py +589 -0
  68. claude_mpm/services/cli/dashboard_launcher.py +424 -0
  69. claude_mpm/services/cli/memory_crud_service.py +617 -0
  70. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  71. claude_mpm/services/cli/session_manager.py +513 -0
  72. claude_mpm/services/cli/socketio_manager.py +498 -0
  73. claude_mpm/services/cli/startup_checker.py +370 -0
  74. claude_mpm/services/core/cache_manager.py +311 -0
  75. claude_mpm/services/core/memory_manager.py +637 -0
  76. claude_mpm/services/core/path_resolver.py +498 -0
  77. claude_mpm/services/core/service_container.py +520 -0
  78. claude_mpm/services/core/service_interfaces.py +436 -0
  79. claude_mpm/services/diagnostics/checks/agent_check.py +65 -19
  80. claude_mpm/services/memory/router.py +116 -10
  81. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/METADATA +1 -1
  82. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/RECORD +86 -55
  83. claude_mpm/cli/commands/run_config_checker.py +0 -159
  84. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/WHEEL +0 -0
  85. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/entry_points.txt +0 -0
  86. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/licenses/LICENSE +0 -0
  87. {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/top_level.txt +0 -0
@@ -179,6 +179,11 @@ class LogManager:
179
179
  # Add to cache
180
180
  self._dir_cache[log_type] = log_dir
181
181
 
182
+ # One-time migration for MPM logs from old location to new subdirectory
183
+ if log_type == "mpm" and not hasattr(self, "_mpm_logs_migrated"):
184
+ await self._migrate_mpm_logs()
185
+ self._mpm_logs_migrated = True
186
+
182
187
  # Schedule cleanup for old logs
183
188
  await self.cleanup_old_logs(
184
189
  log_dir,
@@ -206,7 +211,7 @@ class LogManager:
206
211
  # Map log types to directory names
207
212
  dir_mapping = {
208
213
  "startup": "startup",
209
- "mpm": "", # Root of logs directory
214
+ "mpm": "mpm", # MPM logs in dedicated subdirectory
210
215
  "prompts": "prompts",
211
216
  "sessions": "sessions",
212
217
  "agents": "agents",
@@ -343,6 +348,49 @@ class LogManager:
343
348
 
344
349
  return deleted_count
345
350
 
351
+ async def _migrate_mpm_logs(self):
352
+ """
353
+ One-time migration to move existing MPM logs to new subdirectory.
354
+
355
+ Moves mpm_*.log files from .claude-mpm/logs/ to .claude-mpm/logs/mpm/
356
+ """
357
+ try:
358
+ old_location = self.base_log_dir
359
+ new_location = self.base_log_dir / "mpm"
360
+
361
+ # Only proceed if old location exists and has MPM logs
362
+ if not old_location.exists():
363
+ return
364
+
365
+ # Find all MPM log files in the old location
366
+ mpm_logs = list(old_location.glob("mpm_*.log"))
367
+
368
+ if not mpm_logs:
369
+ return # No logs to migrate
370
+
371
+ # Ensure new directory exists
372
+ new_location.mkdir(parents=True, exist_ok=True)
373
+
374
+ migrated_count = 0
375
+ for log_file in mpm_logs:
376
+ try:
377
+ # Move file to new location
378
+ new_path = new_location / log_file.name
379
+ if not new_path.exists(): # Don't overwrite existing files
380
+ log_file.rename(new_path)
381
+ migrated_count += 1
382
+ except Exception as e:
383
+ logger.debug(f"Could not migrate {log_file}: {e}")
384
+
385
+ if migrated_count > 0:
386
+ logger.info(
387
+ f"Migrated {migrated_count} MPM log files to {new_location}"
388
+ )
389
+
390
+ except Exception as e:
391
+ # Migration is best-effort, don't fail if something goes wrong
392
+ logger.debug(f"MPM log migration skipped: {e}")
393
+
346
394
  async def log_prompt(
347
395
  self, prompt_type: str, content: str, metadata: Optional[Dict[str, Any]] = None
348
396
  ) -> Optional[Path]:
@@ -27,13 +27,11 @@ from typing import Any, Dict, Optional, Union
27
27
  from claude_mpm.core.logger import (
28
28
  JsonFormatter,
29
29
  finalize_streaming_logs,
30
- )
31
- from claude_mpm.core.logger import get_logger as _get_logger
32
- from claude_mpm.core.logger import (
30
+ get_logger as _get_logger,
33
31
  log_async_performance,
34
32
  log_performance,
33
+ setup_logging as _setup_logging,
35
34
  )
36
- from claude_mpm.core.logger import setup_logging as _setup_logging
37
35
 
38
36
  # Standard log format for consistency
39
37
  STANDARD_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
@@ -5,7 +5,6 @@ This module provides individual event handlers for different types of
5
5
  Claude Code hook events.
6
6
  """
7
7
 
8
- import json
9
8
  import os
10
9
  import re
11
10
  import subprocess
@@ -544,122 +543,13 @@ class EventHandlers:
544
543
  self.hook_handler._emit_socketio_event("", "stop", stop_data)
545
544
 
546
545
  def handle_subagent_stop_fast(self, event):
547
- """Handle subagent stop events with improved agent type detection."""
548
- # Enhanced debug logging for session correlation
549
- session_id = event.get("session_id", "")
550
- if DEBUG:
551
- print(
552
- f" - session_id: {session_id[:16] if session_id else 'None'}...",
553
- file=sys.stderr,
554
- )
555
- print(f" - event keys: {list(event.keys())}", file=sys.stderr)
556
- print(
557
- f" - delegation_requests size: {len(self.hook_handler.delegation_requests)}",
558
- file=sys.stderr,
559
- )
560
-
561
- # First try to get agent type from our tracking
562
- agent_type = (
563
- self.hook_handler._get_delegation_agent_type(session_id)
564
- if session_id
565
- else "unknown"
566
- )
567
-
568
- # Fall back to event data if tracking didn't have it
569
- if agent_type == "unknown":
570
- agent_type = event.get("agent_type", event.get("subagent_type", "unknown"))
571
-
572
- agent_id = event.get("agent_id", event.get("subagent_id", ""))
573
- reason = event.get("reason", event.get("stop_reason", "unknown"))
574
-
575
- # Try to infer agent type from other fields if still unknown
576
- if agent_type == "unknown" and "task" in event:
577
- task_desc = str(event.get("task", "")).lower()
578
- if "research" in task_desc:
579
- agent_type = "research"
580
- elif "engineer" in task_desc or "code" in task_desc:
581
- agent_type = "engineer"
582
- elif "pm" in task_desc or "project" in task_desc:
583
- agent_type = "pm"
584
-
585
- # Always log SubagentStop events for debugging
586
- if DEBUG or agent_type != "unknown":
587
- print(
588
- f"Hook handler: Processing SubagentStop - agent: '{agent_type}', session: '{session_id}', reason: '{reason}'",
589
- file=sys.stderr,
590
- )
591
-
592
- # Get working directory and git branch
593
- working_dir = event.get("cwd", "")
594
- git_branch = self._get_git_branch(working_dir) if working_dir else "Unknown"
595
-
596
- # Try to extract structured response from output if available
597
- output = event.get("output", "")
598
- structured_response = None
599
- if output:
600
- try:
601
- json_match = re.search(
602
- r"```json\s*(\{.*?\})\s*```", str(output), re.DOTALL
603
- )
604
- if json_match:
605
- structured_response = json.loads(json_match.group(1))
606
- if DEBUG:
607
- print(
608
- f"Extracted structured response from {agent_type} agent in SubagentStop",
609
- file=sys.stderr,
610
- )
611
- except (json.JSONDecodeError, AttributeError):
612
- pass # No structured response, that's okay
613
-
614
- # Handle response tracking with fuzzy matching
615
- self._handle_subagent_response_tracking(
616
- session_id,
617
- agent_type,
618
- reason,
619
- output,
620
- structured_response,
621
- working_dir,
622
- git_branch,
623
- )
624
-
625
- # Prepare subagent stop data
626
- subagent_stop_data = {
627
- "agent_type": agent_type,
628
- "agent_id": agent_id,
629
- "reason": reason,
630
- "session_id": session_id,
631
- "working_directory": working_dir,
632
- "git_branch": git_branch,
633
- "timestamp": datetime.now().isoformat(),
634
- "is_successful_completion": reason in ["completed", "finished", "done"],
635
- "is_error_termination": reason in ["error", "timeout", "failed", "blocked"],
636
- "is_delegation_related": agent_type
637
- in ["research", "engineer", "pm", "ops", "qa", "documentation", "security"],
638
- "has_results": bool(event.get("results") or event.get("output")),
639
- "duration_context": event.get("duration_ms"),
640
- "hook_event_name": "SubagentStop", # Explicitly set for dashboard
641
- }
642
-
643
- # Add structured response data if available
644
- if structured_response:
645
- subagent_stop_data["structured_response"] = {
646
- "task_completed": structured_response.get("task_completed", False),
647
- "instructions": structured_response.get("instructions", ""),
648
- "results": structured_response.get("results", ""),
649
- "files_modified": structured_response.get("files_modified", []),
650
- "tools_used": structured_response.get("tools_used", []),
651
- "remember": structured_response.get("remember"),
652
- }
653
-
654
- # Debug log the processed data
655
- if DEBUG:
656
- print(
657
- f"SubagentStop processed data: agent_type='{agent_type}', session_id='{session_id}'",
658
- file=sys.stderr,
659
- )
660
-
661
- # Emit normalized event with high priority
662
- self.hook_handler._emit_socketio_event("", "subagent_stop", subagent_stop_data)
546
+ """Handle subagent stop events by delegating to the specialized processor."""
547
+ # Delegate to the specialized subagent processor
548
+ if hasattr(self.hook_handler, "subagent_processor"):
549
+ self.hook_handler.subagent_processor.process_subagent_stop(event)
550
+ else:
551
+ # Fallback to handle_subagent_stop if processor not available
552
+ self.hook_handler.handle_subagent_stop(event)
663
553
 
664
554
  def _handle_subagent_response_tracking(
665
555
  self,