claude-mpm 3.3.2__py3-none-any.whl → 3.4.0__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/cli/commands/memory.py +186 -13
- claude_mpm/cli/parser.py +13 -1
- claude_mpm/constants.py +1 -0
- claude_mpm/core/claude_runner.py +61 -0
- claude_mpm/core/config.py +1 -1
- claude_mpm/core/simple_runner.py +61 -0
- claude_mpm/hooks/builtin/mpm_command_hook.py +5 -5
- claude_mpm/hooks/claude_hooks/hook_handler.py +211 -4
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +9 -2
- claude_mpm/hooks/memory_integration_hook.py +51 -5
- claude_mpm/services/__init__.py +23 -5
- claude_mpm/services/agent_memory_manager.py +536 -48
- claude_mpm/services/memory_builder.py +338 -6
- claude_mpm/services/project_analyzer.py +771 -0
- claude_mpm/services/socketio_server.py +473 -33
- claude_mpm/services/version_control/git_operations.py +26 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/METADATA +34 -10
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/RECORD +22 -39
- claude_mpm/agents/agent-template.yaml +0 -83
- claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +0 -6
- claude_mpm/cli/README.md +0 -109
- claude_mpm/cli_module/refactoring_guide.md +0 -253
- claude_mpm/core/agent_registry.py.bak +0 -312
- claude_mpm/core/base_service.py.bak +0 -406
- claude_mpm/hooks/README.md +0 -97
- claude_mpm/orchestration/SUBPROCESS_DESIGN.md +0 -66
- claude_mpm/schemas/README_SECURITY.md +0 -92
- claude_mpm/schemas/agent_schema.json +0 -395
- claude_mpm/schemas/agent_schema_documentation.md +0 -181
- claude_mpm/schemas/agent_schema_security_notes.md +0 -165
- claude_mpm/schemas/examples/standard_workflow.json +0 -505
- claude_mpm/schemas/ticket_workflow_documentation.md +0 -482
- claude_mpm/schemas/ticket_workflow_schema.json +0 -590
- claude_mpm/services/framework_claude_md_generator/README.md +0 -92
- claude_mpm/services/parent_directory_manager/README.md +0 -83
- claude_mpm/services/version_control/VERSION +0 -1
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.3.2.dist-info → claude_mpm-3.4.0.dist-info}/top_level.txt +0 -0
|
@@ -49,7 +49,7 @@ def manage_memory(args):
|
|
|
49
49
|
_show_status(memory_manager)
|
|
50
50
|
|
|
51
51
|
elif args.memory_command == "view":
|
|
52
|
-
|
|
52
|
+
_show_memories(args, memory_manager)
|
|
53
53
|
|
|
54
54
|
elif args.memory_command == "add":
|
|
55
55
|
_add_learning(args, memory_manager)
|
|
@@ -72,6 +72,15 @@ def manage_memory(args):
|
|
|
72
72
|
elif args.memory_command == "show":
|
|
73
73
|
_show_memories(args, memory_manager)
|
|
74
74
|
|
|
75
|
+
elif args.memory_command == "init":
|
|
76
|
+
_init_memory(args, memory_manager)
|
|
77
|
+
|
|
78
|
+
else:
|
|
79
|
+
logger.error(f"Unknown memory command: {args.memory_command}")
|
|
80
|
+
print(f"Unknown memory command: {args.memory_command}")
|
|
81
|
+
print("Available commands: init, status, view, add, clean, optimize, build, cross-ref, route, show")
|
|
82
|
+
return 1
|
|
83
|
+
|
|
75
84
|
except Exception as e:
|
|
76
85
|
logger.error(f"Error managing memory: {e}")
|
|
77
86
|
print(f"❌ Error: {e}")
|
|
@@ -80,6 +89,71 @@ def manage_memory(args):
|
|
|
80
89
|
return 0
|
|
81
90
|
|
|
82
91
|
|
|
92
|
+
def _init_memory(args, memory_manager):
|
|
93
|
+
"""
|
|
94
|
+
Initialize project-specific memories via agent delegation.
|
|
95
|
+
|
|
96
|
+
WHY: When starting with a new project, agents need project-specific knowledge
|
|
97
|
+
beyond what automatic analysis provides. This command triggers an agent task
|
|
98
|
+
to comprehensively scan the project and create custom memories.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
args: Command line arguments (unused but kept for consistency)
|
|
102
|
+
memory_manager: AgentMemoryManager instance
|
|
103
|
+
"""
|
|
104
|
+
logger = get_logger("cli")
|
|
105
|
+
|
|
106
|
+
print("🚀 Initializing project-specific memories...")
|
|
107
|
+
print("=" * 80)
|
|
108
|
+
print()
|
|
109
|
+
print("This will analyze the project to:")
|
|
110
|
+
print(" 1. Scan project structure and documentation")
|
|
111
|
+
print(" 2. Analyze source code for patterns and conventions")
|
|
112
|
+
print(" 3. Create targeted memories for each agent type")
|
|
113
|
+
print(" 4. Add insights using 'claude-mpm memory add' commands")
|
|
114
|
+
print()
|
|
115
|
+
print("The analysis will cover:")
|
|
116
|
+
print(" • Project architecture and design patterns")
|
|
117
|
+
print(" • Coding conventions and standards")
|
|
118
|
+
print(" • Key modules and integration points")
|
|
119
|
+
print(" • Testing patterns and quality standards")
|
|
120
|
+
print(" • Performance considerations")
|
|
121
|
+
print(" • Domain-specific terminology")
|
|
122
|
+
print()
|
|
123
|
+
print("=" * 80)
|
|
124
|
+
print()
|
|
125
|
+
print("[Agent Task: Initialize Project-Specific Memories]")
|
|
126
|
+
print()
|
|
127
|
+
print("Please analyze this project and create custom memories for all agents.")
|
|
128
|
+
print()
|
|
129
|
+
print("Instructions:")
|
|
130
|
+
print("1. Scan the project structure, documentation, and source code")
|
|
131
|
+
print("2. Identify key patterns, conventions, and project-specific knowledge")
|
|
132
|
+
print("3. Create targeted memories for each agent type")
|
|
133
|
+
print("4. Use 'claude-mpm memory add <agent> <type> \"<content>\"' commands")
|
|
134
|
+
print()
|
|
135
|
+
print("Focus areas:")
|
|
136
|
+
print(" • Architectural patterns and design decisions")
|
|
137
|
+
print(" • Coding conventions from actual source code")
|
|
138
|
+
print(" • Key modules, APIs, and integration points")
|
|
139
|
+
print(" • Testing patterns and quality standards")
|
|
140
|
+
print(" • Performance considerations specific to this project")
|
|
141
|
+
print(" • Common pitfalls based on the codebase")
|
|
142
|
+
print(" • Domain-specific terminology and concepts")
|
|
143
|
+
print()
|
|
144
|
+
print("Example commands to use:")
|
|
145
|
+
print(' claude-mpm memory add engineer pattern "Use dependency injection with @inject"')
|
|
146
|
+
print(' claude-mpm memory add qa pattern "Test files follow test_<module>_<feature>.py"')
|
|
147
|
+
print(' claude-mpm memory add research context "Project uses microservices architecture"')
|
|
148
|
+
print()
|
|
149
|
+
print("Begin by examining the project structure and key files.")
|
|
150
|
+
print()
|
|
151
|
+
print("=" * 80)
|
|
152
|
+
print()
|
|
153
|
+
print("📝 Note: Copy the task above to execute the memory initialization process.")
|
|
154
|
+
print(" Use 'claude-mpm memory add' commands to add discovered insights.")
|
|
155
|
+
|
|
156
|
+
|
|
83
157
|
def _show_status(memory_manager):
|
|
84
158
|
"""
|
|
85
159
|
Show comprehensive memory system status.
|
|
@@ -113,7 +187,7 @@ def _show_status(memory_manager):
|
|
|
113
187
|
print(f"🧠 Memory System Health: {health_emoji} {system_health}")
|
|
114
188
|
print(f"📁 Memory Directory: {status.get('memory_directory', 'Unknown')}")
|
|
115
189
|
print(f"🔧 System Enabled: {'Yes' if status.get('system_enabled', True) else 'No'}")
|
|
116
|
-
print(f"📚 Auto Learning: {'Yes' if status.get('auto_learning',
|
|
190
|
+
print(f"📚 Auto Learning: {'Yes' if status.get('auto_learning', True) else 'No'}")
|
|
117
191
|
print(f"📊 Total Agents: {status.get('total_agents', 0)}")
|
|
118
192
|
print(f"💾 Total Size: {status.get('total_size_kb', 0):.1f} KB")
|
|
119
193
|
print()
|
|
@@ -143,7 +217,7 @@ def _show_status(memory_manager):
|
|
|
143
217
|
sections = agent_info.get("sections", 0)
|
|
144
218
|
items = agent_info.get("items", 0)
|
|
145
219
|
last_modified = agent_info.get("last_modified", "Unknown")
|
|
146
|
-
auto_learning = agent_info.get("auto_learning",
|
|
220
|
+
auto_learning = agent_info.get("auto_learning", True)
|
|
147
221
|
|
|
148
222
|
# Format last modified time
|
|
149
223
|
try:
|
|
@@ -474,24 +548,48 @@ def _show_memories(args, memory_manager):
|
|
|
474
548
|
WHY: Users need to see agent memories in a readable format to understand
|
|
475
549
|
what agents have learned and identify common patterns across agents.
|
|
476
550
|
|
|
551
|
+
DESIGN DECISION: Added --raw flag to output structured JSON data for
|
|
552
|
+
programmatic processing, enabling external tools and scripts to access
|
|
553
|
+
all agent memories in a structured format.
|
|
554
|
+
|
|
477
555
|
Args:
|
|
478
|
-
args: Command arguments with optional agent_id and
|
|
556
|
+
args: Command arguments with optional agent_id, format, and raw flag
|
|
479
557
|
memory_manager: AgentMemoryManager instance
|
|
480
558
|
"""
|
|
481
|
-
print("🧠 Agent Memories Display")
|
|
482
|
-
print("-" * 80)
|
|
483
|
-
|
|
484
559
|
agent_id = getattr(args, 'agent_id', None)
|
|
485
|
-
format_type = getattr(args, 'format', '
|
|
560
|
+
format_type = getattr(args, 'format', 'detailed')
|
|
561
|
+
raw_output = getattr(args, 'raw', False)
|
|
486
562
|
|
|
487
563
|
try:
|
|
488
|
-
if
|
|
489
|
-
|
|
564
|
+
if raw_output:
|
|
565
|
+
# Output structured JSON data
|
|
566
|
+
if agent_id:
|
|
567
|
+
# Get single agent memory in raw format
|
|
568
|
+
_output_single_agent_raw(agent_id, memory_manager)
|
|
569
|
+
else:
|
|
570
|
+
# Get all agent memories in raw format
|
|
571
|
+
_output_all_memories_raw(memory_manager)
|
|
490
572
|
else:
|
|
491
|
-
|
|
573
|
+
# Normal user-friendly display
|
|
574
|
+
print("🧠 Agent Memories Display")
|
|
575
|
+
print("-" * 80)
|
|
492
576
|
|
|
577
|
+
if agent_id:
|
|
578
|
+
_show_single_agent_memory(agent_id, format_type, memory_manager)
|
|
579
|
+
else:
|
|
580
|
+
_show_all_agent_memories(format_type, memory_manager)
|
|
581
|
+
|
|
493
582
|
except Exception as e:
|
|
494
|
-
|
|
583
|
+
if raw_output:
|
|
584
|
+
# Output error in JSON format for consistency
|
|
585
|
+
error_output = {
|
|
586
|
+
"success": False,
|
|
587
|
+
"error": str(e),
|
|
588
|
+
"timestamp": datetime.now().isoformat()
|
|
589
|
+
}
|
|
590
|
+
print(json.dumps(error_output, indent=2))
|
|
591
|
+
else:
|
|
592
|
+
print(f"❌ Error showing memories: {e}")
|
|
495
593
|
|
|
496
594
|
|
|
497
595
|
def _show_single_agent_memory(agent_id, format_type, memory_manager):
|
|
@@ -779,4 +877,79 @@ def _display_bulk_optimization_results(result):
|
|
|
779
877
|
print(f" {agent_id}: {reduction}% reduction{status}")
|
|
780
878
|
else:
|
|
781
879
|
error = agent_result.get("error", "Unknown error")
|
|
782
|
-
print(f" {agent_id}: ❌ {error}")
|
|
880
|
+
print(f" {agent_id}: ❌ {error}")
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def _output_all_memories_raw(memory_manager):
|
|
884
|
+
"""
|
|
885
|
+
Output all agent memories in raw JSON format.
|
|
886
|
+
|
|
887
|
+
WHY: Provides programmatic access to all agent memories for external tools,
|
|
888
|
+
scripts, or APIs that need to process or analyze the complete memory state.
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
memory_manager: AgentMemoryManager instance
|
|
892
|
+
"""
|
|
893
|
+
try:
|
|
894
|
+
raw_data = memory_manager.get_all_memories_raw()
|
|
895
|
+
print(json.dumps(raw_data, indent=2, ensure_ascii=False))
|
|
896
|
+
except Exception as e:
|
|
897
|
+
error_output = {
|
|
898
|
+
"success": False,
|
|
899
|
+
"error": f"Failed to retrieve all memories: {str(e)}",
|
|
900
|
+
"timestamp": datetime.now().isoformat()
|
|
901
|
+
}
|
|
902
|
+
print(json.dumps(error_output, indent=2))
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def _output_single_agent_raw(agent_id, memory_manager):
|
|
906
|
+
"""
|
|
907
|
+
Output single agent memory in raw JSON format.
|
|
908
|
+
|
|
909
|
+
WHY: Provides programmatic access to a specific agent's memory for
|
|
910
|
+
targeted analysis or processing by external tools.
|
|
911
|
+
|
|
912
|
+
Args:
|
|
913
|
+
agent_id: ID of the agent to retrieve memory for
|
|
914
|
+
memory_manager: AgentMemoryManager instance
|
|
915
|
+
"""
|
|
916
|
+
try:
|
|
917
|
+
# Get all memories and extract the specific agent
|
|
918
|
+
all_memories = memory_manager.get_all_memories_raw()
|
|
919
|
+
|
|
920
|
+
if not all_memories.get("success", False):
|
|
921
|
+
error_output = {
|
|
922
|
+
"success": False,
|
|
923
|
+
"error": all_memories.get("error", "Failed to retrieve memories"),
|
|
924
|
+
"timestamp": datetime.now().isoformat()
|
|
925
|
+
}
|
|
926
|
+
print(json.dumps(error_output, indent=2))
|
|
927
|
+
return
|
|
928
|
+
|
|
929
|
+
agents = all_memories.get("agents", {})
|
|
930
|
+
if agent_id not in agents:
|
|
931
|
+
error_output = {
|
|
932
|
+
"success": False,
|
|
933
|
+
"error": f"No memory found for agent: {agent_id}",
|
|
934
|
+
"available_agents": list(agents.keys()),
|
|
935
|
+
"timestamp": datetime.now().isoformat()
|
|
936
|
+
}
|
|
937
|
+
print(json.dumps(error_output, indent=2))
|
|
938
|
+
return
|
|
939
|
+
|
|
940
|
+
# Return single agent data with metadata
|
|
941
|
+
single_agent_output = {
|
|
942
|
+
"success": True,
|
|
943
|
+
"timestamp": all_memories["timestamp"],
|
|
944
|
+
"agent": agents[agent_id]
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
print(json.dumps(single_agent_output, indent=2, ensure_ascii=False))
|
|
948
|
+
|
|
949
|
+
except Exception as e:
|
|
950
|
+
error_output = {
|
|
951
|
+
"success": False,
|
|
952
|
+
"error": f"Failed to retrieve memory for agent {agent_id}: {str(e)}",
|
|
953
|
+
"timestamp": datetime.now().isoformat()
|
|
954
|
+
}
|
|
955
|
+
print(json.dumps(error_output, indent=2))
|
claude_mpm/cli/parser.py
CHANGED
|
@@ -366,6 +366,12 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp
|
|
|
366
366
|
metavar="SUBCOMMAND"
|
|
367
367
|
)
|
|
368
368
|
|
|
369
|
+
# Init command
|
|
370
|
+
init_parser = memory_subparsers.add_parser(
|
|
371
|
+
MemoryCommands.INIT.value,
|
|
372
|
+
help="Initialize project-specific memories via PM agent"
|
|
373
|
+
)
|
|
374
|
+
|
|
369
375
|
# Status command
|
|
370
376
|
status_parser = memory_subparsers.add_parser(
|
|
371
377
|
MemoryCommands.STATUS.value,
|
|
@@ -379,7 +385,8 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp
|
|
|
379
385
|
)
|
|
380
386
|
view_parser.add_argument(
|
|
381
387
|
"agent_id",
|
|
382
|
-
|
|
388
|
+
nargs="?",
|
|
389
|
+
help="Agent ID to view memory for (optional - shows all agents if not provided)"
|
|
383
390
|
)
|
|
384
391
|
|
|
385
392
|
# Add command
|
|
@@ -468,6 +475,11 @@ def create_parser(prog_name: str = "claude-mpm", version: str = "0.0.0") -> argp
|
|
|
468
475
|
default="summary",
|
|
469
476
|
help="Display format: summary (default), detailed, or full"
|
|
470
477
|
)
|
|
478
|
+
show_parser.add_argument(
|
|
479
|
+
"--raw",
|
|
480
|
+
action="store_true",
|
|
481
|
+
help="Output raw memory content in JSON format for programmatic processing"
|
|
482
|
+
)
|
|
471
483
|
|
|
472
484
|
return parser
|
|
473
485
|
|
claude_mpm/constants.py
CHANGED
claude_mpm/core/claude_runner.py
CHANGED
|
@@ -13,10 +13,14 @@ import uuid
|
|
|
13
13
|
try:
|
|
14
14
|
from claude_mpm.services.agent_deployment import AgentDeploymentService
|
|
15
15
|
from claude_mpm.services.ticket_manager import TicketManager
|
|
16
|
+
from claude_mpm.services.hook_service import HookService
|
|
17
|
+
from claude_mpm.core.config import Config
|
|
16
18
|
from claude_mpm.core.logger import get_logger, get_project_logger, ProjectLogger
|
|
17
19
|
except ImportError:
|
|
18
20
|
from claude_mpm.services.agent_deployment import AgentDeploymentService
|
|
19
21
|
from claude_mpm.services.ticket_manager import TicketManager
|
|
22
|
+
from claude_mpm.services.hook_service import HookService
|
|
23
|
+
from claude_mpm.core.config import Config
|
|
20
24
|
from claude_mpm.core.logger import get_logger, get_project_logger, ProjectLogger
|
|
21
25
|
|
|
22
26
|
|
|
@@ -76,6 +80,11 @@ class ClaudeRunner:
|
|
|
76
80
|
self.ticket_manager = None
|
|
77
81
|
self.enable_tickets = False
|
|
78
82
|
|
|
83
|
+
# Initialize hook service and register memory hooks
|
|
84
|
+
self.config = Config()
|
|
85
|
+
self.hook_service = HookService(self.config)
|
|
86
|
+
self._register_memory_hooks()
|
|
87
|
+
|
|
79
88
|
# Load system instructions
|
|
80
89
|
self.system_instructions = self._load_system_instructions()
|
|
81
90
|
|
|
@@ -741,6 +750,58 @@ class ClaudeRunner:
|
|
|
741
750
|
except Exception as e:
|
|
742
751
|
self.logger.debug(f"Failed to log session event: {e}")
|
|
743
752
|
|
|
753
|
+
def _register_memory_hooks(self):
|
|
754
|
+
"""Register memory integration hooks with the hook service.
|
|
755
|
+
|
|
756
|
+
WHY: This activates the memory system by registering hooks that automatically
|
|
757
|
+
inject agent memory before delegation and extract learnings after delegation.
|
|
758
|
+
This is the critical connection point between the memory system and the CLI.
|
|
759
|
+
|
|
760
|
+
DESIGN DECISION: We register hooks here instead of in __init__ to ensure
|
|
761
|
+
all services are initialized first. Hooks are only registered if the memory
|
|
762
|
+
system is enabled in configuration.
|
|
763
|
+
"""
|
|
764
|
+
try:
|
|
765
|
+
# Only register if memory system is enabled
|
|
766
|
+
if not self.config.get('memory.enabled', True):
|
|
767
|
+
self.logger.debug("Memory system disabled - skipping hook registration")
|
|
768
|
+
return
|
|
769
|
+
|
|
770
|
+
# Import hook classes (lazy import to avoid circular dependencies)
|
|
771
|
+
from claude_mpm.hooks.memory_integration_hook import (
|
|
772
|
+
MemoryPreDelegationHook,
|
|
773
|
+
MemoryPostDelegationHook
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
# Register pre-delegation hook for memory injection
|
|
777
|
+
pre_hook = MemoryPreDelegationHook(self.config)
|
|
778
|
+
success = self.hook_service.register_hook(pre_hook)
|
|
779
|
+
if success:
|
|
780
|
+
self.logger.info(f"✅ Registered memory pre-delegation hook (priority: {pre_hook.priority})")
|
|
781
|
+
else:
|
|
782
|
+
self.logger.warning("❌ Failed to register memory pre-delegation hook")
|
|
783
|
+
|
|
784
|
+
# Register post-delegation hook if auto-learning is enabled
|
|
785
|
+
if self.config.get('memory.auto_learning', True): # Default to True now
|
|
786
|
+
post_hook = MemoryPostDelegationHook(self.config)
|
|
787
|
+
success = self.hook_service.register_hook(post_hook)
|
|
788
|
+
if success:
|
|
789
|
+
self.logger.info(f"✅ Registered memory post-delegation hook (priority: {post_hook.priority})")
|
|
790
|
+
else:
|
|
791
|
+
self.logger.warning("❌ Failed to register memory post-delegation hook")
|
|
792
|
+
else:
|
|
793
|
+
self.logger.info("ℹ️ Auto-learning disabled - skipping post-delegation hook")
|
|
794
|
+
|
|
795
|
+
# Log summary of registered hooks
|
|
796
|
+
hooks = self.hook_service.list_hooks()
|
|
797
|
+
pre_count = len(hooks.get('pre_delegation', []))
|
|
798
|
+
post_count = len(hooks.get('post_delegation', []))
|
|
799
|
+
self.logger.info(f"📋 Hook Service initialized: {pre_count} pre-delegation, {post_count} post-delegation hooks")
|
|
800
|
+
|
|
801
|
+
except Exception as e:
|
|
802
|
+
self.logger.error(f"❌ Failed to register memory hooks: {e}")
|
|
803
|
+
# Don't fail the entire initialization - memory system is optional
|
|
804
|
+
|
|
744
805
|
def _launch_subprocess_interactive(self, cmd: list, env: dict):
|
|
745
806
|
"""Launch Claude as a subprocess with PTY for interactive mode."""
|
|
746
807
|
import pty
|
claude_mpm/core/config.py
CHANGED
|
@@ -231,7 +231,7 @@ class Config:
|
|
|
231
231
|
# Agent Memory System configuration
|
|
232
232
|
"memory": {
|
|
233
233
|
"enabled": True, # Master switch for memory system
|
|
234
|
-
"auto_learning":
|
|
234
|
+
"auto_learning": True, # Automatic learning extraction (changed default to True)
|
|
235
235
|
"limits": {
|
|
236
236
|
"default_size_kb": 8, # Default file size limit
|
|
237
237
|
"max_sections": 10, # Maximum sections per file
|
claude_mpm/core/simple_runner.py
CHANGED
|
@@ -13,10 +13,14 @@ import uuid
|
|
|
13
13
|
try:
|
|
14
14
|
from claude_mpm.services.agent_deployment import AgentDeploymentService
|
|
15
15
|
from claude_mpm.services.ticket_manager import TicketManager
|
|
16
|
+
from claude_mpm.services.hook_service import HookService
|
|
17
|
+
from claude_mpm.core.config import Config
|
|
16
18
|
from claude_mpm.core.logger import get_logger, get_project_logger, ProjectLogger
|
|
17
19
|
except ImportError:
|
|
18
20
|
from claude_mpm.services.agent_deployment import AgentDeploymentService
|
|
19
21
|
from claude_mpm.services.ticket_manager import TicketManager
|
|
22
|
+
from claude_mpm.services.hook_service import HookService
|
|
23
|
+
from claude_mpm.core.config import Config
|
|
20
24
|
from claude_mpm.core.logger import get_logger, get_project_logger, ProjectLogger
|
|
21
25
|
|
|
22
26
|
|
|
@@ -76,6 +80,11 @@ class ClaudeRunner:
|
|
|
76
80
|
self.ticket_manager = None
|
|
77
81
|
self.enable_tickets = False
|
|
78
82
|
|
|
83
|
+
# Initialize hook service and register memory hooks
|
|
84
|
+
self.config = Config()
|
|
85
|
+
self.hook_service = HookService(self.config)
|
|
86
|
+
self._register_memory_hooks()
|
|
87
|
+
|
|
79
88
|
# Load system instructions
|
|
80
89
|
self.system_instructions = self._load_system_instructions()
|
|
81
90
|
|
|
@@ -741,6 +750,58 @@ class ClaudeRunner:
|
|
|
741
750
|
except Exception as e:
|
|
742
751
|
self.logger.debug(f"Failed to log session event: {e}")
|
|
743
752
|
|
|
753
|
+
def _register_memory_hooks(self):
|
|
754
|
+
"""Register memory integration hooks with the hook service.
|
|
755
|
+
|
|
756
|
+
WHY: This activates the memory system by registering hooks that automatically
|
|
757
|
+
inject agent memory before delegation and extract learnings after delegation.
|
|
758
|
+
This is the critical connection point between the memory system and the CLI.
|
|
759
|
+
|
|
760
|
+
DESIGN DECISION: We register hooks here instead of in __init__ to ensure
|
|
761
|
+
all services are initialized first. Hooks are only registered if the memory
|
|
762
|
+
system is enabled in configuration.
|
|
763
|
+
"""
|
|
764
|
+
try:
|
|
765
|
+
# Only register if memory system is enabled
|
|
766
|
+
if not self.config.get('memory.enabled', True):
|
|
767
|
+
self.logger.debug("Memory system disabled - skipping hook registration")
|
|
768
|
+
return
|
|
769
|
+
|
|
770
|
+
# Import hook classes (lazy import to avoid circular dependencies)
|
|
771
|
+
from claude_mpm.hooks.memory_integration_hook import (
|
|
772
|
+
MemoryPreDelegationHook,
|
|
773
|
+
MemoryPostDelegationHook
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
# Register pre-delegation hook for memory injection
|
|
777
|
+
pre_hook = MemoryPreDelegationHook(self.config)
|
|
778
|
+
success = self.hook_service.register_hook(pre_hook)
|
|
779
|
+
if success:
|
|
780
|
+
self.logger.info(f"✅ Registered memory pre-delegation hook (priority: {pre_hook.priority})")
|
|
781
|
+
else:
|
|
782
|
+
self.logger.warning("❌ Failed to register memory pre-delegation hook")
|
|
783
|
+
|
|
784
|
+
# Register post-delegation hook if auto-learning is enabled
|
|
785
|
+
if self.config.get('memory.auto_learning', True): # Default to True now
|
|
786
|
+
post_hook = MemoryPostDelegationHook(self.config)
|
|
787
|
+
success = self.hook_service.register_hook(post_hook)
|
|
788
|
+
if success:
|
|
789
|
+
self.logger.info(f"✅ Registered memory post-delegation hook (priority: {post_hook.priority})")
|
|
790
|
+
else:
|
|
791
|
+
self.logger.warning("❌ Failed to register memory post-delegation hook")
|
|
792
|
+
else:
|
|
793
|
+
self.logger.info("ℹ️ Auto-learning disabled - skipping post-delegation hook")
|
|
794
|
+
|
|
795
|
+
# Log summary of registered hooks
|
|
796
|
+
hooks = self.hook_service.list_hooks()
|
|
797
|
+
pre_count = len(hooks.get('pre_delegation', []))
|
|
798
|
+
post_count = len(hooks.get('post_delegation', []))
|
|
799
|
+
self.logger.info(f"📋 Hook Service initialized: {pre_count} pre-delegation, {post_count} post-delegation hooks")
|
|
800
|
+
|
|
801
|
+
except Exception as e:
|
|
802
|
+
self.logger.error(f"❌ Failed to register memory hooks: {e}")
|
|
803
|
+
# Don't fail the entire initialization - memory system is optional
|
|
804
|
+
|
|
744
805
|
def _launch_subprocess_interactive(self, cmd: list, env: dict):
|
|
745
806
|
"""Launch Claude as a subprocess with PTY for interactive mode."""
|
|
746
807
|
import pty
|
|
@@ -12,11 +12,11 @@ logger = get_logger(__name__)
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class MpmCommandHook(SubmitHook):
|
|
15
|
-
"""Hook that intercepts /mpm
|
|
15
|
+
"""Hook that intercepts /mpm commands and routes them to the command router."""
|
|
16
16
|
|
|
17
17
|
def __init__(self):
|
|
18
18
|
super().__init__(name="mpm_command", priority=1) # High priority to intercept early
|
|
19
|
-
self.command_prefix = "/mpm
|
|
19
|
+
self.command_prefix = "/mpm "
|
|
20
20
|
self.command_router_path = self._find_command_router()
|
|
21
21
|
|
|
22
22
|
def _find_command_router(self) -> Path:
|
|
@@ -35,11 +35,11 @@ class MpmCommandHook(SubmitHook):
|
|
|
35
35
|
return Path(".claude/scripts/command_router.py").resolve()
|
|
36
36
|
|
|
37
37
|
def execute(self, context: HookContext) -> HookResult:
|
|
38
|
-
"""Check for /mpm
|
|
38
|
+
"""Check for /mpm commands and execute them directly."""
|
|
39
39
|
try:
|
|
40
40
|
prompt = context.data.get('prompt', '').strip()
|
|
41
41
|
|
|
42
|
-
# Check if this is an /mpm
|
|
42
|
+
# Check if this is an /mpm command
|
|
43
43
|
if not prompt.startswith(self.command_prefix):
|
|
44
44
|
# Not our command, pass through
|
|
45
45
|
return HookResult(
|
|
@@ -67,7 +67,7 @@ class MpmCommandHook(SubmitHook):
|
|
|
67
67
|
command = parts[0]
|
|
68
68
|
args = parts[1:]
|
|
69
69
|
|
|
70
|
-
logger.info(f"Executing /mpm
|
|
70
|
+
logger.info(f"Executing /mpm {command} with args: {args}")
|
|
71
71
|
|
|
72
72
|
# Execute command using command router
|
|
73
73
|
try:
|