claude-mpm 4.3.11__py3-none-any.whl → 4.3.13__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 (207) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/agents/templates/research.json +20 -8
  5. claude_mpm/agents/templates/web_qa.json +25 -10
  6. claude_mpm/cli/__init__.py +1 -0
  7. claude_mpm/cli/commands/agent_manager.py +3 -3
  8. claude_mpm/cli/commands/agents.py +2 -2
  9. claude_mpm/cli/commands/aggregate.py +1 -1
  10. claude_mpm/cli/commands/config.py +2 -2
  11. claude_mpm/cli/commands/configure.py +5 -5
  12. claude_mpm/cli/commands/configure_tui.py +7 -7
  13. claude_mpm/cli/commands/dashboard.py +1 -1
  14. claude_mpm/cli/commands/debug.py +5 -5
  15. claude_mpm/cli/commands/mcp.py +1 -1
  16. claude_mpm/cli/commands/mcp_command_router.py +12 -1
  17. claude_mpm/cli/commands/mcp_config.py +154 -0
  18. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  19. claude_mpm/cli/commands/mcp_install_commands.py +93 -24
  20. claude_mpm/cli/commands/mcp_setup_external.py +870 -0
  21. claude_mpm/cli/commands/monitor.py +2 -2
  22. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  23. claude_mpm/cli/commands/run.py +114 -0
  24. claude_mpm/cli/commands/search.py +292 -0
  25. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  26. claude_mpm/cli/parsers/base_parser.py +13 -0
  27. claude_mpm/cli/parsers/mcp_parser.py +15 -0
  28. claude_mpm/cli/parsers/run_parser.py +5 -0
  29. claude_mpm/cli/parsers/search_parser.py +245 -0
  30. claude_mpm/cli/startup_logging.py +3 -5
  31. claude_mpm/cli/utils.py +1 -1
  32. claude_mpm/constants.py +1 -0
  33. claude_mpm/core/agent_registry.py +12 -8
  34. claude_mpm/core/agent_session_manager.py +8 -8
  35. claude_mpm/core/api_validator.py +4 -4
  36. claude_mpm/core/base_service.py +10 -10
  37. claude_mpm/core/cache.py +5 -5
  38. claude_mpm/core/config_constants.py +1 -1
  39. claude_mpm/core/container.py +1 -1
  40. claude_mpm/core/error_handler.py +2 -2
  41. claude_mpm/core/file_utils.py +1 -1
  42. claude_mpm/core/framework_loader.py +3 -3
  43. claude_mpm/core/hook_manager.py +8 -6
  44. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  45. claude_mpm/core/interactive_session.py +1 -1
  46. claude_mpm/core/lazy.py +3 -3
  47. claude_mpm/core/log_manager.py +16 -12
  48. claude_mpm/core/logger.py +16 -11
  49. claude_mpm/core/logging_config.py +4 -2
  50. claude_mpm/core/oneshot_session.py +1 -1
  51. claude_mpm/core/optimized_agent_loader.py +6 -6
  52. claude_mpm/core/output_style_manager.py +1 -1
  53. claude_mpm/core/pm_hook_interceptor.py +3 -3
  54. claude_mpm/core/service_registry.py +1 -1
  55. claude_mpm/core/session_manager.py +11 -9
  56. claude_mpm/core/socketio_pool.py +13 -13
  57. claude_mpm/core/types.py +2 -2
  58. claude_mpm/core/unified_agent_registry.py +9 -2
  59. claude_mpm/core/unified_paths.py +1 -1
  60. claude_mpm/dashboard/analysis_runner.py +4 -4
  61. claude_mpm/dashboard/api/simple_directory.py +1 -1
  62. claude_mpm/generators/agent_profile_generator.py +4 -2
  63. claude_mpm/hooks/base_hook.py +2 -2
  64. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  65. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  66. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  67. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  68. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  69. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  70. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  71. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  72. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  73. claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
  74. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  75. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  76. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  77. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  78. claude_mpm/hooks/memory_integration_hook.py +1 -1
  79. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  80. claude_mpm/models/agent_session.py +5 -5
  81. claude_mpm/services/__init__.py +1 -1
  82. claude_mpm/services/agent_capabilities_service.py +1 -1
  83. claude_mpm/services/agents/agent_builder.py +3 -3
  84. claude_mpm/services/agents/deployment/agent_deployment.py +29 -13
  85. claude_mpm/services/agents/deployment/agent_discovery_service.py +22 -6
  86. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
  87. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  88. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  89. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  90. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  91. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  92. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  93. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  94. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +6 -4
  95. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  96. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  97. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  98. claude_mpm/services/agents/local_template_manager.py +6 -6
  99. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  100. claude_mpm/services/agents/memory/content_manager.py +3 -3
  101. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  102. claude_mpm/services/agents/memory/template_generator.py +3 -3
  103. claude_mpm/services/agents/registry/__init__.py +1 -1
  104. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  105. claude_mpm/services/async_session_logger.py +3 -3
  106. claude_mpm/services/claude_session_logger.py +4 -4
  107. claude_mpm/services/cli/agent_cleanup_service.py +5 -0
  108. claude_mpm/services/cli/agent_listing_service.py +1 -1
  109. claude_mpm/services/cli/agent_validation_service.py +1 -0
  110. claude_mpm/services/cli/memory_crud_service.py +11 -6
  111. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  112. claude_mpm/services/cli/session_manager.py +15 -11
  113. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  114. claude_mpm/services/core/memory_manager.py +81 -23
  115. claude_mpm/services/core/path_resolver.py +2 -2
  116. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  117. claude_mpm/services/event_aggregator.py +4 -2
  118. claude_mpm/services/event_bus/direct_relay.py +5 -3
  119. claude_mpm/services/event_bus/event_bus.py +3 -3
  120. claude_mpm/services/event_bus/relay.py +6 -4
  121. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  122. claude_mpm/services/events/core.py +3 -3
  123. claude_mpm/services/events/producers/hook.py +6 -6
  124. claude_mpm/services/events/producers/system.py +8 -8
  125. claude_mpm/services/exceptions.py +5 -5
  126. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  127. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  128. claude_mpm/services/hook_installer_service.py +1 -1
  129. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  130. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  131. claude_mpm/services/infrastructure/logging.py +2 -2
  132. claude_mpm/services/mcp_config_manager.py +439 -0
  133. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  134. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  135. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  136. claude_mpm/services/mcp_gateway/config/configuration.py +18 -1
  137. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  138. claude_mpm/services/mcp_gateway/main.py +52 -0
  139. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  140. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  141. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  142. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
  143. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  144. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  145. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +443 -0
  146. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  147. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  148. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  149. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
  150. claude_mpm/services/memory/builder.py +7 -5
  151. claude_mpm/services/memory/indexed_memory.py +4 -4
  152. claude_mpm/services/memory/optimizer.py +6 -6
  153. claude_mpm/services/memory/router.py +3 -3
  154. claude_mpm/services/monitor/daemon.py +1 -1
  155. claude_mpm/services/monitor/daemon_manager.py +6 -6
  156. claude_mpm/services/monitor/event_emitter.py +2 -2
  157. claude_mpm/services/monitor/handlers/file.py +1 -1
  158. claude_mpm/services/monitor/management/lifecycle.py +1 -1
  159. claude_mpm/services/monitor/server.py +4 -4
  160. claude_mpm/services/monitor_build_service.py +2 -2
  161. claude_mpm/services/port_manager.py +2 -2
  162. claude_mpm/services/response_tracker.py +2 -2
  163. claude_mpm/services/session_management_service.py +3 -2
  164. claude_mpm/services/socketio/client_proxy.py +2 -2
  165. claude_mpm/services/socketio/dashboard_server.py +4 -3
  166. claude_mpm/services/socketio/event_normalizer.py +12 -8
  167. claude_mpm/services/socketio/handlers/base.py +2 -2
  168. claude_mpm/services/socketio/handlers/connection.py +10 -10
  169. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  170. claude_mpm/services/socketio/handlers/file.py +1 -1
  171. claude_mpm/services/socketio/handlers/git.py +1 -1
  172. claude_mpm/services/socketio/handlers/hook.py +16 -15
  173. claude_mpm/services/socketio/migration_utils.py +1 -1
  174. claude_mpm/services/socketio/monitor_client.py +5 -5
  175. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  176. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  177. claude_mpm/services/socketio/server/core.py +7 -5
  178. claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
  179. claude_mpm/services/socketio/server/main.py +13 -13
  180. claude_mpm/services/socketio_client_manager.py +4 -4
  181. claude_mpm/services/system_instructions_service.py +2 -2
  182. claude_mpm/services/ticket_services/validation_service.py +1 -1
  183. claude_mpm/services/utility_service.py +5 -2
  184. claude_mpm/services/version_control/branch_strategy.py +2 -2
  185. claude_mpm/services/version_control/git_operations.py +22 -20
  186. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  187. claude_mpm/services/version_control/version_parser.py +7 -5
  188. claude_mpm/services/visualization/mermaid_generator.py +1 -1
  189. claude_mpm/storage/state_storage.py +1 -1
  190. claude_mpm/tools/code_tree_analyzer.py +19 -18
  191. claude_mpm/tools/code_tree_builder.py +2 -2
  192. claude_mpm/tools/code_tree_events.py +10 -8
  193. claude_mpm/tools/socketio_debug.py +3 -3
  194. claude_mpm/utils/agent_dependency_loader.py +2 -2
  195. claude_mpm/utils/dependency_strategies.py +8 -3
  196. claude_mpm/utils/environment_context.py +2 -2
  197. claude_mpm/utils/error_handler.py +2 -2
  198. claude_mpm/utils/file_utils.py +1 -1
  199. claude_mpm/utils/imports.py +1 -1
  200. claude_mpm/utils/log_cleanup.py +21 -7
  201. claude_mpm/validation/agent_validator.py +2 -2
  202. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +4 -1
  203. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +207 -200
  204. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
  205. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
  206. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
  207. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,245 @@
1
+ """
2
+ Search command parser for mcp-vector-search integration.
3
+
4
+ This module provides argument parsing for the /mpm-search command.
5
+ """
6
+
7
+ import argparse
8
+ from typing import Optional
9
+
10
+
11
+ def add_search_subparser(
12
+ subparsers: argparse._SubParsersAction,
13
+ ) -> argparse.ArgumentParser:
14
+ """
15
+ Add the search command parser.
16
+
17
+ Args:
18
+ subparsers: The subparsers action to add the search parser to.
19
+
20
+ Returns:
21
+ The created search parser.
22
+ """
23
+ search_parser = subparsers.add_parser(
24
+ "mpm-search",
25
+ aliases=["search"],
26
+ help="Search codebase using semantic search",
27
+ description=(
28
+ "Search the codebase using semantic search powered by mcp-vector-search. "
29
+ "Can search by query, find similar code, search by context, or manage the search index."
30
+ ),
31
+ formatter_class=argparse.RawDescriptionHelpFormatter,
32
+ epilog="""
33
+ Examples:
34
+ # Search for code by query
35
+ claude-mpm mpm-search "authentication logic"
36
+
37
+ # Find code similar to a file
38
+ claude-mpm mpm-search --similar src/auth.py
39
+
40
+ # Search by contextual description
41
+ claude-mpm mpm-search --context "find all API endpoints"
42
+
43
+ # Index the project (required before searching)
44
+ claude-mpm mpm-search --index
45
+
46
+ # Force reindex the project
47
+ claude-mpm mpm-search --index --force
48
+
49
+ # Check index status
50
+ claude-mpm mpm-search --status
51
+
52
+ # Search with filters
53
+ claude-mpm mpm-search "database" --language python --limit 20
54
+
55
+ # Search with multiple file extensions
56
+ claude-mpm mpm-search "test" --extensions .py --extensions .js
57
+
58
+ # Find similar code to a specific function
59
+ claude-mpm mpm-search --similar src/auth.py --function authenticate_user
60
+
61
+ # Search with context and focus areas
62
+ claude-mpm mpm-search --context "security vulnerabilities" --focus authentication --focus encryption
63
+
64
+ # Output as JSON for processing
65
+ claude-mpm mpm-search "api" --json
66
+ """,
67
+ )
68
+
69
+ # Primary search modes (mutually exclusive)
70
+ search_mode = search_parser.add_mutually_exclusive_group()
71
+
72
+ search_mode.add_argument(
73
+ "query",
74
+ nargs="?",
75
+ help="Search query for semantic code search",
76
+ )
77
+
78
+ search_mode.add_argument(
79
+ "--similar",
80
+ "-s",
81
+ metavar="FILE",
82
+ help="Find code similar to the specified file",
83
+ )
84
+
85
+ search_mode.add_argument(
86
+ "--context",
87
+ "-c",
88
+ metavar="DESCRIPTION",
89
+ help="Search by contextual description of what you're looking for",
90
+ )
91
+
92
+ # Index management options
93
+ search_parser.add_argument(
94
+ "--index",
95
+ action="store_true",
96
+ help="Index or reindex the project codebase",
97
+ )
98
+
99
+ search_parser.add_argument(
100
+ "--status",
101
+ action="store_true",
102
+ help="Check project indexing status and statistics",
103
+ )
104
+
105
+ # Search filters and options
106
+ search_parser.add_argument(
107
+ "--limit",
108
+ "-l",
109
+ type=int,
110
+ default=10,
111
+ metavar="N",
112
+ help="Maximum number of results to return (default: 10, max: 50)",
113
+ )
114
+
115
+ search_parser.add_argument(
116
+ "--threshold",
117
+ "-t",
118
+ type=float,
119
+ default=0.3,
120
+ metavar="SCORE",
121
+ help="Similarity threshold between 0.0 and 1.0 (default: 0.3)",
122
+ )
123
+
124
+ search_parser.add_argument(
125
+ "--language",
126
+ metavar="LANG",
127
+ help="Filter by programming language (e.g., python, javascript, go)",
128
+ )
129
+
130
+ search_parser.add_argument(
131
+ "--extensions",
132
+ action="append",
133
+ metavar="EXT",
134
+ help="Filter by file extensions (e.g., .py, .js). Can be specified multiple times",
135
+ )
136
+
137
+ # Options for --similar mode
138
+ search_parser.add_argument(
139
+ "--function",
140
+ "-f",
141
+ metavar="NAME",
142
+ help="Function name within the file (used with --similar)",
143
+ )
144
+
145
+ # Options for --context mode
146
+ search_parser.add_argument(
147
+ "--focus",
148
+ action="append",
149
+ metavar="AREA",
150
+ help="Focus areas for contextual search (e.g., security, performance). Can be specified multiple times",
151
+ )
152
+
153
+ # Options for --index mode
154
+ search_parser.add_argument(
155
+ "--force",
156
+ action="store_true",
157
+ help="Force reindexing even if index already exists (used with --index)",
158
+ )
159
+
160
+ # Output options
161
+ search_parser.add_argument(
162
+ "--json",
163
+ action="store_true",
164
+ dest="output_json",
165
+ help="Output results as JSON instead of formatted text",
166
+ )
167
+
168
+ # Additional filters
169
+ search_parser.add_argument(
170
+ "--class",
171
+ dest="class_name",
172
+ metavar="NAME",
173
+ help="Filter by class name",
174
+ )
175
+
176
+ search_parser.add_argument(
177
+ "--files",
178
+ metavar="PATTERN",
179
+ help="Filter by file patterns (e.g., '*.py' or 'src/*.js')",
180
+ )
181
+
182
+ # Verbose output
183
+ search_parser.add_argument(
184
+ "-v",
185
+ "--verbose",
186
+ action="store_true",
187
+ help="Enable verbose output with additional details",
188
+ )
189
+
190
+ return search_parser
191
+
192
+
193
+ def validate_search_args(args: argparse.Namespace) -> Optional[str]: # noqa: PLR0911
194
+ """
195
+ Validate search command arguments.
196
+
197
+ Args:
198
+ args: Parsed command line arguments.
199
+
200
+ Returns:
201
+ Error message if validation fails, None otherwise.
202
+ """
203
+ # Check threshold is in valid range
204
+ if hasattr(args, "threshold") and args.threshold is not None:
205
+ if not 0.0 <= args.threshold <= 1.0:
206
+ return "Similarity threshold must be between 0.0 and 1.0"
207
+
208
+ # Check limit is reasonable
209
+ if hasattr(args, "limit") and args.limit is not None:
210
+ if args.limit < 1:
211
+ return "Limit must be at least 1"
212
+ if args.limit > 50:
213
+ return "Limit cannot exceed 50"
214
+
215
+ # Check that function is only used with --similar
216
+ if (
217
+ hasattr(args, "function")
218
+ and args.function
219
+ and not getattr(args, "similar", None)
220
+ ):
221
+ return "--function can only be used with --similar"
222
+
223
+ # Check that focus is only used with --context
224
+ if hasattr(args, "focus") and args.focus and not getattr(args, "context", None):
225
+ return "--focus can only be used with --context"
226
+
227
+ # Check that force is only used with --index
228
+ if hasattr(args, "force") and args.force and not getattr(args, "index", False):
229
+ return "--force can only be used with --index"
230
+
231
+ # Ensure at least one operation is specified
232
+ if hasattr(args, "command") and args.command in ["mpm-search", "search"]:
233
+ has_operation = any(
234
+ [
235
+ getattr(args, "query", None),
236
+ getattr(args, "similar", None),
237
+ getattr(args, "context", None),
238
+ getattr(args, "index", False),
239
+ getattr(args, "status", False),
240
+ ]
241
+ )
242
+ if not has_operation:
243
+ return "No search operation specified. Use --help for options."
244
+
245
+ return None
@@ -69,7 +69,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
69
69
  f"{prefix}: RSS={rss_mb:.1f}MB, System={memory_percent:.1f}%"
70
70
  )
71
71
  return {"rss_mb": rss_mb, "vms_mb": None, "percent": memory_percent}
72
- except:
72
+ except Exception:
73
73
  logger.info(f"{prefix}: RSS={rss_mb:.1f}MB")
74
74
  return {"rss_mb": rss_mb, "vms_mb": None, "percent": None}
75
75
  else:
@@ -82,7 +82,7 @@ def log_memory_stats(logger=None, prefix="Memory Usage"):
82
82
  f"System={memory_percent:.1f}%"
83
83
  )
84
84
  return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": memory_percent}
85
- except:
85
+ except Exception:
86
86
  logger.info(f"{prefix}: RSS={rss_mb:.1f}MB, VMS={vms_mb:.1f}MB")
87
87
  return {"rss_mb": rss_mb, "vms_mb": vms_mb, "percent": None}
88
88
 
@@ -114,12 +114,10 @@ class StartupStatusLogger:
114
114
  if mcp_executable:
115
115
  self.logger.info(f"MCP Server: Installed at {mcp_executable}")
116
116
 
117
- # Try to get version
117
+ # Try to get version (only log if version is found)
118
118
  version = self._get_mcp_version(mcp_executable)
119
119
  if version:
120
120
  self.logger.info(f"MCP Server: Version {version}")
121
- else:
122
- self.logger.info("MCP Server: Version unknown")
123
121
  else:
124
122
  self.logger.info("MCP Server: Not found in PATH")
125
123
 
claude_mpm/cli/utils.py CHANGED
@@ -106,7 +106,7 @@ def get_agent_versions_display() -> Optional[str]:
106
106
  base_version_tuple
107
107
  )
108
108
  output_lines.append(f"\n Base Agent Version: {base_version_str}")
109
- except:
109
+ except Exception:
110
110
  pass
111
111
 
112
112
  # Check for agents needing migration
claude_mpm/constants.py CHANGED
@@ -140,6 +140,7 @@ class MCPCommands(str, Enum):
140
140
  TEST = "test"
141
141
  CONFIG = "config"
142
142
  SERVER = "server"
143
+ EXTERNAL = "external"
143
144
 
144
145
 
145
146
  class TicketCommands(str, Enum):
@@ -14,23 +14,27 @@ This module provides:
14
14
  import contextlib
15
15
  import warnings
16
16
  from dataclasses import dataclass
17
- from datetime import datetime
17
+ from datetime import datetime, timezone
18
18
  from pathlib import Path
19
19
  from typing import Any, Dict, List, Optional, Set
20
20
 
21
21
  # Import from the unified agent registry system
22
+ from .unified_agent_registry import AgentMetadata as UnifiedAgentMetadata
22
23
  from .unified_agent_registry import (
23
- AgentMetadata as UnifiedAgentMetadata,
24
24
  AgentTier,
25
25
  AgentType,
26
- discover_agents as unified_discover_agents,
27
- get_agent as unified_get_agent,
26
+ )
27
+ from .unified_agent_registry import discover_agents as unified_discover_agents
28
+ from .unified_agent_registry import get_agent as unified_get_agent
29
+ from .unified_agent_registry import (
28
30
  get_agent_registry,
29
- get_core_agents as unified_get_core_agents,
30
- get_registry_stats as unified_get_registry_stats,
31
+ )
32
+ from .unified_agent_registry import get_core_agents as unified_get_core_agents
33
+ from .unified_agent_registry import get_registry_stats as unified_get_registry_stats
34
+ from .unified_agent_registry import (
31
35
  get_specialized_agents as unified_get_specialized_agents,
32
- list_agents as unified_list_agents,
33
36
  )
37
+ from .unified_agent_registry import list_agents as unified_list_agents
34
38
 
35
39
  try:
36
40
  from ..core.logger import get_logger
@@ -379,7 +383,7 @@ class AgentRegistryAdapter:
379
383
  }
380
384
 
381
385
  nickname = nicknames.get(agent_name, agent_name.title())
382
- today = datetime.now().strftime("%Y-%m-%d")
386
+ today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
383
387
 
384
388
  return f"""**{nickname}**: {task}
385
389
 
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  import uuid
5
5
  from collections import defaultdict
6
- from datetime import datetime, timedelta
6
+ from datetime import datetime, timedelta, timezone
7
7
  from pathlib import Path
8
8
  from typing import Dict, Optional
9
9
 
@@ -53,10 +53,10 @@ class AgentSessionManager:
53
53
  if not self.session_locks.get(session_id, False):
54
54
  # Check if session is still fresh (not too old)
55
55
  created = datetime.fromisoformat(session_data["created_at"])
56
- if datetime.now() - created < timedelta(hours=1):
56
+ if datetime.now(timezone.utc) - created < timedelta(hours=1):
57
57
  # Use this session
58
58
  self.session_locks[session_id] = True
59
- session_data["last_used"] = datetime.now().isoformat()
59
+ session_data["last_used"] = datetime.now(timezone.utc).isoformat()
60
60
  session_data["use_count"] += 1
61
61
  logger.info(f"Reusing session {session_id} for {agent_type} agent")
62
62
  return session_id
@@ -85,8 +85,8 @@ class AgentSessionManager:
85
85
  session_data = {
86
86
  "id": session_id,
87
87
  "agent_type": agent_type,
88
- "created_at": datetime.now().isoformat(),
89
- "last_used": datetime.now().isoformat(),
88
+ "created_at": datetime.now(timezone.utc).isoformat(),
89
+ "last_used": datetime.now(timezone.utc).isoformat(),
90
90
  "use_count": 0,
91
91
  "tasks_completed": [],
92
92
  }
@@ -122,7 +122,7 @@ class AgentSessionManager:
122
122
  sessions[session_id]["tasks_completed"].append(
123
123
  {
124
124
  "task": task[:100], # Truncate long tasks
125
- "timestamp": datetime.now().isoformat(),
125
+ "timestamp": datetime.now(timezone.utc).isoformat(),
126
126
  "success": success,
127
127
  }
128
128
  )
@@ -135,7 +135,7 @@ class AgentSessionManager:
135
135
  Args:
136
136
  max_age_hours: Maximum age in hours
137
137
  """
138
- now = datetime.now()
138
+ now = datetime.now(timezone.utc)
139
139
  max_age = timedelta(hours=max_age_hours)
140
140
 
141
141
  for agent_type in list(self.agent_sessions.keys()):
@@ -207,7 +207,7 @@ class AgentSessionManager:
207
207
  try:
208
208
  data = {
209
209
  "agent_sessions": dict(self.agent_sessions),
210
- "updated_at": datetime.now().isoformat(),
210
+ "updated_at": datetime.now(timezone.utc).isoformat(),
211
211
  }
212
212
  with open(session_file, "w") as f:
213
213
  json.dump(data, f, indent=2)
@@ -84,7 +84,7 @@ class APIKeyValidator:
84
84
 
85
85
  return not bool(self.errors), self.errors, self.warnings
86
86
 
87
- def _validate_openai_key(self, api_key: str) -> bool:
87
+ def _validate_openai_key(self, api_key: str) -> bool: # noqa: PLR0911
88
88
  """Validate OpenAI API key.
89
89
 
90
90
  Args:
@@ -133,7 +133,7 @@ class APIKeyValidator:
133
133
  self.errors.append(f"❌ OpenAI API validation failed with error: {e}")
134
134
  return False
135
135
 
136
- def _validate_anthropic_key(self, api_key: str) -> bool:
136
+ def _validate_anthropic_key(self, api_key: str) -> bool: # noqa: PLR0911
137
137
  """Validate Anthropic API key.
138
138
 
139
139
  Args:
@@ -196,7 +196,7 @@ class APIKeyValidator:
196
196
  self.errors.append(f"❌ Anthropic API validation failed with error: {e}")
197
197
  return False
198
198
 
199
- def _validate_github_token(self, token: str) -> bool:
199
+ def _validate_github_token(self, token: str) -> bool: # noqa: PLR0911
200
200
  """Validate GitHub personal access token.
201
201
 
202
202
  Args:
@@ -244,7 +244,7 @@ class APIKeyValidator:
244
244
  self.errors.append(f"❌ GitHub token validation failed with error: {e}")
245
245
  return False
246
246
 
247
- def _validate_custom_api(self, api_name: str, validation_config: Dict) -> bool:
247
+ def _validate_custom_api(self, api_name: str, validation_config: Dict) -> bool: # noqa: PLR0911
248
248
  """Validate a custom API key based on configuration.
249
249
 
250
250
  Args:
@@ -26,7 +26,7 @@ import traceback
26
26
  from abc import ABC, abstractmethod
27
27
  from contextlib import asynccontextmanager
28
28
  from dataclasses import dataclass, field
29
- from datetime import datetime, timedelta
29
+ from datetime import datetime, timedelta, timezone
30
30
  from pathlib import Path
31
31
  from typing import Any, Dict, List, Optional
32
32
 
@@ -144,7 +144,7 @@ class BaseService(LoggerMixin, ABC):
144
144
  self._health = ServiceHealth(
145
145
  status="unknown",
146
146
  message="Service not started",
147
- timestamp=datetime.now().isoformat(),
147
+ timestamp=datetime.now(timezone.utc).isoformat(),
148
148
  )
149
149
  self._metrics = ServiceMetrics()
150
150
  self._last_health_check: Optional[float] = None
@@ -199,7 +199,7 @@ class BaseService(LoggerMixin, ABC):
199
199
  def uptime(self) -> Optional[float]:
200
200
  """Get service uptime in seconds."""
201
201
  if self._start_time and self._running:
202
- return (datetime.now() - self._start_time).total_seconds()
202
+ return (datetime.now(timezone.utc) - self._start_time).total_seconds()
203
203
  return None
204
204
 
205
205
  @property
@@ -237,7 +237,7 @@ class BaseService(LoggerMixin, ABC):
237
237
  self._health = ServiceHealth(
238
238
  status="unhealthy",
239
239
  message=f"Startup failed: {e!s}",
240
- timestamp=datetime.now().isoformat(),
240
+ timestamp=datetime.now(timezone.utc).isoformat(),
241
241
  checks={"startup": False},
242
242
  )
243
243
 
@@ -268,13 +268,13 @@ class BaseService(LoggerMixin, ABC):
268
268
 
269
269
  # Mark as running
270
270
  self._running = True
271
- self._start_time = datetime.now()
271
+ self._start_time = datetime.now(timezone.utc)
272
272
 
273
273
  # Update health status
274
274
  self._health = ServiceHealth(
275
275
  status="healthy",
276
276
  message="Service started successfully",
277
- timestamp=datetime.now().isoformat(),
277
+ timestamp=datetime.now(timezone.utc).isoformat(),
278
278
  checks={"startup": True},
279
279
  metrics=self._get_health_metrics() if self._enable_enhanced else {},
280
280
  )
@@ -338,7 +338,7 @@ class BaseService(LoggerMixin, ABC):
338
338
  self._health = ServiceHealth(
339
339
  status="unknown",
340
340
  message="Service stopped",
341
- timestamp=datetime.now().isoformat(),
341
+ timestamp=datetime.now(timezone.utc).isoformat(),
342
342
  checks={"running": False},
343
343
  )
344
344
 
@@ -388,7 +388,7 @@ class BaseService(LoggerMixin, ABC):
388
388
  self._health = ServiceHealth(
389
389
  status=status,
390
390
  message=message,
391
- timestamp=datetime.now().isoformat(),
391
+ timestamp=datetime.now(timezone.utc).isoformat(),
392
392
  checks=checks,
393
393
  metrics={
394
394
  "uptime": self.uptime,
@@ -404,7 +404,7 @@ class BaseService(LoggerMixin, ABC):
404
404
  self._health = ServiceHealth(
405
405
  status="unhealthy",
406
406
  message=f"Health check error: {e!s}",
407
- timestamp=datetime.now().isoformat(),
407
+ timestamp=datetime.now(timezone.utc).isoformat(),
408
408
  checks={"health_check_error": True},
409
409
  )
410
410
  return self._health
@@ -586,7 +586,7 @@ class BaseService(LoggerMixin, ABC):
586
586
  return ServiceHealth(
587
587
  status="degraded",
588
588
  message="Service circuit breaker is open",
589
- timestamp=datetime.now().isoformat(),
589
+ timestamp=datetime.now(timezone.utc).isoformat(),
590
590
  checks={"circuit_breaker": False},
591
591
  metrics=self._get_health_metrics(),
592
592
  )
claude_mpm/core/cache.py CHANGED
@@ -19,7 +19,7 @@ import pickle
19
19
  import threading
20
20
  from collections import OrderedDict
21
21
  from dataclasses import dataclass, field
22
- from datetime import datetime
22
+ from datetime import datetime, timezone
23
23
  from typing import Any, Callable, Dict, Optional, TypeVar, Union
24
24
 
25
25
  from ..core.logger import get_logger
@@ -43,12 +43,12 @@ class CacheEntry:
43
43
  """Check if entry has expired based on TTL."""
44
44
  if self.ttl is None:
45
45
  return False
46
- age = (datetime.now() - self.created_at).total_seconds()
46
+ age = (datetime.now(timezone.utc) - self.created_at).total_seconds()
47
47
  return age > self.ttl
48
48
 
49
49
  def touch(self):
50
50
  """Update last access time and increment counter."""
51
- self.last_accessed = datetime.now()
51
+ self.last_accessed = datetime.now(timezone.utc)
52
52
  self.access_count += 1
53
53
 
54
54
 
@@ -129,13 +129,13 @@ class FileSystemCache:
129
129
  # Rough estimate using JSON serialization
130
130
  try:
131
131
  return len(json.dumps(value))
132
- except:
132
+ except Exception:
133
133
  return 1000 # Default estimate
134
134
  else:
135
135
  # Use pickle for size estimation
136
136
  try:
137
137
  return len(pickle.dumps(value))
138
- except:
138
+ except Exception:
139
139
  return 100 # Default small size
140
140
 
141
141
  def _evict_lru(self):
@@ -99,7 +99,7 @@ class ConfigConstants:
99
99
  cls._config_service = config_service
100
100
 
101
101
  @classmethod
102
- def get_timeout(cls, timeout_type: str) -> int:
102
+ def get_timeout(cls, timeout_type: str) -> int: # noqa: PLR0911
103
103
  """
104
104
  Get timeout value by type.
105
105
 
@@ -636,7 +636,7 @@ class DIContainer(IServiceContainer):
636
636
  if reg_type.__name__ == param_type:
637
637
  param_type = reg_type
638
638
  break
639
- except:
639
+ except Exception:
640
640
  # If we can't resolve, skip this parameter
641
641
  if param.default != param.empty:
642
642
  kwargs[param_name] = param.default
@@ -384,7 +384,7 @@ def with_error_handling(
384
384
  if callable(fallback_value):
385
385
  try:
386
386
  fb_value = fallback_value(*args, **kwargs)
387
- except:
387
+ except Exception:
388
388
  fb_value = None
389
389
 
390
390
  return handle_error(
@@ -428,7 +428,7 @@ def safe_operation(
428
428
  if callable(fallback_value):
429
429
  try:
430
430
  return fallback_value(*args, **kwargs)
431
- except:
431
+ except Exception:
432
432
  return None
433
433
  return fallback_value
434
434
 
@@ -652,7 +652,7 @@ def file_lock(filepath: Union[str, Path], timeout: float = 5.0):
652
652
  fcntl.flock(lock_handle, fcntl.LOCK_UN)
653
653
  lock_handle.close()
654
654
  lock_file.unlink(missing_ok=True)
655
- except:
655
+ except Exception:
656
656
  pass
657
657
 
658
658
 
@@ -6,7 +6,7 @@ import logging
6
6
  import os
7
7
  import platform
8
8
  import time
9
- from datetime import datetime
9
+ from datetime import datetime, timezone
10
10
  from pathlib import Path
11
11
  from typing import Any, Dict, Optional
12
12
 
@@ -1432,7 +1432,7 @@ Extract tickets from these patterns:
1432
1432
 
1433
1433
  try:
1434
1434
  # Get current datetime with timezone awareness
1435
- now = datetime.now()
1435
+ now = datetime.now(timezone.utc)
1436
1436
 
1437
1437
  # Try to get timezone info - fallback to UTC offset if timezone name not available
1438
1438
  try:
@@ -1470,7 +1470,7 @@ Extract tickets from these patterns:
1470
1470
  # Fallback to basic date if enhanced datetime fails
1471
1471
  self.logger.debug(f"Error generating enhanced datetime context: {e}")
1472
1472
  context_lines.append(
1473
- f"**Today's Date**: {datetime.now().strftime('%Y-%m-%d')}\n"
1473
+ f"**Today's Date**: {datetime.now(timezone.utc).strftime('%Y-%m-%d')}\n"
1474
1474
  )
1475
1475
 
1476
1476
  try: