claude-mpm 4.11.0__py3-none-any.whl → 4.11.1__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 +216 -162
- claude_mpm/cli/commands/mpm_init_handler.py +14 -25
- claude_mpm/cli/parsers/mpm_init_parser.py +32 -31
- claude_mpm/commands/mpm-init.md +129 -78
- claude_mpm/utils/git_analyzer.py +305 -0
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/METADATA +1 -1
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/RECORD +12 -13
- claude_mpm/cli/commands/session_pause_manager.py +0 -389
- claude_mpm/cli/commands/session_resume_manager.py +0 -523
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/WHEEL +0 -0
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.11.0.dist-info → claude_mpm-4.11.1.dist-info}/top_level.txt +0 -0
@@ -31,8 +31,7 @@ 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
|
35
|
-
" claude-mpm mpm-init resume # Resume latest session\n"
|
34
|
+
" claude-mpm mpm-init --catchup # Show recent git history for context\n"
|
36
35
|
" claude-mpm mpm-init --review # Review project state without changes\n"
|
37
36
|
" claude-mpm mpm-init --update # Update existing CLAUDE.md\n"
|
38
37
|
" claude-mpm mpm-init --quick-update # Quick update based on recent git activity\n"
|
@@ -207,55 +206,57 @@ def add_mpm_init_subparser(subparsers: Any) -> None:
|
|
207
206
|
help="Path to project directory (default: current directory)",
|
208
207
|
)
|
209
208
|
|
210
|
-
# Add subparsers for
|
209
|
+
# Add subparsers for context commands
|
211
210
|
subcommands = mpm_init_parser.add_subparsers(
|
212
211
|
dest="subcommand",
|
213
|
-
title="
|
214
|
-
description="Commands for managing
|
212
|
+
title="context management",
|
213
|
+
description="Commands for managing project context",
|
215
214
|
)
|
216
215
|
|
217
|
-
#
|
218
|
-
|
219
|
-
"
|
220
|
-
help="
|
221
|
-
description="
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
"-
|
216
|
+
# Context subcommand (primary name)
|
217
|
+
context_parser = subcommands.add_parser(
|
218
|
+
"context",
|
219
|
+
help="Provide intelligent context for resuming work",
|
220
|
+
description="Analyze git history to provide context for resuming work",
|
221
|
+
epilog="Note: 'resume' is deprecated, use 'context' instead",
|
222
|
+
)
|
223
|
+
context_parser.add_argument(
|
224
|
+
"--session-id",
|
225
|
+
"-i",
|
226
226
|
type=str,
|
227
|
-
help="
|
228
|
-
)
|
229
|
-
pause_parser.add_argument(
|
230
|
-
"--accomplishment",
|
231
|
-
"-a",
|
232
|
-
action="append",
|
233
|
-
help="Accomplishment from this session (can be used multiple times)",
|
227
|
+
help="Unused (for compatibility) - will be removed in future version",
|
234
228
|
)
|
235
|
-
|
236
|
-
"--
|
237
|
-
|
238
|
-
|
239
|
-
help="
|
229
|
+
context_parser.add_argument(
|
230
|
+
"--days",
|
231
|
+
type=int,
|
232
|
+
default=7,
|
233
|
+
help="Number of days of git history to analyze (default: 7)",
|
240
234
|
)
|
241
|
-
|
235
|
+
context_parser.add_argument(
|
242
236
|
"project_path",
|
243
237
|
nargs="?",
|
244
238
|
default=".",
|
245
239
|
help="Path to project directory (default: current directory)",
|
246
240
|
)
|
247
241
|
|
248
|
-
# Resume subcommand
|
242
|
+
# Resume subcommand (deprecated alias for backward compatibility)
|
249
243
|
resume_parser = subcommands.add_parser(
|
250
244
|
"resume",
|
251
|
-
help="
|
252
|
-
description="
|
245
|
+
help="[DEPRECATED] Use 'context' instead",
|
246
|
+
description="[DEPRECATED] This command is deprecated. Use 'context' instead.\n\n"
|
247
|
+
"Analyze git history to provide context for resuming work",
|
253
248
|
)
|
254
249
|
resume_parser.add_argument(
|
255
250
|
"--session-id",
|
256
251
|
"-i",
|
257
252
|
type=str,
|
258
|
-
help="
|
253
|
+
help="Unused (for compatibility) - will be removed in future version",
|
254
|
+
)
|
255
|
+
resume_parser.add_argument(
|
256
|
+
"--days",
|
257
|
+
type=int,
|
258
|
+
default=7,
|
259
|
+
help="Number of days of git history to analyze (default: 7)",
|
259
260
|
)
|
260
261
|
resume_parser.add_argument(
|
261
262
|
"project_path",
|
claude_mpm/commands/mpm-init.md
CHANGED
@@ -7,10 +7,9 @@ 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
|
11
|
-
/mpm-init
|
12
|
-
/mpm-init
|
13
|
-
/mpm-init resume --list # List all paused sessions
|
10
|
+
/mpm-init context # Intelligent context analysis from git history
|
11
|
+
/mpm-init context --days 14 # Analyze last 14 days of git history
|
12
|
+
/mpm-init catchup # Quick commit history display (no analysis)
|
14
13
|
/mpm-init --review # Review project state without changes
|
15
14
|
/mpm-init --update # Full update of existing CLAUDE.md
|
16
15
|
/mpm-init --organize # Organize project structure
|
@@ -21,7 +20,11 @@ Initialize or intelligently update your project for optimal use with Claude Code
|
|
21
20
|
|
22
21
|
## Description
|
23
22
|
|
24
|
-
This command
|
23
|
+
This command has two primary modes:
|
24
|
+
- **Project initialization/updates**: Delegates to the Agentic Coder Optimizer agent for documentation, tooling, and workflow setup
|
25
|
+
- **Context analysis** (context/catchup): Provides intelligent project context from git history for resuming work
|
26
|
+
|
27
|
+
**Note**: The `resume` subcommand is deprecated. Use `context` instead. The `resume` command still works for backward compatibility but will be removed in a future version.
|
25
28
|
|
26
29
|
**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.
|
27
30
|
|
@@ -58,6 +61,46 @@ This command delegates to the Agentic Coder Optimizer agent to establish clear,
|
|
58
61
|
- `--no-preserve-custom`: Don't preserve custom sections
|
59
62
|
- `--skip-archive`: Skip archiving existing files before updating
|
60
63
|
|
64
|
+
## Context Analysis
|
65
|
+
|
66
|
+
**Purpose**: Provide intelligent project context for resuming work by analyzing git history.
|
67
|
+
|
68
|
+
### Commands
|
69
|
+
|
70
|
+
#### `/mpm-init context` (Primary)
|
71
|
+
```bash
|
72
|
+
/mpm-init context # Analyze last 7 days of git history
|
73
|
+
/mpm-init context --days 14 # Analyze last 14 days
|
74
|
+
```
|
75
|
+
|
76
|
+
Analyzes recent git commits to identify:
|
77
|
+
- **Active work streams**: What was being worked on (themes from commit patterns)
|
78
|
+
- **Intent and motivation**: Why this work matters (from commit messages)
|
79
|
+
- **Risks and blockers**: What needs attention (stalled work, conflicts, anti-patterns)
|
80
|
+
- **Recommended next actions**: What to work on next (logical continuations)
|
81
|
+
|
82
|
+
**How it works**:
|
83
|
+
1. Parses git history (default: last 7 days)
|
84
|
+
2. PM delegates to Research agent with structured prompt
|
85
|
+
3. Research analyzes work streams, intent, risks, recommendations
|
86
|
+
4. PM presents intelligent summary for seamless work resumption
|
87
|
+
|
88
|
+
**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
|
+
|
90
|
+
#### `/mpm-init resume` [DEPRECATED]
|
91
|
+
Alias for `context`. Use `context` instead.
|
92
|
+
|
93
|
+
### `/mpm-init catchup` (Simple Git History)
|
94
|
+
```bash
|
95
|
+
/mpm-init catchup
|
96
|
+
```
|
97
|
+
|
98
|
+
Quick display of last 25 commits across all branches. No analysis - just raw git log output with authors and dates. Use this for quick "what happened recently?" checks.
|
99
|
+
|
100
|
+
**Distinction**:
|
101
|
+
- **catchup**: Quick commit history (instant, no analysis)
|
102
|
+
- **context**: Intelligent work resumption (10-30s, deep analysis)
|
103
|
+
|
61
104
|
## What This Command Does
|
62
105
|
|
63
106
|
### Auto-Detection (NEW)
|
@@ -150,92 +193,52 @@ Fast update based on recent 30-day git activity. Generates activity report and u
|
|
150
193
|
|
151
194
|
**Note**: Typing `/mpm-init update` executes `claude-mpm mpm-init --quick-update` automatically.
|
152
195
|
|
153
|
-
###
|
196
|
+
### Context Analysis (Intelligent Resumption)
|
154
197
|
|
155
|
-
|
198
|
+
Get intelligent context for resuming work based on git history analysis:
|
156
199
|
|
200
|
+
**Standard Context Analysis:**
|
157
201
|
```bash
|
158
|
-
/mpm-init
|
202
|
+
/mpm-init context # Analyze last 7 days (default)
|
203
|
+
/mpm-init context --days 14 # Analyze last 14 days
|
204
|
+
/mpm-init context --days 30 # Analyze last 30 days
|
159
205
|
```
|
160
206
|
|
161
|
-
This
|
162
|
-
-
|
163
|
-
-
|
164
|
-
-
|
165
|
-
-
|
166
|
-
- PM recommendations based on commit patterns
|
167
|
-
|
168
|
-
Useful for understanding recent development activity and getting PM up to speed on project changes.
|
169
|
-
|
170
|
-
### Session Management (Pause/Resume)
|
207
|
+
This provides intelligent analysis including:
|
208
|
+
- **Work stream identification** from commit patterns
|
209
|
+
- **Intent analysis** (why work was done)
|
210
|
+
- **Risk detection** (stalled work, conflicts, etc.)
|
211
|
+
- **Recommended next actions** for seamless continuation
|
171
212
|
|
172
|
-
|
213
|
+
**How it works:**
|
214
|
+
1. Parses git history (7 days default)
|
215
|
+
2. PM delegates to Research agent with structured prompt
|
216
|
+
3. Research agent provides deep analysis
|
217
|
+
4. PM presents intelligent summary
|
173
218
|
|
174
|
-
**
|
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
|
219
|
+
**NOT session state**: This reconstructs context from git history, not saved conversation state.
|
185
220
|
|
186
|
-
**
|
221
|
+
**Backward Compatibility:**
|
187
222
|
```bash
|
188
|
-
/mpm-init resume
|
223
|
+
/mpm-init resume # Still works but deprecated
|
189
224
|
```
|
190
225
|
|
191
|
-
|
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
|
226
|
+
The old `resume` command redirects to `context` with a deprecation warning.
|
196
227
|
|
197
|
-
|
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
|
228
|
+
### Quick Git History (Catchup)
|
202
229
|
|
203
|
-
|
204
|
-
- `--session-id TEXT`: Resume specific session by ID
|
205
|
-
- `--list`: List all available paused sessions
|
230
|
+
Display recent commit history without analysis:
|
206
231
|
|
207
|
-
**Example Usage:**
|
208
232
|
```bash
|
209
|
-
|
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
|
233
|
+
/mpm-init catchup
|
225
234
|
```
|
226
235
|
|
227
|
-
|
228
|
-
-
|
229
|
-
-
|
230
|
-
-
|
231
|
-
- Automatic git commit creation (unless `--no-commit`)
|
236
|
+
Shows:
|
237
|
+
- Last 25 commits from all branches
|
238
|
+
- Author attribution and timestamps
|
239
|
+
- Contributor activity summary
|
232
240
|
|
233
|
-
|
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
|
241
|
+
Use this for quick "what happened recently?" checks. For intelligent analysis, use `context` instead.
|
239
242
|
|
240
243
|
### Review Project State
|
241
244
|
```bash
|
@@ -284,6 +287,49 @@ Quick initialization without code analysis.
|
|
284
287
|
|
285
288
|
This command routes between different modes:
|
286
289
|
|
290
|
+
### Context Analysis Commands
|
291
|
+
|
292
|
+
**IMPORTANT**: Context analysis commands (`/mpm-init context`, `/mpm-init catchup`) have distinct behaviors:
|
293
|
+
|
294
|
+
**`/mpm-init context` - Delegates to PM**:
|
295
|
+
```bash
|
296
|
+
claude-mpm mpm-init context --days 7
|
297
|
+
```
|
298
|
+
|
299
|
+
This command delegates work to the PM framework:
|
300
|
+
1. Parses git history (7 days default)
|
301
|
+
2. PM constructs structured Research delegation prompt
|
302
|
+
3. PM presents prompt for Research agent to analyze
|
303
|
+
4. Research identifies work streams, intent, risks, recommendations
|
304
|
+
5. PM synthesizes for user
|
305
|
+
|
306
|
+
This is intelligent analysis requiring Research agent expertise.
|
307
|
+
|
308
|
+
**How the PM delegates to Research:**
|
309
|
+
The PM creates a delegation prompt that asks Research to analyze:
|
310
|
+
- **Work Stream Identification**: Groups related commits into themes
|
311
|
+
- **Intent Analysis**: Infers why work was done from commit messages
|
312
|
+
- **Risk Detection**: Identifies stalled work, conflicts, and blockers
|
313
|
+
- **Recommended Actions**: Suggests logical next steps for continuation
|
314
|
+
|
315
|
+
**`/mpm-init catchup` - Direct CLI execution**:
|
316
|
+
```bash
|
317
|
+
claude-mpm mpm-init catchup
|
318
|
+
```
|
319
|
+
|
320
|
+
This executes directly via CLI without agent delegation:
|
321
|
+
- Displays last 25 commits from all branches
|
322
|
+
- Shows authors, dates, commit messages
|
323
|
+
- Instant output (no analysis)
|
324
|
+
|
325
|
+
This is a simple git log display utility.
|
326
|
+
|
327
|
+
---
|
328
|
+
|
329
|
+
### Project Initialization/Update Commands
|
330
|
+
|
331
|
+
**IMPORTANT**: Standard initialization and update commands delegate to the Agentic Coder Optimizer agent.
|
332
|
+
|
287
333
|
**Quick Update Mode** (`/mpm-init update`):
|
288
334
|
```bash
|
289
335
|
claude-mpm mpm-init --quick-update
|
@@ -342,15 +388,20 @@ The command delegates to the Agentic Coder Optimizer agent which:
|
|
342
388
|
## Notes
|
343
389
|
|
344
390
|
- **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
|
-
- **
|
391
|
+
- **Context Analysis**: Use `/mpm-init context` to analyze git history and get intelligent resumption context from Research agent
|
392
|
+
- **Quick History**: Use `/mpm-init catchup` for instant commit history display without analysis
|
393
|
+
- **Deprecation Notice**: The `resume` command is deprecated. Use `context` instead. The old command still works but shows a warning.
|
346
394
|
- **Smart Mode**: Automatically detects existing CLAUDE.md and offers update vs recreate
|
347
395
|
- **Safe Updates**: Previous versions always archived before updating
|
348
396
|
- **Custom Content**: Your project-specific sections are preserved by default
|
349
|
-
- **Git Integration**: Analyzes recent commits to understand project evolution
|
350
|
-
- **
|
351
|
-
- **Change Detection**: Resume automatically detects and reports changes since pause
|
397
|
+
- **Git Integration**: Analyzes recent commits to understand project evolution and provide work context
|
398
|
+
- **Backward Compatibility**: All existing `resume` commands redirect to `context` with deprecation warning
|
352
399
|
- **Argument Processing**: The slash command processes the `update` argument and routes to `--quick-update` flag
|
353
|
-
-
|
400
|
+
- **Agent Delegation**:
|
401
|
+
- Project initialization and updates use the Agentic Coder Optimizer agent
|
402
|
+
- Context analysis (`context`) delegates to PM, who coordinates with Research agent
|
403
|
+
- Simple git history (`catchup`) executes directly via CLI without agent delegation
|
404
|
+
- **NOT Session State**: Context analysis reconstructs project understanding from git history, not saved conversation state
|
354
405
|
- AST analysis is enabled by default for comprehensive documentation
|
355
406
|
- Priority rankings help AI agents focus on critical instructions first
|
356
407
|
- The holistic review ensures documentation quality and completeness
|
@@ -0,0 +1,305 @@
|
|
1
|
+
"""
|
2
|
+
Git history analysis utilities for intelligent context reconstruction.
|
3
|
+
|
4
|
+
This module provides utilities to analyze git repository activity for
|
5
|
+
context reconstruction and project intelligence. Extracted from the
|
6
|
+
session management system to support git-based context approaches.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import subprocess
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Any, Dict, List, Optional
|
12
|
+
|
13
|
+
from claude_mpm.core.logging_utils import get_logger
|
14
|
+
|
15
|
+
logger = get_logger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def analyze_recent_activity(
|
19
|
+
repo_path: str = ".", days: int = 7, max_commits: int = 50
|
20
|
+
) -> Dict[str, Any]:
|
21
|
+
"""
|
22
|
+
Analyze recent git activity for context reconstruction.
|
23
|
+
|
24
|
+
This function analyzes git history to provide comprehensive context about
|
25
|
+
recent project activity including commits, contributors, file changes,
|
26
|
+
and branch activity.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
repo_path: Path to the git repository (default: current directory)
|
30
|
+
days: Number of days to look back (default: 7)
|
31
|
+
max_commits: Maximum number of commits to analyze (default: 50)
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
Dict containing:
|
35
|
+
- time_range: str - Description of analysis period
|
36
|
+
- commits: List[Dict] - Recent commits with metadata
|
37
|
+
- branches: List[str] - Active branches in the repository
|
38
|
+
- contributors: Dict[str, Dict] - Contributor statistics
|
39
|
+
- file_changes: Dict[str, Dict] - File change statistics
|
40
|
+
- has_activity: bool - Whether any activity was found
|
41
|
+
- error: Optional[str] - Error message if analysis failed
|
42
|
+
"""
|
43
|
+
repo_path_obj = Path(repo_path)
|
44
|
+
analysis = {
|
45
|
+
"time_range": f"last {days} days",
|
46
|
+
"commits": [],
|
47
|
+
"branches": [],
|
48
|
+
"contributors": {},
|
49
|
+
"file_changes": {},
|
50
|
+
"has_activity": False,
|
51
|
+
}
|
52
|
+
|
53
|
+
try:
|
54
|
+
# Get all branches
|
55
|
+
result = subprocess.run(
|
56
|
+
["git", "branch", "-a"],
|
57
|
+
cwd=str(repo_path_obj),
|
58
|
+
capture_output=True,
|
59
|
+
text=True,
|
60
|
+
check=True,
|
61
|
+
)
|
62
|
+
branches = [
|
63
|
+
line.strip().replace("* ", "").replace("remotes/origin/", "")
|
64
|
+
for line in result.stdout.strip().split("\n")
|
65
|
+
if line.strip()
|
66
|
+
]
|
67
|
+
analysis["branches"] = list(set(branches))
|
68
|
+
|
69
|
+
# Get recent commits from all branches
|
70
|
+
result = subprocess.run(
|
71
|
+
[
|
72
|
+
"git",
|
73
|
+
"log",
|
74
|
+
"--all",
|
75
|
+
f"--since={days} days ago",
|
76
|
+
f"--max-count={max_commits}",
|
77
|
+
"--format=%h|%an|%ae|%ai|%s",
|
78
|
+
"--name-status",
|
79
|
+
],
|
80
|
+
cwd=str(repo_path_obj),
|
81
|
+
capture_output=True,
|
82
|
+
text=True,
|
83
|
+
check=True,
|
84
|
+
)
|
85
|
+
|
86
|
+
if not result.stdout.strip():
|
87
|
+
return analysis
|
88
|
+
|
89
|
+
analysis["has_activity"] = True
|
90
|
+
|
91
|
+
# Parse commit log
|
92
|
+
commits = []
|
93
|
+
current_commit = None
|
94
|
+
file_changes = {}
|
95
|
+
|
96
|
+
for line in result.stdout.strip().split("\n"):
|
97
|
+
if not line.strip():
|
98
|
+
continue
|
99
|
+
|
100
|
+
if "|" in line:
|
101
|
+
# Commit line
|
102
|
+
if current_commit:
|
103
|
+
commits.append(current_commit)
|
104
|
+
|
105
|
+
parts = line.split("|", 4)
|
106
|
+
if len(parts) == 5:
|
107
|
+
sha, author, email, timestamp, message = parts
|
108
|
+
current_commit = {
|
109
|
+
"sha": sha,
|
110
|
+
"author": author,
|
111
|
+
"email": email,
|
112
|
+
"timestamp": timestamp,
|
113
|
+
"message": message,
|
114
|
+
"files": [],
|
115
|
+
}
|
116
|
+
|
117
|
+
# Track contributors
|
118
|
+
if author not in analysis["contributors"]:
|
119
|
+
analysis["contributors"][author] = {
|
120
|
+
"email": email,
|
121
|
+
"commits": 0,
|
122
|
+
}
|
123
|
+
analysis["contributors"][author]["commits"] += 1
|
124
|
+
# File change line
|
125
|
+
elif current_commit and "\t" in line:
|
126
|
+
parts = line.split("\t", 1)
|
127
|
+
if len(parts) == 2:
|
128
|
+
status, file_path = parts
|
129
|
+
current_commit["files"].append(
|
130
|
+
{"status": status, "path": file_path}
|
131
|
+
)
|
132
|
+
|
133
|
+
# Track file changes
|
134
|
+
if file_path not in file_changes:
|
135
|
+
file_changes[file_path] = {
|
136
|
+
"modifications": 0,
|
137
|
+
"contributors": set(),
|
138
|
+
}
|
139
|
+
file_changes[file_path]["modifications"] += 1
|
140
|
+
file_changes[file_path]["contributors"].add(
|
141
|
+
current_commit["author"]
|
142
|
+
)
|
143
|
+
|
144
|
+
# Add last commit
|
145
|
+
if current_commit:
|
146
|
+
commits.append(current_commit)
|
147
|
+
|
148
|
+
analysis["commits"] = commits
|
149
|
+
|
150
|
+
# Convert file changes to serializable format
|
151
|
+
analysis["file_changes"] = {
|
152
|
+
path: {
|
153
|
+
"modifications": info["modifications"],
|
154
|
+
"contributors": list(info["contributors"]),
|
155
|
+
}
|
156
|
+
for path, info in file_changes.items()
|
157
|
+
}
|
158
|
+
|
159
|
+
except subprocess.CalledProcessError as e:
|
160
|
+
logger.warning(f"Git command failed: {e}")
|
161
|
+
analysis["error"] = f"Git command failed: {e}"
|
162
|
+
except Exception as e:
|
163
|
+
logger.warning(f"Could not analyze recent activity: {e}")
|
164
|
+
analysis["error"] = str(e)
|
165
|
+
|
166
|
+
return analysis
|
167
|
+
|
168
|
+
|
169
|
+
def get_current_branch(repo_path: str = ".") -> Optional[str]:
|
170
|
+
"""
|
171
|
+
Get the current git branch name.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
repo_path: Path to the git repository (default: current directory)
|
175
|
+
|
176
|
+
Returns:
|
177
|
+
Current branch name or None if not in a git repository
|
178
|
+
"""
|
179
|
+
try:
|
180
|
+
result = subprocess.run(
|
181
|
+
["git", "branch", "--show-current"],
|
182
|
+
cwd=str(Path(repo_path)),
|
183
|
+
capture_output=True,
|
184
|
+
text=True,
|
185
|
+
check=True,
|
186
|
+
)
|
187
|
+
return result.stdout.strip()
|
188
|
+
except Exception:
|
189
|
+
return None
|
190
|
+
|
191
|
+
|
192
|
+
def get_commits_since(since_sha: str, repo_path: str = ".") -> List[Dict[str, str]]:
|
193
|
+
"""
|
194
|
+
Get commits since a specific SHA.
|
195
|
+
|
196
|
+
Args:
|
197
|
+
since_sha: The SHA to get commits after
|
198
|
+
repo_path: Path to the git repository (default: current directory)
|
199
|
+
|
200
|
+
Returns:
|
201
|
+
List of commit dicts with sha, author, timestamp, and message
|
202
|
+
"""
|
203
|
+
try:
|
204
|
+
result = subprocess.run(
|
205
|
+
["git", "log", f"{since_sha}..HEAD", "--format=%h|%an|%ai|%s"],
|
206
|
+
cwd=str(Path(repo_path)),
|
207
|
+
capture_output=True,
|
208
|
+
text=True,
|
209
|
+
check=True,
|
210
|
+
)
|
211
|
+
|
212
|
+
commits = []
|
213
|
+
for line in result.stdout.strip().split("\n"):
|
214
|
+
if not line:
|
215
|
+
continue
|
216
|
+
parts = line.split("|", 3)
|
217
|
+
if len(parts) == 4:
|
218
|
+
sha, author, timestamp, message = parts
|
219
|
+
commits.append(
|
220
|
+
{
|
221
|
+
"sha": sha,
|
222
|
+
"author": author,
|
223
|
+
"timestamp": timestamp,
|
224
|
+
"message": message,
|
225
|
+
}
|
226
|
+
)
|
227
|
+
|
228
|
+
return commits
|
229
|
+
|
230
|
+
except Exception as e:
|
231
|
+
logger.warning(f"Could not get commits: {e}")
|
232
|
+
return []
|
233
|
+
|
234
|
+
|
235
|
+
def get_current_status(repo_path: str = ".") -> Dict[str, Any]:
|
236
|
+
"""
|
237
|
+
Get current git status.
|
238
|
+
|
239
|
+
Args:
|
240
|
+
repo_path: Path to the git repository (default: current directory)
|
241
|
+
|
242
|
+
Returns:
|
243
|
+
Dict with:
|
244
|
+
- clean: bool - Whether working directory is clean
|
245
|
+
- modified_files: List[str] - Modified files
|
246
|
+
- untracked_files: List[str] - Untracked files
|
247
|
+
"""
|
248
|
+
status = {"clean": True, "modified_files": [], "untracked_files": []}
|
249
|
+
|
250
|
+
try:
|
251
|
+
result = subprocess.run(
|
252
|
+
["git", "status", "--porcelain"],
|
253
|
+
cwd=str(Path(repo_path)),
|
254
|
+
capture_output=True,
|
255
|
+
text=True,
|
256
|
+
check=True,
|
257
|
+
)
|
258
|
+
|
259
|
+
modified_files = []
|
260
|
+
untracked_files = []
|
261
|
+
|
262
|
+
for line in result.stdout.strip().split("\n"):
|
263
|
+
if not line:
|
264
|
+
continue
|
265
|
+
status_code = line[:2]
|
266
|
+
file_path = line[3:]
|
267
|
+
|
268
|
+
if status_code.startswith("??"):
|
269
|
+
untracked_files.append(file_path)
|
270
|
+
else:
|
271
|
+
modified_files.append(file_path)
|
272
|
+
|
273
|
+
status = {
|
274
|
+
"clean": len(modified_files) == 0 and len(untracked_files) == 0,
|
275
|
+
"modified_files": modified_files,
|
276
|
+
"untracked_files": untracked_files,
|
277
|
+
}
|
278
|
+
|
279
|
+
except Exception as e:
|
280
|
+
logger.warning(f"Could not get status: {e}")
|
281
|
+
|
282
|
+
return status
|
283
|
+
|
284
|
+
|
285
|
+
def is_git_repository(repo_path: str = ".") -> bool:
|
286
|
+
"""
|
287
|
+
Check if the given path is a git repository.
|
288
|
+
|
289
|
+
Args:
|
290
|
+
repo_path: Path to check (default: current directory)
|
291
|
+
|
292
|
+
Returns:
|
293
|
+
True if the path is a git repository, False otherwise
|
294
|
+
"""
|
295
|
+
try:
|
296
|
+
result = subprocess.run(
|
297
|
+
["git", "rev-parse", "--git-dir"],
|
298
|
+
cwd=str(Path(repo_path)),
|
299
|
+
capture_output=True,
|
300
|
+
text=True,
|
301
|
+
check=False,
|
302
|
+
)
|
303
|
+
return result.returncode == 0
|
304
|
+
except Exception:
|
305
|
+
return False
|