mdan-cli 2.6.0 → 2.7.0

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.
@@ -0,0 +1,539 @@
1
+ #!/usr/bin/env python3
2
+ """MDAN CrewAI CLI - CrewAI integration commands"""
3
+
4
+ import asyncio
5
+ import json
6
+ import os
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ try:
11
+ import click
12
+ except ImportError:
13
+ print("Error: Click is required. Install with: pip install click")
14
+ sys.exit(1)
15
+
16
+ # CrewAI imports - will be loaded lazily
17
+ CREWAI_AVAILABLE = False
18
+ try:
19
+ from integrations.crewai.orchestrator import CrewAIOrchestrator
20
+ from integrations.crewai.skills.skill_router import SkillRouter
21
+
22
+ CREWAI_AVAILABLE = True
23
+ except ImportError:
24
+ CREWAI_AVAILABLE = False
25
+
26
+ # Colors
27
+ GREEN = "\033[0;32m"
28
+ RED = "\033[0;31m"
29
+ YELLOW = "\033[1;33m"
30
+ CYAN = "\033[0;36m"
31
+ MAGENTA = "\033[0;35m"
32
+ BOLD = "\033[1m"
33
+ NC = "\033[0m"
34
+
35
+
36
+ def run_async(coro):
37
+ """Run async coroutine in sync context."""
38
+ try:
39
+ loop = asyncio.get_event_loop()
40
+ except RuntimeError:
41
+ loop = asyncio.new_event_loop()
42
+ asyncio.set_event_loop(loop)
43
+ return loop.run_until_complete(coro)
44
+
45
+
46
+ @click.group(name="crewai")
47
+ def crewai_cli():
48
+ """CrewAI integration commands for MDAN."""
49
+ pass
50
+
51
+
52
+ @crewai_cli.command()
53
+ @click.option(
54
+ "--project-path", default=".", help="Project path (default: current directory)"
55
+ )
56
+ def init(project_path):
57
+ """Initialize CrewAI in a project."""
58
+ project_path = Path(project_path).resolve()
59
+
60
+ click.echo(f"{CYAN}🚀 Initializing CrewAI in: {BOLD}{project_path}{NC}")
61
+
62
+ # Create crewai_config.yaml if it doesn't exist
63
+ config_file = project_path / "crewai_config.yaml"
64
+
65
+ if config_file.exists():
66
+ click.echo(f"{YELLOW}⚠️ CrewAI config already exists at {config_file}{NC}")
67
+ click.echo(f" {BOLD}Next:{NC} Edit the config file to customize your setup")
68
+ return
69
+
70
+ default_config = """# CrewAI Configuration for MDAN
71
+ # Copy this file and customize for your project
72
+
73
+ # LLM Configuration
74
+ llm:
75
+ provider: "openai" # openai, anthropic, local
76
+ model: "gpt-4"
77
+ temperature: 0.7
78
+ max_tokens: 4096
79
+
80
+ # Database Configuration (optional)
81
+ database:
82
+ type: "sqlite" # postgresql, mysql, sqlserver, sqlite
83
+ host: "localhost"
84
+ port: 5432
85
+ database: "mdan_db"
86
+ username: ""
87
+ password: ""
88
+
89
+ # Serper API Key (for web search)
90
+ serper_api_key: "${SERPER_API_KEY}"
91
+
92
+ # Auto Mode Settings
93
+ auto_mode:
94
+ enabled: true
95
+ save_context: true
96
+ context_save_threshold: 0.8 # Save at 80% token usage
97
+
98
+ # Agent Settings
99
+ agents:
100
+ product:
101
+ enabled: true
102
+ verbose: true
103
+ architect:
104
+ enabled: true
105
+ verbose: true
106
+ ux:
107
+ enabled: true
108
+ verbose: true
109
+ dev:
110
+ enabled: true
111
+ verbose: true
112
+ test:
113
+ enabled: true
114
+ verbose: true
115
+ security:
116
+ enabled: true
117
+ verbose: true
118
+ devops:
119
+ enabled: true
120
+ verbose: true
121
+ doc:
122
+ enabled: true
123
+ verbose: true
124
+
125
+ # Flow Settings
126
+ flows:
127
+ auto:
128
+ enabled: true
129
+ discovery:
130
+ enabled: true
131
+ build:
132
+ enabled: true
133
+ debate:
134
+ enabled: true
135
+ """
136
+
137
+ config_file.write_text(default_config)
138
+
139
+ # Create .env.example if it doesn't exist
140
+ env_example = project_path / ".env.example"
141
+ if not env_example.exists():
142
+ env_example.write_text("""# CrewAI Environment Variables
143
+ # Copy this to .env and fill in your values
144
+
145
+ # OpenAI API Key
146
+ OPENAI_API_KEY=your-openai-api-key-here
147
+
148
+ # Serper API Key (for web search)
149
+ SERPER_API_KEY=your-serper-api-key-here
150
+
151
+ # Database Configuration (optional)
152
+ DB_HOST=localhost
153
+ DB_PORT=5432
154
+ DB_NAME=mdan_db
155
+ DB_USER=your-db-user
156
+ DB_PASSWORD=your-db-password
157
+ """)
158
+
159
+ click.echo(f"{GREEN}✅ CrewAI initialized successfully!{NC}")
160
+ click.echo(f" {BOLD}Config file:{NC} {config_file}")
161
+ click.echo(f" {BOLD}Env example:{NC} {env_example}")
162
+ click.echo(f"\n {BOLD}Next:{NC}")
163
+ click.echo(" 1. Copy .env.example to .env and fill in your API keys")
164
+ click.echo(" 2. Customize crewai_config.yaml if needed")
165
+ click.echo(f" 3. Run: {CYAN}mdan crewai status{NC}")
166
+
167
+
168
+ @crewai_cli.command()
169
+ @click.argument("task")
170
+ @click.option(
171
+ "--project-path", default=".", help="Project path (default: current directory)"
172
+ )
173
+ @click.option("--save-context", is_flag=True, help="Save context after execution")
174
+ def auto(task, project_path, save_context):
175
+ """Run autonomous mode with a task."""
176
+ if not CREWAI_AVAILABLE:
177
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
178
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
179
+ click.echo(
180
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
181
+ )
182
+ sys.exit(1)
183
+
184
+ project_path = Path(project_path).resolve()
185
+
186
+ # Check for environment variables
187
+ if not os.getenv("OPENAI_API_KEY"):
188
+ click.echo(f"{RED}❌ OPENAI_API_KEY not set{NC}")
189
+ click.echo(f" Set it with: {CYAN}export OPENAI_API_KEY=your-key{NC}")
190
+ sys.exit(1)
191
+
192
+ click.echo(f"{CYAN}🚀 Starting autonomous mode...{NC}")
193
+ click.echo(f"{BOLD}Task:{NC} {task}\n")
194
+
195
+ try:
196
+ orchestrator = CrewAIOrchestrator(
197
+ project_path=str(project_path),
198
+ auto_mode=True,
199
+ serper_api_key=os.getenv("SERPER_API_KEY"),
200
+ )
201
+
202
+ result = run_async(orchestrator.run_auto_mode(task))
203
+
204
+ if result.get("status") == "success":
205
+ click.echo(f"\n{GREEN}✅ Autonomous mode completed successfully!{NC}")
206
+
207
+ if save_context:
208
+ state_file = project_path / "mdan_crewai_state.json"
209
+ orchestrator.save_state(str(state_file))
210
+ click.echo(f" {BOLD}State saved:{NC} {state_file}")
211
+
212
+ # Display result summary
213
+ if "result" in result:
214
+ click.echo(f"\n{BOLD}Result:{NC}")
215
+ if isinstance(result["result"], dict):
216
+ click.echo(json.dumps(result["result"], indent=2))
217
+ else:
218
+ click.echo(str(result["result"]))
219
+ else:
220
+ click.echo(f"\n{RED}❌ Error:{NC} {result.get('error', 'Unknown error')}")
221
+ sys.exit(1)
222
+
223
+ except Exception as e:
224
+ click.echo(f"\n{RED}❌ Error:{NC} {str(e)}")
225
+ sys.exit(1)
226
+
227
+
228
+ @crewai_cli.command()
229
+ @click.argument("topic")
230
+ @click.option(
231
+ "--project-path", default=".", help="Project path (default: current directory)"
232
+ )
233
+ @click.option("--rounds", default=3, help="Number of debate rounds (default: 3)")
234
+ def debate(topic, project_path, rounds):
235
+ """Start a multi-agent debate on a topic."""
236
+ if not CREWAI_AVAILABLE:
237
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
238
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
239
+ click.echo(
240
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
241
+ )
242
+ sys.exit(1)
243
+
244
+ project_path = Path(project_path).resolve()
245
+
246
+ if not os.getenv("OPENAI_API_KEY"):
247
+ click.echo(f"{RED}❌ OPENAI_API_KEY not set{NC}")
248
+ click.echo(f" Set it with: {CYAN}export OPENAI_API_KEY=your-key{NC}")
249
+ sys.exit(1)
250
+
251
+ click.echo(f"{CYAN}🎯 Starting multi-agent debate...{NC}")
252
+ click.echo(f"{BOLD}Topic:{NC} {topic}")
253
+ click.echo(f"{BOLD}Rounds:{NC} {rounds}\n")
254
+
255
+ try:
256
+ orchestrator = CrewAIOrchestrator(
257
+ project_path=str(project_path),
258
+ serper_api_key=os.getenv("SERPER_API_KEY"),
259
+ )
260
+
261
+ result = run_async(orchestrator.start_debate(topic))
262
+
263
+ if result.get("status") == "success":
264
+ click.echo(f"\n{GREEN}✅ Debate completed!{NC}")
265
+
266
+ if "result" in result:
267
+ click.echo(f"\n{BOLD}Debate Summary:{NC}")
268
+ if isinstance(result["result"], dict):
269
+ click.echo(json.dumps(result["result"], indent=2))
270
+ else:
271
+ click.echo(str(result["result"]))
272
+ else:
273
+ click.echo(f"\n{RED}❌ Error:{NC} {result.get('error', 'Unknown error')}")
274
+ sys.exit(1)
275
+
276
+ except Exception as e:
277
+ click.echo(f"\n{RED}❌ Error:{NC} {str(e)}")
278
+ sys.exit(1)
279
+
280
+
281
+ @crewai_cli.command()
282
+ @click.argument("agent_name")
283
+ @click.argument("task")
284
+ @click.option(
285
+ "--project-path", default=".", help="Project path (default: current directory)"
286
+ )
287
+ def agent(agent_name, task, project_path):
288
+ """Execute a task with a specific agent."""
289
+ if not CREWAI_AVAILABLE:
290
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
291
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
292
+ click.echo(
293
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
294
+ )
295
+ sys.exit(1)
296
+
297
+ project_path = Path(project_path).resolve()
298
+
299
+ valid_agents = [
300
+ "product",
301
+ "architect",
302
+ "ux",
303
+ "dev",
304
+ "test",
305
+ "security",
306
+ "devops",
307
+ "doc",
308
+ ]
309
+
310
+ if agent_name not in valid_agents:
311
+ click.echo(f"{RED}❌ Invalid agent: {agent_name}{NC}")
312
+ click.echo(f" Valid agents: {', '.join(valid_agents)}")
313
+ sys.exit(1)
314
+
315
+ if not os.getenv("OPENAI_API_KEY"):
316
+ click.echo(f"{RED}❌ OPENAI_API_KEY not set{NC}")
317
+ click.echo(f" Set it with: {CYAN}export OPENAI_API_KEY=your-key{NC}")
318
+ sys.exit(1)
319
+
320
+ click.echo(f"{CYAN}🤖 Executing task with {BOLD}{agent_name}{NC} agent...")
321
+ click.echo(f"{BOLD}Task:{NC} {task}\n")
322
+
323
+ try:
324
+ orchestrator = CrewAIOrchestrator(
325
+ project_path=str(project_path),
326
+ serper_api_key=os.getenv("SERPER_API_KEY"),
327
+ )
328
+
329
+ result = run_async(orchestrator.execute_task(task))
330
+
331
+ if result.get("status") == "success":
332
+ click.echo(f"\n{GREEN}✅ Task completed!{NC}")
333
+
334
+ if "result" in result:
335
+ click.echo(f"\n{BOLD}Result:{NC}")
336
+ if isinstance(result["result"], dict):
337
+ click.echo(json.dumps(result["result"], indent=2))
338
+ else:
339
+ click.echo(str(result["result"]))
340
+ else:
341
+ click.echo(f"\n{RED}❌ Error:{NC} {result.get('error', 'Unknown error')}")
342
+ sys.exit(1)
343
+
344
+ except Exception as e:
345
+ click.echo(f"\n{RED}❌ Error:{NC} {str(e)}")
346
+ sys.exit(1)
347
+
348
+
349
+ @crewai_cli.command()
350
+ @click.argument("flow_name")
351
+ @click.argument("task")
352
+ @click.option(
353
+ "--project-path", default=".", help="Project path (default: current directory)"
354
+ )
355
+ def flow(flow_name, task, project_path):
356
+ """Execute a specific flow."""
357
+ if not CREWAI_AVAILABLE:
358
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
359
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
360
+ click.echo(
361
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
362
+ )
363
+ sys.exit(1)
364
+
365
+ project_path = Path(project_path).resolve()
366
+
367
+ valid_flows = ["auto", "discovery", "build", "debate"]
368
+
369
+ if flow_name not in valid_flows:
370
+ click.echo(f"{RED}❌ Invalid flow: {flow_name}{NC}")
371
+ click.echo(f" Valid flows: {', '.join(valid_flows)}")
372
+ sys.exit(1)
373
+
374
+ if not os.getenv("OPENAI_API_KEY"):
375
+ click.echo(f"{RED}❌ OPENAI_API_KEY not set{NC}")
376
+ click.echo(f" Set it with: {CYAN}export OPENAI_API_KEY=your-key{NC}")
377
+ sys.exit(1)
378
+
379
+ click.echo(f"{CYAN}🔄 Executing {BOLD}{flow_name}{NC} flow...")
380
+ click.echo(f"{BOLD}Task:{NC} {task}\n")
381
+
382
+ try:
383
+ orchestrator = CrewAIOrchestrator(
384
+ project_path=str(project_path),
385
+ serper_api_key=os.getenv("SERPER_API_KEY"),
386
+ )
387
+
388
+ result = run_async(orchestrator.execute_task(task))
389
+
390
+ if result.get("status") == "success":
391
+ click.echo(f"\n{GREEN}✅ Flow completed!{NC}")
392
+
393
+ if "result" in result:
394
+ click.echo(f"\n{BOLD}Result:{NC}")
395
+ if isinstance(result["result"], dict):
396
+ click.echo(json.dumps(result["result"], indent=2))
397
+ else:
398
+ click.echo(str(result["result"]))
399
+ else:
400
+ click.echo(f"\n{RED}❌ Error:{NC} {result.get('error', 'Unknown error')}")
401
+ sys.exit(1)
402
+
403
+ except Exception as e:
404
+ click.echo(f"\n{RED}❌ Error:{NC} {str(e)}")
405
+ sys.exit(1)
406
+
407
+
408
+ @crewai_cli.command()
409
+ def skills():
410
+ """List available skills."""
411
+ if not CREWAI_AVAILABLE:
412
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
413
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
414
+ click.echo(
415
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
416
+ )
417
+ sys.exit(1)
418
+
419
+ click.echo(f"{CYAN}📚 Available Skills:{NC}\n")
420
+
421
+ try:
422
+ router = SkillRouter()
423
+ all_skills = router.get_all_skills()
424
+
425
+ # Group by category
426
+ categories = {}
427
+ for skill_name, skill_info in all_skills.items():
428
+ category = skill_info.get("category", "General")
429
+ if category not in categories:
430
+ categories[category] = []
431
+ categories[category].append((skill_name, skill_info))
432
+
433
+ for category, skills in sorted(categories.items()):
434
+ click.echo(f"{BOLD}{category}:{NC}")
435
+ for skill_name, skill_info in skills:
436
+ description = skill_info.get("description", "No description")
437
+ click.echo(f" • {skill_name}: {description}")
438
+ click.echo()
439
+
440
+ except Exception as e:
441
+ click.echo(f"{RED}❌ Error loading skills: {str(e)}{NC}")
442
+ sys.exit(1)
443
+
444
+
445
+ @crewai_cli.command()
446
+ @click.option(
447
+ "--project-path", default=".", help="Project path (default: current directory)"
448
+ )
449
+ def status(project_path):
450
+ """Show CrewAI status."""
451
+ project_path = Path(project_path).resolve()
452
+
453
+ click.echo(f"{CYAN}📊 CrewAI Status{NC}\n")
454
+
455
+ # Check if CrewAI is available
456
+ if not CREWAI_AVAILABLE:
457
+ click.echo(f"{RED}❌ CrewAI integration not found{NC}")
458
+ click.echo(f" Install with: {CYAN}pip install -r requirements_crewai.txt{NC}")
459
+ click.echo(
460
+ f" Note: CrewAI requires Python 3.10-3.13 (current: {sys.version_info.major}.{sys.version_info.minor})"
461
+ )
462
+ return
463
+
464
+ # Check config file
465
+ config_file = project_path / "crewai_config.yaml"
466
+ if config_file.exists():
467
+ click.echo(f"{GREEN}✅ Config file:{NC} {config_file}")
468
+ else:
469
+ click.echo(f"{YELLOW}⚠️ Config file not found{NC}")
470
+ click.echo(f" Run: {CYAN}mdan crewai init{NC}")
471
+ return
472
+
473
+ # Check environment variables
474
+ click.echo(f"\n{BOLD}Environment Variables:{NC}")
475
+
476
+ if os.getenv("OPENAI_API_KEY"):
477
+ click.echo(f" {GREEN}✅{NC} OPENAI_API_KEY: Set")
478
+ else:
479
+ click.echo(f" {RED}❌{NC} OPENAI_API_KEY: Not set")
480
+
481
+ if os.getenv("SERPER_API_KEY"):
482
+ click.echo(f" {GREEN}✅{NC} SERPER_API_KEY: Set")
483
+ else:
484
+ click.echo(f" {YELLOW}⚠️{NC} SERPER_API_KEY: Not set (optional)")
485
+
486
+ # Check state file
487
+ state_file = project_path / "mdan_crewai_state.json"
488
+ if state_file.exists():
489
+ click.echo(f"\n{GREEN}✅ State file:{NC} {state_file}")
490
+ try:
491
+ with open(state_file) as f:
492
+ state = json.load(f)
493
+ click.echo(
494
+ f" {BOLD}Current Phase:{NC} {state.get('current_phase', 'N/A')}"
495
+ )
496
+ click.echo(
497
+ f" {BOLD}Auto Mode:{NC} {state.get('auto_mode_enabled', False)}"
498
+ )
499
+ click.echo(
500
+ f" {BOLD}Tasks Completed:{NC} {len(state.get('task_history', []))}"
501
+ )
502
+ except Exception:
503
+ click.echo(f" {YELLOW}⚠️ Could not read state file{NC}")
504
+
505
+ # Check integrations
506
+ click.echo(f"\n{BOLD}Integrations:{NC}")
507
+
508
+ import importlib.util
509
+
510
+ if importlib.util.find_spec("integrations.crewai.tools.serper_tool") is not None:
511
+ click.echo(f" {GREEN}✅{NC} Serper Tool: Available")
512
+ else:
513
+ click.echo(f" {RED}❌{NC} Serper Tool: Not available")
514
+
515
+ if importlib.util.find_spec("integrations.crewai.tools.sql_tool") is not None:
516
+ click.echo(f" {GREEN}✅{NC} SQL Tool: Available")
517
+ else:
518
+ click.echo(f" {RED}❌{NC} SQL Tool: Not available")
519
+
520
+ if importlib.util.find_spec("integrations.crewai.tools.file_tool") is not None:
521
+ click.echo(f" {GREEN}✅{NC} File Tool: Available")
522
+ else:
523
+ click.echo(f" {RED}❌{NC} File Tool: Not available")
524
+
525
+ # List agents
526
+ click.echo(f"\n{BOLD}Available Agents:{NC}")
527
+ agents = ["product", "architect", "ux", "dev", "test", "security", "devops", "doc"]
528
+ for agent in agents:
529
+ click.echo(f" • {agent}")
530
+
531
+ # List flows
532
+ click.echo(f"\n{BOLD}Available Flows:{NC}")
533
+ flows = ["auto", "discovery", "build", "debate"]
534
+ for flow in flows:
535
+ click.echo(f" • {flow}")
536
+
537
+
538
+ if __name__ == "__main__":
539
+ crewai_cli()