claude-mpm 3.5.4__py3-none-any.whl → 3.6.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.
Files changed (68) hide show
  1. claude_mpm/.claude-mpm/logs/hooks_20250728.log +10 -0
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +96 -23
  4. claude_mpm/agents/BASE_PM.md +273 -0
  5. claude_mpm/agents/INSTRUCTIONS.md +114 -102
  6. claude_mpm/agents/agent-template.yaml +83 -0
  7. claude_mpm/agents/agent_loader.py +36 -1
  8. claude_mpm/agents/async_agent_loader.py +421 -0
  9. claude_mpm/agents/templates/code_analyzer.json +81 -0
  10. claude_mpm/agents/templates/data_engineer.json +18 -3
  11. claude_mpm/agents/templates/documentation.json +18 -3
  12. claude_mpm/agents/templates/engineer.json +19 -4
  13. claude_mpm/agents/templates/ops.json +18 -3
  14. claude_mpm/agents/templates/qa.json +20 -4
  15. claude_mpm/agents/templates/research.json +20 -4
  16. claude_mpm/agents/templates/security.json +18 -3
  17. claude_mpm/agents/templates/version_control.json +16 -3
  18. claude_mpm/cli/README.md +108 -0
  19. claude_mpm/cli/__init__.py +5 -1
  20. claude_mpm/cli/commands/__init__.py +5 -1
  21. claude_mpm/cli/commands/agents.py +233 -6
  22. claude_mpm/cli/commands/aggregate.py +462 -0
  23. claude_mpm/cli/commands/config.py +277 -0
  24. claude_mpm/cli/commands/run.py +228 -47
  25. claude_mpm/cli/parser.py +176 -1
  26. claude_mpm/cli/utils.py +9 -1
  27. claude_mpm/cli_module/refactoring_guide.md +253 -0
  28. claude_mpm/config/async_logging_config.yaml +145 -0
  29. claude_mpm/constants.py +19 -0
  30. claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
  31. claude_mpm/core/claude_runner.py +413 -76
  32. claude_mpm/core/config.py +161 -4
  33. claude_mpm/core/config_paths.py +0 -1
  34. claude_mpm/core/factories.py +9 -3
  35. claude_mpm/core/framework_loader.py +81 -0
  36. claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
  37. claude_mpm/dashboard/README.md +121 -0
  38. claude_mpm/dashboard/static/js/dashboard.js.backup +1973 -0
  39. claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
  40. claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
  41. claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
  42. claude_mpm/hooks/README.md +96 -0
  43. claude_mpm/hooks/claude_hooks/hook_handler.py +391 -9
  44. claude_mpm/init.py +123 -18
  45. claude_mpm/models/agent_session.py +511 -0
  46. claude_mpm/schemas/agent_schema.json +435 -0
  47. claude_mpm/scripts/__init__.py +15 -0
  48. claude_mpm/scripts/start_activity_logging.py +86 -0
  49. claude_mpm/services/agents/deployment/agent_deployment.py +326 -24
  50. claude_mpm/services/agents/deployment/async_agent_deployment.py +461 -0
  51. claude_mpm/services/agents/management/agent_management_service.py +2 -1
  52. claude_mpm/services/event_aggregator.py +547 -0
  53. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  54. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +3 -3
  55. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +2 -2
  56. claude_mpm/services/version_control/VERSION +1 -0
  57. claude_mpm/utils/agent_dependency_loader.py +655 -0
  58. claude_mpm/utils/console.py +11 -0
  59. claude_mpm/utils/dependency_cache.py +376 -0
  60. claude_mpm/utils/dependency_strategies.py +343 -0
  61. claude_mpm/utils/environment_context.py +310 -0
  62. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/METADATA +87 -1
  63. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/RECORD +67 -37
  64. claude_mpm/agents/templates/pm.json +0 -122
  65. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/WHEEL +0 -0
  66. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/entry_points.txt +0 -0
  67. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/licenses/LICENSE +0 -0
  68. {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/top_level.txt +0 -0
claude_mpm/init.py CHANGED
@@ -8,6 +8,7 @@ import shutil
8
8
  from pathlib import Path
9
9
  from typing import Optional, Dict, Any
10
10
  import json
11
+ import yaml
11
12
 
12
13
  from claude_mpm.core.logger import get_logger
13
14
 
@@ -48,9 +49,15 @@ class ProjectInitializer:
48
49
  for directory in directories:
49
50
  directory.mkdir(parents=True, exist_ok=True)
50
51
 
51
- # Create default configuration if it doesn't exist
52
- config_file = self.user_dir / "config" / "settings.json"
53
- if not config_file.exists():
52
+ # Check for migration from old settings.json to new configuration.yaml
53
+ old_config_file = self.user_dir / "config" / "settings.json"
54
+ config_file = self.user_dir / "config" / "configuration.yaml"
55
+
56
+ # Migrate if old file exists but new doesn't
57
+ if old_config_file.exists() and not config_file.exists():
58
+ self._migrate_json_to_yaml(old_config_file, config_file)
59
+ elif not config_file.exists():
60
+ # Create default configuration if it doesn't exist
54
61
  self._create_default_config(config_file)
55
62
 
56
63
  # Copy agent templates if they don't exist
@@ -68,8 +75,7 @@ class ProjectInitializer:
68
75
 
69
76
  Creates:
70
77
  - .claude-mpm/
71
- - agents/
72
- - project-specific/
78
+ - agents/ (for project agent JSON files)
73
79
  - config/
74
80
  - responses/
75
81
  - logs/
@@ -80,20 +86,33 @@ class ProjectInitializer:
80
86
  project_root = project_path
81
87
  self.project_dir = project_path / ".claude-mpm"
82
88
  else:
83
- # Always use current working directory for project directories
84
- # This ensures .claude-mpm is created where the user launches the tool
85
- project_root = Path.cwd()
89
+ # Check for the user's original working directory from launch script
90
+ # The launch script sets CLAUDE_MPM_USER_PWD before changing to framework directory
91
+ user_pwd = os.environ.get('CLAUDE_MPM_USER_PWD')
92
+
93
+ if user_pwd:
94
+ # Use the original user working directory
95
+ project_root = Path(user_pwd)
96
+ self.logger.debug(f"Using user working directory from CLAUDE_MPM_USER_PWD: {project_root}")
97
+ else:
98
+ # Fallback to current working directory (backward compatibility)
99
+ project_root = Path.cwd()
100
+ self.logger.debug(f"CLAUDE_MPM_USER_PWD not set, using cwd: {project_root}")
101
+
86
102
  self.project_dir = project_root / ".claude-mpm"
87
103
 
88
104
  # Check if directory already exists
89
105
  directory_existed = self.project_dir.exists()
90
106
 
107
+ # Migrate existing agents from project-specific subdirectory if needed
108
+ self._migrate_project_agents()
109
+
91
110
  # Create project directory
92
111
  self.project_dir.mkdir(exist_ok=True)
93
112
 
94
113
  # Create subdirectories
95
114
  directories = [
96
- self.project_dir / "agents" / "project-specific",
115
+ self.project_dir / "agents", # Direct agents directory for project agents
97
116
  self.project_dir / "config",
98
117
  self.project_dir / "responses",
99
118
  self.project_dir / "logs",
@@ -122,6 +141,12 @@ class ProjectInitializer:
122
141
  else:
123
142
  print(f"✓ Initialized .claude-mpm/ in {project_root}")
124
143
 
144
+ # Check if migration happened
145
+ agents_dir = self.project_dir / "agents"
146
+ if agents_dir.exists() and any(agents_dir.glob("*.json")):
147
+ agent_count = len(list(agents_dir.glob("*.json")))
148
+ print(f"✓ Found {agent_count} project agent(s) in .claude-mpm/agents/")
149
+
125
150
  return True
126
151
 
127
152
  except Exception as e:
@@ -129,6 +154,54 @@ class ProjectInitializer:
129
154
  print(f"✗ Failed to create .claude-mpm/ directory: {e}")
130
155
  return False
131
156
 
157
+ def _migrate_project_agents(self):
158
+ """Migrate agents from old subdirectory structure to direct agents directory.
159
+
160
+ WHY: We're simplifying the directory structure to match the deployment expectations.
161
+ The old structure had a subdirectory but the deployment now looks for agents
162
+ directly in .claude-mpm/agents/.
163
+ """
164
+ if not self.project_dir:
165
+ return
166
+
167
+ old_agents_dir = self.project_dir / "agents" / "project-specific"
168
+ new_agents_dir = self.project_dir / "agents"
169
+
170
+ # Check if old directory exists with JSON files
171
+ if old_agents_dir.exists() and old_agents_dir.is_dir():
172
+ json_files = list(old_agents_dir.glob("*.json"))
173
+ if json_files:
174
+ self.logger.info(f"Migrating {len(json_files)} agents from old subdirectory")
175
+
176
+ # Ensure new agents directory exists
177
+ new_agents_dir.mkdir(parents=True, exist_ok=True)
178
+
179
+ # Move each JSON file
180
+ migrated_count = 0
181
+ for json_file in json_files:
182
+ try:
183
+ target_file = new_agents_dir / json_file.name
184
+ if not target_file.exists():
185
+ # Move the file
186
+ shutil.move(str(json_file), str(target_file))
187
+ migrated_count += 1
188
+ self.logger.debug(f"Migrated {json_file.name} to agents directory")
189
+ else:
190
+ self.logger.debug(f"Skipping {json_file.name} - already exists in target")
191
+ except Exception as e:
192
+ self.logger.error(f"Failed to migrate {json_file.name}: {e}")
193
+
194
+ if migrated_count > 0:
195
+ print(f"✓ Migrated {migrated_count} agent(s) from old location to agents/")
196
+
197
+ # Remove old directory if empty
198
+ try:
199
+ if not any(old_agents_dir.iterdir()):
200
+ old_agents_dir.rmdir()
201
+ self.logger.debug("Removed empty old subdirectory")
202
+ except Exception as e:
203
+ self.logger.debug(f"Could not remove old directory: {e}")
204
+
132
205
  def _find_project_root(self) -> Optional[Path]:
133
206
  """Find project root by looking for .git or other project markers."""
134
207
  current = Path.cwd()
@@ -142,8 +215,36 @@ class ProjectInitializer:
142
215
  current = current.parent
143
216
  return None
144
217
 
218
+ def _migrate_json_to_yaml(self, old_file: Path, new_file: Path):
219
+ """Migrate configuration from JSON to YAML format.
220
+
221
+ Args:
222
+ old_file: Path to existing settings.json
223
+ new_file: Path to new configuration.yaml
224
+ """
225
+ try:
226
+ # Read existing JSON configuration
227
+ with open(old_file, 'r') as f:
228
+ config = json.load(f)
229
+
230
+ # Write as YAML
231
+ with open(new_file, 'w') as f:
232
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
233
+
234
+ self.logger.info(f"Migrated configuration from {old_file.name} to {new_file.name}")
235
+
236
+ # Optionally rename old file to .backup
237
+ backup_file = old_file.with_suffix('.json.backup')
238
+ old_file.rename(backup_file)
239
+ self.logger.info(f"Renamed old configuration to {backup_file.name}")
240
+
241
+ except Exception as e:
242
+ self.logger.error(f"Failed to migrate configuration: {e}")
243
+ # Fall back to creating default config
244
+ self._create_default_config(new_file)
245
+
145
246
  def _create_default_config(self, config_file: Path):
146
- """Create default user configuration."""
247
+ """Create default user configuration in YAML format."""
147
248
  default_config = {
148
249
  "version": "1.0",
149
250
  "hooks": {
@@ -166,7 +267,7 @@ class ProjectInitializer:
166
267
  }
167
268
 
168
269
  with open(config_file, 'w') as f:
169
- json.dump(default_config, f, indent=2)
270
+ yaml.dump(default_config, f, default_flow_style=False, sort_keys=False)
170
271
 
171
272
  def _create_project_config(self, config_file: Path):
172
273
  """Create default project configuration."""
@@ -237,19 +338,23 @@ class ProjectInitializer:
237
338
 
238
339
  Shows clear information about where directories are being created.
239
340
  """
240
- # Show working directory info at startup
241
- cwd = Path.cwd()
242
- framework_path = Path(__file__).parent.parent.parent
341
+ # Determine actual working directory
342
+ user_pwd = os.environ.get('CLAUDE_MPM_USER_PWD')
343
+ if user_pwd:
344
+ actual_wd = Path(user_pwd)
345
+ self.logger.info(f"User working directory (from CLAUDE_MPM_USER_PWD): {actual_wd}")
346
+ else:
347
+ actual_wd = Path.cwd()
348
+ self.logger.info(f"Working directory: {actual_wd}")
243
349
 
244
- # Log startup context
245
- self.logger.info(f"Working directory: {cwd}")
350
+ framework_path = Path(__file__).parent.parent.parent
246
351
  self.logger.info(f"Framework path: {framework_path}")
247
352
 
248
353
  # Initialize user directory (in home)
249
354
  user_ok = self.initialize_user_directory()
250
355
 
251
- # Initialize project directory (in current working directory)
252
- self.logger.info(f"Checking for .claude-mpm/ in {cwd}")
356
+ # Initialize project directory (in user's actual working directory)
357
+ self.logger.info(f"Checking for .claude-mpm/ in {actual_wd}")
253
358
  project_ok = self.initialize_project_directory()
254
359
 
255
360
  return user_ok and project_ok