@anh3d0nic/qwen-code-termux-ice 3.0.1 → 6.0.0
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 +87 -97
- package/package.json +18 -14
- package/scripts/ice-mobile.js +5 -0
- package/scripts/ice-session.js +6 -0
- package/scripts/ice-v4.js +657 -0
- package/scripts/ice-v5.js +371 -0
- package/scripts/ice-v6.js +415 -0
- package/scripts/test-v4.js +47 -0
- package/scripts/test-v6.js +59 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ❄️ ICE v6.0 - MOBILE UX POLISH
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Shorter responses on mobile (detect screen size)
|
|
9
|
+
* - Vim-style keyboard shortcuts (Hacker's Keyboard optimized)
|
|
10
|
+
* - AMOLED dark mode theme
|
|
11
|
+
* - Session resume after Termux killed (auto-save/restore)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
|
|
17
|
+
const SESSION_FILE = join(process.env.HOME, '.qwen', 'ice_session.json');
|
|
18
|
+
const CONFIG_FILE = join(process.env.HOME, '.qwen', 'ice_config.json');
|
|
19
|
+
|
|
20
|
+
// ============================================
|
|
21
|
+
// MOBILE DETECTION & SHORTER RESPONSES
|
|
22
|
+
// ============================================
|
|
23
|
+
|
|
24
|
+
function detectMobile() {
|
|
25
|
+
// Check TERMUX_VERSION env (Termux sets this)
|
|
26
|
+
const isTermux = !!process.env.TERMUX_VERSION;
|
|
27
|
+
const columns = process.stdout.columns || 80;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
isTermux,
|
|
31
|
+
isSmallScreen: columns < 80,
|
|
32
|
+
columns
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatResponse(content, options = {}) {
|
|
37
|
+
const device = detectMobile();
|
|
38
|
+
|
|
39
|
+
if (device.isSmallScreen || device.isTermux) {
|
|
40
|
+
// MOBILE MODE: Shorter, more concise
|
|
41
|
+
return formatMobileResponse(content);
|
|
42
|
+
} else {
|
|
43
|
+
// DESKTOP MODE: Full detail
|
|
44
|
+
return formatDesktopResponse(content);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function formatMobileResponse(content) {
|
|
49
|
+
// Mobile formatting:
|
|
50
|
+
// - Shorter lines (max 60 chars)
|
|
51
|
+
// - Emoji-first for quick scanning
|
|
52
|
+
// - Bullet points instead of paragraphs
|
|
53
|
+
// - No ASCII art (wastes space)
|
|
54
|
+
|
|
55
|
+
console.log('\n📱 Mobile Mode\n');
|
|
56
|
+
console.log('─'.repeat(Math.min(60, process.stdout.columns || 60)));
|
|
57
|
+
|
|
58
|
+
// Truncate long content
|
|
59
|
+
const maxLength = 500;
|
|
60
|
+
if (content.length > maxLength) {
|
|
61
|
+
console.log(content.substring(0, maxLength) + '...');
|
|
62
|
+
console.log('\n⋯ Full response available in desktop mode');
|
|
63
|
+
} else {
|
|
64
|
+
console.log(content);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log('─'.repeat(Math.min(60, process.stdout.columns || 60)));
|
|
68
|
+
console.log('\n💡 Tip: Use --desktop for full output\n');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function formatDesktopResponse(content) {
|
|
72
|
+
// Desktop formatting:
|
|
73
|
+
// - Full width
|
|
74
|
+
// - Detailed explanations
|
|
75
|
+
// - ASCII art OK
|
|
76
|
+
// - Multiple sections
|
|
77
|
+
|
|
78
|
+
console.log('\n💻 Desktop Mode\n');
|
|
79
|
+
console.log('═'.repeat(80));
|
|
80
|
+
console.log(content);
|
|
81
|
+
console.log('═'.repeat(80));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================
|
|
85
|
+
// VIM-STYLE KEYBOARD SHORTCUTS
|
|
86
|
+
// ============================================
|
|
87
|
+
|
|
88
|
+
const VIM_SHORTCUTS = {
|
|
89
|
+
// Navigation
|
|
90
|
+
'h': 'Move cursor left',
|
|
91
|
+
'j': 'Move cursor down',
|
|
92
|
+
'k': 'Move cursor up',
|
|
93
|
+
'l': 'Move cursor right',
|
|
94
|
+
'gg': 'Go to start',
|
|
95
|
+
'G': 'Go to end',
|
|
96
|
+
'0': 'Go to line start',
|
|
97
|
+
'$': 'Go to line end',
|
|
98
|
+
|
|
99
|
+
// Actions
|
|
100
|
+
'i': 'Insert mode (type)',
|
|
101
|
+
'a': 'Append after cursor',
|
|
102
|
+
'o': 'Open new line below',
|
|
103
|
+
'O': 'Open new line above',
|
|
104
|
+
'x': 'Delete character',
|
|
105
|
+
'dd': 'Delete line',
|
|
106
|
+
'yy': 'Yank (copy) line',
|
|
107
|
+
'p': 'Paste after',
|
|
108
|
+
'P': 'Paste before',
|
|
109
|
+
'u': 'Undo',
|
|
110
|
+
'Ctrl+r': 'Redo',
|
|
111
|
+
|
|
112
|
+
// Search
|
|
113
|
+
'/': 'Search forward',
|
|
114
|
+
'?': 'Search backward',
|
|
115
|
+
'n': 'Next match',
|
|
116
|
+
'N': 'Previous match',
|
|
117
|
+
'*': 'Search word under cursor',
|
|
118
|
+
|
|
119
|
+
// ICE-specific
|
|
120
|
+
'q': 'Quit',
|
|
121
|
+
'Q': 'Quit without saving',
|
|
122
|
+
'w': 'Save',
|
|
123
|
+
's': 'Send message',
|
|
124
|
+
'r': 'Regenerate response',
|
|
125
|
+
'c': 'Clear conversation',
|
|
126
|
+
't': 'Show thinking',
|
|
127
|
+
'v': 'Toggle verbose',
|
|
128
|
+
'm': 'Mobile mode',
|
|
129
|
+
'd': 'Desktop mode',
|
|
130
|
+
'?': 'Show help'
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
function showVimShortcuts() {
|
|
134
|
+
const device = detectMobile();
|
|
135
|
+
const isMobile = device.isSmallScreen || device.isTermux;
|
|
136
|
+
|
|
137
|
+
console.log('\n⌨️ Vim-Style Keyboard Shortcuts\n');
|
|
138
|
+
console.log('─'.repeat(isMobile ? 40 : 60));
|
|
139
|
+
|
|
140
|
+
const categories = {
|
|
141
|
+
'Navigation': ['h', 'j', 'k', 'l', 'gg', 'G', '0', '$'],
|
|
142
|
+
'Actions': ['i', 'a', 'o', 'O', 'x', 'dd', 'yy', 'p', 'P', 'u', 'Ctrl+r'],
|
|
143
|
+
'Search': ['/', '?', 'n', 'N', '*'],
|
|
144
|
+
'ICE': ['q', 'Q', 'w', 's', 'r', 'c', 't', 'v', 'm', 'd', '?']
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
Object.entries(categories).forEach(([category, keys]) => {
|
|
148
|
+
console.log(`\n${category}:`);
|
|
149
|
+
keys.forEach(key => {
|
|
150
|
+
const desc = VIM_SHORTCUTS[key] || 'Action';
|
|
151
|
+
const keyDisplay = key.replace('Ctrl', '^');
|
|
152
|
+
console.log(` ${keyDisplay.padEnd(10)} ${desc}`);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
console.log('\n💡 Optimized for Hacker\'s Keyboard / BT Keyboard');
|
|
157
|
+
console.log('─'.repeat(isMobile ? 40 : 60));
|
|
158
|
+
console.log();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ============================================
|
|
162
|
+
// AMOLED DARK MODE THEME
|
|
163
|
+
// ============================================
|
|
164
|
+
|
|
165
|
+
const THEMES = {
|
|
166
|
+
amoled: {
|
|
167
|
+
name: 'AMOLED Dark',
|
|
168
|
+
background: '#000000', // Pure black for AMOLED
|
|
169
|
+
text: '#E0E0E0', // Light gray (not pure white)
|
|
170
|
+
accent: '#00E676', // Bright green (good on AMOLED)
|
|
171
|
+
error: '#FF5252', // Red
|
|
172
|
+
warning: '#FFB74D', // Orange
|
|
173
|
+
info: '#4FC3F7', // Light blue
|
|
174
|
+
dim: '#757575' // Gray for less important text
|
|
175
|
+
},
|
|
176
|
+
termux: {
|
|
177
|
+
name: 'Termux Default',
|
|
178
|
+
background: '#000000',
|
|
179
|
+
text: '#FFFFFF',
|
|
180
|
+
accent: '#00FF00',
|
|
181
|
+
error: '#FF0000',
|
|
182
|
+
warning: '#FFFF00',
|
|
183
|
+
info: '#00FFFF',
|
|
184
|
+
dim: '#808080'
|
|
185
|
+
},
|
|
186
|
+
solarized: {
|
|
187
|
+
name: 'Solarized Dark',
|
|
188
|
+
background: '#002B36',
|
|
189
|
+
text: '#839496',
|
|
190
|
+
accent: '#2AA198',
|
|
191
|
+
error: '#DC322F',
|
|
192
|
+
warning: '#B58900',
|
|
193
|
+
info: '#268BD2',
|
|
194
|
+
dim: '#586E75'
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
function applyTheme(themeName = 'amoled') {
|
|
199
|
+
const theme = THEMES[themeName] || THEMES.amoled;
|
|
200
|
+
|
|
201
|
+
// ANSI escape codes for terminal colors
|
|
202
|
+
const colors = {
|
|
203
|
+
reset: '\x1b[0m',
|
|
204
|
+
bold: '\x1b[1m',
|
|
205
|
+
dim: '\x1b[2m',
|
|
206
|
+
|
|
207
|
+
// Foreground
|
|
208
|
+
fg: `\x1b[38;2;${hexToRgb(theme.text).join(';')}m`,
|
|
209
|
+
accent: `\x1b[38;2;${hexToRgb(theme.accent).join(';')}m`,
|
|
210
|
+
error: `\x1b[38;2;${hexToRgb(theme.error).join(';')}m`,
|
|
211
|
+
warning: `\x1b[38;2;${hexToRgb(theme.warning).join(';')}m`,
|
|
212
|
+
info: `\x1b[38;2;${hexToRgb(theme.info).join(';')}m`,
|
|
213
|
+
|
|
214
|
+
// Background
|
|
215
|
+
bg: `\x1b[48;2;${hexToRgb(theme.background).join(';')}m`
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
console.log(`${colors.bg}${colors.fg}`);
|
|
219
|
+
console.log(`\n🎨 Theme: ${theme.name}`);
|
|
220
|
+
console.log('─'.repeat(40));
|
|
221
|
+
console.log(`${colors.accent}✓ Accent text${colors.reset}`);
|
|
222
|
+
console.log(`${colors.error}✗ Error text${colors.reset}`);
|
|
223
|
+
console.log(`${colors.warning}⚠ Warning text${colors.reset}`);
|
|
224
|
+
console.log(`${colors.info}ℹ Info text${colors.reset}`);
|
|
225
|
+
console.log(`${colors.dim}… Dim text${colors.reset}`);
|
|
226
|
+
console.log('─'.repeat(40));
|
|
227
|
+
console.log(`${colors.reset}`);
|
|
228
|
+
|
|
229
|
+
return colors;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function hexToRgb(hex) {
|
|
233
|
+
// Convert #RRGGBB to [R, G, B]
|
|
234
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
235
|
+
return result ? [
|
|
236
|
+
parseInt(result[1], 16),
|
|
237
|
+
parseInt(result[2], 16),
|
|
238
|
+
parseInt(result[3], 16)
|
|
239
|
+
] : [255, 255, 255];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ============================================
|
|
243
|
+
// SESSION RESUME (Auto-save/restore)
|
|
244
|
+
// ============================================
|
|
245
|
+
|
|
246
|
+
class SessionManager {
|
|
247
|
+
constructor() {
|
|
248
|
+
this.sessionDir = join(process.env.HOME, '.qwen');
|
|
249
|
+
this.ensureDir();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
ensureDir() {
|
|
253
|
+
if (!existsSync(this.sessionDir)) {
|
|
254
|
+
mkdirSync(this.sessionDir, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
saveSession(data) {
|
|
259
|
+
const session = {
|
|
260
|
+
timestamp: Date.now(),
|
|
261
|
+
conversation: data.conversation || [],
|
|
262
|
+
context: data.context || {},
|
|
263
|
+
settings: data.settings || {}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
writeFileSync(SESSION_FILE, JSON.stringify(session, null, 2));
|
|
268
|
+
console.log('💾 Session auto-saved');
|
|
269
|
+
return true;
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.log('⚠️ Could not save session');
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
restoreSession() {
|
|
277
|
+
if (!existsSync(SESSION_FILE)) {
|
|
278
|
+
console.log('ℹ️ No previous session found');
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
const session = JSON.parse(readFileSync(SESSION_FILE, 'utf-8'));
|
|
284
|
+
const age = Date.now() - session.timestamp;
|
|
285
|
+
const ageHours = Math.floor(age / (1000 * 60 * 60));
|
|
286
|
+
|
|
287
|
+
console.log('📋 Found previous session');
|
|
288
|
+
console.log(` Age: ${ageHours} hours ago`);
|
|
289
|
+
console.log(` Messages: ${session.conversation.length}`);
|
|
290
|
+
console.log();
|
|
291
|
+
console.log('Restore this session? [Y/n]');
|
|
292
|
+
|
|
293
|
+
// In real implementation, wait for user input
|
|
294
|
+
return session;
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.log('⚠️ Could not restore session');
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
autoSave(interval = 30000) {
|
|
302
|
+
// Auto-save every N milliseconds
|
|
303
|
+
setInterval(() => {
|
|
304
|
+
this.saveSession({ conversation: [], context: {} });
|
|
305
|
+
}, interval);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
clearSession() {
|
|
309
|
+
if (existsSync(SESSION_FILE)) {
|
|
310
|
+
writeFileSync(SESSION_FILE, JSON.stringify({ timestamp: Date.now(), conversation: [] }, null, 2));
|
|
311
|
+
console.log('🗑️ Session cleared');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ============================================
|
|
317
|
+
// MOBILE-OPTIMIZED UI
|
|
318
|
+
// ============================================
|
|
319
|
+
|
|
320
|
+
function showMobileUI() {
|
|
321
|
+
const device = detectMobile();
|
|
322
|
+
|
|
323
|
+
console.log('\n❄️ ICE v6.0 - Mobile UX\n');
|
|
324
|
+
|
|
325
|
+
if (device.isSmallScreen) {
|
|
326
|
+
// Compact mobile layout
|
|
327
|
+
console.log('┌────────────────────────────────────┐');
|
|
328
|
+
console.log('│ ICE v6.0 │ 📱 Mobile │ ^q Quit │');
|
|
329
|
+
console.log('└────────────────────────────────────┘');
|
|
330
|
+
console.log();
|
|
331
|
+
console.log('Type your message:');
|
|
332
|
+
console.log('┌────────────────────────────────────┐');
|
|
333
|
+
console.log('│ > _ │');
|
|
334
|
+
console.log('│ │');
|
|
335
|
+
console.log('└────────────────────────────────────┘');
|
|
336
|
+
console.log();
|
|
337
|
+
console.log('Shortcuts: ^s Send ^c Clear ^? Help');
|
|
338
|
+
} else {
|
|
339
|
+
// Desktop layout
|
|
340
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
341
|
+
console.log('║ ❄️ ICE v6.0 │ 💻 Desktop │ :q Quit ║');
|
|
342
|
+
console.log('╠════════════════════════════════════════════════════════╣');
|
|
343
|
+
console.log('║ ║');
|
|
344
|
+
console.log('║ Type your message: ║');
|
|
345
|
+
console.log('║ > _ ║');
|
|
346
|
+
console.log('║ ║');
|
|
347
|
+
console.log('╚════════════════════════════════════════════════════════╝');
|
|
348
|
+
console.log();
|
|
349
|
+
console.log('Shortcuts: :w Save :r Regenerate :c Clear :? Help');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
console.log();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ============================================
|
|
356
|
+
// MAIN CLI
|
|
357
|
+
// ============================================
|
|
358
|
+
|
|
359
|
+
const args = process.argv.slice(2);
|
|
360
|
+
const command = args[0];
|
|
361
|
+
const sessionManager = new SessionManager();
|
|
362
|
+
|
|
363
|
+
if (!command) {
|
|
364
|
+
console.log('❄️ ICE v6.0 - Mobile UX Polish\n');
|
|
365
|
+
console.log('Usage:');
|
|
366
|
+
console.log(' ice-v6 mobile # Mobile-optimized UI');
|
|
367
|
+
console.log(' ice-v6 shortcuts # Vim-style keyboard shortcuts');
|
|
368
|
+
console.log(' ice-v6 theme [amoled|termux|solarized]');
|
|
369
|
+
console.log(' ice-v6 session save # Save current session');
|
|
370
|
+
console.log(' ice-v6 session restore # Restore previous session');
|
|
371
|
+
console.log(' ice-v6 session clear # Clear saved session\n');
|
|
372
|
+
console.log('Mobile-first features:');
|
|
373
|
+
console.log(' ✅ Shorter responses on small screens');
|
|
374
|
+
console.log(' ✅ Vim-style shortcuts (Hacker\'s Keyboard)');
|
|
375
|
+
console.log(' ✅ AMOLED dark mode theme');
|
|
376
|
+
console.log(' ✅ Session resume after Termux killed\n');
|
|
377
|
+
process.exit(0);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
switch (command) {
|
|
381
|
+
case 'mobile':
|
|
382
|
+
showMobileUI();
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
case 'shortcuts':
|
|
386
|
+
showVimShortcuts();
|
|
387
|
+
break;
|
|
388
|
+
|
|
389
|
+
case 'theme':
|
|
390
|
+
const themeName = args[1] || 'amoled';
|
|
391
|
+
applyTheme(themeName);
|
|
392
|
+
break;
|
|
393
|
+
|
|
394
|
+
case 'session':
|
|
395
|
+
const action = args[1];
|
|
396
|
+
if (action === 'save') {
|
|
397
|
+
sessionManager.saveSession({ conversation: [], context: {} });
|
|
398
|
+
} else if (action === 'restore') {
|
|
399
|
+
sessionManager.restoreSession();
|
|
400
|
+
} else if (action === 'clear') {
|
|
401
|
+
sessionManager.clearSession();
|
|
402
|
+
} else {
|
|
403
|
+
console.log('Usage: ice-v6 session [save|restore|clear]');
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
|
|
407
|
+
case 'response':
|
|
408
|
+
const content = args.slice(1).join(' ') || 'This is a test response';
|
|
409
|
+
formatResponse(content);
|
|
410
|
+
break;
|
|
411
|
+
|
|
412
|
+
default:
|
|
413
|
+
console.log(`Unknown command: ${command}`);
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ICE v4.0 Test Suite
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
console.log('❄️ ICE v4.0 Test Suite\\n');
|
|
10
|
+
console.log('=' .repeat(60));
|
|
11
|
+
|
|
12
|
+
const tests = [
|
|
13
|
+
{
|
|
14
|
+
name: 'Enhanced Validation (50 rules)',
|
|
15
|
+
command: 'node scripts/ice-v4.js validate "def login(user): query = \'SELECT * FROM users WHERE id = \' + user"'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'Feedback System',
|
|
19
|
+
command: 'node scripts/ice-v4.js feedback --stats'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Multi-Model Voting',
|
|
23
|
+
command: 'node scripts/ice-v4.js vote "test code"'
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
let passed = 0;
|
|
28
|
+
let failed = 0;
|
|
29
|
+
|
|
30
|
+
tests.forEach((test, i) => {
|
|
31
|
+
console.log(`\\nTest ${i + 1}: ${test.name}`);
|
|
32
|
+
console.log('-'.repeat(60));
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
execSync(test.command, { stdio: 'inherit' });
|
|
36
|
+
console.log(`✅ PASS\\n`);
|
|
37
|
+
passed++;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.log(`❌ FAIL\\n`);
|
|
40
|
+
failed++;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log('=' .repeat(60));
|
|
45
|
+
console.log(`\\nResults: ${passed} passed, ${failed} failed\\n`);
|
|
46
|
+
|
|
47
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ICE v6.0 Test Suite
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
console.log('❄️ ICE v6.0 Test Suite\\n');
|
|
10
|
+
console.log('=' .repeat(60));
|
|
11
|
+
|
|
12
|
+
const tests = [
|
|
13
|
+
{
|
|
14
|
+
name: 'Mobile UI',
|
|
15
|
+
command: 'node scripts/ice-v6.js mobile'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'Vim Shortcuts',
|
|
19
|
+
command: 'node scripts/ice-v6.js shortcuts'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'AMOLED Theme',
|
|
23
|
+
command: 'node scripts/ice-v6.js theme amoled'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Session Save/Restore',
|
|
27
|
+
command: 'node scripts/ice-v6.js session save'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Context-Aware (v5.0)',
|
|
31
|
+
command: 'node scripts/ice-v5.js context "prisma.user.findUnique()"'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'Pushback Mode (v5.0)',
|
|
35
|
+
command: 'node scripts/ice-v5.js pushback "SELECT * + userId"'
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
let passed = 0;
|
|
40
|
+
let failed = 0;
|
|
41
|
+
|
|
42
|
+
tests.forEach((test, i) => {
|
|
43
|
+
console.log(`\\nTest ${i + 1}: ${test.name}`);
|
|
44
|
+
console.log('-'.repeat(60));
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
execSync(test.command, { stdio: 'inherit' });
|
|
48
|
+
console.log(`✅ PASS\\n`);
|
|
49
|
+
passed++;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(`❌ FAIL\\n`);
|
|
52
|
+
failed++;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log('=' .repeat(60));
|
|
57
|
+
console.log(`\\nResults: ${passed} passed, ${failed} failed\\n`);
|
|
58
|
+
|
|
59
|
+
process.exit(failed > 0 ? 1 : 0);
|