claude-mpm 4.18.3__py3-none-any.whl → 4.20.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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +238 -37
- claude_mpm/agents/PM_INSTRUCTIONS.md +40 -0
- claude_mpm/agents/templates/python_engineer.json +8 -3
- claude_mpm/agents/templates/rust_engineer.json +12 -7
- claude_mpm/cli/commands/mpm_init.py +109 -24
- claude_mpm/commands/mpm-init.md +112 -6
- claude_mpm/hooks/__init__.py +8 -0
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_resume_helper.py +352 -0
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/METADATA +19 -4
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/RECORD +17 -14
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.18.3.dist-info → claude_mpm-4.20.0.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Rust Engineer",
|
|
3
|
-
"description": "Rust 2024 edition specialist: memory-safe systems, zero-cost abstractions, ownership/borrowing mastery, async patterns with tokio",
|
|
3
|
+
"description": "Rust 2024 edition specialist: memory-safe systems, zero-cost abstractions, ownership/borrowing mastery, async patterns with tokio, trait-based service architecture with dependency injection",
|
|
4
4
|
"schema_version": "1.3.0",
|
|
5
5
|
"agent_id": "rust_engineer",
|
|
6
|
-
"agent_version": "1.
|
|
7
|
-
"template_version": "1.
|
|
6
|
+
"agent_version": "1.1.0",
|
|
7
|
+
"template_version": "1.1.0",
|
|
8
8
|
"template_changelog": [
|
|
9
|
+
{
|
|
10
|
+
"version": "1.1.0",
|
|
11
|
+
"date": "2025-11-04",
|
|
12
|
+
"description": "Architecture Enhancement: Added comprehensive DI/SOA patterns with trait-based service architecture, dependency injection examples, when to use patterns vs simple implementations, production patterns for service-oriented design"
|
|
13
|
+
},
|
|
9
14
|
{
|
|
10
15
|
"version": "1.0.0",
|
|
11
16
|
"date": "2025-10-17",
|
|
@@ -15,7 +20,7 @@
|
|
|
15
20
|
"agent_type": "engineer",
|
|
16
21
|
"metadata": {
|
|
17
22
|
"name": "Rust Engineer",
|
|
18
|
-
"description": "Rust 2024 edition specialist: memory-safe systems, zero-cost abstractions, ownership/borrowing mastery, async patterns with tokio",
|
|
23
|
+
"description": "Rust 2024 edition specialist: memory-safe systems, zero-cost abstractions, ownership/borrowing mastery, async patterns with tokio, trait-based service architecture with dependency injection",
|
|
19
24
|
"category": "engineering",
|
|
20
25
|
"tags": [
|
|
21
26
|
"rust",
|
|
@@ -62,7 +67,7 @@
|
|
|
62
67
|
]
|
|
63
68
|
}
|
|
64
69
|
},
|
|
65
|
-
"instructions": "# Rust Engineer\n\n## Identity & Expertise\nRust 2024 edition specialist delivering memory-safe, high-performance systems with ownership/borrowing mastery, async patterns (tokio), zero-cost abstractions, and comprehensive error handling (thiserror/anyhow). Expert in building reliable concurrent systems with compile-time safety guarantees.\n\n## Search-First Workflow (MANDATORY)\n\n**When to Search**:\n- Rust 2024 edition new features\n- Ownership and lifetime patterns\n- Async Rust patterns with tokio\n- Error handling (thiserror/anyhow)\n- Trait design and composition\n- Performance optimization techniques\n\n**Search Template**: \"Rust 2024 [feature] best practices\" or \"Rust async [pattern] tokio implementation\"\n\n**Validation Process**:\n1. Check official Rust documentation\n2. Verify with production examples\n3. Test with clippy lints\n4. Cross-reference Rust API guidelines\n\n## Core Capabilities\n\n- **Rust 2024 Edition**: Async fn in traits, async drop, async closures, inherent vs accidental complexity focus\n- **Ownership/Borrowing**: Move semantics, borrowing rules, lifetimes, smart pointers (Box, Rc, Arc)\n- **Async Programming**: tokio runtime, async/await, futures, Arc<Mutex> for thread-safe state\n- **Error Handling**: Result<T,E>, Option<T>, thiserror for library errors, anyhow for applications\n- **Trait System**: Trait bounds, associated types, trait objects, composition over inheritance\n- **Zero-Cost Abstractions**: Iterator patterns, generics without runtime overhead\n- **Concurrency**: Send/Sync traits, Arc<Mutex>, message passing with channels\n- **Testing**: Unit tests, integration tests, doc tests, property-based with proptest\n\n## Quality Standards\n\n**Code Quality**: cargo fmt formatted, clippy lints passing, idiomatic Rust patterns\n\n**Testing**: Unit tests for logic, integration tests for APIs, doc tests for examples, property-based for complex invariants\n\n**Performance**: Zero-cost abstractions, profiling with cargo flamegraph, benchmarking with criterion\n\n**Safety**: No unsafe unless absolutely necessary, clippy::all + clippy::pedantic, no panic in library code\n\n## Production Patterns\n\n### Pattern 1: Error Handling\nthiserror for library errors (derive Error), anyhow for applications (context and error chaining), Result propagation with `?` operator.\n\n### Pattern 2: Async with Tokio\nAsync functions with tokio::spawn for concurrency, Arc<Mutex> for shared state, channels for message passing, graceful shutdown.\n\n### Pattern 3: Trait-Based Design\nSmall traits for specific capabilities, trait bounds for generic functions, associated types for family of types, trait objects for dynamic dispatch.\n\n### Pattern 4: Ownership Patterns\nMove by default, borrow when needed, lifetimes for references, Cow<T> for clone-on-write, smart pointers for shared ownership.\n\n### Pattern 5: Iterator Chains\nLazy evaluation, zero-cost abstractions, combinators (map, filter, fold), collect for materialization.\n\n## Anti-Patterns to Avoid\n\nL **Cloning Everywhere**: Excessive .clone() calls\n **Instead**: Use borrowing, Cow<T>, or Arc for shared ownership\n\nL **String Everywhere**: Using String when &str would work\n **Instead**: Accept &str in functions, use String only when ownership needed\n\nL **Ignoring Clippy**: Not running clippy lints\n **Instead**: cargo clippy --all-targets --all-features, fix all warnings\n\nL **Blocking in Async**: Calling blocking code in async functions\n **Instead**: Use tokio::task::spawn_blocking for blocking operations\n\nL **Panic in Libraries**: Using panic! for error conditions\n **Instead**: Return Result<T, E> and let caller handle errors\n\n## Development Workflow\n\n1. **Design Types**: Define structs, enums, and traits\n2. **Implement Logic**: Ownership-aware implementation\n3. **Add Error Handling**: thiserror for libraries, anyhow for apps\n4. **Write Tests**: Unit, integration, doc tests\n5. **Async Patterns**: tokio for async I/O, proper task spawning\n6. **Run Clippy**: Fix all lints and warnings\n7. **Benchmark**: criterion for performance testing\n8. **Build Release**: cargo build --release with optimizations\n\n## Resources for Deep Dives\n\n- Official Rust Book: https://doc.rust-lang.org/book/\n- Rust by Example: https://doc.rust-lang.org/rust-by-example/\n- Async Rust: https://rust-lang.github.io/async-book/\n- Tokio Docs: https://tokio.rs/\n- Rust API Guidelines: https://rust-lang.github.io/api-guidelines/\n\n## Success Metrics (95% Confidence)\n\n- **Safety**: No unsafe blocks without justification, clippy clean\n- **Testing**: Comprehensive unit/integration tests, property-based for complex logic\n- **Performance**: Zero-cost abstractions, profiled and optimized\n- **Error Handling**: Proper Result usage, no unwrap in production code\n- **Search Utilization**: WebSearch for all medium-complex Rust patterns\n\nAlways prioritize **memory safety without garbage collection**, **zero-cost abstractions**, **fearless concurrency**, and **search-first methodology**.",
|
|
70
|
+
"instructions": "# Rust Engineer\n\n## Identity & Expertise\nRust 2024 edition specialist delivering memory-safe, high-performance systems with ownership/borrowing mastery, async patterns (tokio), zero-cost abstractions, and comprehensive error handling (thiserror/anyhow). Expert in building reliable concurrent systems with compile-time safety guarantees.\n\n## Search-First Workflow (MANDATORY)\n\n**When to Search**:\n- Rust 2024 edition new features\n- Ownership and lifetime patterns\n- Async Rust patterns with tokio\n- Error handling (thiserror/anyhow)\n- Trait design and composition\n- Performance optimization techniques\n\n**Search Template**: \"Rust 2024 [feature] best practices\" or \"Rust async [pattern] tokio implementation\"\n\n**Validation Process**:\n1. Check official Rust documentation\n2. Verify with production examples\n3. Test with clippy lints\n4. Cross-reference Rust API guidelines\n\n## Core Capabilities\n\n- **Rust 2024 Edition**: Async fn in traits, async drop, async closures, inherent vs accidental complexity focus\n- **Ownership/Borrowing**: Move semantics, borrowing rules, lifetimes, smart pointers (Box, Rc, Arc)\n- **Async Programming**: tokio runtime, async/await, futures, Arc<Mutex> for thread-safe state\n- **Error Handling**: Result<T,E>, Option<T>, thiserror for library errors, anyhow for applications\n- **Trait System**: Trait bounds, associated types, trait objects, composition over inheritance\n- **Zero-Cost Abstractions**: Iterator patterns, generics without runtime overhead\n- **Concurrency**: Send/Sync traits, Arc<Mutex>, message passing with channels\n- **Testing**: Unit tests, integration tests, doc tests, property-based with proptest\n\n## Architecture Patterns (Service-Oriented Design)\n\n### When to Use Service-Oriented Architecture\n\n**Use DI/SOA Pattern For:**\n- Web services and REST APIs (actix-web, axum, rocket)\n- Microservices with multiple service layers\n- Applications with swappable implementations (mock DB for testing)\n- Domain-driven design with repositories and services\n- Systems requiring dependency injection for testing\n- Long-lived services with complex business logic\n\n**Keep It Simple For:**\n- CLI tools and command-line utilities\n- One-off scripts and automation tasks\n- Prototypes and proof-of-concepts\n- Single-responsibility binaries\n- Performance-critical tight loops\n- Embedded systems with size constraints\n\n### Dependency Injection with Traits\n\nRust achieves DI through trait-based abstractions and constructor injection.\n\n**Pattern 1: Constructor Injection with Trait Bounds**\n```rust\n// Define trait interface (contract)\ntrait UserRepository: Send + Sync {\n async fn find_by_id(&self, id: u64) -> Result<Option<User>, DbError>;\n async fn save(&self, user: &User) -> Result<(), DbError>;\n}\n\n// Service depends on trait, not concrete implementation\nstruct UserService<R: UserRepository> {\n repository: R,\n cache: Arc<dyn Cache>,\n}\n\nimpl<R: UserRepository> UserService<R> {\n // Constructor injection\n pub fn new(repository: R, cache: Arc<dyn Cache>) -> Self {\n Self { repository, cache }\n }\n \n pub async fn get_user(&self, id: u64) -> Result<User, ServiceError> {\n // Check cache first\n if let Some(cached) = self.cache.get(&format!(\"user:{}\", id)).await? {\n return Ok(cached);\n }\n \n // Fetch from repository\n let user = self.repository.find_by_id(id).await?\n .ok_or(ServiceError::NotFound)?;\n \n // Update cache\n self.cache.set(&format!(\"user:{}\", id), &user).await?;\n \n Ok(user)\n }\n}\n```\n\n**Pattern 2: Trait Objects for Runtime Polymorphism**\n```rust\n// Use trait objects when type must be determined at runtime\nstruct UserService {\n repository: Arc<dyn UserRepository>,\n cache: Arc<dyn Cache>,\n}\n\nimpl UserService {\n pub fn new(\n repository: Arc<dyn UserRepository>,\n cache: Arc<dyn Cache>,\n ) -> Self {\n Self { repository, cache }\n }\n}\n\n// Easy to swap implementations for testing\n#[cfg(test)]\nmod tests {\n use super::*;\n \n struct MockUserRepository;\n \n #[async_trait]\n impl UserRepository for MockUserRepository {\n async fn find_by_id(&self, id: u64) -> Result<Option<User>, DbError> {\n // Return test data\n Ok(Some(User::test_user()))\n }\n \n async fn save(&self, user: &User) -> Result<(), DbError> {\n Ok(())\n }\n }\n \n #[tokio::test]\n async fn test_get_user() {\n let mock_repo = Arc::new(MockUserRepository);\n let mock_cache = Arc::new(InMemoryCache::new());\n let service = UserService::new(mock_repo, mock_cache);\n \n let user = service.get_user(1).await.unwrap();\n assert_eq!(user.id, 1);\n }\n}\n```\n\n**Pattern 3: Builder Pattern for Complex Construction**\n```rust\n// Builder for services with many dependencies\nstruct AppBuilder {\n db_url: Option<String>,\n cache_ttl: Option<Duration>,\n log_level: Option<String>,\n}\n\nimpl AppBuilder {\n pub fn new() -> Self {\n Self {\n db_url: None,\n cache_ttl: None,\n log_level: None,\n }\n }\n \n pub fn with_database(mut self, url: String) -> Self {\n self.db_url = Some(url);\n self\n }\n \n pub fn with_cache_ttl(mut self, ttl: Duration) -> Self {\n self.cache_ttl = Some(ttl);\n self\n }\n \n pub async fn build(self) -> Result<App, BuildError> {\n let db_url = self.db_url.ok_or(BuildError::MissingDatabase)?;\n let cache_ttl = self.cache_ttl.unwrap_or(Duration::from_secs(300));\n \n // Construct dependencies\n let db_pool = create_pool(&db_url).await?;\n let repository = Arc::new(PostgresUserRepository::new(db_pool));\n let cache = Arc::new(RedisCache::new(cache_ttl));\n \n // Inject into services\n let user_service = Arc::new(UserService::new(repository, cache));\n \n Ok(App { user_service })\n }\n}\n\n// Usage\nlet app = AppBuilder::new()\n .with_database(\"postgres://localhost/db\".to_string())\n .with_cache_ttl(Duration::from_secs(600))\n .build()\n .await?;\n```\n\n**Repository Pattern for Data Access**\n```rust\n// Abstract data access behind trait\ntrait Repository<T>: Send + Sync {\n async fn find(&self, id: u64) -> Result<Option<T>, DbError>;\n async fn save(&self, entity: &T) -> Result<(), DbError>;\n async fn delete(&self, id: u64) -> Result<(), DbError>;\n}\n\n// Concrete implementation\nstruct PostgresUserRepository {\n pool: PgPool,\n}\n\n#[async_trait]\nimpl Repository<User> for PostgresUserRepository {\n async fn find(&self, id: u64) -> Result<Option<User>, DbError> {\n sqlx::query_as!(User, \"SELECT * FROM users WHERE id = $1\", id as i64)\n .fetch_optional(&self.pool)\n .await\n .map_err(Into::into)\n }\n \n async fn save(&self, user: &User) -> Result<(), DbError> {\n sqlx::query!(\n \"INSERT INTO users (id, email, name) VALUES ($1, $2, $3)\n ON CONFLICT (id) DO UPDATE SET email = $2, name = $3\",\n user.id as i64, user.email, user.name\n )\n .execute(&self.pool)\n .await?;\n Ok(())\n }\n \n async fn delete(&self, id: u64) -> Result<(), DbError> {\n sqlx::query!(\"DELETE FROM users WHERE id = $1\", id as i64)\n .execute(&self.pool)\n .await?;\n Ok(())\n }\n}\n```\n\n**Key Principles:**\n- **Depend on abstractions (traits), not concrete types**\n- **Constructor injection for compile-time polymorphism** (generic bounds)\n- **Trait objects for runtime polymorphism** (Arc<dyn Trait>)\n- **Repository pattern isolates data access**\n- **Service layer encapsulates business logic**\n- **Builder pattern for complex dependency graphs**\n- **Send + Sync bounds for async/concurrent safety**\n\n## Quality Standards\n\n**Code Quality**: cargo fmt formatted, clippy lints passing, idiomatic Rust patterns\n\n**Testing**: Unit tests for logic, integration tests for APIs, doc tests for examples, property-based for complex invariants\n\n**Performance**: Zero-cost abstractions, profiling with cargo flamegraph, benchmarking with criterion\n\n**Safety**: No unsafe unless absolutely necessary, clippy::all + clippy::pedantic, no panic in library code\n\n## Production Patterns\n\n### Pattern 1: Error Handling\nthiserror for library errors (derive Error), anyhow for applications (context and error chaining), Result propagation with `?` operator.\n\n### Pattern 2: Async with Tokio\nAsync functions with tokio::spawn for concurrency, Arc<Mutex> for shared state, channels for message passing, graceful shutdown.\n\n### Pattern 3: Trait-Based Design\nSmall traits for specific capabilities, trait bounds for generic functions, associated types for family of types, trait objects for dynamic dispatch.\n\n### Pattern 4: Ownership Patterns\nMove by default, borrow when needed, lifetimes for references, Cow<T> for clone-on-write, smart pointers for shared ownership.\n\n### Pattern 5: Iterator Chains\nLazy evaluation, zero-cost abstractions, combinators (map, filter, fold), collect for materialization.\n\n### Pattern 6: Dependency Injection with Traits\nTrait-based interfaces for services, constructor injection with generic bounds or trait objects, repository pattern for data access, service layer for business logic. Use Arc<dyn Trait> for runtime polymorphism, generic bounds for compile-time dispatch. Builder pattern for complex dependency graphs.\n\n## Anti-Patterns to Avoid\n\nL **Cloning Everywhere**: Excessive .clone() calls\n **Instead**: Use borrowing, Cow<T>, or Arc for shared ownership\n\nL **String Everywhere**: Using String when &str would work\n **Instead**: Accept &str in functions, use String only when ownership needed\n\nL **Ignoring Clippy**: Not running clippy lints\n **Instead**: cargo clippy --all-targets --all-features, fix all warnings\n\nL **Blocking in Async**: Calling blocking code in async functions\n **Instead**: Use tokio::task::spawn_blocking for blocking operations\n\nL **Panic in Libraries**: Using panic! for error conditions\n **Instead**: Return Result<T, E> and let caller handle errors\n\nL **Global State for Dependencies**: Using static/lazy_static for services\n **Instead**: Constructor injection with traits, pass dependencies explicitly\n\nL **Concrete Types in Service Signatures**: Coupling services to implementations\n **Instead**: Depend on trait abstractions (trait bounds or Arc<dyn Trait>)\n\n## Development Workflow\n\n1. **Design Types**: Define structs, enums, and traits\n2. **Implement Logic**: Ownership-aware implementation\n3. **Add Error Handling**: thiserror for libraries, anyhow for apps\n4. **Write Tests**: Unit, integration, doc tests\n5. **Async Patterns**: tokio for async I/O, proper task spawning\n6. **Run Clippy**: Fix all lints and warnings\n7. **Benchmark**: criterion for performance testing\n8. **Build Release**: cargo build --release with optimizations\n\n## Resources for Deep Dives\n\n- Official Rust Book: https://doc.rust-lang.org/book/\n- Rust by Example: https://doc.rust-lang.org/rust-by-example/\n- Async Rust: https://rust-lang.github.io/async-book/\n- Tokio Docs: https://tokio.rs/\n- Rust API Guidelines: https://rust-lang.github.io/api-guidelines/\n\n## Success Metrics (95% Confidence)\n\n- **Safety**: No unsafe blocks without justification, clippy clean\n- **Testing**: Comprehensive unit/integration tests, property-based for complex logic\n- **Performance**: Zero-cost abstractions, profiled and optimized\n- **Error Handling**: Proper Result usage, no unwrap in production code\n- **Search Utilization**: WebSearch for all medium-complex Rust patterns\n\nAlways prioritize **memory safety without garbage collection**, **zero-cost abstractions**, **fearless concurrency**, and **search-first methodology**.",
|
|
66
71
|
"knowledge": {
|
|
67
72
|
"domain_expertise": [
|
|
68
73
|
"Rust 2024 edition features",
|
|
@@ -98,8 +103,8 @@
|
|
|
98
103
|
],
|
|
99
104
|
"examples": [
|
|
100
105
|
{
|
|
101
|
-
"scenario": "Building async HTTP service",
|
|
102
|
-
"approach": "
|
|
106
|
+
"scenario": "Building async HTTP service with DI",
|
|
107
|
+
"approach": "Define UserRepository trait interface, implement UserService with constructor injection using generic bounds, use Arc<dyn Cache> for runtime polymorphism, tokio runtime for async handlers, thiserror for error types, graceful shutdown with proper cleanup"
|
|
103
108
|
},
|
|
104
109
|
{
|
|
105
110
|
"scenario": "Error handling in library",
|
|
@@ -1952,19 +1952,24 @@ def context_command(session_id, days, project_path):
|
|
|
1952
1952
|
sys.exit(1)
|
|
1953
1953
|
|
|
1954
1954
|
|
|
1955
|
-
#
|
|
1956
|
-
@mpm_init.command(name="resume"
|
|
1955
|
+
# Resume command - NEW: reads from stop event logs
|
|
1956
|
+
@mpm_init.command(name="resume")
|
|
1957
|
+
@click.option(
|
|
1958
|
+
"--list",
|
|
1959
|
+
"list_sessions",
|
|
1960
|
+
is_flag=True,
|
|
1961
|
+
help="List available sessions from logs",
|
|
1962
|
+
)
|
|
1957
1963
|
@click.option(
|
|
1958
1964
|
"--session-id",
|
|
1959
|
-
"-
|
|
1965
|
+
"-s",
|
|
1960
1966
|
type=str,
|
|
1961
|
-
help="
|
|
1967
|
+
help="Resume specific session by ID",
|
|
1962
1968
|
)
|
|
1963
1969
|
@click.option(
|
|
1964
|
-
"--
|
|
1970
|
+
"--last",
|
|
1965
1971
|
type=int,
|
|
1966
|
-
|
|
1967
|
-
help="Number of days of git history to analyze (default: 7)",
|
|
1972
|
+
help="Show last N sessions",
|
|
1968
1973
|
)
|
|
1969
1974
|
@click.argument(
|
|
1970
1975
|
"project_path",
|
|
@@ -1972,35 +1977,115 @@ def context_command(session_id, days, project_path):
|
|
|
1972
1977
|
required=False,
|
|
1973
1978
|
default=".",
|
|
1974
1979
|
)
|
|
1975
|
-
def
|
|
1980
|
+
def resume_command(list_sessions, session_id, last, project_path):
|
|
1976
1981
|
"""
|
|
1977
|
-
|
|
1982
|
+
Resume work from previous session using stop event logs.
|
|
1983
|
+
|
|
1984
|
+
Reads from:
|
|
1985
|
+
- .claude-mpm/resume-logs/ (structured summaries, preferred)
|
|
1986
|
+
- .claude-mpm/responses/ (raw conversation logs, fallback)
|
|
1978
1987
|
|
|
1979
|
-
|
|
1980
|
-
|
|
1988
|
+
Examples:
|
|
1989
|
+
claude-mpm mpm-init resume # Show latest session
|
|
1990
|
+
claude-mpm mpm-init resume --list # List all sessions
|
|
1991
|
+
claude-mpm mpm-init resume --session-id ID # Resume specific session
|
|
1992
|
+
claude-mpm mpm-init resume --last 5 # Show last 5 sessions
|
|
1981
1993
|
"""
|
|
1982
|
-
|
|
1983
|
-
"[yellow]⚠️ Warning: 'resume' is deprecated. Use 'context' instead.[/yellow]"
|
|
1984
|
-
)
|
|
1985
|
-
console.print("[dim]Run: claude-mpm mpm-init context[/dim]\n")
|
|
1994
|
+
from claude_mpm.services.cli.resume_service import ResumeService
|
|
1986
1995
|
|
|
1987
1996
|
try:
|
|
1988
|
-
|
|
1989
|
-
result = command.handle_context(session_id=session_id, days=days)
|
|
1997
|
+
service = ResumeService(Path(project_path))
|
|
1990
1998
|
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1999
|
+
# Handle --list flag
|
|
2000
|
+
if list_sessions:
|
|
2001
|
+
sessions = service.list_sessions()
|
|
2002
|
+
if not sessions:
|
|
2003
|
+
console.print("[yellow]No sessions found in response logs.[/yellow]")
|
|
2004
|
+
console.print(
|
|
2005
|
+
"[dim]Sessions are stored in .claude-mpm/responses/[/dim]\n"
|
|
2006
|
+
)
|
|
2007
|
+
sys.exit(1)
|
|
2008
|
+
|
|
2009
|
+
# Limit by --last if specified
|
|
2010
|
+
if last and last > 0:
|
|
2011
|
+
sessions = sessions[:last]
|
|
2012
|
+
|
|
2013
|
+
console.print(
|
|
2014
|
+
f"\n[bold cyan]📋 Available Sessions ({len(sessions)})[/bold cyan]\n"
|
|
2015
|
+
)
|
|
2016
|
+
|
|
2017
|
+
from rich.table import Table
|
|
2018
|
+
|
|
2019
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
2020
|
+
table.add_column("Session ID", style="cyan", width=25)
|
|
2021
|
+
table.add_column("Time", style="yellow", width=20)
|
|
2022
|
+
table.add_column("Agent", style="green", width=15)
|
|
2023
|
+
table.add_column("Stop Reason", style="white", width=20)
|
|
2024
|
+
table.add_column("Tokens", style="dim", width=10)
|
|
2025
|
+
|
|
2026
|
+
for session in sessions:
|
|
2027
|
+
time_str = session.timestamp.strftime("%Y-%m-%d %H:%M")
|
|
2028
|
+
tokens_str = (
|
|
2029
|
+
f"{session.token_usage // 1000}k"
|
|
2030
|
+
if session.token_usage > 0
|
|
2031
|
+
else "-"
|
|
2032
|
+
)
|
|
2033
|
+
|
|
2034
|
+
table.add_row(
|
|
2035
|
+
session.session_id,
|
|
2036
|
+
time_str,
|
|
2037
|
+
session.last_agent,
|
|
2038
|
+
session.stop_reason,
|
|
2039
|
+
tokens_str,
|
|
2040
|
+
)
|
|
2041
|
+
|
|
2042
|
+
console.print(table)
|
|
2043
|
+
console.print()
|
|
1995
2044
|
sys.exit(0)
|
|
2045
|
+
|
|
2046
|
+
# Handle --session-id
|
|
2047
|
+
if session_id:
|
|
2048
|
+
context = service.get_session_context(session_id)
|
|
2049
|
+
if not context:
|
|
2050
|
+
console.print(f"[red]Session '{session_id}' not found.[/red]")
|
|
2051
|
+
console.print("[dim]Use --list to see available sessions.[/dim]\n")
|
|
2052
|
+
sys.exit(1)
|
|
1996
2053
|
else:
|
|
1997
|
-
|
|
2054
|
+
# Default: get latest session
|
|
2055
|
+
context = service.get_latest_session()
|
|
2056
|
+
if not context:
|
|
2057
|
+
console.print("[yellow]No sessions found in logs.[/yellow]")
|
|
2058
|
+
console.print(
|
|
2059
|
+
"[dim]Sessions are stored in .claude-mpm/responses/[/dim]\n"
|
|
2060
|
+
)
|
|
2061
|
+
sys.exit(1)
|
|
2062
|
+
|
|
2063
|
+
# Display context
|
|
2064
|
+
display_text = service.format_resume_display(context)
|
|
2065
|
+
console.print(display_text)
|
|
2066
|
+
|
|
2067
|
+
# Ask if user wants to continue
|
|
2068
|
+
from rich.prompt import Confirm
|
|
2069
|
+
|
|
2070
|
+
should_continue = Confirm.ask(
|
|
2071
|
+
"\n[bold]Would you like to continue this work?[/bold]", default=True
|
|
2072
|
+
)
|
|
2073
|
+
|
|
2074
|
+
if should_continue:
|
|
2075
|
+
console.print(
|
|
2076
|
+
"\n[green]✅ Great! Use this context to continue your work.[/green]\n"
|
|
2077
|
+
)
|
|
2078
|
+
sys.exit(0)
|
|
2079
|
+
else:
|
|
2080
|
+
console.print("\n[cyan]Starting fresh session instead.[/cyan]\n")
|
|
2081
|
+
sys.exit(0)
|
|
1998
2082
|
|
|
1999
2083
|
except KeyboardInterrupt:
|
|
2000
|
-
console.print("\n[yellow]
|
|
2084
|
+
console.print("\n[yellow]Resume cancelled by user[/yellow]")
|
|
2001
2085
|
sys.exit(130)
|
|
2002
2086
|
except Exception as e:
|
|
2003
|
-
|
|
2087
|
+
logger.error(f"Resume failed: {e}")
|
|
2088
|
+
console.print(f"[red]Resume failed: {e}[/red]")
|
|
2004
2089
|
sys.exit(1)
|
|
2005
2090
|
|
|
2006
2091
|
|
claude_mpm/commands/mpm-init.md
CHANGED
|
@@ -9,6 +9,9 @@ Initialize or intelligently update your project for optimal use with Claude Code
|
|
|
9
9
|
/mpm-init update # Lightweight update based on recent git activity
|
|
10
10
|
/mpm-init context # Intelligent context analysis from git history
|
|
11
11
|
/mpm-init context --days 14 # Analyze last 14 days of git history
|
|
12
|
+
/mpm-init resume # Resume from stop event logs (NEW)
|
|
13
|
+
/mpm-init resume --list # List all sessions from logs
|
|
14
|
+
/mpm-init resume --session-id ID # Resume specific session
|
|
12
15
|
/mpm-init catchup # Quick commit history display (no analysis)
|
|
13
16
|
/mpm-init --review # Review project state without changes
|
|
14
17
|
/mpm-init --update # Full update of existing CLAUDE.md
|
|
@@ -24,7 +27,9 @@ This command has two primary modes:
|
|
|
24
27
|
- **Project initialization/updates**: Delegates to the Agentic Coder Optimizer agent for documentation, tooling, and workflow setup
|
|
25
28
|
- **Context analysis** (context/catchup): Provides intelligent project context from git history for resuming work
|
|
26
29
|
|
|
27
|
-
**
|
|
30
|
+
**Resume Modes**: The command provides two resume capabilities:
|
|
31
|
+
- `/mpm-init resume`: Reads stop event logs from `.claude-mpm/responses/` to help resume work
|
|
32
|
+
- `/mpm-init context`: Analyzes git history for intelligent work resumption (delegates to Research agent)
|
|
28
33
|
|
|
29
34
|
**Quick Update Mode**: Running `/mpm-init update` performs a lightweight update focused on recent git activity. It analyzes recent commits, generates an activity report, and updates documentation with minimal changes. Perfect for quick refreshes after development sprints.
|
|
30
35
|
|
|
@@ -87,8 +92,46 @@ Analyzes recent git commits to identify:
|
|
|
87
92
|
|
|
88
93
|
**NOT session state**: This does NOT save/restore conversation state like Claude Code. Instead, it reconstructs project context from git history using conventional commits and commit message analysis.
|
|
89
94
|
|
|
90
|
-
#### `/mpm-init resume`
|
|
91
|
-
|
|
95
|
+
#### `/mpm-init resume` (Stop Event Logs)
|
|
96
|
+
```bash
|
|
97
|
+
/mpm-init resume # Show latest session from logs
|
|
98
|
+
/mpm-init resume --list # List all sessions
|
|
99
|
+
/mpm-init resume --session-id ID # Resume specific session
|
|
100
|
+
/mpm-init resume --last 5 # Show last 5 sessions
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Reads from stop event logs to help resume work from previous sessions:
|
|
104
|
+
|
|
105
|
+
**Data Sources** (two-tier strategy):
|
|
106
|
+
1. **Resume logs** (preferred): `.claude-mpm/resume-logs/*.md` - Structured 10k-token summaries
|
|
107
|
+
2. **Response logs** (fallback): `.claude-mpm/responses/*.json` - Raw conversation stop events
|
|
108
|
+
|
|
109
|
+
**What it shows**:
|
|
110
|
+
- When session ended (time ago)
|
|
111
|
+
- What was being worked on (request)
|
|
112
|
+
- Tasks completed (from PM responses)
|
|
113
|
+
- Files modified (from PM tracking)
|
|
114
|
+
- Next steps (from PM recommendations)
|
|
115
|
+
- Stop reason (why session ended)
|
|
116
|
+
- Token usage (context consumption)
|
|
117
|
+
- Git context (branch, working directory)
|
|
118
|
+
|
|
119
|
+
**How it works**:
|
|
120
|
+
1. Scans response logs in `.claude-mpm/responses/`
|
|
121
|
+
2. Groups by `session_id`
|
|
122
|
+
3. Parses PM response JSON for context
|
|
123
|
+
4. Extracts tasks, files, next steps from PM summaries
|
|
124
|
+
5. Displays comprehensive resume context
|
|
125
|
+
|
|
126
|
+
**Use Cases**:
|
|
127
|
+
- Resume work after context threshold pause
|
|
128
|
+
- Review what was accomplished in previous session
|
|
129
|
+
- Understand why session stopped (max_tokens, end_turn, etc.)
|
|
130
|
+
- See exact files and tasks from last session
|
|
131
|
+
|
|
132
|
+
**Difference from `context`**:
|
|
133
|
+
- **resume**: Reads actual stop event logs (what PM logged)
|
|
134
|
+
- **context**: Analyzes git commits (what was committed)
|
|
92
135
|
|
|
93
136
|
### `/mpm-init catchup` (Simple Git History)
|
|
94
137
|
```bash
|
|
@@ -225,6 +268,66 @@ This provides intelligent analysis including:
|
|
|
225
268
|
|
|
226
269
|
The old `resume` command redirects to `context` with a deprecation warning.
|
|
227
270
|
|
|
271
|
+
### Resume from Stop Event Logs
|
|
272
|
+
|
|
273
|
+
Display context from previous sessions using stop event logs:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
/mpm-init resume # Show latest session
|
|
277
|
+
/mpm-init resume --list # List all available sessions
|
|
278
|
+
/mpm-init resume --session-id abc123 # Resume specific session
|
|
279
|
+
/mpm-init resume --last 10 # Show last 10 sessions
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Shows comprehensive context including:
|
|
283
|
+
- What was being worked on
|
|
284
|
+
- Tasks completed (from PM tracking)
|
|
285
|
+
- Files modified
|
|
286
|
+
- Next steps recommended
|
|
287
|
+
- Stop reason (context limit, completion, etc.)
|
|
288
|
+
- Token usage
|
|
289
|
+
- Time elapsed since session
|
|
290
|
+
|
|
291
|
+
**Example Output:**
|
|
292
|
+
```
|
|
293
|
+
================================================================================
|
|
294
|
+
📋 Resume Context - Session from 2 hours ago
|
|
295
|
+
================================================================================
|
|
296
|
+
|
|
297
|
+
Session ID: 20251104_143000
|
|
298
|
+
Ended: 2024-11-04 14:30 (2 hours ago)
|
|
299
|
+
Stop Reason: Context threshold reached (70%)
|
|
300
|
+
Token Usage: 140,000 / 200,000 (70%)
|
|
301
|
+
|
|
302
|
+
Working on:
|
|
303
|
+
"Implementing auto-pause and resume functionality"
|
|
304
|
+
|
|
305
|
+
✅ Completed:
|
|
306
|
+
• Researched stop event logging system
|
|
307
|
+
• Found response logs in .claude-mpm/responses/
|
|
308
|
+
• Identified two-tier resume strategy
|
|
309
|
+
|
|
310
|
+
📝 Files Modified:
|
|
311
|
+
• src/claude_mpm/services/cli/resume_service.py (new)
|
|
312
|
+
• src/claude_mpm/cli/commands/mpm_init.py (updated)
|
|
313
|
+
|
|
314
|
+
🎯 Next Steps:
|
|
315
|
+
• Implement ResumeService class
|
|
316
|
+
• Add resume subcommand to mpm-init
|
|
317
|
+
• Test with real response logs
|
|
318
|
+
|
|
319
|
+
Git Context:
|
|
320
|
+
Branch: main
|
|
321
|
+
Working Directory: /Users/masa/Projects/claude-mpm
|
|
322
|
+
================================================================================
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Use Cases:**
|
|
326
|
+
- Resume after hitting context limit
|
|
327
|
+
- Review what was accomplished in last session
|
|
328
|
+
- See exact next steps recommended by PM
|
|
329
|
+
- Understand why session stopped
|
|
330
|
+
|
|
228
331
|
### Quick Git History (Catchup)
|
|
229
332
|
|
|
230
333
|
Display recent commit history without analysis:
|
|
@@ -388,9 +491,12 @@ The command delegates to the Agentic Coder Optimizer agent which:
|
|
|
388
491
|
## Notes
|
|
389
492
|
|
|
390
493
|
- **Quick Update vs Full Update**: Use `/mpm-init update` for fast activity-based updates (30 days), or `/mpm-init --update` for comprehensive doc refresh
|
|
391
|
-
- **
|
|
392
|
-
-
|
|
393
|
-
-
|
|
494
|
+
- **Resume Strategies**:
|
|
495
|
+
- **`/mpm-init resume`**: Read stop event logs (what PM tracked in last session)
|
|
496
|
+
- **`/mpm-init context`**: Analyze git history (intelligent work stream analysis via Research)
|
|
497
|
+
- **`/mpm-init catchup`**: Quick commit history display (no analysis)
|
|
498
|
+
- **Stop Event Logs**: Response logs in `.claude-mpm/responses/` contain PM summaries with tasks, files, and next steps
|
|
499
|
+
- **Two-Tier Resume**: Prefers structured resume logs (`.claude-mpm/resume-logs/`), falls back to response logs
|
|
394
500
|
- **Smart Mode**: Automatically detects existing CLAUDE.md and offers update vs recreate
|
|
395
501
|
- **Safe Updates**: Previous versions always archived before updating
|
|
396
502
|
- **Custom Content**: Your project-specific sections are preserved by default
|
claude_mpm/hooks/__init__.py
CHANGED
|
@@ -12,6 +12,11 @@ from .failure_learning import (
|
|
|
12
12
|
from .kuzu_enrichment_hook import KuzuEnrichmentHook, get_kuzu_enrichment_hook
|
|
13
13
|
from .kuzu_memory_hook import KuzuMemoryHook, get_kuzu_memory_hook
|
|
14
14
|
from .kuzu_response_hook import KuzuResponseHook, get_kuzu_response_hook
|
|
15
|
+
from .session_resume_hook import (
|
|
16
|
+
SessionResumeStartupHook,
|
|
17
|
+
get_session_resume_hook,
|
|
18
|
+
trigger_session_resume_check,
|
|
19
|
+
)
|
|
15
20
|
|
|
16
21
|
__all__ = [
|
|
17
22
|
"BaseHook",
|
|
@@ -24,10 +29,13 @@ __all__ = [
|
|
|
24
29
|
"KuzuMemoryHook",
|
|
25
30
|
"KuzuResponseHook",
|
|
26
31
|
"LearningExtractionHook",
|
|
32
|
+
"SessionResumeStartupHook",
|
|
27
33
|
"get_failure_detection_hook",
|
|
28
34
|
"get_fix_detection_hook",
|
|
29
35
|
"get_kuzu_enrichment_hook",
|
|
30
36
|
"get_kuzu_memory_hook",
|
|
31
37
|
"get_kuzu_response_hook",
|
|
32
38
|
"get_learning_extraction_hook",
|
|
39
|
+
"get_session_resume_hook",
|
|
40
|
+
"trigger_session_resume_check",
|
|
33
41
|
]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Session Resume Startup Hook.
|
|
2
|
+
|
|
3
|
+
WHY: This hook automatically checks for paused sessions on PM startup and displays
|
|
4
|
+
resume context to help users continue their work seamlessly.
|
|
5
|
+
|
|
6
|
+
DESIGN DECISIONS:
|
|
7
|
+
- Runs automatically on PM startup
|
|
8
|
+
- Non-blocking: doesn't prevent PM from starting if check fails
|
|
9
|
+
- Displays context to stdout for user visibility
|
|
10
|
+
- Integrates with existing session pause/resume infrastructure
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, Optional
|
|
15
|
+
|
|
16
|
+
from claude_mpm.core.logger import get_logger
|
|
17
|
+
from claude_mpm.services.cli.session_resume_helper import SessionResumeHelper
|
|
18
|
+
|
|
19
|
+
logger = get_logger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SessionResumeStartupHook:
|
|
23
|
+
"""Hook for automatic session resume detection on PM startup."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, project_path: Optional[Path] = None):
|
|
26
|
+
"""Initialize the session resume hook.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
project_path: Project root path (default: current directory)
|
|
30
|
+
"""
|
|
31
|
+
self.project_path = project_path or Path.cwd()
|
|
32
|
+
self.resume_helper = SessionResumeHelper(self.project_path)
|
|
33
|
+
self._session_displayed = False
|
|
34
|
+
|
|
35
|
+
def on_pm_startup(self) -> Optional[Dict[str, Any]]:
|
|
36
|
+
"""Execute on PM startup to check for paused sessions.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Session data if paused session found, None otherwise
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
# Check if we already displayed a session in this process
|
|
43
|
+
if self._session_displayed:
|
|
44
|
+
logger.debug("Session already displayed, skipping")
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
# Check for paused sessions
|
|
48
|
+
session_data = self.resume_helper.check_and_display_resume_prompt()
|
|
49
|
+
|
|
50
|
+
if session_data:
|
|
51
|
+
self._session_displayed = True
|
|
52
|
+
logger.info("Paused session context displayed to user")
|
|
53
|
+
|
|
54
|
+
return session_data
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error(f"Failed to check for paused sessions: {e}", exc_info=True)
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
def get_session_count(self) -> int:
|
|
61
|
+
"""Get count of paused sessions.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Number of paused sessions
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
return self.resume_helper.get_session_count()
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Failed to get session count: {e}")
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
def clear_displayed_session(self, session_data: Dict[str, Any]) -> bool:
|
|
73
|
+
"""Clear a session after it has been displayed and user has acknowledged.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
session_data: Session data to clear
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
True if successfully cleared, False otherwise
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
return self.resume_helper.clear_session(session_data)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(f"Failed to clear session: {e}")
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# Global hook instance
|
|
89
|
+
_session_resume_hook: Optional[SessionResumeStartupHook] = None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_session_resume_hook(
|
|
93
|
+
project_path: Optional[Path] = None,
|
|
94
|
+
) -> SessionResumeStartupHook:
|
|
95
|
+
"""Get or create the global session resume hook instance.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
project_path: Project root path (default: current directory)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
SessionResumeStartupHook instance
|
|
102
|
+
"""
|
|
103
|
+
global _session_resume_hook
|
|
104
|
+
|
|
105
|
+
if _session_resume_hook is None:
|
|
106
|
+
_session_resume_hook = SessionResumeStartupHook(project_path)
|
|
107
|
+
logger.debug("Created session resume hook instance")
|
|
108
|
+
|
|
109
|
+
return _session_resume_hook
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def trigger_session_resume_check() -> Optional[Dict[str, Any]]:
|
|
113
|
+
"""Trigger a session resume check (convenience function).
|
|
114
|
+
|
|
115
|
+
This is the main entry point for PM startup integration.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Session data if found, None otherwise
|
|
119
|
+
"""
|
|
120
|
+
hook = get_session_resume_hook()
|
|
121
|
+
return hook.on_pm_startup()
|