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 +1 -1
- claude_mpm/cli/commands/mpm_init.py +250 -1
- claude_mpm/cli/commands/mpm_init_handler.py +41 -1
- claude_mpm/cli/commands/session_pause_manager.py +389 -0
- claude_mpm/cli/commands/session_resume_manager.py +523 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +59 -0
- claude_mpm/commands/mpm-init.md +78 -1
- claude_mpm/storage/state_storage.py +15 -15
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/METADATA +1 -1
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/RECORD +14 -12
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.10.0.dist-info → claude_mpm-4.11.0.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.
|
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.
|
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),
|