claude-mpm 4.7.4__py3-none-any.whl → 4.7.6__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 CHANGED
@@ -1 +1 @@
1
- 4.7.4
1
+ 4.7.6
@@ -374,7 +374,9 @@ class ConfigureCommand(BaseCommand):
374
374
  self.console.print(menu_panel)
375
375
  self.console.print()
376
376
 
377
- return Prompt.ask("[bold cyan]Select an option[/bold cyan]", default="q")
377
+ choice = Prompt.ask("[bold cyan]Select an option[/bold cyan]", default="q")
378
+ # Strip whitespace to handle leading/trailing spaces
379
+ return choice.strip().lower()
378
380
 
379
381
  def _manage_agents(self) -> None:
380
382
  """Agent management interface."""
@@ -425,7 +427,7 @@ class ConfigureCommand(BaseCommand):
425
427
  table.add_column("ID", style="dim", width=3)
426
428
  table.add_column("Name", style="cyan", width=22)
427
429
  table.add_column("Status", width=12)
428
- table.add_column("Description", style="white", width=45)
430
+ table.add_column("Description", style="bold cyan", width=45)
429
431
  table.add_column("Model/Tools", style="dim", width=20)
430
432
 
431
433
  for idx, agent in enumerate(agents, 1):
@@ -456,12 +458,11 @@ class ConfigureCommand(BaseCommand):
456
458
  except Exception:
457
459
  tools_display = "Default"
458
460
 
459
- # Truncate description for table display
460
- desc_display = (
461
- agent.description[:42] + "..."
462
- if len(agent.description) > 42
463
- else agent.description
464
- )
461
+ # Truncate description for table display with bright styling
462
+ if len(agent.description) > 42:
463
+ desc_display = f"[cyan]{agent.description[:42]}[/cyan][dim]...[/dim]"
464
+ else:
465
+ desc_display = f"[cyan]{agent.description}[/cyan]"
465
466
 
466
467
  table.add_row(str(idx), agent.name, status, desc_display, tools_display)
467
468
 
@@ -821,6 +822,61 @@ class ConfigureCommand(BaseCommand):
821
822
  with self.console.pager():
822
823
  self.console.print(syntax)
823
824
 
825
+ def _reset_agent_defaults(self, agents: List[AgentConfig]) -> None:
826
+ """Reset an agent to default enabled state and remove custom template.
827
+
828
+ This method:
829
+ - Prompts for agent ID
830
+ - Resets agent to enabled state
831
+ - Removes any custom template overrides
832
+ - Shows success/error messages
833
+ """
834
+ agent_id = Prompt.ask("Enter agent ID to reset to defaults")
835
+
836
+ try:
837
+ idx = int(agent_id) - 1
838
+ if 0 <= idx < len(agents):
839
+ agent = agents[idx]
840
+
841
+ # Confirm the reset action
842
+ if not Confirm.ask(
843
+ f"[yellow]Reset '{agent.name}' to defaults? This will:[/yellow]\n"
844
+ " - Enable the agent\n"
845
+ " - Remove custom template (if any)\n"
846
+ "[yellow]Continue?[/yellow]"
847
+ ):
848
+ self.console.print("[yellow]Reset cancelled.[/yellow]")
849
+ Prompt.ask("Press Enter to continue")
850
+ return
851
+
852
+ # Enable the agent
853
+ self.agent_manager.set_agent_enabled(agent.name, True)
854
+
855
+ # Remove custom template if exists
856
+ template_path = self._get_agent_template_path(agent.name)
857
+ if template_path.exists() and not str(template_path).startswith(
858
+ str(self.agent_manager.templates_dir)
859
+ ):
860
+ # This is a custom template, remove it
861
+ template_path.unlink(missing_ok=True)
862
+ self.console.print(
863
+ f"[green]✓ Removed custom template for '{agent.name}'[/green]"
864
+ )
865
+
866
+ self.console.print(
867
+ f"[green]✓ Agent '{agent.name}' reset to defaults![/green]"
868
+ )
869
+ self.console.print(
870
+ "[dim]Agent is now enabled with system template.[/dim]"
871
+ )
872
+ else:
873
+ self.console.print("[red]Invalid agent ID.[/red]")
874
+
875
+ except ValueError:
876
+ self.console.print("[red]Invalid input. Please enter a number.[/red]")
877
+
878
+ Prompt.ask("Press Enter to continue")
879
+
824
880
  def _view_agent_details(self, agents: List[AgentConfig]) -> None:
825
881
  """View detailed information about an agent."""
826
882
  agent_id = Prompt.ask("Enter agent ID to view")
@@ -1331,7 +1387,7 @@ class ConfigureCommand(BaseCommand):
1331
1387
  table.add_column("ID", style="dim", width=5)
1332
1388
  table.add_column("Agent", style="cyan", width=25)
1333
1389
  table.add_column("Status", width=15)
1334
- table.add_column("Description", style="white", width=45)
1390
+ table.add_column("Description", style="bold cyan", width=45)
1335
1391
 
1336
1392
  for idx, agent in enumerate(agents, 1):
1337
1393
  # Agent is ENABLED if NOT in disabled list
@@ -1341,11 +1397,13 @@ class ConfigureCommand(BaseCommand):
1341
1397
  if is_enabled
1342
1398
  else "[red]✗ Disabled[/red]"
1343
1399
  )
1344
- desc_display = (
1345
- agent.description[:42] + "..."
1346
- if len(agent.description) > 42
1347
- else agent.description
1348
- )
1400
+ # Format description with bright styling
1401
+ if len(agent.description) > 42:
1402
+ desc_display = (
1403
+ f"[cyan]{agent.description[:42]}[/cyan][dim]...[/dim]"
1404
+ )
1405
+ else:
1406
+ desc_display = f"[cyan]{agent.description}[/cyan]"
1349
1407
  table.add_row(str(idx), agent.name, status, desc_display)
1350
1408
 
1351
1409
  self.console.print(table)
@@ -19,7 +19,6 @@ from rich.console import Console
19
19
  from rich.panel import Panel
20
20
  from rich.progress import Progress, SpinnerColumn, TextColumn
21
21
  from rich.prompt import Prompt
22
- from rich.table import Table
23
22
 
24
23
  from claude_mpm.core.logging_utils import get_logger
25
24
 
@@ -28,6 +27,7 @@ from claude_mpm.services.project.archive_manager import ArchiveManager
28
27
  from claude_mpm.services.project.documentation_manager import DocumentationManager
29
28
  from claude_mpm.services.project.enhanced_analyzer import EnhancedProjectAnalyzer
30
29
  from claude_mpm.services.project.project_organizer import ProjectOrganizer
30
+ from claude_mpm.utils.display_helper import DisplayHelper
31
31
 
32
32
  logger = get_logger(__name__)
33
33
  console = Console()
@@ -46,6 +46,7 @@ class MPMInitCommand:
46
46
  self.organizer = ProjectOrganizer(self.project_path)
47
47
  self.archive_manager = ArchiveManager(self.project_path)
48
48
  self.analyzer = EnhancedProjectAnalyzer(self.project_path)
49
+ self.display = DisplayHelper(console)
49
50
 
50
51
  def initialize_project(
51
52
  self,
@@ -426,34 +427,7 @@ The final CLAUDE.md should be a comprehensive, well-organized guide that any AI
426
427
 
427
428
  def _display_documentation_status(self, analysis: Dict) -> None:
428
429
  """Display current documentation status."""
429
- table = Table(title="Current CLAUDE.md Status", show_header=True)
430
- table.add_column("Property", style="cyan")
431
- table.add_column("Value", style="white")
432
-
433
- table.add_row("Size", f"{analysis.get('size', 0):,} characters")
434
- table.add_row("Lines", str(analysis.get("lines", 0)))
435
- table.add_row("Sections", str(len(analysis.get("sections", []))))
436
- table.add_row(
437
- "Has Priority Index", "✓" if analysis.get("has_priority_index") else "✗"
438
- )
439
- table.add_row(
440
- "Has Priority Markers", "✓" if analysis.get("has_priority_markers") else "✗"
441
- )
442
-
443
- if analysis.get("last_modified"):
444
- table.add_row("Last Modified", analysis["last_modified"])
445
-
446
- console.print(table)
447
-
448
- if analysis.get("outdated_patterns"):
449
- console.print("\n[yellow]⚠️ Outdated patterns detected:[/yellow]")
450
- for pattern in analysis["outdated_patterns"]:
451
- console.print(f" • {pattern}")
452
-
453
- if analysis.get("custom_sections"):
454
- console.print("\n[blue][INFO]️ Custom sections found:[/blue]")
455
- for section in analysis["custom_sections"][:5]:
456
- console.print(f" • {section}")
430
+ self.display.display_documentation_status(analysis)
457
431
 
458
432
  def _prompt_update_action(self) -> str:
459
433
  """Prompt user for update action."""
@@ -526,29 +500,26 @@ The final CLAUDE.md should be a comprehensive, well-organized guide that any AI
526
500
  self, structure: Dict, docs: Dict, git: Optional[Dict], state: Dict
527
501
  ) -> None:
528
502
  """Display comprehensive review report."""
529
- console.print("\n" + "=" * 60)
530
- console.print("[bold]PROJECT REVIEW REPORT[/bold]")
531
- console.print("=" * 60 + "\n")
503
+ self.display.display_header("PROJECT REVIEW REPORT")
532
504
 
533
505
  # Project State
534
- console.print("[bold cyan]📊 Project State[/bold cyan]")
535
- console.print(f" Phase: {state.get('phase', 'unknown')}")
506
+ state_data = {"Phase": state.get("phase", "unknown")}
536
507
  if state.get("indicators"):
537
- console.print(" Indicators:")
538
- for indicator in state["indicators"][:5]:
539
- console.print(f" • {indicator}")
508
+ state_data["Indicators"] = state["indicators"][:5]
509
+ self.display.display_report_section("📊 Project State", state_data)
540
510
 
541
511
  # Structure Report
542
- console.print("\n[bold cyan]📁 Project Structure[/bold cyan]")
543
- console.print(f" Existing directories: {len(structure.get('exists', []))}")
544
- console.print(f" Missing directories: {len(structure.get('missing', []))}")
512
+ structure_data = {
513
+ "Existing directories": len(structure.get("exists", [])),
514
+ "Missing directories": len(structure.get("missing", [])),
515
+ }
545
516
  if structure.get("issues"):
546
- console.print(f" Issues found: {len(structure['issues'])}")
547
- for issue in structure["issues"][:3]:
548
- console.print(f" ⚠️ {issue['description']}")
517
+ structure_data["Issues found"] = len(structure["issues"])
518
+ structure_data["Issues"] = structure["issues"][:3]
519
+ self.display.display_report_section("📁 Project Structure", structure_data)
549
520
 
550
521
  # Documentation Report
551
- console.print("\n[bold cyan]📚 Documentation Status[/bold cyan]")
522
+ self.display.display_section_title("📚 Documentation Status")
552
523
  if docs.get("exists"):
553
524
  console.print(f" CLAUDE.md: Found ({docs.get('size', 0):,} chars)")
554
525
  console.print(f" Sections: {len(docs.get('sections', []))}")
@@ -560,32 +531,34 @@ The final CLAUDE.md should be a comprehensive, well-organized guide that any AI
560
531
 
561
532
  # Git Analysis
562
533
  if git and git.get("git_available"):
563
- console.print("\n[bold cyan]📈 Recent Activity (30 days)[/bold cyan]")
564
- console.print(f" Commits: {len(git.get('recent_commits', []))}")
565
- console.print(
566
- f" Authors: {git.get('authors', {}).get('total_authors', 0)}"
567
- )
568
- console.print(
569
- f" Changed files: {git.get('changed_files', {}).get('total_files', 0)}"
570
- )
534
+ git_metrics = {
535
+ "Commits": len(git.get("recent_commits", [])),
536
+ "Authors": git.get("authors", {}).get("total_authors", 0),
537
+ "Changed files": git.get("changed_files", {}).get("total_files", 0),
538
+ }
571
539
 
572
540
  if git.get("branch_info"):
573
541
  branch_info = git["branch_info"]
574
- console.print(
575
- f" Current branch: {branch_info.get('current_branch', 'unknown')}"
542
+ git_metrics["Current branch"] = branch_info.get(
543
+ "current_branch", "unknown"
544
+ )
545
+
546
+ self.display.display_metrics_section(
547
+ "📈 Recent Activity (30 days)", git_metrics
548
+ )
549
+
550
+ if git.get("branch_info", {}).get("has_uncommitted_changes"):
551
+ self.display.display_metric_row(
552
+ "⚠️ Uncommitted changes",
553
+ f"{git['branch_info'].get('uncommitted_files', 0)} files",
554
+ warning=True,
576
555
  )
577
- if branch_info.get("has_uncommitted_changes"):
578
- console.print(
579
- f" ⚠️ Uncommitted changes: {branch_info.get('uncommitted_files', 0)} files"
580
- )
581
556
 
582
557
  # Recommendations
583
558
  if state.get("recommendations"):
584
- console.print("\n[bold cyan]💡 Recommendations[/bold cyan]")
585
- for rec in state["recommendations"][:5]:
586
- console.print(f" → {rec}")
559
+ self.display.display_recommendations(state["recommendations"])
587
560
 
588
- console.print("\n" + "=" * 60 + "\n")
561
+ self.display.display_separator()
589
562
 
590
563
  def _run_quick_update_mode(
591
564
  self,
@@ -881,70 +854,49 @@ The final CLAUDE.md should be a comprehensive, well-organized guide that any AI
881
854
 
882
855
  def _display_activity_report(self, report: Dict) -> None:
883
856
  """Display the activity report in a formatted manner."""
884
- console.print("\n" + "=" * 60)
885
- console.print("[bold]RECENT ACTIVITY SUMMARY[/bold]")
886
- console.print("=" * 60 + "\n")
857
+ self.display.display_header("RECENT ACTIVITY SUMMARY")
887
858
 
888
859
  summary = report.get("summary", {})
889
860
  period = report.get("period", "Last 30 days")
890
861
 
891
862
  # Summary statistics
892
- console.print(f"[bold cyan]📊 Activity Overview ({period.lower()})[/bold cyan]")
893
- console.print(f" Total commits: {summary.get('total_commits', 0)}")
894
- console.print(f" Active contributors: {summary.get('total_authors', 0)}")
895
- console.print(f" Files modified: {summary.get('files_changed', 0)}")
896
- console.print(f" Current branch: {summary.get('current_branch', 'unknown')}")
897
-
898
- if summary.get("has_uncommitted"):
899
- console.print(
900
- f" [yellow]⚠️ Uncommitted changes: {summary.get('uncommitted_count', 0)} files[/yellow]"
901
- )
863
+ self.display.display_activity_summary(summary, period)
902
864
 
903
865
  # Recent commits
904
866
  recent_commits = report.get("recent_commits", [])
905
867
  if recent_commits:
906
- console.print("\n[bold cyan]📝 Recent Commits (last 10)[/bold cyan]")
907
- for commit in recent_commits[:10]:
908
- console.print(
909
- f" [{commit['hash']}] {commit['message'][:60]} - {commit['author']}"
910
- )
868
+ self.display.display_commit_list(recent_commits)
911
869
 
912
870
  # Hot files
913
871
  hot_files = report.get("hot_files", [])
914
872
  if hot_files:
915
- console.print("\n[bold cyan]🔥 Most Changed Files[/bold cyan]")
916
- for file_path, changes in hot_files[:10]:
917
- console.print(f" {file_path}: {changes} changes")
873
+ self.display.display_file_change_list(hot_files)
918
874
 
919
875
  # Active branches
920
876
  branches = report.get("active_branches", [])
877
+ current_branch = summary.get("current_branch", "unknown")
921
878
  if branches:
922
- console.print("\n[bold cyan]🌿 Active Branches[/bold cyan]")
923
- for branch in branches:
924
- marker = "→" if branch == summary.get("current_branch") else " "
925
- console.print(f" {marker} {branch}")
879
+ self.display.display_branch_list(branches, current_branch)
926
880
 
927
881
  # Documentation status
928
882
  doc_status = report.get("doc_status", {})
929
883
  if doc_status:
930
- console.print("\n[bold cyan]📚 CLAUDE.md Status[/bold cyan]")
931
- console.print(f" Size: {doc_status.get('size', 0):,} characters")
932
- console.print(f" Lines: {doc_status.get('lines', 0)}")
933
- console.print(
934
- f" Priority markers: {'' if doc_status.get('has_priority_markers') else ''}"
935
- )
936
- console.print(
937
- f" Last modified: {doc_status.get('last_modified', 'unknown')}"
938
- )
884
+ doc_metrics = {
885
+ "Size": f"{doc_status.get('size', 0):,} characters",
886
+ "Lines": doc_status.get("lines", 0),
887
+ "Priority markers": (
888
+ "✓" if doc_status.get("has_priority_markers") else "✗"
889
+ ),
890
+ "Last modified": doc_status.get("last_modified", "unknown"),
891
+ }
892
+ self.display.display_metrics_section("📚 CLAUDE.md Status", doc_metrics)
939
893
 
940
894
  # Recommendations
941
895
  recommendations = report.get("recommendations", [])
942
896
  if recommendations:
943
- console.print("\n[bold cyan]💡 Recommendations[/bold cyan]")
944
- for rec in recommendations:
945
- console.print(f" → {rec}")
897
+ self.display.display_recommendations(recommendations)
946
898
 
947
- console.print("\n" + "=" * 60 + "\n")
899
+ self.display.display_separator()
948
900
 
949
901
  def _append_activity_notes(self, claude_md_path: Path, report: Dict) -> None:
950
902
  """Append activity notes to CLAUDE.md."""
@@ -1419,39 +1371,35 @@ preserving valuable project-specific information while refreshing standard secti
1419
1371
  if result["status"] == "success":
1420
1372
  console.print("\n[green]✅ Project Initialization Complete![/green]\n")
1421
1373
 
1374
+ # Display files created
1422
1375
  if result.get("files_created"):
1423
- console.print("[bold]Files Created:[/bold]")
1424
- for file in result["files_created"]:
1425
- console.print(f" • {file}")
1426
- console.print()
1376
+ self.display.display_files_list(
1377
+ "Files Created:", result["files_created"]
1378
+ )
1427
1379
 
1380
+ # Display files updated
1428
1381
  if result.get("files_updated"):
1429
- console.print("[bold]Files Updated:[/bold]")
1430
- for file in result["files_updated"]:
1431
- console.print(f" • {file}")
1432
- console.print()
1382
+ self.display.display_files_list(
1383
+ "Files Updated:", result["files_updated"]
1384
+ )
1433
1385
 
1386
+ # Display next steps
1434
1387
  if result.get("next_steps"):
1435
- console.print("[bold]Next Steps:[/bold]")
1436
- for step in result["next_steps"]:
1437
- console.print(f" → {step}")
1438
- console.print()
1439
-
1440
- console.print(
1441
- Panel(
1442
- "[green]Your project is now optimized for Claude Code and Claude MPM![/green]\n\n"
1443
- "Key files:\n"
1444
- "• [cyan]CLAUDE.md[/cyan] - Main documentation for AI agents\n"
1445
- " - Organized with priority rankings (🔴🟡🟢⚪)\n"
1446
- " - Instructions ranked by importance for AI understanding\n"
1447
- " - Holistic documentation review completed\n"
1448
- "• [cyan].claude-mpm/[/cyan] - Configuration and memories\n"
1449
- "• [cyan]CODE_STRUCTURE.md[/cyan] - AST-derived architecture documentation (if enabled)\n\n"
1450
- "[dim]Run 'claude-mpm run' to start using the optimized setup[/dim]",
1451
- title="Success",
1452
- border_style="green",
1453
- )
1388
+ self.display.display_next_steps(result["next_steps"])
1389
+
1390
+ # Display success panel
1391
+ success_content = (
1392
+ "[green]Your project is now optimized for Claude Code and Claude MPM![/green]\n\n"
1393
+ "Key files:\n"
1394
+ "• [cyan]CLAUDE.md[/cyan] - Main documentation for AI agents\n"
1395
+ " - Organized with priority rankings (🔴🟡🟢⚪)\n"
1396
+ " - Instructions ranked by importance for AI understanding\n"
1397
+ " - Holistic documentation review completed\n"
1398
+ "• [cyan].claude-mpm/[/cyan] - Configuration and memories\n"
1399
+ " [cyan]CODE_STRUCTURE.md[/cyan] - AST-derived architecture documentation (if enabled)\n\n"
1400
+ "[dim]Run 'claude-mpm run' to start using the optimized setup[/dim]"
1454
1401
  )
1402
+ self.display.display_success_panel("Success", success_content)
1455
1403
 
1456
1404
 
1457
1405
  @click.command(name="mpm-init")
@@ -1,13 +1,19 @@
1
1
  """Hook system for claude-mpm."""
2
2
 
3
3
  from .base_hook import BaseHook, HookContext, HookResult, HookType
4
+ from .kuzu_enrichment_hook import KuzuEnrichmentHook, get_kuzu_enrichment_hook
4
5
  from .kuzu_memory_hook import KuzuMemoryHook, get_kuzu_memory_hook
6
+ from .kuzu_response_hook import KuzuResponseHook, get_kuzu_response_hook
5
7
 
6
8
  __all__ = [
7
9
  "BaseHook",
8
10
  "HookContext",
9
11
  "HookResult",
10
12
  "HookType",
13
+ "KuzuEnrichmentHook",
11
14
  "KuzuMemoryHook",
15
+ "KuzuResponseHook",
16
+ "get_kuzu_enrichment_hook",
12
17
  "get_kuzu_memory_hook",
18
+ "get_kuzu_response_hook",
13
19
  ]