claude-mpm 4.11.0__py3-none-any.whl → 4.11.2__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.

@@ -0,0 +1,407 @@
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, min_commits: int = 25
20
+ ) -> Dict[str, Any]:
21
+ """
22
+ Analyze recent git activity for context reconstruction with adaptive time window.
23
+
24
+ Strategy:
25
+ 1. Try to get commits from last {days} days
26
+ 2. If fewer than {min_commits} found, expand window to get {min_commits}
27
+ 3. Never exceed {max_commits} total
28
+
29
+ This ensures meaningful context for both high-velocity and low-velocity projects.
30
+
31
+ Args:
32
+ repo_path: Path to the git repository (default: current directory)
33
+ days: Number of days to look back initially (default: 7)
34
+ max_commits: Maximum number of commits to analyze (default: 50)
35
+ min_commits: Minimum commits to retrieve, will expand window if needed (default: 25)
36
+
37
+ Returns:
38
+ Dict containing:
39
+ - time_range: str - Description of analysis period
40
+ - commits: List[Dict] - Recent commits with metadata
41
+ - branches: List[str] - Active branches in the repository
42
+ - contributors: Dict[str, Dict] - Contributor statistics
43
+ - file_changes: Dict[str, Dict] - File change statistics
44
+ - has_activity: bool - Whether any activity was found
45
+ - adaptive_mode: bool - Whether time window was expanded
46
+ - actual_time_span: Optional[str] - Actual time span if adaptive mode was used
47
+ - reason: Optional[str] - Explanation for adaptive mode
48
+ - error: Optional[str] - Error message if analysis failed
49
+ """
50
+ repo_path_obj = Path(repo_path)
51
+ analysis = {
52
+ "time_range": f"last {days} days",
53
+ "commits": [],
54
+ "branches": [],
55
+ "contributors": {},
56
+ "file_changes": {},
57
+ "has_activity": False,
58
+ "adaptive_mode": False,
59
+ "min_commits_target": min_commits,
60
+ }
61
+
62
+ try:
63
+ # Get all branches
64
+ result = subprocess.run(
65
+ ["git", "branch", "-a"],
66
+ cwd=str(repo_path_obj),
67
+ capture_output=True,
68
+ text=True,
69
+ check=True,
70
+ )
71
+ branches = [
72
+ line.strip().replace("* ", "").replace("remotes/origin/", "")
73
+ for line in result.stdout.strip().split("\n")
74
+ if line.strip()
75
+ ]
76
+ analysis["branches"] = list(set(branches))
77
+
78
+ # Step 1: Get commits from specified time window
79
+ result = subprocess.run(
80
+ [
81
+ "git",
82
+ "log",
83
+ "--all",
84
+ f"--since={days} days ago",
85
+ f"--max-count={max_commits}",
86
+ "--format=%h|%an|%ae|%ai|%s",
87
+ "--name-status",
88
+ ],
89
+ cwd=str(repo_path_obj),
90
+ capture_output=True,
91
+ text=True,
92
+ check=True,
93
+ )
94
+
95
+ if not result.stdout.strip():
96
+ return analysis
97
+
98
+ analysis["has_activity"] = True
99
+
100
+ # Step 2: Count commit lines (lines with pipe separator) to determine if we need adaptive mode
101
+ temp_commits = []
102
+ for line in result.stdout.strip().split("\n"):
103
+ if "|" in line:
104
+ temp_commits.append(line)
105
+
106
+ # Step 3: Check if we need adaptive mode
107
+ if len(temp_commits) < min_commits:
108
+ logger.info(
109
+ f"Only {len(temp_commits)} commits found in last {days} days, "
110
+ f"expanding to get at least {min_commits} commits"
111
+ )
112
+
113
+ # Get last N commits regardless of date
114
+ expanded_result = subprocess.run(
115
+ [
116
+ "git",
117
+ "log",
118
+ "--all",
119
+ f"-{min_commits}",
120
+ "--format=%h|%an|%ae|%ai|%s",
121
+ "--name-status",
122
+ ],
123
+ cwd=str(repo_path_obj),
124
+ capture_output=True,
125
+ text=True,
126
+ check=True,
127
+ )
128
+
129
+ if expanded_result.stdout.strip():
130
+ result = expanded_result
131
+ analysis["adaptive_mode"] = True
132
+
133
+ # Calculate actual time span
134
+ from datetime import datetime
135
+
136
+ commit_lines = [
137
+ line for line in result.stdout.strip().split("\n") if "|" in line
138
+ ]
139
+ if commit_lines:
140
+ # Parse first and last commit dates
141
+ try:
142
+ first_parts = commit_lines[0].split("|", 4)
143
+ last_parts = commit_lines[-1].split("|", 4)
144
+
145
+ if len(first_parts) >= 4 and len(last_parts) >= 4:
146
+ # Parse ISO format dates (e.g., "2025-10-20 11:38:20 -0700")
147
+ # Extract just the date portion before timezone
148
+ first_date_str = first_parts[3].strip()
149
+ last_date_str = last_parts[3].strip()
150
+
151
+ # Remove timezone info for parsing
152
+ first_date_clean = first_date_str.split(" +")[0].split(
153
+ " -"
154
+ )[0]
155
+ last_date_clean = last_date_str.split(" +")[0].split(" -")[
156
+ 0
157
+ ]
158
+
159
+ # Parse as datetime
160
+ first_date = datetime.fromisoformat(
161
+ first_date_clean.replace(" ", "T")
162
+ )
163
+ last_date = datetime.fromisoformat(
164
+ last_date_clean.replace(" ", "T")
165
+ )
166
+
167
+ days_diff = (first_date - last_date).days
168
+ # Handle the case where days_diff might be 0 or 1
169
+ if days_diff <= 1:
170
+ days_diff = max(days_diff, 1)
171
+
172
+ analysis["actual_time_span"] = str(days_diff)
173
+
174
+ # Provide clear messaging based on the expansion
175
+ if days_diff > days:
176
+ analysis["reason"] = (
177
+ f"Expanded from {days} days to {days_diff} days "
178
+ f"to reach minimum {min_commits} commits for meaningful context"
179
+ )
180
+ else:
181
+ # High-velocity project: reached min_commits without expanding time window
182
+ analysis["reason"] = (
183
+ f"Fetched last {min_commits} commits (spanning {days_diff} days) "
184
+ f"to ensure meaningful context"
185
+ )
186
+ except Exception as e:
187
+ logger.warning(f"Could not calculate actual time span: {e}")
188
+ analysis["actual_time_span"] = f">{days} days"
189
+ analysis["reason"] = (
190
+ f"Expanded beyond {days} days to get minimum {min_commits} commits"
191
+ )
192
+
193
+ # Parse commit log
194
+ commits = []
195
+ current_commit = None
196
+ file_changes = {}
197
+
198
+ for line in result.stdout.strip().split("\n"):
199
+ if not line.strip():
200
+ continue
201
+
202
+ if "|" in line:
203
+ # Commit line
204
+ if current_commit:
205
+ commits.append(current_commit)
206
+
207
+ parts = line.split("|", 4)
208
+ if len(parts) == 5:
209
+ sha, author, email, timestamp, message = parts
210
+ current_commit = {
211
+ "sha": sha,
212
+ "author": author,
213
+ "email": email,
214
+ "timestamp": timestamp,
215
+ "message": message,
216
+ "files": [],
217
+ }
218
+
219
+ # Track contributors
220
+ if author not in analysis["contributors"]:
221
+ analysis["contributors"][author] = {
222
+ "email": email,
223
+ "commits": 0,
224
+ }
225
+ analysis["contributors"][author]["commits"] += 1
226
+ # File change line
227
+ elif current_commit and "\t" in line:
228
+ parts = line.split("\t", 1)
229
+ if len(parts) == 2:
230
+ status, file_path = parts
231
+ current_commit["files"].append(
232
+ {"status": status, "path": file_path}
233
+ )
234
+
235
+ # Track file changes
236
+ if file_path not in file_changes:
237
+ file_changes[file_path] = {
238
+ "modifications": 0,
239
+ "contributors": set(),
240
+ }
241
+ file_changes[file_path]["modifications"] += 1
242
+ file_changes[file_path]["contributors"].add(
243
+ current_commit["author"]
244
+ )
245
+
246
+ # Add last commit
247
+ if current_commit:
248
+ commits.append(current_commit)
249
+
250
+ analysis["commits"] = commits
251
+
252
+ # Convert file changes to serializable format
253
+ analysis["file_changes"] = {
254
+ path: {
255
+ "modifications": info["modifications"],
256
+ "contributors": list(info["contributors"]),
257
+ }
258
+ for path, info in file_changes.items()
259
+ }
260
+
261
+ except subprocess.CalledProcessError as e:
262
+ logger.warning(f"Git command failed: {e}")
263
+ analysis["error"] = f"Git command failed: {e}"
264
+ except Exception as e:
265
+ logger.warning(f"Could not analyze recent activity: {e}")
266
+ analysis["error"] = str(e)
267
+
268
+ return analysis
269
+
270
+
271
+ def get_current_branch(repo_path: str = ".") -> Optional[str]:
272
+ """
273
+ Get the current git branch name.
274
+
275
+ Args:
276
+ repo_path: Path to the git repository (default: current directory)
277
+
278
+ Returns:
279
+ Current branch name or None if not in a git repository
280
+ """
281
+ try:
282
+ result = subprocess.run(
283
+ ["git", "branch", "--show-current"],
284
+ cwd=str(Path(repo_path)),
285
+ capture_output=True,
286
+ text=True,
287
+ check=True,
288
+ )
289
+ return result.stdout.strip()
290
+ except Exception:
291
+ return None
292
+
293
+
294
+ def get_commits_since(since_sha: str, repo_path: str = ".") -> List[Dict[str, str]]:
295
+ """
296
+ Get commits since a specific SHA.
297
+
298
+ Args:
299
+ since_sha: The SHA to get commits after
300
+ repo_path: Path to the git repository (default: current directory)
301
+
302
+ Returns:
303
+ List of commit dicts with sha, author, timestamp, and message
304
+ """
305
+ try:
306
+ result = subprocess.run(
307
+ ["git", "log", f"{since_sha}..HEAD", "--format=%h|%an|%ai|%s"],
308
+ cwd=str(Path(repo_path)),
309
+ capture_output=True,
310
+ text=True,
311
+ check=True,
312
+ )
313
+
314
+ commits = []
315
+ for line in result.stdout.strip().split("\n"):
316
+ if not line:
317
+ continue
318
+ parts = line.split("|", 3)
319
+ if len(parts) == 4:
320
+ sha, author, timestamp, message = parts
321
+ commits.append(
322
+ {
323
+ "sha": sha,
324
+ "author": author,
325
+ "timestamp": timestamp,
326
+ "message": message,
327
+ }
328
+ )
329
+
330
+ return commits
331
+
332
+ except Exception as e:
333
+ logger.warning(f"Could not get commits: {e}")
334
+ return []
335
+
336
+
337
+ def get_current_status(repo_path: str = ".") -> Dict[str, Any]:
338
+ """
339
+ Get current git status.
340
+
341
+ Args:
342
+ repo_path: Path to the git repository (default: current directory)
343
+
344
+ Returns:
345
+ Dict with:
346
+ - clean: bool - Whether working directory is clean
347
+ - modified_files: List[str] - Modified files
348
+ - untracked_files: List[str] - Untracked files
349
+ """
350
+ status = {"clean": True, "modified_files": [], "untracked_files": []}
351
+
352
+ try:
353
+ result = subprocess.run(
354
+ ["git", "status", "--porcelain"],
355
+ cwd=str(Path(repo_path)),
356
+ capture_output=True,
357
+ text=True,
358
+ check=True,
359
+ )
360
+
361
+ modified_files = []
362
+ untracked_files = []
363
+
364
+ for line in result.stdout.strip().split("\n"):
365
+ if not line:
366
+ continue
367
+ status_code = line[:2]
368
+ file_path = line[3:]
369
+
370
+ if status_code.startswith("??"):
371
+ untracked_files.append(file_path)
372
+ else:
373
+ modified_files.append(file_path)
374
+
375
+ status = {
376
+ "clean": len(modified_files) == 0 and len(untracked_files) == 0,
377
+ "modified_files": modified_files,
378
+ "untracked_files": untracked_files,
379
+ }
380
+
381
+ except Exception as e:
382
+ logger.warning(f"Could not get status: {e}")
383
+
384
+ return status
385
+
386
+
387
+ def is_git_repository(repo_path: str = ".") -> bool:
388
+ """
389
+ Check if the given path is a git repository.
390
+
391
+ Args:
392
+ repo_path: Path to check (default: current directory)
393
+
394
+ Returns:
395
+ True if the path is a git repository, False otherwise
396
+ """
397
+ try:
398
+ result = subprocess.run(
399
+ ["git", "rev-parse", "--git-dir"],
400
+ cwd=str(Path(repo_path)),
401
+ capture_output=True,
402
+ text=True,
403
+ check=False,
404
+ )
405
+ return result.returncode == 0
406
+ except Exception:
407
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.11.0
3
+ Version: 4.11.2
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=9JfxhnDtr-8l3kCP2U5TVXSErptHoga8m7XA8zqgGOc,4
2
- claude_mpm/VERSION,sha256=FFRZhOvxPjL4clpLdj7K74TxFIkhB1BHeUD9jed261o,7
2
+ claude_mpm/VERSION,sha256=oEd-0RuqAA1JoYm8CRr4YanRwGzu-u7mMGWv8tkdGfM,7
3
3
  claude_mpm/__init__.py,sha256=UCw6j9e_tZQ3kJtTqmdfNv7MHyw9nD1jkj80WurwM2g,2064
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=sLjJF6Kw7H4V9WWeaEYltM-77TgXqzEMX5vx4ukM5-0,5977
@@ -100,12 +100,10 @@ claude_mpm/cli/commands/mcp_setup_external.py,sha256=hfBHkaioNa0JRDhahNEc8agyrUw
100
100
  claude_mpm/cli/commands/mcp_tool_commands.py,sha256=q17GzlFT3JiLTrDqwPO2tz1-fKmPO5QU449syTnKTz4,1283
101
101
  claude_mpm/cli/commands/memory.py,sha256=O4T5HGL-Ob_QPt2dZHQvoOrVohnaDKrBjyngq1Mcv1w,26185
102
102
  claude_mpm/cli/commands/monitor.py,sha256=Fjb68hf3dEwTFek2LV8Nh6iU0qEkY7qYlOn32IwNaNg,9566
103
- claude_mpm/cli/commands/mpm_init.py,sha256=dufJ9WQzS5mbEdpSHqOWTk2rBmSO8xkxSJ1D8gsgzZk,72451
104
- claude_mpm/cli/commands/mpm_init_handler.py,sha256=M8S2mRl-wyjM8biP-hRl5V1UYOtYxDyD2KQTAhSw8mM,4869
103
+ claude_mpm/cli/commands/mpm_init.py,sha256=-OsKIhiM6uqrodabyP47UA01o4dbz8qvIwFXf-bPp34,75219
104
+ claude_mpm/cli/commands/mpm_init_handler.py,sha256=FZRoo_zfEakLc_W1G_ej_bhxtaU6ybngyBP5GLxaKD4,4583
105
105
  claude_mpm/cli/commands/run.py,sha256=PB2H55piOPTy4yo4OBgbUCjMlcz9K79wbwpxQVc9m5Q,48225
106
106
  claude_mpm/cli/commands/search.py,sha256=alv6udvKcn-xkqeBlLuPRvfSDV1yxEX4n9mjjRT5uLM,16581
107
- claude_mpm/cli/commands/session_pause_manager.py,sha256=YCUrxOdsoFRKCqlAZJVk6x1HYcece8xqGTl7eCiPx9A,13123
108
- claude_mpm/cli/commands/session_resume_manager.py,sha256=qWFQv3eLhorCln0rtgM8FOGjFlfFNs5c8ctYehgiYqI,18087
109
107
  claude_mpm/cli/commands/tickets.py,sha256=kl2dklTBnG3Y4jUUJ_PcEVsTx4CtVJfkGWboWBx_mQM,21234
110
108
  claude_mpm/cli/commands/uninstall.py,sha256=KGlVG6veEs1efLVjrZ3wSty7e1zVR9wpt-VXQA1RzWw,5945
111
109
  claude_mpm/cli/commands/upgrade.py,sha256=NYMVONNlj78WHoQ6eyVInroE95AeQxUY2_TpjYFTdYE,5409
@@ -125,7 +123,7 @@ claude_mpm/cli/parsers/debug_parser.py,sha256=F7MZdmiXiPfiIPMv21ZUqB2cMT8Ho1LDmp
125
123
  claude_mpm/cli/parsers/mcp_parser.py,sha256=2j6ULhdu55Z2k_-Gu2QxIsFoTQFbDCEMSGePXSuPoQQ,6532
126
124
  claude_mpm/cli/parsers/memory_parser.py,sha256=ZwCDxJEgp-w03L-1tZsWTgisiwamP42s424bA5bvDJc,4760
127
125
  claude_mpm/cli/parsers/monitor_parser.py,sha256=PeoznSi_5Bw6THK_Espl8M20o6dKvvBSmFzAbovkaFQ,4920
128
- claude_mpm/cli/parsers/mpm_init_parser.py,sha256=1FpjO6-5q0Fqgd2w3RvGVDX5tW8iG5zGJhYq3GibvJI,9531
126
+ claude_mpm/cli/parsers/mpm_init_parser.py,sha256=EVyHc7KYpsyxhomZAUnlGS6kq43ix2wjrHLiM5Gf34E,9684
129
127
  claude_mpm/cli/parsers/run_parser.py,sha256=cs34qNonFZG8uYxTYEt0rXi2LcPz3pw8D8hxiywih6w,4927
130
128
  claude_mpm/cli/parsers/search_parser.py,sha256=L8-65kndg-zutSKpzj-eCvTNkeySCZ-WlSHdhk7pEak,6916
131
129
  claude_mpm/cli/parsers/tickets_parser.py,sha256=FYl-VNH7PrZzfZUCcjnf6F7g6JXnL8YDxwrmR5svIcg,6966
@@ -143,7 +141,7 @@ claude_mpm/commands/mpm-agents.md,sha256=JnYPJ-eWvIEEtiCB6iPu182P2xDBRvU3ArVXQ7h
143
141
  claude_mpm/commands/mpm-config.md,sha256=79Eb-srRpEVV3HCHDHZc8SKec6_LVP6HbXDEVkZKLgw,2929
144
142
  claude_mpm/commands/mpm-doctor.md,sha256=ut5LhFKVRw-2ecjMSPsnaTiRuFXa6Q9t-Wgl3CCnQvk,590
145
143
  claude_mpm/commands/mpm-help.md,sha256=zfhpE0Fd-wW5zWmYYAMRMT-xYK8saqbw-HXRD7csJHI,2850
146
- claude_mpm/commands/mpm-init.md,sha256=WcEj7r4HyTHQc7-NVpYlDNOtZrlMs4VH-vm3K1X7At8,13329
144
+ claude_mpm/commands/mpm-init.md,sha256=wwYHkToq8U5ALdhu8bDPygqAsKZ77aMaai7ZJC3oBqU,16054
147
145
  claude_mpm/commands/mpm-monitor.md,sha256=onTHf9Yac1KkdZdENtY2Q5jyw0A-vZLYgoKkPCtZLUY,12193
148
146
  claude_mpm/commands/mpm-organize.md,sha256=T-ysjhwgfW9irjUj02vuY_1jeMdabO_zxcShyjmqsiM,10153
149
147
  claude_mpm/commands/mpm-status.md,sha256=oaM4ybL4ffp55nkT9F0mp_5H4tF-wX9mbqK-LEKEqUU,1919
@@ -789,6 +787,7 @@ claude_mpm/utils/environment_context.py,sha256=mCnRJqQLTyaAv-7M4bp9N9WqVgfSQb5xb
789
787
  claude_mpm/utils/error_handler.py,sha256=RWL7DnXttJKCgYhevUm9XlMC33rEhX2CXo1IiCtwV4g,7969
790
788
  claude_mpm/utils/file_utils.py,sha256=pv3MEKLsn4WIOra5JoHnCm_FaJbNcKMuS3EKuXAWyLc,7859
791
789
  claude_mpm/utils/framework_detection.py,sha256=dCY-N0HzuYS9KBg1BjDw8mJnNb22JqmKBoodjTMzd5w,1183
790
+ claude_mpm/utils/git_analyzer.py,sha256=48fmZzpuOydjdOYa9DAqivmDRLrGlA156ltMmXuFDAE,14129
792
791
  claude_mpm/utils/import_migration_example.py,sha256=sKlV-apfkHDJzzez6uubHXjx91YF_5HPuzu2sLs_U0E,989
793
792
  claude_mpm/utils/imports.py,sha256=IGcW0W6V-2jTmkVlO-l0Zodo3LRA3zkaumD9J2qn7dE,6654
794
793
  claude_mpm/utils/log_cleanup.py,sha256=1d8K1V2uOFPGJJKFOk6E_AMj22sifAibOg-VQyGooWo,22301
@@ -799,9 +798,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
799
798
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
800
799
  claude_mpm/validation/agent_validator.py,sha256=GprtAvu80VyMXcKGsK_VhYiXWA6BjKHv7O6HKx0AB9w,20917
801
800
  claude_mpm/validation/frontmatter_validator.py,sha256=YpJlYNNYcV8u6hIOi3_jaRsDnzhbcQpjCBE6eyBKaFY,7076
802
- claude_mpm-4.11.0.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
803
- claude_mpm-4.11.0.dist-info/METADATA,sha256=MEj3DXeNTTBP_5amuoK5rdIplBHmiEwKSSRJvteORTc,17967
804
- claude_mpm-4.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
805
- claude_mpm-4.11.0.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
806
- claude_mpm-4.11.0.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
807
- claude_mpm-4.11.0.dist-info/RECORD,,
801
+ claude_mpm-4.11.2.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
802
+ claude_mpm-4.11.2.dist-info/METADATA,sha256=fxFp04Rwx9nyCdY9RKXWS0F_IhICPMPGFfk5g6rUyh0,17967
803
+ claude_mpm-4.11.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
804
+ claude_mpm-4.11.2.dist-info/entry_points.txt,sha256=Vlw3GNi-OtTpKSrez04iNrPmxNxYDpIWxmJCxiZ5Tx8,526
805
+ claude_mpm-4.11.2.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
806
+ claude_mpm-4.11.2.dist-info/RECORD,,