@wundr.io/cli 1.0.1 → 1.0.2-dev.20260530180455.e1307186
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/bin/wundr.js +13 -5
- package/package.json +30 -9
- package/src/ai/ai-service.ts +6 -4
- package/src/ai/claude-client.ts +6 -2
- package/src/ai/conversation-manager.ts +12 -5
- package/src/cli.ts +42 -13
- package/src/commands/ai.ts +340 -64
- package/src/commands/alignment.ts +1212 -0
- package/src/commands/analyze-optimized.ts +371 -33
- package/src/commands/analyze.ts +8 -6
- package/src/commands/batch.ts +166 -26
- package/src/commands/chat.ts +20 -10
- package/src/commands/claude-init.ts +31 -27
- package/src/commands/claude-setup.ts +761 -81
- package/src/commands/computer-setup.ts +524 -12
- package/src/commands/create-command.ts +3 -3
- package/src/commands/create.ts +9 -6
- package/src/commands/dashboard.ts +11 -6
- package/src/commands/govern.ts +11 -6
- package/src/commands/governance.ts +1005 -0
- package/src/commands/guardian.ts +887 -0
- package/src/commands/init.ts +104 -11
- package/src/commands/orchestrator.ts +789 -0
- package/src/commands/performance-optimizer.ts +15 -10
- package/src/commands/plugins.ts +8 -5
- package/src/commands/project-update.ts +1156 -0
- package/src/commands/rag.ts +1011 -0
- package/src/commands/session.ts +631 -0
- package/src/commands/setup.ts +42 -344
- package/src/commands/test-init.ts +3 -2
- package/src/commands/test.ts +3 -2
- package/src/commands/watch.ts +21 -11
- package/src/commands/worktree.ts +1057 -0
- package/src/context/context-manager.ts +5 -2
- package/src/context/session-manager.ts +18 -7
- package/src/framework/command-interface.ts +520 -0
- package/src/framework/command-registry.ts +942 -0
- package/src/framework/completion-exporter.ts +383 -0
- package/src/framework/debug-logger.ts +519 -0
- package/src/framework/error-handler.ts +867 -0
- package/src/framework/help-generator.ts +540 -0
- package/src/framework/index.ts +169 -0
- package/src/framework/interactive-repl.ts +703 -0
- package/src/framework/output-formatter.ts +834 -0
- package/src/framework/progress-manager.ts +539 -0
- package/src/index.ts +3 -2
- package/src/interactive/interactive-mode.ts +14 -7
- package/src/lib/conflict-resolution.ts +818 -0
- package/src/lib/merge-strategy.ts +550 -0
- package/src/lib/safety-mechanisms.ts +451 -0
- package/src/lib/state-detection.ts +1030 -0
- package/src/nlp/command-mapper.ts +8 -3
- package/src/nlp/command-parser.ts +5 -2
- package/src/nlp/intent-parser.ts +23 -9
- package/src/plugins/plugin-manager.ts +50 -24
- package/src/tests/computer-setup-integration.test.ts +46 -15
- package/src/types/index.ts +1 -1
- package/src/types/modules.d.ts +425 -1
- package/src/utils/backup-rollback-manager.ts +19 -14
- package/src/utils/claude-config-installer.ts +119 -28
- package/src/utils/config-manager.ts +9 -6
- package/src/utils/error-handler.ts +3 -1
- package/src/utils/logger.ts +35 -12
- package/templates/batch/ci-cd.yaml +7 -7
- package/test-suites/api/health.spec.ts +20 -23
- package/test-suites/helpers/test-config.ts +14 -13
- package/test-suites/ui/accessibility.spec.ts +27 -22
- package/test-suites/ui/smoke.spec.ts +26 -21
- package/src/commands/computer-setup-commands.ts +0 -869
package/src/commands/ai.ts
CHANGED
|
@@ -1,24 +1,55 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
1
|
import chalk from 'chalk';
|
|
4
|
-
import
|
|
5
|
-
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
|
|
6
4
|
import { AIService } from '../ai/ai-service';
|
|
7
|
-
import { logger } from '../utils/logger';
|
|
8
5
|
import { errorHandler } from '../utils/error-handler';
|
|
9
|
-
import {
|
|
6
|
+
import { logger } from '../utils/logger';
|
|
7
|
+
|
|
8
|
+
import type { PluginManager } from '../plugins/plugin-manager';
|
|
9
|
+
import type { ChatSession } from '../types';
|
|
10
|
+
import type { ConfigManager } from '../utils/config-manager';
|
|
11
|
+
import type { Command } from 'commander';
|
|
12
|
+
|
|
13
|
+
/** Review result for a single file */
|
|
14
|
+
interface FileReviewResult {
|
|
15
|
+
file: string;
|
|
16
|
+
issues: Array<{ severity: string; description: string }>;
|
|
17
|
+
suggestions: string[];
|
|
18
|
+
score: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Refactoring plan from AI analysis */
|
|
22
|
+
interface RefactoringPlan {
|
|
23
|
+
description: string;
|
|
24
|
+
changes: Array<{ description: string; code?: string }>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Optimization plan from AI analysis */
|
|
28
|
+
interface OptimizationPlan {
|
|
29
|
+
description: string;
|
|
30
|
+
changes: Array<{ description: string; code?: string }>;
|
|
31
|
+
optimizedCode: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Benchmark result metrics */
|
|
35
|
+
interface BenchmarkResult {
|
|
36
|
+
time: number;
|
|
37
|
+
memory: number;
|
|
38
|
+
}
|
|
10
39
|
|
|
11
40
|
/**
|
|
12
41
|
* AI commands for AI-powered development features
|
|
13
42
|
*/
|
|
14
43
|
export class AICommands {
|
|
15
44
|
private aiService: AIService;
|
|
45
|
+
private pluginManager: PluginManager;
|
|
16
46
|
|
|
17
47
|
constructor(
|
|
18
48
|
private program: Command,
|
|
19
49
|
private configManager: ConfigManager,
|
|
20
|
-
|
|
50
|
+
pluginManager: PluginManager
|
|
21
51
|
) {
|
|
52
|
+
this.pluginManager = pluginManager;
|
|
22
53
|
this.aiService = new AIService(configManager);
|
|
23
54
|
this.registerCommands();
|
|
24
55
|
}
|
|
@@ -261,12 +292,7 @@ export class AICommands {
|
|
|
261
292
|
|
|
262
293
|
const filesToReview =
|
|
263
294
|
files.length > 0 ? files : await this.getChangedFiles();
|
|
264
|
-
const reviewResults:
|
|
265
|
-
file: string;
|
|
266
|
-
issues: any;
|
|
267
|
-
suggestions: any;
|
|
268
|
-
score: any;
|
|
269
|
-
}> = [];
|
|
295
|
+
const reviewResults: FileReviewResult[] = [];
|
|
270
296
|
|
|
271
297
|
for (const file of filesToReview) {
|
|
272
298
|
logger.debug(`Reviewing ${file}...`);
|
|
@@ -378,7 +404,7 @@ export class AICommands {
|
|
|
378
404
|
);
|
|
379
405
|
|
|
380
406
|
const code = await this.readFile(target);
|
|
381
|
-
const
|
|
407
|
+
const docs = await this.callAI('docs', {
|
|
382
408
|
code,
|
|
383
409
|
target,
|
|
384
410
|
type: options.type,
|
|
@@ -391,7 +417,7 @@ export class AICommands {
|
|
|
391
417
|
options.type,
|
|
392
418
|
options.format
|
|
393
419
|
);
|
|
394
|
-
await this.saveGeneratedDocs(
|
|
420
|
+
await this.saveGeneratedDocs(docs, outputPath);
|
|
395
421
|
|
|
396
422
|
logger.success(`Documentation generated: ${outputPath}`);
|
|
397
423
|
} catch (error) {
|
|
@@ -526,13 +552,13 @@ export class AICommands {
|
|
|
526
552
|
logger.info(`Optimizing ${chalk.cyan(target)}...`);
|
|
527
553
|
|
|
528
554
|
const code = await this.readFile(target);
|
|
529
|
-
let beforeBenchmark
|
|
555
|
+
let beforeBenchmark: BenchmarkResult | undefined;
|
|
530
556
|
|
|
531
557
|
if (options.benchmarks) {
|
|
532
558
|
beforeBenchmark = await this.runBenchmark(target);
|
|
533
559
|
}
|
|
534
560
|
|
|
535
|
-
const
|
|
561
|
+
const optimization: OptimizationPlan = await this.callAI('optimize', {
|
|
536
562
|
code,
|
|
537
563
|
target,
|
|
538
564
|
focus: options.focus,
|
|
@@ -548,9 +574,9 @@ export class AICommands {
|
|
|
548
574
|
]);
|
|
549
575
|
|
|
550
576
|
if (apply) {
|
|
551
|
-
await this.applyOptimization(target,
|
|
577
|
+
await this.applyOptimization(target, optimization);
|
|
552
578
|
|
|
553
|
-
if (options.benchmarks) {
|
|
579
|
+
if (options.benchmarks && beforeBenchmark) {
|
|
554
580
|
const afterBenchmark = await this.runBenchmark(target);
|
|
555
581
|
this.displayBenchmarkComparison(beforeBenchmark, afterBenchmark);
|
|
556
582
|
}
|
|
@@ -783,29 +809,153 @@ export class AICommands {
|
|
|
783
809
|
private async callAI(operation: string, params: any): Promise<any> {
|
|
784
810
|
// Check if AI service is ready
|
|
785
811
|
if (!this.aiService.isReady()) {
|
|
786
|
-
throw new Error(
|
|
812
|
+
throw new Error(
|
|
813
|
+
'AI service not configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY, or run `wundr ai setup`.'
|
|
814
|
+
);
|
|
787
815
|
}
|
|
788
816
|
|
|
789
817
|
logger.debug(`Calling AI for operation: ${operation}`);
|
|
790
818
|
|
|
791
|
-
|
|
819
|
+
const sessionId = `ai-cmd-${operation}-${Date.now()}`;
|
|
820
|
+
|
|
792
821
|
switch (operation) {
|
|
793
|
-
case 'generate':
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
822
|
+
case 'generate': {
|
|
823
|
+
const prompt = [
|
|
824
|
+
`Generate ${params.type} code.`,
|
|
825
|
+
params.prompt ? `Requirements: ${params.prompt}` : '',
|
|
826
|
+
params.template ? `Use template style: ${params.template}` : '',
|
|
827
|
+
params.context ? `Context:\n${params.context}` : '',
|
|
828
|
+
'Return only the code, no explanation.',
|
|
829
|
+
]
|
|
830
|
+
.filter(Boolean)
|
|
831
|
+
.join('\n');
|
|
832
|
+
return this.aiService.sendMessage(sessionId, prompt);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
case 'review': {
|
|
836
|
+
const prompt = [
|
|
837
|
+
`Review the following ${params.file} code for issues.`,
|
|
838
|
+
`Focus: ${params.focus || 'all'}. Minimum severity: ${params.severity || 'info'}.`,
|
|
839
|
+
'Return a JSON object with this exact shape: {"issues":[{"severity":"string","description":"string"}],"suggestions":["string"],"score":number}',
|
|
840
|
+
`Code:\n${params.code}`,
|
|
841
|
+
].join('\n');
|
|
842
|
+
const raw = await this.aiService.sendMessage(sessionId, prompt);
|
|
843
|
+
try {
|
|
844
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
845
|
+
return jsonMatch
|
|
846
|
+
? JSON.parse(jsonMatch[0])
|
|
847
|
+
: { issues: [], suggestions: [], score: 0 };
|
|
848
|
+
} catch {
|
|
849
|
+
return { issues: [], suggestions: [], score: 0 };
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
case 'refactor': {
|
|
854
|
+
const prompt = [
|
|
855
|
+
`Create a refactoring plan for the following code in ${params.target}.`,
|
|
856
|
+
`Refactoring type: ${params.type || 'optimize'}. Scope: ${params.scope || 'function'}.`,
|
|
857
|
+
'Return a JSON object with this exact shape: {"description":"string","changes":[{"description":"string","code":"string"}]}',
|
|
858
|
+
`Code:\n${params.code}`,
|
|
859
|
+
].join('\n');
|
|
860
|
+
const raw = await this.aiService.sendMessage(sessionId, prompt);
|
|
861
|
+
try {
|
|
862
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
863
|
+
return jsonMatch
|
|
864
|
+
? JSON.parse(jsonMatch[0])
|
|
865
|
+
: { description: '', changes: [] };
|
|
866
|
+
} catch {
|
|
867
|
+
return { description: '', changes: [] };
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
case 'docs': {
|
|
872
|
+
const prompt = [
|
|
873
|
+
`Generate ${params.type || 'api'} documentation in ${params.format || 'markdown'} format for ${params.target}.`,
|
|
874
|
+
params.includeExamples ? 'Include code examples.' : '',
|
|
875
|
+
`Code:\n${params.code}`,
|
|
876
|
+
]
|
|
877
|
+
.filter(Boolean)
|
|
878
|
+
.join('\n');
|
|
879
|
+
return this.aiService.sendMessage(sessionId, prompt);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
case 'test': {
|
|
883
|
+
const prompt = [
|
|
884
|
+
`Generate ${params.coverage || 'unit'} tests using ${params.framework || 'jest'} for ${params.target}.`,
|
|
885
|
+
params.mocks ? 'Include mock objects where appropriate.' : '',
|
|
886
|
+
'Return only the test code, no explanation.',
|
|
887
|
+
`Code:\n${params.code}`,
|
|
888
|
+
]
|
|
889
|
+
.filter(Boolean)
|
|
890
|
+
.join('\n');
|
|
891
|
+
return this.aiService.sendMessage(sessionId, prompt);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
case 'analyze': {
|
|
895
|
+
const prompt = [
|
|
896
|
+
`Analyze the following code from ${params.target}.`,
|
|
897
|
+
`Aspect: ${params.aspect || 'all'}.`,
|
|
898
|
+
params.suggestions ? 'Include improvement suggestions.' : '',
|
|
899
|
+
'Return a JSON object with this exact shape: {"complexity":"string","maintainability":"string","suggestions":["string"]}',
|
|
900
|
+
`Code:\n${params.code}`,
|
|
901
|
+
]
|
|
902
|
+
.filter(Boolean)
|
|
903
|
+
.join('\n');
|
|
904
|
+
const raw = await this.aiService.sendMessage(sessionId, prompt);
|
|
905
|
+
try {
|
|
906
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
907
|
+
return jsonMatch
|
|
908
|
+
? JSON.parse(jsonMatch[0])
|
|
909
|
+
: {
|
|
910
|
+
complexity: 'unknown',
|
|
911
|
+
maintainability: 'unknown',
|
|
912
|
+
suggestions: [],
|
|
913
|
+
};
|
|
914
|
+
} catch {
|
|
915
|
+
return {
|
|
916
|
+
complexity: 'unknown',
|
|
917
|
+
maintainability: 'unknown',
|
|
918
|
+
suggestions: [],
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
case 'optimize': {
|
|
924
|
+
const prompt = [
|
|
925
|
+
`Create a performance optimization plan for the following code in ${params.target}.`,
|
|
926
|
+
`Optimization focus: ${params.focus || 'speed'}.`,
|
|
927
|
+
'Return a JSON object with this exact shape: {"description":"string","changes":[{"description":"string"}],"optimizedCode":"string"}',
|
|
928
|
+
`Code:\n${params.code}`,
|
|
929
|
+
].join('\n');
|
|
930
|
+
const raw = await this.aiService.sendMessage(sessionId, prompt);
|
|
931
|
+
try {
|
|
932
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
933
|
+
return jsonMatch
|
|
934
|
+
? JSON.parse(jsonMatch[0])
|
|
935
|
+
: { description: '', changes: [], optimizedCode: params.code };
|
|
936
|
+
} catch {
|
|
937
|
+
return { description: '', changes: [], optimizedCode: params.code };
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
807
941
|
case 'chat':
|
|
808
|
-
return
|
|
942
|
+
return this.aiService.sendMessage(sessionId, params.message || '');
|
|
943
|
+
|
|
944
|
+
case 'suggest-fix': {
|
|
945
|
+
const prompt = [
|
|
946
|
+
`Suggest a fix for the following issue in ${params.file}:`,
|
|
947
|
+
`Issue (${params.severity}): ${params.issue}`,
|
|
948
|
+
'Return a JSON object with this shape: {"suggestion":"string"}',
|
|
949
|
+
].join('\n');
|
|
950
|
+
const raw = await this.aiService.sendMessage(sessionId, prompt);
|
|
951
|
+
try {
|
|
952
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
953
|
+
return jsonMatch ? JSON.parse(jsonMatch[0]) : { suggestion: raw };
|
|
954
|
+
} catch {
|
|
955
|
+
return { suggestion: raw };
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
809
959
|
default:
|
|
810
960
|
throw new Error(`Unknown AI operation: ${operation}`);
|
|
811
961
|
}
|
|
@@ -824,48 +974,120 @@ export class AICommands {
|
|
|
824
974
|
}
|
|
825
975
|
|
|
826
976
|
private async loadContext(contextPath: string): Promise<string> {
|
|
827
|
-
|
|
828
|
-
|
|
977
|
+
const fs = await import('fs/promises');
|
|
978
|
+
const path = await import('path');
|
|
979
|
+
const stat = await fs.stat(contextPath);
|
|
980
|
+
if (stat.isDirectory()) {
|
|
981
|
+
// Read all TypeScript/JavaScript files in the directory (non-recursive, shallow)
|
|
982
|
+
const entries = await fs.readdir(contextPath);
|
|
983
|
+
const parts: string[] = [];
|
|
984
|
+
for (const entry of entries) {
|
|
985
|
+
if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
|
|
986
|
+
const filePath = path.join(contextPath, entry);
|
|
987
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
988
|
+
parts.push(`// ${filePath}\n${content}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return parts.join('\n\n');
|
|
992
|
+
}
|
|
993
|
+
return fs.readFile(contextPath, 'utf-8');
|
|
829
994
|
}
|
|
830
995
|
|
|
831
996
|
private async saveGeneratedCode(
|
|
832
|
-
|
|
997
|
+
code: string,
|
|
833
998
|
outputPath: string
|
|
834
999
|
): Promise<void> {
|
|
835
|
-
|
|
836
|
-
|
|
1000
|
+
const fs = await import('fs/promises');
|
|
1001
|
+
const path = await import('path');
|
|
1002
|
+
|
|
1003
|
+
// Ensure directory exists
|
|
1004
|
+
const dir = path.dirname(outputPath);
|
|
1005
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1006
|
+
|
|
1007
|
+
// Write the generated code to file
|
|
1008
|
+
await fs.writeFile(outputPath, code, 'utf-8');
|
|
1009
|
+
logger.debug(`Saved generated code to ${outputPath}`);
|
|
837
1010
|
}
|
|
838
1011
|
|
|
839
1012
|
private async readFile(filePath: string): Promise<string> {
|
|
840
|
-
|
|
841
|
-
return
|
|
1013
|
+
const fs = await import('fs/promises');
|
|
1014
|
+
return fs.readFile(filePath, 'utf-8');
|
|
842
1015
|
}
|
|
843
1016
|
|
|
844
1017
|
private async getChangedFiles(): Promise<string[]> {
|
|
845
|
-
|
|
846
|
-
|
|
1018
|
+
const { execSync } = await import('child_process');
|
|
1019
|
+
try {
|
|
1020
|
+
const output = execSync('git diff --name-only HEAD', {
|
|
1021
|
+
encoding: 'utf-8',
|
|
1022
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1023
|
+
}).trim();
|
|
1024
|
+
if (!output) {
|
|
1025
|
+
return [];
|
|
1026
|
+
}
|
|
1027
|
+
return output.split('\n').filter(Boolean);
|
|
1028
|
+
} catch {
|
|
1029
|
+
// Fall back to staged changes if HEAD diff fails (e.g. no commits yet)
|
|
1030
|
+
try {
|
|
1031
|
+
const { execSync: exec } = await import('child_process');
|
|
1032
|
+
const output = exec('git diff --name-only --cached', {
|
|
1033
|
+
encoding: 'utf-8',
|
|
1034
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1035
|
+
}).trim();
|
|
1036
|
+
return output ? output.split('\n').filter(Boolean) : [];
|
|
1037
|
+
} catch {
|
|
1038
|
+
return [];
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
847
1041
|
}
|
|
848
1042
|
|
|
849
|
-
private displayReviewResults(results:
|
|
1043
|
+
private displayReviewResults(results: FileReviewResult[]): void {
|
|
850
1044
|
console.log(chalk.blue('\nCode Review Results:'));
|
|
851
1045
|
results.forEach(result => {
|
|
852
1046
|
console.log(`\n${chalk.cyan(result.file)} (Score: ${result.score}/100)`);
|
|
853
1047
|
if (result.issues.length > 0) {
|
|
854
|
-
result.issues.forEach(
|
|
1048
|
+
result.issues.forEach(issue => {
|
|
855
1049
|
console.log(` ${issue.severity}: ${issue.description}`);
|
|
856
1050
|
});
|
|
857
1051
|
}
|
|
858
1052
|
});
|
|
859
1053
|
}
|
|
860
1054
|
|
|
861
|
-
private async suggestFixes(
|
|
862
|
-
// Implementation for suggesting fixes
|
|
1055
|
+
private async suggestFixes(results: FileReviewResult[]): Promise<void> {
|
|
863
1056
|
logger.info('Generating fix suggestions...');
|
|
1057
|
+
|
|
1058
|
+
for (const result of results) {
|
|
1059
|
+
if (result.issues.length > 0) {
|
|
1060
|
+
console.log(chalk.yellow(`\nSuggested fixes for ${result.file}:`));
|
|
1061
|
+
for (const issue of result.issues) {
|
|
1062
|
+
const fix = await this.callAI('suggest-fix', {
|
|
1063
|
+
file: result.file,
|
|
1064
|
+
issue: issue.description,
|
|
1065
|
+
severity: issue.severity,
|
|
1066
|
+
});
|
|
1067
|
+
console.log(
|
|
1068
|
+
` - ${issue.description}: ${fix.suggestion || 'No automatic fix available'}`
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
864
1073
|
}
|
|
865
1074
|
|
|
866
|
-
private async applyRefactoring(
|
|
867
|
-
|
|
1075
|
+
private async applyRefactoring(
|
|
1076
|
+
target: string,
|
|
1077
|
+
plan: RefactoringPlan
|
|
1078
|
+
): Promise<void> {
|
|
1079
|
+
const fs = await import('fs/promises');
|
|
1080
|
+
|
|
868
1081
|
logger.debug(`Applying refactoring to ${target}`);
|
|
1082
|
+
logger.info(`Refactoring: ${plan.description}`);
|
|
1083
|
+
|
|
1084
|
+
// Apply each change from the refactoring plan
|
|
1085
|
+
for (const change of plan.changes) {
|
|
1086
|
+
logger.debug(` Applying: ${change.description}`);
|
|
1087
|
+
if (change.code) {
|
|
1088
|
+
await fs.writeFile(target, change.code, 'utf-8');
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
869
1091
|
}
|
|
870
1092
|
|
|
871
1093
|
private getDocsOutputPath(
|
|
@@ -878,15 +1100,29 @@ export class AICommands {
|
|
|
878
1100
|
}
|
|
879
1101
|
|
|
880
1102
|
private async saveGeneratedDocs(
|
|
881
|
-
|
|
1103
|
+
docs: string,
|
|
882
1104
|
outputPath: string
|
|
883
1105
|
): Promise<void> {
|
|
884
|
-
|
|
885
|
-
|
|
1106
|
+
const fs = await import('fs/promises');
|
|
1107
|
+
const path = await import('path');
|
|
1108
|
+
|
|
1109
|
+
// Ensure docs directory exists
|
|
1110
|
+
const dir = path.dirname(outputPath);
|
|
1111
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1112
|
+
|
|
1113
|
+
// Write the generated documentation to file
|
|
1114
|
+
await fs.writeFile(outputPath, docs, 'utf-8');
|
|
1115
|
+
logger.debug(`Saved documentation to ${outputPath}`);
|
|
886
1116
|
}
|
|
887
1117
|
|
|
888
|
-
private getTestOutputPath(target: string,
|
|
889
|
-
|
|
1118
|
+
private getTestOutputPath(target: string, framework: string): string {
|
|
1119
|
+
const path = require('path');
|
|
1120
|
+
const baseName = path.basename(target, path.extname(target));
|
|
1121
|
+
const dirName = path.dirname(target);
|
|
1122
|
+
|
|
1123
|
+
// Use framework-specific test file extensions
|
|
1124
|
+
const extension = framework === 'vitest' ? '.test.ts' : '.test.js';
|
|
1125
|
+
return path.join(dirName, '__tests__', `${baseName}${extension}`);
|
|
890
1126
|
}
|
|
891
1127
|
|
|
892
1128
|
private async loadChatSession(sessionId: string): Promise<ChatSession> {
|
|
@@ -970,26 +1206,66 @@ export class AICommands {
|
|
|
970
1206
|
}
|
|
971
1207
|
}
|
|
972
1208
|
|
|
973
|
-
private async runBenchmark(
|
|
974
|
-
|
|
975
|
-
|
|
1209
|
+
private async runBenchmark(target: string): Promise<BenchmarkResult> {
|
|
1210
|
+
const { performance } = await import('perf_hooks');
|
|
1211
|
+
|
|
1212
|
+
logger.debug(`Running benchmark for ${target}`);
|
|
1213
|
+
|
|
1214
|
+
const startTime = performance.now();
|
|
1215
|
+
const startMemory = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
1216
|
+
|
|
1217
|
+
// Simulate loading and analyzing the file for benchmarking
|
|
1218
|
+
const code = await this.readFile(target);
|
|
1219
|
+
// Simple analysis to measure time
|
|
1220
|
+
const lines = code.split('\n').length;
|
|
1221
|
+
logger.debug(`Analyzed ${lines} lines`);
|
|
1222
|
+
|
|
1223
|
+
const endTime = performance.now();
|
|
1224
|
+
const endMemory = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
1225
|
+
|
|
1226
|
+
return {
|
|
1227
|
+
time: Math.round(endTime - startTime),
|
|
1228
|
+
memory: Math.round(endMemory - startMemory),
|
|
1229
|
+
};
|
|
976
1230
|
}
|
|
977
1231
|
|
|
978
1232
|
private async applyOptimization(
|
|
979
1233
|
target: string,
|
|
980
|
-
|
|
1234
|
+
optimization: OptimizationPlan
|
|
981
1235
|
): Promise<void> {
|
|
982
|
-
|
|
1236
|
+
const fs = await import('fs/promises');
|
|
1237
|
+
|
|
983
1238
|
logger.debug(`Applying optimization to ${target}`);
|
|
1239
|
+
logger.info(`Optimization: ${optimization.description}`);
|
|
1240
|
+
|
|
1241
|
+
// Log each change being applied
|
|
1242
|
+
for (const change of optimization.changes) {
|
|
1243
|
+
logger.debug(` Applying: ${change.description}`);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Write the optimized code to the file
|
|
1247
|
+
if (optimization.optimizedCode) {
|
|
1248
|
+
await fs.writeFile(target, optimization.optimizedCode, 'utf-8');
|
|
1249
|
+
logger.success(`Optimization applied to ${target}`);
|
|
1250
|
+
}
|
|
984
1251
|
}
|
|
985
1252
|
|
|
986
|
-
private displayBenchmarkComparison(
|
|
1253
|
+
private displayBenchmarkComparison(
|
|
1254
|
+
before: BenchmarkResult,
|
|
1255
|
+
after: BenchmarkResult
|
|
1256
|
+
): void {
|
|
987
1257
|
console.log(chalk.blue('\nBenchmark Comparison:'));
|
|
1258
|
+
const timeDiff = after.time - before.time;
|
|
1259
|
+
const memDiff = after.memory - before.memory;
|
|
1260
|
+
|
|
1261
|
+
const timeColor = timeDiff < 0 ? chalk.green : chalk.yellow;
|
|
1262
|
+
const memColor = memDiff < 0 ? chalk.green : chalk.yellow;
|
|
1263
|
+
|
|
988
1264
|
console.log(
|
|
989
|
-
`Time: ${before.time}ms → ${after.time}ms (${
|
|
1265
|
+
`Time: ${before.time}ms → ${after.time}ms (${timeColor(timeDiff > 0 ? '+' : '')}${timeColor(timeDiff + 'ms')})`
|
|
990
1266
|
);
|
|
991
1267
|
console.log(
|
|
992
|
-
`Memory: ${before.memory}MB → ${after.memory}MB (${
|
|
1268
|
+
`Memory: ${before.memory}MB → ${after.memory}MB (${memColor(memDiff > 0 ? '+' : '')}${memColor(memDiff + 'MB')})`
|
|
993
1269
|
);
|
|
994
1270
|
}
|
|
995
1271
|
}
|