claude-mpm 4.15.3__py3-none-any.whl → 4.16.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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (77) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/templates/agentic-coder-optimizer.json +9 -2
  3. claude_mpm/agents/templates/api_qa.json +7 -1
  4. claude_mpm/agents/templates/clerk-ops.json +8 -1
  5. claude_mpm/agents/templates/code_analyzer.json +4 -1
  6. claude_mpm/agents/templates/dart_engineer.json +11 -1
  7. claude_mpm/agents/templates/data_engineer.json +11 -1
  8. claude_mpm/agents/templates/documentation.json +6 -1
  9. claude_mpm/agents/templates/engineer.json +13 -0
  10. claude_mpm/agents/templates/gcp_ops_agent.json +8 -1
  11. claude_mpm/agents/templates/golang_engineer.json +11 -1
  12. claude_mpm/agents/templates/java_engineer.json +12 -2
  13. claude_mpm/agents/templates/local_ops_agent.json +216 -37
  14. claude_mpm/agents/templates/nextjs_engineer.json +11 -1
  15. claude_mpm/agents/templates/ops.json +8 -1
  16. claude_mpm/agents/templates/php-engineer.json +11 -1
  17. claude_mpm/agents/templates/project_organizer.json +9 -2
  18. claude_mpm/agents/templates/prompt-engineer.json +5 -1
  19. claude_mpm/agents/templates/python_engineer.json +11 -1
  20. claude_mpm/agents/templates/qa.json +7 -1
  21. claude_mpm/agents/templates/react_engineer.json +11 -1
  22. claude_mpm/agents/templates/refactoring_engineer.json +8 -1
  23. claude_mpm/agents/templates/research.json +4 -1
  24. claude_mpm/agents/templates/ruby-engineer.json +11 -1
  25. claude_mpm/agents/templates/rust_engineer.json +11 -1
  26. claude_mpm/agents/templates/security.json +6 -1
  27. claude_mpm/agents/templates/ticketing.json +6 -1
  28. claude_mpm/agents/templates/typescript_engineer.json +11 -1
  29. claude_mpm/agents/templates/vercel_ops_agent.json +8 -1
  30. claude_mpm/agents/templates/version_control.json +8 -1
  31. claude_mpm/agents/templates/web_qa.json +7 -1
  32. claude_mpm/agents/templates/web_ui.json +11 -1
  33. claude_mpm/cli/commands/configure.py +164 -16
  34. claude_mpm/cli/commands/configure_agent_display.py +6 -6
  35. claude_mpm/cli/commands/configure_behavior_manager.py +8 -8
  36. claude_mpm/cli/commands/configure_navigation.py +20 -18
  37. claude_mpm/cli/commands/configure_startup_manager.py +14 -14
  38. claude_mpm/cli/commands/configure_template_editor.py +8 -8
  39. claude_mpm/cli/interactive/__init__.py +3 -0
  40. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  41. claude_mpm/cli/startup.py +26 -0
  42. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  43. claude_mpm/dashboard/templates/index.html +3 -41
  44. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  45. claude_mpm/services/socketio/handlers/hook.py +10 -0
  46. claude_mpm/services/socketio/handlers/registry.py +4 -2
  47. claude_mpm/services/socketio/server/main.py +7 -7
  48. claude_mpm/skills/__init__.py +21 -0
  49. claude_mpm/skills/bundled/__init__.py +6 -0
  50. claude_mpm/skills/registry.py +198 -0
  51. claude_mpm/skills/skill_manager.py +310 -0
  52. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/METADATA +37 -8
  53. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/RECORD +57 -72
  54. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  55. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  56. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  57. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  58. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  59. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  60. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  61. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  63. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  64. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
  65. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  66. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  67. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  68. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  69. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
  70. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  71. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  72. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  73. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  74. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/WHEEL +0 -0
  75. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/entry_points.txt +0 -0
  76. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/licenses/LICENSE +0 -0
  77. {claude_mpm-4.15.3.dist-info → claude_mpm-4.16.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,491 @@
1
+ """Interactive Skills Selection Wizard for Claude MPM.
2
+
3
+ This module provides a step-by-step interactive wizard for selecting and configuring
4
+ skills for agents with user-friendly prompts and intelligent auto-linking.
5
+ """
6
+
7
+ from typing import Dict, List, Optional, Tuple
8
+
9
+ from claude_mpm.core.logging_config import get_logger
10
+ from claude_mpm.skills.registry import get_registry
11
+ from claude_mpm.skills.skill_manager import get_manager
12
+
13
+ logger = get_logger(__name__)
14
+
15
+
16
+ # Agent-to-skills auto-linking mappings
17
+ ENGINEER_CORE_SKILLS = [
18
+ "test-driven-development",
19
+ "systematic-debugging",
20
+ "code-review",
21
+ "refactoring-patterns",
22
+ "git-workflow",
23
+ ]
24
+
25
+ PYTHON_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
26
+ TYPESCRIPT_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
27
+ GOLANG_SKILLS = ENGINEER_CORE_SKILLS + ["async-testing"]
28
+ REACT_SKILLS = TYPESCRIPT_SKILLS + ["performance-profiling"]
29
+ NEXTJS_SKILLS = REACT_SKILLS
30
+ VUE_SKILLS = TYPESCRIPT_SKILLS + ["performance-profiling"]
31
+
32
+ OPS_SKILLS = [
33
+ "docker-containerization",
34
+ "database-migration",
35
+ "security-scanning",
36
+ "systematic-debugging",
37
+ ]
38
+
39
+ DOCUMENTATION_SKILLS = [
40
+ "api-documentation",
41
+ "code-review",
42
+ ]
43
+
44
+ QA_SKILLS = [
45
+ "test-driven-development",
46
+ "systematic-debugging",
47
+ "async-testing",
48
+ "performance-profiling",
49
+ ]
50
+
51
+ # Mapping of agent types to their recommended skills
52
+ AGENT_SKILL_MAPPING = {
53
+ # Engineer agents
54
+ "engineer": ENGINEER_CORE_SKILLS,
55
+ "python-engineer": PYTHON_SKILLS,
56
+ "typescript-engineer": TYPESCRIPT_SKILLS,
57
+ "golang-engineer": GOLANG_SKILLS,
58
+ "react-engineer": REACT_SKILLS,
59
+ "nextjs-engineer": NEXTJS_SKILLS,
60
+ "vue-engineer": VUE_SKILLS,
61
+ # Ops agents
62
+ "ops": OPS_SKILLS,
63
+ "devops": OPS_SKILLS,
64
+ "local-ops": OPS_SKILLS,
65
+ # Documentation agents
66
+ "docs": DOCUMENTATION_SKILLS,
67
+ "documentation": DOCUMENTATION_SKILLS,
68
+ "technical-writer": DOCUMENTATION_SKILLS,
69
+ # QA agents
70
+ "qa": QA_SKILLS,
71
+ "web-qa": QA_SKILLS,
72
+ "api-qa": QA_SKILLS,
73
+ "tester": QA_SKILLS,
74
+ }
75
+
76
+
77
+ class SkillsWizard:
78
+ """Interactive wizard for skills selection and configuration."""
79
+
80
+ def __init__(self):
81
+ """Initialize the skills wizard."""
82
+ self.registry = get_registry()
83
+ self.manager = get_manager()
84
+ self.logger = logger
85
+
86
+ def run_interactive_selection(
87
+ self, selected_agents: Optional[List[str]] = None
88
+ ) -> Tuple[bool, Dict[str, List[str]]]:
89
+ """Run interactive skills selection wizard.
90
+
91
+ Args:
92
+ selected_agents: List of agent IDs that were selected in agent wizard
93
+
94
+ Returns:
95
+ Tuple of (success, agent_skills_mapping)
96
+ - success: Boolean indicating if selection was successful
97
+ - agent_skills_mapping: Dict mapping agent IDs to lists of skill names
98
+ """
99
+ try:
100
+ print("\n" + "=" * 60)
101
+ print("🎯 Skills Selection Wizard")
102
+ print("=" * 60)
103
+ print("\nI'll help you select skills for your agents.")
104
+ print("Press Ctrl+C anytime to cancel.\n")
105
+
106
+ # Auto-link skills based on selected agents
107
+ agent_skills_mapping = {}
108
+ if selected_agents:
109
+ print("📋 Auto-linking skills based on selected agents...\n")
110
+ agent_skills_mapping = self._auto_link_skills(selected_agents)
111
+ self._display_auto_linked_skills(agent_skills_mapping)
112
+
113
+ # Ask if user wants to customize
114
+ customize = (
115
+ input("\nWould you like to customize skill selections? [y/N]: ")
116
+ .strip()
117
+ .lower()
118
+ )
119
+
120
+ if customize in ["y", "yes"]:
121
+ agent_skills_mapping = self._run_custom_selection(
122
+ selected_agents, agent_skills_mapping
123
+ )
124
+
125
+ # Preview final configuration
126
+ self._preview_final_configuration(agent_skills_mapping)
127
+
128
+ # Confirm
129
+ confirm = (
130
+ input("\nApply this skills configuration? [Y/n]: ").strip().lower()
131
+ )
132
+ if confirm in ["n", "no"]:
133
+ return False, {}
134
+
135
+ # Apply configuration
136
+ self._apply_skills_configuration(agent_skills_mapping)
137
+
138
+ print("\n✅ Skills configuration complete!")
139
+ return True, agent_skills_mapping
140
+
141
+ except KeyboardInterrupt:
142
+ print("\n\n❌ Skills selection cancelled")
143
+ return False, {}
144
+ except Exception as e:
145
+ error_msg = f"Skills selection error: {e}"
146
+ self.logger.error(error_msg, exc_info=True)
147
+ print(f"\n❌ {error_msg}")
148
+ return False, {}
149
+
150
+ def _auto_link_skills(self, agent_ids: List[str]) -> Dict[str, List[str]]:
151
+ """Auto-link skills to agents based on agent types.
152
+
153
+ Args:
154
+ agent_ids: List of agent IDs
155
+
156
+ Returns:
157
+ Dictionary mapping agent IDs to skill names
158
+ """
159
+ mapping = {}
160
+ for agent_id in agent_ids:
161
+ # Try to match against known patterns
162
+ skills = self._get_recommended_skills_for_agent(agent_id)
163
+ if skills:
164
+ mapping[agent_id] = skills
165
+ else:
166
+ # Default to core engineer skills if no match
167
+ mapping[agent_id] = ENGINEER_CORE_SKILLS.copy()
168
+
169
+ return mapping
170
+
171
+ def _get_recommended_skills_for_agent(self, agent_id: str) -> List[str]:
172
+ """Get recommended skills for an agent based on its ID.
173
+
174
+ Args:
175
+ agent_id: Agent identifier
176
+
177
+ Returns:
178
+ List of recommended skill names
179
+ """
180
+ agent_id_lower = agent_id.lower()
181
+
182
+ # Direct match
183
+ if agent_id_lower in AGENT_SKILL_MAPPING:
184
+ return AGENT_SKILL_MAPPING[agent_id_lower].copy()
185
+
186
+ # Fuzzy matching for common patterns
187
+ if "python" in agent_id_lower:
188
+ return PYTHON_SKILLS.copy()
189
+ if any(js in agent_id_lower for js in ["typescript", "ts", "javascript", "js"]):
190
+ return TYPESCRIPT_SKILLS.copy()
191
+ if "react" in agent_id_lower:
192
+ return REACT_SKILLS.copy()
193
+ if "next" in agent_id_lower:
194
+ return NEXTJS_SKILLS.copy()
195
+ if "vue" in agent_id_lower:
196
+ return VUE_SKILLS.copy()
197
+ if "go" in agent_id_lower or "golang" in agent_id_lower:
198
+ return GOLANG_SKILLS.copy()
199
+ if any(ops in agent_id_lower for ops in ["ops", "devops", "deploy"]):
200
+ return OPS_SKILLS.copy()
201
+ if any(qa in agent_id_lower for qa in ["qa", "test", "quality"]):
202
+ return QA_SKILLS.copy()
203
+ if any(doc in agent_id_lower for doc in ["doc", "writer", "technical"]):
204
+ return DOCUMENTATION_SKILLS.copy()
205
+ if "engineer" in agent_id_lower:
206
+ return ENGINEER_CORE_SKILLS.copy()
207
+
208
+ # Default
209
+ return []
210
+
211
+ def _display_auto_linked_skills(self, mapping: Dict[str, List[str]]):
212
+ """Display auto-linked skills configuration.
213
+
214
+ Args:
215
+ mapping: Agent-to-skills mapping
216
+ """
217
+ for agent_id, skills in mapping.items():
218
+ print(f" • {agent_id}:")
219
+ for skill in skills:
220
+ print(f" - {skill}")
221
+ print()
222
+
223
+ def _run_custom_selection(
224
+ self, agent_ids: Optional[List[str]], initial_mapping: Dict[str, List[str]]
225
+ ) -> Dict[str, List[str]]:
226
+ """Run custom skills selection for each agent.
227
+
228
+ Args:
229
+ agent_ids: List of agent IDs
230
+ initial_mapping: Initial auto-linked mapping
231
+
232
+ Returns:
233
+ Updated agent-to-skills mapping
234
+ """
235
+ mapping = initial_mapping.copy()
236
+
237
+ # Get all available bundled skills
238
+ bundled_skills = self.registry.list_skills(source="bundled")
239
+ skill_list = sorted([skill.name for skill in bundled_skills])
240
+
241
+ print("\n" + "=" * 60)
242
+ print("Available Bundled Skills:")
243
+ print("=" * 60)
244
+ for i, skill in enumerate(bundled_skills, 1):
245
+ description = (
246
+ skill.description[:60] + "..."
247
+ if len(skill.description) > 60
248
+ else skill.description
249
+ )
250
+ print(f" [{i:2d}] {skill.name}")
251
+ print(f" {description}")
252
+ print()
253
+
254
+ # If no agents provided, ask which agents to configure
255
+ if not agent_ids:
256
+ agent_ids = self._get_agents_to_configure()
257
+
258
+ # Configure each agent
259
+ for agent_id in agent_ids:
260
+ print(f"\n🔧 Configuring skills for: {agent_id}")
261
+ current_skills = mapping.get(agent_id, [])
262
+
263
+ print(f" Current skills ({len(current_skills)}):")
264
+ for skill in current_skills:
265
+ print(f" - {skill}")
266
+
267
+ modify = (
268
+ input(f"\n Modify skills for {agent_id}? [y/N]: ").strip().lower()
269
+ )
270
+ if modify not in ["y", "yes"]:
271
+ continue
272
+
273
+ # Let user select skills
274
+ print("\n Enter skill numbers (comma-separated), or:")
275
+ print(" 'all' - Select all skills")
276
+ print(" 'none' - Clear all skills")
277
+ print(" 'keep' - Keep current selection")
278
+ selection = input(" Selection: ").strip().lower()
279
+
280
+ if selection == "keep":
281
+ continue
282
+ if selection == "none":
283
+ mapping[agent_id] = []
284
+ elif selection == "all":
285
+ mapping[agent_id] = skill_list.copy()
286
+ else:
287
+ # Parse comma-separated numbers
288
+ try:
289
+ selected_indices = [
290
+ int(idx.strip()) for idx in selection.split(",")
291
+ ]
292
+ selected_skills = [
293
+ skill_list[idx - 1]
294
+ for idx in selected_indices
295
+ if 1 <= idx <= len(skill_list)
296
+ ]
297
+ mapping[agent_id] = selected_skills
298
+ except (ValueError, IndexError) as e:
299
+ print(f" ⚠️ Invalid selection, keeping current: {e}")
300
+
301
+ return mapping
302
+
303
+ def _get_agents_to_configure(self) -> List[str]:
304
+ """Ask user which agents to configure.
305
+
306
+ Returns:
307
+ List of agent IDs
308
+ """
309
+ agent_ids_input = input("\nEnter agent IDs (comma-separated): ").strip()
310
+ return [aid.strip() for aid in agent_ids_input.split(",") if aid.strip()]
311
+
312
+ def _preview_final_configuration(self, mapping: Dict[str, List[str]]):
313
+ """Display final skills configuration preview.
314
+
315
+ Args:
316
+ mapping: Agent-to-skills mapping
317
+ """
318
+ print("\n" + "=" * 60)
319
+ print("📋 Final Skills Configuration:")
320
+ print("=" * 60)
321
+
322
+ if not mapping:
323
+ print(" (No skills configured)")
324
+ return
325
+
326
+ for agent_id, skills in mapping.items():
327
+ print(f"\n {agent_id} ({len(skills)} skills):")
328
+ if skills:
329
+ for skill in skills:
330
+ print(f" ✓ {skill}")
331
+ else:
332
+ print(" (no skills)")
333
+
334
+ def _apply_skills_configuration(self, mapping: Dict[str, List[str]]):
335
+ """Apply skills configuration to skill manager.
336
+
337
+ Args:
338
+ mapping: Agent-to-skills mapping
339
+ """
340
+ for agent_id, skills in mapping.items():
341
+ # Clear existing mappings for this agent
342
+ if agent_id in self.manager.agent_skill_mapping:
343
+ self.manager.agent_skill_mapping[agent_id] = []
344
+
345
+ # Add each skill
346
+ for skill_name in skills:
347
+ self.manager.add_skill_to_agent(agent_id, skill_name)
348
+
349
+ self.logger.info(f"Applied skills configuration for {len(mapping)} agents")
350
+
351
+ def list_available_skills(self):
352
+ """Display all available skills."""
353
+ print("\n" + "=" * 60)
354
+ print("📚 Available Skills")
355
+ print("=" * 60)
356
+
357
+ # Bundled skills
358
+ bundled_skills = self.registry.list_skills(source="bundled")
359
+ if bundled_skills:
360
+ print(f"\n🔹 Bundled Skills ({len(bundled_skills)}):")
361
+ for skill in sorted(bundled_skills, key=lambda s: s.name):
362
+ print(f" • {skill.name}")
363
+ if skill.description:
364
+ desc = (
365
+ skill.description[:80] + "..."
366
+ if len(skill.description) > 80
367
+ else skill.description
368
+ )
369
+ print(f" {desc}")
370
+
371
+ # User skills
372
+ user_skills = self.registry.list_skills(source="user")
373
+ if user_skills:
374
+ print(f"\n👤 User Skills ({len(user_skills)}):")
375
+ for skill in sorted(user_skills, key=lambda s: s.name):
376
+ print(f" • {skill.name}")
377
+ if skill.description:
378
+ desc = (
379
+ skill.description[:80] + "..."
380
+ if len(skill.description) > 80
381
+ else skill.description
382
+ )
383
+ print(f" {desc}")
384
+
385
+ # Project skills
386
+ project_skills = self.registry.list_skills(source="project")
387
+ if project_skills:
388
+ print(f"\n📂 Project Skills ({len(project_skills)}):")
389
+ for skill in sorted(project_skills, key=lambda s: s.name):
390
+ print(f" • {skill.name}")
391
+ if skill.description:
392
+ desc = (
393
+ skill.description[:80] + "..."
394
+ if len(skill.description) > 80
395
+ else skill.description
396
+ )
397
+ print(f" {desc}")
398
+
399
+ print()
400
+
401
+
402
+ def discover_and_link_runtime_skills():
403
+ """Discover user/project skills and auto-link to agents at runtime.
404
+
405
+ This function is called during startup to:
406
+ 1. Reload the skills registry (picks up new skills from .claude/skills/)
407
+ 2. Auto-link discovered skills to agents based on tags/naming conventions
408
+ """
409
+ try:
410
+ registry = get_registry()
411
+ manager = get_manager()
412
+
413
+ # Reload registry to pick up new skills
414
+ registry.reload()
415
+
416
+ # Get discovered skills (user and project)
417
+ discovered_skills = registry.list_skills(source="user") + registry.list_skills(
418
+ source="project"
419
+ )
420
+
421
+ if not discovered_skills:
422
+ logger.debug("No runtime skills discovered")
423
+ return
424
+
425
+ logger.info(f"Discovered {len(discovered_skills)} runtime skills")
426
+
427
+ # Auto-link based on skill content and naming
428
+ for skill in discovered_skills:
429
+ agents = _infer_agents_for_skill(skill)
430
+ for agent_id in agents:
431
+ manager.add_skill_to_agent(agent_id, skill.name)
432
+ logger.debug(f"Auto-linked skill '{skill.name}' to agent '{agent_id}'")
433
+
434
+ except Exception as e:
435
+ logger.error(f"Error during runtime skills discovery: {e}", exc_info=True)
436
+
437
+
438
+ def _infer_agents_for_skill(skill) -> List[str]:
439
+ """Infer which agents should have this skill based on tags/name.
440
+
441
+ Args:
442
+ skill: Skill object to analyze
443
+
444
+ Returns:
445
+ List of agent IDs that should have this skill
446
+ """
447
+ agents = []
448
+ content_lower = skill.content.lower()
449
+ name_lower = skill.name.lower()
450
+
451
+ # Python-related
452
+ if any(
453
+ tag in content_lower or tag in name_lower
454
+ for tag in ["python", "django", "flask", "fastapi"]
455
+ ):
456
+ agents.append("python-engineer")
457
+
458
+ # TypeScript/JavaScript-related
459
+ if any(
460
+ tag in content_lower or tag in name_lower
461
+ for tag in ["typescript", "javascript", "react", "next", "vue", "node"]
462
+ ):
463
+ agents.extend(["typescript-engineer", "react-engineer", "nextjs-engineer"])
464
+
465
+ # Go-related
466
+ if any(tag in content_lower or tag in name_lower for tag in ["golang", "go "]):
467
+ agents.append("golang-engineer")
468
+
469
+ # Ops-related
470
+ if any(
471
+ tag in content_lower or tag in name_lower
472
+ for tag in ["docker", "kubernetes", "deploy", "devops", "ops"]
473
+ ):
474
+ agents.extend(["ops", "devops", "local-ops"])
475
+
476
+ # Testing/QA-related
477
+ if any(
478
+ tag in content_lower or tag in name_lower
479
+ for tag in ["test", "qa", "quality", "assert"]
480
+ ):
481
+ agents.extend(["qa", "web-qa", "api-qa"])
482
+
483
+ # Documentation-related
484
+ if any(
485
+ tag in content_lower or tag in name_lower
486
+ for tag in ["documentation", "docs", "api doc", "openapi"]
487
+ ):
488
+ agents.extend(["docs", "documentation", "technical-writer"])
489
+
490
+ # Remove duplicates
491
+ return list(set(agents))
claude_mpm/cli/startup.py CHANGED
@@ -79,6 +79,31 @@ def setup_configure_command_environment(args):
79
79
  logging.getLogger("claude_mpm").setLevel(logging.WARNING)
80
80
 
81
81
 
82
+ def discover_and_link_runtime_skills():
83
+ """
84
+ Discover and link runtime skills from user/project directories.
85
+
86
+ WHY: Automatically discover and link skills added to .claude/skills/
87
+ without requiring manual configuration.
88
+
89
+ DESIGN DECISION: Failures are logged but don't block startup to ensure
90
+ claude-mpm remains functional even if skills discovery fails.
91
+ """
92
+ try:
93
+ from ..cli.interactive.skills_wizard import (
94
+ discover_and_link_runtime_skills as discover_skills,
95
+ )
96
+
97
+ discover_skills()
98
+ except Exception as e:
99
+ # Import logger here to avoid circular imports
100
+ from ..core.logger import get_logger
101
+
102
+ logger = get_logger("cli")
103
+ logger.debug(f"Failed to discover runtime skills: {e}")
104
+ # Continue execution - skills discovery failure shouldn't block startup
105
+
106
+
82
107
  def run_background_services():
83
108
  """
84
109
  Initialize all background services on startup.
@@ -89,6 +114,7 @@ def run_background_services():
89
114
  check_mcp_auto_configuration()
90
115
  verify_mcp_gateway_startup()
91
116
  check_for_updates_async()
117
+ discover_and_link_runtime_skills()
92
118
 
93
119
 
94
120
  def setup_mcp_server_logging(args):
@@ -321,14 +321,6 @@ class Dashboard {
321
321
  // Process agent inference for new events
322
322
  this.agentInference.processAgentInference();
323
323
 
324
- // Notify CodeViewer that file operations have been updated
325
- // This ensures File Tree tab shows the same data as Files tab
326
- if (window.CodeViewer && typeof window.CodeViewer.refreshFromFileToolTracker === 'function') {
327
- setTimeout(() => {
328
- window.CodeViewer.refreshFromFileToolTracker();
329
- }, 50);
330
- }
331
-
332
324
  // Update agent hierarchy with new events
333
325
  this.agentHierarchy.updateWithNewEvents(events);
334
326
 
@@ -445,12 +437,6 @@ class Dashboard {
445
437
  case 'events':
446
438
  // Events tab is handled by EventViewer
447
439
  break;
448
- case 'claude-tree':
449
- // File Tree tab - trigger CodeViewer rendering
450
- if (window.CodeViewer && typeof window.CodeViewer.show === 'function') {
451
- window.CodeViewer.show();
452
- }
453
- break;
454
440
  case 'activity':
455
441
  // Trigger Activity tab rendering through the component
456
442
  // Check if ActivityTree class is available (from built module)
@@ -33,7 +33,6 @@
33
33
  <link rel="stylesheet" href="/static/css/dashboard.css">
34
34
  <link rel="stylesheet" href="/static/css/connection-status.css">
35
35
  <link rel="stylesheet" href="/static/css/activity.css">
36
- <link rel="stylesheet" href="/static/css/code-tree.css">
37
36
 
38
37
  <!-- Additional styles for file operations -->
39
38
  <style>
@@ -258,7 +257,6 @@
258
257
  <a href="#tools" class="tab-button" data-tab="tools">🔧 Tools</a>
259
258
  <a href="#files" class="tab-button" data-tab="files">📁 Files</a>
260
259
  <a href="#activity" class="tab-button" data-tab="activity">🌳 Activity</a>
261
- <a href="#file_tree" class="tab-button" data-tab="claude-tree">📝 File Tree</a>
262
260
  </div>
263
261
 
264
262
  <!-- Events Tab -->
@@ -397,15 +395,6 @@
397
395
  </div>
398
396
  </div>
399
397
 
400
- <!-- File Tree Tab -->
401
- <div class="tab-content" id="claude-tree-tab">
402
- <div id="claude-tree-container" style="width: 100%; height: 100%; position: relative;">
403
- <!-- File activity tree will be rendered here by code-viewer.js -->
404
- <!-- This container is ISOLATED from other tabs -->
405
- </div>
406
- </div>
407
-
408
-
409
398
  </div>
410
399
  </div>
411
400
  </div>
@@ -489,16 +478,12 @@
489
478
  });
490
479
  };
491
480
 
492
- // Load shared services first, then tree modules, then components
481
+ // Load shared services first, then components
493
482
  // Load services sequentially to ensure dependencies are available
494
483
  loadModule('/static/js/shared/tooltip-service.js')
495
484
  .then(() => loadModule('/static/js/shared/dom-helpers.js'))
496
485
  .then(() => loadModule('/static/js/shared/event-bus.js'))
497
486
  .then(() => loadModule('/static/js/shared/logger.js'))
498
- .then(() => loadModule('/static/js/components/code-tree/tree-utils.js'))
499
- .then(() => loadModule('/static/js/components/code-tree/tree-constants.js'))
500
- .then(() => loadModule('/static/js/components/code-tree/tree-search.js'))
501
- .then(() => loadModule('/static/js/components/code-tree/tree-breadcrumb.js'))
502
487
  .then(() => {
503
488
  // CRITICAL: Load socket-client.js FIRST (dependency of socket-manager)
504
489
  return loadModule('/static/js/socket-client.js');
@@ -530,29 +515,15 @@
530
515
  return Promise.all([
531
516
  loadModule('/static/dist/dashboard.js'), // Use dist version that requires above components
532
517
  loadModule('/static/dist/components/activity-tree.js'),
533
- loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
534
- loadModule('/static/js/components/code-viewer.js').catch(err => {
535
- console.error('[CRITICAL] Failed to load code-viewer.js:', err);
536
- throw err;
537
- }), // Code viewer now includes file change tracking
538
518
  loadModule('/static/dist/components/file-viewer.js') // File viewer for viewing file contents
539
519
  ]);
540
520
  })
541
521
  .then(() => {
542
522
  console.log('All dashboard modules loaded successfully');
543
-
544
- // Debug: Check if CodeViewer loaded
545
- if (window.CodeViewer) {
546
- console.log('[DEBUG] CodeViewer is available on window object');
547
- } else {
548
- console.error('[ERROR] CodeViewer NOT FOUND on window object!');
549
- }
550
-
551
- // CodeViewer will auto-initialize and handle tab switching internally
552
-
523
+
553
524
  // Browser Log Viewer initialization is now handled by UIStateManager
554
525
  // This prevents duplicate event handlers and tab selection conflicts
555
-
526
+
556
527
  // Load bulletproof tab isolation fix
557
528
  loadModule('/static/js/tab-isolation-fix.js')
558
529
  .then(() => {
@@ -564,15 +535,6 @@
564
535
 
565
536
  // Hash navigation will handle default tab based on URL
566
537
  // If no hash, default will be 'events' as per hashToTab mapping
567
- // To start with File Tree, we can set hash if not present
568
- setTimeout(() => {
569
- if (!window.location.hash) {
570
- console.log('No hash present, setting default to File Tree tab...');
571
- window.location.hash = '#file_tree';
572
- } else {
573
- console.log('Hash present:', window.location.hash);
574
- }
575
- }, 500);
576
538
  })
577
539
  .catch(error => {
578
540
  console.error('[CRITICAL] Error loading dashboard modules:', error);
@@ -7,7 +7,9 @@ and maintainability.
7
7
  """
8
8
 
9
9
  from .base import BaseEventHandler
10
- from .code_analysis import CodeAnalysisEventHandler
10
+
11
+ # DISABLED: File Tree interface removed from dashboard
12
+ # from .code_analysis import CodeAnalysisEventHandler
11
13
  from .connection import ConnectionEventHandler
12
14
  from .file import FileEventHandler
13
15
  from .git import GitEventHandler
@@ -17,7 +19,8 @@ from .registry import EventHandlerRegistry
17
19
 
18
20
  __all__ = [
19
21
  "BaseEventHandler",
20
- "CodeAnalysisEventHandler",
22
+ # DISABLED: File Tree interface removed from dashboard
23
+ # "CodeAnalysisEventHandler",
21
24
  "ConnectionEventHandler",
22
25
  "EventHandlerRegistry",
23
26
  "FileEventHandler",