claude-mpm 4.7.4__py3-none-any.whl → 4.7.5__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/cli/commands/mpm_init.py +75 -127
- claude_mpm/utils/display_helper.py +260 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/METADATA +1 -1
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/RECORD +9 -9
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.7.5.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.7.
|
1
|
+
4.7.5
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
535
|
-
console.print(f" Phase: {state.get('phase', 'unknown')}")
|
506
|
+
state_data = {"Phase": state.get("phase", "unknown")}
|
536
507
|
if state.get("indicators"):
|
537
|
-
|
538
|
-
|
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
|
-
|
543
|
-
|
544
|
-
|
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
|
-
|
547
|
-
|
548
|
-
|
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
|
-
|
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
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
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
|
-
|
575
|
-
|
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
|
-
|
585
|
-
for rec in state["recommendations"][:5]:
|
586
|
-
console.print(f" → {rec}")
|
559
|
+
self.display.display_recommendations(state["recommendations"])
|
587
560
|
|
588
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
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
|
-
|
944
|
-
for rec in recommendations:
|
945
|
-
console.print(f" → {rec}")
|
897
|
+
self.display.display_recommendations(recommendations)
|
946
898
|
|
947
|
-
|
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
|
-
|
1424
|
-
|
1425
|
-
|
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
|
-
|
1430
|
-
|
1431
|
-
|
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
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
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")
|
@@ -0,0 +1,260 @@
|
|
1
|
+
"""
|
2
|
+
Display Helper for Rich Console Output.
|
3
|
+
|
4
|
+
WHY: Centralizes display formatting logic to reduce code duplication
|
5
|
+
across CLI commands. Provides reusable components for tables, panels,
|
6
|
+
reports, and structured output.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from typing import Any, Dict, List, Tuple
|
10
|
+
|
11
|
+
from rich.console import Console
|
12
|
+
from rich.panel import Panel
|
13
|
+
from rich.table import Table
|
14
|
+
|
15
|
+
|
16
|
+
class DisplayHelper:
|
17
|
+
"""Centralized display formatting for Rich console output."""
|
18
|
+
|
19
|
+
def __init__(self, console: Console):
|
20
|
+
"""Initialize display helper with console instance."""
|
21
|
+
self.console = console
|
22
|
+
|
23
|
+
def display_separator(self, char: str = "=", width: int = 60) -> None:
|
24
|
+
"""Display a separator line."""
|
25
|
+
self.console.print(char * width)
|
26
|
+
|
27
|
+
def display_header(self, title: str, width: int = 60) -> None:
|
28
|
+
"""Display a formatted header with separators."""
|
29
|
+
self.display_separator(width=width)
|
30
|
+
self.console.print(f"[bold]{title}[/bold]")
|
31
|
+
self.display_separator(width=width)
|
32
|
+
self.console.print()
|
33
|
+
|
34
|
+
def display_section_title(self, title: str, emoji: str = "") -> None:
|
35
|
+
"""Display a section title with optional emoji."""
|
36
|
+
if emoji:
|
37
|
+
self.console.print(f"[bold cyan]{emoji} {title}[/bold cyan]")
|
38
|
+
else:
|
39
|
+
self.console.print(f"[bold cyan]{title}[/bold cyan]")
|
40
|
+
|
41
|
+
def display_key_value_table(
|
42
|
+
self,
|
43
|
+
title: str,
|
44
|
+
data: Dict[str, Any],
|
45
|
+
key_style: str = "cyan",
|
46
|
+
value_style: str = "white",
|
47
|
+
) -> None:
|
48
|
+
"""Display a two-column key-value table."""
|
49
|
+
table = Table(title=title, show_header=True)
|
50
|
+
table.add_column("Property", style=key_style)
|
51
|
+
table.add_column("Value", style=value_style)
|
52
|
+
|
53
|
+
for key, value in data.items():
|
54
|
+
# Handle various value types
|
55
|
+
if isinstance(value, bool):
|
56
|
+
display_value = "✓" if value else "✗"
|
57
|
+
elif isinstance(value, int) and key.lower().find("size") >= 0:
|
58
|
+
display_value = f"{value:,} characters"
|
59
|
+
else:
|
60
|
+
display_value = str(value)
|
61
|
+
table.add_row(key, display_value)
|
62
|
+
|
63
|
+
self.console.print(table)
|
64
|
+
|
65
|
+
def display_list_section(
|
66
|
+
self, title: str, items: List[str], max_items: int = 10, color: str = "white"
|
67
|
+
) -> None:
|
68
|
+
"""Display a titled list of items."""
|
69
|
+
self.console.print(f"\n[bold cyan]{title}[/bold cyan]")
|
70
|
+
for item in items[:max_items]:
|
71
|
+
self.console.print(f" [{color}]{item}[/{color}]")
|
72
|
+
|
73
|
+
def display_warning_list(self, title: str, items: List[str]) -> None:
|
74
|
+
"""Display a list of warning items."""
|
75
|
+
self.console.print(f"\n[yellow]{title}[/yellow]")
|
76
|
+
for item in items:
|
77
|
+
self.console.print(f" • {item}")
|
78
|
+
|
79
|
+
def display_info_list(self, title: str, items: List[str]) -> None:
|
80
|
+
"""Display a list of info items."""
|
81
|
+
self.console.print(f"\n[blue]{title}[/blue]")
|
82
|
+
for item in items[:5]:
|
83
|
+
self.console.print(f" • {item}")
|
84
|
+
|
85
|
+
def display_metric_row(
|
86
|
+
self, label: str, value: Any, indent: int = 2, warning: bool = False
|
87
|
+
) -> None:
|
88
|
+
"""Display a single metric row with label and value."""
|
89
|
+
indent_str = " " * indent
|
90
|
+
if warning:
|
91
|
+
self.console.print(f"{indent_str}[yellow]{label}: {value}[/yellow]")
|
92
|
+
else:
|
93
|
+
self.console.print(f"{indent_str}{label}: {value}")
|
94
|
+
|
95
|
+
def display_metrics_section(
|
96
|
+
self, title: str, metrics: Dict[str, Any], emoji: str = ""
|
97
|
+
) -> None:
|
98
|
+
"""Display a section with multiple metrics."""
|
99
|
+
self.display_section_title(title, emoji)
|
100
|
+
for label, value in metrics.items():
|
101
|
+
self.display_metric_row(label, value)
|
102
|
+
|
103
|
+
def display_report_section(
|
104
|
+
self,
|
105
|
+
title: str,
|
106
|
+
data: Dict[str, Any],
|
107
|
+
emoji: str = "",
|
108
|
+
show_warnings: bool = True,
|
109
|
+
) -> None:
|
110
|
+
"""Display a generic report section with data and optional warnings."""
|
111
|
+
self.display_section_title(title, emoji)
|
112
|
+
|
113
|
+
for key, value in data.items():
|
114
|
+
if isinstance(value, dict):
|
115
|
+
# Handle nested dictionaries
|
116
|
+
self.console.print(f" {key}:")
|
117
|
+
for sub_key, sub_value in value.items():
|
118
|
+
self.console.print(f" {sub_key}: {sub_value}")
|
119
|
+
elif isinstance(value, list):
|
120
|
+
# Handle lists
|
121
|
+
self.console.print(f" {key}:")
|
122
|
+
for item in value[:5]: # Limit to first 5 items
|
123
|
+
if isinstance(item, dict):
|
124
|
+
# Handle dict items in list
|
125
|
+
desc = item.get("description") or str(item)
|
126
|
+
prefix = "⚠️ " if show_warnings else "•"
|
127
|
+
self.console.print(f" {prefix} {desc}")
|
128
|
+
else:
|
129
|
+
self.console.print(f" • {item}")
|
130
|
+
else:
|
131
|
+
# Simple key-value
|
132
|
+
self.console.print(f" {key}: {value}")
|
133
|
+
|
134
|
+
def display_recommendations(self, recommendations: List[str]) -> None:
|
135
|
+
"""Display a recommendations section."""
|
136
|
+
if recommendations:
|
137
|
+
self.display_section_title("💡 Recommendations")
|
138
|
+
for rec in recommendations[:5]:
|
139
|
+
self.console.print(f" → {rec}")
|
140
|
+
|
141
|
+
def display_documentation_status(
|
142
|
+
self, analysis: Dict, title: str = "Current CLAUDE.md Status"
|
143
|
+
) -> None:
|
144
|
+
"""Display documentation status table."""
|
145
|
+
data = {
|
146
|
+
"Size": analysis.get("size", 0),
|
147
|
+
"Lines": analysis.get("lines", 0),
|
148
|
+
"Sections": len(analysis.get("sections", [])),
|
149
|
+
"Has Priority Index": analysis.get("has_priority_index", False),
|
150
|
+
"Has Priority Markers": analysis.get("has_priority_markers", False),
|
151
|
+
}
|
152
|
+
|
153
|
+
if analysis.get("last_modified"):
|
154
|
+
data["Last Modified"] = analysis["last_modified"]
|
155
|
+
|
156
|
+
self.display_key_value_table(title, data)
|
157
|
+
|
158
|
+
# Display warnings if present
|
159
|
+
if analysis.get("outdated_patterns"):
|
160
|
+
self.display_warning_list(
|
161
|
+
"⚠️ Outdated patterns detected:", analysis["outdated_patterns"]
|
162
|
+
)
|
163
|
+
|
164
|
+
# Display custom sections if present
|
165
|
+
if analysis.get("custom_sections"):
|
166
|
+
self.display_info_list(
|
167
|
+
"[INFO]️ Custom sections found:", analysis["custom_sections"]
|
168
|
+
)
|
169
|
+
|
170
|
+
def display_activity_summary(
|
171
|
+
self, summary: Dict, period: str = "Last 30 days"
|
172
|
+
) -> None:
|
173
|
+
"""Display activity summary metrics."""
|
174
|
+
metrics = {
|
175
|
+
"Total commits": summary.get("total_commits", 0),
|
176
|
+
"Active contributors": summary.get("total_authors", 0),
|
177
|
+
"Files modified": summary.get("files_changed", 0),
|
178
|
+
"Current branch": summary.get("current_branch", "unknown"),
|
179
|
+
}
|
180
|
+
|
181
|
+
self.display_metrics_section(
|
182
|
+
f"📊 Activity Overview ({period.lower()})", metrics
|
183
|
+
)
|
184
|
+
|
185
|
+
if summary.get("has_uncommitted"):
|
186
|
+
self.display_metric_row(
|
187
|
+
"⚠️ Uncommitted changes",
|
188
|
+
f"{summary.get('uncommitted_count', 0)} files",
|
189
|
+
warning=True,
|
190
|
+
)
|
191
|
+
|
192
|
+
def display_commit_list(
|
193
|
+
self, commits: List[Dict], title: str = "📝 Recent Commits (last 10)"
|
194
|
+
) -> None:
|
195
|
+
"""Display a list of commits."""
|
196
|
+
if commits:
|
197
|
+
self.display_section_title(title)
|
198
|
+
for commit in commits[:10]:
|
199
|
+
msg = commit.get("message", "")[:60]
|
200
|
+
hash_val = commit.get("hash", "")
|
201
|
+
author = commit.get("author", "")
|
202
|
+
self.console.print(f" [{hash_val}] {msg} - {author}")
|
203
|
+
|
204
|
+
def display_file_change_list(
|
205
|
+
self, files: List[Tuple[str, int]], title: str = "🔥 Most Changed Files"
|
206
|
+
) -> None:
|
207
|
+
"""Display a list of changed files with change counts."""
|
208
|
+
if files:
|
209
|
+
self.display_section_title(title)
|
210
|
+
for file_path, changes in files[:10]:
|
211
|
+
self.console.print(f" {file_path}: {changes} changes")
|
212
|
+
|
213
|
+
def display_branch_list(
|
214
|
+
self,
|
215
|
+
branches: List[str],
|
216
|
+
current_branch: str,
|
217
|
+
title: str = "🌿 Active Branches",
|
218
|
+
) -> None:
|
219
|
+
"""Display a list of branches with current branch marked."""
|
220
|
+
if branches:
|
221
|
+
self.display_section_title(title)
|
222
|
+
for branch in branches:
|
223
|
+
marker = "→" if branch == current_branch else " "
|
224
|
+
self.console.print(f" {marker} {branch}")
|
225
|
+
|
226
|
+
def display_success_panel(
|
227
|
+
self,
|
228
|
+
title: str,
|
229
|
+
content: str,
|
230
|
+
border_style: str = "green",
|
231
|
+
) -> None:
|
232
|
+
"""Display a success panel with content."""
|
233
|
+
self.console.print(Panel(content, title=title, border_style=border_style))
|
234
|
+
|
235
|
+
def display_info_panel(
|
236
|
+
self,
|
237
|
+
title: str,
|
238
|
+
content: str,
|
239
|
+
border_style: str = "cyan",
|
240
|
+
) -> None:
|
241
|
+
"""Display an info panel with content."""
|
242
|
+
self.console.print(Panel(content, title=title, border_style=border_style))
|
243
|
+
|
244
|
+
def display_files_list(
|
245
|
+
self, title: str, files: List[str], prefix: str = "•"
|
246
|
+
) -> None:
|
247
|
+
"""Display a list of files."""
|
248
|
+
if files:
|
249
|
+
self.console.print(f"[bold]{title}[/bold]")
|
250
|
+
for file in files:
|
251
|
+
self.console.print(f" {prefix} {file}")
|
252
|
+
self.console.print()
|
253
|
+
|
254
|
+
def display_next_steps(self, steps: List[str]) -> None:
|
255
|
+
"""Display next steps list."""
|
256
|
+
if steps:
|
257
|
+
self.console.print("[bold]Next Steps:[/bold]")
|
258
|
+
for step in steps:
|
259
|
+
self.console.print(f" → {step}")
|
260
|
+
self.console.print()
|
@@ -1,5 +1,5 @@
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
|
2
|
-
claude_mpm/VERSION,sha256=
|
2
|
+
claude_mpm/VERSION,sha256=S1_5LwX4BqRmj3UoBp6ODrFMvkFt5xvcn9wfpuFze9Y,6
|
3
3
|
claude_mpm/__init__.py,sha256=UCw6j9e_tZQ3kJtTqmdfNv7MHyw9nD1jkj80WurwM2g,2064
|
4
4
|
claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
|
5
5
|
claude_mpm/constants.py,sha256=cChN3myrAcF3jC-6DvHnBFTEnwlDk-TAsIXPvUZr_yw,5953
|
@@ -96,7 +96,7 @@ claude_mpm/cli/commands/mcp_setup_external.py,sha256=hfBHkaioNa0JRDhahNEc8agyrUw
|
|
96
96
|
claude_mpm/cli/commands/mcp_tool_commands.py,sha256=q17GzlFT3JiLTrDqwPO2tz1-fKmPO5QU449syTnKTz4,1283
|
97
97
|
claude_mpm/cli/commands/memory.py,sha256=O4T5HGL-Ob_QPt2dZHQvoOrVohnaDKrBjyngq1Mcv1w,26185
|
98
98
|
claude_mpm/cli/commands/monitor.py,sha256=Fjb68hf3dEwTFek2LV8Nh6iU0qEkY7qYlOn32IwNaNg,9566
|
99
|
-
claude_mpm/cli/commands/mpm_init.py,sha256=
|
99
|
+
claude_mpm/cli/commands/mpm_init.py,sha256=H7op69CaE7VPOViTuEiCTeANe708ZAcJpkpgbfG2baM,60311
|
100
100
|
claude_mpm/cli/commands/mpm_init_handler.py,sha256=b1CSwZYJ89wMorKzPOKS-RVxOKR2kT9yv9KQLvKkd2U,3532
|
101
101
|
claude_mpm/cli/commands/run.py,sha256=PB2H55piOPTy4yo4OBgbUCjMlcz9K79wbwpxQVc9m5Q,48225
|
102
102
|
claude_mpm/cli/commands/search.py,sha256=_0qbUnop8v758MHsB0fAop8FVxwygD59tec_-iN7pLE,9806
|
@@ -222,7 +222,6 @@ claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css,sha256=
|
|
222
222
|
claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css,sha256=v6uB3hr2dU7aGodvQVxu1y-bM-pN-jeOD_-iwGG7mIc,603
|
223
223
|
claude_mpm/dashboard/react/components/shared/FilterBar.module.css,sha256=Ea-dpAlKoY7WobxLESQsNvLUVjFhJlQvLygCY8-47Vk,1690
|
224
224
|
claude_mpm/dashboard/static/events.html,sha256=iKBH2gqxhU6JTmSglAVyNJkWA9c11L4Dxn40otAfnAU,17952
|
225
|
-
claude_mpm/dashboard/static/index-hub-backup.html,sha256=5N7toUxcTQJgqwGPyk8J7kvzR71WCdMpy3F8niM-ZK0,26044
|
226
225
|
claude_mpm/dashboard/static/index.html,sha256=F971Wwl0opHFb-SKD3fi0tvZmrzMPLh7MkJsJzR9tAc,31192
|
227
226
|
claude_mpm/dashboard/static/monitors.html,sha256=waNCJiIGWBvve7nbzvihnVDjaP49FPfFSNqOpkwiIaM,14229
|
228
227
|
claude_mpm/dashboard/static/socket.io.min.js,sha256=c-uha8iV_fpFTifsuA3vMe3o2GH5nhdf-TsRDqvsBE8,49993
|
@@ -770,6 +769,7 @@ claude_mpm/utils/database_connector.py,sha256=7Fa9gzr19Y-5eJuvCGfBYJRjMfI6s-EIB6
|
|
770
769
|
claude_mpm/utils/dependency_cache.py,sha256=GmdSYmV6YSmvtaoeAR2vGZpD3ormFsHpooKJqYgOZa0,11780
|
771
770
|
claude_mpm/utils/dependency_manager.py,sha256=g9iYA_uyZ4XE8cY-VfhKYd1NA3aqr9ZYT3IBTv_abmY,7356
|
772
771
|
claude_mpm/utils/dependency_strategies.py,sha256=m-VyZP0KF8z1mCcd_dEPNZ8WbU8z0GyBpvw210yCNvM,12149
|
772
|
+
claude_mpm/utils/display_helper.py,sha256=Ce2TGGOqMLq3o7L5ax9YtxNaFuNisLb97Cdoe4Y5Gjs,9783
|
773
773
|
claude_mpm/utils/environment_context.py,sha256=mCnRJqQLTyaAv-7M4bp9N9WqVgfSQb5xbbfgvFxGHJA,10141
|
774
774
|
claude_mpm/utils/error_handler.py,sha256=RWL7DnXttJKCgYhevUm9XlMC33rEhX2CXo1IiCtwV4g,7969
|
775
775
|
claude_mpm/utils/file_utils.py,sha256=pv3MEKLsn4WIOra5JoHnCm_FaJbNcKMuS3EKuXAWyLc,7859
|
@@ -784,9 +784,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
|
|
784
784
|
claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
|
785
785
|
claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
|
786
786
|
claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
|
787
|
-
claude_mpm-4.7.
|
788
|
-
claude_mpm-4.7.
|
789
|
-
claude_mpm-4.7.
|
790
|
-
claude_mpm-4.7.
|
791
|
-
claude_mpm-4.7.
|
792
|
-
claude_mpm-4.7.
|
787
|
+
claude_mpm-4.7.5.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
|
788
|
+
claude_mpm-4.7.5.dist-info/METADATA,sha256=hq04JsKoSrZIIOVtawIlwapyPzZOkFxDl2BhsNcOFR0,17517
|
789
|
+
claude_mpm-4.7.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
790
|
+
claude_mpm-4.7.5.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
|
791
|
+
claude_mpm-4.7.5.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
|
792
|
+
claude_mpm-4.7.5.dist-info/RECORD,,
|