vigthoria-cli 1.6.1 → 1.6.4
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 +52 -1
- package/dist/commands/chat.d.ts +31 -45
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +374 -855
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/repo.d.ts +10 -0
- package/dist/commands/repo.d.ts.map +1 -1
- package/dist/commands/repo.js +215 -97
- package/dist/commands/repo.js.map +1 -1
- package/dist/index.js +32 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +8 -0
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +183 -42
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +2 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/tools.d.ts +3 -0
- package/dist/utils/tools.d.ts.map +1 -1
- package/dist/utils/tools.js +252 -14
- package/dist/utils/tools.js.map +1 -1
- package/package.json +13 -2
- package/install.ps1 +0 -290
- package/install.sh +0 -307
- package/src/commands/auth.ts +0 -226
- package/src/commands/chat.ts +0 -1101
- package/src/commands/config.ts +0 -306
- package/src/commands/deploy.ts +0 -609
- package/src/commands/edit.ts +0 -310
- package/src/commands/explain.ts +0 -115
- package/src/commands/generate.ts +0 -222
- package/src/commands/hub.ts +0 -382
- package/src/commands/repo.ts +0 -742
- package/src/commands/review.ts +0 -186
- package/src/index.ts +0 -601
- package/src/types/marked-terminal.d.ts +0 -31
- package/src/utils/api.ts +0 -526
- package/src/utils/config.ts +0 -241
- package/src/utils/files.ts +0 -273
- package/src/utils/logger.ts +0 -130
- package/src/utils/session.ts +0 -179
- package/src/utils/tools.ts +0 -1964
- package/test-parse.js +0 -105
- package/test-parse2.js +0 -35
- package/tsconfig.json +0 -20
package/src/commands/edit.ts
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Edit Command - File editing with AI assistance
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import ora from 'ora';
|
|
7
|
-
import * as readline from 'readline';
|
|
8
|
-
import inquirer from 'inquirer';
|
|
9
|
-
import { Config } from '../utils/config.js';
|
|
10
|
-
import { Logger } from '../utils/logger.js';
|
|
11
|
-
import { APIClient } from '../utils/api.js';
|
|
12
|
-
import { FileUtils } from '../utils/files.js';
|
|
13
|
-
|
|
14
|
-
interface EditOptions {
|
|
15
|
-
instruction?: string;
|
|
16
|
-
model: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface FixOptions {
|
|
20
|
-
type: string;
|
|
21
|
-
apply: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class EditCommand {
|
|
25
|
-
private config: Config;
|
|
26
|
-
private logger: Logger;
|
|
27
|
-
private api: APIClient;
|
|
28
|
-
private fileUtils: FileUtils;
|
|
29
|
-
|
|
30
|
-
constructor(config: Config, logger: Logger) {
|
|
31
|
-
this.config = config;
|
|
32
|
-
this.logger = logger;
|
|
33
|
-
this.api = new APIClient(config, logger);
|
|
34
|
-
this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async run(filePath: string, options: EditOptions): Promise<void> {
|
|
38
|
-
// Check auth
|
|
39
|
-
if (!this.config.isAuthenticated()) {
|
|
40
|
-
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Read file
|
|
45
|
-
const file = this.fileUtils.readFile(filePath);
|
|
46
|
-
if (!file) {
|
|
47
|
-
this.logger.error(`File not found: ${filePath}`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.logger.section(`Editing: ${file.relativePath}`);
|
|
52
|
-
console.log(chalk.gray(`Language: ${file.language} | Lines: ${file.lines}`));
|
|
53
|
-
console.log();
|
|
54
|
-
|
|
55
|
-
// Get instruction
|
|
56
|
-
let instruction = options.instruction;
|
|
57
|
-
if (!instruction) {
|
|
58
|
-
const answer = await inquirer.prompt([
|
|
59
|
-
{
|
|
60
|
-
type: 'input',
|
|
61
|
-
name: 'instruction',
|
|
62
|
-
message: 'What changes would you like to make?',
|
|
63
|
-
validate: (input) => input.length > 0 || 'Please provide an instruction',
|
|
64
|
-
},
|
|
65
|
-
]);
|
|
66
|
-
instruction = answer.instruction;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Generate edit
|
|
70
|
-
const spinner = ora({
|
|
71
|
-
text: 'Generating changes...',
|
|
72
|
-
spinner: 'dots',
|
|
73
|
-
}).start();
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const response = await this.api.chat([
|
|
77
|
-
{
|
|
78
|
-
role: 'system',
|
|
79
|
-
content: `You are a code editor. Edit the provided code according to the user's instruction.
|
|
80
|
-
Return ONLY the complete modified code without any explanation or markdown formatting.
|
|
81
|
-
Preserve the original formatting and style unless the instruction specifically asks to change it.`,
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
role: 'user',
|
|
85
|
-
content: `File: ${file.relativePath}
|
|
86
|
-
Language: ${file.language}
|
|
87
|
-
|
|
88
|
-
Original code:
|
|
89
|
-
\`\`\`${file.language}
|
|
90
|
-
${file.content}
|
|
91
|
-
\`\`\`
|
|
92
|
-
|
|
93
|
-
Instruction: ${instruction}
|
|
94
|
-
|
|
95
|
-
Return the complete modified code:`,
|
|
96
|
-
},
|
|
97
|
-
], options.model);
|
|
98
|
-
|
|
99
|
-
spinner.stop();
|
|
100
|
-
|
|
101
|
-
// Extract code from response
|
|
102
|
-
const modifiedCode = this.extractCode(response.message, file.language);
|
|
103
|
-
|
|
104
|
-
if (!modifiedCode) {
|
|
105
|
-
this.logger.error('Failed to generate valid code changes');
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Show diff
|
|
110
|
-
await this.showDiffAndConfirm(file.path, file.content, modifiedCode);
|
|
111
|
-
|
|
112
|
-
} catch (error) {
|
|
113
|
-
spinner.stop();
|
|
114
|
-
this.logger.error('Edit failed:', (error as Error).message);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async fix(filePath: string, options: FixOptions): Promise<void> {
|
|
119
|
-
// Check auth
|
|
120
|
-
if (!this.config.isAuthenticated()) {
|
|
121
|
-
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Read file
|
|
126
|
-
const file = this.fileUtils.readFile(filePath);
|
|
127
|
-
if (!file) {
|
|
128
|
-
this.logger.error(`File not found: ${filePath}`);
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this.logger.section(`Fixing: ${file.relativePath}`);
|
|
133
|
-
console.log(chalk.gray(`Fix type: ${options.type} | Language: ${file.language}`));
|
|
134
|
-
console.log();
|
|
135
|
-
|
|
136
|
-
const spinner = ora({
|
|
137
|
-
text: `Analyzing for ${options.type} issues...`,
|
|
138
|
-
spinner: 'dots',
|
|
139
|
-
}).start();
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
const result = await this.api.fixCode(file.content, file.language, options.type);
|
|
143
|
-
|
|
144
|
-
spinner.stop();
|
|
145
|
-
|
|
146
|
-
if (result.changes.length === 0) {
|
|
147
|
-
this.logger.success('No issues found!');
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Show fixes
|
|
152
|
-
this.logger.section(`Found ${result.changes.length} issue(s)`);
|
|
153
|
-
|
|
154
|
-
result.changes.forEach((change, i) => {
|
|
155
|
-
console.log(chalk.yellow(`${i + 1}. Line ${change.line}:`));
|
|
156
|
-
console.log(chalk.red(` - ${change.before}`));
|
|
157
|
-
console.log(chalk.green(` + ${change.after}`));
|
|
158
|
-
console.log(chalk.gray(` Reason: ${change.reason}`));
|
|
159
|
-
console.log();
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Apply or confirm
|
|
163
|
-
if (options.apply) {
|
|
164
|
-
await this.applyFix(file.path, file.content, result.fixed);
|
|
165
|
-
} else {
|
|
166
|
-
await this.showDiffAndConfirm(file.path, file.content, result.fixed);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
} catch (error) {
|
|
170
|
-
spinner.stop();
|
|
171
|
-
this.logger.error('Fix failed:', (error as Error).message);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private extractCode(response: string, language: string): string | null {
|
|
176
|
-
// Try to extract code block
|
|
177
|
-
const codeBlockRegex = new RegExp(`\`\`\`(?:${language})?\\n([\\s\\S]*?)\`\`\``, 'i');
|
|
178
|
-
const match = response.match(codeBlockRegex);
|
|
179
|
-
|
|
180
|
-
if (match) {
|
|
181
|
-
return match[1].trim();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// If no code block, check if response looks like code
|
|
185
|
-
const trimmed = response.trim();
|
|
186
|
-
if (!trimmed.startsWith('```') && !trimmed.includes('Here') && !trimmed.includes('I ')) {
|
|
187
|
-
return trimmed;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private async showDiffAndConfirm(
|
|
194
|
-
filePath: string,
|
|
195
|
-
original: string,
|
|
196
|
-
modified: string
|
|
197
|
-
): Promise<void> {
|
|
198
|
-
const diff = this.fileUtils.createDiff(original, modified);
|
|
199
|
-
|
|
200
|
-
if (diff.added.length === 0 && diff.removed.length === 0) {
|
|
201
|
-
this.logger.info('No changes detected');
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Show diff
|
|
206
|
-
this.logger.section('Changes');
|
|
207
|
-
|
|
208
|
-
diff.removed.forEach(line => {
|
|
209
|
-
console.log(chalk.red(line));
|
|
210
|
-
});
|
|
211
|
-
diff.added.forEach(line => {
|
|
212
|
-
console.log(chalk.green(line));
|
|
213
|
-
});
|
|
214
|
-
console.log();
|
|
215
|
-
|
|
216
|
-
// Confirm
|
|
217
|
-
const showDiffs = this.config.get('preferences').showDiffs;
|
|
218
|
-
const autoApply = this.config.get('preferences').autoApplyFixes;
|
|
219
|
-
|
|
220
|
-
if (autoApply) {
|
|
221
|
-
await this.applyFix(filePath, original, modified);
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const { action } = await inquirer.prompt([
|
|
226
|
-
{
|
|
227
|
-
type: 'list',
|
|
228
|
-
name: 'action',
|
|
229
|
-
message: 'What would you like to do?',
|
|
230
|
-
choices: [
|
|
231
|
-
{ name: 'Apply changes', value: 'apply' },
|
|
232
|
-
{ name: 'View full diff', value: 'view' },
|
|
233
|
-
{ name: 'Discard changes', value: 'discard' },
|
|
234
|
-
],
|
|
235
|
-
},
|
|
236
|
-
]);
|
|
237
|
-
|
|
238
|
-
switch (action) {
|
|
239
|
-
case 'apply':
|
|
240
|
-
await this.applyFix(filePath, original, modified);
|
|
241
|
-
break;
|
|
242
|
-
case 'view':
|
|
243
|
-
this.showFullDiff(original, modified);
|
|
244
|
-
const { confirm } = await inquirer.prompt([
|
|
245
|
-
{
|
|
246
|
-
type: 'confirm',
|
|
247
|
-
name: 'confirm',
|
|
248
|
-
message: 'Apply these changes?',
|
|
249
|
-
default: true,
|
|
250
|
-
},
|
|
251
|
-
]);
|
|
252
|
-
if (confirm) {
|
|
253
|
-
await this.applyFix(filePath, original, modified);
|
|
254
|
-
}
|
|
255
|
-
break;
|
|
256
|
-
case 'discard':
|
|
257
|
-
this.logger.info('Changes discarded');
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private showFullDiff(original: string, modified: string): void {
|
|
263
|
-
const originalLines = original.split('\n');
|
|
264
|
-
const modifiedLines = modified.split('\n');
|
|
265
|
-
|
|
266
|
-
console.log();
|
|
267
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
268
|
-
|
|
269
|
-
const maxLen = Math.max(originalLines.length, modifiedLines.length);
|
|
270
|
-
|
|
271
|
-
for (let i = 0; i < maxLen; i++) {
|
|
272
|
-
const orig = originalLines[i];
|
|
273
|
-
const mod = modifiedLines[i];
|
|
274
|
-
const lineNum = String(i + 1).padStart(4, ' ');
|
|
275
|
-
|
|
276
|
-
if (orig === mod) {
|
|
277
|
-
console.log(chalk.gray(`${lineNum} │ ${orig || ''}`));
|
|
278
|
-
} else {
|
|
279
|
-
if (orig !== undefined) {
|
|
280
|
-
console.log(chalk.red(`${lineNum} - ${orig}`));
|
|
281
|
-
}
|
|
282
|
-
if (mod !== undefined) {
|
|
283
|
-
console.log(chalk.green(`${lineNum} + ${mod}`));
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
289
|
-
console.log();
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
private async applyFix(
|
|
293
|
-
filePath: string,
|
|
294
|
-
original: string,
|
|
295
|
-
modified: string
|
|
296
|
-
): Promise<void> {
|
|
297
|
-
// Create backup
|
|
298
|
-
const backup = this.fileUtils.backupFile(filePath);
|
|
299
|
-
if (backup) {
|
|
300
|
-
this.logger.info(`Backup: ${chalk.gray(backup)}`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Apply changes
|
|
304
|
-
if (this.fileUtils.writeFile(filePath, modified)) {
|
|
305
|
-
this.logger.success(`Changes applied to ${filePath}`);
|
|
306
|
-
} else {
|
|
307
|
-
this.logger.error('Failed to write changes');
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
package/src/commands/explain.ts
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Explain Command - Explain code in files
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import ora from 'ora';
|
|
7
|
-
import { Marked } from 'marked';
|
|
8
|
-
import { markedTerminal } from 'marked-terminal';
|
|
9
|
-
import { Config } from '../utils/config.js';
|
|
10
|
-
import { Logger } from '../utils/logger.js';
|
|
11
|
-
import { APIClient } from '../utils/api.js';
|
|
12
|
-
import { FileUtils } from '../utils/files.js';
|
|
13
|
-
|
|
14
|
-
interface ExplainOptions {
|
|
15
|
-
lines?: string;
|
|
16
|
-
detail: 'brief' | 'normal' | 'detailed';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class ExplainCommand {
|
|
20
|
-
private config: Config;
|
|
21
|
-
private logger: Logger;
|
|
22
|
-
private api: APIClient;
|
|
23
|
-
private fileUtils: FileUtils;
|
|
24
|
-
private marked: Marked;
|
|
25
|
-
|
|
26
|
-
constructor(config: Config, logger: Logger) {
|
|
27
|
-
this.config = config;
|
|
28
|
-
this.logger = logger;
|
|
29
|
-
this.api = new APIClient(config, logger);
|
|
30
|
-
this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
|
|
31
|
-
|
|
32
|
-
this.marked = new Marked();
|
|
33
|
-
this.marked.use(markedTerminal() as any);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async run(filePath: string, options: ExplainOptions): Promise<void> {
|
|
37
|
-
// Check auth
|
|
38
|
-
if (!this.config.isAuthenticated()) {
|
|
39
|
-
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Read file
|
|
44
|
-
const file = this.fileUtils.readFile(filePath);
|
|
45
|
-
if (!file) {
|
|
46
|
-
this.logger.error(`File not found: ${filePath}`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Get code to explain
|
|
51
|
-
let codeToExplain = file.content;
|
|
52
|
-
let lineInfo = '';
|
|
53
|
-
|
|
54
|
-
if (options.lines) {
|
|
55
|
-
const [start, end] = options.lines.split('-').map(Number);
|
|
56
|
-
const lines = this.fileUtils.readLines(filePath, start, end || start);
|
|
57
|
-
if (lines) {
|
|
58
|
-
codeToExplain = lines;
|
|
59
|
-
lineInfo = ` (lines ${start}-${end || start})`;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
this.logger.section(`Explaining: ${file.relativePath}${lineInfo}`);
|
|
64
|
-
console.log(chalk.gray(`Language: ${file.language} | Detail: ${options.detail}`));
|
|
65
|
-
console.log();
|
|
66
|
-
|
|
67
|
-
// Show the code being explained
|
|
68
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
69
|
-
codeToExplain.split('\n').forEach((line, i) => {
|
|
70
|
-
const lineNum = chalk.gray(String(i + 1).padStart(4, ' ') + ' │ ');
|
|
71
|
-
console.log(lineNum + line);
|
|
72
|
-
});
|
|
73
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
74
|
-
console.log();
|
|
75
|
-
|
|
76
|
-
const spinner = ora({
|
|
77
|
-
text: 'Analyzing code...',
|
|
78
|
-
spinner: 'dots',
|
|
79
|
-
}).start();
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const explanation = await this.api.explainCode(codeToExplain, file.language);
|
|
83
|
-
|
|
84
|
-
spinner.stop();
|
|
85
|
-
|
|
86
|
-
// Format based on detail level
|
|
87
|
-
const formattedExplanation = this.formatExplanation(explanation, options.detail);
|
|
88
|
-
|
|
89
|
-
this.logger.section('Explanation');
|
|
90
|
-
console.log(this.marked.parse(formattedExplanation));
|
|
91
|
-
|
|
92
|
-
} catch (error) {
|
|
93
|
-
spinner.stop();
|
|
94
|
-
this.logger.error('Explanation failed:', (error as Error).message);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private formatExplanation(explanation: string, detail: string): string {
|
|
99
|
-
switch (detail) {
|
|
100
|
-
case 'brief':
|
|
101
|
-
// Extract just the summary
|
|
102
|
-
const lines = explanation.split('\n');
|
|
103
|
-
const summaryLines = lines.slice(0, Math.min(lines.length, 5));
|
|
104
|
-
return summaryLines.join('\n');
|
|
105
|
-
|
|
106
|
-
case 'detailed':
|
|
107
|
-
// Add extra formatting
|
|
108
|
-
return explanation + '\n\n---\n*Detailed analysis by Vigthoria*';
|
|
109
|
-
|
|
110
|
-
case 'normal':
|
|
111
|
-
default:
|
|
112
|
-
return explanation;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
package/src/commands/generate.ts
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate Command - Generate code from description
|
|
3
|
-
*
|
|
4
|
-
* Now with Senior Developer Mode (--pro) for impressive, production-ready output
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import chalk from 'chalk';
|
|
8
|
-
import ora from 'ora';
|
|
9
|
-
import inquirer from 'inquirer';
|
|
10
|
-
import { Config } from '../utils/config.js';
|
|
11
|
-
import { Logger } from '../utils/logger.js';
|
|
12
|
-
import { APIClient } from '../utils/api.js';
|
|
13
|
-
import { FileUtils } from '../utils/files.js';
|
|
14
|
-
|
|
15
|
-
interface GenerateOptions {
|
|
16
|
-
language: string;
|
|
17
|
-
output?: string;
|
|
18
|
-
model: string;
|
|
19
|
-
pro?: boolean; // Senior Developer Mode
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class GenerateCommand {
|
|
23
|
-
private config: Config;
|
|
24
|
-
private logger: Logger;
|
|
25
|
-
private api: APIClient;
|
|
26
|
-
private fileUtils: FileUtils;
|
|
27
|
-
|
|
28
|
-
constructor(config: Config, logger: Logger) {
|
|
29
|
-
this.config = config;
|
|
30
|
-
this.logger = logger;
|
|
31
|
-
this.api = new APIClient(config, logger);
|
|
32
|
-
this.fileUtils = new FileUtils(process.cwd(), config.get('project').ignorePatterns);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async run(description: string, options: GenerateOptions): Promise<void> {
|
|
36
|
-
// Check auth
|
|
37
|
-
if (!this.config.isAuthenticated()) {
|
|
38
|
-
this.logger.error('Not authenticated. Run: vigthoria login');
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Determine mode
|
|
43
|
-
const proMode = options.pro === true;
|
|
44
|
-
|
|
45
|
-
this.logger.section(proMode ? '🚀 Senior Developer Mode' : 'Code Generation');
|
|
46
|
-
console.log(chalk.gray(`Language: ${options.language}`));
|
|
47
|
-
console.log(chalk.gray(`Description: ${description}`));
|
|
48
|
-
if (proMode) {
|
|
49
|
-
console.log(chalk.cyan('Pro Mode: Planning → Generating → Quality Check'));
|
|
50
|
-
}
|
|
51
|
-
console.log();
|
|
52
|
-
|
|
53
|
-
const spinner = ora({
|
|
54
|
-
text: proMode ? 'Phase 1: Planning project structure...' : 'Generating code...',
|
|
55
|
-
spinner: 'dots',
|
|
56
|
-
}).start();
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
let code: string;
|
|
60
|
-
let quality: any = null;
|
|
61
|
-
|
|
62
|
-
if (proMode) {
|
|
63
|
-
// Senior Developer Mode - uses planning and quality checks
|
|
64
|
-
spinner.text = 'Phase 1: Planning project structure...';
|
|
65
|
-
const result = await this.api.generateProject(description, options.language, options.model);
|
|
66
|
-
|
|
67
|
-
spinner.text = 'Phase 2: Generating impressive code...';
|
|
68
|
-
code = result.code;
|
|
69
|
-
quality = result.quality;
|
|
70
|
-
|
|
71
|
-
spinner.stop();
|
|
72
|
-
|
|
73
|
-
// Show quality report
|
|
74
|
-
if (quality) {
|
|
75
|
-
console.log();
|
|
76
|
-
this.logger.section('Quality Report');
|
|
77
|
-
console.log(chalk.gray(`Lines of code: ${quality.lineCount}`));
|
|
78
|
-
console.log(chalk.gray(`Quality score: ${quality.score}/5`));
|
|
79
|
-
console.log();
|
|
80
|
-
console.log(chalk.gray('Visual Checks:'));
|
|
81
|
-
console.log(` ${quality.checks?.hasAnimations ? chalk.green('✓') : chalk.red('✗')} CSS Animations (@keyframes)`);
|
|
82
|
-
console.log(` ${quality.checks?.hasNeonEffects ? chalk.green('✓') : chalk.red('✗')} Neon/Glow Effects`);
|
|
83
|
-
console.log(` ${quality.checks?.hasResponsive ? chalk.green('✓') : chalk.red('✗')} Responsive Design (@media)`);
|
|
84
|
-
console.log(` ${quality.checks?.hasFontAwesome ? chalk.green('✓') : chalk.red('✗')} Font Awesome Icons`);
|
|
85
|
-
console.log(` ${quality.checks?.hasGoogleFonts ? chalk.green('✓') : chalk.red('✗')} Google Fonts`);
|
|
86
|
-
console.log();
|
|
87
|
-
console.log(chalk.gray('Structure Checks:'));
|
|
88
|
-
console.log(` ${quality.checks?.hasEmbeddedCSS ? chalk.green('✓') : chalk.red('✗')} Embedded CSS (<style> tag)`);
|
|
89
|
-
console.log(` ${quality.checks?.hasEmbeddedJS ? chalk.green('✓') : chalk.red('✗')} Embedded JavaScript (<script> tag)`);
|
|
90
|
-
console.log(` ${quality.checks?.singleFile ? chalk.green('✓') : chalk.red('✗')} Single-file (no external CSS/JS)`);
|
|
91
|
-
console.log();
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
// Standard mode
|
|
95
|
-
code = await this.api.generateCode(description, options.language, options.model);
|
|
96
|
-
spinner.stop();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Display generated code
|
|
100
|
-
this.logger.section('Generated Code');
|
|
101
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
102
|
-
console.log(this.highlightCode(code, options.language));
|
|
103
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
104
|
-
console.log();
|
|
105
|
-
|
|
106
|
-
// Save options
|
|
107
|
-
if (options.output) {
|
|
108
|
-
await this.saveToFile(options.output, code);
|
|
109
|
-
} else {
|
|
110
|
-
await this.promptForAction(code, options.language);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
} catch (error) {
|
|
114
|
-
spinner.stop();
|
|
115
|
-
this.logger.error('Generation failed:', (error as Error).message);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private highlightCode(code: string, language: string): string {
|
|
120
|
-
// Basic syntax highlighting
|
|
121
|
-
// In production, use a proper library like highlight.js
|
|
122
|
-
const lines = code.split('\n');
|
|
123
|
-
|
|
124
|
-
return lines.map((line, i) => {
|
|
125
|
-
const lineNum = chalk.gray(String(i + 1).padStart(4, ' ') + ' │ ');
|
|
126
|
-
return lineNum + this.highlightLine(line, language);
|
|
127
|
-
}).join('\n');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private highlightLine(line: string, language: string): string {
|
|
131
|
-
// Simple keyword highlighting
|
|
132
|
-
const keywords: Record<string, string[]> = {
|
|
133
|
-
typescript: ['const', 'let', 'var', 'function', 'class', 'interface', 'type', 'export', 'import', 'from', 'async', 'await', 'return', 'if', 'else', 'for', 'while', 'try', 'catch', 'throw', 'new'],
|
|
134
|
-
javascript: ['const', 'let', 'var', 'function', 'class', 'export', 'import', 'from', 'async', 'await', 'return', 'if', 'else', 'for', 'while', 'try', 'catch', 'throw', 'new'],
|
|
135
|
-
python: ['def', 'class', 'import', 'from', 'return', 'if', 'elif', 'else', 'for', 'while', 'try', 'except', 'raise', 'with', 'as', 'async', 'await', 'yield', 'lambda'],
|
|
136
|
-
rust: ['fn', 'let', 'mut', 'const', 'struct', 'enum', 'impl', 'trait', 'pub', 'use', 'mod', 'return', 'if', 'else', 'match', 'for', 'while', 'loop', 'async', 'await'],
|
|
137
|
-
go: ['func', 'var', 'const', 'type', 'struct', 'interface', 'package', 'import', 'return', 'if', 'else', 'for', 'range', 'switch', 'case', 'go', 'defer', 'chan'],
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const langKeywords = keywords[language] || keywords['typescript'];
|
|
141
|
-
let highlighted = line;
|
|
142
|
-
|
|
143
|
-
// Highlight keywords
|
|
144
|
-
langKeywords.forEach(kw => {
|
|
145
|
-
const regex = new RegExp(`\\b${kw}\\b`, 'g');
|
|
146
|
-
highlighted = highlighted.replace(regex, chalk.magenta(kw));
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// Highlight strings
|
|
150
|
-
highlighted = highlighted.replace(/(["'`])(?:(?!\1)[^\\]|\\.)*\1/g, (match) => chalk.green(match));
|
|
151
|
-
|
|
152
|
-
// Highlight comments
|
|
153
|
-
highlighted = highlighted.replace(/(\/\/.*$|#.*$)/g, (match) => chalk.gray(match));
|
|
154
|
-
|
|
155
|
-
// Highlight numbers
|
|
156
|
-
highlighted = highlighted.replace(/\b(\d+)\b/g, (match) => chalk.yellow(match));
|
|
157
|
-
|
|
158
|
-
return highlighted;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private async saveToFile(filePath: string, code: string): Promise<void> {
|
|
162
|
-
if (this.fileUtils.writeFile(filePath, code)) {
|
|
163
|
-
this.logger.success(`Code saved to ${filePath}`);
|
|
164
|
-
} else {
|
|
165
|
-
this.logger.error('Failed to save file');
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private async promptForAction(code: string, language: string): Promise<void> {
|
|
170
|
-
const { action } = await inquirer.prompt([
|
|
171
|
-
{
|
|
172
|
-
type: 'list',
|
|
173
|
-
name: 'action',
|
|
174
|
-
message: 'What would you like to do with this code?',
|
|
175
|
-
choices: [
|
|
176
|
-
{ name: 'Copy to clipboard', value: 'copy' },
|
|
177
|
-
{ name: 'Save to file', value: 'save' },
|
|
178
|
-
{ name: 'Regenerate', value: 'regenerate' },
|
|
179
|
-
{ name: 'Done', value: 'done' },
|
|
180
|
-
],
|
|
181
|
-
},
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
switch (action) {
|
|
185
|
-
case 'copy':
|
|
186
|
-
// Note: Clipboard access requires additional setup
|
|
187
|
-
this.logger.info('Code copied to clipboard');
|
|
188
|
-
console.log(chalk.gray('(Note: Clipboard access may require additional permissions)'));
|
|
189
|
-
break;
|
|
190
|
-
case 'save':
|
|
191
|
-
const { filename } = await inquirer.prompt([
|
|
192
|
-
{
|
|
193
|
-
type: 'input',
|
|
194
|
-
name: 'filename',
|
|
195
|
-
message: 'Enter filename:',
|
|
196
|
-
default: this.suggestFilename(language),
|
|
197
|
-
},
|
|
198
|
-
]);
|
|
199
|
-
await this.saveToFile(filename, code);
|
|
200
|
-
break;
|
|
201
|
-
case 'regenerate':
|
|
202
|
-
this.logger.info('Use the generate command again with different parameters');
|
|
203
|
-
break;
|
|
204
|
-
case 'done':
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
private suggestFilename(language: string): string {
|
|
210
|
-
const extensions: Record<string, string> = {
|
|
211
|
-
typescript: 'generated.ts',
|
|
212
|
-
javascript: 'generated.js',
|
|
213
|
-
python: 'generated.py',
|
|
214
|
-
rust: 'generated.rs',
|
|
215
|
-
go: 'generated.go',
|
|
216
|
-
java: 'Generated.java',
|
|
217
|
-
csharp: 'Generated.cs',
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
return extensions[language] || 'generated.txt';
|
|
221
|
-
}
|
|
222
|
-
}
|