plazbot-cli 0.2.19 → 0.2.21
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/cli.js +3 -0
- package/dist/commands/agent/templates.js +29 -24
- package/dist/commands/agent/wizard.js +1 -0
- package/dist/commands/workers/deploy.js +127 -0
- package/dist/commands/workers/index.js +18 -0
- package/dist/commands/workers/list.js +81 -0
- package/dist/commands/workers/logs.js +78 -0
- package/dist/commands/workers/remove.js +88 -0
- package/dist/commands/workers/secret.js +151 -0
- package/dist/commands/workers/test.js +109 -0
- package/dist/types/workers.js +2 -0
- package/dist/utils/api.js +25 -0
- package/package.json +2 -2
- package/src/cli.ts +4 -0
- package/src/commands/agent/templates.ts +28 -25
- package/src/commands/agent/wizard.ts +2 -2
- package/src/commands/workers/deploy.ts +144 -0
- package/src/commands/workers/index.ts +16 -0
- package/src/commands/workers/list.ts +93 -0
- package/src/commands/workers/logs.ts +89 -0
- package/src/commands/workers/remove.ts +95 -0
- package/src/commands/workers/secret.ts +179 -0
- package/src/commands/workers/test.ts +133 -0
- package/src/types/workers.ts +86 -0
- package/src/utils/api.ts +29 -0
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ const portal_1 = require("./commands/portal");
|
|
|
6
6
|
const auth_1 = require("./commands/auth");
|
|
7
7
|
const agent_1 = require("./commands/agent");
|
|
8
8
|
const whatsapp_1 = require("./commands/whatsapp");
|
|
9
|
+
const workers_1 = require("./commands/workers");
|
|
9
10
|
const banner_1 = require("./utils/banner");
|
|
10
11
|
// Configuracion basica del CLI
|
|
11
12
|
commander_1.program
|
|
@@ -20,6 +21,8 @@ commander_1.program.addCommand(agent_1.agentCommands);
|
|
|
20
21
|
commander_1.program.addCommand(portal_1.portalCommands);
|
|
21
22
|
// Registrar todos los comandos de WhatsApp
|
|
22
23
|
commander_1.program.addCommand(whatsapp_1.whatsappCommands);
|
|
24
|
+
// Registrar todos los comandos de Workers
|
|
25
|
+
commander_1.program.addCommand(workers_1.workersCommands);
|
|
23
26
|
// Si no se pasan argumentos, mostrar banner
|
|
24
27
|
if (process.argv.length <= 2) {
|
|
25
28
|
(0, banner_1.showBanner)().then(() => {
|
|
@@ -10,6 +10,7 @@ const plazbot_1 = require("plazbot");
|
|
|
10
10
|
const credentials_1 = require("../../utils/credentials");
|
|
11
11
|
const logger_1 = require("../../utils/logger");
|
|
12
12
|
const ui_1 = require("../../utils/ui");
|
|
13
|
+
const wizard_1 = require("./wizard");
|
|
13
14
|
// Plantilla: Clinica
|
|
14
15
|
const plantillaClinica = {
|
|
15
16
|
"name": "Asistente Clinica Salud",
|
|
@@ -704,23 +705,24 @@ exports.templatesCommand = new commander_1.Command('templates')
|
|
|
704
705
|
}]);
|
|
705
706
|
placeholderAnswers[ph.key] = value.trim();
|
|
706
707
|
}
|
|
707
|
-
// Paso 3: WhatsApp
|
|
708
|
-
console.log(ui_1.theme.bold('\n
|
|
709
|
-
const {
|
|
708
|
+
// Paso 3: Canales (WhatsApp, Messenger, Instagram, Telegram)
|
|
709
|
+
console.log(ui_1.theme.bold('\n Conexion de canales'));
|
|
710
|
+
const { wantChannels } = await inquirer_1.default.prompt([{
|
|
710
711
|
type: 'confirm',
|
|
711
|
-
name: '
|
|
712
|
-
message: 'Deseas
|
|
712
|
+
name: 'wantChannels',
|
|
713
|
+
message: 'Deseas conectar canales (WhatsApp, Messenger, Instagram, Telegram)?',
|
|
713
714
|
default: true,
|
|
714
715
|
}]);
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
716
|
+
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
717
|
+
let connectedChannels = [];
|
|
718
|
+
if (wantChannels) {
|
|
719
|
+
const wizardCtx = {
|
|
720
|
+
zone: credentials.zone,
|
|
721
|
+
workspaceId: credentials.workspace,
|
|
722
|
+
apiKey: credentials.apiKey,
|
|
723
|
+
dev: !!options.dev,
|
|
724
|
+
};
|
|
725
|
+
connectedChannels = await (0, wizard_1.connectChannelFlow)(wizardCtx);
|
|
724
726
|
}
|
|
725
727
|
// Paso 4: API Key de OpenAI
|
|
726
728
|
console.log(ui_1.theme.bold('\n Configuracion de IA'));
|
|
@@ -752,8 +754,8 @@ exports.templatesCommand = new commander_1.Command('templates')
|
|
|
752
754
|
const configClone = JSON.parse(JSON.stringify(template.config));
|
|
753
755
|
const finalConfig = replacePlaceholders(configClone, placeholderAnswers);
|
|
754
756
|
finalConfig.timezone = timezone;
|
|
755
|
-
if (
|
|
756
|
-
finalConfig.channels =
|
|
757
|
+
if (connectedChannels.length > 0) {
|
|
758
|
+
finalConfig.channels = connectedChannels;
|
|
757
759
|
}
|
|
758
760
|
else {
|
|
759
761
|
finalConfig.channels = [];
|
|
@@ -773,7 +775,7 @@ exports.templatesCommand = new commander_1.Command('templates')
|
|
|
773
775
|
for (const ph of template.placeholders) {
|
|
774
776
|
console.log((0, ui_1.kvPair)(ph.label, placeholderAnswers[ph.key]));
|
|
775
777
|
}
|
|
776
|
-
console.log((0, ui_1.kvPair)('
|
|
778
|
+
console.log((0, ui_1.kvPair)('Canales', connectedChannels.length > 0 ? connectedChannels.map(c => `${c.channel} (${c.key})`).join(', ') : 'No configurado'));
|
|
777
779
|
console.log((0, ui_1.kvPair)('API Key OpenAI', apiToken ? 'Configurada' : 'No configurada (el agente no funcionara sin ella)'));
|
|
778
780
|
console.log((0, ui_1.kvPair)('Zona horaria', timezone));
|
|
779
781
|
console.log((0, ui_1.kvPair)('Acciones', String(finalConfig.actions.length)));
|
|
@@ -790,7 +792,6 @@ exports.templatesCommand = new commander_1.Command('templates')
|
|
|
790
792
|
return;
|
|
791
793
|
}
|
|
792
794
|
// Paso 7: Crear agente
|
|
793
|
-
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
794
795
|
const agent = new plazbot_1.Agent({
|
|
795
796
|
workspaceId: credentials.workspace,
|
|
796
797
|
apiKey: credentials.apiKey,
|
|
@@ -808,16 +809,20 @@ exports.templatesCommand = new commander_1.Command('templates')
|
|
|
808
809
|
}
|
|
809
810
|
logger_1.logger.label('Nombre', finalConfig.name);
|
|
810
811
|
logger_1.logger.label('Industria', template.industry);
|
|
811
|
-
if (
|
|
812
|
-
logger_1.logger.label('
|
|
812
|
+
if (connectedChannels.length > 0) {
|
|
813
|
+
logger_1.logger.label('Canales', connectedChannels.map(c => `${c.channel} (${c.key})`).join(', '));
|
|
813
814
|
}
|
|
814
815
|
logger_1.logger.label('Acciones', String(finalConfig.actions.length));
|
|
815
816
|
console.log();
|
|
816
817
|
console.log((0, ui_1.section)('Siguientes pasos'));
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
818
|
+
if (connectedChannels.length === 0) {
|
|
819
|
+
console.log(ui_1.theme.bold(' 1.') + ' Conecta canales desde: ' + ui_1.theme.success('plazbot agent chat -a <agentId>'));
|
|
820
|
+
console.log(ui_1.theme.bold(' 2.') + ' O conecta desde la plataforma en Ajustes > Integraciones');
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
console.log(ui_1.theme.bold(' 1.') + ' Tu agente ya tiene canales conectados y activados');
|
|
824
|
+
}
|
|
825
|
+
console.log(ui_1.theme.bold(` ${connectedChannels.length === 0 ? '3' : '2'}.`) + ' Agrega tu API Key de OpenAI si no la configuraste');
|
|
821
826
|
console.log();
|
|
822
827
|
if (!apiToken) {
|
|
823
828
|
logger_1.logger.warning('Recuerda configurar tu API Key de OpenAI para que el agente funcione:');
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.connectChannelFlow = connectChannelFlow;
|
|
6
7
|
exports.runAgentWizard = runAgentWizard;
|
|
7
8
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
@@ -0,0 +1,127 @@
|
|
|
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.deployCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const credentials_1 = require("../../utils/credentials");
|
|
11
|
+
const api_1 = require("../../utils/api");
|
|
12
|
+
const logger_1 = require("../../utils/logger");
|
|
13
|
+
const ui_1 = require("../../utils/ui");
|
|
14
|
+
exports.deployCommand = new commander_1.Command('deploy')
|
|
15
|
+
.description('Despliega un worker al workspace de Plazbot')
|
|
16
|
+
.argument('[file]', 'Archivo TypeScript del worker (ej: ./workers/mi-tool.ts)')
|
|
17
|
+
.option('-n, --name <name>', 'Nombre del worker (sobreescribe el del archivo)')
|
|
18
|
+
.option('-d, --description <desc>', 'Descripcion del worker')
|
|
19
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
20
|
+
.action(async (file, options) => {
|
|
21
|
+
try {
|
|
22
|
+
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
23
|
+
// Buscar archivos de workers
|
|
24
|
+
const files = await resolveWorkerFiles(file);
|
|
25
|
+
if (files.length === 0) {
|
|
26
|
+
logger_1.logger.error('No se encontraron archivos de workers para desplegar');
|
|
27
|
+
logger_1.logger.dim('Uso: plazbot workers deploy ./workers/mi-tool.ts');
|
|
28
|
+
logger_1.logger.dim(' o: plazbot workers deploy (busca en ./workers/ automaticamente)');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const api = (0, api_1.createApiClient)({
|
|
32
|
+
apiKey: credentials.apiKey,
|
|
33
|
+
workspace: credentials.workspace,
|
|
34
|
+
zone: credentials.zone,
|
|
35
|
+
dev: options.dev,
|
|
36
|
+
});
|
|
37
|
+
logger_1.logger.title(`Desplegando ${files.length} worker${files.length > 1 ? 's' : ''}`);
|
|
38
|
+
console.log();
|
|
39
|
+
const results = [];
|
|
40
|
+
for (const filePath of files) {
|
|
41
|
+
const fileName = path_1.default.basename(filePath);
|
|
42
|
+
const spinner = (0, ui_1.createSpinner)(`Desplegando ${fileName}...`);
|
|
43
|
+
spinner.start();
|
|
44
|
+
try {
|
|
45
|
+
// Leer archivo fuente
|
|
46
|
+
const sourceCode = await promises_1.default.readFile(filePath, 'utf-8');
|
|
47
|
+
// Enviar al API
|
|
48
|
+
const response = await api.post('/api/workers/deploy', {
|
|
49
|
+
sourceCode,
|
|
50
|
+
fileName,
|
|
51
|
+
name: files.length === 1 ? options.name : undefined,
|
|
52
|
+
description: files.length === 1 ? options.description : undefined,
|
|
53
|
+
});
|
|
54
|
+
const data = response.data;
|
|
55
|
+
spinner.succeed(`${fileName} → ${data.name} (${data.type})`);
|
|
56
|
+
results.push({ file: fileName, result: data });
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const msg = error.response?.data?.message || error.message || 'Error desconocido';
|
|
60
|
+
spinner.fail(`${fileName}: ${msg}`);
|
|
61
|
+
results.push({ file: fileName, error: msg });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Resumen
|
|
65
|
+
console.log();
|
|
66
|
+
const success = results.filter(r => r.result);
|
|
67
|
+
const failed = results.filter(r => r.error);
|
|
68
|
+
if (success.length > 0) {
|
|
69
|
+
logger_1.logger.success(`${success.length} worker${success.length > 1 ? 's' : ''} desplegado${success.length > 1 ? 's' : ''}`);
|
|
70
|
+
const rows = success.map(r => [
|
|
71
|
+
r.result.name,
|
|
72
|
+
r.result.type,
|
|
73
|
+
r.result.status,
|
|
74
|
+
r.result.webhookUrl || r.result.cronExpression || '—',
|
|
75
|
+
]);
|
|
76
|
+
console.log((0, ui_1.createTable)(['Nombre', 'Tipo', 'Estado', 'URL/Cron'], rows));
|
|
77
|
+
}
|
|
78
|
+
if (failed.length > 0) {
|
|
79
|
+
logger_1.logger.warning(`${failed.length} worker${failed.length > 1 ? 's' : ''} fallaron`);
|
|
80
|
+
failed.forEach(f => logger_1.logger.dim(` ${f.file}: ${f.error}`));
|
|
81
|
+
}
|
|
82
|
+
// Mostrar webhook URLs si hay
|
|
83
|
+
const webhooks = success.filter(r => r.result.webhookUrl);
|
|
84
|
+
if (webhooks.length > 0) {
|
|
85
|
+
console.log();
|
|
86
|
+
logger_1.logger.title('Webhook URLs');
|
|
87
|
+
webhooks.forEach(w => {
|
|
88
|
+
logger_1.logger.label(w.result.name, ui_1.theme.secondary(w.result.webhookUrl));
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
console.log();
|
|
92
|
+
if (options.dev) {
|
|
93
|
+
logger_1.logger.warning('Ambiente: desarrollo');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
98
|
+
logger_1.logger.error(message);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// Resuelve los archivos a desplegar
|
|
103
|
+
async function resolveWorkerFiles(file) {
|
|
104
|
+
if (file) {
|
|
105
|
+
// Archivo especifico
|
|
106
|
+
const resolved = path_1.default.resolve(file);
|
|
107
|
+
try {
|
|
108
|
+
await promises_1.default.access(resolved);
|
|
109
|
+
return [resolved];
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw new Error(`Archivo no encontrado: ${file}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Buscar en ./workers/ automaticamente
|
|
116
|
+
const workersDir = path_1.default.resolve('workers');
|
|
117
|
+
try {
|
|
118
|
+
const entries = await promises_1.default.readdir(workersDir);
|
|
119
|
+
const tsFiles = entries
|
|
120
|
+
.filter(e => e.endsWith('.ts') && !e.endsWith('.d.ts'))
|
|
121
|
+
.map(e => path_1.default.join(workersDir, e));
|
|
122
|
+
return tsFiles;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.workersCommands = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const deploy_1 = require("./deploy");
|
|
6
|
+
const list_1 = require("./list");
|
|
7
|
+
const logs_1 = require("./logs");
|
|
8
|
+
const remove_1 = require("./remove");
|
|
9
|
+
const secret_1 = require("./secret");
|
|
10
|
+
const test_1 = require("./test");
|
|
11
|
+
exports.workersCommands = new commander_1.Command('workers')
|
|
12
|
+
.description('Comandos para gestionar workers (tools, syncs, schedules, webhooks)')
|
|
13
|
+
.addCommand(deploy_1.deployCommand)
|
|
14
|
+
.addCommand(list_1.listCommand)
|
|
15
|
+
.addCommand(logs_1.logsCommand)
|
|
16
|
+
.addCommand(remove_1.removeCommand)
|
|
17
|
+
.addCommand(secret_1.secretCommand)
|
|
18
|
+
.addCommand(test_1.testCommand);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const credentials_1 = require("../../utils/credentials");
|
|
6
|
+
const api_1 = require("../../utils/api");
|
|
7
|
+
const logger_1 = require("../../utils/logger");
|
|
8
|
+
const ui_1 = require("../../utils/ui");
|
|
9
|
+
exports.listCommand = new commander_1.Command('list')
|
|
10
|
+
.description('Lista todos los workers del workspace')
|
|
11
|
+
.option('-t, --type <type>', 'Filtrar por tipo (tool, worker, sync, schedule, webhook)')
|
|
12
|
+
.option('-s, --status <status>', 'Filtrar por estado (active, inactive, error)')
|
|
13
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
try {
|
|
16
|
+
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
17
|
+
const api = (0, api_1.createApiClient)({
|
|
18
|
+
apiKey: credentials.apiKey,
|
|
19
|
+
workspace: credentials.workspace,
|
|
20
|
+
zone: credentials.zone,
|
|
21
|
+
dev: options.dev,
|
|
22
|
+
});
|
|
23
|
+
const spinner = (0, ui_1.createSpinner)('Obteniendo workers...');
|
|
24
|
+
spinner.start();
|
|
25
|
+
const params = {};
|
|
26
|
+
if (options.type)
|
|
27
|
+
params.type = options.type;
|
|
28
|
+
if (options.status)
|
|
29
|
+
params.status = options.status;
|
|
30
|
+
const response = await api.get('/api/workers', { params });
|
|
31
|
+
const workers = response.data;
|
|
32
|
+
spinner.stop();
|
|
33
|
+
if (!workers || workers.length === 0) {
|
|
34
|
+
logger_1.logger.info('\n No se encontraron workers en este workspace');
|
|
35
|
+
logger_1.logger.dim(' Despliega tu primer worker: plazbot workers deploy ./workers/mi-tool.ts');
|
|
36
|
+
console.log();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
logger_1.logger.title(`Workers (${workers.length})`);
|
|
40
|
+
const rows = workers.map(w => [
|
|
41
|
+
w.name,
|
|
42
|
+
typeLabel(w.type),
|
|
43
|
+
w.status === 'active' ? ui_1.theme.success('activo')
|
|
44
|
+
: w.status === 'error' ? ui_1.theme.error('error')
|
|
45
|
+
: ui_1.theme.muted('inactivo'),
|
|
46
|
+
`${w.executionCount}`,
|
|
47
|
+
w.errorCount > 0 ? ui_1.theme.error(`${w.errorCount}`) : ui_1.theme.muted('0'),
|
|
48
|
+
w.avgDurationMs > 0 ? `${w.avgDurationMs}ms` : '—',
|
|
49
|
+
w.lastExecutedAt ? (0, ui_1.formatDate)(w.lastExecutedAt) : '—',
|
|
50
|
+
]);
|
|
51
|
+
console.log((0, ui_1.createTable)(['Nombre', 'Tipo', 'Estado', 'Ejecuciones', 'Errores', 'Duracion', 'Ultima ejecucion'], rows));
|
|
52
|
+
// Mostrar workers con error
|
|
53
|
+
const errored = workers.filter(w => w.status === 'error');
|
|
54
|
+
if (errored.length > 0) {
|
|
55
|
+
console.log();
|
|
56
|
+
logger_1.logger.warning('Workers con error:');
|
|
57
|
+
errored.forEach(w => {
|
|
58
|
+
logger_1.logger.dim(` ${w.name}: ${w.lastError || 'sin detalles'}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
console.log();
|
|
62
|
+
if (options.dev) {
|
|
63
|
+
logger_1.logger.warning('Ambiente: desarrollo');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
68
|
+
logger_1.logger.error(message);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
function typeLabel(type) {
|
|
73
|
+
const labels = {
|
|
74
|
+
tool: ui_1.theme.secondary('tool'),
|
|
75
|
+
worker: ui_1.theme.primary('worker'),
|
|
76
|
+
sync: ui_1.theme.accent('sync'),
|
|
77
|
+
schedule: ui_1.theme.muted('schedule'),
|
|
78
|
+
webhook: ui_1.theme.warning('webhook'),
|
|
79
|
+
};
|
|
80
|
+
return labels[type] || type;
|
|
81
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logsCommand = void 0;
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const credentials_1 = require("../../utils/credentials");
|
|
6
|
+
const api_1 = require("../../utils/api");
|
|
7
|
+
const logger_1 = require("../../utils/logger");
|
|
8
|
+
const ui_1 = require("../../utils/ui");
|
|
9
|
+
exports.logsCommand = new commander_1.Command('logs')
|
|
10
|
+
.description('Ver logs de ejecucion de un worker')
|
|
11
|
+
.argument('<name>', 'Nombre del worker')
|
|
12
|
+
.option('-l, --limit <number>', 'Numero de logs a mostrar', '20')
|
|
13
|
+
.option('-s, --status <status>', 'Filtrar por estado (success, error, timeout)')
|
|
14
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
15
|
+
.action(async (name, options) => {
|
|
16
|
+
try {
|
|
17
|
+
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
18
|
+
const api = (0, api_1.createApiClient)({
|
|
19
|
+
apiKey: credentials.apiKey,
|
|
20
|
+
workspace: credentials.workspace,
|
|
21
|
+
zone: credentials.zone,
|
|
22
|
+
dev: options.dev,
|
|
23
|
+
});
|
|
24
|
+
const spinner = (0, ui_1.createSpinner)(`Obteniendo logs de "${name}"...`);
|
|
25
|
+
spinner.start();
|
|
26
|
+
const params = {
|
|
27
|
+
limit: String(options.limit || 20),
|
|
28
|
+
};
|
|
29
|
+
if (options.status)
|
|
30
|
+
params.status = options.status;
|
|
31
|
+
const response = await api.get(`/api/workers/${encodeURIComponent(name)}/logs`, { params });
|
|
32
|
+
const logs = response.data;
|
|
33
|
+
spinner.stop();
|
|
34
|
+
if (!logs || logs.length === 0) {
|
|
35
|
+
logger_1.logger.info(`\n No se encontraron logs para "${name}"`);
|
|
36
|
+
console.log();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
logger_1.logger.title(`Logs de "${name}" (${logs.length})`);
|
|
40
|
+
const rows = logs.map(log => [
|
|
41
|
+
(0, ui_1.formatDate)(log.createdAt),
|
|
42
|
+
log.status === 'success' ? ui_1.theme.success('ok')
|
|
43
|
+
: log.status === 'error' ? ui_1.theme.error('error')
|
|
44
|
+
: ui_1.theme.warning('timeout'),
|
|
45
|
+
`${log.durationMs}ms`,
|
|
46
|
+
log.triggerSource || '—',
|
|
47
|
+
log.error ? ui_1.theme.error(truncate(log.error, 40)) : '—',
|
|
48
|
+
]);
|
|
49
|
+
console.log((0, ui_1.createTable)(['Fecha', 'Estado', 'Duracion', 'Origen', 'Error'], rows));
|
|
50
|
+
// Resumen
|
|
51
|
+
const successCount = logs.filter(l => l.status === 'success').length;
|
|
52
|
+
const errorCount = logs.filter(l => l.status === 'error').length;
|
|
53
|
+
const avgDuration = Math.round(logs.reduce((sum, l) => sum + l.durationMs, 0) / logs.length);
|
|
54
|
+
console.log();
|
|
55
|
+
logger_1.logger.label('Exitosos', ui_1.theme.success(`${successCount}`));
|
|
56
|
+
logger_1.logger.label('Errores', errorCount > 0 ? ui_1.theme.error(`${errorCount}`) : ui_1.theme.muted('0'));
|
|
57
|
+
logger_1.logger.label('Duracion promedio', `${avgDuration}ms`);
|
|
58
|
+
console.log();
|
|
59
|
+
if (options.dev) {
|
|
60
|
+
logger_1.logger.warning('Ambiente: desarrollo');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.response?.status === 404) {
|
|
65
|
+
logger_1.logger.error(`Worker "${name}" no encontrado`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
69
|
+
logger_1.logger.error(message);
|
|
70
|
+
}
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
function truncate(text, max) {
|
|
75
|
+
if (text.length <= max)
|
|
76
|
+
return text;
|
|
77
|
+
return text.substring(0, max - 3) + '...';
|
|
78
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
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.removeCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const credentials_1 = require("../../utils/credentials");
|
|
9
|
+
const api_1 = require("../../utils/api");
|
|
10
|
+
const logger_1 = require("../../utils/logger");
|
|
11
|
+
const ui_1 = require("../../utils/ui");
|
|
12
|
+
const readline_1 = __importDefault(require("readline"));
|
|
13
|
+
exports.removeCommand = new commander_1.Command('remove')
|
|
14
|
+
.description('Elimina un worker del workspace')
|
|
15
|
+
.argument('<name>', 'Nombre del worker a eliminar')
|
|
16
|
+
.option('-f, --force', 'Eliminar sin confirmacion', false)
|
|
17
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
18
|
+
.action(async (name, options) => {
|
|
19
|
+
try {
|
|
20
|
+
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
21
|
+
const api = (0, api_1.createApiClient)({
|
|
22
|
+
apiKey: credentials.apiKey,
|
|
23
|
+
workspace: credentials.workspace,
|
|
24
|
+
zone: credentials.zone,
|
|
25
|
+
dev: options.dev,
|
|
26
|
+
});
|
|
27
|
+
// Verificar que el worker existe
|
|
28
|
+
const spinner = (0, ui_1.createSpinner)(`Buscando worker "${name}"...`);
|
|
29
|
+
spinner.start();
|
|
30
|
+
let workerInfo;
|
|
31
|
+
try {
|
|
32
|
+
const response = await api.get(`/api/workers/${encodeURIComponent(name)}`);
|
|
33
|
+
workerInfo = response.data;
|
|
34
|
+
spinner.stop();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
spinner.stop();
|
|
38
|
+
if (error.response?.status === 404) {
|
|
39
|
+
logger_1.logger.error(`Worker "${name}" no encontrado`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
logger_1.logger.error(error.response?.data?.message || error.message);
|
|
43
|
+
}
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
// Mostrar info del worker
|
|
47
|
+
logger_1.logger.warning(`\n Vas a eliminar el siguiente worker:`);
|
|
48
|
+
logger_1.logger.divider();
|
|
49
|
+
logger_1.logger.label('Nombre', workerInfo.name);
|
|
50
|
+
logger_1.logger.label('Tipo', workerInfo.type);
|
|
51
|
+
logger_1.logger.label('Estado', workerInfo.status);
|
|
52
|
+
logger_1.logger.label('Ejecuciones', `${workerInfo.executionCount || 0}`);
|
|
53
|
+
logger_1.logger.divider();
|
|
54
|
+
// Confirmacion
|
|
55
|
+
if (!options.force) {
|
|
56
|
+
const confirmed = await askConfirmation(`Eliminar worker "${name}"? Esta accion no se puede deshacer (y/N): `);
|
|
57
|
+
if (!confirmed) {
|
|
58
|
+
logger_1.logger.info('\n Operacion cancelada');
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const deleteSpinner = (0, ui_1.createSpinner)(`Eliminando "${name}"...`);
|
|
63
|
+
deleteSpinner.start();
|
|
64
|
+
await api.delete(`/api/workers/${encodeURIComponent(name)}`);
|
|
65
|
+
deleteSpinner.succeed(`Worker "${name}" eliminado`);
|
|
66
|
+
console.log();
|
|
67
|
+
if (options.dev) {
|
|
68
|
+
logger_1.logger.warning('Ambiente: desarrollo');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
73
|
+
logger_1.logger.error(message);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
function askConfirmation(question) {
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
const rl = readline_1.default.createInterface({
|
|
80
|
+
input: process.stdin,
|
|
81
|
+
output: process.stdout,
|
|
82
|
+
});
|
|
83
|
+
rl.question(question, (answer) => {
|
|
84
|
+
rl.close();
|
|
85
|
+
resolve(answer.toLowerCase() === 'y');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|