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.
@@ -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