claude-mpm 4.10.0__py3-none-any.whl → 4.11.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.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.10.0
1
+ 4.11.0
@@ -11,6 +11,7 @@ documentation with code structure analysis.
11
11
  import contextlib
12
12
  import subprocess
13
13
  import sys
14
+ from datetime import datetime
14
15
  from pathlib import Path
15
16
  from typing import Any, Dict, List, Optional
16
17
 
@@ -20,6 +21,9 @@ from rich.panel import Panel
20
21
  from rich.progress import Progress, SpinnerColumn, TextColumn
21
22
  from rich.prompt import Prompt
22
23
 
24
+ # Import pause/resume managers
25
+ from claude_mpm.cli.commands.session_pause_manager import SessionPauseManager
26
+ from claude_mpm.cli.commands.session_resume_manager import SessionResumeManager
23
27
  from claude_mpm.core.logging_utils import get_logger
24
28
 
25
29
  # Import new services
@@ -48,6 +52,10 @@ class MPMInitCommand:
48
52
  self.analyzer = EnhancedProjectAnalyzer(self.project_path)
49
53
  self.display = DisplayHelper(console)
50
54
 
55
+ # Session management
56
+ self.pause_manager = SessionPauseManager(self.project_path)
57
+ self.resume_manager = SessionResumeManager(self.project_path)
58
+
51
59
  def initialize_project(
52
60
  self,
53
61
  project_type: Optional[str] = None,
@@ -1464,6 +1472,125 @@ preserving valuable project-specific information while refreshing standard secti
1464
1472
  logger.error(f"Initialization failed: {e}")
1465
1473
  return {"status": "error", "message": str(e)}
1466
1474
 
1475
+ def handle_pause(
1476
+ self,
1477
+ summary: Optional[str] = None,
1478
+ accomplishments: Optional[List[str]] = None,
1479
+ next_steps: Optional[List[str]] = None,
1480
+ ) -> Dict[str, Any]:
1481
+ """Handle session pause request.
1482
+
1483
+ Args:
1484
+ summary: Summary of what was being worked on
1485
+ accomplishments: List of things accomplished
1486
+ next_steps: List of next steps to continue work
1487
+
1488
+ Returns:
1489
+ Dict containing pause result
1490
+ """
1491
+ try:
1492
+ # If no context provided, prompt for it
1493
+ if not summary:
1494
+ summary = Prompt.ask(
1495
+ "\n[bold]What were you working on?[/bold]",
1496
+ default="Working on project improvements",
1497
+ )
1498
+
1499
+ if not accomplishments:
1500
+ console.print(
1501
+ "\n[bold]List accomplishments (enter blank line to finish):[/bold]"
1502
+ )
1503
+ accomplishments = []
1504
+ while True:
1505
+ item = Prompt.ask(" Accomplishment", default="")
1506
+ if not item:
1507
+ break
1508
+ accomplishments.append(item)
1509
+
1510
+ if not next_steps:
1511
+ console.print(
1512
+ "\n[bold]List next steps (enter blank line to finish):[/bold]"
1513
+ )
1514
+ next_steps = []
1515
+ while True:
1516
+ item = Prompt.ask(" Next step", default="")
1517
+ if not item:
1518
+ break
1519
+ next_steps.append(item)
1520
+
1521
+ # Pause the session
1522
+ return self.pause_manager.pause_session(
1523
+ conversation_summary=summary,
1524
+ accomplishments=accomplishments,
1525
+ next_steps=next_steps,
1526
+ )
1527
+
1528
+ except Exception as e:
1529
+ logger.error(f"Failed to pause session: {e}")
1530
+ console.print(f"[red]❌ Error pausing session: {e}[/red]")
1531
+ return {"status": "error", "message": str(e)}
1532
+
1533
+ def handle_resume(self, session_id: Optional[str] = None) -> Dict[str, Any]:
1534
+ """Handle session resume request.
1535
+
1536
+ Args:
1537
+ session_id: Optional specific session ID to resume
1538
+
1539
+ Returns:
1540
+ Dict containing resume result
1541
+ """
1542
+ try:
1543
+ # Check if there are any paused sessions
1544
+ available_sessions = self.resume_manager.list_available_sessions()
1545
+
1546
+ if not available_sessions:
1547
+ console.print("\n[yellow]No paused sessions found.[/yellow]")
1548
+ console.print(
1549
+ "[dim]To pause a session, run: claude-mpm mpm-init pause[/dim]\n"
1550
+ )
1551
+ return {"status": "error", "message": "No paused sessions found"}
1552
+
1553
+ # If no session ID specified and multiple sessions exist, let user choose
1554
+ if not session_id and len(available_sessions) > 1:
1555
+ console.print("\n[bold]Available Paused Sessions:[/bold]\n")
1556
+ for idx, session in enumerate(available_sessions, 1):
1557
+ paused_at = session.get("paused_at", "unknown")
1558
+ try:
1559
+ dt = datetime.fromisoformat(paused_at.replace("Z", "+00:00"))
1560
+ paused_display = dt.strftime("%Y-%m-%d %H:%M")
1561
+ except Exception:
1562
+ paused_display = paused_at
1563
+
1564
+ summary = session.get("summary", "No summary")
1565
+ if len(summary) > 60:
1566
+ summary = summary[:57] + "..."
1567
+
1568
+ console.print(
1569
+ f" [{idx}] {session['session_id']} - {paused_display}"
1570
+ )
1571
+ console.print(f" {summary}\n")
1572
+
1573
+ choice = Prompt.ask(
1574
+ "Select session to resume",
1575
+ choices=[str(i) for i in range(1, len(available_sessions) + 1)],
1576
+ default="1",
1577
+ )
1578
+ session_id = available_sessions[int(choice) - 1]["session_id"]
1579
+
1580
+ # Resume the session
1581
+ result = self.resume_manager.resume_session(session_id=session_id)
1582
+
1583
+ # Display resume context
1584
+ if result.get("status") == "success":
1585
+ console.print("\n[dim]Resume context has been displayed above.[/dim]\n")
1586
+
1587
+ return result
1588
+
1589
+ except Exception as e:
1590
+ logger.error(f"Failed to resume session: {e}")
1591
+ console.print(f"[red]❌ Error resuming session: {e}[/red]")
1592
+ return {"status": "error", "message": str(e)}
1593
+
1467
1594
  def _display_results(self, result: Dict, verbose: bool):
1468
1595
  """Display initialization results."""
1469
1596
  if result["status"] == "success":
@@ -1500,7 +1627,7 @@ preserving valuable project-specific information while refreshing standard secti
1500
1627
  self.display.display_success_panel("Success", success_content)
1501
1628
 
1502
1629
 
1503
- @click.command(name="mpm-init")
1630
+ @click.group(name="mpm-init", invoke_without_command=True)
1504
1631
  @click.option(
1505
1632
  "--project-type",
1506
1633
  type=click.Choice(
@@ -1589,7 +1716,9 @@ preserving valuable project-specific information while refreshing standard secti
1589
1716
  required=False,
1590
1717
  default=".",
1591
1718
  )
1719
+ @click.pass_context
1592
1720
  def mpm_init(
1721
+ ctx,
1593
1722
  project_type,
1594
1723
  framework,
1595
1724
  force,
@@ -1619,18 +1748,28 @@ def mpm_init(
1619
1748
  - Optimize for AI agent understanding
1620
1749
  - Perform AST analysis for enhanced developer documentation
1621
1750
 
1751
+ Session Management:
1752
+ - pause: Pause the current session and save state
1753
+ - resume: Resume the most recent (or specified) paused session
1754
+
1622
1755
  Update Mode:
1623
1756
  When CLAUDE.md exists, the command offers to update rather than recreate,
1624
1757
  preserving custom content while refreshing standard sections.
1625
1758
 
1626
1759
  Examples:
1627
1760
  claude-mpm mpm-init # Initialize/update current directory
1761
+ claude-mpm mpm-init pause # Pause current session
1762
+ claude-mpm mpm-init resume # Resume latest session
1628
1763
  claude-mpm mpm-init --review # Review project state without changes
1629
1764
  claude-mpm mpm-init --update # Force update mode
1630
1765
  claude-mpm mpm-init --organize # Organize misplaced files
1631
1766
  claude-mpm mpm-init --project-type web # Initialize as web project
1632
1767
  claude-mpm mpm-init /path/to/project --force # Force reinitialize project
1633
1768
  """
1769
+ # If a subcommand is being invoked, don't run the main command
1770
+ if ctx.invoked_subcommand is not None:
1771
+ return
1772
+
1634
1773
  try:
1635
1774
  # Create command instance
1636
1775
  command = MPMInitCommand(Path(project_path))
@@ -1668,5 +1807,115 @@ def mpm_init(
1668
1807
  sys.exit(1)
1669
1808
 
1670
1809
 
1810
+ @mpm_init.command(name="pause")
1811
+ @click.option(
1812
+ "--summary",
1813
+ "-s",
1814
+ type=str,
1815
+ help="Summary of what you were working on",
1816
+ )
1817
+ @click.option(
1818
+ "--accomplishment",
1819
+ "-a",
1820
+ multiple=True,
1821
+ help="Accomplishment from this session (can be used multiple times)",
1822
+ )
1823
+ @click.option(
1824
+ "--next-step",
1825
+ "-n",
1826
+ multiple=True,
1827
+ help="Next step to continue work (can be used multiple times)",
1828
+ )
1829
+ @click.argument(
1830
+ "project_path",
1831
+ type=click.Path(exists=True, file_okay=False, dir_okay=True),
1832
+ required=False,
1833
+ default=".",
1834
+ )
1835
+ def pause_session(summary, accomplishment, next_step, project_path):
1836
+ """
1837
+ Pause the current session and save state.
1838
+
1839
+ This command captures:
1840
+ - Conversation summary and progress
1841
+ - Git repository state (commits, branch, status)
1842
+ - Todo list status
1843
+ - Working directory changes
1844
+
1845
+ The saved state enables seamless session resumption with full context.
1846
+
1847
+ Examples:
1848
+ claude-mpm mpm-init pause
1849
+ claude-mpm mpm-init pause -s "Working on authentication feature"
1850
+ claude-mpm mpm-init pause -a "Implemented login" -a "Added tests"
1851
+ claude-mpm mpm-init pause -n "Add logout functionality"
1852
+ """
1853
+ try:
1854
+ command = MPMInitCommand(Path(project_path))
1855
+
1856
+ result = command.handle_pause(
1857
+ summary=summary,
1858
+ accomplishments=list(accomplishment) if accomplishment else None,
1859
+ next_steps=list(next_step) if next_step else None,
1860
+ )
1861
+
1862
+ if result["status"] == "success":
1863
+ sys.exit(0)
1864
+ else:
1865
+ sys.exit(1)
1866
+
1867
+ except KeyboardInterrupt:
1868
+ console.print("\n[yellow]Pause cancelled by user[/yellow]")
1869
+ sys.exit(130)
1870
+ except Exception as e:
1871
+ console.print(f"[red]Pause failed: {e}[/red]")
1872
+ sys.exit(1)
1873
+
1874
+
1875
+ @mpm_init.command(name="resume")
1876
+ @click.option(
1877
+ "--session-id",
1878
+ "-i",
1879
+ type=str,
1880
+ help="Specific session ID to resume (defaults to most recent)",
1881
+ )
1882
+ @click.argument(
1883
+ "project_path",
1884
+ type=click.Path(exists=True, file_okay=False, dir_okay=True),
1885
+ required=False,
1886
+ default=".",
1887
+ )
1888
+ def resume_session(session_id, project_path):
1889
+ """
1890
+ Resume a paused session.
1891
+
1892
+ This command:
1893
+ - Loads the most recent (or specified) paused session
1894
+ - Checks for changes since the pause (commits, file changes, branch changes)
1895
+ - Displays warnings for any conflicts
1896
+ - Generates a complete context summary for seamless resumption
1897
+
1898
+ Examples:
1899
+ claude-mpm mpm-init resume
1900
+ claude-mpm mpm-init resume --session-id session-20251019-120000
1901
+ """
1902
+ try:
1903
+ command = MPMInitCommand(Path(project_path))
1904
+
1905
+ result = command.handle_resume(session_id=session_id)
1906
+
1907
+ if result["status"] == "success":
1908
+ sys.exit(0)
1909
+ else:
1910
+ sys.exit(1)
1911
+
1912
+ except KeyboardInterrupt:
1913
+ console.print("\n[yellow]Resume cancelled by user[/yellow]")
1914
+ sys.exit(130)
1915
+ except Exception as e:
1916
+ console.print(f"[red]Resume failed: {e}[/red]")
1917
+ sys.exit(1)
1918
+
1919
+
1671
1920
  # Export for CLI registration
1672
1921
  __all__ = ["mpm_init"]
@@ -25,6 +25,47 @@ def manage_mpm_init(args):
25
25
  # Import the command implementation
26
26
  from .mpm_init import MPMInitCommand
27
27
 
28
+ # Handle pause/resume subcommands
29
+ subcommand = getattr(args, "subcommand", None)
30
+
31
+ if subcommand == "pause":
32
+ # Get project path
33
+ project_path = (
34
+ Path(args.project_path) if hasattr(args, "project_path") else Path.cwd()
35
+ )
36
+
37
+ # Create command instance
38
+ command = MPMInitCommand(project_path)
39
+
40
+ # Handle pause with optional arguments
41
+ result = command.handle_pause(
42
+ summary=getattr(args, "summary", None),
43
+ accomplishments=getattr(args, "accomplishment", None),
44
+ next_steps=getattr(args, "next_step", None),
45
+ )
46
+
47
+ # Return appropriate exit code
48
+ if result.get("status") == "success":
49
+ return 0
50
+ return 1
51
+
52
+ if subcommand == "resume":
53
+ # Get project path
54
+ project_path = (
55
+ Path(args.project_path) if hasattr(args, "project_path") else Path.cwd()
56
+ )
57
+
58
+ # Create command instance
59
+ command = MPMInitCommand(project_path)
60
+
61
+ # Handle resume with optional session ID
62
+ result = command.handle_resume(session_id=getattr(args, "session_id", None))
63
+
64
+ # Return appropriate exit code
65
+ if result.get("status") == "success":
66
+ return 0
67
+ return 1
68
+
28
69
  # Handle special flags
29
70
  if getattr(args, "list_templates", False):
30
71
  # List available templates
@@ -55,7 +96,6 @@ def manage_mpm_init(args):
55
96
  "framework": getattr(args, "framework", None),
56
97
  "force": getattr(args, "force", False),
57
98
  "verbose": getattr(args, "verbose", False),
58
- "use_venv": getattr(args, "use_venv", False),
59
99
  "ast_analysis": getattr(args, "ast_analysis", True),
60
100
  "update_mode": getattr(args, "update", False),
61
101
  "review_only": getattr(args, "review", False),