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/utils/config.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration Manager for Vigthoria CLI
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import Conf from 'conf';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import * as os from 'os';
|
|
8
|
-
|
|
9
|
-
export interface VigthoriaCLIConfig {
|
|
10
|
-
apiUrl: string;
|
|
11
|
-
modelsApiUrl: string; // Direct Vigthoria Models API
|
|
12
|
-
wsUrl: string;
|
|
13
|
-
authToken: string | null;
|
|
14
|
-
refreshToken: string | null;
|
|
15
|
-
userId: string | null;
|
|
16
|
-
email: string | null;
|
|
17
|
-
subscription: {
|
|
18
|
-
plan: string | null;
|
|
19
|
-
status: string | null;
|
|
20
|
-
expiresAt: string | null;
|
|
21
|
-
};
|
|
22
|
-
preferences: {
|
|
23
|
-
defaultModel: string;
|
|
24
|
-
theme: 'dark' | 'light';
|
|
25
|
-
autoApplyFixes: boolean;
|
|
26
|
-
showDiffs: boolean;
|
|
27
|
-
contextLines: number;
|
|
28
|
-
maxTokens: number;
|
|
29
|
-
};
|
|
30
|
-
project: {
|
|
31
|
-
rootPath: string | null;
|
|
32
|
-
ignorePatterns: string[];
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const defaultConfig: VigthoriaCLIConfig = {
|
|
37
|
-
apiUrl: 'https://coder.vigthoria.io',
|
|
38
|
-
modelsApiUrl: 'https://api.vigthoria.io', // Direct AI Models API - no proxying through Coder
|
|
39
|
-
wsUrl: 'wss://coder.vigthoria.io/ws',
|
|
40
|
-
authToken: null,
|
|
41
|
-
refreshToken: null,
|
|
42
|
-
userId: null,
|
|
43
|
-
email: null,
|
|
44
|
-
subscription: {
|
|
45
|
-
plan: null,
|
|
46
|
-
status: null,
|
|
47
|
-
expiresAt: null,
|
|
48
|
-
},
|
|
49
|
-
preferences: {
|
|
50
|
-
defaultModel: 'vigthoria-code',
|
|
51
|
-
theme: 'dark',
|
|
52
|
-
autoApplyFixes: false,
|
|
53
|
-
showDiffs: true,
|
|
54
|
-
contextLines: 3,
|
|
55
|
-
maxTokens: 4096,
|
|
56
|
-
},
|
|
57
|
-
project: {
|
|
58
|
-
rootPath: null,
|
|
59
|
-
ignorePatterns: [
|
|
60
|
-
'node_modules',
|
|
61
|
-
'.git',
|
|
62
|
-
'dist',
|
|
63
|
-
'build',
|
|
64
|
-
'__pycache__',
|
|
65
|
-
'.venv',
|
|
66
|
-
'venv',
|
|
67
|
-
'.env',
|
|
68
|
-
'*.log',
|
|
69
|
-
],
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export class Config {
|
|
74
|
-
private store: Conf<VigthoriaCLIConfig>;
|
|
75
|
-
|
|
76
|
-
constructor() {
|
|
77
|
-
this.store = new Conf<VigthoriaCLIConfig>({
|
|
78
|
-
projectName: 'vigthoria-cli',
|
|
79
|
-
defaults: defaultConfig,
|
|
80
|
-
schema: {
|
|
81
|
-
apiUrl: { type: 'string' },
|
|
82
|
-
modelsApiUrl: { type: 'string' },
|
|
83
|
-
wsUrl: { type: 'string' },
|
|
84
|
-
authToken: { type: ['string', 'null'] },
|
|
85
|
-
refreshToken: { type: ['string', 'null'] },
|
|
86
|
-
userId: { type: ['string', 'null'] },
|
|
87
|
-
email: { type: ['string', 'null'] },
|
|
88
|
-
subscription: {
|
|
89
|
-
type: 'object',
|
|
90
|
-
properties: {
|
|
91
|
-
plan: { type: ['string', 'null'] },
|
|
92
|
-
status: { type: ['string', 'null'] },
|
|
93
|
-
expiresAt: { type: ['string', 'null'] },
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
preferences: {
|
|
97
|
-
type: 'object',
|
|
98
|
-
properties: {
|
|
99
|
-
defaultModel: { type: 'string' },
|
|
100
|
-
theme: { type: 'string', enum: ['dark', 'light'] },
|
|
101
|
-
autoApplyFixes: { type: 'boolean' },
|
|
102
|
-
showDiffs: { type: 'boolean' },
|
|
103
|
-
contextLines: { type: 'number' },
|
|
104
|
-
maxTokens: { type: 'number' },
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
project: {
|
|
108
|
-
type: 'object',
|
|
109
|
-
properties: {
|
|
110
|
-
rootPath: { type: ['string', 'null'] },
|
|
111
|
-
ignorePatterns: { type: 'array', items: { type: 'string' } },
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
get<K extends keyof VigthoriaCLIConfig>(key: K): VigthoriaCLIConfig[K] {
|
|
119
|
-
return this.store.get(key);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
set<K extends keyof VigthoriaCLIConfig>(key: K, value: VigthoriaCLIConfig[K]): void {
|
|
123
|
-
this.store.set(key, value);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
getAll(): VigthoriaCLIConfig {
|
|
127
|
-
return this.store.store;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
reset(): void {
|
|
131
|
-
this.store.clear();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
isAuthenticated(): boolean {
|
|
135
|
-
return this.store.get('authToken') !== null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
hasValidSubscription(): boolean {
|
|
139
|
-
const sub = this.store.get('subscription');
|
|
140
|
-
if (!sub.status || sub.status !== 'active') return false;
|
|
141
|
-
if (sub.expiresAt) {
|
|
142
|
-
const expires = new Date(sub.expiresAt);
|
|
143
|
-
return expires > new Date();
|
|
144
|
-
}
|
|
145
|
-
return true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
getConfigPath(): string {
|
|
149
|
-
return this.store.path;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Auth helpers
|
|
153
|
-
setAuth(data: {
|
|
154
|
-
token: string;
|
|
155
|
-
refreshToken?: string;
|
|
156
|
-
userId: string;
|
|
157
|
-
email: string;
|
|
158
|
-
}): void {
|
|
159
|
-
this.store.set('authToken', data.token);
|
|
160
|
-
if (data.refreshToken) {
|
|
161
|
-
this.store.set('refreshToken', data.refreshToken);
|
|
162
|
-
}
|
|
163
|
-
this.store.set('userId', data.userId);
|
|
164
|
-
this.store.set('email', data.email);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
clearAuth(): void {
|
|
168
|
-
this.store.set('authToken', null);
|
|
169
|
-
this.store.set('refreshToken', null);
|
|
170
|
-
this.store.set('userId', null);
|
|
171
|
-
this.store.set('email', null);
|
|
172
|
-
this.store.set('subscription', {
|
|
173
|
-
plan: null,
|
|
174
|
-
status: null,
|
|
175
|
-
expiresAt: null,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
setSubscription(data: {
|
|
180
|
-
plan: string;
|
|
181
|
-
status: string;
|
|
182
|
-
expiresAt?: string;
|
|
183
|
-
}): void {
|
|
184
|
-
this.store.set('subscription', {
|
|
185
|
-
plan: data.plan,
|
|
186
|
-
status: data.status,
|
|
187
|
-
expiresAt: data.expiresAt || null,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Model selection - Vigthoria Models (internal: qwen3-coder, deepseek via OpenRouter)
|
|
192
|
-
getAvailableModels(): { id: string; name: string; description: string; tier: string }[] {
|
|
193
|
-
const sub = this.store.get('subscription');
|
|
194
|
-
const plan = (sub.plan || '').toLowerCase();
|
|
195
|
-
|
|
196
|
-
// ═══════════════════════════════════════════════════════════════
|
|
197
|
-
// VIGTHORIA LOCAL - Self-hosted models (fast, no API costs)
|
|
198
|
-
// ═══════════════════════════════════════════════════════════════
|
|
199
|
-
const models: { id: string; name: string; description: string; tier: string }[] = [
|
|
200
|
-
{ id: 'code', name: 'Vigthoria v3 Code 30B', description: '🏠 30B coding powerhouse - default', tier: 'local' },
|
|
201
|
-
{ id: 'code-30b', name: 'Vigthoria v3 Code 30B', description: '🏠 Same as code', tier: 'local' },
|
|
202
|
-
{ id: 'code-8b', name: 'Vigthoria v2 Code 8B', description: '🏠 Lighter 8B model', tier: 'local' },
|
|
203
|
-
{ id: 'balanced', name: 'Vigthoria Balanced 4B', description: '🏠 General purpose', tier: 'local' },
|
|
204
|
-
{ id: 'fast', name: 'Vigthoria Fast 1.7B', description: '🏠 Quick responses', tier: 'local' },
|
|
205
|
-
{ id: 'creative', name: 'Vigthoria Creative 9B', description: '🏠 Creative writing', tier: 'local' },
|
|
206
|
-
];
|
|
207
|
-
|
|
208
|
-
// ═══════════════════════════════════════════════════════════════
|
|
209
|
-
// VIGTHORIA CLOUD - Premium cloud models (Pro subscription)
|
|
210
|
-
// For complex multi-file tasks, large refactoring, architecture
|
|
211
|
-
// ═══════════════════════════════════════════════════════════════
|
|
212
|
-
const proPlansList = ['developer', 'pro', 'ultra', 'enterprise', 'master_admin', 'admin'];
|
|
213
|
-
if (proPlansList.includes(plan)) {
|
|
214
|
-
models.push(
|
|
215
|
-
{ id: 'cloud', name: 'Vigthoria Cloud 671B', description: '☁️ 671B cloud model - complex tasks', tier: 'cloud' },
|
|
216
|
-
{ id: 'cloud-reason', name: 'Vigthoria Cloud Reason', description: '☁️ Reasoning expert model', tier: 'cloud' },
|
|
217
|
-
{ id: 'ultra', name: 'Vigthoria Ultra', description: '☁️ Maximum capability', tier: 'cloud' },
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return models;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Check if a model is a "Cloud" tier model
|
|
225
|
-
isCloudModel(modelId: string): boolean {
|
|
226
|
-
const cloudModels = ['cloud', 'cloud-reason', 'ultra', 'agent'];
|
|
227
|
-
return cloudModels.includes(modelId) || modelId.includes('cloud');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Check if task is complex enough to suggest Cloud upgrade
|
|
231
|
-
isComplexTask(prompt: string): boolean {
|
|
232
|
-
const complexIndicators = [
|
|
233
|
-
/refactor/i, /architect/i, /redesign/i, /migrate/i,
|
|
234
|
-
/multi.?file/i, /multiple files/i, /entire.*project/i,
|
|
235
|
-
/all files/i, /whole.*codebase/i, /implement.*feature/i,
|
|
236
|
-
/create.*system/i, /build.*from.*scratch/i,
|
|
237
|
-
/analyze.*project/i, /review.*codebase/i,
|
|
238
|
-
];
|
|
239
|
-
return complexIndicators.some(pattern => pattern.test(prompt));
|
|
240
|
-
}
|
|
241
|
-
}
|
package/src/utils/files.ts
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File utilities for Vigthoria CLI
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import * as path from 'path';
|
|
7
|
-
import { glob } from 'glob';
|
|
8
|
-
|
|
9
|
-
export interface FileInfo {
|
|
10
|
-
path: string;
|
|
11
|
-
relativePath: string;
|
|
12
|
-
content: string;
|
|
13
|
-
language: string;
|
|
14
|
-
lines: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class FileUtils {
|
|
18
|
-
private projectRoot: string;
|
|
19
|
-
private ignorePatterns: string[];
|
|
20
|
-
|
|
21
|
-
constructor(projectRoot: string, ignorePatterns: string[] = []) {
|
|
22
|
-
// Resolve symlinks and normalize path for consistent behavior
|
|
23
|
-
try {
|
|
24
|
-
this.projectRoot = fs.realpathSync(projectRoot);
|
|
25
|
-
} catch {
|
|
26
|
-
// If realpath fails (e.g., path doesn't exist), use the original
|
|
27
|
-
this.projectRoot = path.resolve(projectRoot);
|
|
28
|
-
}
|
|
29
|
-
this.ignorePatterns = ignorePatterns;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Read file with metadata
|
|
33
|
-
readFile(filePath: string): FileInfo | null {
|
|
34
|
-
try {
|
|
35
|
-
let absolutePath = path.isAbsolute(filePath)
|
|
36
|
-
? filePath
|
|
37
|
-
: path.join(this.projectRoot, filePath);
|
|
38
|
-
|
|
39
|
-
// Resolve symlinks for consistent path handling
|
|
40
|
-
try {
|
|
41
|
-
absolutePath = fs.realpathSync(absolutePath);
|
|
42
|
-
} catch {
|
|
43
|
-
// Keep original path if realpath fails
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Check if it's a regular file (not a directory or special file)
|
|
47
|
-
const stats = fs.statSync(absolutePath);
|
|
48
|
-
if (!stats.isFile()) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const content = fs.readFileSync(absolutePath, 'utf-8');
|
|
53
|
-
const relativePath = path.relative(this.projectRoot, absolutePath);
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
path: absolutePath,
|
|
57
|
-
relativePath,
|
|
58
|
-
content,
|
|
59
|
-
language: this.detectLanguage(absolutePath),
|
|
60
|
-
lines: content.split('\n').length,
|
|
61
|
-
};
|
|
62
|
-
} catch (error) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Read specific lines
|
|
68
|
-
readLines(filePath: string, start: number, end: number): string | null {
|
|
69
|
-
const file = this.readFile(filePath);
|
|
70
|
-
if (!file) return null;
|
|
71
|
-
|
|
72
|
-
const lines = file.content.split('\n');
|
|
73
|
-
return lines.slice(start - 1, end).join('\n');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Write file
|
|
77
|
-
writeFile(filePath: string, content: string): boolean {
|
|
78
|
-
try {
|
|
79
|
-
const absolutePath = path.isAbsolute(filePath)
|
|
80
|
-
? filePath
|
|
81
|
-
: path.join(this.projectRoot, filePath);
|
|
82
|
-
|
|
83
|
-
// Create directory if needed
|
|
84
|
-
const dir = path.dirname(absolutePath);
|
|
85
|
-
if (!fs.existsSync(dir)) {
|
|
86
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
fs.writeFileSync(absolutePath, content, 'utf-8');
|
|
90
|
-
return true;
|
|
91
|
-
} catch {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Backup file
|
|
97
|
-
backupFile(filePath: string): string | null {
|
|
98
|
-
const file = this.readFile(filePath);
|
|
99
|
-
if (!file) return null;
|
|
100
|
-
|
|
101
|
-
const backupPath = `${file.path}.bak.${Date.now()}`;
|
|
102
|
-
if (this.writeFile(backupPath, file.content)) {
|
|
103
|
-
return backupPath;
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// List project files
|
|
109
|
-
async listFiles(pattern: string = '**/*'): Promise<string[]> {
|
|
110
|
-
try {
|
|
111
|
-
// Check if project root exists
|
|
112
|
-
if (!fs.existsSync(this.projectRoot)) {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const files = await glob(pattern, {
|
|
117
|
-
cwd: this.projectRoot,
|
|
118
|
-
ignore: this.ignorePatterns,
|
|
119
|
-
nodir: true,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
return files;
|
|
123
|
-
} catch (error) {
|
|
124
|
-
// Return empty array on error (e.g., permission issues on Windows)
|
|
125
|
-
return [];
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Detect language from file extension
|
|
130
|
-
detectLanguage(filePath: string): string {
|
|
131
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
132
|
-
const languageMap: Record<string, string> = {
|
|
133
|
-
'.ts': 'typescript',
|
|
134
|
-
'.tsx': 'typescript',
|
|
135
|
-
'.js': 'javascript',
|
|
136
|
-
'.jsx': 'javascript',
|
|
137
|
-
'.py': 'python',
|
|
138
|
-
'.rs': 'rust',
|
|
139
|
-
'.go': 'go',
|
|
140
|
-
'.java': 'java',
|
|
141
|
-
'.c': 'c',
|
|
142
|
-
'.cpp': 'cpp',
|
|
143
|
-
'.h': 'c',
|
|
144
|
-
'.hpp': 'cpp',
|
|
145
|
-
'.cs': 'csharp',
|
|
146
|
-
'.rb': 'ruby',
|
|
147
|
-
'.php': 'php',
|
|
148
|
-
'.swift': 'swift',
|
|
149
|
-
'.kt': 'kotlin',
|
|
150
|
-
'.scala': 'scala',
|
|
151
|
-
'.sql': 'sql',
|
|
152
|
-
'.html': 'html',
|
|
153
|
-
'.css': 'css',
|
|
154
|
-
'.scss': 'scss',
|
|
155
|
-
'.less': 'less',
|
|
156
|
-
'.json': 'json',
|
|
157
|
-
'.yaml': 'yaml',
|
|
158
|
-
'.yml': 'yaml',
|
|
159
|
-
'.xml': 'xml',
|
|
160
|
-
'.md': 'markdown',
|
|
161
|
-
'.sh': 'bash',
|
|
162
|
-
'.bash': 'bash',
|
|
163
|
-
'.zsh': 'zsh',
|
|
164
|
-
'.dockerfile': 'dockerfile',
|
|
165
|
-
'.vue': 'vue',
|
|
166
|
-
'.svelte': 'svelte',
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
return languageMap[ext] || 'text';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Get project context
|
|
173
|
-
async getProjectContext(maxFiles: number = 20): Promise<{
|
|
174
|
-
type: string;
|
|
175
|
-
files: string[];
|
|
176
|
-
dependencies: Record<string, string>;
|
|
177
|
-
}> {
|
|
178
|
-
const context = {
|
|
179
|
-
type: 'unknown',
|
|
180
|
-
files: [] as string[],
|
|
181
|
-
dependencies: {} as Record<string, string>,
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// Detect project type
|
|
185
|
-
if (fs.existsSync(path.join(this.projectRoot, 'package.json'))) {
|
|
186
|
-
context.type = 'node';
|
|
187
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
188
|
-
path.join(this.projectRoot, 'package.json'),
|
|
189
|
-
'utf-8'
|
|
190
|
-
));
|
|
191
|
-
context.dependencies = {
|
|
192
|
-
...pkg.dependencies,
|
|
193
|
-
...pkg.devDependencies,
|
|
194
|
-
};
|
|
195
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'requirements.txt'))) {
|
|
196
|
-
context.type = 'python';
|
|
197
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'Cargo.toml'))) {
|
|
198
|
-
context.type = 'rust';
|
|
199
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'go.mod'))) {
|
|
200
|
-
context.type = 'go';
|
|
201
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'pom.xml'))) {
|
|
202
|
-
context.type = 'java-maven';
|
|
203
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'build.gradle'))) {
|
|
204
|
-
context.type = 'java-gradle';
|
|
205
|
-
} else if (
|
|
206
|
-
fs.existsSync(path.join(this.projectRoot, 'core', 'core.services.yml')) ||
|
|
207
|
-
fs.existsSync(path.join(this.projectRoot, 'web', 'core', 'core.services.yml')) ||
|
|
208
|
-
fs.existsSync(path.join(this.projectRoot, 'sites', 'default', 'settings.php'))
|
|
209
|
-
) {
|
|
210
|
-
// Drupal 8/9/10/11 detection
|
|
211
|
-
context.type = 'drupal';
|
|
212
|
-
// Try to read composer.json for Drupal version info
|
|
213
|
-
const composerPath = fs.existsSync(path.join(this.projectRoot, 'composer.json'))
|
|
214
|
-
? path.join(this.projectRoot, 'composer.json')
|
|
215
|
-
: fs.existsSync(path.join(this.projectRoot, 'web', 'composer.json'))
|
|
216
|
-
? path.join(this.projectRoot, 'web', 'composer.json')
|
|
217
|
-
: null;
|
|
218
|
-
if (composerPath) {
|
|
219
|
-
try {
|
|
220
|
-
const composer = JSON.parse(fs.readFileSync(composerPath, 'utf-8'));
|
|
221
|
-
context.dependencies = composer.require || {};
|
|
222
|
-
} catch { /* ignore parse errors */ }
|
|
223
|
-
}
|
|
224
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'wp-config.php'))) {
|
|
225
|
-
context.type = 'wordpress';
|
|
226
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'artisan'))) {
|
|
227
|
-
context.type = 'laravel';
|
|
228
|
-
} else if (fs.existsSync(path.join(this.projectRoot, 'composer.json'))) {
|
|
229
|
-
context.type = 'php-composer';
|
|
230
|
-
try {
|
|
231
|
-
const composer = JSON.parse(fs.readFileSync(
|
|
232
|
-
path.join(this.projectRoot, 'composer.json'),
|
|
233
|
-
'utf-8'
|
|
234
|
-
));
|
|
235
|
-
context.dependencies = composer.require || {};
|
|
236
|
-
} catch { /* ignore parse errors */ }
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Get relevant files
|
|
240
|
-
const allFiles = await this.listFiles();
|
|
241
|
-
context.files = allFiles.slice(0, maxFiles);
|
|
242
|
-
|
|
243
|
-
return context;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Create diff
|
|
247
|
-
createDiff(original: string, modified: string): { added: string[]; removed: string[] } {
|
|
248
|
-
const originalLines = original.split('\n');
|
|
249
|
-
const modifiedLines = modified.split('\n');
|
|
250
|
-
|
|
251
|
-
const added: string[] = [];
|
|
252
|
-
const removed: string[] = [];
|
|
253
|
-
|
|
254
|
-
// Simple diff - for display purposes
|
|
255
|
-
const maxLen = Math.max(originalLines.length, modifiedLines.length);
|
|
256
|
-
|
|
257
|
-
for (let i = 0; i < maxLen; i++) {
|
|
258
|
-
const origLine = originalLines[i];
|
|
259
|
-
const modLine = modifiedLines[i];
|
|
260
|
-
|
|
261
|
-
if (origLine !== modLine) {
|
|
262
|
-
if (origLine !== undefined) {
|
|
263
|
-
removed.push(`${i + 1}: ${origLine}`);
|
|
264
|
-
}
|
|
265
|
-
if (modLine !== undefined) {
|
|
266
|
-
added.push(`${i + 1}: ${modLine}`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return { added, removed };
|
|
272
|
-
}
|
|
273
|
-
}
|
package/src/utils/logger.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger utility for Vigthoria CLI
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
|
|
7
|
-
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success';
|
|
8
|
-
|
|
9
|
-
export class Logger {
|
|
10
|
-
private verbose: boolean = false;
|
|
11
|
-
|
|
12
|
-
setVerbose(verbose: boolean): void {
|
|
13
|
-
this.verbose = verbose;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
debug(...args: unknown[]): void {
|
|
17
|
-
if (this.verbose) {
|
|
18
|
-
console.log(chalk.gray('[DEBUG]'), ...args);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
info(...args: unknown[]): void {
|
|
23
|
-
console.log(chalk.blue('ℹ'), ...args);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
warn(...args: unknown[]): void {
|
|
27
|
-
console.log(chalk.yellow('⚠'), ...args);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
error(...args: unknown[]): void {
|
|
31
|
-
console.error(chalk.red('✗'), ...args);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
success(...args: unknown[]): void {
|
|
35
|
-
console.log(chalk.green('✓'), ...args);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// AI response formatting
|
|
39
|
-
ai(message: string): void {
|
|
40
|
-
console.log(chalk.cyan('🤖'), message);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// User input formatting
|
|
44
|
-
user(message: string): void {
|
|
45
|
-
console.log(chalk.white('👤'), message);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Code block
|
|
49
|
-
code(code: string, language?: string): void {
|
|
50
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
51
|
-
console.log(chalk.yellow(code));
|
|
52
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Diff output
|
|
56
|
-
diff(added: string[], removed: string[]): void {
|
|
57
|
-
removed.forEach(line => console.log(chalk.red(`- ${line}`)));
|
|
58
|
-
added.forEach(line => console.log(chalk.green(`+ ${line}`)));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Section header
|
|
62
|
-
section(title: string): void {
|
|
63
|
-
console.log();
|
|
64
|
-
console.log(chalk.bold.cyan(`═══ ${title} ═══`));
|
|
65
|
-
console.log();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Progress
|
|
69
|
-
progress(message: string): void {
|
|
70
|
-
process.stdout.write(chalk.gray(`${message}\r`));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Clear line
|
|
74
|
-
clearLine(): void {
|
|
75
|
-
process.stdout.write('\r\x1b[K');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Box output
|
|
79
|
-
box(content: string, title?: string): void {
|
|
80
|
-
const lines = content.split('\n');
|
|
81
|
-
// Strip ANSI codes when calculating length for proper alignment
|
|
82
|
-
const stripAnsi = (str: string) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
83
|
-
const maxLen = Math.max(...lines.map(l => stripAnsi(l).length), title?.length || 0);
|
|
84
|
-
const width = maxLen + 4;
|
|
85
|
-
|
|
86
|
-
console.log(chalk.cyan('┌' + '─'.repeat(width - 2) + '┐'));
|
|
87
|
-
if (title) {
|
|
88
|
-
console.log(chalk.cyan('│ ') + chalk.bold.white(title.padEnd(width - 4)) + chalk.cyan(' │'));
|
|
89
|
-
console.log(chalk.cyan('├' + '─'.repeat(width - 2) + '┤'));
|
|
90
|
-
}
|
|
91
|
-
lines.forEach(line => {
|
|
92
|
-
// Calculate visible length and pad accordingly
|
|
93
|
-
const visibleLen = stripAnsi(line).length;
|
|
94
|
-
const padding = ' '.repeat(Math.max(0, width - 4 - visibleLen));
|
|
95
|
-
console.log(chalk.cyan('│ ') + line + padding + chalk.cyan(' │'));
|
|
96
|
-
});
|
|
97
|
-
console.log(chalk.cyan('└' + '─'.repeat(width - 2) + '┘'));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Table output
|
|
101
|
-
table(headers: string[], rows: string[][]): void {
|
|
102
|
-
const colWidths = headers.map((h, i) => {
|
|
103
|
-
const maxData = Math.max(...rows.map(r => (r[i] || '').length));
|
|
104
|
-
return Math.max(h.length, maxData);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Header
|
|
108
|
-
console.log(
|
|
109
|
-
chalk.gray('│ ') +
|
|
110
|
-
headers.map((h, i) => chalk.bold(h.padEnd(colWidths[i]))).join(chalk.gray(' │ ')) +
|
|
111
|
-
chalk.gray(' │')
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
// Separator
|
|
115
|
-
console.log(
|
|
116
|
-
chalk.gray('├─') +
|
|
117
|
-
colWidths.map(w => '─'.repeat(w)).join(chalk.gray('─┼─')) +
|
|
118
|
-
chalk.gray('─┤')
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
// Rows
|
|
122
|
-
rows.forEach(row => {
|
|
123
|
-
console.log(
|
|
124
|
-
chalk.gray('│ ') +
|
|
125
|
-
row.map((cell, i) => (cell || '').padEnd(colWidths[i])).join(chalk.gray(' │ ')) +
|
|
126
|
-
chalk.gray(' │')
|
|
127
|
-
);
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|