vg-coder-cli 2.0.23 → 2.0.25
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/package.json +1 -1
- package/src/server/api-server.js +76 -0
- package/src/server/terminal-manager.js +109 -1
- package/src/server/views/css/terminal.css +88 -0
- package/src/server/views/dashboard.css +267 -0
- package/src/server/views/dashboard.html +56 -8
- package/src/server/views/js/features/commands.js +228 -0
- package/src/server/views/js/features/terminal.js +238 -4
- package/src/server/views/js/main.js +4 -0
- package/src/server/views/js/utils/log-utils.js +164 -0
- package/src/server/views/js/utils/smart-copy-engine.js +283 -0
- package/vg-coder-cli-2.0.24.tgz +0 -0
- package/vg-coder-cli-2.0.25.tgz +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Copy Engine
|
|
3
|
+
* Implements 4 copy strategies for terminal logs with token optimization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Import log utils (will be available globally in browser)
|
|
7
|
+
const LogUtils = typeof window !== 'undefined' ? window.LogUtils : require('./log-utils.js');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate Smart Copy (optimized for 3000 token limit)
|
|
11
|
+
* Strategy:
|
|
12
|
+
* - If < 3000 tokens: copy all
|
|
13
|
+
* - If > 3000 tokens: first 50 + all errors + last 50 + summary
|
|
14
|
+
*
|
|
15
|
+
* @param {string[]} lines - Array of log lines
|
|
16
|
+
* @param {number} maxTokens - Maximum token limit (default: 3000)
|
|
17
|
+
* @returns {Object} {content, tokens, strategy, stats}
|
|
18
|
+
*/
|
|
19
|
+
function generateSmartCopy(lines, maxTokens = 3000) {
|
|
20
|
+
if (!lines || lines.length === 0) {
|
|
21
|
+
return { content: '', tokens: 0, strategy: 'smart', stats: { totalLines: 0 } };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Strip ANSI codes from all lines
|
|
25
|
+
const cleanLines = lines.map(line => LogUtils.stripAnsiCodes(line));
|
|
26
|
+
|
|
27
|
+
// Check if we can copy everything
|
|
28
|
+
const fullContent = cleanLines.join('\n');
|
|
29
|
+
const fullTokens = LogUtils.estimateTokens(fullContent);
|
|
30
|
+
|
|
31
|
+
if (fullTokens <= maxTokens) {
|
|
32
|
+
return {
|
|
33
|
+
content: fullContent,
|
|
34
|
+
tokens: fullTokens,
|
|
35
|
+
strategy: 'smart-full',
|
|
36
|
+
stats: {
|
|
37
|
+
totalLines: cleanLines.length,
|
|
38
|
+
message: 'Full log (within token limit)'
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Need to optimize - extract components
|
|
44
|
+
const startLines = cleanLines.slice(0, 50);
|
|
45
|
+
const endLines = cleanLines.slice(-50);
|
|
46
|
+
const errorLines = LogUtils.extractErrors(cleanLines);
|
|
47
|
+
|
|
48
|
+
// Build optimized content
|
|
49
|
+
const sections = [];
|
|
50
|
+
|
|
51
|
+
// Header
|
|
52
|
+
sections.push('=== APPLICATION LOG (Smart Copy) ===\n');
|
|
53
|
+
|
|
54
|
+
// Startup section
|
|
55
|
+
sections.push('[STARTUP - First 50 lines]');
|
|
56
|
+
sections.push(startLines.join('\n'));
|
|
57
|
+
sections.push('');
|
|
58
|
+
|
|
59
|
+
// Errors section (if any)
|
|
60
|
+
if (errorLines.length > 0) {
|
|
61
|
+
sections.push(`[ERRORS & WARNINGS - ${errorLines.length} lines]`);
|
|
62
|
+
sections.push(errorLines.map(e => e.line).join('\n'));
|
|
63
|
+
sections.push('');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Recent section
|
|
67
|
+
sections.push('[RECENT - Last 50 lines]');
|
|
68
|
+
sections.push(endLines.join('\n'));
|
|
69
|
+
sections.push('');
|
|
70
|
+
|
|
71
|
+
// Summary
|
|
72
|
+
const skippedLines = cleanLines.length - 100 - errorLines.length;
|
|
73
|
+
if (skippedLines > 0) {
|
|
74
|
+
sections.push(`[Summary: Skipped ${skippedLines} normal log lines]`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const content = sections.join('\n');
|
|
78
|
+
const tokens = LogUtils.estimateTokens(content);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
content,
|
|
82
|
+
tokens,
|
|
83
|
+
strategy: 'smart-optimized',
|
|
84
|
+
stats: {
|
|
85
|
+
totalLines: cleanLines.length,
|
|
86
|
+
startupLines: 50,
|
|
87
|
+
errorLines: errorLines.length,
|
|
88
|
+
recentLines: 50,
|
|
89
|
+
skippedLines,
|
|
90
|
+
message: `Optimized from ${cleanLines.length} lines`
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate Errors Only Copy
|
|
97
|
+
* Only includes error/warning lines with 2-line context
|
|
98
|
+
*
|
|
99
|
+
* @param {string[]} lines - Array of log lines
|
|
100
|
+
* @returns {Object} {content, tokens, strategy, stats}
|
|
101
|
+
*/
|
|
102
|
+
function generateErrorsOnly(lines) {
|
|
103
|
+
if (!lines || lines.length === 0) {
|
|
104
|
+
return { content: '', tokens: 0, strategy: 'errors', stats: { totalLines: 0 } };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const cleanLines = lines.map(line => LogUtils.stripAnsiCodes(line));
|
|
108
|
+
const errorLines = LogUtils.extractErrors(cleanLines, 2);
|
|
109
|
+
|
|
110
|
+
if (errorLines.length === 0) {
|
|
111
|
+
const content = '=== NO ERRORS OR WARNINGS FOUND ===';
|
|
112
|
+
return {
|
|
113
|
+
content,
|
|
114
|
+
tokens: LogUtils.estimateTokens(content),
|
|
115
|
+
strategy: 'errors',
|
|
116
|
+
stats: {
|
|
117
|
+
totalLines: cleanLines.length,
|
|
118
|
+
errorLines: 0,
|
|
119
|
+
message: 'No errors found'
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const sections = [];
|
|
125
|
+
sections.push('=== ERRORS & WARNINGS ONLY ===\n');
|
|
126
|
+
sections.push(errorLines.map(e => e.line).join('\n'));
|
|
127
|
+
|
|
128
|
+
const content = sections.join('\n');
|
|
129
|
+
const tokens = LogUtils.estimateTokens(content);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
content,
|
|
133
|
+
tokens,
|
|
134
|
+
strategy: 'errors',
|
|
135
|
+
stats: {
|
|
136
|
+
totalLines: cleanLines.length,
|
|
137
|
+
errorLines: errorLines.length,
|
|
138
|
+
message: `Found ${errorLines.length} error/warning lines with context`
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate Recent Copy
|
|
145
|
+
* Copy last N lines (default: 200)
|
|
146
|
+
*
|
|
147
|
+
* @param {string[]} lines - Array of log lines
|
|
148
|
+
* @param {number} count - Number of recent lines to copy (default: 200)
|
|
149
|
+
* @returns {Object} {content, tokens, strategy, stats}
|
|
150
|
+
*/
|
|
151
|
+
function generateRecent(lines, count = 200) {
|
|
152
|
+
if (!lines || lines.length === 0) {
|
|
153
|
+
return { content: '', tokens: 0, strategy: 'recent', stats: { totalLines: 0 } };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const cleanLines = lines.map(line => LogUtils.stripAnsiCodes(line));
|
|
157
|
+
const recentLines = cleanLines.slice(-count);
|
|
158
|
+
|
|
159
|
+
const sections = [];
|
|
160
|
+
sections.push(`=== RECENT ${count} LINES ===\n`);
|
|
161
|
+
sections.push(recentLines.join('\n'));
|
|
162
|
+
|
|
163
|
+
if (cleanLines.length > count) {
|
|
164
|
+
sections.push('');
|
|
165
|
+
sections.push(`[Note: Showing last ${count} of ${cleanLines.length} total lines]`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const content = sections.join('\n');
|
|
169
|
+
const tokens = LogUtils.estimateTokens(content);
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
content,
|
|
173
|
+
tokens,
|
|
174
|
+
strategy: 'recent',
|
|
175
|
+
stats: {
|
|
176
|
+
totalLines: cleanLines.length,
|
|
177
|
+
recentLines: recentLines.length,
|
|
178
|
+
message: `Last ${recentLines.length} lines`
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Generate Copy All
|
|
185
|
+
* Copy entire log with warning if > 5000 tokens
|
|
186
|
+
*
|
|
187
|
+
* @param {string[]} lines - Array of log lines
|
|
188
|
+
* @returns {Object} {content, tokens, strategy, stats, warning}
|
|
189
|
+
*/
|
|
190
|
+
function generateCopyAll(lines) {
|
|
191
|
+
if (!lines || lines.length === 0) {
|
|
192
|
+
return { content: '', tokens: 0, strategy: 'all', stats: { totalLines: 0 } };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const cleanLines = lines.map(line => LogUtils.stripAnsiCodes(line));
|
|
196
|
+
const content = cleanLines.join('\n');
|
|
197
|
+
const tokens = LogUtils.estimateTokens(content);
|
|
198
|
+
|
|
199
|
+
const result = {
|
|
200
|
+
content,
|
|
201
|
+
tokens,
|
|
202
|
+
strategy: 'all',
|
|
203
|
+
stats: {
|
|
204
|
+
totalLines: cleanLines.length,
|
|
205
|
+
message: `Full log (${cleanLines.length} lines)`
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Add warning if too large
|
|
210
|
+
if (tokens > 5000) {
|
|
211
|
+
result.warning = `⚠️ Large log: ${tokens} tokens may exceed AI context limits`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Analyze log buffer and return stats for all strategies
|
|
219
|
+
* Used to update button badges in real-time
|
|
220
|
+
*
|
|
221
|
+
* @param {string[]} lines - Array of log lines
|
|
222
|
+
* @returns {Object} Stats for all 4 strategies
|
|
223
|
+
*/
|
|
224
|
+
function analyzeLogBuffer(lines) {
|
|
225
|
+
if (!lines || lines.length === 0) {
|
|
226
|
+
return {
|
|
227
|
+
smart: { tokens: 0, lines: 0 },
|
|
228
|
+
errors: { tokens: 0, lines: 0 },
|
|
229
|
+
recent: { tokens: 0, lines: 0 },
|
|
230
|
+
all: { tokens: 0, lines: 0 }
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const cleanLines = lines.map(line => LogUtils.stripAnsiCodes(line));
|
|
235
|
+
const errorLines = LogUtils.extractErrors(cleanLines);
|
|
236
|
+
|
|
237
|
+
// Estimate for each strategy
|
|
238
|
+
const smartResult = generateSmartCopy(lines, 3000);
|
|
239
|
+
const recentLines = cleanLines.slice(-200);
|
|
240
|
+
const allContent = cleanLines.join('\n');
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
smart: {
|
|
244
|
+
tokens: smartResult.tokens,
|
|
245
|
+
lines: cleanLines.length,
|
|
246
|
+
optimized: smartResult.strategy === 'smart-optimized'
|
|
247
|
+
},
|
|
248
|
+
errors: {
|
|
249
|
+
tokens: LogUtils.estimateTokens(errorLines.map(e => e.line).join('\n')),
|
|
250
|
+
lines: errorLines.length
|
|
251
|
+
},
|
|
252
|
+
recent: {
|
|
253
|
+
tokens: LogUtils.estimateTokens(recentLines.join('\n')),
|
|
254
|
+
lines: Math.min(200, cleanLines.length)
|
|
255
|
+
},
|
|
256
|
+
all: {
|
|
257
|
+
tokens: LogUtils.estimateTokens(allContent),
|
|
258
|
+
lines: cleanLines.length
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Export for Node.js
|
|
264
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
265
|
+
module.exports = {
|
|
266
|
+
generateSmartCopy,
|
|
267
|
+
generateErrorsOnly,
|
|
268
|
+
generateRecent,
|
|
269
|
+
generateCopyAll,
|
|
270
|
+
analyzeLogBuffer
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Export for browser
|
|
275
|
+
if (typeof window !== 'undefined') {
|
|
276
|
+
window.SmartCopyEngine = {
|
|
277
|
+
generateSmartCopy,
|
|
278
|
+
generateErrorsOnly,
|
|
279
|
+
generateRecent,
|
|
280
|
+
generateCopyAll,
|
|
281
|
+
analyzeLogBuffer
|
|
282
|
+
};
|
|
283
|
+
}
|
|
Binary file
|
|
Binary file
|