claude-mpm 4.9.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.
@@ -0,0 +1,523 @@
1
+ """
2
+ Session Resume Manager - Loads and analyzes paused session state.
3
+
4
+ This module provides functionality to resume a paused Claude MPM session by:
5
+ - Loading the most recent (or specified) paused session
6
+ - Checking for changes since the pause
7
+ - Detecting potential conflicts
8
+ - Generating context summary for seamless resumption
9
+
10
+ The resume manager ensures users have full awareness of what changed during the pause.
11
+ """
12
+
13
+ import subprocess
14
+ from datetime import datetime
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from rich.console import Console
19
+ from rich.panel import Panel
20
+ from rich.table import Table
21
+
22
+ from claude_mpm.core.logging_utils import get_logger
23
+ from claude_mpm.storage.state_storage import StateStorage
24
+
25
+ logger = get_logger(__name__)
26
+ console = Console()
27
+
28
+
29
+ class SessionResumeManager:
30
+ """Manages resuming paused sessions with change detection."""
31
+
32
+ def __init__(self, project_path: Path):
33
+ """Initialize Session Resume Manager.
34
+
35
+ Args:
36
+ project_path: Path to the project directory
37
+ """
38
+ self.project_path = project_path
39
+ self.session_dir = project_path / ".claude-mpm" / "sessions" / "pause"
40
+ self.storage = StateStorage()
41
+
42
+ def resume_session(self, session_id: Optional[str] = None) -> Dict[str, Any]:
43
+ """Resume a paused session.
44
+
45
+ Args:
46
+ session_id: Optional specific session ID to resume (defaults to most recent)
47
+
48
+ Returns:
49
+ Dict containing resume context and warnings
50
+ """
51
+ try:
52
+ # Load session state
53
+ if session_id:
54
+ session_state = self._load_session_by_id(session_id)
55
+ else:
56
+ session_state = self._load_latest_session()
57
+
58
+ if not session_state:
59
+ return {
60
+ "status": "error",
61
+ "message": (
62
+ "No paused sessions found"
63
+ if not session_id
64
+ else f"Session {session_id} not found"
65
+ ),
66
+ }
67
+
68
+ # Analyze changes since pause
69
+ changes = self._analyze_changes_since_pause(session_state)
70
+
71
+ # Generate resume context
72
+ resume_context = self._generate_resume_context(session_state, changes)
73
+
74
+ # Display resume information
75
+ self._display_resume_info(session_state, changes)
76
+
77
+ return {
78
+ "status": "success",
79
+ "session_state": session_state,
80
+ "changes": changes,
81
+ "resume_context": resume_context,
82
+ }
83
+
84
+ except Exception as e:
85
+ logger.error(f"Failed to resume session: {e}")
86
+ return {"status": "error", "message": str(e)}
87
+
88
+ def _load_session_by_id(self, session_id: str) -> Optional[Dict[str, Any]]:
89
+ """Load a specific session by ID.
90
+
91
+ Args:
92
+ session_id: The session identifier
93
+
94
+ Returns:
95
+ Session state dict or None if not found
96
+ """
97
+ session_file = self.session_dir / f"{session_id}.json"
98
+ if not session_file.exists():
99
+ logger.warning(f"Session file not found: {session_file}")
100
+ return None
101
+
102
+ return self.storage.read_json(session_file)
103
+
104
+ def _load_latest_session(self) -> Optional[Dict[str, Any]]:
105
+ """Load the most recent paused session.
106
+
107
+ Returns:
108
+ Session state dict or None if no sessions found
109
+ """
110
+ if not self.session_dir.exists():
111
+ return None
112
+
113
+ session_files = sorted(self.session_dir.glob("session-*.json"))
114
+ if not session_files:
115
+ return None
116
+
117
+ # Load the most recent session
118
+ latest_file = session_files[-1]
119
+ return self.storage.read_json(latest_file)
120
+
121
+ def _analyze_changes_since_pause(
122
+ self, session_state: Dict[str, Any]
123
+ ) -> Dict[str, Any]:
124
+ """Analyze what changed since session was paused.
125
+
126
+ Args:
127
+ session_state: The paused session state
128
+
129
+ Returns:
130
+ Dict containing change analysis
131
+ """
132
+ changes: Dict[str, Any] = {
133
+ "branch_changed": False,
134
+ "new_commits": [],
135
+ "new_commits_count": 0,
136
+ "working_directory_changes": {
137
+ "new_modified": [],
138
+ "new_untracked": [],
139
+ "resolved_files": [],
140
+ },
141
+ "warnings": [],
142
+ }
143
+
144
+ try:
145
+ git_context = session_state.get("git_context", {})
146
+
147
+ if not git_context.get("is_git_repo"):
148
+ return changes
149
+
150
+ # Check if branch changed
151
+ paused_branch = git_context.get("branch")
152
+ current_branch = self._get_current_branch()
153
+
154
+ if paused_branch and current_branch and paused_branch != current_branch:
155
+ changes["branch_changed"] = True
156
+ changes["warnings"].append(
157
+ f"Branch changed from '{paused_branch}' to '{current_branch}'"
158
+ )
159
+
160
+ # Check for new commits
161
+ paused_commits = git_context.get("recent_commits", [])
162
+ if paused_commits:
163
+ latest_paused_sha = paused_commits[0]["sha"]
164
+ new_commits = self._get_commits_since(latest_paused_sha)
165
+ changes["new_commits"] = new_commits
166
+ changes["new_commits_count"] = len(new_commits)
167
+
168
+ if new_commits:
169
+ changes["warnings"].append(
170
+ f"{len(new_commits)} new commit(s) since pause"
171
+ )
172
+
173
+ # Check working directory changes
174
+ paused_status = git_context.get("status", {})
175
+ current_status = self._get_current_status()
176
+
177
+ paused_modified = set(paused_status.get("modified_files", []))
178
+ current_modified = set(current_status.get("modified_files", []))
179
+ paused_untracked = set(paused_status.get("untracked_files", []))
180
+ current_untracked = set(current_status.get("untracked_files", []))
181
+
182
+ # Files that are newly modified
183
+ new_modified = list(current_modified - paused_modified)
184
+ # Files that are newly untracked
185
+ new_untracked = list(current_untracked - paused_untracked)
186
+ # Files that were modified but are now clean
187
+ resolved_files = list(paused_modified - current_modified)
188
+
189
+ changes["working_directory_changes"] = {
190
+ "new_modified": new_modified,
191
+ "new_untracked": new_untracked,
192
+ "resolved_files": resolved_files,
193
+ }
194
+
195
+ if new_modified:
196
+ changes["warnings"].append(
197
+ f"{len(new_modified)} file(s) modified since pause"
198
+ )
199
+ if new_untracked:
200
+ changes["warnings"].append(
201
+ f"{len(new_untracked)} new untracked file(s)"
202
+ )
203
+
204
+ except Exception as e:
205
+ logger.warning(f"Could not analyze changes: {e}")
206
+ changes["warnings"].append(f"Could not analyze changes: {e}")
207
+
208
+ return changes
209
+
210
+ def _get_current_branch(self) -> Optional[str]:
211
+ """Get current git branch.
212
+
213
+ Returns:
214
+ Branch name or None
215
+ """
216
+ try:
217
+ result = subprocess.run(
218
+ ["git", "branch", "--show-current"],
219
+ cwd=str(self.project_path),
220
+ capture_output=True,
221
+ text=True,
222
+ check=True,
223
+ )
224
+ return result.stdout.strip()
225
+ except Exception:
226
+ return None
227
+
228
+ def _get_commits_since(self, since_sha: str) -> List[Dict[str, str]]:
229
+ """Get commits since a specific SHA.
230
+
231
+ Args:
232
+ since_sha: The SHA to get commits after
233
+
234
+ Returns:
235
+ List of commit dicts
236
+ """
237
+ try:
238
+ result = subprocess.run(
239
+ ["git", "log", f"{since_sha}..HEAD", "--format=%h|%an|%ai|%s"],
240
+ cwd=str(self.project_path),
241
+ capture_output=True,
242
+ text=True,
243
+ check=True,
244
+ )
245
+
246
+ commits = []
247
+ for line in result.stdout.strip().split("\n"):
248
+ if not line:
249
+ continue
250
+ parts = line.split("|", 3)
251
+ if len(parts) == 4:
252
+ sha, author, timestamp, message = parts
253
+ commits.append(
254
+ {
255
+ "sha": sha,
256
+ "author": author,
257
+ "timestamp": timestamp,
258
+ "message": message,
259
+ }
260
+ )
261
+
262
+ return commits
263
+
264
+ except Exception as e:
265
+ logger.warning(f"Could not get commits: {e}")
266
+ return []
267
+
268
+ def _get_current_status(self) -> Dict[str, Any]:
269
+ """Get current git status.
270
+
271
+ Returns:
272
+ Dict with status information
273
+ """
274
+ status = {"clean": True, "modified_files": [], "untracked_files": []}
275
+
276
+ try:
277
+ result = subprocess.run(
278
+ ["git", "status", "--porcelain"],
279
+ cwd=str(self.project_path),
280
+ capture_output=True,
281
+ text=True,
282
+ check=True,
283
+ )
284
+
285
+ modified_files = []
286
+ untracked_files = []
287
+
288
+ for line in result.stdout.strip().split("\n"):
289
+ if not line:
290
+ continue
291
+ status_code = line[:2]
292
+ file_path = line[3:]
293
+
294
+ if status_code.startswith("??"):
295
+ untracked_files.append(file_path)
296
+ else:
297
+ modified_files.append(file_path)
298
+
299
+ status = {
300
+ "clean": len(modified_files) == 0 and len(untracked_files) == 0,
301
+ "modified_files": modified_files,
302
+ "untracked_files": untracked_files,
303
+ }
304
+
305
+ except Exception as e:
306
+ logger.warning(f"Could not get status: {e}")
307
+
308
+ return status
309
+
310
+ def _generate_resume_context(
311
+ self, session_state: Dict[str, Any], changes: Dict[str, Any]
312
+ ) -> str:
313
+ """Generate formatted context summary for resuming.
314
+
315
+ Args:
316
+ session_state: The paused session state
317
+ changes: Analysis of changes since pause
318
+
319
+ Returns:
320
+ Formatted context string
321
+ """
322
+ lines = []
323
+ lines.append("=" * 80)
324
+ lines.append("SESSION RESUME CONTEXT")
325
+ lines.append("=" * 80)
326
+ lines.append("")
327
+
328
+ # Session info
329
+ session_id = session_state.get("session_id", "unknown")
330
+ paused_at = session_state.get("paused_at", "unknown")
331
+ lines.append(f"Session ID: {session_id}")
332
+ lines.append(f"Paused at: {paused_at}")
333
+ lines.append("")
334
+
335
+ # Previous context
336
+ conversation = session_state.get("conversation", {})
337
+ lines.append("PREVIOUS CONTEXT:")
338
+ lines.append(f" Summary: {conversation.get('summary', 'Not provided')}")
339
+ lines.append("")
340
+
341
+ # Accomplishments
342
+ accomplishments = conversation.get("accomplishments", [])
343
+ if accomplishments:
344
+ lines.append("ACCOMPLISHMENTS:")
345
+ for item in accomplishments:
346
+ lines.append(f" - {item}")
347
+ lines.append("")
348
+
349
+ # Next steps
350
+ next_steps = conversation.get("next_steps", [])
351
+ if next_steps:
352
+ lines.append("PLANNED NEXT STEPS:")
353
+ for item in next_steps:
354
+ lines.append(f" - {item}")
355
+ lines.append("")
356
+
357
+ # Changes since pause
358
+ if changes.get("warnings"):
359
+ lines.append("CHANGES SINCE PAUSE:")
360
+ for warning in changes["warnings"]:
361
+ lines.append(f" ⚠️ {warning}")
362
+ lines.append("")
363
+
364
+ # New commits details
365
+ if changes.get("new_commits"):
366
+ lines.append("NEW COMMITS:")
367
+ for commit in changes["new_commits"][:5]:
368
+ lines.append(
369
+ f" - {commit['sha']}: {commit['message']} ({commit['author']})"
370
+ )
371
+ if len(changes["new_commits"]) > 5:
372
+ lines.append(f" ... and {len(changes['new_commits']) - 5} more")
373
+ lines.append("")
374
+
375
+ # Working directory changes
376
+ wd_changes = changes.get("working_directory_changes", {})
377
+ if wd_changes.get("new_modified"):
378
+ lines.append("NEWLY MODIFIED FILES:")
379
+ for file_path in wd_changes["new_modified"][:10]:
380
+ lines.append(f" - {file_path}")
381
+ if len(wd_changes["new_modified"]) > 10:
382
+ lines.append(f" ... and {len(wd_changes['new_modified']) - 10} more")
383
+ lines.append("")
384
+
385
+ # Todos
386
+ todos = session_state.get("todos", {})
387
+ active_todos = todos.get("active", [])
388
+ if active_todos:
389
+ lines.append("ACTIVE TODO ITEMS:")
390
+ for todo in active_todos:
391
+ status = todo.get("status", "unknown")
392
+ content = todo.get("content", "unknown")
393
+ lines.append(f" [{status}] {content}")
394
+ lines.append("")
395
+
396
+ lines.append("=" * 80)
397
+ lines.append("Ready to resume work!")
398
+ lines.append("=" * 80)
399
+
400
+ return "\n".join(lines)
401
+
402
+ def _display_resume_info(
403
+ self, session_state: Dict[str, Any], changes: Dict[str, Any]
404
+ ) -> None:
405
+ """Display resume information to console.
406
+
407
+ Args:
408
+ session_state: The paused session state
409
+ changes: Analysis of changes since pause
410
+ """
411
+ console.print()
412
+
413
+ # Session header
414
+ session_id = session_state.get("session_id", "unknown")
415
+ paused_at = session_state.get("paused_at", "unknown")
416
+
417
+ # Parse timestamp for better display
418
+ try:
419
+ dt = datetime.fromisoformat(paused_at.replace("Z", "+00:00"))
420
+ paused_display = dt.strftime("%Y-%m-%d %H:%M:%S UTC")
421
+ except Exception:
422
+ paused_display = paused_at
423
+
424
+ console.print(
425
+ Panel(
426
+ f"[bold cyan]Resuming Session[/bold cyan]\n\n"
427
+ f"[yellow]Session ID:[/yellow] {session_id}\n"
428
+ f"[yellow]Paused at:[/yellow] {paused_display}",
429
+ title="🟢 Session Resume",
430
+ border_style="cyan",
431
+ )
432
+ )
433
+
434
+ # Previous context
435
+ conversation = session_state.get("conversation", {})
436
+ console.print("\n[bold]Previous Context:[/bold]")
437
+ console.print(f" {conversation.get('summary', 'Not provided')}")
438
+
439
+ # Accomplishments
440
+ accomplishments = conversation.get("accomplishments", [])
441
+ if accomplishments:
442
+ console.print("\n[bold green]Accomplishments:[/bold green]")
443
+ for item in accomplishments:
444
+ console.print(f" ✓ {item}")
445
+
446
+ # Next steps
447
+ next_steps = conversation.get("next_steps", [])
448
+ if next_steps:
449
+ console.print("\n[bold yellow]Planned Next Steps:[/bold yellow]")
450
+ for idx, item in enumerate(next_steps, 1):
451
+ console.print(f" {idx}. {item}")
452
+
453
+ # Changes/Warnings
454
+ warnings = changes.get("warnings", [])
455
+ if warnings:
456
+ console.print("\n[bold red]⚠️ Changes Since Pause:[/bold red]")
457
+ for warning in warnings:
458
+ console.print(f" • {warning}")
459
+
460
+ # New commits table
461
+ new_commits = changes.get("new_commits", [])
462
+ if new_commits:
463
+ console.print("\n[bold]New Commits:[/bold]")
464
+ table = Table(show_header=True, header_style="bold magenta")
465
+ table.add_column("SHA", style="yellow", width=8)
466
+ table.add_column("Author", style="green", width=20)
467
+ table.add_column("Message", style="white")
468
+
469
+ for commit in new_commits[:5]:
470
+ msg = commit["message"]
471
+ if len(msg) > 60:
472
+ msg = msg[:57] + "..."
473
+ table.add_row(commit["sha"], commit["author"], msg)
474
+
475
+ console.print(table)
476
+ if len(new_commits) > 5:
477
+ console.print(
478
+ f" [dim]... and {len(new_commits) - 5} more commits[/dim]"
479
+ )
480
+
481
+ # Active todos
482
+ todos = session_state.get("todos", {})
483
+ active_todos = todos.get("active", [])
484
+ if active_todos:
485
+ console.print("\n[bold]Active Todo Items:[/bold]")
486
+ for todo in active_todos:
487
+ status = todo.get("status", "unknown")
488
+ content = todo.get("content", "unknown")
489
+ status_icon = {
490
+ "pending": "⏸️",
491
+ "in_progress": "🔄",
492
+ "completed": "✅",
493
+ }.get(status, "❓")
494
+ console.print(f" {status_icon} [{status}] {content}")
495
+
496
+ console.print()
497
+
498
+ def list_available_sessions(self) -> List[Dict[str, Any]]:
499
+ """List all available paused sessions.
500
+
501
+ Returns:
502
+ List of session information dicts
503
+ """
504
+ if not self.session_dir.exists():
505
+ return []
506
+
507
+ sessions = []
508
+ for session_file in sorted(self.session_dir.glob("session-*.json")):
509
+ try:
510
+ state = self.storage.read_json(session_file)
511
+ if state:
512
+ sessions.append(
513
+ {
514
+ "session_id": state.get("session_id"),
515
+ "paused_at": state.get("paused_at"),
516
+ "summary": state.get("conversation", {}).get("summary"),
517
+ "file_path": str(session_file),
518
+ }
519
+ )
520
+ except Exception as e:
521
+ logger.warning(f"Could not read session file {session_file}: {e}")
522
+
523
+ return sessions
@@ -31,6 +31,8 @@ def add_mpm_init_subparser(subparsers: Any) -> None:
31
31
  epilog=(
32
32
  "Examples:\n"
33
33
  " claude-mpm mpm-init # Initialize/update current directory\n"
34
+ " claude-mpm mpm-init pause # Pause current session\n"
35
+ " claude-mpm mpm-init resume # Resume latest session\n"
34
36
  " claude-mpm mpm-init --review # Review project state without changes\n"
35
37
  " claude-mpm mpm-init --update # Update existing CLAUDE.md\n"
36
38
  " claude-mpm mpm-init --quick-update # Quick update based on recent git activity\n"
@@ -205,5 +207,62 @@ def add_mpm_init_subparser(subparsers: Any) -> None:
205
207
  help="Path to project directory (default: current directory)",
206
208
  )
207
209
 
210
+ # Add subparsers for pause/resume commands
211
+ subcommands = mpm_init_parser.add_subparsers(
212
+ dest="subcommand",
213
+ title="session management",
214
+ description="Commands for managing session pause/resume",
215
+ )
216
+
217
+ # Pause subcommand
218
+ pause_parser = subcommands.add_parser(
219
+ "pause",
220
+ help="Pause current session and save state",
221
+ description="Pause the current session and capture state for later resumption",
222
+ )
223
+ pause_parser.add_argument(
224
+ "--summary",
225
+ "-s",
226
+ type=str,
227
+ help="Summary of what you were working on",
228
+ )
229
+ pause_parser.add_argument(
230
+ "--accomplishment",
231
+ "-a",
232
+ action="append",
233
+ help="Accomplishment from this session (can be used multiple times)",
234
+ )
235
+ pause_parser.add_argument(
236
+ "--next-step",
237
+ "-n",
238
+ action="append",
239
+ help="Next step to continue work (can be used multiple times)",
240
+ )
241
+ pause_parser.add_argument(
242
+ "project_path",
243
+ nargs="?",
244
+ default=".",
245
+ help="Path to project directory (default: current directory)",
246
+ )
247
+
248
+ # Resume subcommand
249
+ resume_parser = subcommands.add_parser(
250
+ "resume",
251
+ help="Resume a paused session",
252
+ description="Resume the most recent (or specified) paused session",
253
+ )
254
+ resume_parser.add_argument(
255
+ "--session-id",
256
+ "-i",
257
+ type=str,
258
+ help="Specific session ID to resume (defaults to most recent)",
259
+ )
260
+ resume_parser.add_argument(
261
+ "project_path",
262
+ nargs="?",
263
+ default=".",
264
+ help="Path to project directory (default: current directory)",
265
+ )
266
+
208
267
  # Set the command handler
209
268
  mpm_init_parser.set_defaults(command="mpm-init")
@@ -7,6 +7,10 @@ Initialize or intelligently update your project for optimal use with Claude Code
7
7
  ```
8
8
  /mpm-init # Auto-detects and offers update or create
9
9
  /mpm-init update # Lightweight update based on recent git activity
10
+ /mpm-init catchup # Show recent commit history for context
11
+ /mpm-init pause # Pause session and save state
12
+ /mpm-init resume # Resume most recent paused session
13
+ /mpm-init resume --list # List all paused sessions
10
14
  /mpm-init --review # Review project state without changes
11
15
  /mpm-init --update # Full update of existing CLAUDE.md
12
16
  /mpm-init --organize # Organize project structure
@@ -163,6 +167,76 @@ This displays:
163
167
 
164
168
  Useful for understanding recent development activity and getting PM up to speed on project changes.
165
169
 
170
+ ### Session Management (Pause/Resume)
171
+
172
+ Save and restore session state across Claude sessions:
173
+
174
+ **Pause Current Session:**
175
+ ```bash
176
+ /mpm-init pause
177
+ ```
178
+
179
+ This captures and saves:
180
+ - Conversation context and progress
181
+ - Current git repository state
182
+ - Active and completed todo items
183
+ - Working directory status
184
+ - Session timestamp and metadata
185
+
186
+ **Resume Previous Session:**
187
+ ```bash
188
+ /mpm-init resume
189
+ ```
190
+
191
+ This loads and analyzes:
192
+ - Most recent (or specified) paused session
193
+ - Changes since pause (git commits, file modifications)
194
+ - Potential conflicts or warnings
195
+ - Full context for seamless continuation
196
+
197
+ **Pause Options:**
198
+ - `-s, --summary TEXT`: Provide session summary
199
+ - `-a, --accomplishment TEXT`: Record accomplishments (can be used multiple times)
200
+ - `-n, --next-step TEXT`: Document next steps (can be used multiple times)
201
+ - `--no-commit`: Skip creating git commit with session info
202
+
203
+ **Resume Options:**
204
+ - `--session-id TEXT`: Resume specific session by ID
205
+ - `--list`: List all available paused sessions
206
+
207
+ **Example Usage:**
208
+ ```bash
209
+ # Pause with detailed context
210
+ /mpm-init pause -s "Implemented authentication system" \
211
+ -a "Added login endpoint" \
212
+ -a "Created user model" \
213
+ -a "Wrote integration tests" \
214
+ -n "Add logout endpoint" \
215
+ -n "Implement password reset"
216
+
217
+ # Resume latest session
218
+ /mpm-init resume
219
+
220
+ # List available sessions
221
+ /mpm-init resume --list
222
+
223
+ # Resume specific session
224
+ /mpm-init resume --session-id session-20251020-012501
225
+ ```
226
+
227
+ **Session Storage:**
228
+ - Sessions saved in `.claude-mpm/sessions/pause/`
229
+ - JSON format with secure permissions (0600)
230
+ - Includes checksums for data integrity
231
+ - Automatic git commit creation (unless `--no-commit`)
232
+
233
+ **Use Cases:**
234
+ - **Context Continuity**: Maintain context across multiple Claude sessions
235
+ - **Team Handoffs**: Save state before passing work to another team member
236
+ - **Long-running Projects**: Track progress over multiple work sessions
237
+ - **Break Points**: Document progress at natural stopping points
238
+ - **Change Awareness**: Detect what changed while you were away
239
+
166
240
  ### Review Project State
167
241
  ```bash
168
242
  /mpm-init --review
@@ -268,10 +342,13 @@ The command delegates to the Agentic Coder Optimizer agent which:
268
342
  ## Notes
269
343
 
270
344
  - **Quick Update vs Full Update**: Use `/mpm-init update` for fast activity-based updates (30 days), or `/mpm-init --update` for comprehensive doc refresh
345
+ - **Session Management**: Use `/mpm-init pause` to save state and `/mpm-init resume` to continue later with full context
271
346
  - **Smart Mode**: Automatically detects existing CLAUDE.md and offers update vs recreate
272
347
  - **Safe Updates**: Previous versions always archived before updating
273
348
  - **Custom Content**: Your project-specific sections are preserved by default
274
- - **Git Integration**: Analyzes recent commits to understand project evolution
349
+ - **Git Integration**: Analyzes recent commits to understand project evolution; pause creates optional git commits
350
+ - **Session Storage**: Paused sessions stored in `.claude-mpm/sessions/pause/` with secure permissions
351
+ - **Change Detection**: Resume automatically detects and reports changes since pause
275
352
  - **Argument Processing**: The slash command processes the `update` argument and routes to `--quick-update` flag
276
353
  - The command uses the Agentic Coder Optimizer agent for implementation
277
354
  - AST analysis is enabled by default for comprehensive documentation