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 CHANGED
@@ -1 +1 @@
1
- 4.7.4
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
- 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")
@@ -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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.7.4
3
+ Version: 4.7.5
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=7l6EwjOR-pq8p3cqBD3TobvpQd2ubAiLeapnXloBUX4,6
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=OLkoRLGTT7Y9pxsTev22KfK4DfHz9HlfZdKvxu9XAyI,63075
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.4.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
788
- claude_mpm-4.7.4.dist-info/METADATA,sha256=2c6NYh3MyaMjPYOXXXKRzFlHNTvdUD7WlNiKj2wfHWg,17517
789
- claude_mpm-4.7.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
790
- claude_mpm-4.7.4.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
791
- claude_mpm-4.7.4.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
792
- claude_mpm-4.7.4.dist-info/RECORD,,
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,,