codeflow-hook 1.3.0 â 2.0.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.
- package/README.md +140 -122
- package/bin/codeflow-hook.js +280 -71
- package/lib/cli-integration/dist/index.d.ts +128 -0
- package/lib/cli-integration/dist/index.js +585 -0
- package/lib/cli-integration/dist/pipelineConfigs.d.ts +60 -0
- package/lib/cli-integration/dist/pipelineConfigs.js +549 -0
- package/lib/cli-integration/dist/simulationEngine.d.ts +86 -0
- package/lib/cli-integration/dist/simulationEngine.js +475 -0
- package/lib/cli-integration/dist/types.d.ts +156 -0
- package/lib/cli-integration/dist/types.js +15 -0
- package/lib/cli-integration/src/index.ts +748 -0
- package/lib/cli-integration/src/pipelineConfigs.ts +579 -0
- package/lib/cli-integration/src/simulationEngine.ts +622 -0
- package/lib/cli-integration/src/types.ts +175 -0
- package/package.json +10 -4
package/bin/codeflow-hook.js
CHANGED
|
@@ -8,9 +8,11 @@ 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
|
|
|
13
|
+
// Import CLI integration service
|
|
14
|
+
import { indexProject, analyzeDiff } from '../lib/cli-integration/dist/index.js';
|
|
15
|
+
|
|
14
16
|
// Export for use in agents module
|
|
15
17
|
export { callAIProvider };
|
|
16
18
|
|
|
@@ -18,8 +20,8 @@ const program = new Command();
|
|
|
18
20
|
|
|
19
21
|
program
|
|
20
22
|
.name('codeflow-hook')
|
|
21
|
-
.description('Interactive CI/CD simulator and AI-powered code reviewer')
|
|
22
|
-
.version('
|
|
23
|
+
.description('Interactive CI/CD simulator and AI-powered code reviewer with EKG backend integration')
|
|
24
|
+
.version('4.0.0');
|
|
23
25
|
|
|
24
26
|
// Configure AI provider settings
|
|
25
27
|
program
|
|
@@ -199,41 +201,34 @@ program
|
|
|
199
201
|
}
|
|
200
202
|
});
|
|
201
203
|
|
|
202
|
-
// Index
|
|
204
|
+
// Index repository via EKG Ingestion Service (Phase 4)
|
|
203
205
|
program
|
|
204
206
|
.command('index')
|
|
205
|
-
.description('Index
|
|
206
|
-
.option('-d, --dry-run', 'Show what
|
|
207
|
+
.description('Index repository via EKG Ingestion Service')
|
|
208
|
+
.option('-d, --dry-run', 'Show what would be indexed without actually indexing')
|
|
207
209
|
.action(async (options) => {
|
|
208
210
|
try {
|
|
209
|
-
const
|
|
211
|
+
const spinner = ora('Submitting repository for EKG analysis...').start();
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
213
|
+
const result = await indexProject({
|
|
214
|
+
dryRun: options.dryRun || false
|
|
215
|
+
});
|
|
215
216
|
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
spinner.succeed('Repository indexing initiated');
|
|
218
|
+
console.log(chalk.green(`â
${result.message}`));
|
|
218
219
|
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
console.log(chalk.blue('đ Dry run mode - files to be indexed:'));
|
|
222
|
-
const { findKeyFiles } = await import('./rag.js');
|
|
223
|
-
const keyFiles = await findKeyFiles(process.cwd());
|
|
224
|
-
keyFiles.forEach(file => console.log(chalk.gray(` - ${file}`)));
|
|
225
|
-
console.log(chalk.green(`đ Total files to index: ${keyFiles.length}`));
|
|
226
|
-
return;
|
|
220
|
+
if (result.repositoryId) {
|
|
221
|
+
console.log(chalk.blue(`đ Repository ID: ${result.repositoryId}`));
|
|
227
222
|
}
|
|
228
223
|
|
|
229
|
-
|
|
224
|
+
if (result.stats) {
|
|
225
|
+
console.log(chalk.gray(`đ Stats: ${JSON.stringify(result.stats, null, 2)}`));
|
|
226
|
+
}
|
|
230
227
|
|
|
231
|
-
|
|
232
|
-
console.log(chalk.green(`â
Indexed ${result.indexedFiles} files with ${result.totalChunks} chunks`));
|
|
233
|
-
console.log(chalk.blue('đ Knowledge base stored in: .codeflow/index/'));
|
|
228
|
+
console.log(chalk.cyan('đ Repository submitted to EKG Ingestion Service for analysis'));
|
|
234
229
|
|
|
235
230
|
} catch (error) {
|
|
236
|
-
console.
|
|
231
|
+
console.log(chalk.red(`â Indexing failed: ${error.message}`));
|
|
237
232
|
process.exit(1);
|
|
238
233
|
}
|
|
239
234
|
});
|
|
@@ -298,13 +293,12 @@ exit 0
|
|
|
298
293
|
}
|
|
299
294
|
});
|
|
300
295
|
|
|
301
|
-
// Analyze diff with
|
|
296
|
+
// Analyze diff with EKG Query Service context enhancement (Phase 4)
|
|
302
297
|
program
|
|
303
298
|
.command('analyze-diff')
|
|
304
|
-
.description('Analyze git diff using
|
|
299
|
+
.description('Analyze git diff using EKG context enhancement')
|
|
305
300
|
.argument('[diff]', 'Git diff content')
|
|
306
|
-
.option('--legacy', 'Use legacy
|
|
307
|
-
.option('--no-rag', 'Disable RAG context retrieval')
|
|
301
|
+
.option('--legacy', 'Use legacy analysis instead of EKG-enhanced analysis')
|
|
308
302
|
.action(async (diff, options) => {
|
|
309
303
|
try {
|
|
310
304
|
// Read diff content from stdin or argument
|
|
@@ -317,63 +311,120 @@ program
|
|
|
317
311
|
diffContent = Buffer.concat(chunks).toString('utf8');
|
|
318
312
|
}
|
|
319
313
|
|
|
320
|
-
const configPath = path.join(os.homedir(), '.codeflow-hook', 'config.json');
|
|
321
|
-
|
|
322
|
-
if (!fs.existsSync(configPath)) {
|
|
323
|
-
console.log(chalk.red('No configuration found. Run: codeflow-hook config -k <api-key>'));
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
328
|
-
|
|
329
314
|
if (diffContent.trim() === '') {
|
|
330
315
|
console.log(chalk.gray('âšī¸ No changes to analyze'));
|
|
331
316
|
return;
|
|
332
317
|
}
|
|
333
318
|
|
|
334
|
-
|
|
335
|
-
if (options.legacy) {
|
|
336
|
-
const spinner = ora(`Analyzing code with ${config.provider}...`).start();
|
|
337
|
-
const prompt = generateCodeReviewPrompt(diffContent);
|
|
319
|
+
console.log(chalk.blue('đŦ Analyzing diff with EKG context enhancement...'));
|
|
338
320
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
321
|
+
const result = await analyzeDiff(diffContent, {
|
|
322
|
+
legacy: options.legacy || false,
|
|
323
|
+
outputFormat: 'console'
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
if (result.success) {
|
|
327
|
+
console.log(chalk.green(`â
${result.message}`));
|
|
328
|
+
displayEKGAnalysisResults(result.analysis);
|
|
329
|
+
|
|
330
|
+
if (result.stats) {
|
|
331
|
+
console.log(chalk.gray(`đ EKG Queries: ${result.stats.ekg_queries}`));
|
|
332
|
+
console.log(chalk.gray(`đĨ Similar Repos Found: ${result.stats.similar_repos_found}`));
|
|
333
|
+
console.log(chalk.gray(`âąī¸ Analysis Time: ${result.stats.analysis_time}ms`));
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
console.log(chalk.red(`â Analysis failed: ${result.message}`));
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.log(chalk.red(`â Analysis error: ${error.message}`));
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
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
|
+
});
|
|
345
381
|
process.exit(1);
|
|
346
382
|
}
|
|
383
|
+
}
|
|
347
384
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
385
|
+
// Apply customizations
|
|
386
|
+
if (options.mode) {
|
|
387
|
+
pipelineConfig.settings.mode = options.mode.toUpperCase();
|
|
351
388
|
}
|
|
352
389
|
|
|
353
|
-
|
|
354
|
-
|
|
390
|
+
if (options.commitMessage) {
|
|
391
|
+
pipelineConfig.environment = {
|
|
392
|
+
...pipelineConfig.environment,
|
|
393
|
+
COMMIT_MESSAGE: options.commitMessage
|
|
394
|
+
};
|
|
395
|
+
}
|
|
355
396
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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);
|
|
370
414
|
}
|
|
371
415
|
|
|
372
|
-
|
|
373
|
-
|
|
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);
|
|
374
425
|
|
|
375
426
|
} catch (error) {
|
|
376
|
-
console.log(chalk.red(
|
|
427
|
+
console.log(chalk.red(`â Simulation failed: ${error.message}`));
|
|
377
428
|
process.exit(1);
|
|
378
429
|
}
|
|
379
430
|
});
|
|
@@ -734,5 +785,163 @@ function getTypeIcon(type) {
|
|
|
734
785
|
}
|
|
735
786
|
}
|
|
736
787
|
|
|
788
|
+
// Display EKG-enhanced analysis results (Phase 4)
|
|
789
|
+
function displayEKGAnalysisResults(analysis) {
|
|
790
|
+
if (!analysis) {
|
|
791
|
+
console.log(chalk.yellow('â ī¸ No analysis results available'));
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Display summary
|
|
796
|
+
if (analysis.summary) {
|
|
797
|
+
console.log(chalk.blue('đ Analysis Summary:'));
|
|
798
|
+
console.log(` đ Files modified: ${analysis.summary.totalFiles}`);
|
|
799
|
+
console.log(` â Additions: ${analysis.summary.totalAdditions}`);
|
|
800
|
+
console.log(` â Deletions: ${analysis.summary.totalDeletions}`);
|
|
801
|
+
console.log(` đ§ EKG enhanced: ${analysis.summary.ekgEnhanced ? 'Yes' : 'No'}`);
|
|
802
|
+
console.log();
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Display EKG context information
|
|
806
|
+
if (analysis.ekg_context) {
|
|
807
|
+
console.log(chalk.blue('đ§ EKG Context:'));
|
|
808
|
+
console.log(` đ Patterns analyzed: ${analysis.ekg_context.patterns_analyzed || 0}`);
|
|
809
|
+
console.log(` đĨ Similar repositories: ${analysis.ekg_context.similar_repositories_found || 0}`);
|
|
810
|
+
console.log(` đ Repository known to EKG: ${analysis.ekg_context.repository_known ? 'Yes' : 'No'}`);
|
|
811
|
+
console.log();
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// Display issues
|
|
815
|
+
if (analysis.issues && analysis.issues.length > 0) {
|
|
816
|
+
console.log(chalk.yellow('â ī¸ Issues Found:'));
|
|
817
|
+
analysis.issues.forEach(issue => {
|
|
818
|
+
const severityColor = getSeverityColor(issue.severity);
|
|
819
|
+
const typeIcon = getTypeIcon(issue.type);
|
|
820
|
+
console.log(` ${severityColor}${typeIcon} ${issue.severity}: ${issue.description}`);
|
|
821
|
+
});
|
|
822
|
+
console.log();
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Display recommendations
|
|
826
|
+
if (analysis.recommendations && analysis.recommendations.length > 0) {
|
|
827
|
+
console.log(chalk.green('đĄ Recommendations:'));
|
|
828
|
+
analysis.recommendations.forEach(rec => {
|
|
829
|
+
const severityColor = getSeverityColor(rec.severity);
|
|
830
|
+
console.log(` ${severityColor}âĸ ${rec.description}`);
|
|
831
|
+
if (rec.file) {
|
|
832
|
+
console.log(chalk.gray(` đ File: ${rec.file}`));
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
console.log();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// Display file details
|
|
839
|
+
if (analysis.files && analysis.files.length > 0) {
|
|
840
|
+
console.log(chalk.blue('đ Files Changed:'));
|
|
841
|
+
analysis.files.forEach(file => {
|
|
842
|
+
const changeType = file.isNew ? 'NEW' : 'MODIFIED';
|
|
843
|
+
const changeColor = file.isNew ? chalk.green : chalk.blue;
|
|
844
|
+
console.log(`${changeColor} ${changeType} ${file.path} (${file.language})`);
|
|
845
|
+
console.log(chalk.gray(` +${file.additions} -${file.deletions} changes`));
|
|
846
|
+
});
|
|
847
|
+
console.log();
|
|
848
|
+
}
|
|
849
|
+
}
|
|
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
|
+
|
|
737
946
|
// Make sure the final line uses parseAsync
|
|
738
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;
|