claude-mpm 5.4.14__py3-none-any.whl → 5.4.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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT.md +164 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
- claude_mpm/agents/MEMORY.md +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +363 -817
- claude_mpm/agents/WORKFLOW.md +5 -254
- claude_mpm/agents/agent_loader.py +1 -1
- claude_mpm/agents/base_agent.json +31 -0
- claude_mpm/cli/chrome_devtools_installer.py +175 -0
- claude_mpm/cli/commands/agent_state_manager.py +10 -10
- claude_mpm/cli/commands/agents.py +9 -40
- claude_mpm/cli/commands/auto_configure.py +4 -4
- claude_mpm/cli/commands/configure.py +1 -1
- claude_mpm/cli/commands/postmortem.py +1 -1
- claude_mpm/cli/commands/skills.py +193 -187
- claude_mpm/cli/interactive/agent_wizard.py +2 -2
- claude_mpm/cli/parsers/agents_parser.py +0 -9
- claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
- claude_mpm/cli/startup.py +330 -78
- claude_mpm/commands/mpm-config.md +1 -2
- claude_mpm/commands/mpm-help.md +14 -95
- claude_mpm/commands/mpm-organize.md +350 -153
- claude_mpm/core/config.py +2 -4
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
- claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
- claude_mpm/dashboard/static/svelte-build/index.html +36 -0
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +5 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +149 -1
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +26 -6
- claude_mpm/models/git_repository.py +3 -3
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/cache_git_manager.py +6 -6
- claude_mpm/services/agents/deployment/agent_deployment.py +7 -7
- claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +2 -2
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +20 -22
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +55 -53
- claude_mpm/services/agents/git_source_manager.py +2 -2
- claude_mpm/services/agents/recommender.py +5 -3
- claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +5 -5
- claude_mpm/services/agents/startup_sync.py +22 -2
- claude_mpm/services/command_deployment_service.py +10 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
- claude_mpm/services/git/git_operations_service.py +8 -8
- claude_mpm/services/monitor/server.py +473 -3
- claude_mpm/services/skills/selective_skill_deployer.py +475 -1
- claude_mpm/services/skills_deployer.py +62 -6
- claude_mpm/services/socketio/dashboard_server.py +1 -0
- claude_mpm/services/socketio/event_normalizer.py +37 -6
- claude_mpm/services/socketio/server/core.py +262 -123
- claude_mpm/utils/agent_dependency_loader.py +14 -2
- claude_mpm/utils/agent_filters.py +1 -1
- claude_mpm/utils/migration.py +4 -4
- claude_mpm/utils/robust_installer.py +47 -3
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/METADATA +5 -3
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/RECORD +96 -66
- claude_mpm/cli/commands/agents_detect.py +0 -380
- claude_mpm/cli/commands/agents_recommend.py +0 -309
- claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
- claude_mpm/commands/mpm-agents-detect.md +0 -177
- claude_mpm/commands/mpm-agents-list.md +0 -131
- claude_mpm/commands/mpm-agents-recommend.md +0 -223
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.14.dist-info → claude_mpm-5.4.36.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
|
+
|
|
8
|
+
<link rel="modulepreload" href="/_app/immutable/entry/start.DzuEhzqh.js">
|
|
9
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/CIXEwuWe.js">
|
|
10
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DjhvlsAc.js">
|
|
11
|
+
<link rel="modulepreload" href="/_app/immutable/entry/app.DTL5mJO-.js">
|
|
12
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DMkZpdF2.js">
|
|
13
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/CWc5urbQ.js">
|
|
14
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/BgChzWQ1.js">
|
|
15
|
+
</head>
|
|
16
|
+
<body data-sveltekit-preload-data="hover">
|
|
17
|
+
<div style="display: contents">
|
|
18
|
+
<script>
|
|
19
|
+
{
|
|
20
|
+
__sveltekit_16ujgvz = {
|
|
21
|
+
base: ""
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const element = document.currentScript.parentElement;
|
|
25
|
+
|
|
26
|
+
Promise.all([
|
|
27
|
+
import("/_app/immutable/entry/start.DzuEhzqh.js"),
|
|
28
|
+
import("/_app/immutable/entry/app.DTL5mJO-.js")
|
|
29
|
+
]).then(([kit, app]) => {
|
|
30
|
+
kit.start(app, element);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
</div>
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -455,6 +455,11 @@ class EventHandlers:
|
|
|
455
455
|
),
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
+
# Include full output for file operations (Read, Edit, Write)
|
|
459
|
+
# so frontend can display file content
|
|
460
|
+
if tool_name in ("Read", "Edit", "Write", "Grep", "Glob") and "output" in event:
|
|
461
|
+
post_tool_data["output"] = event["output"]
|
|
462
|
+
|
|
458
463
|
# Add correlation_id if available for correlation with pre_tool
|
|
459
464
|
if tool_call_id:
|
|
460
465
|
post_tool_data["correlation_id"] = tool_call_id
|
|
@@ -394,6 +394,8 @@ class ClaudeHookHandler:
|
|
|
394
394
|
Returns:
|
|
395
395
|
Modified input for PreToolUse events (v2.0.30+), None otherwise
|
|
396
396
|
"""
|
|
397
|
+
import time
|
|
398
|
+
|
|
397
399
|
# Try multiple field names for compatibility
|
|
398
400
|
hook_type = (
|
|
399
401
|
event.get("hook_event_name")
|
|
@@ -425,15 +427,40 @@ class ClaudeHookHandler:
|
|
|
425
427
|
# Call appropriate handler if exists
|
|
426
428
|
handler = event_handlers.get(hook_type)
|
|
427
429
|
if handler:
|
|
430
|
+
# Track execution timing for hook emission
|
|
431
|
+
start_time = time.time()
|
|
432
|
+
success = False
|
|
433
|
+
error_message = None
|
|
434
|
+
result = None
|
|
435
|
+
|
|
428
436
|
try:
|
|
429
437
|
# Handlers can optionally return modified input
|
|
430
438
|
result = handler(event)
|
|
439
|
+
success = True
|
|
431
440
|
# Only PreToolUse handlers should return modified input
|
|
432
441
|
if hook_type == "PreToolUse" and result is not None:
|
|
433
|
-
|
|
442
|
+
return_value = result
|
|
443
|
+
else:
|
|
444
|
+
return_value = None
|
|
434
445
|
except Exception as e:
|
|
446
|
+
error_message = str(e)
|
|
447
|
+
return_value = None
|
|
435
448
|
if DEBUG:
|
|
436
449
|
print(f"Error handling {hook_type}: {e}", file=sys.stderr)
|
|
450
|
+
finally:
|
|
451
|
+
# Calculate duration
|
|
452
|
+
duration_ms = int((time.time() - start_time) * 1000)
|
|
453
|
+
|
|
454
|
+
# Emit hook execution event
|
|
455
|
+
self._emit_hook_execution_event(
|
|
456
|
+
hook_type=hook_type,
|
|
457
|
+
event=event,
|
|
458
|
+
success=success,
|
|
459
|
+
duration_ms=duration_ms,
|
|
460
|
+
error_message=error_message,
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
return return_value
|
|
437
464
|
|
|
438
465
|
return None
|
|
439
466
|
|
|
@@ -478,6 +505,127 @@ class ClaudeHookHandler:
|
|
|
478
505
|
"""Generate event key through duplicate detector (backward compatibility)."""
|
|
479
506
|
return self.duplicate_detector.generate_event_key(event)
|
|
480
507
|
|
|
508
|
+
def _emit_hook_execution_event(
|
|
509
|
+
self,
|
|
510
|
+
hook_type: str,
|
|
511
|
+
event: dict,
|
|
512
|
+
success: bool,
|
|
513
|
+
duration_ms: int,
|
|
514
|
+
error_message: Optional[str] = None,
|
|
515
|
+
):
|
|
516
|
+
"""Emit a structured JSON event for hook execution.
|
|
517
|
+
|
|
518
|
+
This emits a normalized event following the claude_event schema to provide
|
|
519
|
+
visibility into hook processing, timing, and success/failure status.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
hook_type: The type of hook that executed (e.g., "UserPromptSubmit", "PreToolUse")
|
|
523
|
+
event: The original hook event data
|
|
524
|
+
success: Whether the hook executed successfully
|
|
525
|
+
duration_ms: How long the hook took to execute in milliseconds
|
|
526
|
+
error_message: Optional error message if the hook failed
|
|
527
|
+
"""
|
|
528
|
+
# Generate a human-readable summary based on hook type
|
|
529
|
+
summary = self._generate_hook_summary(hook_type, event, success)
|
|
530
|
+
|
|
531
|
+
# Extract common fields
|
|
532
|
+
session_id = event.get("session_id", "")
|
|
533
|
+
working_dir = event.get("cwd", "")
|
|
534
|
+
|
|
535
|
+
# Build hook execution data
|
|
536
|
+
hook_data = {
|
|
537
|
+
"hook_name": hook_type,
|
|
538
|
+
"hook_type": hook_type,
|
|
539
|
+
"session_id": session_id,
|
|
540
|
+
"working_directory": working_dir,
|
|
541
|
+
"success": success,
|
|
542
|
+
"duration_ms": duration_ms,
|
|
543
|
+
"result_summary": summary,
|
|
544
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
# Add error information if present
|
|
548
|
+
if error_message:
|
|
549
|
+
hook_data["error_message"] = error_message
|
|
550
|
+
|
|
551
|
+
# Add hook-specific context
|
|
552
|
+
if hook_type == "PreToolUse":
|
|
553
|
+
hook_data["tool_name"] = event.get("tool_name", "")
|
|
554
|
+
elif hook_type == "PostToolUse":
|
|
555
|
+
hook_data["tool_name"] = event.get("tool_name", "")
|
|
556
|
+
hook_data["exit_code"] = event.get("exit_code", 0)
|
|
557
|
+
elif hook_type == "UserPromptSubmit":
|
|
558
|
+
prompt = event.get("prompt", "")
|
|
559
|
+
hook_data["prompt_preview"] = prompt[:100] if len(prompt) > 100 else prompt
|
|
560
|
+
hook_data["prompt_length"] = len(prompt)
|
|
561
|
+
elif hook_type == "SubagentStop":
|
|
562
|
+
hook_data["agent_type"] = event.get("agent_type", "unknown")
|
|
563
|
+
hook_data["reason"] = event.get("reason", "unknown")
|
|
564
|
+
|
|
565
|
+
# Emit through connection manager with proper structure
|
|
566
|
+
# This uses the existing event infrastructure
|
|
567
|
+
self._emit_socketio_event("", "hook_execution", hook_data)
|
|
568
|
+
|
|
569
|
+
if DEBUG:
|
|
570
|
+
print(
|
|
571
|
+
f"📊 Hook execution event: {hook_type} - {duration_ms}ms - {'✅' if success else '❌'}",
|
|
572
|
+
file=sys.stderr,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
def _generate_hook_summary(self, hook_type: str, event: dict, success: bool) -> str:
|
|
576
|
+
"""Generate a human-readable summary of what the hook did.
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
hook_type: The type of hook
|
|
580
|
+
event: The hook event data
|
|
581
|
+
success: Whether the hook executed successfully
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
A brief description of what happened
|
|
585
|
+
"""
|
|
586
|
+
if not success:
|
|
587
|
+
return f"Hook {hook_type} failed during processing"
|
|
588
|
+
|
|
589
|
+
# Generate hook-specific summaries
|
|
590
|
+
if hook_type == "UserPromptSubmit":
|
|
591
|
+
prompt = event.get("prompt", "")
|
|
592
|
+
if prompt.startswith("/"):
|
|
593
|
+
return f"Processed command: {prompt.split()[0]}"
|
|
594
|
+
return f"Processed user prompt ({len(prompt)} chars)"
|
|
595
|
+
|
|
596
|
+
if hook_type == "PreToolUse":
|
|
597
|
+
tool_name = event.get("tool_name", "unknown")
|
|
598
|
+
return f"Pre-processing tool call: {tool_name}"
|
|
599
|
+
|
|
600
|
+
if hook_type == "PostToolUse":
|
|
601
|
+
tool_name = event.get("tool_name", "unknown")
|
|
602
|
+
exit_code = event.get("exit_code", 0)
|
|
603
|
+
status = "success" if exit_code == 0 else "failed"
|
|
604
|
+
return f"Completed tool call: {tool_name} ({status})"
|
|
605
|
+
|
|
606
|
+
if hook_type == "SubagentStop":
|
|
607
|
+
agent_type = event.get("agent_type", "unknown")
|
|
608
|
+
reason = event.get("reason", "unknown")
|
|
609
|
+
return f"Subagent {agent_type} stopped: {reason}"
|
|
610
|
+
|
|
611
|
+
if hook_type == "SessionStart":
|
|
612
|
+
return "New session started"
|
|
613
|
+
|
|
614
|
+
if hook_type == "Stop":
|
|
615
|
+
reason = event.get("reason", "unknown")
|
|
616
|
+
return f"Session stopped: {reason}"
|
|
617
|
+
|
|
618
|
+
if hook_type == "Notification":
|
|
619
|
+
notification_type = event.get("notification_type", "unknown")
|
|
620
|
+
return f"Notification received: {notification_type}"
|
|
621
|
+
|
|
622
|
+
if hook_type == "AssistantResponse":
|
|
623
|
+
response_len = len(event.get("response", ""))
|
|
624
|
+
return f"Assistant response generated ({response_len} chars)"
|
|
625
|
+
|
|
626
|
+
# Default summary
|
|
627
|
+
return f"Hook {hook_type} processed successfully"
|
|
628
|
+
|
|
481
629
|
def __del__(self):
|
|
482
630
|
"""Cleanup on handler destruction."""
|
|
483
631
|
# Clean up connection manager if it exists
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -58,7 +58,7 @@ except ImportError:
|
|
|
58
58
|
(),
|
|
59
59
|
{
|
|
60
60
|
"to_dict": lambda: {
|
|
61
|
-
"event": "
|
|
61
|
+
"event": "mpm_event",
|
|
62
62
|
"type": event_data.get("type", "unknown"),
|
|
63
63
|
"subtype": event_data.get("subtype", "generic"),
|
|
64
64
|
"timestamp": event_data.get(
|
|
@@ -119,13 +119,33 @@ class ConnectionManagerService:
|
|
|
119
119
|
tool_call_id = data.get("tool_call_id")
|
|
120
120
|
|
|
121
121
|
# Create event data for normalization
|
|
122
|
+
# Extract session_id (try both camelCase and snake_case)
|
|
123
|
+
session_id = data.get("session_id") or data.get("sessionId")
|
|
124
|
+
|
|
125
|
+
# Extract working directory for project identification
|
|
126
|
+
# Try multiple field names for maximum compatibility
|
|
127
|
+
cwd = (
|
|
128
|
+
data.get("cwd")
|
|
129
|
+
or data.get("working_directory")
|
|
130
|
+
or data.get("workingDirectory")
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# For hook_execution events, extract the actual hook type from data
|
|
134
|
+
# Otherwise use "hook" as the type
|
|
135
|
+
if event == "hook_execution":
|
|
136
|
+
hook_type = data.get("hook_type", "unknown")
|
|
137
|
+
event_type = hook_type
|
|
138
|
+
else:
|
|
139
|
+
event_type = "hook"
|
|
140
|
+
|
|
122
141
|
raw_event = {
|
|
123
|
-
"type": "hook"
|
|
124
|
-
"subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop"
|
|
142
|
+
"type": event_type, # Use actual hook type for hook_execution, "hook" otherwise
|
|
143
|
+
"subtype": event, # e.g., "user_prompt", "pre_tool", "subagent_stop", "execution"
|
|
125
144
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
126
145
|
"data": data,
|
|
127
|
-
"source": "
|
|
128
|
-
"session_id":
|
|
146
|
+
"source": "mpm_hook", # Identify the source as mpm_hook
|
|
147
|
+
"session_id": session_id, # Include session if available (supports both naming conventions)
|
|
148
|
+
"cwd": cwd, # Add working directory at top level for easy frontend access
|
|
129
149
|
"correlation_id": tool_call_id, # Set from tool_call_id for event correlation
|
|
130
150
|
}
|
|
131
151
|
|
|
@@ -154,7 +174,7 @@ class ConnectionManagerService:
|
|
|
154
174
|
if self.connection_pool:
|
|
155
175
|
try:
|
|
156
176
|
# Emit to Socket.IO server directly
|
|
157
|
-
self.connection_pool.emit("
|
|
177
|
+
self.connection_pool.emit("mpm_event", claude_event_data)
|
|
158
178
|
if DEBUG:
|
|
159
179
|
print(f"✅ Emitted via connection pool: {event}", file=sys.stderr)
|
|
160
180
|
return # Success - no need for fallback
|
|
@@ -34,7 +34,7 @@ class GitRepository:
|
|
|
34
34
|
def cache_path(self) -> Path:
|
|
35
35
|
"""Return cache directory path for this repository.
|
|
36
36
|
|
|
37
|
-
Cache structure: ~/.claude-mpm/cache/
|
|
37
|
+
Cache structure: ~/.claude-mpm/cache/agents/{owner}/{repo}/{subdirectory}/
|
|
38
38
|
|
|
39
39
|
Returns:
|
|
40
40
|
Absolute path to cache directory for this repository
|
|
@@ -45,10 +45,10 @@ class GitRepository:
|
|
|
45
45
|
... subdirectory="agents"
|
|
46
46
|
... )
|
|
47
47
|
>>> repo.cache_path
|
|
48
|
-
Path('/Users/user/.claude-mpm/cache/
|
|
48
|
+
Path('/Users/user/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents')
|
|
49
49
|
"""
|
|
50
50
|
home = Path.home()
|
|
51
|
-
base_cache = home / ".claude-mpm" / "cache" / "
|
|
51
|
+
base_cache = home / ".claude-mpm" / "cache" / "agents"
|
|
52
52
|
|
|
53
53
|
# Extract owner and repo from URL
|
|
54
54
|
owner, repo = self._parse_github_url(self.url)
|
|
File without changes
|
|
@@ -29,7 +29,7 @@ Error Handling:
|
|
|
29
29
|
|
|
30
30
|
Example:
|
|
31
31
|
>>> from pathlib import Path
|
|
32
|
-
>>> manager = CacheGitManager(Path.home() / ".claude-mpm/cache/
|
|
32
|
+
>>> manager = CacheGitManager(Path.home() / ".claude-mpm/cache/agents")
|
|
33
33
|
>>> if manager.is_git_repo():
|
|
34
34
|
... status = manager.get_status()
|
|
35
35
|
... print(f"Branch: {status['branch']}, Uncommitted: {len(status['uncommitted'])}")
|
|
@@ -76,7 +76,7 @@ class CacheGitManager:
|
|
|
76
76
|
timeout: Git command timeout in seconds (default: 30)
|
|
77
77
|
|
|
78
78
|
Example:
|
|
79
|
-
>>> cache_dir = Path.home() / ".claude-mpm/cache/
|
|
79
|
+
>>> cache_dir = Path.home() / ".claude-mpm/cache/agents"
|
|
80
80
|
>>> manager = CacheGitManager(cache_dir)
|
|
81
81
|
"""
|
|
82
82
|
self.cache_path = Path(cache_path)
|
|
@@ -105,12 +105,12 @@ class CacheGitManager:
|
|
|
105
105
|
|
|
106
106
|
Example:
|
|
107
107
|
>>> # Case 1: cache_path inside repo (searches upward)
|
|
108
|
-
>>> # cache_path: ~/.claude-mpm/cache/
|
|
109
|
-
>>> # Found at: ~/.claude-mpm/cache/
|
|
108
|
+
>>> # cache_path: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/agents
|
|
109
|
+
>>> # Found at: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents
|
|
110
110
|
|
|
111
111
|
>>> # Case 2: repo nested in cache_path (searches downward)
|
|
112
|
-
>>> # cache_path: ~/.claude-mpm/cache/
|
|
113
|
-
>>> # Found at: ~/.claude-mpm/cache/
|
|
112
|
+
>>> # cache_path: ~/.claude-mpm/cache/agents
|
|
113
|
+
>>> # Found at: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents
|
|
114
114
|
"""
|
|
115
115
|
# Strategy 1: Search upward (cache_path is inside repo)
|
|
116
116
|
current = self.cache_path
|
|
@@ -876,13 +876,13 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
876
876
|
user_agents_dir = potential_user_dir
|
|
877
877
|
self.logger.info(f"Found user agents at: {user_agents_dir}")
|
|
878
878
|
|
|
879
|
-
# Check for
|
|
880
|
-
|
|
879
|
+
# Check for agents cache (from Git sources)
|
|
880
|
+
agents_cache_dir = None
|
|
881
881
|
cache_dir = user_home / ".claude-mpm" / "cache"
|
|
882
|
-
|
|
883
|
-
if
|
|
884
|
-
|
|
885
|
-
self.logger.info(f"Found
|
|
882
|
+
potential_cache_dir = cache_dir / "agents"
|
|
883
|
+
if potential_cache_dir.exists():
|
|
884
|
+
agents_cache_dir = potential_cache_dir
|
|
885
|
+
self.logger.info(f"Found agents cache at: {agents_cache_dir}")
|
|
886
886
|
|
|
887
887
|
# Get agents with version comparison and cleanup (4-tier discovery)
|
|
888
888
|
agents_to_deploy, agent_sources, cleanup_results = (
|
|
@@ -890,7 +890,7 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
890
890
|
system_templates_dir=system_templates_dir,
|
|
891
891
|
project_agents_dir=project_agents_dir,
|
|
892
892
|
user_agents_dir=user_agents_dir,
|
|
893
|
-
|
|
893
|
+
agents_cache_dir=agents_cache_dir, # NEW: 4th tier
|
|
894
894
|
working_directory=self.working_directory,
|
|
895
895
|
excluded_agents=excluded_agents,
|
|
896
896
|
config=config,
|
|
@@ -248,7 +248,7 @@ class AgentDiscoveryService:
|
|
|
248
248
|
return agent_info
|
|
249
249
|
|
|
250
250
|
except yaml.YAMLError as e:
|
|
251
|
-
self.logger.
|
|
251
|
+
self.logger.warning(f"Invalid YAML frontmatter in {template_file.name}: {e}")
|
|
252
252
|
return None
|
|
253
253
|
except Exception as e:
|
|
254
254
|
self.logger.error(
|
|
@@ -431,7 +431,7 @@ class AgentDiscoveryService:
|
|
|
431
431
|
return True
|
|
432
432
|
|
|
433
433
|
except yaml.YAMLError:
|
|
434
|
-
self.logger.
|
|
434
|
+
self.logger.warning(
|
|
435
435
|
f"Invalid YAML frontmatter in template: {template_file.name}"
|
|
436
436
|
)
|
|
437
437
|
return False
|
|
@@ -135,8 +135,8 @@ class AgentTemplateBuilder:
|
|
|
135
135
|
break
|
|
136
136
|
|
|
137
137
|
# Stop at common repository root indicators (check AFTER finding BASE-AGENT.md)
|
|
138
|
-
#
|
|
139
|
-
if current_dir.name in [".claude-mpm", "
|
|
138
|
+
# Stop at cache root or .claude-mpm directory
|
|
139
|
+
if current_dir.name in [".claude-mpm", "cache"]:
|
|
140
140
|
self.logger.debug(
|
|
141
141
|
f"Reached repository root indicator at: {current_dir}"
|
|
142
142
|
)
|
|
@@ -8,7 +8,7 @@ DEPLOYMENT ARCHITECTURE:
|
|
|
8
8
|
|
|
9
9
|
Agent Source Locations (Discovery):
|
|
10
10
|
-----------------------------------
|
|
11
|
-
1. System Agents: ~/.claude-mpm/cache/
|
|
11
|
+
1. System Agents: ~/.claude-mpm/cache/agents/bobmatnyc/claude-mpm-agents/
|
|
12
12
|
- Synced from GitHub repository
|
|
13
13
|
- Read-only (managed by git pull)
|
|
14
14
|
- 44+ agents organized by category
|
|
@@ -39,7 +39,7 @@ Why Project-Level Deployment?
|
|
|
39
39
|
Example Flow:
|
|
40
40
|
-------------
|
|
41
41
|
1. User runs: claude-mpm agents deploy
|
|
42
|
-
2. Agents synced from GitHub → ~/.claude-mpm/cache/
|
|
42
|
+
2. Agents synced from GitHub → ~/.claude-mpm/cache/agents/
|
|
43
43
|
3. Agents deployed FROM cache → .claude/agents/
|
|
44
44
|
4. Claude Code discovers agents FROM .claude/agents/
|
|
45
45
|
|
|
@@ -179,14 +179,14 @@ class MultiSourceAgentDeploymentService:
|
|
|
179
179
|
system_templates_dir: Optional[Path] = None,
|
|
180
180
|
project_agents_dir: Optional[Path] = None,
|
|
181
181
|
user_agents_dir: Optional[Path] = None,
|
|
182
|
-
|
|
182
|
+
agents_cache_dir: Optional[Path] = None,
|
|
183
183
|
working_directory: Optional[Path] = None,
|
|
184
184
|
) -> Dict[str, List[Dict[str, Any]]]:
|
|
185
|
-
"""Discover agents from all 4 tiers (system, user,
|
|
185
|
+
"""Discover agents from all 4 tiers (system, user, cache, project).
|
|
186
186
|
|
|
187
187
|
Priority hierarchy (highest to lowest):
|
|
188
188
|
4. Project agents - Highest priority, project-specific customizations
|
|
189
|
-
3.
|
|
189
|
+
3. Cached agents - GitHub-synced agents from cache
|
|
190
190
|
2. User agents - DEPRECATED, user-level customizations
|
|
191
191
|
1. System templates - Lowest priority, built-in agents
|
|
192
192
|
|
|
@@ -194,7 +194,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
194
194
|
system_templates_dir: Directory containing system agent templates
|
|
195
195
|
project_agents_dir: Directory containing project-specific agents
|
|
196
196
|
user_agents_dir: Directory containing user custom agents (DEPRECATED)
|
|
197
|
-
|
|
197
|
+
agents_cache_dir: Directory containing cached agents from Git sources
|
|
198
198
|
working_directory: Current working directory for finding project agents
|
|
199
199
|
|
|
200
200
|
Returns:
|
|
@@ -225,12 +225,12 @@ class MultiSourceAgentDeploymentService:
|
|
|
225
225
|
if not user_agents_dir.exists():
|
|
226
226
|
user_agents_dir = None
|
|
227
227
|
|
|
228
|
-
if not
|
|
229
|
-
# Check for
|
|
228
|
+
if not agents_cache_dir:
|
|
229
|
+
# Check for agents in cache directory
|
|
230
230
|
cache_dir = Path.home() / ".claude-mpm" / "cache"
|
|
231
|
-
|
|
232
|
-
if not
|
|
233
|
-
|
|
231
|
+
agents_cache_dir = cache_dir / "agents"
|
|
232
|
+
if not agents_cache_dir.exists():
|
|
233
|
+
agents_cache_dir = None
|
|
234
234
|
|
|
235
235
|
# Discover agents from each source in priority order
|
|
236
236
|
# Note: We process in reverse priority order (system first) and build up the dictionary
|
|
@@ -238,7 +238,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
238
238
|
sources = [
|
|
239
239
|
("system", system_templates_dir),
|
|
240
240
|
("user", user_agents_dir),
|
|
241
|
-
("remote",
|
|
241
|
+
("remote", agents_cache_dir),
|
|
242
242
|
("project", project_agents_dir),
|
|
243
243
|
]
|
|
244
244
|
|
|
@@ -323,7 +323,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
323
323
|
def get_agents_by_collection(
|
|
324
324
|
self,
|
|
325
325
|
collection_id: str,
|
|
326
|
-
|
|
326
|
+
agents_cache_dir: Optional[Path] = None,
|
|
327
327
|
) -> List[Dict[str, Any]]:
|
|
328
328
|
"""Get all agents from a specific collection.
|
|
329
329
|
|
|
@@ -331,7 +331,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
331
331
|
|
|
332
332
|
Args:
|
|
333
333
|
collection_id: Collection identifier (e.g., "bobmatnyc/claude-mpm-agents")
|
|
334
|
-
|
|
334
|
+
agents_cache_dir: Directory containing agents cache
|
|
335
335
|
|
|
336
336
|
Returns:
|
|
337
337
|
List of agent dictionaries from the specified collection
|
|
@@ -342,18 +342,16 @@ class MultiSourceAgentDeploymentService:
|
|
|
342
342
|
>>> len(agents)
|
|
343
343
|
45
|
|
344
344
|
"""
|
|
345
|
-
if not
|
|
345
|
+
if not agents_cache_dir:
|
|
346
346
|
cache_dir = Path.home() / ".claude-mpm" / "cache"
|
|
347
|
-
|
|
347
|
+
agents_cache_dir = cache_dir / "agents"
|
|
348
348
|
|
|
349
|
-
if not
|
|
350
|
-
self.logger.warning(
|
|
351
|
-
f"Remote agents directory not found: {remote_agents_dir}"
|
|
352
|
-
)
|
|
349
|
+
if not agents_cache_dir.exists():
|
|
350
|
+
self.logger.warning(f"Agents cache directory not found: {agents_cache_dir}")
|
|
353
351
|
return []
|
|
354
352
|
|
|
355
353
|
# Use RemoteAgentDiscoveryService to get collection agents
|
|
356
|
-
remote_service = RemoteAgentDiscoveryService(
|
|
354
|
+
remote_service = RemoteAgentDiscoveryService(agents_cache_dir)
|
|
357
355
|
collection_agents = remote_service.get_agents_by_collection(collection_id)
|
|
358
356
|
|
|
359
357
|
self.logger.info(
|
|
@@ -470,7 +468,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
470
468
|
system_templates_dir: Optional[Path] = None,
|
|
471
469
|
project_agents_dir: Optional[Path] = None,
|
|
472
470
|
user_agents_dir: Optional[Path] = None,
|
|
473
|
-
|
|
471
|
+
agents_cache_dir: Optional[Path] = None,
|
|
474
472
|
working_directory: Optional[Path] = None,
|
|
475
473
|
excluded_agents: Optional[List[str]] = None,
|
|
476
474
|
config: Optional[Config] = None,
|
|
@@ -482,7 +480,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
482
480
|
system_templates_dir: Directory containing system agent templates
|
|
483
481
|
project_agents_dir: Directory containing project-specific agents
|
|
484
482
|
user_agents_dir: Directory containing user custom agents (DEPRECATED)
|
|
485
|
-
|
|
483
|
+
agents_cache_dir: Directory containing cached agents from Git sources
|
|
486
484
|
working_directory: Current working directory for finding project agents
|
|
487
485
|
excluded_agents: List of agent names to exclude from deployment
|
|
488
486
|
config: Configuration object for additional filtering
|
|
@@ -499,7 +497,7 @@ class MultiSourceAgentDeploymentService:
|
|
|
499
497
|
system_templates_dir=system_templates_dir,
|
|
500
498
|
project_agents_dir=project_agents_dir,
|
|
501
499
|
user_agents_dir=user_agents_dir,
|
|
502
|
-
|
|
500
|
+
agents_cache_dir=agents_cache_dir,
|
|
503
501
|
working_directory=working_directory,
|
|
504
502
|
)
|
|
505
503
|
|