@ayurak/aribot-cli 1.0.5 → 1.0.7

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.
package/src/cli.ts CHANGED
@@ -1,6 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Aribot CLI - AI-Powered Threat Modeling
3
+ * Aribot CLI - Economic, Regulatory & Security APIs for Modern Applications
4
+ *
5
+ * Analyze your tech stack. Optimize architecture. Model costs. Identify threats dynamically.
6
+ *
7
+ * Features:
8
+ * - Advanced Threat Modeling (STRIDE, PASTA, NIST, Aristiun Framework)
9
+ * - 100+ Compliance Standards (SOC2, ISO27001, PCI-DSS, GDPR, HIPAA...)
10
+ * - Cloud Security (CSPM/CNAPP)
11
+ * - Economic Intelligence & FinOps
12
+ * - Red Team Automation
4
13
  *
5
14
  * Usage:
6
15
  * aribot login # Authenticate with API key
@@ -26,7 +35,7 @@ const program = new Command();
26
35
 
27
36
  program
28
37
  .name('aribot')
29
- .description('AI-powered threat modeling CLI by Ayurak')
38
+ .description('Aribot - Economic, Regulatory & Security APIs for Modern Applications')
30
39
  .version('1.0.5');
31
40
 
32
41
  // Helper to get auth headers
@@ -57,6 +66,24 @@ async function apiRequest(endpoint: string, options: any = {}): Promise<any> {
57
66
  return response.json();
58
67
  }
59
68
 
69
+ // Resolve short UUID to full UUID
70
+ async function resolveDiagramId(shortId: string): Promise<string> {
71
+ // If it already looks like a full UUID, return it
72
+ if (shortId.includes('-') || shortId.length >= 32) {
73
+ return shortId;
74
+ }
75
+
76
+ // Fetch diagrams and find by prefix match
77
+ const data = await apiRequest('/v2/threat-modeling/diagrams/?limit=100');
78
+ const match = data.results?.find((d: any) => d.id.startsWith(shortId));
79
+
80
+ if (!match) {
81
+ throw new Error(`No diagram found matching ID: ${shortId}`);
82
+ }
83
+
84
+ return match.id;
85
+ }
86
+
60
87
  // Login command
61
88
  program
62
89
  .command('login')
@@ -213,7 +240,10 @@ program
213
240
  const spinner = ora('Fetching threats...').start();
214
241
 
215
242
  try {
216
- let url = `/v2/threat-modeling/diagrams/${diagramId}/threats/`;
243
+ // Resolve short UUID to full UUID
244
+ const fullId = await resolveDiagramId(diagramId);
245
+
246
+ let url = `/v2/threat-modeling/diagrams/${fullId}/threats/`;
217
247
  if (options.severity) {
218
248
  url += `?severity=${options.severity}`;
219
249
  }
@@ -255,19 +285,32 @@ program
255
285
  const spinner = ora(`Exporting ${options.format.toUpperCase()} report...`).start();
256
286
 
257
287
  try {
288
+ // Resolve short UUID to full UUID
289
+ const fullId = await resolveDiagramId(diagramId);
290
+
258
291
  const fetch = (await import('node-fetch')).default;
259
- const apiKey = config.get('apiKey') as string;
292
+ const headers = getHeaders();
293
+
294
+ // Choose endpoint based on format
295
+ let endpoint: string;
296
+ if (options.format === 'csv') {
297
+ endpoint = `/v2/threat-modeling/diagrams/${fullId}/export/csv/`;
298
+ } else if (options.format === 'pdf') {
299
+ endpoint = `/v2/threat-modeling/diagrams/${fullId}/unified-report/?format=pdf`;
300
+ } else {
301
+ endpoint = `/v2/threat-modeling/diagrams/${fullId}/report/`;
302
+ }
260
303
 
261
304
  const response = await fetch(
262
- `${API_BASE}/v2/threat-modeling/diagrams/${diagramId}/export/?format=${options.format}`,
263
- { headers: { 'Authorization': `Bearer ${apiKey}` } }
305
+ `${API_BASE}${endpoint}`,
306
+ { headers }
264
307
  );
265
308
 
266
309
  if (!response.ok) {
267
310
  throw new Error(`Export failed: ${response.status}`);
268
311
  }
269
312
 
270
- const outputPath = options.output || `aribot-report-${diagramId.slice(0, 8)}.${options.format}`;
313
+ const outputPath = options.output || `aribot-report-${fullId.slice(0, 8)}.${options.format}`;
271
314
 
272
315
  if (options.format === 'json') {
273
316
  const data = await response.json();
@@ -292,7 +335,10 @@ program
292
335
  const spinner = ora('Generating AI threats...').start();
293
336
 
294
337
  try {
295
- await apiRequest(`/v2/threat-modeling/diagrams/${diagramId}/generate-threats/`, {
338
+ // Resolve short UUID to full UUID
339
+ const fullId = await resolveDiagramId(diagramId);
340
+
341
+ await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/generate-threats/`, {
296
342
  method: 'POST'
297
343
  });
298
344
 
@@ -302,7 +348,7 @@ program
302
348
  let attempts = 0;
303
349
  while (attempts < 30) {
304
350
  await new Promise(r => setTimeout(r, 2000));
305
- const status = await apiRequest(`/v2/threat-modeling/diagrams/${diagramId}/`);
351
+ const status = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
306
352
 
307
353
  if (status.ai_threats_generated) {
308
354
  spinner.succeed(`Generated ${status.threats_count} threats`);
@@ -348,4 +394,953 @@ program
348
394
  }
349
395
  });
350
396
 
397
+ // Status command - Check API status and rate limits
398
+ program
399
+ .command('status')
400
+ .description('Check API status and rate limits')
401
+ .action(async () => {
402
+ const spinner = ora('Checking API status...').start();
403
+
404
+ try {
405
+ const fetch = (await import('node-fetch')).default;
406
+
407
+ // Check health endpoint (no auth required)
408
+ const healthResponse = await fetch(`${API_BASE}/health/`);
409
+ const health = await healthResponse.json() as any;
410
+
411
+ spinner.stop();
412
+ console.log(chalk.bold('\nAPI Status:\n'));
413
+ console.log(` Status: ${health.status === 'healthy' ? chalk.green('✓ Healthy') : chalk.red('✗ Unhealthy')}`);
414
+ console.log(` Version: ${chalk.cyan(health.version || 'N/A')}`);
415
+ console.log(` Features: ${health.features_enabled ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
416
+
417
+ // Check rate limits if authenticated
418
+ const apiKey = config.get('apiKey') as string;
419
+ if (apiKey) {
420
+ try {
421
+ const limits = await apiRequest('/v2/developer-portal/rate-limits/usage/');
422
+ console.log(chalk.bold('\nRate Limits:\n'));
423
+ console.log(` Requests/min: ${limits.requests_per_minute?.used || 0}/${limits.requests_per_minute?.limit || 'unlimited'}`);
424
+ console.log(` Requests/hour: ${limits.requests_per_hour?.used || 0}/${limits.requests_per_hour?.limit || 'unlimited'}`);
425
+ console.log(` Requests/day: ${limits.requests_per_day?.used || 0}/${limits.requests_per_day?.limit || 'unlimited'}`);
426
+ } catch {
427
+ console.log(chalk.dim('\nRate limit info requires authentication'));
428
+ }
429
+ }
430
+ } catch (error) {
431
+ spinner.fail('Failed to check status');
432
+ console.error(error);
433
+ }
434
+ });
435
+
436
+ // Compliance command - Run compliance assessment
437
+ program
438
+ .command('compliance')
439
+ .description('Run compliance assessment on a diagram')
440
+ .argument('[diagram-id]', 'Diagram ID to assess')
441
+ .option('-s, --standard <standard>', 'Compliance standard (SOC2, ISO27001, NIST, PCI-DSS, GDPR, HIPAA)', 'SOC2')
442
+ .option('--list-standards', 'List all available compliance standards')
443
+ .action(async (diagramId, options) => {
444
+ if (options.listStandards) {
445
+ console.log(chalk.bold('\nSupported Compliance Standards:\n'));
446
+ const standards = [
447
+ 'SOC2', 'ISO27001', 'ISO27017', 'ISO27018', 'ISO22301',
448
+ 'NIST-CSF', 'NIST-800-53', 'NIST-800-171',
449
+ 'PCI-DSS', 'PCI-DSS-4.0',
450
+ 'GDPR', 'CCPA', 'LGPD', 'PIPEDA',
451
+ 'HIPAA', 'HITRUST',
452
+ 'FedRAMP-Low', 'FedRAMP-Moderate', 'FedRAMP-High',
453
+ 'CIS-AWS', 'CIS-Azure', 'CIS-GCP', 'CIS-Kubernetes',
454
+ 'SOX', 'GLBA', 'FISMA',
455
+ 'CSA-CCM', 'MITRE-ATT&CK', 'OWASP-TOP-10',
456
+ ];
457
+ standards.forEach(s => console.log(` ${chalk.cyan('•')} ${s}`));
458
+ return;
459
+ }
460
+
461
+ if (!diagramId) {
462
+ console.error(chalk.red('Error: diagram-id is required for compliance assessment'));
463
+ console.log(chalk.dim('Usage: aribot compliance <diagram-id> --standard SOC2'));
464
+ console.log(chalk.dim(' aribot compliance --list-standards'));
465
+ process.exit(1);
466
+ }
467
+
468
+ const spinner = ora(`Running ${options.standard} compliance assessment...`).start();
469
+
470
+ try {
471
+ // Resolve short UUID to full UUID
472
+ const fullId = await resolveDiagramId(diagramId);
473
+
474
+ const data = await apiRequest('/v2/compliances/assess_diagram/', {
475
+ method: 'POST',
476
+ body: JSON.stringify({
477
+ diagram_id: fullId,
478
+ frameworks: [options.standard]
479
+ })
480
+ });
481
+
482
+ spinner.succeed('Compliance assessment complete!');
483
+
484
+ console.log(chalk.bold(`\n${options.standard} Compliance Report:\n`));
485
+ console.log(` Score: ${data.score >= 80 ? chalk.green(data.score + '%') : data.score >= 60 ? chalk.yellow(data.score + '%') : chalk.red(data.score + '%')}`);
486
+ console.log(` Passed Controls: ${chalk.green(data.passed_controls || 0)}`);
487
+ console.log(` Failed Controls: ${chalk.red(data.failed_controls || 0)}`);
488
+ console.log(` Status: ${data.status === 'compliant' ? chalk.green('Compliant') : chalk.yellow('Non-Compliant')}`);
489
+
490
+ if (data.findings?.length > 0) {
491
+ console.log(chalk.bold('\nTop Findings:\n'));
492
+ data.findings.slice(0, 5).forEach((f: any) => {
493
+ const severityColor = f.severity === 'high' ? chalk.red : f.severity === 'medium' ? chalk.yellow : chalk.dim;
494
+ console.log(` ${severityColor(`[${f.severity?.toUpperCase()}]`)} ${f.title || f.control_id}`);
495
+ });
496
+ }
497
+ } catch (error) {
498
+ spinner.fail('Compliance assessment failed');
499
+ console.error(error);
500
+ }
501
+ });
502
+
503
+ // Economics command - Calculate ROI, TCO, cost analysis
504
+ program
505
+ .command('economics')
506
+ .description('Economic intelligence and cost analysis')
507
+ .option('--roi <investment>', 'Calculate ROI for security investment (in USD)')
508
+ .option('--tco <provider>', 'Calculate TCO for cloud provider (aws, azure, gcp)')
509
+ .option('--analyze <diagram-id>', 'Analyze costs for a diagram')
510
+ .option('--dashboard', 'Show economic intelligence dashboard')
511
+ .action(async (options) => {
512
+ const spinner = ora('Calculating...').start();
513
+
514
+ try {
515
+ if (options.roi) {
516
+ const investment = parseFloat(options.roi);
517
+ const data = await apiRequest('/v2/economic/v2/roi/create/', {
518
+ method: 'POST',
519
+ body: JSON.stringify({
520
+ investment,
521
+ risk_reduction: 50,
522
+ time_horizon: 3
523
+ })
524
+ });
525
+
526
+ spinner.succeed('ROI Analysis Complete!');
527
+ console.log(chalk.bold('\nSecurity ROI Analysis:\n'));
528
+ console.log(` Investment: ${chalk.cyan('$' + investment.toLocaleString())}`);
529
+ console.log(` Expected ROI: ${chalk.green((data.roi_percentage || data.roi || 0) + '%')}`);
530
+ console.log(` NPV: ${chalk.green('$' + (data.npv || 0).toLocaleString())}`);
531
+ console.log(` Payback Period: ${chalk.cyan((data.payback_months || data.payback_period || 0) + ' months')}`);
532
+ console.log(` Risk Reduction: ${chalk.green('50%')}`);
533
+
534
+ } else if (options.tco) {
535
+ const data = await apiRequest('/v2/economic/tco/', {
536
+ method: 'POST',
537
+ body: JSON.stringify({
538
+ provider: options.tco,
539
+ workload_type: 'general',
540
+ duration_months: 36
541
+ })
542
+ });
543
+
544
+ spinner.succeed('TCO Analysis Complete!');
545
+ console.log(chalk.bold(`\nTotal Cost of Ownership (${options.tco.toUpperCase()}):\n`));
546
+ console.log(` Monthly Cost: ${chalk.cyan('$' + (data.monthly_cost || 0).toLocaleString())}`);
547
+ console.log(` Annual Cost: ${chalk.cyan('$' + (data.annual_cost || 0).toLocaleString())}`);
548
+ console.log(` 3-Year TCO: ${chalk.yellow('$' + (data.total_cost || data.tco || 0).toLocaleString())}`);
549
+
550
+ } else if (options.analyze) {
551
+ const data = await apiRequest('/v2/economic/analyze/', {
552
+ method: 'POST',
553
+ body: JSON.stringify({ diagram_id: options.analyze })
554
+ });
555
+
556
+ spinner.succeed('Cost Analysis Complete!');
557
+ console.log(chalk.bold('\nDiagram Cost Analysis:\n'));
558
+ console.log(` Estimated Monthly: ${chalk.cyan('$' + (data.monthly_estimate || 0).toLocaleString())}`);
559
+ console.log(` Security Costs: ${chalk.yellow('$' + (data.security_cost || 0).toLocaleString())}`);
560
+ console.log(` Breach Risk Cost: ${chalk.red('$' + (data.breach_risk_cost || 0).toLocaleString())}`);
561
+
562
+ } else if (options.dashboard) {
563
+ const data = await apiRequest('/v2/economic/v2/dashboard/');
564
+
565
+ spinner.succeed('Dashboard loaded!');
566
+ console.log(chalk.bold('\nEconomic Intelligence Dashboard:\n'));
567
+ console.log(` Total Security Spend: ${chalk.cyan('$' + (data.total_spend || 0).toLocaleString())}`);
568
+ console.log(` Risk Score: ${chalk.yellow(data.risk_score || 'N/A')}`);
569
+ console.log(` Cost Efficiency: ${chalk.green((data.efficiency_score || 0) + '%')}`);
570
+
571
+ } else {
572
+ spinner.stop();
573
+ console.log(chalk.yellow('Usage: aribot economics [--roi <amount>] [--tco <provider>] [--analyze <diagram-id>] [--dashboard]'));
574
+ }
575
+ } catch (error) {
576
+ spinner.fail('Economic analysis failed');
577
+ console.error(error);
578
+ }
579
+ });
580
+
581
+ // Cloud Security command
582
+ program
583
+ .command('cloud-security')
584
+ .description('Cloud security posture management (CSPM/CNAPP)')
585
+ .option('--scan [provider]', 'Scan cloud security posture (aws, azure, gcp)')
586
+ .option('--findings', 'List security findings')
587
+ .option('--dashboard', 'Show cloud security dashboard')
588
+ .option('-s, --severity <level>', 'Filter findings by severity (critical, high, medium, low)')
589
+ .action(async (options) => {
590
+ const spinner = ora('Scanning cloud security...').start();
591
+
592
+ try {
593
+ if (options.scan) {
594
+ const provider = typeof options.scan === 'string' ? options.scan : undefined;
595
+ const data = await apiRequest('/v2/compliances/scan/', {
596
+ method: 'POST',
597
+ body: JSON.stringify(provider ? { provider } : {})
598
+ });
599
+
600
+ spinner.succeed('Cloud security scan complete!');
601
+ console.log(chalk.bold('\nCloud Security Scan Results:\n'));
602
+ console.log(` Total Resources: ${chalk.cyan(data.total_resources || 0)}`);
603
+ console.log(` Compliant: ${chalk.green(data.compliant_resources || 0)}`);
604
+ console.log(` Non-Compliant: ${chalk.red(data.non_compliant_resources || 0)}`);
605
+ console.log(` Critical Issues: ${chalk.red(data.critical_findings || 0)}`);
606
+
607
+ } else if (options.findings) {
608
+ let url = '/v2/compliances/scan/?status=open&limit=20';
609
+ if (options.severity) {
610
+ url += `&severity=${options.severity}`;
611
+ }
612
+ const data = await apiRequest(url);
613
+
614
+ spinner.stop();
615
+ console.log(chalk.bold('\nCloud Security Findings:\n'));
616
+
617
+ const findings = data.results || data.findings || [];
618
+ if (findings.length === 0) {
619
+ console.log(chalk.green(' No open findings! Your cloud is secure.'));
620
+ } else {
621
+ const severityColors: Record<string, any> = {
622
+ critical: chalk.red,
623
+ high: chalk.yellow,
624
+ medium: chalk.blue,
625
+ low: chalk.dim
626
+ };
627
+
628
+ findings.slice(0, 10).forEach((f: any) => {
629
+ const color = severityColors[f.severity] || chalk.white;
630
+ console.log(` ${color(`[${f.severity?.toUpperCase()}]`)} ${f.title}`);
631
+ console.log(chalk.dim(` Resource: ${f.resource_type || 'N/A'} | Policy: ${f.policy || 'N/A'}`));
632
+ });
633
+ console.log(chalk.dim(`\nShowing ${Math.min(10, findings.length)} of ${findings.length} findings`));
634
+ }
635
+
636
+ } else if (options.dashboard) {
637
+ const data = await apiRequest('/v2/compliances/dashboard/cloud-stats/');
638
+
639
+ spinner.succeed('Dashboard loaded!');
640
+ console.log(chalk.bold('\nCloud Security Dashboard:\n'));
641
+ console.log(` Security Score: ${data.security_score >= 80 ? chalk.green(data.security_score) : chalk.yellow(data.security_score || 'N/A')}`);
642
+ console.log(` Total Resources: ${chalk.cyan(data.total_resources || 0)}`);
643
+ console.log(` Open Findings: ${chalk.yellow(data.open_findings || 0)}`);
644
+
645
+ } else {
646
+ spinner.stop();
647
+ console.log(chalk.yellow('Usage: aribot cloud-security [--scan [provider]] [--findings] [--dashboard]'));
648
+ }
649
+ } catch (error) {
650
+ spinner.fail('Cloud security operation failed');
651
+ console.error(error);
652
+ }
653
+ });
654
+
655
+ // Red Team command - Attack path analysis and threat simulation
656
+ program
657
+ .command('redteam')
658
+ .description('Red team attack simulation and threat analysis')
659
+ .option('--methodologies', 'List available threat modeling methodologies')
660
+ .option('--intelligence', 'Get threat intelligence summary')
661
+ .option('--attack-paths', 'Analyze attack paths (requires --diagram)')
662
+ .option('-d, --diagram <diagram-id>', 'Diagram ID for analysis')
663
+ .option('--analyze <diagram-id>', 'Comprehensive threat analysis for diagram')
664
+ .option('--requirements <diagram-id>', 'Generate security requirements')
665
+ .action(async (options) => {
666
+ if (options.methodologies) {
667
+ const spinner = ora('Fetching methodologies...').start();
668
+ try {
669
+ const data = await apiRequest('/v2/threat-engine/threat-models/');
670
+ spinner.stop();
671
+
672
+ console.log(chalk.bold('\nThreat Modeling Methodologies:\n'));
673
+ (data.available_methodologies || []).forEach((m: any) => {
674
+ console.log(` ${chalk.cyan(m.name.toUpperCase().padEnd(12))} ${chalk.dim(m.description)}`);
675
+ });
676
+
677
+ console.log(chalk.bold('\nRisk Levels:\n'));
678
+ (data.risk_levels || []).forEach((r: any) => {
679
+ console.log(` ${chalk.yellow(r.name.padEnd(12))} ${chalk.dim(r.description)}`);
680
+ });
681
+
682
+ console.log(chalk.bold('\nCompliance Frameworks:\n'));
683
+ (data.compliance_frameworks || []).slice(0, 10).forEach((f: any) => {
684
+ console.log(` ${chalk.green(f.name.padEnd(20))} ${chalk.dim(f.description)}`);
685
+ });
686
+
687
+ console.log(chalk.bold('\nEngine Capabilities:\n'));
688
+ const caps = data.engine_capabilities || {};
689
+ Object.entries(caps).forEach(([key, value]) => {
690
+ console.log(` ${value ? chalk.green('✓') : chalk.red('✗')} ${key.replace(/_/g, ' ')}`);
691
+ });
692
+ } catch (error) {
693
+ spinner.fail('Failed to fetch methodologies');
694
+ console.error(error);
695
+ }
696
+ return;
697
+ }
698
+
699
+ if (options.intelligence) {
700
+ const spinner = ora('Fetching threat intelligence...').start();
701
+ try {
702
+ const data = await apiRequest('/v2/threat-engine/threat-intelligence/');
703
+ spinner.stop();
704
+
705
+ console.log(chalk.bold('\nThreat Intelligence Summary:\n'));
706
+ const intel = data.threat_intelligence || {};
707
+ console.log(` Integration: ${intel.integration_status === 'active' ? chalk.green('Active') : chalk.red('Inactive')}`);
708
+ console.log(` Cache TTL: ${chalk.cyan(intel.cache_ttl + 's')}`);
709
+ console.log(` Real-time Feeds: ${intel.real_time_feeds ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
710
+ console.log(` Correlation: ${intel.correlation_engine ? chalk.green('Enabled') : chalk.yellow('Disabled')}`);
711
+
712
+ console.log(chalk.bold('\nSupported Indicators:\n'));
713
+ (intel.supported_indicators || []).forEach((i: string) => {
714
+ console.log(` ${chalk.cyan('•')} ${i}`);
715
+ });
716
+
717
+ console.log(chalk.bold('\nVision 2040 Features:\n'));
718
+ const v2040 = data.vision_2040_features || {};
719
+ Object.entries(v2040).forEach(([key, value]) => {
720
+ console.log(` ${value ? chalk.green('✓') : chalk.red('✗')} ${key.replace(/_/g, ' ')}`);
721
+ });
722
+ } catch (error) {
723
+ spinner.fail('Failed to fetch threat intelligence');
724
+ console.error(error);
725
+ }
726
+ return;
727
+ }
728
+
729
+ if (options.attackPaths) {
730
+ if (!options.diagram) {
731
+ console.log(chalk.yellow('Usage: aribot redteam --attack-paths --diagram <diagram-id>'));
732
+ return;
733
+ }
734
+
735
+ const spinner = ora('Analyzing attack paths...').start();
736
+ try {
737
+ // First get the diagram components
738
+ const fullId = await resolveDiagramId(options.diagram);
739
+ const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
740
+
741
+ // Get components and build connections
742
+ const components = (diagramData.components || []).map((c: any) => ({
743
+ id: c.id || c.uuid,
744
+ type: c.component_type || c.type || 'component',
745
+ name: c.name || c.label || 'Unknown'
746
+ }));
747
+
748
+ const connections = (diagramData.links || diagramData.connections || []).map((l: any) => ({
749
+ source: l.source_id || l.source,
750
+ target: l.target_id || l.target
751
+ }));
752
+
753
+ if (components.length < 2) {
754
+ spinner.stop();
755
+ console.log(chalk.yellow('\nInsufficient components for attack path analysis.'));
756
+ console.log(chalk.dim('Upload a diagram with at least 2 connected components.'));
757
+ return;
758
+ }
759
+
760
+ // Generate attack paths
761
+ const data = await apiRequest('/v2/threat-engine/attack-paths/', {
762
+ method: 'POST',
763
+ body: JSON.stringify({
764
+ components,
765
+ connections,
766
+ source_node: components[0]?.id || '',
767
+ target_node: components[components.length - 1]?.id || ''
768
+ })
769
+ });
770
+
771
+ spinner.succeed('Attack path analysis complete!');
772
+
773
+ console.log(chalk.bold('\nAttack Path Analysis:\n'));
774
+ console.log(` Source: ${chalk.cyan(data.analysis_summary?.source_node || 'N/A')}`);
775
+ console.log(` Target: ${chalk.cyan(data.analysis_summary?.target_node || 'N/A')}`);
776
+ console.log(` Paths Found: ${chalk.yellow(data.analysis_summary?.total_paths_found || 0)}`);
777
+
778
+ const paths = data.attack_paths || [];
779
+ if (paths.length > 0) {
780
+ console.log(chalk.bold('\nIdentified Attack Paths:\n'));
781
+ paths.slice(0, 5).forEach((p: any, i: number) => {
782
+ const riskColor = p.risk_score > 0.5 ? chalk.red : p.risk_score > 0.2 ? chalk.yellow : chalk.green;
783
+ console.log(` ${chalk.bold(`Path ${i + 1}:`)} ${p.source_node} → ${p.target_node}`);
784
+ console.log(` Risk Score: ${riskColor((p.risk_score * 100).toFixed(1) + '%')}`);
785
+ console.log(` Likelihood: ${chalk.cyan((p.likelihood * 100).toFixed(1) + '%')}`);
786
+ console.log(` Impact: ${chalk.yellow((p.impact * 100).toFixed(1) + '%')}`);
787
+ console.log(` Steps: ${chalk.dim(p.steps?.length || 0)}`);
788
+ if (p.steps?.length > 0) {
789
+ p.steps.forEach((s: any, j: number) => {
790
+ console.log(chalk.dim(` ${j + 1}. ${s.from_node} → ${s.to_node}`));
791
+ });
792
+ }
793
+ console.log();
794
+ });
795
+ } else {
796
+ console.log(chalk.green('\n No critical attack paths identified!'));
797
+ }
798
+ } catch (error) {
799
+ spinner.fail('Attack path analysis failed');
800
+ console.error(error);
801
+ }
802
+ return;
803
+ }
804
+
805
+ if (options.analyze) {
806
+ const spinner = ora('Running comprehensive threat analysis...').start();
807
+ try {
808
+ const fullId = await resolveDiagramId(options.analyze);
809
+ const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/`);
810
+
811
+ const data = await apiRequest('/v2/threat-engine/analyze-comprehensive/', {
812
+ method: 'POST',
813
+ body: JSON.stringify({
814
+ component_data: {
815
+ id: fullId,
816
+ type: 'diagram',
817
+ name: diagramData.name || 'Diagram',
818
+ components: diagramData.components || []
819
+ },
820
+ context: {
821
+ diagram_id: fullId,
822
+ analysis_type: 'comprehensive'
823
+ }
824
+ })
825
+ });
826
+
827
+ spinner.succeed('Comprehensive analysis complete!');
828
+
829
+ console.log(chalk.bold('\nComprehensive Threat Analysis:\n'));
830
+ const analysis = data.comprehensive_analysis || {};
831
+ console.log(` Component: ${chalk.cyan(analysis.component_type || 'N/A')}`);
832
+ console.log(` Risk Level: ${chalk.yellow(analysis.risk_summary?.overall_risk_level || 'N/A')}`);
833
+ console.log(` Risk Score: ${chalk.red(analysis.risk_summary?.risk_score || 'N/A')}`);
834
+
835
+ const threats = analysis.threats || [];
836
+ if (threats.length > 0) {
837
+ console.log(chalk.bold('\nTop Threats:\n'));
838
+ threats.slice(0, 5).forEach((t: any) => {
839
+ const severity = t.severity === 'critical' ? chalk.red : t.severity === 'high' ? chalk.yellow : chalk.blue;
840
+ console.log(` ${severity(`[${t.severity?.toUpperCase()}]`)} ${t.title}`);
841
+ console.log(chalk.dim(` Category: ${t.category || 'N/A'} | MITRE: ${t.mitre_mapping || 'N/A'}`));
842
+ });
843
+ }
844
+
845
+ console.log(chalk.dim(`\nMethodologies: ${data.metadata?.methodologies?.join(', ') || 'N/A'}`));
846
+ } catch (error) {
847
+ spinner.fail('Comprehensive analysis failed');
848
+ console.error(error);
849
+ }
850
+ return;
851
+ }
852
+
853
+ if (options.requirements) {
854
+ const spinner = ora('Generating security requirements...').start();
855
+ try {
856
+ const fullId = await resolveDiagramId(options.requirements);
857
+ const diagramData = await apiRequest(`/v2/threat-modeling/diagrams/${fullId}/threats/`);
858
+
859
+ const threats = (diagramData.threats || diagramData.results || []).slice(0, 10).map((t: any) => ({
860
+ id: t.id,
861
+ title: t.title || t.name,
862
+ severity: t.severity,
863
+ category: t.category
864
+ }));
865
+
866
+ const data = await apiRequest('/v2/threat-engine/security-requirements/', {
867
+ method: 'POST',
868
+ body: JSON.stringify({
869
+ threats,
870
+ context: { diagram_id: fullId }
871
+ })
872
+ });
873
+
874
+ spinner.succeed('Security requirements generated!');
875
+
876
+ console.log(chalk.bold('\nSecurity Requirements:\n'));
877
+ console.log(` Total: ${chalk.cyan(data.summary?.total_requirements || 0)}`);
878
+ console.log(` Critical: ${chalk.red(data.summary?.critical_requirements || 0)}`);
879
+ console.log(` High: ${chalk.yellow(data.summary?.high_requirements || 0)}`);
880
+
881
+ const reqs = data.security_requirements || [];
882
+ if (reqs.length > 0) {
883
+ console.log(chalk.bold('\nRequirements:\n'));
884
+ reqs.slice(0, 5).forEach((r: any, i: number) => {
885
+ const priority = r.priority === 'critical' ? chalk.red : r.priority === 'high' ? chalk.yellow : chalk.blue;
886
+ console.log(` ${i + 1}. ${priority(`[${r.priority?.toUpperCase()}]`)} ${r.title}`);
887
+ console.log(chalk.dim(` ${r.description?.slice(0, 80) || ''}...`));
888
+ console.log(chalk.dim(` Category: ${r.category || 'N/A'}`));
889
+ });
890
+ }
891
+ } catch (error) {
892
+ spinner.fail('Security requirements generation failed');
893
+ console.error(error);
894
+ }
895
+ return;
896
+ }
897
+
898
+ // Default: show usage
899
+ console.log(chalk.bold('\nRed Team Commands:\n'));
900
+ console.log(` ${chalk.cyan('aribot redteam --methodologies')} List threat modeling methodologies`);
901
+ console.log(` ${chalk.cyan('aribot redteam --intelligence')} Get threat intelligence summary`);
902
+ console.log(` ${chalk.cyan('aribot redteam --attack-paths -d <id>')} Analyze attack paths for diagram`);
903
+ console.log(` ${chalk.cyan('aribot redteam --analyze <id>')} Comprehensive threat analysis`);
904
+ console.log(` ${chalk.cyan('aribot redteam --requirements <id>')} Generate security requirements`);
905
+ });
906
+
907
+ // AI Analysis command
908
+ program
909
+ .command('ai')
910
+ .description('AI-powered analysis and predictions')
911
+ .option('--analyze <diagram-id>', 'Analyze diagram with AI')
912
+ .option('--predict <diagram-id>', 'Predict threats for diagram')
913
+ .option('--recommendations <diagram-id>', 'Get AI recommendations')
914
+ .option('--cost <diagram-id>', 'Analyze costs with AI')
915
+ .action(async (options) => {
916
+ const spinner = ora('Running AI analysis...').start();
917
+
918
+ try {
919
+ if (options.analyze) {
920
+ const fullId = await resolveDiagramId(options.analyze);
921
+ const data = await apiRequest('/v2/ai-agents/analyze/', {
922
+ method: 'POST',
923
+ body: JSON.stringify({ diagram_id: fullId })
924
+ });
925
+ spinner.succeed('AI analysis complete!');
926
+ console.log(chalk.bold('\nAI Analysis Results:\n'));
927
+ console.log(` Risk Level: ${chalk.yellow(data.risk_level || 'N/A')}`);
928
+ console.log(` Findings: ${chalk.cyan(data.findings_count || 0)}`);
929
+ console.log(` Confidence: ${chalk.green((data.confidence || 0) + '%')}`);
930
+
931
+ } else if (options.predict) {
932
+ const fullId = await resolveDiagramId(options.predict);
933
+ const data = await apiRequest('/v2/ai-agents/predict/', {
934
+ method: 'POST',
935
+ body: JSON.stringify({ diagram_id: fullId })
936
+ });
937
+ spinner.succeed('Threat prediction complete!');
938
+ console.log(chalk.bold('\nPredicted Threats:\n'));
939
+ (data.predictions || []).slice(0, 5).forEach((p: any) => {
940
+ console.log(` ${chalk.red('•')} ${p.threat_type}: ${p.probability}% likelihood`);
941
+ });
942
+
943
+ } else if (options.recommendations) {
944
+ const fullId = await resolveDiagramId(options.recommendations);
945
+ const data = await apiRequest('/v2/ai-agents/recommendations/', {
946
+ method: 'POST',
947
+ body: JSON.stringify({ diagram_id: fullId })
948
+ });
949
+ spinner.succeed('Recommendations generated!');
950
+ console.log(chalk.bold('\nAI Recommendations:\n'));
951
+ (data.recommendations || []).slice(0, 5).forEach((r: any, i: number) => {
952
+ console.log(` ${i + 1}. ${r.title}`);
953
+ console.log(chalk.dim(` Priority: ${r.priority} | Impact: ${r.impact}`));
954
+ });
955
+
956
+ } else if (options.cost) {
957
+ const fullId = await resolveDiagramId(options.cost);
958
+ const data = await apiRequest(`/v2/ai-agents/cost-analysis/${fullId}/`);
959
+ spinner.succeed('Cost analysis complete!');
960
+ console.log(chalk.bold('\nAI Cost Analysis:\n'));
961
+ console.log(` Monthly Estimate: ${chalk.cyan('$' + (data.monthly_cost || 0).toLocaleString())}`);
962
+ console.log(` Annual Estimate: ${chalk.cyan('$' + (data.annual_cost || 0).toLocaleString())}`);
963
+ console.log(` Optimization: ${chalk.green((data.optimization_potential || 0) + '%')}`);
964
+
965
+ } else {
966
+ spinner.stop();
967
+ console.log(chalk.yellow('Usage: aribot ai [--analyze|--predict|--recommendations|--cost] <diagram-id>'));
968
+ }
969
+ } catch (error) {
970
+ spinner.fail('AI analysis failed');
971
+ console.error(error);
972
+ }
973
+ });
974
+
975
+ // SBOM (Software Bill of Materials) command
976
+ program
977
+ .command('sbom')
978
+ .description('Software Bill of Materials management')
979
+ .option('--generate <diagram-id>', 'Generate SBOM for diagram')
980
+ .option('--analyze <sbom-id>', 'Analyze SBOM dependencies')
981
+ .option('--vulnerabilities [sbom-id]', 'Scan for vulnerabilities')
982
+ .option('--list', 'List all SBOM documents')
983
+ .action(async (options) => {
984
+ const spinner = ora('Processing SBOM...').start();
985
+
986
+ try {
987
+ if (options.generate) {
988
+ const fullId = await resolveDiagramId(options.generate);
989
+ const data = await apiRequest('/v2/sbom/generate/', {
990
+ method: 'POST',
991
+ body: JSON.stringify({ diagram_id: fullId })
992
+ });
993
+ spinner.succeed('SBOM generated!');
994
+ console.log(chalk.bold('\nSBOM Document:\n'));
995
+ console.log(` ID: ${chalk.cyan(data.id || data.sbom_id)}`);
996
+ console.log(` Components: ${chalk.yellow(data.component_count || 0)}`);
997
+ console.log(` Format: ${chalk.dim(data.format || 'CycloneDX')}`);
998
+
999
+ } else if (options.analyze) {
1000
+ const data = await apiRequest('/v2/sbom/analyze/', {
1001
+ method: 'POST',
1002
+ body: JSON.stringify({ sbom_id: options.analyze })
1003
+ });
1004
+ spinner.succeed('SBOM analysis complete!');
1005
+ console.log(chalk.bold('\nDependency Analysis:\n'));
1006
+ console.log(` Total Dependencies: ${chalk.cyan(data.total_dependencies || 0)}`);
1007
+ console.log(` Direct: ${chalk.yellow(data.direct_dependencies || 0)}`);
1008
+ console.log(` Transitive: ${chalk.dim(data.transitive_dependencies || 0)}`);
1009
+ console.log(` Outdated: ${chalk.red(data.outdated_count || 0)}`);
1010
+
1011
+ } else if (options.vulnerabilities) {
1012
+ const data = await apiRequest('/v2/sbom/vulnerabilities/');
1013
+ spinner.succeed('Vulnerability scan complete!');
1014
+ console.log(chalk.bold('\nVulnerability Report:\n'));
1015
+ console.log(` Critical: ${chalk.red(data.critical || 0)}`);
1016
+ console.log(` High: ${chalk.yellow(data.high || 0)}`);
1017
+ console.log(` Medium: ${chalk.blue(data.medium || 0)}`);
1018
+ console.log(` Low: ${chalk.dim(data.low || 0)}`);
1019
+
1020
+ } else if (options.list) {
1021
+ const data = await apiRequest('/v2/sbom/documents/');
1022
+ spinner.stop();
1023
+ console.log(chalk.bold('\nSBOM Documents:\n'));
1024
+ (data.results || data || []).forEach((s: any) => {
1025
+ console.log(` ${chalk.cyan(String(s.id).slice(0, 8))} ${s.name || 'Unnamed'} ${chalk.dim(s.component_count + ' components')}`);
1026
+ });
1027
+
1028
+ } else {
1029
+ spinner.stop();
1030
+ console.log(chalk.yellow('Usage: aribot sbom [--generate <diagram-id>] [--analyze <sbom-id>] [--vulnerabilities] [--list]'));
1031
+ }
1032
+ } catch (error) {
1033
+ spinner.fail('SBOM operation failed');
1034
+ console.error(error);
1035
+ }
1036
+ });
1037
+
1038
+ // Digital Twin command
1039
+ program
1040
+ .command('digital-twin')
1041
+ .description('Digital twin and cloud resource management')
1042
+ .option('--providers', 'List cloud providers')
1043
+ .option('--resources [provider]', 'List cloud resources')
1044
+ .option('--sync <provider-id>', 'Sync cloud resources')
1045
+ .option('--discover <provider-id>', 'Discover cloud resources')
1046
+ .option('--health', 'Check digital twin health')
1047
+ .action(async (options) => {
1048
+ const spinner = ora('Processing...').start();
1049
+
1050
+ try {
1051
+ if (options.providers) {
1052
+ const data = await apiRequest('/v2/digital-twin/providers/');
1053
+ spinner.stop();
1054
+ console.log(chalk.bold('\nCloud Providers:\n'));
1055
+ (data.results || data || []).forEach((p: any) => {
1056
+ const status = p.connected ? chalk.green('✓') : chalk.red('✗');
1057
+ console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.provider_type || p.type)}`);
1058
+ });
1059
+
1060
+ } else if (options.resources) {
1061
+ const provider = typeof options.resources === 'string' ? `?provider=${options.resources}` : '';
1062
+ const data = await apiRequest(`/v2/digital-twin/resources/${provider}`);
1063
+ spinner.stop();
1064
+ console.log(chalk.bold('\nCloud Resources:\n'));
1065
+ (data.results || data || []).slice(0, 20).forEach((r: any) => {
1066
+ console.log(` ${chalk.cyan(r.resource_type || r.type)} ${r.name} ${chalk.dim(r.region || '')}`);
1067
+ });
1068
+
1069
+ } else if (options.sync) {
1070
+ const data = await apiRequest('/v2/digital-twin/sync/', {
1071
+ method: 'POST',
1072
+ body: JSON.stringify({ provider_id: options.sync })
1073
+ });
1074
+ spinner.succeed('Cloud sync initiated!');
1075
+ console.log(` Resources discovered: ${chalk.cyan(data.resources_found || 0)}`);
1076
+
1077
+ } else if (options.discover) {
1078
+ const data = await apiRequest('/v2/digital-twin/discover/', {
1079
+ method: 'POST',
1080
+ body: JSON.stringify({ provider_id: options.discover })
1081
+ });
1082
+ spinner.succeed('Discovery complete!');
1083
+ console.log(` Resources found: ${chalk.cyan(data.resources_count || 0)}`);
1084
+
1085
+ } else if (options.health) {
1086
+ const data = await apiRequest('/v2/digital-twin/health/');
1087
+ spinner.stop();
1088
+ console.log(chalk.bold('\nDigital Twin Health:\n'));
1089
+ console.log(` Status: ${data.healthy ? chalk.green('Healthy') : chalk.red('Unhealthy')}`);
1090
+ console.log(` Providers: ${chalk.cyan(data.providers_connected || 0)}`);
1091
+ console.log(` Resources: ${chalk.cyan(data.total_resources || 0)}`);
1092
+ console.log(` Last Sync: ${chalk.dim(data.last_sync || 'Never')}`);
1093
+
1094
+ } else {
1095
+ spinner.stop();
1096
+ console.log(chalk.yellow('Usage: aribot digital-twin [--providers] [--resources] [--sync <id>] [--discover <id>] [--health]'));
1097
+ }
1098
+ } catch (error) {
1099
+ spinner.fail('Digital twin operation failed');
1100
+ console.error(error);
1101
+ }
1102
+ });
1103
+
1104
+ // Pipeline Security command
1105
+ program
1106
+ .command('pipeline')
1107
+ .description('Pipeline security scanning')
1108
+ .option('--projects', 'List pipeline projects')
1109
+ .option('--scans [project-id]', 'List or run scans')
1110
+ .option('--vulnerabilities [project-id]', 'List vulnerabilities')
1111
+ .option('--scan <project-id>', 'Run a new scan')
1112
+ .option('--stats', 'Get pipeline statistics')
1113
+ .action(async (options) => {
1114
+ const spinner = ora('Processing...').start();
1115
+
1116
+ try {
1117
+ if (options.projects) {
1118
+ const data = await apiRequest('/v1/pipeline/projects/');
1119
+ spinner.stop();
1120
+ console.log(chalk.bold('\nPipeline Projects:\n'));
1121
+ (data.results || data || []).forEach((p: any) => {
1122
+ const status = p.last_scan_status === 'passed' ? chalk.green('✓') : chalk.red('✗');
1123
+ console.log(` ${status} ${chalk.cyan(p.name)} ${chalk.dim(p.repository || '')}`);
1124
+ });
1125
+
1126
+ } else if (options.scans) {
1127
+ const project = typeof options.scans === 'string' ? `?project=${options.scans}` : '';
1128
+ const data = await apiRequest(`/v1/pipeline/scans/${project}`);
1129
+ spinner.stop();
1130
+ console.log(chalk.bold('\nPipeline Scans:\n'));
1131
+ (data.results || data || []).slice(0, 10).forEach((s: any) => {
1132
+ const status = s.status === 'completed' ? chalk.green('✓') : chalk.yellow('⋯');
1133
+ console.log(` ${status} ${chalk.cyan(String(s.id).slice(0, 8))} ${s.scan_type || 'security'} ${chalk.dim(s.created_at?.slice(0, 10) || '')}`);
1134
+ });
1135
+
1136
+ } else if (options.vulnerabilities) {
1137
+ const project = typeof options.vulnerabilities === 'string' ? `?project=${options.vulnerabilities}` : '';
1138
+ const data = await apiRequest(`/v1/pipeline/vulnerabilities/${project}`);
1139
+ spinner.stop();
1140
+ console.log(chalk.bold('\nPipeline Vulnerabilities:\n'));
1141
+ (data.results || data || []).slice(0, 10).forEach((v: any) => {
1142
+ const severity = v.severity === 'critical' ? chalk.red : v.severity === 'high' ? chalk.yellow : chalk.blue;
1143
+ console.log(` ${severity(`[${v.severity?.toUpperCase()}]`)} ${v.title || v.name}`);
1144
+ });
1145
+
1146
+ } else if (options.scan) {
1147
+ const data = await apiRequest('/v1/pipeline/scans/', {
1148
+ method: 'POST',
1149
+ body: JSON.stringify({ project_id: options.scan })
1150
+ });
1151
+ spinner.succeed('Scan initiated!');
1152
+ console.log(` Scan ID: ${chalk.cyan(data.id || data.scan_id)}`);
1153
+
1154
+ } else if (options.stats) {
1155
+ const data = await apiRequest('/v1/pipeline/stats/');
1156
+ spinner.stop();
1157
+ console.log(chalk.bold('\nPipeline Statistics:\n'));
1158
+ console.log(` Total Projects: ${chalk.cyan(data.total_projects || 0)}`);
1159
+ console.log(` Total Scans: ${chalk.cyan(data.total_scans || 0)}`);
1160
+ console.log(` Vulnerabilities: ${chalk.red(data.total_vulnerabilities || 0)}`);
1161
+ console.log(` Pass Rate: ${chalk.green((data.pass_rate || 0) + '%')}`);
1162
+
1163
+ } else {
1164
+ spinner.stop();
1165
+ console.log(chalk.yellow('Usage: aribot pipeline [--projects] [--scans] [--vulnerabilities] [--scan <id>] [--stats]'));
1166
+ }
1167
+ } catch (error) {
1168
+ spinner.fail('Pipeline operation failed');
1169
+ console.error(error);
1170
+ }
1171
+ });
1172
+
1173
+ // API Keys command
1174
+ program
1175
+ .command('api-keys')
1176
+ .description('Manage API keys')
1177
+ .option('--list', 'List all API keys')
1178
+ .option('--create <name>', 'Create new API key')
1179
+ .option('--delete <key-id>', 'Delete API key')
1180
+ .option('--usage', 'Show API usage')
1181
+ .action(async (options) => {
1182
+ const spinner = ora('Processing...').start();
1183
+
1184
+ try {
1185
+ if (options.list) {
1186
+ const data = await apiRequest('/v1/developer/api-keys/');
1187
+ spinner.stop();
1188
+ console.log(chalk.bold('\nAPI Keys:\n'));
1189
+ (data.results || data || []).forEach((k: any) => {
1190
+ const status = k.is_active ? chalk.green('active') : chalk.red('inactive');
1191
+ console.log(` ${chalk.cyan(k.name)} ${chalk.dim(k.key_prefix + '...')} ${status}`);
1192
+ });
1193
+
1194
+ } else if (options.create) {
1195
+ const data = await apiRequest('/v1/developer/api-keys/', {
1196
+ method: 'POST',
1197
+ body: JSON.stringify({ name: options.create })
1198
+ });
1199
+ spinner.succeed('API key created!');
1200
+ console.log(chalk.bold('\nNew API Key:\n'));
1201
+ console.log(` Name: ${chalk.cyan(data.name)}`);
1202
+ console.log(` Key: ${chalk.yellow(data.key)}`);
1203
+ console.log(chalk.red('\n ⚠ Save this key now - it won\'t be shown again!'));
1204
+
1205
+ } else if (options.delete) {
1206
+ await apiRequest(`/v1/developer/api-keys/${options.delete}/`, {
1207
+ method: 'DELETE'
1208
+ });
1209
+ spinner.succeed('API key deleted!');
1210
+
1211
+ } else if (options.usage) {
1212
+ const data = await apiRequest('/v1/developer/usage/');
1213
+ spinner.stop();
1214
+ console.log(chalk.bold('\nAPI Usage:\n'));
1215
+ console.log(` Today: ${chalk.cyan(data.today || 0)} requests`);
1216
+ console.log(` This Month: ${chalk.cyan(data.this_month || 0)} requests`);
1217
+ console.log(` Limit: ${chalk.dim(data.limit || 'unlimited')}`);
1218
+
1219
+ } else {
1220
+ spinner.stop();
1221
+ console.log(chalk.yellow('Usage: aribot api-keys [--list] [--create <name>] [--delete <id>] [--usage]'));
1222
+ }
1223
+ } catch (error) {
1224
+ spinner.fail('API key operation failed');
1225
+ console.error(error);
1226
+ }
1227
+ });
1228
+
1229
+ // Marketplace command
1230
+ program
1231
+ .command('marketplace')
1232
+ .description('Browse and manage architecture templates')
1233
+ .option('--search <query>', 'Search templates')
1234
+ .option('--featured', 'List featured templates')
1235
+ .option('--categories', 'List template categories')
1236
+ .option('--my-templates', 'List your templates')
1237
+ .option('--get <template-id>', 'Get template details')
1238
+ .action(async (options) => {
1239
+ const spinner = ora('Fetching...').start();
1240
+
1241
+ try {
1242
+ if (options.search) {
1243
+ const data = await apiRequest(`/v2/marketplace/search/?q=${encodeURIComponent(options.search)}`);
1244
+ spinner.stop();
1245
+ console.log(chalk.bold(`\nSearch Results for "${options.search}":\n`));
1246
+ (data.results || data || []).slice(0, 10).forEach((t: any) => {
1247
+ console.log(` ${chalk.cyan(t.name)} ${chalk.dim('$' + (t.price || 0))}`);
1248
+ console.log(chalk.dim(` ${t.description?.slice(0, 60) || ''}...`));
1249
+ });
1250
+
1251
+ } else if (options.featured) {
1252
+ const data = await apiRequest('/v2/marketplace/featured/');
1253
+ spinner.stop();
1254
+ console.log(chalk.bold('\nFeatured Templates:\n'));
1255
+ (data.results || data || []).forEach((t: any) => {
1256
+ console.log(` ${chalk.green('★')} ${chalk.cyan(t.name)} ${chalk.dim('$' + (t.price || 0))}`);
1257
+ });
1258
+
1259
+ } else if (options.categories) {
1260
+ const data = await apiRequest('/v2/marketplace/categories/');
1261
+ spinner.stop();
1262
+ console.log(chalk.bold('\nTemplate Categories:\n'));
1263
+ (data.results || data || []).forEach((c: any) => {
1264
+ console.log(` ${chalk.cyan(c.name)} ${chalk.dim(c.template_count + ' templates')}`);
1265
+ });
1266
+
1267
+ } else if (options.myTemplates) {
1268
+ const data = await apiRequest('/v2/marketplace/my-templates/');
1269
+ spinner.stop();
1270
+ console.log(chalk.bold('\nYour Templates:\n'));
1271
+ (data.results || data || []).forEach((t: any) => {
1272
+ console.log(` ${chalk.cyan(t.name)} ${chalk.dim(t.status)}`);
1273
+ });
1274
+
1275
+ } else if (options.get) {
1276
+ const data = await apiRequest(`/v2/marketplace/v2/templates/${options.get}/`);
1277
+ spinner.stop();
1278
+ console.log(chalk.bold(`\n${data.name}\n`));
1279
+ console.log(` Category: ${chalk.cyan(data.category)}`);
1280
+ console.log(` Price: ${chalk.yellow('$' + (data.price || 0))}`);
1281
+ console.log(` Downloads: ${chalk.dim(data.download_count || 0)}`);
1282
+ console.log(` Rating: ${chalk.green(data.rating || 'N/A')}`);
1283
+ console.log(`\n ${chalk.dim(data.description || '')}`);
1284
+
1285
+ } else {
1286
+ spinner.stop();
1287
+ console.log(chalk.yellow('Usage: aribot marketplace [--search <query>] [--featured] [--categories] [--my-templates] [--get <id>]'));
1288
+ }
1289
+ } catch (error) {
1290
+ spinner.fail('Marketplace operation failed');
1291
+ console.error(error);
1292
+ }
1293
+ });
1294
+
1295
+ // Dashboard command
1296
+ program
1297
+ .command('dashboard')
1298
+ .description('View dashboard and statistics')
1299
+ .option('--overview', 'Show dashboard overview')
1300
+ .option('--recent', 'Show recent activity')
1301
+ .option('--risk', 'Show risk summary')
1302
+ .option('--billing', 'Show billing information')
1303
+ .action(async (options) => {
1304
+ const spinner = ora('Loading dashboard...').start();
1305
+
1306
+ try {
1307
+ if (options.overview || (!options.recent && !options.risk && !options.billing)) {
1308
+ const data = await apiRequest('/v2/threat-modeling/dashboard/');
1309
+ spinner.stop();
1310
+ console.log(chalk.bold('\nDashboard Overview:\n'));
1311
+ console.log(` Total Diagrams: ${chalk.cyan(data.total_diagrams || 0)}`);
1312
+ console.log(` Total Threats: ${chalk.yellow(data.total_threats || 0)}`);
1313
+ console.log(` Critical Threats: ${chalk.red(data.critical_threats || 0)}`);
1314
+ console.log(` Compliance Score: ${chalk.green((data.compliance_score || 0) + '%')}`);
1315
+
1316
+ } else if (options.recent) {
1317
+ const data = await apiRequest('/v2/threat-modeling/dashboard/recent-activity/');
1318
+ spinner.stop();
1319
+ console.log(chalk.bold('\nRecent Activity:\n'));
1320
+ (data.activities || data || []).slice(0, 10).forEach((a: any) => {
1321
+ console.log(` ${chalk.dim(a.timestamp?.slice(0, 16) || '')} ${a.action} ${chalk.cyan(a.resource || '')}`);
1322
+ });
1323
+
1324
+ } else if (options.risk) {
1325
+ const data = await apiRequest('/v2/threat-modeling/dashboard/risk-summary/');
1326
+ spinner.stop();
1327
+ console.log(chalk.bold('\nRisk Summary:\n'));
1328
+ console.log(` Overall Risk: ${data.overall_risk === 'high' ? chalk.red(data.overall_risk) : chalk.yellow(data.overall_risk || 'N/A')}`);
1329
+ console.log(` Open Threats: ${chalk.yellow(data.open_threats || 0)}`);
1330
+ console.log(` Mitigated: ${chalk.green(data.mitigated_threats || 0)}`);
1331
+
1332
+ } else if (options.billing) {
1333
+ const data = await apiRequest('/v1/developer/billing/');
1334
+ spinner.stop();
1335
+ console.log(chalk.bold('\nBilling Information:\n'));
1336
+ console.log(` Plan: ${chalk.cyan(data.plan || 'Free')}`);
1337
+ console.log(` Usage: ${chalk.yellow((data.usage || 0) + ' requests')}`);
1338
+ console.log(` Next Billing: ${chalk.dim(data.next_billing_date || 'N/A')}`);
1339
+ }
1340
+ } catch (error) {
1341
+ spinner.fail('Dashboard failed to load');
1342
+ console.error(error);
1343
+ }
1344
+ });
1345
+
351
1346
  program.parse();