helix-assistant-cli 0.2.14 → 0.6.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 +25 -0
- package/dist/commands/browser.js +3 -2
- package/dist/commands/memory.d.ts +6 -0
- package/dist/commands/memory.js +129 -0
- package/dist/commands/model.d.ts +24 -0
- package/dist/commands/model.js +220 -0
- package/dist/commands/subagents.d.ts +15 -0
- package/dist/commands/subagents.js +123 -0
- package/dist/config/mcp-defaults.js +13 -4
- package/dist/index.js +5 -1
- package/dist/ui/autocomplete.js +23 -8
- package/dist/ui/browser-ascii.d.ts +2 -0
- package/dist/ui/browser-ascii.js +67 -0
- package/dist/ui/repl.d.ts +1 -0
- package/dist/ui/repl.js +89 -42
- package/package.json +4 -2
- package/src/commands/browser.ts +3 -2
- package/src/commands/memory.ts +167 -0
- package/src/commands/model.ts +237 -0
- package/src/commands/subagents.ts +150 -0
- package/src/config/mcp-defaults.ts +13 -4
- package/src/global.d.ts +23 -0
- package/src/index.ts +2 -1
- package/src/ui/autocomplete.ts +26 -9
- package/src/ui/browser-ascii.ts +82 -0
- package/src/ui/repl.ts +101 -43
- package/tests/cli.test.ts +41 -0
- package/tsconfig.json +4 -4
package/dist/ui/autocomplete.js
CHANGED
|
@@ -12,16 +12,19 @@ exports.SLASH_COMMANDS = [
|
|
|
12
12
|
{ command: '/skill', description: 'Listar o inspeccionar skills registradas', usage: '/skill [nombre]' },
|
|
13
13
|
{ command: '/mcp', description: 'Listar servidores MCP y sus herramientas', usage: '/mcp [defaults]' },
|
|
14
14
|
{ command: '/create-mcp', description: 'Registrar y configurar un nuevo servidor MCP' },
|
|
15
|
-
{ command: '/browser', description: 'Ver estado
|
|
15
|
+
{ command: '/browser', description: 'Ver estado, abrir URLs o alternar la vista ASCII', usage: '/browser [open <url>|live [on|off]]' },
|
|
16
|
+
{ command: '/subagents', description: 'Ver el panel ASCII o chatear con un subagente', usage: '/subagents [list|chat <id> <mensaje>]' },
|
|
16
17
|
{ command: '/config-apikey', description: 'Configurador interactivo de API Keys (OpenAI, Anthropic, Gemini, etc.)' },
|
|
17
18
|
{ command: '/show-apikey', description: 'Ver estado y validez de las API Keys configuradas' },
|
|
18
|
-
{ command: '/microphone', description: 'Ver o alternar estado del
|
|
19
|
+
{ command: '/microphone', description: 'Ver o alternar estado del micrófono', usage: '/microphone [enable|disable]' },
|
|
19
20
|
{ command: '/tasks', description: 'Ver tareas activas y recientes del agente' },
|
|
21
|
+
{ command: '/model', description: 'Ver o cambiar el modelo activo (free/local/cloud)', usage: '/model [list|set <id>|effort <low|medium|high>]' },
|
|
20
22
|
{ command: '/models', description: 'Listar modelos disponibles de proveedores configurados' },
|
|
23
|
+
{ command: '/memory', description: 'Ver estadísticas del harness de aprendizaje adaptativo', usage: '/memory [stats|rules|reset]' },
|
|
21
24
|
{ command: '/status', description: 'Mostrar resumen del estado del sistema' },
|
|
22
25
|
{ command: '/providers', description: 'Ver proveedores configurados y salud de sus claves' },
|
|
23
26
|
{ command: '/capabilities', description: 'Ver capacidades activas: sandbox, subagentes, voz y browser' },
|
|
24
|
-
{ command: '/settings', description: 'Ver
|
|
27
|
+
{ command: '/settings', description: 'Ver configuración efectiva sin exponer secretos' },
|
|
25
28
|
{ command: '/clear', description: 'Limpiar pantalla y restaurar el banner de HELIX' },
|
|
26
29
|
{ command: '/stop', description: 'Parada de emergencia de todas las tareas activas' },
|
|
27
30
|
{ command: '/help', description: 'Mostrar ayuda de comandos y atajos' },
|
|
@@ -107,7 +110,19 @@ class Autocompleter {
|
|
|
107
110
|
const hits = options.filter((o) => o.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
108
111
|
return [hits.length ? hits : options, line];
|
|
109
112
|
}
|
|
110
|
-
// 3.
|
|
113
|
+
// 3. Model sub-arguments
|
|
114
|
+
if (trimmed.startsWith('/model ')) {
|
|
115
|
+
const options = ['/model list', '/model set ', '/model effort low', '/model effort medium', '/model effort high'];
|
|
116
|
+
const hits = options.filter((o) => o.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
117
|
+
return [hits.length ? hits : options, line];
|
|
118
|
+
}
|
|
119
|
+
// 3b. Memory sub-arguments
|
|
120
|
+
if (trimmed.startsWith('/memory ')) {
|
|
121
|
+
const options = ['/memory stats', '/memory rules', '/memory reset'];
|
|
122
|
+
const hits = options.filter((o) => o.toLowerCase().startsWith(trimmed.toLowerCase()));
|
|
123
|
+
return [hits.length ? hits : options, line];
|
|
124
|
+
}
|
|
125
|
+
// 4. Browser sub-arguments
|
|
111
126
|
if (trimmed.startsWith('/browser ')) {
|
|
112
127
|
const options = ['/browser open https://'];
|
|
113
128
|
return [options, line];
|
|
@@ -144,15 +159,15 @@ class Autocompleter {
|
|
|
144
159
|
*/
|
|
145
160
|
renderHelp() {
|
|
146
161
|
console.log('');
|
|
147
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
148
|
-
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))}`);
|
|
149
164
|
for (const cmd of exports.SLASH_COMMANDS) {
|
|
150
165
|
const usage = cmd.usage ? ` ${chalk_1.default.gray(cmd.usage)}` : '';
|
|
151
166
|
console.log(` ${chalk_1.default.magenta(cmd.command.padEnd(16))} ${chalk_1.default.gray(cmd.description)}${usage}`);
|
|
152
167
|
}
|
|
153
168
|
console.log('');
|
|
154
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
155
|
-
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))}`);
|
|
156
171
|
console.log(` ${(0, colors_1.formatSkill)('nombre')} ${chalk_1.default.gray('Invoca una skill registrada')}`);
|
|
157
172
|
console.log(` ${(0, colors_1.formatMcp)('herramienta')} ${chalk_1.default.gray('Invoca herramientas MCP')}`);
|
|
158
173
|
console.log('');
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.grayscaleToAscii = grayscaleToAscii;
|
|
7
|
+
exports.renderJpegAsAscii = renderJpegAsAscii;
|
|
8
|
+
const jpeg_js_1 = __importDefault(require("jpeg-js"));
|
|
9
|
+
const ASCII_RAMP = ' .:-=+*#%@';
|
|
10
|
+
const MAX_FRAME_WIDTH = 76;
|
|
11
|
+
const MAX_FRAME_HEIGHT = 34;
|
|
12
|
+
const MAX_JPEG_BYTES = 560_000;
|
|
13
|
+
function grayscaleToAscii(pixels, width = MAX_FRAME_WIDTH) {
|
|
14
|
+
if (!pixels.length || !pixels[0]?.length) {
|
|
15
|
+
throw new Error('Browser frame has no pixels to render.');
|
|
16
|
+
}
|
|
17
|
+
const boundedWidth = Math.max(1, Math.min(MAX_FRAME_WIDTH, Math.floor(width)));
|
|
18
|
+
const sourceHeight = pixels.length;
|
|
19
|
+
const sourceWidth = pixels[0].length;
|
|
20
|
+
const outputHeight = Math.max(1, Math.min(MAX_FRAME_HEIGHT, Math.round((sourceHeight / sourceWidth) * boundedWidth * 0.5)));
|
|
21
|
+
const lines = [];
|
|
22
|
+
for (let y = 0; y < outputHeight; y += 1) {
|
|
23
|
+
const sourceY = Math.min(sourceHeight - 1, Math.floor((y / outputHeight) * sourceHeight));
|
|
24
|
+
let line = '';
|
|
25
|
+
for (let x = 0; x < boundedWidth; x += 1) {
|
|
26
|
+
const sourceX = Math.min(sourceWidth - 1, Math.floor((x / boundedWidth) * sourceWidth));
|
|
27
|
+
const value = Math.max(0, Math.min(255, pixels[sourceY][sourceX]));
|
|
28
|
+
const index = Math.round(((255 - value) / 255) * (ASCII_RAMP.length - 1));
|
|
29
|
+
line += ASCII_RAMP[index];
|
|
30
|
+
}
|
|
31
|
+
lines.push(line);
|
|
32
|
+
}
|
|
33
|
+
return lines.join('\n');
|
|
34
|
+
}
|
|
35
|
+
function renderJpegAsAscii(base64, width = MAX_FRAME_WIDTH) {
|
|
36
|
+
if (typeof base64 !== 'string'
|
|
37
|
+
|| !/^[A-Za-z0-9+/]+={0,2}$/.test(base64)
|
|
38
|
+
|| base64.length > Math.ceil(MAX_JPEG_BYTES * 4 / 3)) {
|
|
39
|
+
throw new Error('Browser frame is not a valid, bounded Base64 JPEG.');
|
|
40
|
+
}
|
|
41
|
+
const bytes = Buffer.from(base64, 'base64');
|
|
42
|
+
if (bytes.length === 0 || bytes.length > MAX_JPEG_BYTES) {
|
|
43
|
+
throw new Error('Browser frame exceeds the supported JPEG size.');
|
|
44
|
+
}
|
|
45
|
+
const image = jpeg_js_1.default.decode(bytes, {
|
|
46
|
+
useTArray: true,
|
|
47
|
+
formatAsRGBA: true,
|
|
48
|
+
maxResolutionInMP: 4,
|
|
49
|
+
maxMemoryUsageInMB: 128,
|
|
50
|
+
});
|
|
51
|
+
const pixels = [];
|
|
52
|
+
const outputWidth = Math.min(MAX_FRAME_WIDTH, image.width);
|
|
53
|
+
const outputHeight = Math.max(1, Math.min(MAX_FRAME_HEIGHT, Math.round((image.height / image.width) * outputWidth * 0.5)));
|
|
54
|
+
for (let y = 0; y < outputHeight; y += 1) {
|
|
55
|
+
const row = [];
|
|
56
|
+
const sourceY = Math.min(image.height - 1, Math.floor((y / outputHeight) * image.height));
|
|
57
|
+
for (let x = 0; x < outputWidth; x += 1) {
|
|
58
|
+
const sourceX = Math.min(image.width - 1, Math.floor((x / outputWidth) * image.width));
|
|
59
|
+
const offset = (sourceY * image.width + sourceX) * 4;
|
|
60
|
+
row.push(image.data[offset] * 0.299
|
|
61
|
+
+ image.data[offset + 1] * 0.587
|
|
62
|
+
+ image.data[offset + 2] * 0.114);
|
|
63
|
+
}
|
|
64
|
+
pixels.push(row);
|
|
65
|
+
}
|
|
66
|
+
return grayscaleToAscii(pixels, Math.min(width, outputWidth));
|
|
67
|
+
}
|
package/dist/ui/repl.d.ts
CHANGED
package/dist/ui/repl.js
CHANGED
|
@@ -16,8 +16,12 @@ const skills_1 = require("../commands/skills");
|
|
|
16
16
|
const mcp_1 = require("../commands/mcp");
|
|
17
17
|
const mic_1 = require("../commands/mic");
|
|
18
18
|
const browser_1 = require("../commands/browser");
|
|
19
|
+
const subagents_1 = require("../commands/subagents");
|
|
19
20
|
const markdown_1 = require("./markdown");
|
|
20
21
|
const diagnostics_1 = require("../commands/diagnostics");
|
|
22
|
+
const browser_ascii_1 = require("./browser-ascii");
|
|
23
|
+
const model_1 = require("../commands/model");
|
|
24
|
+
const memory_1 = require("../commands/memory");
|
|
21
25
|
class HelixRepl {
|
|
22
26
|
options;
|
|
23
27
|
rl = null;
|
|
@@ -32,6 +36,7 @@ class HelixRepl {
|
|
|
32
36
|
activeTasksCount = 0;
|
|
33
37
|
isProcessingPrompt = false;
|
|
34
38
|
plain = false;
|
|
39
|
+
browserLiveViewEnabled = false;
|
|
35
40
|
constructor(options) {
|
|
36
41
|
this.options = options;
|
|
37
42
|
this.conversationId = `cli_conv_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
@@ -95,7 +100,7 @@ class HelixRepl {
|
|
|
95
100
|
this.waitingLogged = false;
|
|
96
101
|
await this._syncSettings();
|
|
97
102
|
await this.autocompleter.refreshSuggestions();
|
|
98
|
-
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`);
|
|
99
104
|
this._promptUser();
|
|
100
105
|
});
|
|
101
106
|
this.client.on('disconnected', () => {
|
|
@@ -104,40 +109,40 @@ class HelixRepl {
|
|
|
104
109
|
}
|
|
105
110
|
if (!this.waitingLogged) {
|
|
106
111
|
this.waitingLogged = true;
|
|
107
|
-
console.log(`\n${(0, colors_1.RED)('
|
|
108
|
-
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`);
|
|
109
114
|
}
|
|
110
115
|
this._promptUser();
|
|
111
116
|
});
|
|
112
117
|
this.client.on('auto_spawning_agent', () => {
|
|
113
|
-
process.stdout.write(`\n${(0, colors_1.CYAN_BOLD)('
|
|
114
|
-
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`);
|
|
115
120
|
});
|
|
116
121
|
this.client.on('agent_starting_progress', (data) => {
|
|
117
|
-
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)`)}`);
|
|
118
123
|
});
|
|
119
124
|
this.client.on('agent_ready', () => {
|
|
120
|
-
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`);
|
|
121
126
|
});
|
|
122
127
|
this.client.on('agent_start_failed', (data) => {
|
|
123
|
-
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`);
|
|
124
129
|
this._promptUser();
|
|
125
130
|
});
|
|
126
131
|
// Voice Capture indicator
|
|
127
132
|
this.client.on('voice_capture_started', () => {
|
|
128
133
|
this.isCapturingVoice = true;
|
|
129
|
-
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`);
|
|
130
135
|
});
|
|
131
136
|
this.client.on('voice_capture_stopped', () => {
|
|
132
137
|
this.isCapturingVoice = false;
|
|
133
|
-
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`);
|
|
134
139
|
this._promptUser();
|
|
135
140
|
});
|
|
136
141
|
// ReAct Step Progress
|
|
137
142
|
this.client.on('react_step', (step) => {
|
|
138
143
|
const iter = step?.iteration ?? 1;
|
|
139
144
|
const role = step?.role ? chalk_1.default.gray(` (${step.role})`) : '';
|
|
140
|
-
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...`)}`);
|
|
141
146
|
});
|
|
142
147
|
// Agent assistant message
|
|
143
148
|
this.client.on('agent_message', (payload) => {
|
|
@@ -153,12 +158,12 @@ class HelixRepl {
|
|
|
153
158
|
process.stdout.write('\r\x1b[K');
|
|
154
159
|
// Branded header
|
|
155
160
|
console.log('');
|
|
156
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
161
|
+
console.log(` ${chalk_1.default.hex('#FF8C00').bold('⬡ HELIX')}${modelBadge}`);
|
|
157
162
|
// Content with subtle left border and clean Markdown formatting
|
|
158
163
|
const formatted = (0, markdown_1.formatTerminalMarkdown)(content, this.plain);
|
|
159
164
|
const contentLines = formatted.trim().split('\n');
|
|
160
165
|
for (const line of contentLines) {
|
|
161
|
-
console.log(` ${chalk_1.default.gray('
|
|
166
|
+
console.log(` ${chalk_1.default.gray('│')} ${line}`);
|
|
162
167
|
}
|
|
163
168
|
console.log('');
|
|
164
169
|
this.conversationHistory.push({ role: 'assistant', content });
|
|
@@ -174,32 +179,49 @@ class HelixRepl {
|
|
|
174
179
|
this.activeTaskId = task.task_id || null;
|
|
175
180
|
}
|
|
176
181
|
});
|
|
182
|
+
this.client.on('browser_frame', (payload) => {
|
|
183
|
+
if (!this.browserLiveViewEnabled
|
|
184
|
+
|| !payload?.conversation_id?.startsWith('cli_')
|
|
185
|
+
|| payload.mime_type !== 'image/jpeg'
|
|
186
|
+
|| typeof payload.image_base64 !== 'string') {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
process.stdout.write('\r\x1b[K');
|
|
191
|
+
console.log(`\n${(0, colors_1.CYAN_BOLD)(' HELIX LIVE BROWSER')}`);
|
|
192
|
+
console.log((0, browser_ascii_1.renderJpegAsAscii)(payload.image_base64));
|
|
193
|
+
this._promptUser();
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
console.log((0, colors_1.RED)(` No se pudo representar el cuadro del navegador: ${error.message}`));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
177
199
|
}
|
|
178
200
|
async _handleConfirmationDialog(req) {
|
|
179
|
-
console.log(`\n${(0, colors_1.YELLOW_BOLD)('
|
|
180
|
-
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')}`);
|
|
181
203
|
if (req.description) {
|
|
182
|
-
console.log(`
|
|
204
|
+
console.log(` Descripción: ${(0, colors_1.DIM)(req.description)}`);
|
|
183
205
|
}
|
|
184
206
|
if (req.arguments && Object.keys(req.arguments).length > 0) {
|
|
185
|
-
console.log(`
|
|
207
|
+
console.log(` Parámetros: ${(0, colors_1.GRAY)(JSON.stringify(req.arguments))}`);
|
|
186
208
|
}
|
|
187
209
|
this.rl?.pause();
|
|
188
210
|
try {
|
|
189
211
|
const answer = await (0, prompts_1.default)({
|
|
190
212
|
type: 'confirm',
|
|
191
213
|
name: 'confirmed',
|
|
192
|
-
message: '
|
|
214
|
+
message: '¿Permitir al agente ejecutar esta acción?',
|
|
193
215
|
initial: true,
|
|
194
216
|
});
|
|
195
217
|
const reqId = req.request_id || req.id || '';
|
|
196
218
|
if (answer && answer.confirmed) {
|
|
197
219
|
this.client.confirmAction(reqId);
|
|
198
|
-
console.log((0, colors_1.GREEN)('
|
|
220
|
+
console.log((0, colors_1.GREEN)(' ✔ Acción confirmada.\n'));
|
|
199
221
|
}
|
|
200
222
|
else {
|
|
201
223
|
this.client.rejectAction(reqId);
|
|
202
|
-
console.log((0, colors_1.RED)('
|
|
224
|
+
console.log((0, colors_1.RED)(' ✖ Acción rechazada.\n'));
|
|
203
225
|
}
|
|
204
226
|
}
|
|
205
227
|
finally {
|
|
@@ -229,7 +251,7 @@ class HelixRepl {
|
|
|
229
251
|
await this._handleInputLine(line.trim());
|
|
230
252
|
});
|
|
231
253
|
rl.on('close', () => {
|
|
232
|
-
console.log((0, colors_1.DIM)('\nCerrando
|
|
254
|
+
console.log((0, colors_1.DIM)('\nCerrando sesión de HELIX CLI...'));
|
|
233
255
|
this.client.close();
|
|
234
256
|
process.exit(0);
|
|
235
257
|
});
|
|
@@ -243,7 +265,7 @@ class HelixRepl {
|
|
|
243
265
|
this._promptUser();
|
|
244
266
|
}
|
|
245
267
|
else {
|
|
246
|
-
console.log((0, colors_1.DIM)('\n
|
|
268
|
+
console.log((0, colors_1.DIM)('\n¡Hasta pronto!'));
|
|
247
269
|
this.client.close();
|
|
248
270
|
process.exit(0);
|
|
249
271
|
}
|
|
@@ -253,7 +275,7 @@ class HelixRepl {
|
|
|
253
275
|
_promptUser() {
|
|
254
276
|
if (!this.rl)
|
|
255
277
|
return;
|
|
256
|
-
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('â¯')} `;
|
|
257
279
|
this.rl.setPrompt(promptPrefix);
|
|
258
280
|
this.rl.prompt();
|
|
259
281
|
}
|
|
@@ -263,7 +285,7 @@ class HelixRepl {
|
|
|
263
285
|
return;
|
|
264
286
|
}
|
|
265
287
|
if (this.client.isStarting) {
|
|
266
|
-
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`);
|
|
267
289
|
this._promptUser();
|
|
268
290
|
return;
|
|
269
291
|
}
|
|
@@ -343,15 +365,40 @@ class HelixRepl {
|
|
|
343
365
|
this.voiceEnabled = newState;
|
|
344
366
|
break;
|
|
345
367
|
}
|
|
346
|
-
case '/browser':
|
|
368
|
+
case '/browser': {
|
|
369
|
+
const browserArgs = args.trim().split(/\s+/);
|
|
370
|
+
if (browserArgs[0]?.toLowerCase() === 'live') {
|
|
371
|
+
const requestedState = browserArgs[1]?.toLowerCase();
|
|
372
|
+
if (requestedState && !['on', 'off'].includes(requestedState)) {
|
|
373
|
+
console.log((0, colors_1.YELLOW)(' Uso: /browser live [on|off]\n'));
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
this.browserLiveViewEnabled = requestedState
|
|
377
|
+
? requestedState === 'on'
|
|
378
|
+
: !this.browserLiveViewEnabled;
|
|
379
|
+
console.log(this.browserLiveViewEnabled
|
|
380
|
+
? (0, colors_1.GREEN)(' Vista ASCII del navegador activada.\n')
|
|
381
|
+
: (0, colors_1.YELLOW)(' Vista ASCII del navegador desactivada.\n'));
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
347
384
|
await (0, browser_1.handleBrowserCommand)(this.client, args);
|
|
348
385
|
break;
|
|
386
|
+
}
|
|
387
|
+
case '/subagents':
|
|
388
|
+
await (0, subagents_1.handleSubagentsCommand)(this.client, args);
|
|
389
|
+
break;
|
|
349
390
|
case '/tasks':
|
|
350
391
|
await this._handleListTasks();
|
|
351
392
|
break;
|
|
393
|
+
case '/model':
|
|
394
|
+
await (0, model_1.handleModelCommand)(this.client, args);
|
|
395
|
+
break;
|
|
352
396
|
case '/models':
|
|
353
397
|
await this._handleListModels();
|
|
354
398
|
break;
|
|
399
|
+
case '/memory':
|
|
400
|
+
await (0, memory_1.handleMemoryCommand)(this.client, args);
|
|
401
|
+
break;
|
|
355
402
|
case '/status':
|
|
356
403
|
await this._handleStatus();
|
|
357
404
|
break;
|
|
@@ -369,7 +416,7 @@ class HelixRepl {
|
|
|
369
416
|
this.client.emergencyStop();
|
|
370
417
|
this.isProcessingPrompt = false;
|
|
371
418
|
this.activeTaskId = null;
|
|
372
|
-
console.log((0, colors_1.GREEN)('
|
|
419
|
+
console.log((0, colors_1.GREEN)('✔ Todas las tareas han sido detenidas.\n'));
|
|
373
420
|
break;
|
|
374
421
|
case '/exit':
|
|
375
422
|
case '/quit':
|
|
@@ -385,7 +432,7 @@ class HelixRepl {
|
|
|
385
432
|
}
|
|
386
433
|
// --- Direct chat message / @skill / #mcp ---
|
|
387
434
|
if (!this.client.connected) {
|
|
388
|
-
console.log((0, colors_1.YELLOW)('
|
|
435
|
+
console.log((0, colors_1.YELLOW)('⚠El agente no está conectado actualmente. Intentando enviar de todos modos...'));
|
|
389
436
|
}
|
|
390
437
|
// Highlight skills in strong orange (#FF8C00) and mcps in cyan
|
|
391
438
|
const knownSkills = this.autocompleter.getSkills();
|
|
@@ -394,12 +441,12 @@ class HelixRepl {
|
|
|
394
441
|
this.conversationHistory.push({ role: 'user', content: line });
|
|
395
442
|
this.isProcessingPrompt = true;
|
|
396
443
|
this.activeTasksCount++;
|
|
397
|
-
process.stdout.write(` ${chalk_1.default.gray('
|
|
398
|
-
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...')}`);
|
|
399
446
|
const sent = this.client.sendUserText(line, this.conversationId, this.conversationHistory.slice(-10));
|
|
400
447
|
if (!sent) {
|
|
401
448
|
process.stdout.write('\r\x1b[K');
|
|
402
|
-
console.log((0, colors_1.RED)('
|
|
449
|
+
console.log((0, colors_1.RED)('✖ Error: No se pudo enviar el mensaje (WebSocket desconectado).'));
|
|
403
450
|
this.isProcessingPrompt = false;
|
|
404
451
|
this.activeTasksCount = Math.max(0, this.activeTasksCount - 1);
|
|
405
452
|
this._promptUser();
|
|
@@ -408,7 +455,7 @@ class HelixRepl {
|
|
|
408
455
|
async _handleListTasks() {
|
|
409
456
|
try {
|
|
410
457
|
const tasks = await this.client.getTasks();
|
|
411
|
-
console.log(`\n${(0, colors_1.BOLD)('
|
|
458
|
+
console.log(`\n${(0, colors_1.BOLD)('📋 Tareas Registradas en HELIX:')}\n`);
|
|
412
459
|
if (!tasks || tasks.length === 0) {
|
|
413
460
|
console.log((0, colors_1.GRAY)(' No hay tareas recientes registradas.\n'));
|
|
414
461
|
return;
|
|
@@ -416,13 +463,13 @@ class HelixRepl {
|
|
|
416
463
|
for (const t of tasks.slice(-10)) {
|
|
417
464
|
let statusBadge = chalk_1.default.gray(t.status);
|
|
418
465
|
if (t.status === 'COMPLETED')
|
|
419
|
-
statusBadge = chalk_1.default.green('
|
|
466
|
+
statusBadge = chalk_1.default.green('✔ Completada');
|
|
420
467
|
if (t.status === 'RUNNING')
|
|
421
|
-
statusBadge = chalk_1.default.yellow('
|
|
468
|
+
statusBadge = chalk_1.default.yellow('ⳠEn ejecución');
|
|
422
469
|
if (t.status === 'FAILED')
|
|
423
|
-
statusBadge = chalk_1.default.red('
|
|
470
|
+
statusBadge = chalk_1.default.red('✖ Fallida');
|
|
424
471
|
if (t.status === 'CANCELLED')
|
|
425
|
-
statusBadge = chalk_1.default.gray('
|
|
472
|
+
statusBadge = chalk_1.default.gray('â—‹ Cancelada');
|
|
426
473
|
console.log(` ${statusBadge} ${(0, colors_1.DIM)(t.task_id)}`);
|
|
427
474
|
if (t.prompt)
|
|
428
475
|
console.log(` ${chalk_1.default.white(t.prompt)}`);
|
|
@@ -436,13 +483,13 @@ class HelixRepl {
|
|
|
436
483
|
async _handleListModels() {
|
|
437
484
|
try {
|
|
438
485
|
const models = await this.client.getModels();
|
|
439
|
-
console.log(`\n${(0, colors_1.BOLD)('
|
|
486
|
+
console.log(`\n${(0, colors_1.BOLD)('🧠Modelos Disponibles en Proveedores Configurados:')}\n`);
|
|
440
487
|
if (!models || models.length === 0) {
|
|
441
488
|
console.log((0, colors_1.GRAY)(' No hay modelos disponibles. Configura tus API Keys con /config-apikey.\n'));
|
|
442
489
|
return;
|
|
443
490
|
}
|
|
444
491
|
for (const m of models) {
|
|
445
|
-
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}]`)}`);
|
|
446
493
|
}
|
|
447
494
|
console.log('');
|
|
448
495
|
}
|
|
@@ -452,11 +499,11 @@ class HelixRepl {
|
|
|
452
499
|
}
|
|
453
500
|
async _handleStatus() {
|
|
454
501
|
console.log('');
|
|
455
|
-
console.log(` ${chalk_1.default.hex('#FF8C00').bold('
|
|
456
|
-
console.log(` ${chalk_1.default.gray('
|
|
457
|
-
console.log(` ${chalk_1.default.gray('Agente WS')} ${this.client.connected ? chalk_1.default.green('
|
|
458
|
-
console.log(` ${chalk_1.default.gray('
|
|
459
|
-
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)`)}`);
|
|
460
507
|
console.log(` ${chalk_1.default.gray('Skills')} ${chalk_1.default.hex('#FF8C00').bold(this.autocompleter.getSkills().length.toString())} registradas`);
|
|
461
508
|
console.log(` ${chalk_1.default.gray('MCP Tools')} ${chalk_1.default.cyan.bold(this.autocompleter.getMcpTools().length.toString())} disponibles`);
|
|
462
509
|
console.log('');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"name": "helix-assistant-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "HELIX - Interactive Terminal CLI for Windows AI Desktop Agent",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -21,10 +21,12 @@
|
|
|
21
21
|
"chalk": "^4.1.2",
|
|
22
22
|
"commander": "^12.0.0",
|
|
23
23
|
"dotenv": "^16.4.5",
|
|
24
|
+
"jpeg-js": "^0.4.4",
|
|
24
25
|
"prompts": "^2.4.2",
|
|
25
26
|
"ws": "^8.16.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
29
|
+
"@types/jpeg-js": "^0.3.0",
|
|
28
30
|
"@types/node": "^20.11.0",
|
|
29
31
|
"@types/prompts": "^2.4.9",
|
|
30
32
|
"@types/ws": "^8.5.10",
|
package/src/commands/browser.ts
CHANGED
|
@@ -14,7 +14,7 @@ export async function handleBrowserCommand(
|
|
|
14
14
|
console.log(CYAN(`\n Solicitando al agente abrir en navegador: ${targetUrl}...`));
|
|
15
15
|
client.sendUserText(
|
|
16
16
|
`Por favor abre la siguiente URL en el navegador: ${targetUrl}`,
|
|
17
|
-
`
|
|
17
|
+
`cli_browser_${Date.now()}`
|
|
18
18
|
);
|
|
19
19
|
console.log(GREEN(` ✔ Comando enviado al agente.\n`));
|
|
20
20
|
return;
|
|
@@ -32,7 +32,8 @@ export async function handleBrowserCommand(
|
|
|
32
32
|
console.log(` Dominios: ${settings.block_untrusted_domains ? YELLOW('Filtrado Estricto') : GRAY('Abierto')}`);
|
|
33
33
|
console.log(`\n ${DIM('Comandos disponibles:')}`);
|
|
34
34
|
console.log(` ${CYAN('/browser')} ${DIM('- Ver estado de navegación')}`);
|
|
35
|
-
console.log(` ${CYAN('/browser open <url>')} ${DIM('- Abrir URL con el agente')}
|
|
35
|
+
console.log(` ${CYAN('/browser open <url>')} ${DIM('- Abrir URL con el agente')}`);
|
|
36
|
+
console.log(` ${CYAN('/browser live [on|off]')} ${DIM('- Alternar la vista ASCII de capturas')}\n`);
|
|
36
37
|
} catch (err) {
|
|
37
38
|
console.log(RED(` Error al consultar estado del navegador: ${(err as Error).message}\n`));
|
|
38
39
|
}
|