helix-assistant-cli 0.6.0 → 0.6.1
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/dist/ui/autocomplete.js +6 -6
- package/dist/ui/repl.js +41 -41
- package/package.json +2 -2
- package/src/ui/autocomplete.ts +7 -7
- package/src/ui/repl.ts +42 -42
- package/tsconfig.json +1 -1
package/dist/ui/autocomplete.js
CHANGED
|
@@ -16,7 +16,7 @@ exports.SLASH_COMMANDS = [
|
|
|
16
16
|
{ command: '/subagents', description: 'Ver el panel ASCII o chatear con un subagente', usage: '/subagents [list|chat <id> <mensaje>]' },
|
|
17
17
|
{ command: '/config-apikey', description: 'Configurador interactivo de API Keys (OpenAI, Anthropic, Gemini, etc.)' },
|
|
18
18
|
{ command: '/show-apikey', description: 'Ver estado y validez de las API Keys configuradas' },
|
|
19
|
-
{ command: '/microphone', description: 'Ver o alternar estado del
|
|
19
|
+
{ command: '/microphone', description: 'Ver o alternar estado del micrófono', usage: '/microphone [enable|disable]' },
|
|
20
20
|
{ command: '/tasks', description: 'Ver tareas activas y recientes del agente' },
|
|
21
21
|
{ command: '/model', description: 'Ver o cambiar el modelo activo (free/local/cloud)', usage: '/model [list|set <id>|effort <low|medium|high>]' },
|
|
22
22
|
{ command: '/models', description: 'Listar modelos disponibles de proveedores configurados' },
|
|
@@ -24,7 +24,7 @@ exports.SLASH_COMMANDS = [
|
|
|
24
24
|
{ command: '/status', description: 'Mostrar resumen del estado del sistema' },
|
|
25
25
|
{ command: '/providers', description: 'Ver proveedores configurados y salud de sus claves' },
|
|
26
26
|
{ command: '/capabilities', description: 'Ver capacidades activas: sandbox, subagentes, voz y browser' },
|
|
27
|
-
{ command: '/settings', description: 'Ver
|
|
27
|
+
{ command: '/settings', description: 'Ver configuración efectiva sin exponer secretos' },
|
|
28
28
|
{ command: '/clear', description: 'Limpiar pantalla y restaurar el banner de HELIX' },
|
|
29
29
|
{ command: '/stop', description: 'Parada de emergencia de todas las tareas activas' },
|
|
30
30
|
{ command: '/help', description: 'Mostrar ayuda de comandos y atajos' },
|
|
@@ -159,15 +159,15 @@ class Autocompleter {
|
|
|
159
159
|
*/
|
|
160
160
|
renderHelp() {
|
|
161
161
|
console.log('');
|
|
162
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
163
|
-
console.log(` ${chalk_1.default.gray('
|
|
162
|
+
console.log(` ${chalk_1.default.hex('#FF8C00').bold('⬡ Comandos Disponibles')} ${chalk_1.default.gray('(/ + [Tab] para autocompletar)')}`);
|
|
163
|
+
console.log(` ${chalk_1.default.gray('─'.repeat(50))}`);
|
|
164
164
|
for (const cmd of exports.SLASH_COMMANDS) {
|
|
165
165
|
const usage = cmd.usage ? ` ${chalk_1.default.gray(cmd.usage)}` : '';
|
|
166
166
|
console.log(` ${chalk_1.default.magenta(cmd.command.padEnd(16))} ${chalk_1.default.gray(cmd.description)}${usage}`);
|
|
167
167
|
}
|
|
168
168
|
console.log('');
|
|
169
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
170
|
-
console.log(` ${chalk_1.default.gray('
|
|
169
|
+
console.log(` ${chalk_1.default.hex('#FF8C00').bold('⬡ Prefijos Especiales')}`);
|
|
170
|
+
console.log(` ${chalk_1.default.gray('─'.repeat(50))}`);
|
|
171
171
|
console.log(` ${(0, colors_1.formatSkill)('nombre')} ${chalk_1.default.gray('Invoca una skill registrada')}`);
|
|
172
172
|
console.log(` ${(0, colors_1.formatMcp)('herramienta')} ${chalk_1.default.gray('Invoca herramientas MCP')}`);
|
|
173
173
|
console.log('');
|
package/dist/ui/repl.js
CHANGED
|
@@ -100,7 +100,7 @@ class HelixRepl {
|
|
|
100
100
|
this.waitingLogged = false;
|
|
101
101
|
await this._syncSettings();
|
|
102
102
|
await this.autocompleter.refreshSuggestions();
|
|
103
|
-
process.stdout.write(`\r\x1b[K${chalk_1.default.green('
|
|
103
|
+
process.stdout.write(`\r\x1b[K${chalk_1.default.green('●')} ${chalk_1.default.greenBright.bold('Conectado al agente HELIX')} \n`);
|
|
104
104
|
this._promptUser();
|
|
105
105
|
});
|
|
106
106
|
this.client.on('disconnected', () => {
|
|
@@ -109,40 +109,40 @@ class HelixRepl {
|
|
|
109
109
|
}
|
|
110
110
|
if (!this.waitingLogged) {
|
|
111
111
|
this.waitingLogged = true;
|
|
112
|
-
console.log(`\n${(0, colors_1.RED)('
|
|
113
|
-
console.log(`${(0, colors_1.GRAY)(' (Si no responde tras 3 reintentos, el CLI lo
|
|
112
|
+
console.log(`\n${(0, colors_1.RED)('●')} ${chalk_1.default.yellowBright('Esperando al servicio del agente HELIX en ws://127.0.0.1:8765...')}`);
|
|
113
|
+
console.log(`${(0, colors_1.GRAY)(' (Si no responde tras 3 reintentos, el CLI lo iniciará automáticamente en segundo plano)')}\n`);
|
|
114
114
|
}
|
|
115
115
|
this._promptUser();
|
|
116
116
|
});
|
|
117
117
|
this.client.on('auto_spawning_agent', () => {
|
|
118
|
-
process.stdout.write(`\n${(0, colors_1.CYAN_BOLD)('
|
|
119
|
-
process.stdout.write(`${(0, colors_1.GRAY)(' Por favor espere mientras termina de inicializarse (no se
|
|
118
|
+
process.stdout.write(`\n${(0, colors_1.CYAN_BOLD)('⚙️')} ${chalk_1.default.hex('#FF9F1C').bold('[AUTO-START]:')} Iniciando el servicio del agente HELIX en segundo plano...\n`);
|
|
119
|
+
process.stdout.write(`${(0, colors_1.GRAY)(' Por favor espere mientras termina de inicializarse (no se realizarán reintentos hasta que esté listo).')}\n`);
|
|
120
120
|
});
|
|
121
121
|
this.client.on('agent_starting_progress', (data) => {
|
|
122
|
-
process.stdout.write(`\r ${chalk_1.default.hex('#FF9F1C')('
|
|
122
|
+
process.stdout.write(`\r ${chalk_1.default.hex('#FF9F1C')('⏳')} ${chalk_1.default.gray(`Inicializando subsistemas de HELIX en segundo plano... (${data.elapsedSec}s)`)}`);
|
|
123
123
|
});
|
|
124
124
|
this.client.on('agent_ready', () => {
|
|
125
|
-
process.stdout.write(`\r\x1b[K ${chalk_1.default.green('
|
|
125
|
+
process.stdout.write(`\r\x1b[K ${chalk_1.default.green('✔')} ${chalk_1.default.greenBright('Servicio de HELIX listo. Conectando...')}\n\n`);
|
|
126
126
|
});
|
|
127
127
|
this.client.on('agent_start_failed', (data) => {
|
|
128
|
-
process.stdout.write(`\r\x1b[K\n ${chalk_1.default.red('
|
|
128
|
+
process.stdout.write(`\r\x1b[K\n ${chalk_1.default.red('✖')} ${chalk_1.default.redBright('No se pudo iniciar el servicio automáticamente:')} ${chalk_1.default.gray(data?.error || 'Tiempo agotado')}\n`);
|
|
129
129
|
this._promptUser();
|
|
130
130
|
});
|
|
131
131
|
// Voice Capture indicator
|
|
132
132
|
this.client.on('voice_capture_started', () => {
|
|
133
133
|
this.isCapturingVoice = true;
|
|
134
|
-
process.stdout.write(`\n${chalk_1.default.bgRed.white.bold('
|
|
134
|
+
process.stdout.write(`\n${chalk_1.default.bgRed.white.bold(' 🎙️ [VOZ DETECTADA - HEY HELIX]: Capturando audio... ')}\n`);
|
|
135
135
|
});
|
|
136
136
|
this.client.on('voice_capture_stopped', () => {
|
|
137
137
|
this.isCapturingVoice = false;
|
|
138
|
-
process.stdout.write(`\n${chalk_1.default.bgCyan.black.bold('
|
|
138
|
+
process.stdout.write(`\n${chalk_1.default.bgCyan.black.bold(' 🔊 [AUDIO RECIBIDO]: Procesando voz... ')}\n`);
|
|
139
139
|
this._promptUser();
|
|
140
140
|
});
|
|
141
141
|
// ReAct Step Progress
|
|
142
142
|
this.client.on('react_step', (step) => {
|
|
143
143
|
const iter = step?.iteration ?? 1;
|
|
144
144
|
const role = step?.role ? chalk_1.default.gray(` (${step.role})`) : '';
|
|
145
|
-
process.stdout.write(`\r ${chalk_1.default.hex('#FF9F1C')('
|
|
145
|
+
process.stdout.write(`\r ${chalk_1.default.hex('#FF9F1C')('◆')} ${chalk_1.default.gray(`Paso ${iter}${role} — Razonando...`)}`);
|
|
146
146
|
});
|
|
147
147
|
// Agent assistant message
|
|
148
148
|
this.client.on('agent_message', (payload) => {
|
|
@@ -158,12 +158,12 @@ class HelixRepl {
|
|
|
158
158
|
process.stdout.write('\r\x1b[K');
|
|
159
159
|
// Branded header
|
|
160
160
|
console.log('');
|
|
161
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
161
|
+
console.log(` ${chalk_1.default.hex('#FF8C00').bold('⬡ HELIX')}${modelBadge}`);
|
|
162
162
|
// Content with subtle left border and clean Markdown formatting
|
|
163
163
|
const formatted = (0, markdown_1.formatTerminalMarkdown)(content, this.plain);
|
|
164
164
|
const contentLines = formatted.trim().split('\n');
|
|
165
165
|
for (const line of contentLines) {
|
|
166
|
-
console.log(` ${chalk_1.default.gray('
|
|
166
|
+
console.log(` ${chalk_1.default.gray('│')} ${line}`);
|
|
167
167
|
}
|
|
168
168
|
console.log('');
|
|
169
169
|
this.conversationHistory.push({ role: 'assistant', content });
|
|
@@ -198,30 +198,30 @@ class HelixRepl {
|
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
200
|
async _handleConfirmationDialog(req) {
|
|
201
|
-
console.log(`\n${(0, colors_1.YELLOW_BOLD)('
|
|
202
|
-
console.log(`
|
|
201
|
+
console.log(`\n${(0, colors_1.YELLOW_BOLD)('⚠️ CONFIRMACIÓN DE ACCIÓN REQUERIDA')}`);
|
|
202
|
+
console.log(` Acción: ${chalk_1.default.white.bold(req.action || req.tool || 'Acción del sistema')}`);
|
|
203
203
|
if (req.description) {
|
|
204
|
-
console.log(`
|
|
204
|
+
console.log(` Descripción: ${(0, colors_1.DIM)(req.description)}`);
|
|
205
205
|
}
|
|
206
206
|
if (req.arguments && Object.keys(req.arguments).length > 0) {
|
|
207
|
-
console.log(`
|
|
207
|
+
console.log(` Parámetros: ${(0, colors_1.GRAY)(JSON.stringify(req.arguments))}`);
|
|
208
208
|
}
|
|
209
209
|
this.rl?.pause();
|
|
210
210
|
try {
|
|
211
211
|
const answer = await (0, prompts_1.default)({
|
|
212
212
|
type: 'confirm',
|
|
213
213
|
name: 'confirmed',
|
|
214
|
-
message: '
|
|
214
|
+
message: '¿Permitir al agente ejecutar esta acción?',
|
|
215
215
|
initial: true,
|
|
216
216
|
});
|
|
217
217
|
const reqId = req.request_id || req.id || '';
|
|
218
218
|
if (answer && answer.confirmed) {
|
|
219
219
|
this.client.confirmAction(reqId);
|
|
220
|
-
console.log((0, colors_1.GREEN)('
|
|
220
|
+
console.log((0, colors_1.GREEN)(' ✔ Acción confirmada.\n'));
|
|
221
221
|
}
|
|
222
222
|
else {
|
|
223
223
|
this.client.rejectAction(reqId);
|
|
224
|
-
console.log((0, colors_1.RED)('
|
|
224
|
+
console.log((0, colors_1.RED)(' ✖ Acción rechazada.\n'));
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
finally {
|
|
@@ -251,7 +251,7 @@ class HelixRepl {
|
|
|
251
251
|
await this._handleInputLine(line.trim());
|
|
252
252
|
});
|
|
253
253
|
rl.on('close', () => {
|
|
254
|
-
console.log((0, colors_1.DIM)('\nCerrando
|
|
254
|
+
console.log((0, colors_1.DIM)('\nCerrando sesión de HELIX CLI...'));
|
|
255
255
|
this.client.close();
|
|
256
256
|
process.exit(0);
|
|
257
257
|
});
|
|
@@ -265,7 +265,7 @@ class HelixRepl {
|
|
|
265
265
|
this._promptUser();
|
|
266
266
|
}
|
|
267
267
|
else {
|
|
268
|
-
console.log((0, colors_1.DIM)('\n
|
|
268
|
+
console.log((0, colors_1.DIM)('\n¡Hasta pronto!'));
|
|
269
269
|
this.client.close();
|
|
270
270
|
process.exit(0);
|
|
271
271
|
}
|
|
@@ -275,7 +275,7 @@ class HelixRepl {
|
|
|
275
275
|
_promptUser() {
|
|
276
276
|
if (!this.rl)
|
|
277
277
|
return;
|
|
278
|
-
const promptPrefix = ` ${chalk_1.default.hex('#FF8C00').bold('helix')} ${chalk_1.default.gray('
|
|
278
|
+
const promptPrefix = ` ${chalk_1.default.hex('#FF8C00').bold('helix')} ${chalk_1.default.gray('❯')} `;
|
|
279
279
|
this.rl.setPrompt(promptPrefix);
|
|
280
280
|
this.rl.prompt();
|
|
281
281
|
}
|
|
@@ -285,7 +285,7 @@ class HelixRepl {
|
|
|
285
285
|
return;
|
|
286
286
|
}
|
|
287
287
|
if (this.client.isStarting) {
|
|
288
|
-
console.log(`\n ${chalk_1.default.yellow('
|
|
288
|
+
console.log(`\n ${chalk_1.default.yellow('⚠️')} ${chalk_1.default.yellowBright('El servicio de HELIX se está iniciando en segundo plano. Espera a que termine antes de enviar comandos o reintentar.')}\n`);
|
|
289
289
|
this._promptUser();
|
|
290
290
|
return;
|
|
291
291
|
}
|
|
@@ -416,7 +416,7 @@ class HelixRepl {
|
|
|
416
416
|
this.client.emergencyStop();
|
|
417
417
|
this.isProcessingPrompt = false;
|
|
418
418
|
this.activeTaskId = null;
|
|
419
|
-
console.log((0, colors_1.GREEN)('
|
|
419
|
+
console.log((0, colors_1.GREEN)('✔ Todas las tareas han sido detenidas.\n'));
|
|
420
420
|
break;
|
|
421
421
|
case '/exit':
|
|
422
422
|
case '/quit':
|
|
@@ -432,7 +432,7 @@ class HelixRepl {
|
|
|
432
432
|
}
|
|
433
433
|
// --- Direct chat message / @skill / #mcp ---
|
|
434
434
|
if (!this.client.connected) {
|
|
435
|
-
console.log((0, colors_1.YELLOW)('
|
|
435
|
+
console.log((0, colors_1.YELLOW)('⚠ El agente no está conectado actualmente. Intentando enviar de todos modos...'));
|
|
436
436
|
}
|
|
437
437
|
// Highlight skills in strong orange (#FF8C00) and mcps in cyan
|
|
438
438
|
const knownSkills = this.autocompleter.getSkills();
|
|
@@ -441,12 +441,12 @@ class HelixRepl {
|
|
|
441
441
|
this.conversationHistory.push({ role: 'user', content: line });
|
|
442
442
|
this.isProcessingPrompt = true;
|
|
443
443
|
this.activeTasksCount++;
|
|
444
|
-
process.stdout.write(` ${chalk_1.default.gray('
|
|
445
|
-
process.stdout.write(` ${chalk_1.default.hex('#FF9F1C')('
|
|
444
|
+
process.stdout.write(` ${chalk_1.default.gray('→')} ${formattedEcho}\n`);
|
|
445
|
+
process.stdout.write(` ${chalk_1.default.hex('#FF9F1C')('◆')} ${chalk_1.default.gray('Procesando...')}`);
|
|
446
446
|
const sent = this.client.sendUserText(line, this.conversationId, this.conversationHistory.slice(-10));
|
|
447
447
|
if (!sent) {
|
|
448
448
|
process.stdout.write('\r\x1b[K');
|
|
449
|
-
console.log((0, colors_1.RED)('
|
|
449
|
+
console.log((0, colors_1.RED)('✖ Error: No se pudo enviar el mensaje (WebSocket desconectado).'));
|
|
450
450
|
this.isProcessingPrompt = false;
|
|
451
451
|
this.activeTasksCount = Math.max(0, this.activeTasksCount - 1);
|
|
452
452
|
this._promptUser();
|
|
@@ -455,7 +455,7 @@ class HelixRepl {
|
|
|
455
455
|
async _handleListTasks() {
|
|
456
456
|
try {
|
|
457
457
|
const tasks = await this.client.getTasks();
|
|
458
|
-
console.log(`\n${(0, colors_1.BOLD)('
|
|
458
|
+
console.log(`\n${(0, colors_1.BOLD)('📋 Tareas Registradas en HELIX:')}\n`);
|
|
459
459
|
if (!tasks || tasks.length === 0) {
|
|
460
460
|
console.log((0, colors_1.GRAY)(' No hay tareas recientes registradas.\n'));
|
|
461
461
|
return;
|
|
@@ -463,13 +463,13 @@ class HelixRepl {
|
|
|
463
463
|
for (const t of tasks.slice(-10)) {
|
|
464
464
|
let statusBadge = chalk_1.default.gray(t.status);
|
|
465
465
|
if (t.status === 'COMPLETED')
|
|
466
|
-
statusBadge = chalk_1.default.green('
|
|
466
|
+
statusBadge = chalk_1.default.green('✔ Completada');
|
|
467
467
|
if (t.status === 'RUNNING')
|
|
468
|
-
statusBadge = chalk_1.default.yellow('
|
|
468
|
+
statusBadge = chalk_1.default.yellow('⏳ En ejecución');
|
|
469
469
|
if (t.status === 'FAILED')
|
|
470
|
-
statusBadge = chalk_1.default.red('
|
|
470
|
+
statusBadge = chalk_1.default.red('✖ Fallida');
|
|
471
471
|
if (t.status === 'CANCELLED')
|
|
472
|
-
statusBadge = chalk_1.default.gray('
|
|
472
|
+
statusBadge = chalk_1.default.gray('○ Cancelada');
|
|
473
473
|
console.log(` ${statusBadge} ${(0, colors_1.DIM)(t.task_id)}`);
|
|
474
474
|
if (t.prompt)
|
|
475
475
|
console.log(` ${chalk_1.default.white(t.prompt)}`);
|
|
@@ -483,13 +483,13 @@ class HelixRepl {
|
|
|
483
483
|
async _handleListModels() {
|
|
484
484
|
try {
|
|
485
485
|
const models = await this.client.getModels();
|
|
486
|
-
console.log(`\n${(0, colors_1.BOLD)('
|
|
486
|
+
console.log(`\n${(0, colors_1.BOLD)('🧠 Modelos Disponibles en Proveedores Configurados:')}\n`);
|
|
487
487
|
if (!models || models.length === 0) {
|
|
488
488
|
console.log((0, colors_1.GRAY)(' No hay modelos disponibles. Configura tus API Keys con /config-apikey.\n'));
|
|
489
489
|
return;
|
|
490
490
|
}
|
|
491
491
|
for (const m of models) {
|
|
492
|
-
console.log(` ${(0, colors_1.CYAN)('
|
|
492
|
+
console.log(` ${(0, colors_1.CYAN)('•')} ${chalk_1.default.bold(m.id)} ${(0, colors_1.DIM)(`[${m.provider}]`)}`);
|
|
493
493
|
}
|
|
494
494
|
console.log('');
|
|
495
495
|
}
|
|
@@ -499,11 +499,11 @@ class HelixRepl {
|
|
|
499
499
|
}
|
|
500
500
|
async _handleStatus() {
|
|
501
501
|
console.log('');
|
|
502
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
503
|
-
console.log(` ${chalk_1.default.gray('
|
|
504
|
-
console.log(` ${chalk_1.default.gray('Agente WS')} ${this.client.connected ? chalk_1.default.green('
|
|
505
|
-
console.log(` ${chalk_1.default.gray('
|
|
506
|
-
console.log(` ${chalk_1.default.gray('
|
|
502
|
+
console.log(` ${chalk_1.default.hex('#FF8C00').bold('⬡ Estado del Sistema')}`);
|
|
503
|
+
console.log(` ${chalk_1.default.gray('─'.repeat(40))}`);
|
|
504
|
+
console.log(` ${chalk_1.default.gray('Agente WS')} ${this.client.connected ? chalk_1.default.green('● Conectado') : chalk_1.default.red('● Desconectado')} ${chalk_1.default.gray(this.client.url)}`);
|
|
505
|
+
console.log(` ${chalk_1.default.gray('Micrófono')} ${this.voiceEnabled ? chalk_1.default.green('● Activo') + chalk_1.default.gray(' (hey helix)') : chalk_1.default.red('● Inactivo')}`);
|
|
506
|
+
console.log(` ${chalk_1.default.gray('Conversación')} ${chalk_1.default.gray(this.conversationId)} ${chalk_1.default.gray(`(${this.conversationHistory.length} msgs)`)}`);
|
|
507
507
|
console.log(` ${chalk_1.default.gray('Skills')} ${chalk_1.default.hex('#FF8C00').bold(this.autocompleter.getSkills().length.toString())} registradas`);
|
|
508
508
|
console.log(` ${chalk_1.default.gray('MCP Tools')} ${chalk_1.default.cyan.bold(this.autocompleter.getMcpTools().length.toString())} disponibles`);
|
|
509
509
|
console.log('');
|
package/package.json
CHANGED
package/src/ui/autocomplete.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
2
|
import type { AgentClient } from '../client/agent-client';
|
|
3
3
|
import { formatSkill, formatMcp, ORANGE, CYAN, MAGENTA, DIM } from './colors';
|
|
4
4
|
import { discoverUserSkillNames, getUserSkillsDirectory } from '../skills/user-skill-discovery';
|
|
@@ -18,7 +18,7 @@ export const SLASH_COMMANDS: CommandDefinition[] = [
|
|
|
18
18
|
{ command: '/subagents', description: 'Ver el panel ASCII o chatear con un subagente', usage: '/subagents [list|chat <id> <mensaje>]' },
|
|
19
19
|
{ command: '/config-apikey', description: 'Configurador interactivo de API Keys (OpenAI, Anthropic, Gemini, etc.)' },
|
|
20
20
|
{ command: '/show-apikey', description: 'Ver estado y validez de las API Keys configuradas' },
|
|
21
|
-
{ command: '/microphone', description: 'Ver o alternar estado del
|
|
21
|
+
{ command: '/microphone', description: 'Ver o alternar estado del micrófono', usage: '/microphone [enable|disable]' },
|
|
22
22
|
{ command: '/tasks', description: 'Ver tareas activas y recientes del agente' },
|
|
23
23
|
{ command: '/model', description: 'Ver o cambiar el modelo activo (free/local/cloud)', usage: '/model [list|set <id>|effort <low|medium|high>]' },
|
|
24
24
|
{ command: '/models', description: 'Listar modelos disponibles de proveedores configurados' },
|
|
@@ -26,7 +26,7 @@ export const SLASH_COMMANDS: CommandDefinition[] = [
|
|
|
26
26
|
{ command: '/status', description: 'Mostrar resumen del estado del sistema' },
|
|
27
27
|
{ command: '/providers', description: 'Ver proveedores configurados y salud de sus claves' },
|
|
28
28
|
{ command: '/capabilities', description: 'Ver capacidades activas: sandbox, subagentes, voz y browser' },
|
|
29
|
-
{ command: '/settings', description: 'Ver
|
|
29
|
+
{ command: '/settings', description: 'Ver configuración efectiva sin exponer secretos' },
|
|
30
30
|
{ command: '/clear', description: 'Limpiar pantalla y restaurar el banner de HELIX' },
|
|
31
31
|
{ command: '/stop', description: 'Parada de emergencia de todas las tareas activas' },
|
|
32
32
|
{ command: '/help', description: 'Mostrar ayuda de comandos y atajos' },
|
|
@@ -175,16 +175,16 @@ export class Autocompleter {
|
|
|
175
175
|
*/
|
|
176
176
|
public renderHelp(): void {
|
|
177
177
|
console.log('');
|
|
178
|
-
console.log(` ${chalk.hex('#FF8C00').bold('
|
|
179
|
-
console.log(` ${chalk.gray('
|
|
178
|
+
console.log(` ${chalk.hex('#FF8C00').bold('⬡ Comandos Disponibles')} ${chalk.gray('(/ + [Tab] para autocompletar)')}`);
|
|
179
|
+
console.log(` ${chalk.gray('─'.repeat(50))}`);
|
|
180
180
|
for (const cmd of SLASH_COMMANDS) {
|
|
181
181
|
const usage = cmd.usage ? ` ${chalk.gray(cmd.usage)}` : '';
|
|
182
182
|
console.log(` ${chalk.magenta(cmd.command.padEnd(16))} ${chalk.gray(cmd.description)}${usage}`);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
console.log('');
|
|
186
|
-
console.log(` ${chalk.hex('#FF8C00').bold('
|
|
187
|
-
console.log(` ${chalk.gray('
|
|
186
|
+
console.log(` ${chalk.hex('#FF8C00').bold('⬡ Prefijos Especiales')}`);
|
|
187
|
+
console.log(` ${chalk.gray('─'.repeat(50))}`);
|
|
188
188
|
console.log(` ${formatSkill('nombre')} ${chalk.gray('Invoca una skill registrada')}`);
|
|
189
189
|
console.log(` ${formatMcp('herramienta')} ${chalk.gray('Invoca herramientas MCP')}`);
|
|
190
190
|
console.log('');
|
package/src/ui/repl.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import readline from 'readline';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import { AgentClient } from '../client/agent-client';
|
|
@@ -121,7 +121,7 @@ export class HelixRepl {
|
|
|
121
121
|
this.waitingLogged = false;
|
|
122
122
|
await this._syncSettings();
|
|
123
123
|
await this.autocompleter.refreshSuggestions();
|
|
124
|
-
process.stdout.write(`\r\x1b[K${chalk.green('
|
|
124
|
+
process.stdout.write(`\r\x1b[K${chalk.green('●')} ${chalk.greenBright.bold('Conectado al agente HELIX')} \n`);
|
|
125
125
|
this._promptUser();
|
|
126
126
|
});
|
|
127
127
|
|
|
@@ -131,39 +131,39 @@ export class HelixRepl {
|
|
|
131
131
|
}
|
|
132
132
|
if (!this.waitingLogged) {
|
|
133
133
|
this.waitingLogged = true;
|
|
134
|
-
console.log(`\n${RED('
|
|
135
|
-
console.log(`${GRAY(' (Si no responde tras 3 reintentos, el CLI lo
|
|
134
|
+
console.log(`\n${RED('●')} ${chalk.yellowBright('Esperando al servicio del agente HELIX en ws://127.0.0.1:8765...')}`);
|
|
135
|
+
console.log(`${GRAY(' (Si no responde tras 3 reintentos, el CLI lo iniciará automáticamente en segundo plano)')}\n`);
|
|
136
136
|
}
|
|
137
137
|
this._promptUser();
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
this.client.on('auto_spawning_agent', () => {
|
|
141
|
-
process.stdout.write(`\n${CYAN_BOLD('
|
|
142
|
-
process.stdout.write(`${GRAY(' Por favor espere mientras termina de inicializarse (no se
|
|
141
|
+
process.stdout.write(`\n${CYAN_BOLD('⚙️')} ${chalk.hex('#FF9F1C').bold('[AUTO-START]:')} Iniciando el servicio del agente HELIX en segundo plano...\n`);
|
|
142
|
+
process.stdout.write(`${GRAY(' Por favor espere mientras termina de inicializarse (no se realizarán reintentos hasta que esté listo).')}\n`);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
this.client.on('agent_starting_progress', (data: { elapsedSec: number }) => {
|
|
146
|
-
process.stdout.write(`\r ${chalk.hex('#FF9F1C')('
|
|
146
|
+
process.stdout.write(`\r ${chalk.hex('#FF9F1C')('⏳')} ${chalk.gray(`Inicializando subsistemas de HELIX en segundo plano... (${data.elapsedSec}s)`)}`);
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
this.client.on('agent_ready', () => {
|
|
150
|
-
process.stdout.write(`\r\x1b[K ${chalk.green('
|
|
150
|
+
process.stdout.write(`\r\x1b[K ${chalk.green('✔')} ${chalk.greenBright('Servicio de HELIX listo. Conectando...')}\n\n`);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
this.client.on('agent_start_failed', (data: { error?: string }) => {
|
|
154
|
-
process.stdout.write(`\r\x1b[K\n ${chalk.red('
|
|
154
|
+
process.stdout.write(`\r\x1b[K\n ${chalk.red('✖')} ${chalk.redBright('No se pudo iniciar el servicio automáticamente:')} ${chalk.gray(data?.error || 'Tiempo agotado')}\n`);
|
|
155
155
|
this._promptUser();
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
// Voice Capture indicator
|
|
159
159
|
this.client.on('voice_capture_started', () => {
|
|
160
160
|
this.isCapturingVoice = true;
|
|
161
|
-
process.stdout.write(`\n${chalk.bgRed.white.bold('
|
|
161
|
+
process.stdout.write(`\n${chalk.bgRed.white.bold(' 🎙️ [VOZ DETECTADA - HEY HELIX]: Capturando audio... ')}\n`);
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
this.client.on('voice_capture_stopped', () => {
|
|
165
165
|
this.isCapturingVoice = false;
|
|
166
|
-
process.stdout.write(`\n${chalk.bgCyan.black.bold('
|
|
166
|
+
process.stdout.write(`\n${chalk.bgCyan.black.bold(' 🔊 [AUDIO RECIBIDO]: Procesando voz... ')}\n`);
|
|
167
167
|
this._promptUser();
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -171,7 +171,7 @@ export class HelixRepl {
|
|
|
171
171
|
this.client.on('react_step', (step: { iteration?: number; role?: string }) => {
|
|
172
172
|
const iter = step?.iteration ?? 1;
|
|
173
173
|
const role = step?.role ? chalk.gray(` (${step.role})`) : '';
|
|
174
|
-
process.stdout.write(`\r ${chalk.hex('#FF9F1C')('
|
|
174
|
+
process.stdout.write(`\r ${chalk.hex('#FF9F1C')('◆')} ${chalk.gray(`Paso ${iter}${role} — Razonando...`)}`);
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
// Agent assistant message
|
|
@@ -190,13 +190,13 @@ export class HelixRepl {
|
|
|
190
190
|
|
|
191
191
|
// Branded header
|
|
192
192
|
console.log('');
|
|
193
|
-
console.log(` ${chalk.hex('#FF8C00').bold('
|
|
193
|
+
console.log(` ${chalk.hex('#FF8C00').bold('⬡ HELIX')}${modelBadge}`);
|
|
194
194
|
|
|
195
195
|
// Content with subtle left border and clean Markdown formatting
|
|
196
196
|
const formatted = formatTerminalMarkdown(content, this.plain);
|
|
197
197
|
const contentLines = formatted.trim().split('\n');
|
|
198
198
|
for (const line of contentLines) {
|
|
199
|
-
console.log(` ${chalk.gray('
|
|
199
|
+
console.log(` ${chalk.gray('│')} ${line}`);
|
|
200
200
|
}
|
|
201
201
|
console.log('');
|
|
202
202
|
|
|
@@ -241,13 +241,13 @@ export class HelixRepl {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
private async _handleConfirmationDialog(req: ConfirmationRequest): Promise<void> {
|
|
244
|
-
console.log(`\n${YELLOW_BOLD('
|
|
245
|
-
console.log(`
|
|
244
|
+
console.log(`\n${YELLOW_BOLD('⚠️ CONFIRMACIÓN DE ACCIÓN REQUERIDA')}`);
|
|
245
|
+
console.log(` Acción: ${chalk.white.bold(req.action || req.tool || 'Acción del sistema')}`);
|
|
246
246
|
if (req.description) {
|
|
247
|
-
console.log(`
|
|
247
|
+
console.log(` Descripción: ${DIM(req.description)}`);
|
|
248
248
|
}
|
|
249
249
|
if (req.arguments && Object.keys(req.arguments).length > 0) {
|
|
250
|
-
console.log(`
|
|
250
|
+
console.log(` Parámetros: ${GRAY(JSON.stringify(req.arguments))}`);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
this.rl?.pause();
|
|
@@ -255,17 +255,17 @@ export class HelixRepl {
|
|
|
255
255
|
const answer = await prompts({
|
|
256
256
|
type: 'confirm',
|
|
257
257
|
name: 'confirmed',
|
|
258
|
-
message: '
|
|
258
|
+
message: '¿Permitir al agente ejecutar esta acción?',
|
|
259
259
|
initial: true,
|
|
260
260
|
});
|
|
261
261
|
|
|
262
262
|
const reqId = req.request_id || req.id || '';
|
|
263
263
|
if (answer && answer.confirmed) {
|
|
264
264
|
this.client.confirmAction(reqId);
|
|
265
|
-
console.log(GREEN('
|
|
265
|
+
console.log(GREEN(' ✔ Acción confirmada.\n'));
|
|
266
266
|
} else {
|
|
267
267
|
this.client.rejectAction(reqId);
|
|
268
|
-
console.log(RED('
|
|
268
|
+
console.log(RED(' ✖ Acción rechazada.\n'));
|
|
269
269
|
}
|
|
270
270
|
} finally {
|
|
271
271
|
if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') {
|
|
@@ -297,7 +297,7 @@ export class HelixRepl {
|
|
|
297
297
|
});
|
|
298
298
|
|
|
299
299
|
rl.on('close', () => {
|
|
300
|
-
console.log(DIM('\nCerrando
|
|
300
|
+
console.log(DIM('\nCerrando sesión de HELIX CLI...'));
|
|
301
301
|
this.client.close();
|
|
302
302
|
process.exit(0);
|
|
303
303
|
});
|
|
@@ -311,7 +311,7 @@ export class HelixRepl {
|
|
|
311
311
|
this.activeTaskId = null;
|
|
312
312
|
this._promptUser();
|
|
313
313
|
} else {
|
|
314
|
-
console.log(DIM('\n
|
|
314
|
+
console.log(DIM('\n¡Hasta pronto!'));
|
|
315
315
|
this.client.close();
|
|
316
316
|
process.exit(0);
|
|
317
317
|
}
|
|
@@ -322,7 +322,7 @@ export class HelixRepl {
|
|
|
322
322
|
|
|
323
323
|
private _promptUser(): void {
|
|
324
324
|
if (!this.rl) return;
|
|
325
|
-
const promptPrefix = ` ${chalk.hex('#FF8C00').bold('helix')} ${chalk.gray('
|
|
325
|
+
const promptPrefix = ` ${chalk.hex('#FF8C00').bold('helix')} ${chalk.gray('❯')} `;
|
|
326
326
|
this.rl.setPrompt(promptPrefix);
|
|
327
327
|
this.rl.prompt();
|
|
328
328
|
}
|
|
@@ -334,7 +334,7 @@ export class HelixRepl {
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
if (this.client.isStarting) {
|
|
337
|
-
console.log(`\n ${chalk.yellow('
|
|
337
|
+
console.log(`\n ${chalk.yellow('⚠️')} ${chalk.yellowBright('El servicio de HELIX se está iniciando en segundo plano. Espera a que termine antes de enviar comandos o reintentar.')}\n`);
|
|
338
338
|
this._promptUser();
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
@@ -474,7 +474,7 @@ export class HelixRepl {
|
|
|
474
474
|
this.client.emergencyStop();
|
|
475
475
|
this.isProcessingPrompt = false;
|
|
476
476
|
this.activeTaskId = null;
|
|
477
|
-
console.log(GREEN('
|
|
477
|
+
console.log(GREEN('✔ Todas las tareas han sido detenidas.\n'));
|
|
478
478
|
break;
|
|
479
479
|
|
|
480
480
|
case '/exit':
|
|
@@ -494,7 +494,7 @@ export class HelixRepl {
|
|
|
494
494
|
|
|
495
495
|
// --- Direct chat message / @skill / #mcp ---
|
|
496
496
|
if (!this.client.connected) {
|
|
497
|
-
console.log(YELLOW('
|
|
497
|
+
console.log(YELLOW('⚠ El agente no está conectado actualmente. Intentando enviar de todos modos...'));
|
|
498
498
|
}
|
|
499
499
|
|
|
500
500
|
// Highlight skills in strong orange (#FF8C00) and mcps in cyan
|
|
@@ -506,8 +506,8 @@ export class HelixRepl {
|
|
|
506
506
|
this.isProcessingPrompt = true;
|
|
507
507
|
this.activeTasksCount++;
|
|
508
508
|
|
|
509
|
-
process.stdout.write(` ${chalk.gray('
|
|
510
|
-
process.stdout.write(` ${chalk.hex('#FF9F1C')('
|
|
509
|
+
process.stdout.write(` ${chalk.gray('→')} ${formattedEcho}\n`);
|
|
510
|
+
process.stdout.write(` ${chalk.hex('#FF9F1C')('◆')} ${chalk.gray('Procesando...')}`);
|
|
511
511
|
|
|
512
512
|
const sent = this.client.sendUserText(
|
|
513
513
|
line,
|
|
@@ -517,7 +517,7 @@ export class HelixRepl {
|
|
|
517
517
|
|
|
518
518
|
if (!sent) {
|
|
519
519
|
process.stdout.write('\r\x1b[K');
|
|
520
|
-
console.log(RED('
|
|
520
|
+
console.log(RED('✖ Error: No se pudo enviar el mensaje (WebSocket desconectado).'));
|
|
521
521
|
this.isProcessingPrompt = false;
|
|
522
522
|
this.activeTasksCount = Math.max(0, this.activeTasksCount - 1);
|
|
523
523
|
this._promptUser();
|
|
@@ -527,7 +527,7 @@ export class HelixRepl {
|
|
|
527
527
|
private async _handleListTasks(): Promise<void> {
|
|
528
528
|
try {
|
|
529
529
|
const tasks = await this.client.getTasks();
|
|
530
|
-
console.log(`\n${BOLD('
|
|
530
|
+
console.log(`\n${BOLD('📋 Tareas Registradas en HELIX:')}\n`);
|
|
531
531
|
if (!tasks || tasks.length === 0) {
|
|
532
532
|
console.log(GRAY(' No hay tareas recientes registradas.\n'));
|
|
533
533
|
return;
|
|
@@ -535,10 +535,10 @@ export class HelixRepl {
|
|
|
535
535
|
|
|
536
536
|
for (const t of tasks.slice(-10)) {
|
|
537
537
|
let statusBadge = chalk.gray(t.status);
|
|
538
|
-
if (t.status === 'COMPLETED') statusBadge = chalk.green('
|
|
539
|
-
if (t.status === 'RUNNING') statusBadge = chalk.yellow('
|
|
540
|
-
if (t.status === 'FAILED') statusBadge = chalk.red('
|
|
541
|
-
if (t.status === 'CANCELLED') statusBadge = chalk.gray('
|
|
538
|
+
if (t.status === 'COMPLETED') statusBadge = chalk.green('✔ Completada');
|
|
539
|
+
if (t.status === 'RUNNING') statusBadge = chalk.yellow('⏳ En ejecución');
|
|
540
|
+
if (t.status === 'FAILED') statusBadge = chalk.red('✖ Fallida');
|
|
541
|
+
if (t.status === 'CANCELLED') statusBadge = chalk.gray('○ Cancelada');
|
|
542
542
|
|
|
543
543
|
console.log(` ${statusBadge} ${DIM(t.task_id)}`);
|
|
544
544
|
if (t.prompt) console.log(` ${chalk.white(t.prompt)}`);
|
|
@@ -552,14 +552,14 @@ export class HelixRepl {
|
|
|
552
552
|
private async _handleListModels(): Promise<void> {
|
|
553
553
|
try {
|
|
554
554
|
const models = await this.client.getModels();
|
|
555
|
-
console.log(`\n${BOLD('
|
|
555
|
+
console.log(`\n${BOLD('🧠 Modelos Disponibles en Proveedores Configurados:')}\n`);
|
|
556
556
|
if (!models || models.length === 0) {
|
|
557
557
|
console.log(GRAY(' No hay modelos disponibles. Configura tus API Keys con /config-apikey.\n'));
|
|
558
558
|
return;
|
|
559
559
|
}
|
|
560
560
|
|
|
561
561
|
for (const m of models) {
|
|
562
|
-
console.log(` ${CYAN('
|
|
562
|
+
console.log(` ${CYAN('•')} ${chalk.bold(m.id)} ${DIM(`[${m.provider}]`)}`);
|
|
563
563
|
}
|
|
564
564
|
console.log('');
|
|
565
565
|
} catch (err) {
|
|
@@ -569,11 +569,11 @@ export class HelixRepl {
|
|
|
569
569
|
|
|
570
570
|
private async _handleStatus(): Promise<void> {
|
|
571
571
|
console.log('');
|
|
572
|
-
console.log(` ${chalk.hex('#FF8C00').bold('
|
|
573
|
-
console.log(` ${chalk.gray('
|
|
574
|
-
console.log(` ${chalk.gray('Agente WS')} ${this.client.connected ? chalk.green('
|
|
575
|
-
console.log(` ${chalk.gray('
|
|
576
|
-
console.log(` ${chalk.gray('
|
|
572
|
+
console.log(` ${chalk.hex('#FF8C00').bold('⬡ Estado del Sistema')}`);
|
|
573
|
+
console.log(` ${chalk.gray('─'.repeat(40))}`);
|
|
574
|
+
console.log(` ${chalk.gray('Agente WS')} ${this.client.connected ? chalk.green('● Conectado') : chalk.red('● Desconectado')} ${chalk.gray(this.client.url)}`);
|
|
575
|
+
console.log(` ${chalk.gray('Micrófono')} ${this.voiceEnabled ? chalk.green('● Activo') + chalk.gray(' (hey helix)') : chalk.red('● Inactivo')}`);
|
|
576
|
+
console.log(` ${chalk.gray('Conversación')} ${chalk.gray(this.conversationId)} ${chalk.gray(`(${this.conversationHistory.length} msgs)`)}`);
|
|
577
577
|
console.log(` ${chalk.gray('Skills')} ${chalk.hex('#FF8C00').bold(this.autocompleter.getSkills().length.toString())} registradas`);
|
|
578
578
|
console.log(` ${chalk.gray('MCP Tools')} ${chalk.cyan.bold(this.autocompleter.getMcpTools().length.toString())} disponibles`);
|
|
579
579
|
console.log('');
|
package/tsconfig.json
CHANGED