codeflow-hook 1.4.0 → 2.1.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.
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
@@ -8,11 +8,10 @@ import fs from 'fs';
8
8
  import path from 'path';
9
9
  import os from 'os'; // Make sure os is imported
10
10
  import readline from 'readline';
11
- import { indexProject } from './rag.js';
12
11
  import { orchestrateReview } from './agents.js';
13
12
 
14
13
  // Import CLI integration service
15
- import { indexProject, analyzeDiff } from '../services/cli-integration/src/index.js';
14
+ import { indexProject, analyzeDiff } from '../lib/cli-integration/dist/index.js';
16
15
 
17
16
  // Export for use in agents module
18
17
  export { callAIProvider };
@@ -344,6 +343,92 @@ program
344
343
  }
345
344
  });
346
345
 
346
+ // Run pipeline simulation (Enhanced Frontend Integration)
347
+ program
348
+ .command('simulate')
349
+ .description('Run configurable CI/CD pipeline simulation')
350
+ .argument('[template]', 'Pipeline template ID (nodejs-basic, enterprise-advanced, fast-dev, chaotic-test, microservices-parallel)')
351
+ .option('-c, --config <file>', 'Custom pipeline configuration JSON file')
352
+ .option('-o, --output <file>', 'Output results to JSON file')
353
+ .option('-m, --mode <mode>', 'Simulation mode (REALISTIC, FAST, DETERMINISTIC, CHAOTIC)', 'REALISTIC')
354
+ .option('--commit-message <message>', 'Custom commit message for simulation')
355
+ .option('--json', 'Output results as JSON only')
356
+ .action(async (template, options) => {
357
+ try {
358
+ let pipelineConfig;
359
+
360
+ // Load configuration from file or template
361
+ if (options.config) {
362
+ console.log(chalk.blue(`📄 Loading pipeline config from: ${options.config}`));
363
+ const fs = await import('fs/promises');
364
+ const configData = await fs.readFile(options.config, 'utf8');
365
+ pipelineConfig = JSON.parse(configData);
366
+ } else {
367
+ const templateId = template || 'nodejs-basic';
368
+ console.log(chalk.blue(`🎯 Using pipeline template: ${templateId}`));
369
+
370
+ // Import simulation engine and config manager dynamically
371
+ const { PipelineConfigManager } = await import('../lib/cli-integration/dist/pipelineConfigs.js');
372
+ pipelineConfig = PipelineConfigManager.getPipelineById(templateId);
373
+
374
+ if (!pipelineConfig) {
375
+ console.log(chalk.red(`❌ Unknown pipeline template: ${templateId}`));
376
+ console.log(chalk.gray('Available templates:'));
377
+ const templates = PipelineConfigManager.getAvailableTemplates();
378
+ templates.forEach(t => {
379
+ console.log(chalk.gray(` • ${t.id}: ${t.description}`));
380
+ });
381
+ process.exit(1);
382
+ }
383
+ }
384
+
385
+ // Apply customizations
386
+ if (options.mode) {
387
+ pipelineConfig.settings.mode = options.mode.toUpperCase();
388
+ }
389
+
390
+ if (options.commitMessage) {
391
+ pipelineConfig.environment = {
392
+ ...pipelineConfig.environment,
393
+ COMMIT_MESSAGE: options.commitMessage
394
+ };
395
+ }
396
+
397
+ console.log(chalk.blue(`🚀 Starting pipeline simulation: ${pipelineConfig.name}`));
398
+ console.log(chalk.gray(` Mode: ${pipelineConfig.settings.mode}`));
399
+ console.log(chalk.gray(` Stages: ${pipelineConfig.stages.length}`));
400
+
401
+ const spinner = ora('Running pipeline simulation...').start();
402
+
403
+ // Import and run simulation engine
404
+ const { simulationEngine } = await import('../lib/cli-integration/dist/simulationEngine.js');
405
+ const result = await simulationEngine.executePipeline(pipelineConfig);
406
+
407
+ spinner.succeed('Simulation completed');
408
+
409
+ // Display results
410
+ if (options.json) {
411
+ console.log(JSON.stringify(result, null, 2));
412
+ } else {
413
+ displaySimulationResults(result);
414
+ }
415
+
416
+ // Save to file if requested
417
+ if (options.output) {
418
+ const fs = await import('fs/promises');
419
+ await fs.writeFile(options.output, JSON.stringify(result, null, 2), 'utf8');
420
+ console.log(chalk.green(`💾 Results saved to: ${options.output}`));
421
+ }
422
+
423
+ // Exit with appropriate code
424
+ process.exit(result.status === 'success' ? 0 : 1);
425
+
426
+ } catch (error) {
427
+ console.log(chalk.red(`❌ Simulation failed: ${error.message}`));
428
+ process.exit(1);
429
+ }
430
+ });
431
+
347
432
  // Show status
348
433
  program
349
434
  .command('status')
@@ -763,5 +848,100 @@ function displayEKGAnalysisResults(analysis) {
763
848
  }
764
849
  }
765
850
 
851
+ // Display pipeline simulation results
852
+ function displaySimulationResults(result) {
853
+ if (!result) {
854
+ console.log(chalk.yellow('⚠️ No simulation results available'));
855
+ return;
856
+ }
857
+
858
+ // Overall status
859
+ const statusIcon = result.status === 'success' ? '✅' :
860
+ result.status === 'failed' ? '❌' :
861
+ result.status === 'partial' ? '⚠️' : '⏸️';
862
+ const statusColor = result.status === 'success' ? chalk.green :
863
+ result.status === 'failed' ? chalk.red :
864
+ result.status === 'partial' ? chalk.yellow : chalk.gray;
865
+
866
+ console.log(statusColor(`${statusIcon} Pipeline ${result.status.toUpperCase()}`));
867
+ console.log(chalk.blue(`📋 Execution ID: ${result.executionId}`));
868
+ console.log(chalk.gray(`⏱️ Duration: ${(result.metrics.totalDuration / 1000).toFixed(2)}s`));
869
+ console.log();
870
+
871
+ // Pipeline metrics
872
+ console.log(chalk.blue('📊 Pipeline Metrics:'));
873
+ console.log(` 📊 Stages: ${result.metrics.successCount}/${result.metrics.stageCount} passed`);
874
+ if (result.metrics.failureCount > 0) {
875
+ console.log(chalk.red(` ❌ Failed: ${result.metrics.failureCount}`));
876
+ }
877
+ if (result.metrics.skippedCount > 0) {
878
+ console.log(chalk.yellow(` ⏭️ Skipped: ${result.metrics.skippedCount}`));
879
+ }
880
+ console.log(` 📈 Avg Stage Duration: ${(result.metrics.averageStageDuration / 1000).toFixed(2)}s`);
881
+ if (result.metrics.bottleneckStage) {
882
+ console.log(chalk.yellow(` 🐌 Bottleneck: ${result.metrics.bottleneckStage}`));
883
+ }
884
+ console.log();
885
+
886
+ // Resource utilization
887
+ console.log(chalk.blue('💻 Resource Utilization:'));
888
+ console.log(` 🖥️ Avg CPU: ${result.metrics.resourceUtilization.avgCpu}%`);
889
+ console.log(` 🧠 Avg Memory: ${result.metrics.resourceUtilization.avgMemory}MB`);
890
+ console.log(` 🔥 Peak CPU: ${result.metrics.resourceUtilization.peakCpu}%`);
891
+ console.log(` 💾 Peak Memory: ${result.metrics.resourceUtilization.peakMemory}MB`);
892
+ console.log();
893
+
894
+ // Stage details
895
+ console.log(chalk.blue('🔧 Stage Results:'));
896
+ result.stages.forEach(stage => {
897
+ const stageIcon = stage.status === 'SUCCESS' ? '✅' :
898
+ stage.status === 'FAILED' ? '❌' :
899
+ stage.status === 'SKIPPED' ? '⏭️' : '⏳';
900
+ const stageColor = stage.status === 'SUCCESS' ? chalk.green :
901
+ stage.status === 'FAILED' ? chalk.red :
902
+ stage.status === 'SKIPPED' ? chalk.yellow : chalk.gray;
903
+
904
+ const duration = stage.duration ? `${(stage.duration / 1000).toFixed(2)}s` : 'N/A';
905
+ console.log(`${stageColor(` ${stageIcon} ${stage.id}: ${duration}`)}`);
906
+
907
+ // Show metrics if available
908
+ if (stage.metrics) {
909
+ console.log(chalk.gray(` CPU: ${stage.metrics.cpuUsage}%, Mem: ${stage.metrics.memoryUsage}MB`));
910
+ }
911
+
912
+ // Show errors if any
913
+ if (stage.errors && stage.errors.length > 0) {
914
+ stage.errors.forEach(error => {
915
+ console.log(chalk.red(` 💥 ${error.message}`));
916
+ });
917
+ }
918
+ });
919
+ console.log();
920
+
921
+ // Artifacts
922
+ if (result.artifacts && result.artifacts.length > 0) {
923
+ console.log(chalk.blue('📦 Generated Artifacts:'));
924
+ result.artifacts.forEach(artifact => {
925
+ console.log(` 📄 ${artifact.name} (${(artifact.size / 1024 / 1024).toFixed(2)}MB)`);
926
+ console.log(chalk.gray(` ${artifact.path}`));
927
+ });
928
+ console.log();
929
+ }
930
+
931
+ // Execution logs summary
932
+ if (result.logs && result.logs.length > 0) {
933
+ console.log(chalk.blue('📝 Execution Summary:'));
934
+ // Show last few log lines
935
+ const recentLogs = result.logs.slice(-5);
936
+ recentLogs.forEach(log => {
937
+ console.log(chalk.gray(` ${log}`));
938
+ });
939
+ if (result.logs.length > 5) {
940
+ console.log(chalk.gray(` ... and ${result.logs.length - 5} more log entries`));
941
+ }
942
+ console.log();
943
+ }
944
+ }
945
+
766
946
  // Make sure the final line uses parseAsync
767
947
  program.parseAsync(process.argv);
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI Integration Service - Phase 4
4
+ *
5
+ * Bridges the local CLI commands with EKG backend services.
6
+ * Transforms CLI operations from local processing to backend-driven workflows.
7
+ *
8
+ * Key transformations:
9
+ * - `codeflow index` → EKG Ingestion Service webhook simulation
10
+ * - `codeflow analyze-diff` → EKG Query Service context-enhanced analysis
11
+ */
12
+ /**
13
+ * CLI Integration Service
14
+ * Provides methods that CLI commands can call to interact with EKG backend
15
+ */
16
+ export declare class CLIIntegrationService {
17
+ private config;
18
+ private git;
19
+ constructor();
20
+ /**
21
+ * Index repository for EKG - equivalent to `codeflow index`
22
+ *
23
+ * Sends repository URL to EKG Ingestion Service for analysis and graph population
24
+ */
25
+ indexRepository(options?: {
26
+ repositoryUrl?: string;
27
+ dryRun?: boolean;
28
+ }): Promise<{
29
+ success: boolean;
30
+ repositoryId?: string;
31
+ message: string;
32
+ stats?: {
33
+ indexedFiles: number;
34
+ analysisTime: number;
35
+ webhookAccepted: boolean;
36
+ };
37
+ }>;
38
+ /**
39
+ * Analyze code diff with EKG context enhancement
40
+ *
41
+ * Sends diff to Query Service for EKG-enhanced analysis instead of local RAG
42
+ */
43
+ analyzeDiff(diffContent: string, options?: {
44
+ legacy?: boolean;
45
+ outputFormat?: 'console' | 'json';
46
+ }): Promise<{
47
+ success: boolean;
48
+ analysis: any;
49
+ message: string;
50
+ stats?: {
51
+ ekg_queries: number;
52
+ similar_repos_found: number;
53
+ analysis_time: number;
54
+ };
55
+ }>;
56
+ /**
57
+ * Analyze diff content and extract structured information
58
+ */
59
+ private analyzeDiffContent;
60
+ /**
61
+ * Query EKG for context on affected files
62
+ */
63
+ private getEKGContext;
64
+ /**
65
+ * Generate enhanced analysis using EKG context
66
+ */
67
+ private generateEKGEnhancedAnalysis;
68
+ /**
69
+ * Get current repository information
70
+ */
71
+ private getRepositoryInfo;
72
+ /**
73
+ * Get list of files that would be indexed
74
+ */
75
+ private getIndexableFiles;
76
+ /**
77
+ * Make HTTP request to backend service with retry logic
78
+ */
79
+ private makeBackendRequest;
80
+ /**
81
+ * Make GraphQL request to Query Service
82
+ */
83
+ private makeGraphQLRequest;
84
+ /**
85
+ * Generate repository ID (similar to ingestion service)
86
+ */
87
+ private generateRepositoryId;
88
+ /**
89
+ * Get current user information
90
+ */
91
+ private getCurrentUser;
92
+ /**
93
+ * Detect language from file extension
94
+ */
95
+ private detectLanguage;
96
+ /**
97
+ * Format error for logging and display
98
+ */
99
+ private formatError;
100
+ }
101
+ export declare const cliIntegrationService: CLIIntegrationService;
102
+ export declare const indexProject: (options?: {
103
+ repositoryUrl?: string;
104
+ dryRun?: boolean;
105
+ }) => Promise<{
106
+ success: boolean;
107
+ repositoryId?: string;
108
+ message: string;
109
+ stats?: {
110
+ indexedFiles: number;
111
+ analysisTime: number;
112
+ webhookAccepted: boolean;
113
+ };
114
+ }>;
115
+ export declare const analyzeDiff: (diffContent: string, options?: {
116
+ legacy?: boolean;
117
+ outputFormat?: 'console' | 'json';
118
+ }) => Promise<{
119
+ success: boolean;
120
+ analysis: any;
121
+ message: string;
122
+ stats?: {
123
+ ekg_queries: number;
124
+ similar_repos_found: number;
125
+ analysis_time: number;
126
+ };
127
+ }>;
128
+ export default cliIntegrationService;