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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +16 -19
- claude_mpm/agents/MEMORY.md +21 -49
- claude_mpm/agents/templates/OPTIMIZATION_REPORT.md +156 -0
- claude_mpm/agents/templates/api_qa.json +36 -116
- claude_mpm/agents/templates/backup/data_engineer_agent_20250726_234551.json +42 -9
- claude_mpm/agents/templates/backup/documentation_agent_20250726_234551.json +29 -6
- claude_mpm/agents/templates/backup/engineer_agent_20250726_234551.json +34 -6
- claude_mpm/agents/templates/backup/ops_agent_20250726_234551.json +41 -9
- claude_mpm/agents/templates/backup/qa_agent_20250726_234551.json +30 -8
- claude_mpm/agents/templates/backup/research_agent_2025011_234551.json +2 -2
- claude_mpm/agents/templates/backup/research_agent_20250726_234551.json +29 -6
- claude_mpm/agents/templates/backup/research_memory_efficient.json +2 -2
- claude_mpm/agents/templates/backup/security_agent_20250726_234551.json +41 -9
- claude_mpm/agents/templates/backup/version_control_agent_20250726_234551.json +23 -7
- claude_mpm/agents/templates/code_analyzer.json +18 -36
- claude_mpm/agents/templates/data_engineer.json +43 -14
- claude_mpm/agents/templates/documentation.json +55 -74
- claude_mpm/agents/templates/engineer.json +57 -40
- claude_mpm/agents/templates/imagemagick.json +7 -2
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +36 -4
- claude_mpm/agents/templates/project_organizer.json +23 -71
- claude_mpm/agents/templates/qa.json +34 -2
- claude_mpm/agents/templates/refactoring_engineer.json +9 -5
- claude_mpm/agents/templates/research.json +36 -4
- claude_mpm/agents/templates/security.json +29 -2
- claude_mpm/agents/templates/ticketing.json +3 -3
- claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
- claude_mpm/agents/templates/version_control.json +28 -2
- claude_mpm/agents/templates/web_qa.json +38 -151
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/commands/agent_manager.py +221 -1
- claude_mpm/cli/commands/agents.py +556 -1009
- claude_mpm/cli/commands/memory.py +248 -927
- claude_mpm/cli/commands/run.py +139 -484
- claude_mpm/cli/parsers/agent_manager_parser.py +34 -0
- claude_mpm/cli/startup_logging.py +76 -0
- claude_mpm/core/agent_registry.py +6 -10
- claude_mpm/core/framework_loader.py +205 -595
- claude_mpm/core/log_manager.py +49 -1
- claude_mpm/core/logging_config.py +2 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +7 -117
- claude_mpm/hooks/claude_hooks/hook_handler.py +91 -755
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +42 -454
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/memory/agent_memory_manager.py +42 -508
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/registry/__init__.py +1 -1
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +65 -19
- claude_mpm/services/memory/router.py +116 -10
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/RECORD +86 -55
- claude_mpm/cli/commands/run_config_checker.py +0 -159
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.2.dist-info → claude_mpm-4.1.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Cleanup Service
|
|
3
|
+
=====================
|
|
4
|
+
|
|
5
|
+
WHY: This service manages agent cleanup operations including removing deployed agents
|
|
6
|
+
and cleaning up orphaned agents. It provides a clean interface for the CLI to perform
|
|
7
|
+
cleanup operations with dry-run support and progress reporting.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISIONS:
|
|
10
|
+
- Separates cleanup logic from CLI command implementation
|
|
11
|
+
- Provides dry-run mode for safe preview of changes
|
|
12
|
+
- Identifies orphaned agents (deployed without templates)
|
|
13
|
+
- Validates cleanup operations before execution
|
|
14
|
+
- Generates detailed cleanup reports for user feedback
|
|
15
|
+
- Maintains backward compatibility with existing deployment service
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
21
|
+
|
|
22
|
+
from ...core.logger import get_logger
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class IAgentCleanupService(ABC):
|
|
26
|
+
"""Interface for agent cleanup operations."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def clean_deployed_agents(
|
|
30
|
+
self, agents_dir: Optional[Path] = None
|
|
31
|
+
) -> Dict[str, Any]:
|
|
32
|
+
"""Clean up deployed agents while preserving user-created agents."""
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def clean_orphaned_agents(
|
|
36
|
+
self, agents_dir: Optional[Path] = None, dry_run: bool = True
|
|
37
|
+
) -> Dict[str, Any]:
|
|
38
|
+
"""Clean up orphaned agents that don't have templates."""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get_orphaned_agents(
|
|
42
|
+
self, agents_dir: Optional[Path] = None
|
|
43
|
+
) -> List[Dict[str, Any]]:
|
|
44
|
+
"""Find orphaned agents (deployed without templates)."""
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def perform_cleanup(
|
|
48
|
+
self,
|
|
49
|
+
agents_dir: Optional[Path] = None,
|
|
50
|
+
cleanup_type: str = "all",
|
|
51
|
+
dry_run: bool = False,
|
|
52
|
+
) -> Dict[str, Any]:
|
|
53
|
+
"""Execute cleanup with specified options."""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def validate_cleanup(self, agents_dir: Optional[Path] = None) -> Dict[str, Any]:
|
|
57
|
+
"""Verify cleanup operation safety before execution."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AgentCleanupService(IAgentCleanupService):
|
|
61
|
+
"""Service for managing agent cleanup operations with robust error handling."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, deployment_service=None):
|
|
64
|
+
"""
|
|
65
|
+
Initialize the cleanup service.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
deployment_service: Optional deployment service for cleanup operations
|
|
69
|
+
"""
|
|
70
|
+
self.logger = get_logger(__name__)
|
|
71
|
+
self._deployment_service = deployment_service
|
|
72
|
+
self._multi_source_service = None
|
|
73
|
+
|
|
74
|
+
def _get_deployment_service(self):
|
|
75
|
+
"""Get or create deployment service instance."""
|
|
76
|
+
if self._deployment_service is None:
|
|
77
|
+
from ...services.agents.deployment.agent_deployment import (
|
|
78
|
+
AgentDeploymentService,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
self._deployment_service = AgentDeploymentService()
|
|
82
|
+
return self._deployment_service
|
|
83
|
+
|
|
84
|
+
def _get_multi_source_service(self):
|
|
85
|
+
"""Get or create multi-source deployment service instance."""
|
|
86
|
+
if self._multi_source_service is None:
|
|
87
|
+
from ...services.agents.deployment.multi_source_deployment_service import (
|
|
88
|
+
MultiSourceAgentDeploymentService,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self._multi_source_service = MultiSourceAgentDeploymentService()
|
|
92
|
+
return self._multi_source_service
|
|
93
|
+
|
|
94
|
+
def _determine_agents_dir(self, agents_dir: Optional[Path] = None) -> Path:
|
|
95
|
+
"""
|
|
96
|
+
Determine the agents directory to use.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
agents_dir: Optional explicit agents directory
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Path to agents directory
|
|
103
|
+
"""
|
|
104
|
+
if agents_dir:
|
|
105
|
+
return agents_dir
|
|
106
|
+
|
|
107
|
+
# Check for project-level .claude/agents first
|
|
108
|
+
project_agents_dir = Path.cwd() / ".claude" / "agents"
|
|
109
|
+
if project_agents_dir.exists():
|
|
110
|
+
return project_agents_dir
|
|
111
|
+
|
|
112
|
+
# Fall back to user home directory
|
|
113
|
+
return Path.home() / ".claude" / "agents"
|
|
114
|
+
|
|
115
|
+
def clean_deployed_agents(
|
|
116
|
+
self, agents_dir: Optional[Path] = None
|
|
117
|
+
) -> Dict[str, Any]:
|
|
118
|
+
"""
|
|
119
|
+
Clean up deployed agents while preserving user-created agents.
|
|
120
|
+
|
|
121
|
+
This removes system-deployed agents (authored by claude-mpm) while
|
|
122
|
+
preserving any user-created agents in the directory.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
agents_dir: Optional agents directory to clean
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Dictionary containing cleanup results
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
deployment_service = self._get_deployment_service()
|
|
132
|
+
|
|
133
|
+
# Use deployment service's clean_deployment method
|
|
134
|
+
if hasattr(deployment_service, "clean_deployment"):
|
|
135
|
+
result = deployment_service.clean_deployment()
|
|
136
|
+
|
|
137
|
+
# Ensure consistent result format
|
|
138
|
+
if not isinstance(result, dict):
|
|
139
|
+
result = {"success": bool(result)}
|
|
140
|
+
|
|
141
|
+
# Add cleaned_count for backward compatibility
|
|
142
|
+
if "cleaned_count" not in result:
|
|
143
|
+
removed_count = len(result.get("removed", []))
|
|
144
|
+
result["cleaned_count"] = removed_count
|
|
145
|
+
|
|
146
|
+
return result
|
|
147
|
+
# Fallback if method doesn't exist
|
|
148
|
+
return {
|
|
149
|
+
"success": False,
|
|
150
|
+
"error": "Deployment service does not support cleanup",
|
|
151
|
+
"cleaned_count": 0,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
except Exception as e:
|
|
155
|
+
self.logger.error(f"Error cleaning deployed agents: {e}", exc_info=True)
|
|
156
|
+
return {"success": False, "error": str(e), "cleaned_count": 0}
|
|
157
|
+
|
|
158
|
+
def clean_orphaned_agents(
|
|
159
|
+
self, agents_dir: Optional[Path] = None, dry_run: bool = True
|
|
160
|
+
) -> Dict[str, Any]:
|
|
161
|
+
"""
|
|
162
|
+
Clean up orphaned agents that don't have templates.
|
|
163
|
+
|
|
164
|
+
Orphaned agents are deployed agents that no longer have corresponding
|
|
165
|
+
templates in the codebase. This method identifies and optionally removes them.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
agents_dir: Optional agents directory to clean
|
|
169
|
+
dry_run: If True, only report what would be removed
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Dictionary containing cleanup results
|
|
173
|
+
"""
|
|
174
|
+
try:
|
|
175
|
+
agents_dir = self._determine_agents_dir(agents_dir)
|
|
176
|
+
|
|
177
|
+
if not agents_dir.exists():
|
|
178
|
+
return {
|
|
179
|
+
"success": True,
|
|
180
|
+
"message": f"Agents directory not found: {agents_dir}",
|
|
181
|
+
"orphaned": [],
|
|
182
|
+
"removed": [],
|
|
183
|
+
"errors": [],
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
multi_source_service = self._get_multi_source_service()
|
|
187
|
+
|
|
188
|
+
# Perform cleanup using multi-source service
|
|
189
|
+
results = multi_source_service.cleanup_orphaned_agents(
|
|
190
|
+
agents_dir, dry_run=dry_run
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# Add success flag for consistent interface
|
|
194
|
+
if "success" not in results:
|
|
195
|
+
results["success"] = not bool(results.get("errors"))
|
|
196
|
+
|
|
197
|
+
return results
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
self.logger.error(f"Error cleaning orphaned agents: {e}", exc_info=True)
|
|
201
|
+
return {
|
|
202
|
+
"success": False,
|
|
203
|
+
"error": str(e),
|
|
204
|
+
"orphaned": [],
|
|
205
|
+
"removed": [],
|
|
206
|
+
"errors": [str(e)],
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
def get_orphaned_agents(
|
|
210
|
+
self, agents_dir: Optional[Path] = None
|
|
211
|
+
) -> List[Dict[str, Any]]:
|
|
212
|
+
"""
|
|
213
|
+
Find orphaned agents (deployed without templates).
|
|
214
|
+
|
|
215
|
+
This method identifies deployed agents that no longer have corresponding
|
|
216
|
+
templates in the codebase without removing them.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
agents_dir: Optional agents directory to check
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
List of orphaned agent information dictionaries
|
|
223
|
+
"""
|
|
224
|
+
try:
|
|
225
|
+
agents_dir = self._determine_agents_dir(agents_dir)
|
|
226
|
+
|
|
227
|
+
if not agents_dir.exists():
|
|
228
|
+
return []
|
|
229
|
+
|
|
230
|
+
multi_source_service = self._get_multi_source_service()
|
|
231
|
+
|
|
232
|
+
# Discover all available agents from all sources
|
|
233
|
+
all_agents = multi_source_service.discover_agents_from_all_sources()
|
|
234
|
+
|
|
235
|
+
# Detect orphaned agents
|
|
236
|
+
orphaned = multi_source_service.detect_orphaned_agents(
|
|
237
|
+
agents_dir, all_agents
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
return orphaned
|
|
241
|
+
|
|
242
|
+
except Exception as e:
|
|
243
|
+
self.logger.error(f"Error finding orphaned agents: {e}", exc_info=True)
|
|
244
|
+
return []
|
|
245
|
+
|
|
246
|
+
def perform_cleanup(
|
|
247
|
+
self,
|
|
248
|
+
agents_dir: Optional[Path] = None,
|
|
249
|
+
cleanup_type: str = "all",
|
|
250
|
+
dry_run: bool = False,
|
|
251
|
+
) -> Dict[str, Any]:
|
|
252
|
+
"""
|
|
253
|
+
Execute cleanup with specified options.
|
|
254
|
+
|
|
255
|
+
This method provides a unified interface for different cleanup operations.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
agents_dir: Optional agents directory to clean
|
|
259
|
+
cleanup_type: Type of cleanup ("all", "deployed", "orphaned")
|
|
260
|
+
dry_run: If True, only preview changes without executing
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Dictionary containing cleanup results
|
|
264
|
+
"""
|
|
265
|
+
try:
|
|
266
|
+
results = {
|
|
267
|
+
"success": True,
|
|
268
|
+
"cleanup_type": cleanup_type,
|
|
269
|
+
"dry_run": dry_run,
|
|
270
|
+
"operations": [],
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if cleanup_type in ["all", "deployed"]:
|
|
274
|
+
# Clean deployed agents
|
|
275
|
+
deployed_result = self.clean_deployed_agents(agents_dir)
|
|
276
|
+
results["operations"].append(
|
|
277
|
+
{"type": "deployed", "result": deployed_result}
|
|
278
|
+
)
|
|
279
|
+
if not deployed_result.get("success", False):
|
|
280
|
+
results["success"] = False
|
|
281
|
+
|
|
282
|
+
if cleanup_type in ["all", "orphaned"]:
|
|
283
|
+
# Clean orphaned agents
|
|
284
|
+
orphaned_result = self.clean_orphaned_agents(
|
|
285
|
+
agents_dir, dry_run=dry_run
|
|
286
|
+
)
|
|
287
|
+
results["operations"].append(
|
|
288
|
+
{"type": "orphaned", "result": orphaned_result}
|
|
289
|
+
)
|
|
290
|
+
if not orphaned_result.get("success", False):
|
|
291
|
+
results["success"] = False
|
|
292
|
+
|
|
293
|
+
# Calculate totals
|
|
294
|
+
total_cleaned = 0
|
|
295
|
+
total_errors = 0
|
|
296
|
+
for op in results["operations"]:
|
|
297
|
+
result = op["result"]
|
|
298
|
+
if op["type"] == "deployed":
|
|
299
|
+
total_cleaned += result.get("cleaned_count", 0)
|
|
300
|
+
elif op["type"] == "orphaned":
|
|
301
|
+
if dry_run:
|
|
302
|
+
total_cleaned += len(result.get("orphaned", []))
|
|
303
|
+
else:
|
|
304
|
+
total_cleaned += len(result.get("removed", []))
|
|
305
|
+
total_errors += len(result.get("errors", []))
|
|
306
|
+
|
|
307
|
+
results["total_cleaned"] = total_cleaned
|
|
308
|
+
results["total_errors"] = total_errors
|
|
309
|
+
|
|
310
|
+
return results
|
|
311
|
+
|
|
312
|
+
except Exception as e:
|
|
313
|
+
self.logger.error(f"Error performing cleanup: {e}", exc_info=True)
|
|
314
|
+
return {
|
|
315
|
+
"success": False,
|
|
316
|
+
"error": str(e),
|
|
317
|
+
"cleanup_type": cleanup_type,
|
|
318
|
+
"dry_run": dry_run,
|
|
319
|
+
"operations": [],
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
def validate_cleanup(self, agents_dir: Optional[Path] = None) -> Dict[str, Any]:
|
|
323
|
+
"""
|
|
324
|
+
Verify cleanup operation safety before execution.
|
|
325
|
+
|
|
326
|
+
This method checks for potential issues that might occur during cleanup
|
|
327
|
+
and provides warnings about what will be removed.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
agents_dir: Optional agents directory to validate
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Dictionary containing validation results
|
|
334
|
+
"""
|
|
335
|
+
try:
|
|
336
|
+
agents_dir = self._determine_agents_dir(agents_dir)
|
|
337
|
+
|
|
338
|
+
validation = {
|
|
339
|
+
"success": True,
|
|
340
|
+
"agents_dir": str(agents_dir),
|
|
341
|
+
"exists": agents_dir.exists(),
|
|
342
|
+
"warnings": [],
|
|
343
|
+
"info": [],
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if not agents_dir.exists():
|
|
347
|
+
validation["info"].append(
|
|
348
|
+
f"Agents directory does not exist: {agents_dir}"
|
|
349
|
+
)
|
|
350
|
+
return validation
|
|
351
|
+
|
|
352
|
+
# Count deployed agents
|
|
353
|
+
deployed_count = 0
|
|
354
|
+
user_created_count = 0
|
|
355
|
+
|
|
356
|
+
for agent_file in agents_dir.glob("*.md"):
|
|
357
|
+
try:
|
|
358
|
+
content = agent_file.read_text()
|
|
359
|
+
if "author: claude-mpm" in content.lower():
|
|
360
|
+
deployed_count += 1
|
|
361
|
+
else:
|
|
362
|
+
user_created_count += 1
|
|
363
|
+
except Exception as e:
|
|
364
|
+
validation["warnings"].append(
|
|
365
|
+
f"Could not read {agent_file.name}: {e}"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
validation["deployed_count"] = deployed_count
|
|
369
|
+
validation["user_created_count"] = user_created_count
|
|
370
|
+
|
|
371
|
+
# Check for orphaned agents
|
|
372
|
+
orphaned = self.get_orphaned_agents(agents_dir)
|
|
373
|
+
validation["orphaned_count"] = len(orphaned)
|
|
374
|
+
|
|
375
|
+
if orphaned:
|
|
376
|
+
validation["orphaned_agents"] = [
|
|
377
|
+
{"name": agent["name"], "version": agent.get("version", "unknown")}
|
|
378
|
+
for agent in orphaned
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
# Add informational messages
|
|
382
|
+
if deployed_count > 0:
|
|
383
|
+
validation["info"].append(
|
|
384
|
+
f"Found {deployed_count} system-deployed agent(s) that can be cleaned"
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
if user_created_count > 0:
|
|
388
|
+
validation["info"].append(
|
|
389
|
+
f"Found {user_created_count} user-created agent(s) that will be preserved"
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
if orphaned:
|
|
393
|
+
validation["warnings"].append(
|
|
394
|
+
f"Found {len(orphaned)} orphaned agent(s) without templates"
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
return validation
|
|
398
|
+
|
|
399
|
+
except Exception as e:
|
|
400
|
+
self.logger.error(f"Error validating cleanup: {e}", exc_info=True)
|
|
401
|
+
return {
|
|
402
|
+
"success": False,
|
|
403
|
+
"error": str(e),
|
|
404
|
+
"agents_dir": str(agents_dir) if agents_dir else "unknown",
|
|
405
|
+
"warnings": [str(e)],
|
|
406
|
+
"info": [],
|
|
407
|
+
}
|