claude-mpm 0.3.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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (159) hide show
  1. claude_mpm/__init__.py +17 -0
  2. claude_mpm/__main__.py +14 -0
  3. claude_mpm/_version.py +32 -0
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +88 -0
  5. claude_mpm/agents/INSTRUCTIONS.md +375 -0
  6. claude_mpm/agents/__init__.py +118 -0
  7. claude_mpm/agents/agent_loader.py +621 -0
  8. claude_mpm/agents/agent_loader_integration.py +229 -0
  9. claude_mpm/agents/agents_metadata.py +204 -0
  10. claude_mpm/agents/base_agent.json +27 -0
  11. claude_mpm/agents/base_agent_loader.py +519 -0
  12. claude_mpm/agents/schema/agent_schema.json +160 -0
  13. claude_mpm/agents/system_agent_config.py +587 -0
  14. claude_mpm/agents/templates/__init__.py +101 -0
  15. claude_mpm/agents/templates/data_engineer_agent.json +46 -0
  16. claude_mpm/agents/templates/documentation_agent.json +45 -0
  17. claude_mpm/agents/templates/engineer_agent.json +49 -0
  18. claude_mpm/agents/templates/ops_agent.json +46 -0
  19. claude_mpm/agents/templates/qa_agent.json +45 -0
  20. claude_mpm/agents/templates/research_agent.json +49 -0
  21. claude_mpm/agents/templates/security_agent.json +46 -0
  22. claude_mpm/agents/templates/update-optimized-specialized-agents.json +374 -0
  23. claude_mpm/agents/templates/version_control_agent.json +46 -0
  24. claude_mpm/agents/test_fix_deployment/.claude-pm/config/project.json +6 -0
  25. claude_mpm/cli.py +655 -0
  26. claude_mpm/cli_main.py +13 -0
  27. claude_mpm/cli_module/__init__.py +15 -0
  28. claude_mpm/cli_module/args.py +222 -0
  29. claude_mpm/cli_module/commands.py +203 -0
  30. claude_mpm/cli_module/migration_example.py +183 -0
  31. claude_mpm/cli_module/refactoring_guide.md +253 -0
  32. claude_mpm/cli_old/__init__.py +1 -0
  33. claude_mpm/cli_old/ticket_cli.py +102 -0
  34. claude_mpm/config/__init__.py +5 -0
  35. claude_mpm/config/hook_config.py +42 -0
  36. claude_mpm/constants.py +150 -0
  37. claude_mpm/core/__init__.py +45 -0
  38. claude_mpm/core/agent_name_normalizer.py +248 -0
  39. claude_mpm/core/agent_registry.py +627 -0
  40. claude_mpm/core/agent_registry.py.bak +312 -0
  41. claude_mpm/core/agent_session_manager.py +273 -0
  42. claude_mpm/core/base_service.py +747 -0
  43. claude_mpm/core/base_service.py.bak +406 -0
  44. claude_mpm/core/config.py +334 -0
  45. claude_mpm/core/config_aliases.py +292 -0
  46. claude_mpm/core/container.py +347 -0
  47. claude_mpm/core/factories.py +281 -0
  48. claude_mpm/core/framework_loader.py +472 -0
  49. claude_mpm/core/injectable_service.py +206 -0
  50. claude_mpm/core/interfaces.py +539 -0
  51. claude_mpm/core/logger.py +468 -0
  52. claude_mpm/core/minimal_framework_loader.py +107 -0
  53. claude_mpm/core/mixins.py +150 -0
  54. claude_mpm/core/service_registry.py +299 -0
  55. claude_mpm/core/session_manager.py +190 -0
  56. claude_mpm/core/simple_runner.py +511 -0
  57. claude_mpm/core/tool_access_control.py +173 -0
  58. claude_mpm/hooks/README.md +243 -0
  59. claude_mpm/hooks/__init__.py +5 -0
  60. claude_mpm/hooks/base_hook.py +154 -0
  61. claude_mpm/hooks/builtin/__init__.py +1 -0
  62. claude_mpm/hooks/builtin/logging_hook_example.py +165 -0
  63. claude_mpm/hooks/builtin/post_delegation_hook_example.py +124 -0
  64. claude_mpm/hooks/builtin/pre_delegation_hook_example.py +125 -0
  65. claude_mpm/hooks/builtin/submit_hook_example.py +100 -0
  66. claude_mpm/hooks/builtin/ticket_extraction_hook_example.py +237 -0
  67. claude_mpm/hooks/builtin/todo_agent_prefix_hook.py +239 -0
  68. claude_mpm/hooks/builtin/workflow_start_hook.py +181 -0
  69. claude_mpm/hooks/hook_client.py +264 -0
  70. claude_mpm/hooks/hook_runner.py +370 -0
  71. claude_mpm/hooks/json_rpc_executor.py +259 -0
  72. claude_mpm/hooks/json_rpc_hook_client.py +319 -0
  73. claude_mpm/hooks/tool_call_interceptor.py +204 -0
  74. claude_mpm/init.py +246 -0
  75. claude_mpm/orchestration/SUBPROCESS_DESIGN.md +66 -0
  76. claude_mpm/orchestration/__init__.py +6 -0
  77. claude_mpm/orchestration/archive/direct_orchestrator.py +195 -0
  78. claude_mpm/orchestration/archive/factory.py +215 -0
  79. claude_mpm/orchestration/archive/hook_enabled_orchestrator.py +188 -0
  80. claude_mpm/orchestration/archive/hook_integration_example.py +178 -0
  81. claude_mpm/orchestration/archive/interactive_subprocess_orchestrator.py +826 -0
  82. claude_mpm/orchestration/archive/orchestrator.py +501 -0
  83. claude_mpm/orchestration/archive/pexpect_orchestrator.py +252 -0
  84. claude_mpm/orchestration/archive/pty_orchestrator.py +270 -0
  85. claude_mpm/orchestration/archive/simple_orchestrator.py +82 -0
  86. claude_mpm/orchestration/archive/subprocess_orchestrator.py +801 -0
  87. claude_mpm/orchestration/archive/system_prompt_orchestrator.py +278 -0
  88. claude_mpm/orchestration/archive/wrapper_orchestrator.py +187 -0
  89. claude_mpm/scripts/__init__.py +1 -0
  90. claude_mpm/scripts/ticket.py +269 -0
  91. claude_mpm/services/__init__.py +10 -0
  92. claude_mpm/services/agent_deployment.py +955 -0
  93. claude_mpm/services/agent_lifecycle_manager.py +948 -0
  94. claude_mpm/services/agent_management_service.py +596 -0
  95. claude_mpm/services/agent_modification_tracker.py +841 -0
  96. claude_mpm/services/agent_profile_loader.py +606 -0
  97. claude_mpm/services/agent_registry.py +677 -0
  98. claude_mpm/services/base_agent_manager.py +380 -0
  99. claude_mpm/services/framework_agent_loader.py +337 -0
  100. claude_mpm/services/framework_claude_md_generator/README.md +92 -0
  101. claude_mpm/services/framework_claude_md_generator/__init__.py +206 -0
  102. claude_mpm/services/framework_claude_md_generator/content_assembler.py +151 -0
  103. claude_mpm/services/framework_claude_md_generator/content_validator.py +126 -0
  104. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +137 -0
  105. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +106 -0
  106. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +582 -0
  107. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +97 -0
  108. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +27 -0
  109. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +23 -0
  110. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +23 -0
  111. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +20 -0
  112. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +26 -0
  113. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +30 -0
  114. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +37 -0
  115. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +111 -0
  116. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +89 -0
  117. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +39 -0
  118. claude_mpm/services/framework_claude_md_generator/section_manager.py +106 -0
  119. claude_mpm/services/framework_claude_md_generator/version_manager.py +121 -0
  120. claude_mpm/services/framework_claude_md_generator.py +621 -0
  121. claude_mpm/services/hook_service.py +388 -0
  122. claude_mpm/services/hook_service_manager.py +223 -0
  123. claude_mpm/services/json_rpc_hook_manager.py +92 -0
  124. claude_mpm/services/parent_directory_manager/README.md +83 -0
  125. claude_mpm/services/parent_directory_manager/__init__.py +577 -0
  126. claude_mpm/services/parent_directory_manager/backup_manager.py +258 -0
  127. claude_mpm/services/parent_directory_manager/config_manager.py +210 -0
  128. claude_mpm/services/parent_directory_manager/deduplication_manager.py +279 -0
  129. claude_mpm/services/parent_directory_manager/framework_protector.py +143 -0
  130. claude_mpm/services/parent_directory_manager/operations.py +186 -0
  131. claude_mpm/services/parent_directory_manager/state_manager.py +624 -0
  132. claude_mpm/services/parent_directory_manager/template_deployer.py +579 -0
  133. claude_mpm/services/parent_directory_manager/validation_manager.py +378 -0
  134. claude_mpm/services/parent_directory_manager/version_control_helper.py +339 -0
  135. claude_mpm/services/parent_directory_manager/version_manager.py +222 -0
  136. claude_mpm/services/shared_prompt_cache.py +819 -0
  137. claude_mpm/services/ticket_manager.py +213 -0
  138. claude_mpm/services/ticket_manager_di.py +318 -0
  139. claude_mpm/services/ticketing_service_original.py +508 -0
  140. claude_mpm/services/version_control/VERSION +1 -0
  141. claude_mpm/services/version_control/__init__.py +70 -0
  142. claude_mpm/services/version_control/branch_strategy.py +670 -0
  143. claude_mpm/services/version_control/conflict_resolution.py +744 -0
  144. claude_mpm/services/version_control/git_operations.py +784 -0
  145. claude_mpm/services/version_control/semantic_versioning.py +703 -0
  146. claude_mpm/ui/__init__.py +1 -0
  147. claude_mpm/ui/rich_terminal_ui.py +295 -0
  148. claude_mpm/ui/terminal_ui.py +328 -0
  149. claude_mpm/utils/__init__.py +16 -0
  150. claude_mpm/utils/config_manager.py +468 -0
  151. claude_mpm/utils/import_migration_example.py +80 -0
  152. claude_mpm/utils/imports.py +182 -0
  153. claude_mpm/utils/path_operations.py +357 -0
  154. claude_mpm/utils/paths.py +289 -0
  155. claude_mpm-0.3.0.dist-info/METADATA +290 -0
  156. claude_mpm-0.3.0.dist-info/RECORD +159 -0
  157. claude_mpm-0.3.0.dist-info/WHEEL +5 -0
  158. claude_mpm-0.3.0.dist-info/entry_points.txt +4 -0
  159. claude_mpm-0.3.0.dist-info/top_level.txt +1 -0
claude_mpm/cli.py ADDED
@@ -0,0 +1,655 @@
1
+ """Command-line interface for Claude MPM."""
2
+
3
+ import argparse
4
+ import sys
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ try:
9
+ # Try relative imports first (when used as package)
10
+ from ._version import __version__
11
+ from .core.logger import get_logger, setup_logging
12
+ from .services.json_rpc_hook_manager import JSONRPCHookManager
13
+ from .constants import CLICommands, CLIPrefix, AgentCommands, LogLevel, CLIFlags
14
+ except ImportError:
15
+ # Fall back to absolute imports (when run directly)
16
+ from claude_mpm._version import __version__
17
+ from core.logger import get_logger, setup_logging
18
+ from services.json_rpc_hook_manager import JSONRPCHookManager
19
+ from constants import CLICommands, CLIPrefix, AgentCommands, LogLevel, CLIFlags
20
+
21
+
22
+
23
+ def _preprocess_args(argv: Optional[list] = None) -> list:
24
+ """Preprocess arguments to handle --mpm: prefix commands."""
25
+ if argv is None:
26
+ argv = sys.argv[1:]
27
+
28
+ # Convert --mpm:command to command for argparse compatibility
29
+ processed_args = []
30
+ for i, arg in enumerate(argv):
31
+ if arg.startswith(CLIPrefix.MPM.value):
32
+ # Extract command after prefix
33
+ command = arg[len(CLIPrefix.MPM.value):]
34
+ processed_args.append(command)
35
+ else:
36
+ processed_args.append(arg)
37
+
38
+ return processed_args
39
+
40
+
41
+ def main(argv: Optional[list] = None):
42
+ """Main CLI entry point."""
43
+ # Ensure directories are initialized on first run
44
+ try:
45
+ from .init import ensure_directories
46
+ ensure_directories()
47
+ except Exception:
48
+ # Continue even if initialization fails
49
+ pass
50
+
51
+ parser = argparse.ArgumentParser(
52
+ prog="claude-mpm",
53
+ description=f"Claude Multi-Agent Project Manager v{__version__} - Orchestrate Claude with agent delegation and ticket tracking",
54
+ epilog="By default, runs an orchestrated Claude session. Use 'claude-mpm' for interactive mode or 'claude-mpm -i \"prompt\"' for non-interactive mode.\n\nTo pass arguments to Claude CLI, use -- separator: claude-mpm run -- --model sonnet --temperature 0.1"
55
+ )
56
+
57
+ # Version
58
+ parser.add_argument(
59
+ "--version",
60
+ action="version",
61
+ version=f"claude-mpm {__version__}"
62
+ )
63
+
64
+ # Global options
65
+ parser.add_argument(
66
+ "-d", "--debug",
67
+ action="store_true",
68
+ help="Enable debug logging (deprecated, use --logging DEBUG)"
69
+ )
70
+
71
+ parser.add_argument(
72
+ "--logging",
73
+ choices=[level.value for level in LogLevel],
74
+ default=LogLevel.INFO.value,
75
+ help="Logging level (default: INFO)"
76
+ )
77
+
78
+ parser.add_argument(
79
+ "--log-dir",
80
+ type=Path,
81
+ help="Custom log directory (default: ~/.claude-mpm/logs)"
82
+ )
83
+
84
+ parser.add_argument(
85
+ "--framework-path",
86
+ type=Path,
87
+ help="Path to claude-mpm framework"
88
+ )
89
+
90
+ parser.add_argument(
91
+ "--agents-dir",
92
+ type=Path,
93
+ help="Custom agents directory to use"
94
+ )
95
+
96
+ parser.add_argument(
97
+ "--no-hooks",
98
+ action="store_true",
99
+ help="Disable hook service (runs without hooks)"
100
+ )
101
+
102
+ # Add run-specific arguments at top level (for default behavior)
103
+ parser.add_argument(
104
+ "--no-tickets",
105
+ action="store_true",
106
+ help="Disable automatic ticket creation"
107
+ )
108
+ parser.add_argument(
109
+ "-i", "--input",
110
+ type=str,
111
+ help="Input text or file path (for non-interactive mode)"
112
+ )
113
+ parser.add_argument(
114
+ "--non-interactive",
115
+ action="store_true",
116
+ help="Run in non-interactive mode (read from stdin or --input)"
117
+ )
118
+ parser.add_argument(
119
+ "--no-native-agents",
120
+ action="store_true",
121
+ help="Disable deployment of Claude Code native agents"
122
+ )
123
+
124
+ # Don't add claude_args at top level - it conflicts with subcommands
125
+
126
+ # Commands (only non-prefixed for argparse, but we preprocess to support both)
127
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
128
+
129
+ # Run command (default)
130
+ run_parser = subparsers.add_parser(CLICommands.RUN.value, help="Run orchestrated Claude session (default)")
131
+
132
+ run_parser.add_argument(
133
+ "--no-hooks",
134
+ action="store_true",
135
+ help="Disable hook service (runs without hooks)"
136
+ )
137
+ run_parser.add_argument(
138
+ "--no-tickets",
139
+ action="store_true",
140
+ help="Disable automatic ticket creation"
141
+ )
142
+ run_parser.add_argument(
143
+ "-i", "--input",
144
+ type=str,
145
+ help="Input text or file path (for non-interactive mode)"
146
+ )
147
+ run_parser.add_argument(
148
+ "--non-interactive",
149
+ action="store_true",
150
+ help="Run in non-interactive mode (read from stdin or --input)"
151
+ )
152
+ run_parser.add_argument(
153
+ "--no-native-agents",
154
+ action="store_true",
155
+ help="Disable deployment of Claude Code native agents"
156
+ )
157
+ run_parser.add_argument(
158
+ "claude_args",
159
+ nargs=argparse.REMAINDER,
160
+ help="Additional arguments to pass to Claude CLI (use -- before Claude args)"
161
+ )
162
+
163
+ # List tickets command
164
+ list_parser = subparsers.add_parser(CLICommands.TICKETS.value, help="List recent tickets")
165
+ list_parser.add_argument(
166
+ "-n", "--limit",
167
+ type=int,
168
+ default=10,
169
+ help="Number of tickets to show"
170
+ )
171
+
172
+ # Info command
173
+ info_parser = subparsers.add_parser(CLICommands.INFO.value, help="Show framework and configuration info")
174
+
175
+ # UI command
176
+ ui_parser = subparsers.add_parser(CLICommands.UI.value, help="Launch terminal UI with multiple panes")
177
+ ui_parser.add_argument(
178
+ "--mode",
179
+ choices=["terminal", "curses"],
180
+ default="terminal",
181
+ help="UI mode to launch (default: terminal)"
182
+ )
183
+
184
+ # Agent management commands
185
+ agents_parser = subparsers.add_parser(CLICommands.AGENTS.value, help="Manage Claude Code native agents")
186
+ agents_subparsers = agents_parser.add_subparsers(dest="agents_command", help="Agent commands")
187
+
188
+ # List agents
189
+ list_agents_parser = agents_subparsers.add_parser(AgentCommands.LIST.value, help="List available agents")
190
+ list_agents_parser.add_argument(
191
+ "--system",
192
+ action="store_true",
193
+ help="List system agents"
194
+ )
195
+ list_agents_parser.add_argument(
196
+ "--deployed",
197
+ action="store_true",
198
+ help="List deployed agents"
199
+ )
200
+
201
+ # Deploy agents
202
+ deploy_agents_parser = agents_subparsers.add_parser(AgentCommands.DEPLOY.value, help="Deploy system agents")
203
+ deploy_agents_parser.add_argument(
204
+ "--target",
205
+ type=Path,
206
+ help="Target directory (default: .claude/agents/)"
207
+ )
208
+
209
+ # Force deploy agents
210
+ force_deploy_parser = agents_subparsers.add_parser(AgentCommands.FORCE_DEPLOY.value, help="Force deploy all system agents")
211
+ force_deploy_parser.add_argument(
212
+ "--target",
213
+ type=Path,
214
+ help="Target directory (default: .claude/agents/)"
215
+ )
216
+
217
+ # Clean agents
218
+ clean_agents_parser = agents_subparsers.add_parser(AgentCommands.CLEAN.value, help="Remove deployed system agents")
219
+ clean_agents_parser.add_argument(
220
+ "--target",
221
+ type=Path,
222
+ help="Target directory (default: .claude/)"
223
+ )
224
+
225
+ # Preprocess and parse arguments
226
+ processed_argv = _preprocess_args(argv)
227
+ args = parser.parse_args(processed_argv)
228
+
229
+ # Debug: Print parsed args
230
+ if hasattr(args, 'debug') and args.debug:
231
+ print(f"DEBUG: Parsed args: {args}")
232
+
233
+ # Set up logging first
234
+ # Handle deprecated --debug flag
235
+ if args.debug and args.logging == LogLevel.INFO.value:
236
+ args.logging = LogLevel.DEBUG.value
237
+
238
+ # Only setup logging if not OFF
239
+ if args.logging != LogLevel.OFF.value:
240
+ logger = setup_logging(level=args.logging, log_dir=args.log_dir)
241
+ else:
242
+ # Minimal logger for CLI feedback
243
+ import logging
244
+ logger = logging.getLogger("cli")
245
+ logger.setLevel(logging.WARNING)
246
+
247
+ # Initialize hook service manager (unless disabled)
248
+ hook_manager = None
249
+ if not getattr(args, 'no_hooks', False):
250
+ try:
251
+ # Check if hooks are enabled via config
252
+ try:
253
+ from .config.hook_config import HookConfig
254
+ except ImportError:
255
+ from config.hook_config import HookConfig
256
+ if HookConfig.is_hooks_enabled():
257
+ hook_manager = JSONRPCHookManager(log_dir=args.log_dir)
258
+ if hook_manager.start_service():
259
+ logger.info("JSON-RPC hook system initialized")
260
+ if args.logging != LogLevel.OFF.value:
261
+ print("✓ JSON-RPC hook system initialized")
262
+ else:
263
+ logger.warning("Failed to initialize JSON-RPC hooks, continuing without hooks")
264
+ if args.logging != LogLevel.OFF.value:
265
+ print("⚠️ Failed to initialize JSON-RPC hooks, continuing without hooks")
266
+ hook_manager = None
267
+ else:
268
+ logger.info("Hooks disabled via configuration")
269
+ except Exception as e:
270
+ logger.warning(f"Hook service initialization failed: {e}, continuing without hooks")
271
+ hook_manager = None
272
+
273
+ # Default to run command
274
+ if not args.command:
275
+ args.command = CLICommands.RUN.value
276
+ # Also set default arguments for run command when no subcommand specified
277
+ args.no_tickets = getattr(args, 'no_tickets', False)
278
+ args.no_hooks = getattr(args, 'no_hooks', False)
279
+ args.input = getattr(args, 'input', None)
280
+ args.non_interactive = getattr(args, 'non_interactive', False)
281
+ args.claude_args = getattr(args, 'claude_args', [])
282
+
283
+ # Debug output
284
+ logger.debug(f"Command: {args.command}")
285
+ logger.debug(f"Arguments: {args}")
286
+
287
+ # Execute command (we've already preprocessed prefixes)
288
+ command = args.command
289
+
290
+ try:
291
+ if command in [CLICommands.RUN.value, None]:
292
+ run_session(args, hook_manager)
293
+ elif command == CLICommands.TICKETS.value:
294
+ list_tickets(args)
295
+ elif command == CLICommands.INFO.value:
296
+ show_info(args, hook_manager)
297
+ elif command == CLICommands.AGENTS.value:
298
+ manage_agents(args)
299
+ elif command == CLICommands.UI.value:
300
+ run_terminal_ui(args)
301
+ else:
302
+ parser.print_help()
303
+ return 1
304
+ except KeyboardInterrupt:
305
+ logger.info("Session interrupted by user")
306
+ return 0
307
+ except Exception as e:
308
+ logger.error(f"Error: {e}")
309
+ if args.debug:
310
+ import traceback
311
+ traceback.print_exc()
312
+ return 1
313
+ finally:
314
+ # Clean up hook service
315
+ if hook_manager:
316
+ hook_manager.stop_service()
317
+
318
+ return 0
319
+
320
+
321
+ def _get_user_input(args, logger):
322
+ """Get user input based on args."""
323
+ if args.input:
324
+ # Read from file or use as direct input
325
+ input_path = Path(args.input)
326
+ if input_path.exists():
327
+ logger.info(f"Reading input from file: {input_path}")
328
+ return input_path.read_text()
329
+ else:
330
+ logger.info("Using command line input")
331
+ return args.input
332
+ else:
333
+ # Read from stdin
334
+ logger.info("Reading input from stdin")
335
+ return sys.stdin.read()
336
+
337
+
338
+
339
+
340
+ def run_session(args, hook_manager=None):
341
+ """Run a simplified Claude session."""
342
+ logger = get_logger("cli")
343
+ if args.logging != LogLevel.OFF.value:
344
+ logger.info("Starting Claude MPM session")
345
+
346
+ try:
347
+ from .core.simple_runner import SimpleClaudeRunner, create_simple_context
348
+ except ImportError:
349
+ from core.simple_runner import SimpleClaudeRunner, create_simple_context
350
+
351
+ # Skip native agents if disabled
352
+ if getattr(args, 'no_native_agents', False):
353
+ print("Native agents disabled")
354
+
355
+ # Create simple runner
356
+ enable_tickets = not args.no_tickets
357
+ claude_args = getattr(args, 'claude_args', []) or []
358
+ runner = SimpleClaudeRunner(enable_tickets=enable_tickets, log_level=args.logging, claude_args=claude_args)
359
+
360
+ # Create basic context
361
+ context = create_simple_context()
362
+
363
+ # Run session based on mode
364
+ if args.non_interactive or args.input:
365
+ user_input = _get_user_input(args, logger)
366
+ success = runner.run_oneshot(user_input, context)
367
+ if not success:
368
+ logger.error("Session failed")
369
+ else:
370
+ # Run interactive session
371
+ runner.run_interactive(context)
372
+
373
+
374
+ def list_tickets(args):
375
+ """List recent tickets."""
376
+ logger = get_logger("cli")
377
+
378
+ try:
379
+ try:
380
+ from .services.ticket_manager import TicketManager
381
+ except ImportError:
382
+ from services.ticket_manager import TicketManager
383
+
384
+ ticket_manager = TicketManager()
385
+ tickets = ticket_manager.list_recent_tickets(limit=args.limit)
386
+
387
+ if not tickets:
388
+ print("No tickets found")
389
+ return
390
+
391
+ print(f"Recent tickets (showing {len(tickets)}):")
392
+ print("-" * 80)
393
+
394
+ for ticket in tickets:
395
+ status_emoji = {
396
+ "open": "🔵",
397
+ "in_progress": "🟡",
398
+ "done": "🟢",
399
+ "closed": "⚫"
400
+ }.get(ticket['status'], "⚪")
401
+
402
+ print(f"{status_emoji} [{ticket['id']}] {ticket['title']}")
403
+ print(f" Priority: {ticket['priority']} | Tags: {', '.join(ticket['tags'])}")
404
+ print(f" Created: {ticket['created_at']}")
405
+ print()
406
+
407
+ except ImportError:
408
+ logger.error("ai-trackdown-pytools not installed")
409
+ print("Error: ai-trackdown-pytools not installed")
410
+ print("Install with: pip install ai-trackdown-pytools")
411
+ except Exception as e:
412
+ logger.error(f"Error listing tickets: {e}")
413
+ print(f"Error: {e}")
414
+
415
+
416
+ def manage_agents(args):
417
+ """Manage Claude Code native agents."""
418
+ logger = get_logger("cli")
419
+
420
+ try:
421
+ from .services.agent_deployment import AgentDeploymentService
422
+ deployment_service = AgentDeploymentService()
423
+
424
+ if not args.agents_command:
425
+ print("Error: No agent command specified")
426
+ print("\nUsage: claude-mpm --mpm:agents <command> [options]")
427
+ print("\nAvailable commands:")
428
+ print(" list - List available agents")
429
+ print(" deploy - Deploy system agents")
430
+ print(" force-deploy - Force deploy all system agents")
431
+ print(" clean - Remove deployed system agents")
432
+ print("\nExamples:")
433
+ print(" claude-mpm --mpm:agents list --system")
434
+ print(" claude-mpm --mpm:agents deploy")
435
+ print(" claude-mpm --mpm:agents force-deploy")
436
+ return
437
+
438
+ if args.agents_command == AgentCommands.LIST.value:
439
+ # Determine what to list
440
+ if args.system:
441
+ # List available agent templates
442
+ print("Available Agent Templates:")
443
+ print("-" * 80)
444
+ agents = deployment_service.list_available_agents()
445
+ if not agents:
446
+ print("No agent templates found")
447
+ else:
448
+ for agent in agents:
449
+ print(f"📄 {agent['file']}")
450
+ if 'name' in agent:
451
+ print(f" Name: {agent['name']}")
452
+ if 'description' in agent:
453
+ print(f" Description: {agent['description']}")
454
+ if 'version' in agent:
455
+ print(f" Version: {agent['version']}")
456
+ print()
457
+
458
+ elif args.deployed:
459
+ # List deployed agents
460
+ print("Deployed Agents:")
461
+ print("-" * 80)
462
+ verification = deployment_service.verify_deployment()
463
+ if not verification["agents_found"]:
464
+ print("No deployed agents found")
465
+ else:
466
+ for agent in verification["agents_found"]:
467
+ print(f"📄 {agent['file']}")
468
+ if 'name' in agent:
469
+ print(f" Name: {agent['name']}")
470
+ print(f" Path: {agent['path']}")
471
+ print()
472
+
473
+ if verification["warnings"]:
474
+ print("\nWarnings:")
475
+ for warning in verification["warnings"]:
476
+ print(f" ⚠️ {warning}")
477
+
478
+ else:
479
+ # Default: list both
480
+ print("Use --system to list system agents or --deployed to list deployed agents")
481
+
482
+ elif args.agents_command == AgentCommands.DEPLOY.value:
483
+ # Deploy agents
484
+ print("Deploying system agents...")
485
+ results = deployment_service.deploy_agents(args.target, force_rebuild=False)
486
+
487
+ if results["deployed"]:
488
+ print(f"\n✓ Successfully deployed {len(results['deployed'])} agents to {results['target_dir']}")
489
+ for agent in results["deployed"]:
490
+ print(f" - {agent['name']}")
491
+
492
+ elif args.agents_command == AgentCommands.FORCE_DEPLOY.value:
493
+ # Force deploy agents
494
+ print("Force deploying all system agents...")
495
+ results = deployment_service.deploy_agents(args.target, force_rebuild=True)
496
+
497
+ if results["deployed"]:
498
+ print(f"\n✓ Successfully deployed {len(results['deployed'])} agents to {results['target_dir']}")
499
+ for agent in results["deployed"]:
500
+ print(f" - {agent['name']}")
501
+
502
+ if results.get("updated", []):
503
+ print(f"\n✓ Updated {len(results['updated'])} agents")
504
+ for agent in results["updated"]:
505
+ print(f" - {agent['name']}")
506
+
507
+ if results.get("skipped", []):
508
+ print(f"\n✓ Skipped {len(results['skipped'])} up-to-date agents")
509
+
510
+ if results["errors"]:
511
+ print("\n❌ Errors during deployment:")
512
+ for error in results["errors"]:
513
+ print(f" - {error}")
514
+
515
+ # Set environment
516
+ env_vars = deployment_service.set_claude_environment(args.target.parent if args.target else None)
517
+ print(f"\n✓ Set Claude environment variables:")
518
+ for key, value in env_vars.items():
519
+ print(f" - {key}={value}")
520
+
521
+ elif args.agents_command == AgentCommands.CLEAN.value:
522
+ # Clean deployed agents
523
+ print("Cleaning deployed system agents...")
524
+ results = deployment_service.clean_deployment(args.target)
525
+
526
+ if results["removed"]:
527
+ print(f"\n✓ Removed {len(results['removed'])} agents")
528
+ for path in results["removed"]:
529
+ print(f" - {Path(path).name}")
530
+ else:
531
+ print("No system agents found to remove")
532
+
533
+ if results["errors"]:
534
+ print("\n❌ Errors during cleanup:")
535
+ for error in results["errors"]:
536
+ print(f" - {error}")
537
+
538
+ except ImportError:
539
+ logger.error("Agent deployment service not available")
540
+ print("Error: Agent deployment service not available")
541
+ except Exception as e:
542
+ logger.error(f"Error managing agents: {e}")
543
+ print(f"Error: {e}")
544
+
545
+
546
+ def run_terminal_ui(args):
547
+ """Run the terminal UI."""
548
+ logger = get_logger("cli")
549
+
550
+ ui_mode = getattr(args, 'mode', 'terminal')
551
+
552
+ try:
553
+ if ui_mode == 'terminal':
554
+ # Try rich UI first
555
+ try:
556
+ from .ui.rich_terminal_ui import main as run_rich_ui
557
+ logger.info("Starting rich terminal UI...")
558
+ run_rich_ui()
559
+ except ImportError:
560
+ # Fallback to curses UI
561
+ logger.info("Rich not available, falling back to curses UI...")
562
+ from .ui.terminal_ui import TerminalUI
563
+ ui = TerminalUI()
564
+ ui.run()
565
+ else:
566
+ # Use curses UI
567
+ from .ui.terminal_ui import TerminalUI
568
+ ui = TerminalUI()
569
+ ui.run()
570
+ except ImportError as e:
571
+ logger.error(f"UI module not found: {e}")
572
+ print(f"Error: Terminal UI requires 'curses' (built-in) or 'rich' (pip install rich)")
573
+ return 1
574
+ except Exception as e:
575
+ logger.error(f"Error running terminal UI: {e}")
576
+ print(f"Error: {e}")
577
+ return 1
578
+
579
+ return 0
580
+
581
+
582
+ def show_info(args, hook_manager=None):
583
+ """Show framework and configuration information."""
584
+ try:
585
+ from .core.framework_loader import FrameworkLoader
586
+ except ImportError:
587
+ from core.framework_loader import FrameworkLoader
588
+
589
+ print("Claude MPM - Multi-Agent Project Manager")
590
+ print("=" * 50)
591
+
592
+ # Framework info
593
+ loader = FrameworkLoader(args.framework_path)
594
+ if loader.framework_content["loaded"]:
595
+ print(f"Framework: claude-multiagent-pm")
596
+ print(f"Version: {loader.framework_content['version']}")
597
+ print(f"Path: {loader.framework_path}")
598
+ print(f"Agents: {', '.join(loader.get_agent_list())}")
599
+ else:
600
+ print("Framework: Not found (using minimal instructions)")
601
+
602
+ print()
603
+
604
+ # Configuration
605
+ print("Configuration:")
606
+ print(f" Log directory: {args.log_dir or '~/.claude-mpm/logs'}")
607
+ print(f" Debug mode: {args.debug}")
608
+
609
+ # Show agent hierarchy
610
+ if loader.agent_registry:
611
+ hierarchy = loader.agent_registry.get_agent_hierarchy()
612
+ print("\nAgent Hierarchy:")
613
+ print(f" Project agents: {len(hierarchy['project'])}")
614
+ print(f" User agents: {len(hierarchy['user'])}")
615
+ print(f" System agents: {len(hierarchy['system'])}")
616
+
617
+ # Show core agents
618
+ core_agents = loader.agent_registry.get_core_agents()
619
+ print(f"\nCore Agents: {', '.join(core_agents)}")
620
+
621
+ # Check dependencies
622
+ print("\nDependencies:")
623
+
624
+ # Check Claude
625
+ import shutil
626
+ claude_path = shutil.which("claude")
627
+ if claude_path:
628
+ print(f" ✓ Claude CLI: {claude_path}")
629
+ else:
630
+ print(" ✗ Claude CLI: Not found in PATH")
631
+
632
+ # Check ai-trackdown-pytools
633
+ try:
634
+ import ai_trackdown_pytools
635
+ print(" ✓ ai-trackdown-pytools: Installed")
636
+ except ImportError:
637
+ print(" ✗ ai-trackdown-pytools: Not installed")
638
+
639
+ # Check hook service
640
+ if hook_manager:
641
+ info = hook_manager.get_service_info()
642
+ if info['running']:
643
+ print(f" ✓ Hook System: JSON-RPC ({info.get('hook_count', 0)} hooks)")
644
+ if 'discovered_hooks' in info and info['discovered_hooks']:
645
+ print(f" Hooks: {', '.join(info['discovered_hooks'][:5])}")
646
+ if len(info['discovered_hooks']) > 5:
647
+ print(f" ... and {len(info['discovered_hooks']) - 5} more")
648
+ else:
649
+ print(" ✗ Hook System: Not running")
650
+ else:
651
+ print(" ✗ Hook System: Disabled (--no-hooks)")
652
+
653
+
654
+ if __name__ == "__main__":
655
+ sys.exit(main())
claude_mpm/cli_main.py ADDED
@@ -0,0 +1,13 @@
1
+ """Main entry point for CLI that can be run directly."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ # Add src directory to path so claude_mpm can be imported
7
+ src_dir = Path(__file__).parent.parent
8
+ sys.path.insert(0, str(src_dir))
9
+
10
+ from claude_mpm.cli import main
11
+
12
+ if __name__ == "__main__":
13
+ sys.exit(main())
@@ -0,0 +1,15 @@
1
+ """CLI module for claude-mpm.
2
+
3
+ This module provides registry-based argument and command management
4
+ to reduce complexity in the main CLI function.
5
+ """
6
+
7
+ from .args import ArgumentRegistry
8
+ from .commands import CommandRegistry, CommandDefinition, register_standard_commands
9
+
10
+ __all__ = [
11
+ 'ArgumentRegistry',
12
+ 'CommandRegistry',
13
+ 'CommandDefinition',
14
+ 'register_standard_commands'
15
+ ]