claude-mpm 3.4.27__py3-none-any.whl → 3.5.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.
Files changed (123) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +182 -299
  3. claude_mpm/agents/agent_loader.py +283 -57
  4. claude_mpm/agents/agent_loader_integration.py +6 -9
  5. claude_mpm/agents/base_agent.json +2 -1
  6. claude_mpm/agents/base_agent_loader.py +1 -1
  7. claude_mpm/cli/__init__.py +5 -7
  8. claude_mpm/cli/commands/__init__.py +0 -2
  9. claude_mpm/cli/commands/agents.py +1 -1
  10. claude_mpm/cli/commands/memory.py +1 -1
  11. claude_mpm/cli/commands/run.py +12 -0
  12. claude_mpm/cli/parser.py +0 -13
  13. claude_mpm/cli/utils.py +1 -1
  14. claude_mpm/config/__init__.py +44 -2
  15. claude_mpm/config/agent_config.py +348 -0
  16. claude_mpm/config/paths.py +322 -0
  17. claude_mpm/constants.py +0 -1
  18. claude_mpm/core/__init__.py +2 -5
  19. claude_mpm/core/agent_registry.py +63 -17
  20. claude_mpm/core/claude_runner.py +354 -43
  21. claude_mpm/core/config.py +7 -1
  22. claude_mpm/core/config_aliases.py +4 -3
  23. claude_mpm/core/config_paths.py +151 -0
  24. claude_mpm/core/factories.py +4 -50
  25. claude_mpm/core/logger.py +11 -13
  26. claude_mpm/core/service_registry.py +2 -2
  27. claude_mpm/dashboard/static/js/components/agent-inference.js +101 -25
  28. claude_mpm/dashboard/static/js/components/event-processor.js +3 -2
  29. claude_mpm/hooks/claude_hooks/hook_handler.py +343 -83
  30. claude_mpm/hooks/memory_integration_hook.py +1 -1
  31. claude_mpm/init.py +37 -6
  32. claude_mpm/scripts/socketio_daemon.py +6 -2
  33. claude_mpm/services/__init__.py +71 -3
  34. claude_mpm/services/agents/__init__.py +85 -0
  35. claude_mpm/services/agents/deployment/__init__.py +21 -0
  36. claude_mpm/services/{agent_deployment.py → agents/deployment/agent_deployment.py} +192 -41
  37. claude_mpm/services/{agent_lifecycle_manager.py → agents/deployment/agent_lifecycle_manager.py} +11 -10
  38. claude_mpm/services/agents/loading/__init__.py +11 -0
  39. claude_mpm/services/{agent_profile_loader.py → agents/loading/agent_profile_loader.py} +9 -8
  40. claude_mpm/services/{base_agent_manager.py → agents/loading/base_agent_manager.py} +2 -2
  41. claude_mpm/services/{framework_agent_loader.py → agents/loading/framework_agent_loader.py} +116 -40
  42. claude_mpm/services/agents/management/__init__.py +9 -0
  43. claude_mpm/services/{agent_management_service.py → agents/management/agent_management_service.py} +6 -5
  44. claude_mpm/services/agents/memory/__init__.py +21 -0
  45. claude_mpm/services/{agent_memory_manager.py → agents/memory/agent_memory_manager.py} +3 -3
  46. claude_mpm/services/agents/registry/__init__.py +29 -0
  47. claude_mpm/services/{agent_registry.py → agents/registry/agent_registry.py} +101 -16
  48. claude_mpm/services/{deployed_agent_discovery.py → agents/registry/deployed_agent_discovery.py} +12 -2
  49. claude_mpm/services/{agent_modification_tracker.py → agents/registry/modification_tracker.py} +6 -5
  50. claude_mpm/services/async_session_logger.py +584 -0
  51. claude_mpm/services/claude_session_logger.py +299 -0
  52. claude_mpm/services/framework_claude_md_generator/content_assembler.py +2 -2
  53. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +17 -17
  54. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +3 -3
  55. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +1 -1
  56. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +1 -1
  57. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +19 -24
  58. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +1 -1
  59. claude_mpm/services/framework_claude_md_generator.py +4 -2
  60. claude_mpm/services/memory/__init__.py +17 -0
  61. claude_mpm/services/{memory_builder.py → memory/builder.py} +3 -3
  62. claude_mpm/services/memory/cache/__init__.py +14 -0
  63. claude_mpm/services/{shared_prompt_cache.py → memory/cache/shared_prompt_cache.py} +1 -1
  64. claude_mpm/services/memory/cache/simple_cache.py +317 -0
  65. claude_mpm/services/{memory_optimizer.py → memory/optimizer.py} +1 -1
  66. claude_mpm/services/{memory_router.py → memory/router.py} +1 -1
  67. claude_mpm/services/optimized_hook_service.py +542 -0
  68. claude_mpm/services/project_registry.py +14 -8
  69. claude_mpm/services/response_tracker.py +237 -0
  70. claude_mpm/services/ticketing_service_original.py +4 -2
  71. claude_mpm/services/version_control/branch_strategy.py +3 -1
  72. claude_mpm/utils/paths.py +12 -10
  73. claude_mpm/utils/session_logging.py +114 -0
  74. claude_mpm/validation/agent_validator.py +2 -1
  75. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/METADATA +28 -20
  76. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/RECORD +83 -106
  77. claude_mpm/cli/commands/ui.py +0 -57
  78. claude_mpm/core/simple_runner.py +0 -1046
  79. claude_mpm/hooks/builtin/__init__.py +0 -1
  80. claude_mpm/hooks/builtin/logging_hook_example.py +0 -165
  81. claude_mpm/hooks/builtin/memory_hooks_example.py +0 -67
  82. claude_mpm/hooks/builtin/mpm_command_hook.py +0 -125
  83. claude_mpm/hooks/builtin/post_delegation_hook_example.py +0 -124
  84. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +0 -125
  85. claude_mpm/hooks/builtin/submit_hook_example.py +0 -100
  86. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +0 -237
  87. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +0 -240
  88. claude_mpm/hooks/builtin/workflow_start_hook.py +0 -181
  89. claude_mpm/orchestration/__init__.py +0 -6
  90. claude_mpm/orchestration/archive/direct_orchestrator.py +0 -195
  91. claude_mpm/orchestration/archive/factory.py +0 -215
  92. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +0 -188
  93. claude_mpm/orchestration/archive/hook_integration_example.py +0 -178
  94. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +0 -826
  95. claude_mpm/orchestration/archive/orchestrator.py +0 -501
  96. claude_mpm/orchestration/archive/pexpect_orchestrator.py +0 -252
  97. claude_mpm/orchestration/archive/pty_orchestrator.py +0 -270
  98. claude_mpm/orchestration/archive/simple_orchestrator.py +0 -82
  99. claude_mpm/orchestration/archive/subprocess_orchestrator.py +0 -801
  100. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +0 -278
  101. claude_mpm/orchestration/archive/wrapper_orchestrator.py +0 -187
  102. claude_mpm/schemas/workflow_validator.py +0 -411
  103. claude_mpm/services/parent_directory_manager/__init__.py +0 -577
  104. claude_mpm/services/parent_directory_manager/backup_manager.py +0 -258
  105. claude_mpm/services/parent_directory_manager/config_manager.py +0 -210
  106. claude_mpm/services/parent_directory_manager/deduplication_manager.py +0 -279
  107. claude_mpm/services/parent_directory_manager/framework_protector.py +0 -143
  108. claude_mpm/services/parent_directory_manager/operations.py +0 -186
  109. claude_mpm/services/parent_directory_manager/state_manager.py +0 -624
  110. claude_mpm/services/parent_directory_manager/template_deployer.py +0 -579
  111. claude_mpm/services/parent_directory_manager/validation_manager.py +0 -378
  112. claude_mpm/services/parent_directory_manager/version_control_helper.py +0 -339
  113. claude_mpm/services/parent_directory_manager/version_manager.py +0 -222
  114. claude_mpm/ui/__init__.py +0 -1
  115. claude_mpm/ui/rich_terminal_ui.py +0 -295
  116. claude_mpm/ui/terminal_ui.py +0 -328
  117. /claude_mpm/services/{agent_versioning.py → agents/deployment/agent_versioning.py} +0 -0
  118. /claude_mpm/services/{agent_capabilities_generator.py → agents/management/agent_capabilities_generator.py} +0 -0
  119. /claude_mpm/services/{agent_persistence_service.py → agents/memory/agent_persistence_service.py} +0 -0
  120. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/WHEEL +0 -0
  121. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/entry_points.txt +0 -0
  122. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/licenses/LICENSE +0 -0
  123. {claude_mpm-3.4.27.dist-info → claude_mpm-3.5.1.dist-info}/top_level.txt +0 -0
@@ -9,15 +9,16 @@ from datetime import datetime
9
9
  from pathlib import Path
10
10
  from typing import Optional
11
11
  import uuid
12
+ from claude_mpm.config.paths import paths
12
13
 
13
14
  try:
14
- from claude_mpm.services.agent_deployment import AgentDeploymentService
15
+ from claude_mpm.services.agents.deployment import AgentDeploymentService
15
16
  from claude_mpm.services.ticket_manager import TicketManager
16
17
  from claude_mpm.services.hook_service import HookService
17
18
  from claude_mpm.core.config import Config
18
19
  from claude_mpm.core.logger import get_logger, get_project_logger, ProjectLogger
19
20
  except ImportError:
20
- from claude_mpm.services.agent_deployment import AgentDeploymentService
21
+ from claude_mpm.services.agents.deployment import AgentDeploymentService
21
22
  from claude_mpm.services.ticket_manager import TicketManager
22
23
  from claude_mpm.services.hook_service import HookService
23
24
  from claude_mpm.core.config import Config
@@ -67,23 +68,58 @@ class ClaudeRunner:
67
68
  level="INFO",
68
69
  component="runner"
69
70
  )
71
+ except ImportError as e:
72
+ self.logger.warning(f"Project logger module not available: {e}")
70
73
  except Exception as e:
71
74
  self.logger.warning(f"Failed to initialize project logger: {e}")
72
75
 
73
- # Initialize services
74
- self.deployment_service = AgentDeploymentService()
76
+ # Initialize services with proper error handling
77
+ try:
78
+ self.deployment_service = AgentDeploymentService()
79
+ except ImportError as e:
80
+ self.logger.error(f"Failed to import AgentDeploymentService: {e}")
81
+ raise RuntimeError("Required module AgentDeploymentService not available. Please reinstall claude-mpm.") from e
82
+ except Exception as e:
83
+ self.logger.error(f"Failed to initialize AgentDeploymentService: {e}")
84
+ raise RuntimeError(f"Agent deployment service initialization failed: {e}") from e
85
+
86
+ # Initialize ticket manager if enabled
75
87
  if enable_tickets:
76
88
  try:
77
89
  self.ticket_manager = TicketManager()
78
- except (ImportError, TypeError, Exception) as e:
79
- self.logger.warning(f"Ticket manager not available: {e}")
90
+ except ImportError as e:
91
+ self.logger.warning(f"Ticket manager module not available: {e}")
92
+ self.ticket_manager = None
93
+ self.enable_tickets = False
94
+ except TypeError as e:
95
+ self.logger.warning(f"Ticket manager initialization error: {e}")
96
+ self.ticket_manager = None
97
+ self.enable_tickets = False
98
+ except Exception as e:
99
+ self.logger.warning(f"Unexpected error initializing ticket manager: {e}")
80
100
  self.ticket_manager = None
81
101
  self.enable_tickets = False
82
102
 
83
- # Initialize hook service and register memory hooks
84
- self.config = Config()
85
- self.hook_service = HookService(self.config)
86
- self._register_memory_hooks()
103
+ # Initialize configuration
104
+ try:
105
+ self.config = Config()
106
+ except FileNotFoundError as e:
107
+ self.logger.warning(f"Configuration file not found, using defaults: {e}")
108
+ self.config = Config() # Will use defaults
109
+ except Exception as e:
110
+ self.logger.error(f"Failed to load configuration: {e}")
111
+ raise RuntimeError(f"Configuration initialization failed: {e}") from e
112
+
113
+ # Initialize hook service
114
+ try:
115
+ self.hook_service = HookService(self.config)
116
+ self._register_memory_hooks()
117
+ except ImportError as e:
118
+ self.logger.warning(f"Hook service module not available: {e}")
119
+ self.hook_service = None
120
+ except Exception as e:
121
+ self.logger.warning(f"Failed to initialize hook service: {e}")
122
+ self.hook_service = None
87
123
 
88
124
  # Load system instructions
89
125
  self.system_instructions = self._load_system_instructions()
@@ -101,6 +137,10 @@ class ClaudeRunner:
101
137
  "log_level": log_level,
102
138
  "launch_method": launch_method
103
139
  })
140
+ except PermissionError as e:
141
+ self.logger.debug(f"Permission denied creating session log file: {e}")
142
+ except OSError as e:
143
+ self.logger.debug(f"OS error creating session log file: {e}")
104
144
  except Exception as e:
105
145
  self.logger.debug(f"Failed to create session log file: {e}")
106
146
 
@@ -148,12 +188,99 @@ class ClaudeRunner:
148
188
  )
149
189
  return True
150
190
 
191
+
192
+ except PermissionError as e:
193
+ error_msg = f"Permission denied deploying agents to .claude/agents/: {e}"
194
+ self.logger.error(error_msg)
195
+ print(f"❌ {error_msg}")
196
+ print("💡 Try running with appropriate permissions or check directory ownership")
197
+ if self.project_logger:
198
+ self.project_logger.log_system(error_msg, level="ERROR", component="deployment")
199
+ return False
200
+
201
+ except FileNotFoundError as e:
202
+ error_msg = f"Agent templates not found: {e}"
203
+ self.logger.error(error_msg)
204
+ print(f"❌ {error_msg}")
205
+ print("💡 Ensure claude-mpm is properly installed")
206
+ if self.project_logger:
207
+ self.project_logger.log_system(error_msg, level="ERROR", component="deployment")
208
+ return False
209
+
210
+ except ImportError as e:
211
+ error_msg = f"Missing required module for agent deployment: {e}"
212
+ self.logger.error(error_msg)
213
+ print(f"⚠️ {error_msg}")
214
+ print("💡 Some agent features may be limited")
215
+ if self.project_logger:
216
+ self.project_logger.log_system(error_msg, level="WARNING", component="deployment")
217
+ return False
218
+
219
+ except Exception as e:
220
+ error_msg = f"Unexpected error during agent deployment: {e}"
221
+ self.logger.error(error_msg)
222
+ print(f"⚠️ {error_msg}")
223
+ if self.project_logger:
224
+ self.project_logger.log_system(error_msg, level="ERROR", component="deployment")
225
+ # Continue without agents rather than failing completely
226
+ return False
227
+
228
+ def ensure_project_agents(self) -> bool:
229
+ """Ensure system agents are available in the project directory.
230
+
231
+ Deploys system agents to project's .claude-mpm/agents/ directory
232
+ if they don't exist or are outdated. This enables project-level
233
+ agent customization and ensures all agents are available locally.
234
+
235
+ Returns:
236
+ bool: True if agents are available, False on error
237
+ """
238
+ try:
239
+ # Check if we're in a project directory
240
+ project_dir = Path.cwd()
241
+ project_agents_dir = project_dir / ".claude-mpm" / "agents"
242
+
243
+ # Create directory if it doesn't exist
244
+ project_agents_dir.mkdir(parents=True, exist_ok=True)
245
+
246
+ if self.project_logger:
247
+ self.project_logger.log_system(
248
+ f"Ensuring agents are available in project: {project_agents_dir}",
249
+ level="INFO",
250
+ component="deployment"
251
+ )
252
+
253
+ # Deploy agents to project directory with project deployment mode
254
+ # This ensures all system agents are deployed regardless of version
255
+ results = self.deployment_service.deploy_agents(
256
+ target_dir=project_dir / ".claude-mpm",
257
+ force_rebuild=False,
258
+ deployment_mode="project"
259
+ )
260
+
261
+ if results["deployed"] or results.get("updated", []):
262
+ deployed_count = len(results['deployed'])
263
+ updated_count = len(results.get('updated', []))
264
+
265
+ if deployed_count > 0:
266
+ self.logger.info(f"Deployed {deployed_count} agents to project")
267
+ if updated_count > 0:
268
+ self.logger.info(f"Updated {updated_count} agents in project")
269
+
270
+ return True
271
+ elif results.get("skipped", []):
272
+ # Agents already exist and are current
273
+ self.logger.debug(f"Project agents up to date: {len(results['skipped'])} agents")
274
+ return True
275
+ else:
276
+ self.logger.warning("No agents deployed to project")
277
+ return False
278
+
151
279
  except Exception as e:
152
- self.logger.error(f"Agent deployment failed: {e}")
153
- print(f"⚠️ Agent deployment failed: {e}")
280
+ self.logger.error(f"Failed to ensure project agents: {e}")
154
281
  if self.project_logger:
155
282
  self.project_logger.log_system(
156
- f"Agent deployment failed: {e}",
283
+ f"Failed to ensure project agents: {e}",
157
284
  level="ERROR",
158
285
  component="deployment"
159
286
  )
@@ -180,8 +307,14 @@ class ClaudeRunner:
180
307
  launch_method=self.launch_method,
181
308
  working_dir=working_dir
182
309
  )
310
+ except ImportError as e:
311
+ self.logger.warning(f"Socket.IO module not available: {e}")
312
+ self.websocket_server = None
313
+ except ConnectionError as e:
314
+ self.logger.warning(f"Cannot connect to Socket.IO server on port {self.websocket_port}: {e}")
315
+ self.websocket_server = None
183
316
  except Exception as e:
184
- self.logger.warning(f"Failed to connect to Socket.IO server: {e}")
317
+ self.logger.warning(f"Unexpected error with Socket.IO server: {e}")
185
318
  self.websocket_server = None
186
319
 
187
320
  # Get version with robust fallback mechanisms
@@ -246,8 +379,12 @@ class ClaudeRunner:
246
379
  try:
247
380
  os.chdir(user_pwd)
248
381
  self.logger.info(f"Changed working directory to: {user_pwd}")
249
- except Exception as e:
250
- self.logger.warning(f"Could not change to user directory {user_pwd}: {e}")
382
+ except PermissionError as e:
383
+ self.logger.warning(f"Permission denied accessing directory {user_pwd}: {e}")
384
+ except FileNotFoundError as e:
385
+ self.logger.warning(f"Directory not found {user_pwd}: {e}")
386
+ except OSError as e:
387
+ self.logger.warning(f"OS error changing to directory {user_pwd}: {e}")
251
388
 
252
389
  print("Launching Claude...")
253
390
 
@@ -283,18 +420,62 @@ class ClaudeRunner:
283
420
  )
284
421
  os.execvpe(cmd[0], cmd, clean_env)
285
422
 
286
- except Exception as e:
287
- print(f"Failed to launch Claude: {e}")
423
+ except FileNotFoundError as e:
424
+ error_msg = f"Claude CLI not found. Please ensure 'claude' is installed and in your PATH: {e}"
425
+ print(f"❌ {error_msg}")
426
+ if self.project_logger:
427
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
428
+ self._log_session_event({
429
+ "event": "interactive_launch_failed",
430
+ "error": str(e),
431
+ "exception_type": "FileNotFoundError",
432
+ "recovery_action": "fallback_to_subprocess"
433
+ })
434
+ except PermissionError as e:
435
+ error_msg = f"Permission denied executing Claude CLI: {e}"
436
+ print(f"❌ {error_msg}")
437
+ if self.project_logger:
438
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
439
+ self._log_session_event({
440
+ "event": "interactive_launch_failed",
441
+ "error": str(e),
442
+ "exception_type": "PermissionError",
443
+ "recovery_action": "check_file_permissions"
444
+ })
445
+ except OSError as e:
446
+ error_msg = f"OS error launching Claude: {e}"
447
+ print(f"❌ {error_msg}")
448
+ if self.project_logger:
449
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
450
+ self._log_session_event({
451
+ "event": "interactive_launch_failed",
452
+ "error": str(e),
453
+ "exception_type": "OSError",
454
+ "recovery_action": "fallback_to_subprocess"
455
+ })
456
+ except KeyboardInterrupt:
457
+ print("\n⚠️ Session interrupted by user")
288
458
  if self.project_logger:
289
459
  self.project_logger.log_system(
290
- f"Failed to launch Claude: {e}",
291
- level="ERROR",
460
+ "Session interrupted by user",
461
+ level="INFO",
292
462
  component="session"
293
463
  )
464
+ self._log_session_event({
465
+ "event": "session_interrupted",
466
+ "reason": "user_interrupt"
467
+ })
468
+ return # Clean exit on user interrupt
469
+ except Exception as e:
470
+ error_msg = f"Unexpected error launching Claude: {e}"
471
+ print(f"❌ {error_msg}")
472
+ if self.project_logger:
473
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
294
474
  self._log_session_event({
295
475
  "event": "interactive_launch_failed",
296
476
  "error": str(e),
297
- "exception_type": type(e).__name__
477
+ "exception_type": type(e).__name__,
478
+ "recovery_action": "fallback_to_subprocess"
298
479
  })
299
480
 
300
481
  # Notify WebSocket clients of error
@@ -304,21 +485,52 @@ class ClaudeRunner:
304
485
  message=f"Failed to launch Claude: {e}"
305
486
  )
306
487
  # Fallback to subprocess
488
+ print("\n🔄 Attempting fallback launch method...")
307
489
  try:
308
490
  # Use the same clean_env we prepared earlier
309
- subprocess.run(cmd, stdin=None, stdout=None, stderr=None, env=clean_env)
491
+ result = subprocess.run(cmd, stdin=None, stdout=None, stderr=None, env=clean_env)
492
+ if result.returncode == 0:
493
+ if self.project_logger:
494
+ self.project_logger.log_system(
495
+ "Interactive session completed (subprocess fallback)",
496
+ level="INFO",
497
+ component="session"
498
+ )
499
+ self._log_session_event({
500
+ "event": "interactive_session_complete",
501
+ "fallback": True,
502
+ "return_code": result.returncode
503
+ })
504
+ else:
505
+ print(f"⚠️ Claude exited with code {result.returncode}")
506
+ if self.project_logger:
507
+ self.project_logger.log_system(
508
+ f"Claude exited with non-zero code: {result.returncode}",
509
+ level="WARNING",
510
+ component="session"
511
+ )
512
+ except FileNotFoundError as e:
513
+ print(f"❌ Fallback failed: Claude CLI not found in PATH")
514
+ print("\n💡 To fix this issue:")
515
+ print(" 1. Install Claude CLI: npm install -g @anthropic-ai/claude-ai")
516
+ print(" 2. Or specify the full path to the claude binary")
517
+ if self.project_logger:
518
+ self.project_logger.log_system(
519
+ f"Fallback failed - Claude CLI not found: {e}",
520
+ level="ERROR",
521
+ component="session"
522
+ )
523
+ except KeyboardInterrupt:
524
+ print("\n⚠️ Fallback interrupted by user")
310
525
  if self.project_logger:
311
526
  self.project_logger.log_system(
312
- "Interactive session completed (subprocess fallback)",
527
+ "Fallback interrupted by user",
313
528
  level="INFO",
314
529
  component="session"
315
530
  )
316
- self._log_session_event({
317
- "event": "interactive_session_complete",
318
- "fallback": True
319
- })
320
531
  except Exception as fallback_error:
321
- print(f"Fallback also failed: {fallback_error}")
532
+ print(f"Fallback failed with unexpected error: {fallback_error}")
533
+ print(f" Error type: {type(fallback_error).__name__}")
322
534
  if self.project_logger:
323
535
  self.project_logger.log_system(
324
536
  f"Fallback launch failed: {fallback_error}",
@@ -354,8 +566,14 @@ class ClaudeRunner:
354
566
  launch_method="oneshot",
355
567
  working_dir=working_dir
356
568
  )
569
+ except ImportError as e:
570
+ self.logger.warning(f"Socket.IO module not available: {e}")
571
+ self.websocket_server = None
572
+ except ConnectionError as e:
573
+ self.logger.warning(f"Cannot connect to Socket.IO server on port {self.websocket_port}: {e}")
574
+ self.websocket_server = None
357
575
  except Exception as e:
358
- self.logger.warning(f"Failed to connect to Socket.IO server: {e}")
576
+ self.logger.warning(f"Unexpected error with Socket.IO server: {e}")
359
577
  self.websocket_server = None
360
578
 
361
579
  # Check for /mpm: commands
@@ -412,8 +630,14 @@ class ClaudeRunner:
412
630
  original_cwd = os.getcwd()
413
631
  os.chdir(user_pwd)
414
632
  self.logger.info(f"Changed working directory to: {user_pwd}")
415
- except Exception as e:
416
- self.logger.warning(f"Could not change to user directory {user_pwd}: {e}")
633
+ except PermissionError as e:
634
+ self.logger.warning(f"Permission denied accessing directory {user_pwd}: {e}")
635
+ original_cwd = None
636
+ except FileNotFoundError as e:
637
+ self.logger.warning(f"Directory not found {user_pwd}: {e}")
638
+ original_cwd = None
639
+ except OSError as e:
640
+ self.logger.warning(f"OS error changing to directory {user_pwd}: {e}")
417
641
  original_cwd = None
418
642
  else:
419
643
  original_cwd = None
@@ -523,9 +747,79 @@ class ClaudeRunner:
523
747
  })
524
748
 
525
749
  return False
526
-
750
+
751
+ except subprocess.TimeoutExpired as e:
752
+ error_msg = f"Command timed out after {e.timeout} seconds"
753
+ print(f"⏱️ {error_msg}")
754
+ if self.project_logger:
755
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
756
+ self._log_session_event({
757
+ "event": "session_timeout",
758
+ "success": False,
759
+ "timeout": e.timeout,
760
+ "exception_type": "TimeoutExpired"
761
+ })
762
+ return False
763
+
764
+ except FileNotFoundError as e:
765
+ error_msg = "Claude CLI not found. Please ensure 'claude' is installed and in your PATH"
766
+ print(f"❌ {error_msg}")
767
+ print("\n💡 To fix: Install Claude CLI with 'npm install -g @anthropic-ai/claude-ai'")
768
+ if self.project_logger:
769
+ self.project_logger.log_system(f"{error_msg}: {e}", level="ERROR", component="session")
770
+ self._log_session_event({
771
+ "event": "session_exception",
772
+ "success": False,
773
+ "exception": str(e),
774
+ "exception_type": "FileNotFoundError"
775
+ })
776
+ return False
777
+
778
+ except PermissionError as e:
779
+ error_msg = f"Permission denied executing Claude CLI: {e}"
780
+ print(f"❌ {error_msg}")
781
+ if self.project_logger:
782
+ self.project_logger.log_system(error_msg, level="ERROR", component="session")
783
+ self._log_session_event({
784
+ "event": "session_exception",
785
+ "success": False,
786
+ "exception": str(e),
787
+ "exception_type": "PermissionError"
788
+ })
789
+ return False
790
+
791
+ except KeyboardInterrupt:
792
+ print("\n⚠️ Command interrupted by user")
793
+ if self.project_logger:
794
+ self.project_logger.log_system(
795
+ "Session interrupted by user",
796
+ level="INFO",
797
+ component="session"
798
+ )
799
+ self._log_session_event({
800
+ "event": "session_interrupted",
801
+ "success": False,
802
+ "reason": "user_interrupt"
803
+ })
804
+ return False
805
+
806
+ except MemoryError as e:
807
+ error_msg = "Out of memory while processing command"
808
+ print(f"❌ {error_msg}")
809
+ if self.project_logger:
810
+ self.project_logger.log_system(f"{error_msg}: {e}", level="ERROR", component="session")
811
+ self._log_session_event({
812
+ "event": "session_exception",
813
+ "success": False,
814
+ "exception": str(e),
815
+ "exception_type": "MemoryError"
816
+ })
817
+ return False
818
+
527
819
  except Exception as e:
528
- print(f"Error: {e}")
820
+ error_msg = f"Unexpected error: {e}"
821
+ print(f"❌ {error_msg}")
822
+ print(f" Error type: {type(e).__name__}")
529
823
 
530
824
  if self.project_logger:
531
825
  self.project_logger.log_system(
@@ -580,8 +874,12 @@ class ClaudeRunner:
580
874
  print(f" ... and {len(tickets) - 3} more")
581
875
  else:
582
876
  self.logger.debug("Ticket extraction method not available")
877
+ except AttributeError as e:
878
+ self.logger.debug(f"Ticket manager missing expected method: {e}")
879
+ except TypeError as e:
880
+ self.logger.debug(f"Invalid ticket data format: {e}")
583
881
  except Exception as e:
584
- self.logger.debug(f"Ticket extraction failed: {e}")
882
+ self.logger.debug(f"Unexpected error during ticket extraction: {e}")
585
883
 
586
884
  def _load_system_instructions(self) -> Optional[str]:
587
885
  """Load and process system instructions from agents/INSTRUCTIONS.md.
@@ -714,6 +1012,9 @@ class ClaudeRunner:
714
1012
  component="command"
715
1013
  )
716
1014
  return True
1015
+ except ImportError as e:
1016
+ print(f"Error: CLI module not available: {e}")
1017
+ return False
717
1018
  except Exception as e:
718
1019
  print(f"Error getting agent versions: {e}")
719
1020
  return False
@@ -722,6 +1023,9 @@ class ClaudeRunner:
722
1023
  print("Available commands: test, agents")
723
1024
  return True
724
1025
 
1026
+ except KeyboardInterrupt:
1027
+ print("\nCommand interrupted")
1028
+ return False
725
1029
  except Exception as e:
726
1030
  print(f"Error executing command: {e}")
727
1031
  if self.project_logger:
@@ -743,6 +1047,8 @@ class ClaudeRunner:
743
1047
 
744
1048
  with open(self.session_log_file, 'a') as f:
745
1049
  f.write(json.dumps(log_entry) + '\n')
1050
+ except (OSError, IOError) as e:
1051
+ self.logger.debug(f"IO error logging session event: {e}")
746
1052
  except Exception as e:
747
1053
  self.logger.debug(f"Failed to log session event: {e}")
748
1054
 
@@ -793,14 +1099,13 @@ class ClaudeRunner:
793
1099
  # Method 3: Try reading VERSION file directly (development fallback)
794
1100
  if version == "0.0.0":
795
1101
  try:
796
- # Calculate path relative to this file
797
- version_file = Path(__file__).parent.parent.parent.parent / "VERSION"
798
- if version_file.exists():
799
- version = version_file.read_text().strip()
1102
+ # Use centralized path management for VERSION file
1103
+ if paths.version_file.exists():
1104
+ version = paths.version_file.read_text().strip()
800
1105
  method_used = "version_file"
801
1106
  self.logger.debug(f"Version obtained via VERSION file: {version}")
802
1107
  else:
803
- self.logger.debug(f"VERSION file not found at: {version_file}")
1108
+ self.logger.debug(f"VERSION file not found at: {paths.version_file}")
804
1109
  except Exception as e:
805
1110
  self.logger.warning(f"Failed to read VERSION file: {e}")
806
1111
 
@@ -832,10 +1137,14 @@ class ClaudeRunner:
832
1137
  return
833
1138
 
834
1139
  # Import hook classes (lazy import to avoid circular dependencies)
835
- from claude_mpm.hooks.memory_integration_hook import (
836
- MemoryPreDelegationHook,
837
- MemoryPostDelegationHook
838
- )
1140
+ try:
1141
+ from claude_mpm.hooks.memory_integration_hook import (
1142
+ MemoryPreDelegationHook,
1143
+ MemoryPostDelegationHook
1144
+ )
1145
+ except ImportError as e:
1146
+ self.logger.warning(f"Memory integration hooks not available: {e}")
1147
+ return
839
1148
 
840
1149
  # Register pre-delegation hook for memory injection
841
1150
  pre_hook = MemoryPreDelegationHook(self.config)
@@ -862,6 +1171,8 @@ class ClaudeRunner:
862
1171
  post_count = len(hooks.get('post_delegation', []))
863
1172
  self.logger.info(f"📋 Hook Service initialized: {pre_count} pre-delegation, {post_count} post-delegation hooks")
864
1173
 
1174
+ except AttributeError as e:
1175
+ self.logger.warning(f"Hook service not initialized properly: {e}")
865
1176
  except Exception as e:
866
1177
  self.logger.error(f"❌ Failed to register memory hooks: {e}")
867
1178
  # Don't fail the entire initialization - memory system is optional
claude_mpm/core/config.py CHANGED
@@ -11,6 +11,7 @@ from typing import Any, Dict, Optional, Union
11
11
  import logging
12
12
 
13
13
  from ..utils.config_manager import ConfigurationManager
14
+ from .config_paths import ConfigPaths
14
15
 
15
16
  logger = logging.getLogger(__name__)
16
17
 
@@ -51,6 +52,11 @@ class Config:
51
52
  # Load from file if provided
52
53
  if config_file:
53
54
  self.load_file(config_file)
55
+ else:
56
+ # Try to load from standard location: .claude-mpm/configuration.yaml
57
+ default_config = Path.cwd() / ".claude-mpm" / "configuration.yaml"
58
+ if default_config.exists():
59
+ self.load_file(default_config)
54
60
 
55
61
  # Load from environment variables (new and legacy prefixes)
56
62
  self._load_env_vars()
@@ -220,7 +226,7 @@ class Config:
220
226
  "fallback_tracking_method": "logging", # Options: "logging", "file", "disabled"
221
227
  # Evaluation system - Phase 2 Mirascope integration
222
228
  "enable_evaluation": True,
223
- "evaluation_storage_path": str(Path.home() / ".claude-pm" / "training"),
229
+ "evaluation_storage_path": str(ConfigPaths.get_user_config_dir() / "training"),
224
230
  "correction_capture_enabled": True,
225
231
  "correction_storage_rotation_days": 30,
226
232
  "evaluation_logging_enabled": True,
@@ -5,10 +5,10 @@ Manages friendly directory aliases for configuration paths, allowing users to
5
5
  reference configurations using memorable names instead of full paths.
6
6
 
7
7
  Example:
8
- claude-pm --config personal # Resolves to ~/.claude-pm/configs/personal/
8
+ claude-pm --config personal # Resolves to ~/.claude-mpm/configs/personal/
9
9
  claude-pm --config work # Resolves to ~/work/claude-configs/
10
10
 
11
- Aliases are stored in ~/.claude-pm/config_aliases.json
11
+ Aliases are stored in ~/.claude-mpm/config_aliases.json
12
12
  """
13
13
 
14
14
  import json
@@ -18,6 +18,7 @@ from pathlib import Path
18
18
  from typing import Dict, Optional, List, Tuple
19
19
 
20
20
  from ..utils.config_manager import ConfigurationManager
21
+ from .config_paths import ConfigPaths
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
 
@@ -59,7 +60,7 @@ class ConfigAliasManager:
59
60
  ~/.claude-pm/config_aliases.json
60
61
  """
61
62
  if aliases_file is None:
62
- self.aliases_file = Path.home() / ".claude-pm" / "config_aliases.json"
63
+ self.aliases_file = ConfigPaths.get_user_config_dir() / "config_aliases.json"
63
64
  else:
64
65
  self.aliases_file = Path(aliases_file)
65
66