echo-ai-agent 1.0.67 → 1.0.69
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/cli.js +103 -76
- package/main/main.js +466 -462
- package/package.json +1 -1
- package/scripts/auto-update.js +45 -45
- package/scripts/secure-storage.js +154 -154
- package/scripts/setup-wizard.js +163 -62
- package/ui/renderer.js +38 -28
- package/ui/style.css +73 -62
- package/utils/branding.js +60 -58
- package/.env.example +0 -1
package/cli.js
CHANGED
|
@@ -27,8 +27,6 @@ program
|
|
|
27
27
|
.description('Launch Echo AI Agent')
|
|
28
28
|
.option('-d, --debug', 'Run in debug mode')
|
|
29
29
|
.action((options) => {
|
|
30
|
-
console.log(banner);
|
|
31
|
-
|
|
32
30
|
// Check if configured
|
|
33
31
|
if (!config.get('configured')) {
|
|
34
32
|
console.log(chalk.yellow('⚠️ Echo is not configured yet. Running setup wizard...\n'));
|
|
@@ -36,6 +34,7 @@ program
|
|
|
36
34
|
launchEcho(options.debug);
|
|
37
35
|
});
|
|
38
36
|
} else {
|
|
37
|
+
console.log(banner);
|
|
39
38
|
launchEcho(options.debug);
|
|
40
39
|
}
|
|
41
40
|
});
|
|
@@ -44,7 +43,7 @@ program
|
|
|
44
43
|
.command('setup')
|
|
45
44
|
.description('Run the interactive setup wizard')
|
|
46
45
|
.action(async () => {
|
|
47
|
-
|
|
46
|
+
// Logo is printed by setupWizard.run() - no need to print here
|
|
48
47
|
await setupWizard.run();
|
|
49
48
|
});
|
|
50
49
|
|
|
@@ -130,24 +129,25 @@ program
|
|
|
130
129
|
{
|
|
131
130
|
type: 'list',
|
|
132
131
|
name: 'action',
|
|
133
|
-
message: 'Echo Configuration Management:',
|
|
134
|
-
pageSize:
|
|
132
|
+
message: chalk.cyan.bold('Echo Configuration Management:'),
|
|
133
|
+
pageSize: 12,
|
|
135
134
|
choices: [
|
|
136
|
-
{ name: '📋 View
|
|
135
|
+
{ name: '📋 View Current Configuration', value: 'list' },
|
|
137
136
|
{ name: '🎨 Appearance Settings', value: 'appearance' },
|
|
138
137
|
{ name: '👤 Personalization', value: 'personalization' },
|
|
139
138
|
{ name: '🤖 AI Intelligence', value: 'ai' },
|
|
140
139
|
{ name: '🎙️ Voice Settings', value: 'voice' },
|
|
141
|
-
{ name: '📚 Documentation Hub', value: 'docs' },
|
|
142
140
|
{ name: '🧠 Memory Management', value: 'memory' },
|
|
143
141
|
{ name: '🧩 Plugin Management', value: 'plugins' },
|
|
144
142
|
{ name: '⌨️ Workflow Macros', value: 'workflows' },
|
|
145
143
|
{ name: '🚀 Startup Settings', value: 'startup' },
|
|
146
144
|
{ name: '🔄 Auto-Update Settings', value: 'autoupdate' },
|
|
147
145
|
{ name: '🔔 Notification Settings', value: 'notify' },
|
|
146
|
+
new inquirer.Separator('───'),
|
|
147
|
+
{ name: '📚 Documentation Hub', value: 'docs' },
|
|
148
148
|
{ name: '⚠️ Reset All Settings', value: 'reset' },
|
|
149
149
|
new inquirer.Separator(),
|
|
150
|
-
{ name: '❌ Exit', value: 'exit' }
|
|
150
|
+
{ name: '❌ Exit', value: 'exit', short: 'Exit' }
|
|
151
151
|
]
|
|
152
152
|
}
|
|
153
153
|
]);
|
|
@@ -158,70 +158,89 @@ program
|
|
|
158
158
|
case 'list':
|
|
159
159
|
listConfig();
|
|
160
160
|
break;
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
case 'docs':
|
|
163
163
|
const { startServer } = require('./scripts/docs-server');
|
|
164
164
|
startServer();
|
|
165
|
-
return;
|
|
166
|
-
|
|
165
|
+
return;
|
|
166
|
+
|
|
167
167
|
case 'appearance':
|
|
168
|
+
console.log(chalk.cyan.bold('\n🎨 Appearance Settings\n'));
|
|
168
169
|
const appAnswers = await inquirer.prompt([
|
|
169
170
|
{
|
|
170
171
|
type: 'list',
|
|
171
172
|
name: 'theme',
|
|
172
173
|
message: 'Select Theme:',
|
|
173
|
-
choices: [
|
|
174
|
-
|
|
174
|
+
choices: [
|
|
175
|
+
{ name: '🔵 Cyan (Classic JARVIS)', value: 'cyan', short: 'Cyan' },
|
|
176
|
+
{ name: '🟣 Purple (Royal)', value: 'purple', short: 'Purple' },
|
|
177
|
+
{ name: '🟢 Green (Matrix)', value: 'green', short: 'Green' },
|
|
178
|
+
{ name: '🟡 Gold (Iron Man)', value: 'gold', short: 'Gold' },
|
|
179
|
+
{ name: '🔴 Red (Cyberpunk)', value: 'red', short: 'Red' },
|
|
180
|
+
{ name: '🔷 Blue (Ocean)', value: 'blue', short: 'Blue' }
|
|
181
|
+
],
|
|
182
|
+
default: ['cyan', 'purple', 'green', 'gold', 'red', 'blue'].indexOf(config.get('theme')) || 0,
|
|
183
|
+
pageSize: 6
|
|
175
184
|
},
|
|
176
185
|
{
|
|
177
186
|
type: 'list',
|
|
178
187
|
name: 'size',
|
|
179
188
|
message: 'Window Size:',
|
|
180
|
-
choices: [
|
|
181
|
-
|
|
189
|
+
choices: [
|
|
190
|
+
{ name: '📱 Small (Compact)', value: 'small', short: 'Small' },
|
|
191
|
+
{ name: '💻 Medium (Balanced)', value: 'medium', short: 'Medium' },
|
|
192
|
+
{ name: '🖥️ Large (Full View)', value: 'large', short: 'Large' }
|
|
193
|
+
],
|
|
194
|
+
default: ['small', 'medium', 'large'].indexOf(config.get('size')) || 1,
|
|
195
|
+
pageSize: 3
|
|
182
196
|
}
|
|
183
197
|
]);
|
|
184
198
|
config.set('theme', appAnswers.theme);
|
|
185
199
|
config.set('size', appAnswers.size);
|
|
186
|
-
console.log(chalk.green('✓ Appearance updated.'));
|
|
200
|
+
console.log(chalk.green('\n✓ Appearance updated successfully.'));
|
|
187
201
|
break;
|
|
188
202
|
|
|
189
203
|
case 'personalization':
|
|
204
|
+
console.log(chalk.cyan.bold('\n👤 Personalization\n'));
|
|
190
205
|
const { newName } = await inquirer.prompt([
|
|
191
206
|
{
|
|
192
207
|
type: 'input',
|
|
193
208
|
name: 'newName',
|
|
194
209
|
message: 'What should Echo call you?',
|
|
195
|
-
default: config.get('userName') || 'Friend'
|
|
210
|
+
default: config.get('userName') || 'Friend',
|
|
211
|
+
validate: (input) => input.trim() ? true : 'Name cannot be empty.'
|
|
196
212
|
}
|
|
197
213
|
]);
|
|
198
214
|
config.set('userName', newName);
|
|
199
|
-
console.log(chalk.green(
|
|
215
|
+
console.log(chalk.green(`\n✓ Echo will now call you ${chalk.cyan(newName)}.`));
|
|
200
216
|
break;
|
|
201
217
|
|
|
202
218
|
case 'voice':
|
|
219
|
+
console.log(chalk.cyan.bold('\n🎙️ Voice Recognition Settings\n'));
|
|
203
220
|
const { voiceProvider } = await inquirer.prompt([
|
|
204
221
|
{
|
|
205
222
|
type: 'list',
|
|
206
223
|
name: 'voiceProvider',
|
|
207
224
|
message: 'Select Voice Recognition Engine:',
|
|
208
225
|
choices: [
|
|
209
|
-
{ name: '🌐 Browser API
|
|
210
|
-
{ name: '☁️ Whisper Cloud
|
|
211
|
-
{ name: '🏠 Whisper Local
|
|
226
|
+
{ name: '🌐 Browser API (Native, Fast, Free)', value: 'browser', short: 'Browser API' },
|
|
227
|
+
{ name: '☁️ Whisper Cloud (Best Accuracy, OpenAI Key)', value: 'whisper', short: 'Whisper Cloud' },
|
|
228
|
+
{ name: '🏠 Whisper Local (Privacy, Offline)', value: 'whisper-local', short: 'Whisper Local' }
|
|
212
229
|
],
|
|
213
|
-
default: config.get('voiceProvider') ||
|
|
230
|
+
default: ['browser', 'whisper', 'whisper-local'].indexOf(config.get('voiceProvider')) || 0,
|
|
231
|
+
pageSize: 3
|
|
214
232
|
}
|
|
215
233
|
]);
|
|
216
|
-
|
|
234
|
+
|
|
217
235
|
if (voiceProvider === 'whisper' && (!config.get('apiKeys') || !config.get('apiKeys').openai)) {
|
|
218
|
-
console.log(chalk.yellow('\n⚠️ Whisper requires an OpenAI API key
|
|
236
|
+
console.log(chalk.yellow('\n⚠️ Whisper Cloud requires an OpenAI API key.\n'));
|
|
219
237
|
const { openAIKey } = await inquirer.prompt([
|
|
220
238
|
{
|
|
221
239
|
type: 'input',
|
|
222
240
|
name: 'openAIKey',
|
|
223
241
|
message: 'Enter your OpenAI API Key:',
|
|
224
|
-
validate: (i) => i.trim() ? true : 'Key is required for Whisper.'
|
|
242
|
+
validate: (i) => i.trim() ? true : 'Key is required for Whisper.',
|
|
243
|
+
mask: '*'
|
|
225
244
|
}
|
|
226
245
|
]);
|
|
227
246
|
const keys = config.get('apiKeys') || {};
|
|
@@ -234,63 +253,66 @@ program
|
|
|
234
253
|
await setup();
|
|
235
254
|
} else {
|
|
236
255
|
config.set('voiceProvider', voiceProvider);
|
|
237
|
-
console.log(chalk.green(
|
|
256
|
+
console.log(chalk.green(`\n✓ Voice engine set to ${voiceProvider === 'whisper' ? 'Whisper Cloud' : 'Browser API'}.`));
|
|
238
257
|
}
|
|
239
258
|
break;
|
|
240
259
|
|
|
241
260
|
case 'memory':
|
|
261
|
+
console.log(chalk.cyan.bold('\n🧠 Memory Management\n'));
|
|
262
|
+
const memEnabled = config.get('memoryEnabled') !== false;
|
|
242
263
|
const memAction = await inquirer.prompt([
|
|
243
264
|
{
|
|
244
265
|
type: 'list',
|
|
245
266
|
name: 'type',
|
|
246
|
-
message: '
|
|
267
|
+
message: 'Select Action:',
|
|
247
268
|
choices: [
|
|
248
|
-
{ name:
|
|
249
|
-
{ name: '🗑️ Clear All Memory', value: 'clear' },
|
|
250
|
-
{ name: '⬅️ Back', value: 'back' }
|
|
251
|
-
]
|
|
269
|
+
{ name: memEnabled ? '🔴 Disable Memory' : '🟢 Enable Memory', value: 'toggle', short: memEnabled ? 'Disable' : 'Enable' },
|
|
270
|
+
{ name: '🗑️ Clear All Memory', value: 'clear', short: 'Clear Memory' },
|
|
271
|
+
{ name: '⬅️ Back', value: 'back', short: 'Back' }
|
|
272
|
+
],
|
|
273
|
+
pageSize: 3
|
|
252
274
|
}
|
|
253
275
|
]);
|
|
254
|
-
|
|
276
|
+
|
|
255
277
|
if (memAction.type === 'toggle') {
|
|
256
278
|
const current = config.get('memoryEnabled') !== false;
|
|
257
279
|
config.set('memoryEnabled', !current);
|
|
258
|
-
console.log(chalk.green(
|
|
280
|
+
console.log(chalk.green(`\n✓ Conversational memory is now ${!current ? chalk.green('Enabled') : chalk.red('Disabled')}.`));
|
|
259
281
|
} else if (memAction.type === 'clear') {
|
|
260
282
|
const confirm = await inquirer.prompt([
|
|
261
283
|
{
|
|
262
284
|
type: 'confirm',
|
|
263
285
|
name: 'sure',
|
|
264
|
-
message: chalk.red.bold('Are you
|
|
286
|
+
message: chalk.red.bold('⚠️ Are you sure? Echo will lose all memory and conversation history.'),
|
|
265
287
|
default: false
|
|
266
288
|
}
|
|
267
289
|
]);
|
|
268
290
|
if (confirm.sure) {
|
|
269
291
|
const MemoryManager = require('./scripts/memory-manager');
|
|
270
292
|
new MemoryManager().clearMemory();
|
|
271
|
-
console.log(chalk.green('✓
|
|
293
|
+
console.log(chalk.green('\n✓ All memory has been cleared.'));
|
|
272
294
|
}
|
|
273
295
|
}
|
|
274
296
|
break;
|
|
275
297
|
|
|
276
298
|
case 'plugins':
|
|
277
|
-
|
|
278
|
-
console.log(chalk.cyan('\nRedirecting to Plugin Manager...'));
|
|
299
|
+
console.log(chalk.cyan.bold('\n🧩 Plugin Management\n'));
|
|
279
300
|
const PluginManager = require('./scripts/plugin-manager');
|
|
280
301
|
const generator = require('./scripts/plugin-generator');
|
|
281
302
|
const pm = new PluginManager();
|
|
282
303
|
const allPlugins = pm.listPlugins();
|
|
283
|
-
|
|
304
|
+
|
|
284
305
|
const { pluginAction } = await inquirer.prompt([
|
|
285
306
|
{
|
|
286
307
|
type: 'list',
|
|
287
308
|
name: 'pluginAction',
|
|
288
|
-
message: '
|
|
309
|
+
message: 'Select Action:',
|
|
289
310
|
choices: [
|
|
290
|
-
{ name: '✅ Toggle Plugins', value: 'toggle' },
|
|
291
|
-
{ name: '🛠️ Create New Plugin', value: 'create' },
|
|
292
|
-
{ name: '⬅️ Back', value: 'back' }
|
|
293
|
-
]
|
|
311
|
+
{ name: '✅ Toggle Plugins', value: 'toggle', short: 'Toggle' },
|
|
312
|
+
{ name: '🛠️ Create New Plugin', value: 'create', short: 'Create' },
|
|
313
|
+
{ name: '⬅️ Back', value: 'back', short: 'Back' }
|
|
314
|
+
],
|
|
315
|
+
pageSize: 3
|
|
294
316
|
}
|
|
295
317
|
]);
|
|
296
318
|
|
|
@@ -304,104 +326,116 @@ program
|
|
|
304
326
|
{
|
|
305
327
|
type: 'checkbox',
|
|
306
328
|
name: 'enabledPlugins',
|
|
307
|
-
message: 'Toggle Plugins:',
|
|
329
|
+
message: 'Toggle Plugins (Space to select, Enter to confirm):',
|
|
308
330
|
choices: allPlugins.map(p => ({
|
|
309
|
-
name: `${p.name}
|
|
331
|
+
name: `${p.name} - ${p.description || 'Plugin'}`,
|
|
310
332
|
value: p.name,
|
|
311
333
|
checked: p.enabled
|
|
312
|
-
}))
|
|
334
|
+
})),
|
|
335
|
+
pageSize: Math.min(allPlugins.length, 8)
|
|
313
336
|
}
|
|
314
337
|
]);
|
|
315
338
|
config.set('plugins', pluginAnswers.enabledPlugins);
|
|
316
|
-
console.log(chalk.green('✓ Plugin configuration updated.'));
|
|
317
|
-
|
|
339
|
+
console.log(chalk.green('\n✓ Plugin configuration updated.'));
|
|
340
|
+
break;
|
|
341
|
+
|
|
342
|
+
case 'startup':
|
|
318
343
|
const currentStartup = config.get('startOnBoot') === true;
|
|
344
|
+
console.log(chalk.cyan.bold('\n🚀 Startup Settings\n'));
|
|
319
345
|
const startupConfirm = await inquirer.prompt([
|
|
320
346
|
{
|
|
321
347
|
type: 'confirm',
|
|
322
348
|
name: 'enable',
|
|
323
|
-
message: currentStartup
|
|
349
|
+
message: currentStartup
|
|
350
|
+
? 'Echo is set to start on boot. Would you like to disable this?'
|
|
351
|
+
: 'Would you like Echo to start automatically when you log in?',
|
|
324
352
|
default: !currentStartup
|
|
325
353
|
}
|
|
326
354
|
]);
|
|
327
355
|
config.set('startOnBoot', currentStartup ? !startupConfirm.enable : startupConfirm.enable);
|
|
328
|
-
console.log(chalk.green(
|
|
356
|
+
console.log(chalk.green(`\n✓ Startup preference: ${currentStartup && startupConfirm.enable ? chalk.red('Disabled') : chalk.green('Enabled')}.`));
|
|
329
357
|
break;
|
|
330
358
|
|
|
331
359
|
case 'ai':
|
|
332
360
|
const AI_MODELS = require('./scripts/ai-models');
|
|
333
361
|
const currentProvider = config.get('aiProvider') || 'google';
|
|
334
362
|
const providerData = AI_MODELS[currentProvider];
|
|
335
|
-
|
|
363
|
+
|
|
336
364
|
if (!providerData) {
|
|
337
|
-
console.log(chalk.red('⚠️
|
|
365
|
+
console.log(chalk.red('\n⚠️ Invalid provider configured. Please run "echo-ai setup".'));
|
|
338
366
|
break;
|
|
339
367
|
}
|
|
340
368
|
|
|
369
|
+
console.log(chalk.cyan.bold(`\n🤖 AI Model Selection - ${providerData.name}\n`));
|
|
341
370
|
const { selectedModel } = await inquirer.prompt([
|
|
342
371
|
{
|
|
343
372
|
type: 'list',
|
|
344
373
|
name: 'selectedModel',
|
|
345
|
-
message: `Select
|
|
374
|
+
message: `Select Model:`,
|
|
346
375
|
choices: providerData.models.map(m => ({
|
|
347
|
-
name: m.name + (
|
|
348
|
-
value: m.id
|
|
376
|
+
name: m.name + chalk.gray(` - ${m.description || 'Default model'}`),
|
|
377
|
+
value: m.id,
|
|
378
|
+
short: m.name
|
|
349
379
|
})),
|
|
350
|
-
default: config.get('model')
|
|
380
|
+
default: providerData.models.findIndex(m => m.id === config.get('model')) || 0,
|
|
381
|
+
pageSize: providerData.models.length
|
|
351
382
|
}
|
|
352
383
|
]);
|
|
353
|
-
|
|
384
|
+
|
|
354
385
|
config.set('model', selectedModel);
|
|
355
|
-
console.log(chalk.green(
|
|
386
|
+
console.log(chalk.green(`\n✓ Active model set to ${chalk.cyan(selectedModel)}.`));
|
|
356
387
|
break;
|
|
357
388
|
|
|
358
389
|
case 'reset':
|
|
390
|
+
console.log(chalk.cyan.bold('\n⚠️ Reset Configuration\n'));
|
|
359
391
|
const resetConfirm = await inquirer.prompt([
|
|
360
392
|
{
|
|
361
393
|
type: 'confirm',
|
|
362
394
|
name: 'sure',
|
|
363
|
-
message: chalk.red('Reset all settings to factory defaults? (
|
|
395
|
+
message: chalk.red.bold('Reset all settings to factory defaults? (Memory will be preserved)'),
|
|
364
396
|
default: false
|
|
365
397
|
}
|
|
366
398
|
]);
|
|
367
399
|
if (resetConfirm.sure) {
|
|
368
400
|
config.clear();
|
|
369
|
-
console.log(chalk.green('✓ System reset to defaults.'));
|
|
401
|
+
console.log(chalk.green('\n✓ System reset to factory defaults.'));
|
|
370
402
|
}
|
|
371
403
|
break;
|
|
372
|
-
|
|
404
|
+
|
|
373
405
|
case 'autoupdate':
|
|
374
406
|
const currentAutoUpdate = config.get('autoUpdateCheck') !== false;
|
|
407
|
+
console.log(chalk.cyan.bold('\n🔄 Auto-Update Settings\n'));
|
|
375
408
|
const autoUpdateConfirm = await inquirer.prompt([
|
|
376
409
|
{
|
|
377
410
|
type: 'confirm',
|
|
378
411
|
name: 'enable',
|
|
379
|
-
message: currentAutoUpdate
|
|
380
|
-
? 'Auto-update check is enabled. Would you like to disable it?'
|
|
412
|
+
message: currentAutoUpdate
|
|
413
|
+
? 'Auto-update check is enabled. Would you like to disable it?'
|
|
381
414
|
: 'Would you like Echo to automatically check for updates on startup?',
|
|
382
415
|
default: !currentAutoUpdate
|
|
383
416
|
}
|
|
384
417
|
]);
|
|
385
418
|
config.set('autoUpdateCheck', currentAutoUpdate ? !autoUpdateConfirm.enable : autoUpdateConfirm.enable);
|
|
386
|
-
console.log(chalk.green(
|
|
419
|
+
console.log(chalk.green(`\n✓ Auto-update check ${currentAutoUpdate && autoUpdateConfirm.enable ? chalk.red('Disabled') : chalk.green('Enabled')}.`));
|
|
387
420
|
break;
|
|
388
421
|
|
|
389
422
|
case 'notify':
|
|
390
423
|
const currentNotify = config.get('startupNotification') !== false;
|
|
424
|
+
console.log(chalk.cyan.bold('\n🔔 Notification Settings\n'));
|
|
391
425
|
const notifyConfirm = await inquirer.prompt([
|
|
392
426
|
{
|
|
393
427
|
type: 'confirm',
|
|
394
428
|
name: 'enable',
|
|
395
|
-
message: currentNotify
|
|
396
|
-
? 'Startup notifications are enabled. Would you like to disable them?'
|
|
429
|
+
message: currentNotify
|
|
430
|
+
? 'Startup notifications are enabled. Would you like to disable them?'
|
|
397
431
|
: 'Would you like Echo to notify you when it starts up?',
|
|
398
432
|
default: !currentNotify
|
|
399
433
|
}
|
|
400
434
|
]);
|
|
401
435
|
config.set('startupNotification', currentNotify ? !notifyConfirm.enable : notifyConfirm.enable);
|
|
402
|
-
console.log(chalk.green(
|
|
436
|
+
console.log(chalk.green(`\n✓ Startup notifications ${currentNotify && notifyConfirm.enable ? chalk.red('Disabled') : chalk.green('Enabled')}.`));
|
|
403
437
|
break;
|
|
404
|
-
|
|
438
|
+
|
|
405
439
|
case 'workflows':
|
|
406
440
|
const workflowManager = require('./scripts/workflow-manager-cli');
|
|
407
441
|
await workflowManager.run();
|
|
@@ -720,7 +754,7 @@ program
|
|
|
720
754
|
}
|
|
721
755
|
});
|
|
722
756
|
|
|
723
|
-
// Default action (no command)
|
|
757
|
+
// Default action (no command) - show banner and quick help
|
|
724
758
|
program.action(() => {
|
|
725
759
|
console.log(banner);
|
|
726
760
|
console.log(chalk.gray('Run ') + chalk.cyan('echo-ai start') + chalk.gray(' to launch Echo'));
|
|
@@ -729,13 +763,6 @@ program.action(() => {
|
|
|
729
763
|
|
|
730
764
|
program.parse(process.argv);
|
|
731
765
|
|
|
732
|
-
// If no arguments provided, show banner and help
|
|
733
|
-
if (!process.argv.slice(2).length) {
|
|
734
|
-
console.log(banner);
|
|
735
|
-
console.log(chalk.gray('Run ') + chalk.cyan('echo-ai start') + chalk.gray(' to launch Echo'));
|
|
736
|
-
console.log(chalk.gray('Run ') + chalk.cyan('echo-ai --help') + chalk.gray(' for more commands\n'));
|
|
737
|
-
}
|
|
738
|
-
|
|
739
766
|
function launchEcho(debug = false) {
|
|
740
767
|
console.log(chalk.cyan('🚀 Launching Echo...\n'));
|
|
741
768
|
|