vg-coder-cli 2.0.1 → 2.0.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 +318 -92
- package/{vg/apps/api/src/assets/.gitkeep → change.sh} +0 -0
- package/package.json +4 -11
- package/src/index.js +0 -56
- package/src/server/views/dashboard.html +391 -613
- package/vg-coder-cli-1.0.17.tgz +0 -0
- package/vg-coder-cli-2.0.4.tgz +0 -0
- package/CHANGELOG.md +0 -59
- package/PUBLISHING.md +0 -86
- package/SYSTEM_PROMPT.md +0 -157
- package/init-nx-monorepo.sh +0 -107
- package/vg/.vscode/extensions.json +0 -8
- package/vg/.vscode/launch.json +0 -23
- package/vg/README.md +0 -85
- package/vg/apps/api/project.json +0 -83
- package/vg/apps/api/src/app/analyze.controller.ts +0 -17
- package/vg/apps/api/src/app/analyze.service.ts +0 -57
- package/vg/apps/api/src/app/app.controller.ts +0 -12
- package/vg/apps/api/src/app/app.module.ts +0 -29
- package/vg/apps/api/src/app/app.service.ts +0 -8
- package/vg/apps/api/src/app/clean.controller.ts +0 -40
- package/vg/apps/api/src/app/execute.controller.ts +0 -19
- package/vg/apps/api/src/app/execute.service.ts +0 -46
- package/vg/apps/api/src/app/info.controller.ts +0 -12
- package/vg/apps/api/src/app/info.service.ts +0 -65
- package/vg/apps/api/src/main.ts +0 -28
- package/vg/apps/api/webpack.config.js +0 -25
- package/vg/apps/api-e2e/jest.config.cts +0 -18
- package/vg/apps/api-e2e/project.json +0 -17
- package/vg/apps/api-e2e/src/support/global-setup.ts +0 -16
- package/vg/apps/api-e2e/src/support/global-teardown.ts +0 -10
- package/vg/apps/api-e2e/src/support/test-setup.ts +0 -9
- package/vg/apps/ng-app/jest.config.ts +0 -21
- package/vg/apps/ng-app/project.json +0 -110
- package/vg/apps/ng-app/proxy.conf.json +0 -8
- package/vg/apps/ng-app/public/favicon.ico +0 -0
- package/vg/apps/ng-app/src/app/app.config.ts +0 -17
- package/vg/apps/ng-app/src/app/app.html +0 -1
- package/vg/apps/ng-app/src/app/app.routes.ts +0 -7
- package/vg/apps/ng-app/src/app/app.scss +0 -0
- package/vg/apps/ng-app/src/app/app.ts +0 -12
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.html +0 -87
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.scss +0 -290
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.ts +0 -236
- package/vg/apps/ng-app/src/app/nx-welcome.ts +0 -872
- package/vg/apps/ng-app/src/app/services/api.service.ts +0 -28
- package/vg/apps/ng-app/src/index.html +0 -13
- package/vg/apps/ng-app/src/main.ts +0 -5
- package/vg/apps/ng-app/src/styles.scss +0 -1
- package/vg/apps/ng-app/src/test-setup.ts +0 -6
- package/vg/jest.config.ts +0 -6
- package/vg/nx.json +0 -85
- package/vg/package-lock.json +0 -30707
- package/vg/package.json +0 -75
- package/vg/packages/client/data-access/README.md +0 -7
- package/vg/packages/client/data-access/jest.config.ts +0 -21
- package/vg/packages/client/data-access/project.json +0 -21
- package/vg/packages/client/data-access/src/index.ts +0 -1
- package/vg/packages/client/data-access/src/lib/data-access/data-access.html +0 -1
- package/vg/packages/client/data-access/src/lib/data-access/data-access.scss +0 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.ts +0 -9
- package/vg/packages/client/data-access/src/test-setup.ts +0 -6
- package/vg/packages/core/README.md +0 -11
- package/vg/packages/core/jest.config.ts +0 -10
- package/vg/packages/core/package.json +0 -11
- package/vg/packages/core/project.json +0 -26
- package/vg/packages/core/src/index.ts +0 -6
- package/vg/packages/core/src/lib/core.ts +0 -3
- package/vg/packages/core/src/lib/detectors/project-detector.ts +0 -343
- package/vg/packages/core/src/lib/ignore/ignore-manager.ts +0 -315
- package/vg/packages/core/src/lib/scanner/file-scanner.ts +0 -675
- package/vg/packages/core/src/lib/tokenizer/token-manager.ts +0 -435
- package/vg/packages/core/src/lib/utils/bash-executor.ts +0 -146
- package/vg/packages/shared/data-types/README.md +0 -11
- package/vg/packages/shared/data-types/jest.config.ts +0 -10
- package/vg/packages/shared/data-types/package.json +0 -11
- package/vg/packages/shared/data-types/project.json +0 -26
- package/vg/packages/shared/data-types/src/index.ts +0 -1
- package/vg/packages/shared/data-types/src/lib/data-types.ts +0 -3
- package/vg/start-dev.sh +0 -22
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
import { encoding_for_model, get_encoding, Tiktoken, TiktokenModel } from 'tiktoken';
|
|
2
|
-
|
|
3
|
-
export interface TokenManagerOptions {
|
|
4
|
-
model?: string;
|
|
5
|
-
maxTokens?: number;
|
|
6
|
-
chunkOverlap?: number;
|
|
7
|
-
preserveStructure?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface TokenAnalysis {
|
|
11
|
-
file: string;
|
|
12
|
-
headerTokens: number;
|
|
13
|
-
contentTokens: number;
|
|
14
|
-
totalTokens: number;
|
|
15
|
-
exceedsLimit: boolean;
|
|
16
|
-
chunksNeeded: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface TokenAnalysisSummary {
|
|
20
|
-
files: TokenAnalysis[];
|
|
21
|
-
summary: {
|
|
22
|
-
totalFiles: number;
|
|
23
|
-
totalTokens: number;
|
|
24
|
-
averageTokensPerFile: number;
|
|
25
|
-
filesExceedingLimit: number;
|
|
26
|
-
totalChunks: number;
|
|
27
|
-
estimatedChunks: number;
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ChunkMetadata {
|
|
32
|
-
type?: string;
|
|
33
|
-
filePath?: string;
|
|
34
|
-
partNumber?: number;
|
|
35
|
-
[key: string]: any;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ContentChunk {
|
|
39
|
-
content: string;
|
|
40
|
-
tokens: number;
|
|
41
|
-
chunkIndex: number;
|
|
42
|
-
totalChunks: number;
|
|
43
|
-
metadata: ChunkMetadata;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Manage token counting and chunking
|
|
48
|
-
*/
|
|
49
|
-
export class TokenManager {
|
|
50
|
-
private options: TokenManagerOptions;
|
|
51
|
-
private encoding: Tiktoken | null = null;
|
|
52
|
-
|
|
53
|
-
constructor(options: TokenManagerOptions = {}) {
|
|
54
|
-
this.options = {
|
|
55
|
-
model: options.model || 'gpt-4',
|
|
56
|
-
maxTokens: options.maxTokens || 8000,
|
|
57
|
-
chunkOverlap: options.chunkOverlap || 200,
|
|
58
|
-
preserveStructure: options.preserveStructure !== false,
|
|
59
|
-
...options
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
this.initializeEncoding();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Initialize encoding
|
|
67
|
-
*/
|
|
68
|
-
initializeEncoding(): void {
|
|
69
|
-
try {
|
|
70
|
-
// Try using encoding for specific model
|
|
71
|
-
this.encoding = encoding_for_model(this.options.model as TiktokenModel);
|
|
72
|
-
} catch (error) {
|
|
73
|
-
try {
|
|
74
|
-
// Fallback to cl100k_base (GPT-4, GPT-3.5-turbo)
|
|
75
|
-
this.encoding = get_encoding('cl100k_base');
|
|
76
|
-
} catch (fallbackError) {
|
|
77
|
-
// Fallback to p50k_base (GPT-3)
|
|
78
|
-
this.encoding = get_encoding('p50k_base');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Count tokens in text
|
|
85
|
-
*/
|
|
86
|
-
countTokens(text: string): number {
|
|
87
|
-
if (!text || typeof text !== 'string') {
|
|
88
|
-
return 0;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
if (this.encoding) {
|
|
93
|
-
const tokens = this.encoding.encode(text);
|
|
94
|
-
return tokens.length;
|
|
95
|
-
}
|
|
96
|
-
return Math.ceil(text.length / 4);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
// Fallback: estimate based on characters (rough approximation)
|
|
99
|
-
return Math.ceil(text.length / 4);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Analyze token usage for a file
|
|
105
|
-
*/
|
|
106
|
-
analyzeFile(file: { relativePath: string; content: string; size: number; lines: number }): TokenAnalysis {
|
|
107
|
-
const headerTokens = this.countTokens(this.generateFileHeader(file));
|
|
108
|
-
const contentTokens = this.countTokens(file.content);
|
|
109
|
-
const totalTokens = headerTokens + contentTokens;
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
file: file.relativePath,
|
|
113
|
-
headerTokens,
|
|
114
|
-
contentTokens,
|
|
115
|
-
totalTokens,
|
|
116
|
-
exceedsLimit: totalTokens > (this.options.maxTokens || 8000),
|
|
117
|
-
chunksNeeded: Math.ceil(totalTokens / (this.options.maxTokens || 8000))
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Analyze token usage for all files
|
|
123
|
-
*/
|
|
124
|
-
analyzeFiles(files: any[]): TokenAnalysisSummary {
|
|
125
|
-
const analyses = files.map(file => this.analyzeFile(file));
|
|
126
|
-
|
|
127
|
-
const totalTokens = analyses.reduce((sum, analysis) => sum + analysis.totalTokens, 0);
|
|
128
|
-
const filesExceedingLimit = analyses.filter(analysis => analysis.exceedsLimit);
|
|
129
|
-
const totalChunks = analyses.reduce((sum, analysis) => sum + analysis.chunksNeeded, 0);
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
files: analyses,
|
|
133
|
-
summary: {
|
|
134
|
-
totalFiles: files.length,
|
|
135
|
-
totalTokens,
|
|
136
|
-
averageTokensPerFile: Math.round(totalTokens / files.length),
|
|
137
|
-
filesExceedingLimit: filesExceedingLimit.length,
|
|
138
|
-
totalChunks,
|
|
139
|
-
estimatedChunks: Math.ceil(totalTokens / (this.options.maxTokens || 8000))
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Split content into chunks
|
|
146
|
-
*/
|
|
147
|
-
async chunkContent(content: string, metadata: ChunkMetadata = {}): Promise<ContentChunk[]> {
|
|
148
|
-
const totalTokens = this.countTokens(content);
|
|
149
|
-
const maxTokens = this.options.maxTokens || 8000;
|
|
150
|
-
|
|
151
|
-
if (totalTokens <= maxTokens) {
|
|
152
|
-
return [{
|
|
153
|
-
content,
|
|
154
|
-
tokens: totalTokens,
|
|
155
|
-
chunkIndex: 0,
|
|
156
|
-
totalChunks: 1,
|
|
157
|
-
metadata
|
|
158
|
-
}];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return this.options.preserveStructure
|
|
162
|
-
? await this.chunkByStructure(content, metadata)
|
|
163
|
-
: await this.chunkByTokens(content, metadata);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Split by structure (prioritize keeping files intact)
|
|
168
|
-
*/
|
|
169
|
-
async chunkByStructure(content: string, metadata: ChunkMetadata = {}): Promise<ContentChunk[]> {
|
|
170
|
-
const chunks: ContentChunk[] = [];
|
|
171
|
-
const lines = content.split('\n');
|
|
172
|
-
let currentChunk = '';
|
|
173
|
-
let currentTokens = 0;
|
|
174
|
-
let chunkIndex = 0;
|
|
175
|
-
const maxTokens = this.options.maxTokens || 8000;
|
|
176
|
-
|
|
177
|
-
// Find file boundaries
|
|
178
|
-
const fileBoundaries = this.findFileBoundaries(lines);
|
|
179
|
-
|
|
180
|
-
for (let i = 0; i < fileBoundaries.length; i++) {
|
|
181
|
-
const boundary = fileBoundaries[i];
|
|
182
|
-
const fileContent = lines.slice(boundary.start, boundary.end).join('\n');
|
|
183
|
-
const fileTokens = this.countTokens(fileContent);
|
|
184
|
-
|
|
185
|
-
// If adding this file exceeds limit
|
|
186
|
-
if (currentTokens + fileTokens > maxTokens && currentChunk) {
|
|
187
|
-
// Save current chunk
|
|
188
|
-
chunks.push({
|
|
189
|
-
content: currentChunk.trim(),
|
|
190
|
-
tokens: currentTokens,
|
|
191
|
-
chunkIndex: chunkIndex++,
|
|
192
|
-
totalChunks: 0, // Will update later
|
|
193
|
-
metadata: { ...metadata, type: 'structure' }
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
currentChunk = '';
|
|
197
|
-
currentTokens = 0;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// If file itself is too large, split it
|
|
201
|
-
if (fileTokens > maxTokens) {
|
|
202
|
-
const fileChunks = await this.chunkLargeFile(fileContent, boundary.filePath);
|
|
203
|
-
chunks.push(...fileChunks.map(chunk => ({
|
|
204
|
-
...chunk,
|
|
205
|
-
chunkIndex: chunkIndex++,
|
|
206
|
-
metadata: { ...metadata, ...chunk.metadata, type: 'large-file' }
|
|
207
|
-
})));
|
|
208
|
-
} else {
|
|
209
|
-
currentChunk += fileContent + '\n';
|
|
210
|
-
currentTokens += fileTokens;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Add last chunk
|
|
215
|
-
if (currentChunk.trim()) {
|
|
216
|
-
chunks.push({
|
|
217
|
-
content: currentChunk.trim(),
|
|
218
|
-
tokens: currentTokens,
|
|
219
|
-
chunkIndex: chunkIndex++,
|
|
220
|
-
totalChunks: 0,
|
|
221
|
-
metadata: { ...metadata, type: 'structure' }
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Update totalChunks
|
|
226
|
-
chunks.forEach(chunk => {
|
|
227
|
-
chunk.totalChunks = chunks.length;
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
return chunks;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Split by tokens (simple splitting)
|
|
235
|
-
*/
|
|
236
|
-
async chunkByTokens(content: string, metadata: ChunkMetadata = {}): Promise<ContentChunk[]> {
|
|
237
|
-
const chunks: ContentChunk[] = [];
|
|
238
|
-
const lines = content.split('\n');
|
|
239
|
-
let currentChunk = '';
|
|
240
|
-
let currentTokens = 0;
|
|
241
|
-
let chunkIndex = 0;
|
|
242
|
-
const maxTokens = this.options.maxTokens || 8000;
|
|
243
|
-
const chunkOverlap = this.options.chunkOverlap || 200;
|
|
244
|
-
|
|
245
|
-
for (const line of lines) {
|
|
246
|
-
const lineTokens = this.countTokens(line + '\n');
|
|
247
|
-
|
|
248
|
-
if (currentTokens + lineTokens > maxTokens && currentChunk) {
|
|
249
|
-
// Save current chunk
|
|
250
|
-
chunks.push({
|
|
251
|
-
content: currentChunk.trim(),
|
|
252
|
-
tokens: currentTokens,
|
|
253
|
-
chunkIndex: chunkIndex++,
|
|
254
|
-
totalChunks: 0,
|
|
255
|
-
metadata: { ...metadata, type: 'token-based' }
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// Start new chunk with overlap
|
|
259
|
-
if (chunkOverlap > 0) {
|
|
260
|
-
const overlapLines = this.getOverlapLines(currentChunk, chunkOverlap);
|
|
261
|
-
currentChunk = overlapLines;
|
|
262
|
-
currentTokens = this.countTokens(overlapLines);
|
|
263
|
-
} else {
|
|
264
|
-
currentChunk = '';
|
|
265
|
-
currentTokens = 0;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
currentChunk += line + '\n';
|
|
270
|
-
currentTokens += lineTokens;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Add last chunk
|
|
274
|
-
if (currentChunk.trim()) {
|
|
275
|
-
chunks.push({
|
|
276
|
-
content: currentChunk.trim(),
|
|
277
|
-
tokens: currentTokens,
|
|
278
|
-
chunkIndex: chunkIndex++,
|
|
279
|
-
totalChunks: 0,
|
|
280
|
-
metadata: { ...metadata, type: 'token-based' }
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Update totalChunks
|
|
285
|
-
chunks.forEach(chunk => {
|
|
286
|
-
chunk.totalChunks = chunks.length;
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
return chunks;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Split large file
|
|
294
|
-
*/
|
|
295
|
-
async chunkLargeFile(fileContent: string, filePath: string): Promise<ContentChunk[]> {
|
|
296
|
-
const lines = fileContent.split('\n');
|
|
297
|
-
const chunks: ContentChunk[] = [];
|
|
298
|
-
let currentChunk = '';
|
|
299
|
-
let currentTokens = 0;
|
|
300
|
-
let chunkIndex = 0;
|
|
301
|
-
const maxTokens = this.options.maxTokens || 8000;
|
|
302
|
-
|
|
303
|
-
for (const line of lines) {
|
|
304
|
-
const lineTokens = this.countTokens(line + '\n');
|
|
305
|
-
|
|
306
|
-
if (currentTokens + lineTokens > maxTokens && currentChunk) {
|
|
307
|
-
chunks.push({
|
|
308
|
-
content: currentChunk.trim(),
|
|
309
|
-
tokens: this.countTokens(currentChunk.trim()),
|
|
310
|
-
chunkIndex: chunkIndex++,
|
|
311
|
-
totalChunks: 0,
|
|
312
|
-
metadata: {
|
|
313
|
-
filePath,
|
|
314
|
-
partNumber: chunkIndex + 1,
|
|
315
|
-
type: 'large-file-part'
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
currentChunk = '';
|
|
320
|
-
currentTokens = 0;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
currentChunk += line + '\n';
|
|
324
|
-
currentTokens += lineTokens;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Add last chunk
|
|
328
|
-
if (currentChunk.trim()) {
|
|
329
|
-
chunks.push({
|
|
330
|
-
content: currentChunk.trim(),
|
|
331
|
-
tokens: this.countTokens(currentChunk.trim()),
|
|
332
|
-
chunkIndex: chunkIndex++,
|
|
333
|
-
totalChunks: 0,
|
|
334
|
-
metadata: {
|
|
335
|
-
filePath,
|
|
336
|
-
partNumber: chunkIndex + 1,
|
|
337
|
-
type: 'large-file-part'
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Update totalChunks
|
|
343
|
-
chunks.forEach(chunk => {
|
|
344
|
-
chunk.totalChunks = chunks.length;
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
return chunks;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Find file boundaries in content
|
|
352
|
-
*/
|
|
353
|
-
findFileBoundaries(lines: string[]): { start: number; end: number; filePath: string }[] {
|
|
354
|
-
const boundaries: { start: number; end: number; filePath: string }[] = [];
|
|
355
|
-
let currentStart = 0;
|
|
356
|
-
let currentFilePath: string | null = null;
|
|
357
|
-
|
|
358
|
-
for (let i = 0; i < lines.length; i++) {
|
|
359
|
-
const line = lines[i];
|
|
360
|
-
|
|
361
|
-
// Find file header pattern
|
|
362
|
-
if (line.includes('================================================================================')) {
|
|
363
|
-
if (i + 1 < lines.length && lines[i + 1].startsWith('File: ')) {
|
|
364
|
-
// Save previous boundary
|
|
365
|
-
if (currentFilePath) {
|
|
366
|
-
boundaries.push({
|
|
367
|
-
start: currentStart,
|
|
368
|
-
end: i,
|
|
369
|
-
filePath: currentFilePath
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Start new file
|
|
374
|
-
currentStart = i;
|
|
375
|
-
currentFilePath = lines[i + 1].replace('File: ', '').trim();
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Add last boundary
|
|
381
|
-
if (currentFilePath) {
|
|
382
|
-
boundaries.push({
|
|
383
|
-
start: currentStart,
|
|
384
|
-
end: lines.length,
|
|
385
|
-
filePath: currentFilePath
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return boundaries;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Get overlap lines
|
|
394
|
-
*/
|
|
395
|
-
getOverlapLines(content: string, maxTokens: number): string {
|
|
396
|
-
const lines = content.split('\n');
|
|
397
|
-
let overlapContent = '';
|
|
398
|
-
let tokens = 0;
|
|
399
|
-
|
|
400
|
-
// Get from end
|
|
401
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
402
|
-
const line = lines[i] + '\n';
|
|
403
|
-
const lineTokens = this.countTokens(line);
|
|
404
|
-
|
|
405
|
-
if (tokens + lineTokens > maxTokens) {
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
overlapContent = line + overlapContent;
|
|
410
|
-
tokens += lineTokens;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return overlapContent;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* Generate file header
|
|
418
|
-
*/
|
|
419
|
-
generateFileHeader(file: { relativePath: string; size: number; lines: number }): string {
|
|
420
|
-
return `
|
|
421
|
-
================================================================================
|
|
422
|
-
File: ${file.relativePath}
|
|
423
|
-
Size: ${file.size} bytes | Lines: ${file.lines}
|
|
424
|
-
================================================================================`;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Cleanup encoding
|
|
429
|
-
*/
|
|
430
|
-
cleanup(): void {
|
|
431
|
-
if (this.encoding) {
|
|
432
|
-
this.encoding.free();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { exec } from 'child_process';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as fs from 'fs-extra';
|
|
4
|
-
import { promisify } from 'util';
|
|
5
|
-
|
|
6
|
-
const execAsync = promisify(exec);
|
|
7
|
-
|
|
8
|
-
export interface ExecutionResult {
|
|
9
|
-
success: boolean;
|
|
10
|
-
stdout?: string;
|
|
11
|
-
stderr?: string;
|
|
12
|
-
exitCode?: number;
|
|
13
|
-
error?: string;
|
|
14
|
-
details?: string;
|
|
15
|
-
executionTime: number;
|
|
16
|
-
syntaxError?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface ValidationResult {
|
|
20
|
-
valid: boolean;
|
|
21
|
-
error: string | null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Bash Script Executor
|
|
26
|
-
* Validates and executes bash scripts safely
|
|
27
|
-
*/
|
|
28
|
-
export class BashExecutor {
|
|
29
|
-
private workingDir: string;
|
|
30
|
-
private tempDir: string;
|
|
31
|
-
|
|
32
|
-
constructor(workingDir?: string) {
|
|
33
|
-
this.workingDir = workingDir || process.cwd();
|
|
34
|
-
this.tempDir = path.join(this.workingDir, '.vg', 'temp-execute');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Ensure temp directory exists
|
|
39
|
-
*/
|
|
40
|
-
async ensureTempDir(): Promise<void> {
|
|
41
|
-
await fs.ensureDir(this.tempDir);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Cleanup temp directory
|
|
46
|
-
*/
|
|
47
|
-
async cleanup(): Promise<void> {
|
|
48
|
-
try {
|
|
49
|
-
if (await fs.pathExists(this.tempDir)) {
|
|
50
|
-
await fs.remove(this.tempDir);
|
|
51
|
-
}
|
|
52
|
-
} catch (error: any) {
|
|
53
|
-
console.error('Cleanup error:', error.message);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Validate bash script syntax
|
|
59
|
-
* @param bashScript - The bash script to validate
|
|
60
|
-
*/
|
|
61
|
-
async validateSyntax(bashScript: string): Promise<ValidationResult> {
|
|
62
|
-
await this.ensureTempDir();
|
|
63
|
-
|
|
64
|
-
const scriptPath = path.join(this.tempDir, 'validate.sh');
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
// Write script to temp file
|
|
68
|
-
await fs.writeFile(scriptPath, bashScript, 'utf8');
|
|
69
|
-
|
|
70
|
-
// Validate syntax using bash -n
|
|
71
|
-
await execAsync(`bash -n "${scriptPath}"`);
|
|
72
|
-
|
|
73
|
-
return { valid: true, error: null };
|
|
74
|
-
|
|
75
|
-
} catch (error: any) {
|
|
76
|
-
return {
|
|
77
|
-
valid: false,
|
|
78
|
-
error: error.stderr || error.message
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Execute bash script in working directory
|
|
85
|
-
* @param bashScript - The bash script to execute
|
|
86
|
-
*/
|
|
87
|
-
async execute(bashScript: string): Promise<ExecutionResult> {
|
|
88
|
-
const startTime = Date.now();
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
// First validate syntax
|
|
92
|
-
const validation = await this.validateSyntax(bashScript);
|
|
93
|
-
|
|
94
|
-
if (!validation.valid) {
|
|
95
|
-
return {
|
|
96
|
-
success: false,
|
|
97
|
-
error: 'Syntax validation failed',
|
|
98
|
-
details: validation.error || 'Unknown syntax error',
|
|
99
|
-
executionTime: Date.now() - startTime,
|
|
100
|
-
syntaxError: true
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Execute script in working directory
|
|
105
|
-
const result = await execAsync(bashScript, {
|
|
106
|
-
cwd: this.workingDir,
|
|
107
|
-
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
108
|
-
shell: '/bin/bash'
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Cleanup temp directory
|
|
112
|
-
await this.cleanup();
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
success: true,
|
|
116
|
-
stdout: result.stdout || '',
|
|
117
|
-
stderr: result.stderr || '',
|
|
118
|
-
exitCode: 0,
|
|
119
|
-
executionTime: Date.now() - startTime
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
} catch (error: any) {
|
|
123
|
-
// Cleanup even on error
|
|
124
|
-
await this.cleanup();
|
|
125
|
-
|
|
126
|
-
// Check if it's an execution error (not syntax)
|
|
127
|
-
if (error.code !== undefined) {
|
|
128
|
-
return {
|
|
129
|
-
success: false,
|
|
130
|
-
stdout: error.stdout || '',
|
|
131
|
-
stderr: error.stderr || error.message,
|
|
132
|
-
exitCode: error.code || 1,
|
|
133
|
-
executionTime: Date.now() - startTime
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Unknown error
|
|
138
|
-
return {
|
|
139
|
-
success: false,
|
|
140
|
-
error: 'Execution failed',
|
|
141
|
-
details: error.message,
|
|
142
|
-
executionTime: Date.now() - startTime
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
displayName: 'data-types',
|
|
3
|
-
preset: '../../../jest.preset.js',
|
|
4
|
-
testEnvironment: 'node',
|
|
5
|
-
transform: {
|
|
6
|
-
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
7
|
-
},
|
|
8
|
-
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
9
|
-
coverageDirectory: '../../../coverage/packages/shared/data-types',
|
|
10
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "data-types",
|
|
3
|
-
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "packages/shared/data-types/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"tags": ["scope:shared", "type:lib"],
|
|
7
|
-
"targets": {
|
|
8
|
-
"build": {
|
|
9
|
-
"executor": "@nx/js:tsc",
|
|
10
|
-
"outputs": ["{options.outputPath}"],
|
|
11
|
-
"options": {
|
|
12
|
-
"outputPath": "dist/packages/shared/data-types",
|
|
13
|
-
"main": "packages/shared/data-types/src/index.ts",
|
|
14
|
-
"tsConfig": "packages/shared/data-types/tsconfig.lib.json",
|
|
15
|
-
"assets": ["packages/shared/data-types/*.md"]
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"test": {
|
|
19
|
-
"executor": "@nx/jest:jest",
|
|
20
|
-
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
21
|
-
"options": {
|
|
22
|
-
"jestConfig": "packages/shared/data-types/jest.config.ts"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './lib/data-types';
|
package/vg/start-dev.sh
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# VG Coder - Start Development Servers
|
|
4
|
-
# This script starts both the NestJS API and Angular frontend
|
|
5
|
-
|
|
6
|
-
echo "🚀 Starting VG Coder Development Environment..."
|
|
7
|
-
echo ""
|
|
8
|
-
|
|
9
|
-
# Check if we're in the vg directory
|
|
10
|
-
if [ ! -f "nx.json" ]; then
|
|
11
|
-
echo "❌ Error: Please run this script from the vg directory"
|
|
12
|
-
exit 1
|
|
13
|
-
fi
|
|
14
|
-
|
|
15
|
-
# Start both services
|
|
16
|
-
echo "📦 Starting API backend (port 3000)..."
|
|
17
|
-
echo "🎨 Starting Angular frontend (port 4200)..."
|
|
18
|
-
echo ""
|
|
19
|
-
echo "Press Ctrl+C to stop all services"
|
|
20
|
-
echo ""
|
|
21
|
-
|
|
22
|
-
nx run-many --target=serve --projects=api,ng-app --parallel=2
|