plazbot-cli 0.2.5 → 0.2.7

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.
@@ -119,11 +119,18 @@ exports.monitorCommand = new commander_1.Command('monitor')
119
119
  .option('-f, --filter <types>', 'Filtrar por tipos separados por coma (ej: msg_in,msg_out)')
120
120
  .option('--no-session', 'Ocultar session ID')
121
121
  .option('--json', 'Modo JSON crudo (para piping)', false)
122
+ .option('-w, --workspace <id>', 'Workspace ID (sobreescribe config local)')
123
+ .option('-z, --zone <zone>', 'Zona LA o EU (sobreescribe config local)')
122
124
  .option('--dev', 'Usar ambiente de desarrollo', false)
123
125
  .action(async (options) => {
124
126
  try {
125
127
  const credentials = await (0, credentials_1.getStoredCredentials)();
126
- const baseUrl = getBaseUrl(credentials.zone, options.dev);
128
+ const effectiveWorkspace = options.workspace || credentials.workspace;
129
+ const effectiveZone = (options.zone?.toUpperCase() === 'EU' ? 'EU' : options.zone?.toUpperCase() === 'LA' ? 'LA' : credentials.zone);
130
+ const baseUrl = getBaseUrl(effectiveZone, options.dev);
131
+ if (options.workspace || options.zone) {
132
+ console.log(chalk_1.default.hex('#FFA726')(`\n Modo soporte: workspace=${effectiveWorkspace} zona=${effectiveZone}`));
133
+ }
127
134
  // Filtros iniciales
128
135
  const activeFilters = new Set(options.filter ? options.filter.split(',').map(f => f.trim()) : []);
129
136
  let jsonMode = options.json;
@@ -133,9 +140,9 @@ exports.monitorCommand = new commander_1.Command('monitor')
133
140
  try {
134
141
  process.stdout.write(chalk_1.default.gray(' Conectando con agente...'));
135
142
  const agent = new plazbot_1.Agent({
136
- workspaceId: credentials.workspace,
143
+ workspaceId: effectiveWorkspace,
137
144
  apiKey: credentials.apiKey,
138
- zone: credentials.zone,
145
+ zone: effectiveZone,
139
146
  ...(options.dev && { customUrl: 'http://localhost:5090' }),
140
147
  });
141
148
  const info = await agent.getAgentById({ id: options.agentId });
@@ -10,7 +10,7 @@ const axios_1 = __importDefault(require("axios"));
10
10
  const ora_1 = __importDefault(require("ora"));
11
11
  const ui_1 = require("../../utils/ui");
12
12
  const MODELS = {
13
- openai: ['gpt-4o', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'],
13
+ openai: ['gpt-4o', 'gpt-4o-mini', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'],
14
14
  claude: ['claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-haiku-20240307'],
15
15
  gemini: ['gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'],
16
16
  };
@@ -71,40 +71,76 @@ async function connectChannelFlow(ctx) {
71
71
  }
72
72
  const shortUrl = linkRes.data.data?.shortUrl || '';
73
73
  spinner.stop();
74
- // Mostrar link en box visual
74
+ // Mostrar link
75
75
  console.log();
76
- console.log(chalk_1.default.hex('#4CAF50')(' ┌' + '─'.repeat(64) + '┐'));
77
- console.log(chalk_1.default.hex('#4CAF50')(' │') + chalk_1.default.bold(` Envia este link para conectar ${channelLabel}:`).padEnd(74) + chalk_1.default.hex('#4CAF50')('│'));
78
- console.log(chalk_1.default.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk_1.default.hex('#4CAF50')('│'));
79
- console.log(chalk_1.default.hex('#4CAF50')(' ') + chalk_1.default.hex('#22d3ee')(` ${shortUrl}`).padEnd(74) + chalk_1.default.hex('#4CAF50')('│'));
80
- console.log(chalk_1.default.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk_1.default.hex('#4CAF50')('│'));
81
- console.log(chalk_1.default.hex('#4CAF50')(' └' + '─'.repeat(64) + '┘'));
76
+ console.log(chalk_1.default.hex('#4CAF50')(' ─'.repeat(32)));
77
+ console.log(chalk_1.default.bold(` Envia este link para conectar ${channelLabel}:`));
78
+ console.log();
79
+ console.log(' ' + chalk_1.default.hex('#22d3ee')(shortUrl));
80
+ console.log();
81
+ console.log(chalk_1.default.hex('#4CAF50')(' ─'.repeat(32)));
82
82
  console.log();
83
83
  // Snapshot de integraciones actuales
84
84
  let prevIntegrationIds = new Set();
85
85
  try {
86
86
  const wkRes = await axios_1.default.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
87
- const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
87
+ const integrations = wkRes.data?.integrations || [];
88
88
  prevIntegrationIds = new Set(integrations.map((i) => i.id));
89
89
  }
90
90
  catch {
91
91
  // Si falla, se parte de vacio
92
92
  }
93
- // Polling para detectar nueva integracion
94
- const pollSpinner = (0, ora_1.default)({ text: chalk_1.default.gray('Esperando conexion... (Ctrl+C para cancelar)'), spinner: 'dots', color: 'cyan' }).start();
93
+ // Polling para detectar nueva integracion (Enter para saltar)
94
+ const pollSpinner = (0, ora_1.default)({ text: chalk_1.default.gray('Esperando conexion... (Enter para saltar)'), spinner: 'dots', color: 'cyan' }).start();
95
95
  const POLL_INTERVAL = 5000;
96
96
  const MAX_POLLS = 60; // 5 minutos
97
97
  let detected = null;
98
+ let skipped = false;
99
+ // Escuchar Enter para saltar el polling
100
+ const skipPromise = new Promise(resolve => {
101
+ const onData = (data) => {
102
+ if (data.toString().includes('\n') || data.toString().includes('\r')) {
103
+ skipped = true;
104
+ process.stdin.removeListener('data', onData);
105
+ if (wasRaw)
106
+ process.stdin.setRawMode(false);
107
+ resolve();
108
+ }
109
+ };
110
+ const wasRaw = process.stdin.isRaw;
111
+ if (process.stdin.isTTY)
112
+ process.stdin.setRawMode(true);
113
+ process.stdin.resume();
114
+ process.stdin.on('data', onData);
115
+ // Limpiar si termina el polling naturalmente
116
+ setTimeout(() => {
117
+ process.stdin.removeListener('data', onData);
118
+ if (process.stdin.isTTY && wasRaw !== undefined) {
119
+ try {
120
+ process.stdin.setRawMode(wasRaw);
121
+ }
122
+ catch { }
123
+ }
124
+ resolve();
125
+ }, POLL_INTERVAL * MAX_POLLS + 1000);
126
+ });
98
127
  for (let i = 0; i < MAX_POLLS; i++) {
99
- await new Promise(r => setTimeout(r, POLL_INTERVAL));
128
+ await Promise.race([
129
+ new Promise(r => setTimeout(r, POLL_INTERVAL)),
130
+ skipPromise,
131
+ ]);
132
+ if (skipped)
133
+ break;
100
134
  try {
101
135
  const wkRes = await axios_1.default.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
102
- const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
103
- // Buscar integraciones nuevas del tipo correcto
104
- const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
105
- const newOnes = integrations.filter((ig) => !prevIntegrationIds.has(ig.id) && ig.type === targetType);
136
+ const integrations = wkRes.data?.integrations || [];
137
+ // Buscar integraciones nuevas (cualquier ID que no existia antes)
138
+ const newOnes = integrations.filter((ig) => !prevIntegrationIds.has(ig.id));
106
139
  if (newOnes.length > 0) {
107
- detected = newOnes[0];
140
+ // Preferir la que coincida con el tipo solicitado
141
+ const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
142
+ const matchingNew = newOnes.find((ig) => ig.type === targetType);
143
+ detected = matchingNew || newOnes[0];
108
144
  break;
109
145
  }
110
146
  }
@@ -112,10 +148,11 @@ async function connectChannelFlow(ctx) {
112
148
  // Ignorar errores de poll individual
113
149
  }
114
150
  const elapsed = Math.floor(((i + 1) * POLL_INTERVAL) / 1000);
115
- pollSpinner.text = chalk_1.default.gray(`Esperando conexion... ${elapsed}s`);
151
+ pollSpinner.text = chalk_1.default.gray(`Esperando conexion... ${elapsed}s (Enter para saltar)`);
116
152
  }
117
153
  if (detected) {
118
- pollSpinner.succeed(chalk_1.default.hex('#4ade80')(`Conexion detectada: ${detected.aliasName || detected.id} (${channelLabel})`));
154
+ const detectedName = detected.aliasName || detected.cellphoneNumberFormat || detected.cellphoneNumber || detected.srcName || detected.id;
155
+ pollSpinner.succeed(chalk_1.default.hex('#4ade80')(`Conexion detectada: ${detectedName} (${channelLabel})`));
119
156
  const { associate } = await inquirer_1.default.prompt([{
120
157
  type: 'confirm', name: 'associate',
121
158
  message: 'Deseas asociar este canal al agente?', default: true,
@@ -130,7 +167,7 @@ async function connectChannelFlow(ctx) {
130
167
  }
131
168
  }
132
169
  else {
133
- pollSpinner.warn(chalk_1.default.hex('#FFA726')('Timeout: no se detecto una conexion.'));
170
+ pollSpinner.warn(chalk_1.default.hex('#FFA726')(skipped ? 'Polling omitido.' : 'Timeout: no se detecto una conexion.'));
134
171
  const { action } = await inquirer_1.default.prompt([{
135
172
  type: 'list', name: 'action',
136
173
  message: 'Que deseas hacer?',
@@ -424,15 +461,13 @@ async function runAgentWizard(zone, workspaceId, apiKey, dev) {
424
461
  const aiConfig = await inquirer_1.default.prompt([
425
462
  { type: 'list', name: 'model', message: 'Modelo:', choices: models },
426
463
  { type: 'password', name: 'apiToken', message: 'API Token:', mask: '*', validate: (v) => v.length > 0 || 'Requerido' },
427
- { type: 'number', name: 'temperature', message: 'Temperatura (0-2):', default: 0.7 },
428
- { type: 'number', name: 'maxTokens', message: 'Max tokens (1024-16384):', default: 4096 },
429
464
  ]);
430
465
  aiProviders.push({
431
466
  provider: ai.provider,
432
467
  model: aiConfig.model,
433
468
  apiToken: aiConfig.apiToken,
434
- temperature: aiConfig.temperature,
435
- maxTokens: aiConfig.maxTokens,
469
+ temperature: 0.7,
470
+ maxTokens: 4096,
436
471
  isDefault: true,
437
472
  });
438
473
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plazbot-cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "CLI para Plazbot SDK",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {
@@ -153,17 +153,28 @@ export const monitorCommand = new Command('monitor')
153
153
  .option('-f, --filter <types>', 'Filtrar por tipos separados por coma (ej: msg_in,msg_out)')
154
154
  .option('--no-session', 'Ocultar session ID')
155
155
  .option('--json', 'Modo JSON crudo (para piping)', false)
156
+ .option('-w, --workspace <id>', 'Workspace ID (sobreescribe config local)')
157
+ .option('-z, --zone <zone>', 'Zona LA o EU (sobreescribe config local)')
156
158
  .option('--dev', 'Usar ambiente de desarrollo', false)
157
159
  .action(async (options: {
158
160
  agentId: string;
159
161
  filter?: string;
160
162
  session: boolean;
161
163
  json: boolean;
164
+ workspace?: string;
165
+ zone?: string;
162
166
  dev: boolean;
163
167
  }) => {
164
168
  try {
165
169
  const credentials = await getStoredCredentials();
166
- const baseUrl = getBaseUrl(credentials.zone, options.dev);
170
+
171
+ const effectiveWorkspace = options.workspace || credentials.workspace;
172
+ const effectiveZone = (options.zone?.toUpperCase() === 'EU' ? 'EU' : options.zone?.toUpperCase() === 'LA' ? 'LA' : credentials.zone) as 'LA' | 'EU';
173
+ const baseUrl = getBaseUrl(effectiveZone, options.dev);
174
+
175
+ if (options.workspace || options.zone) {
176
+ console.log(chalk.hex('#FFA726')(`\n Modo soporte: workspace=${effectiveWorkspace} zona=${effectiveZone}`));
177
+ }
167
178
 
168
179
  // Filtros iniciales
169
180
  const activeFilters: Set<string> = new Set(
@@ -177,9 +188,9 @@ export const monitorCommand = new Command('monitor')
177
188
  try {
178
189
  process.stdout.write(chalk.gray(' Conectando con agente...'));
179
190
  const agent = new Agent({
180
- workspaceId: credentials.workspace,
191
+ workspaceId: effectiveWorkspace,
181
192
  apiKey: credentials.apiKey,
182
- zone: credentials.zone,
193
+ zone: effectiveZone,
183
194
  ...(options.dev && { customUrl: 'http://localhost:5090' }),
184
195
  });
185
196
  const info: any = await agent.getAgentById({ id: options.agentId });
@@ -89,7 +89,7 @@ interface AgentExample {
89
89
  }
90
90
 
91
91
  const MODELS: Record<string, string[]> = {
92
- openai: ['gpt-4o', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'],
92
+ openai: ['gpt-4o', 'gpt-4o-mini', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'],
93
93
  claude: ['claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-haiku-20240307'],
94
94
  gemini: ['gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'],
95
95
  };
@@ -172,57 +172,87 @@ async function connectChannelFlow(ctx: WizardContext): Promise<AgentChannel[]> {
172
172
  const shortUrl = linkRes.data.data?.shortUrl || '';
173
173
  spinner.stop();
174
174
 
175
- // Mostrar link en box visual
175
+ // Mostrar link
176
176
  console.log();
177
- console.log(chalk.hex('#4CAF50')(' ┌' + '─'.repeat(64) + '┐'));
178
- console.log(chalk.hex('#4CAF50')(' │') + chalk.bold(` Envia este link para conectar ${channelLabel}:`).padEnd(74) + chalk.hex('#4CAF50')('│'));
179
- console.log(chalk.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk.hex('#4CAF50')('│'));
180
- console.log(chalk.hex('#4CAF50')(' ') + chalk.hex('#22d3ee')(` ${shortUrl}`).padEnd(74) + chalk.hex('#4CAF50')('│'));
181
- console.log(chalk.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk.hex('#4CAF50')('│'));
182
- console.log(chalk.hex('#4CAF50')(' └' + '─'.repeat(64) + '┘'));
177
+ console.log(chalk.hex('#4CAF50')(' ─'.repeat(32)));
178
+ console.log(chalk.bold(` Envia este link para conectar ${channelLabel}:`));
179
+ console.log();
180
+ console.log(' ' + chalk.hex('#22d3ee')(shortUrl));
181
+ console.log();
182
+ console.log(chalk.hex('#4CAF50')(' ─'.repeat(32)));
183
183
  console.log();
184
184
 
185
185
  // Snapshot de integraciones actuales
186
186
  let prevIntegrationIds: Set<string> = new Set();
187
187
  try {
188
188
  const wkRes = await axios.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
189
- const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
189
+ const integrations = wkRes.data?.integrations || [];
190
190
  prevIntegrationIds = new Set(integrations.map((i: any) => i.id));
191
191
  } catch {
192
192
  // Si falla, se parte de vacio
193
193
  }
194
194
 
195
- // Polling para detectar nueva integracion
196
- const pollSpinner = ora({ text: chalk.gray('Esperando conexion... (Ctrl+C para cancelar)'), spinner: 'dots', color: 'cyan' }).start();
195
+ // Polling para detectar nueva integracion (Enter para saltar)
196
+ const pollSpinner = ora({ text: chalk.gray('Esperando conexion... (Enter para saltar)'), spinner: 'dots', color: 'cyan' }).start();
197
197
  const POLL_INTERVAL = 5000;
198
198
  const MAX_POLLS = 60; // 5 minutos
199
199
  let detected: any = null;
200
+ let skipped = false;
201
+
202
+ // Escuchar Enter para saltar el polling
203
+ const skipPromise = new Promise<void>(resolve => {
204
+ const onData = (data: Buffer) => {
205
+ if (data.toString().includes('\n') || data.toString().includes('\r')) {
206
+ skipped = true;
207
+ process.stdin.removeListener('data', onData);
208
+ if (wasRaw) process.stdin.setRawMode(false);
209
+ resolve();
210
+ }
211
+ };
212
+ const wasRaw = process.stdin.isRaw;
213
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
214
+ process.stdin.resume();
215
+ process.stdin.on('data', onData);
216
+ // Limpiar si termina el polling naturalmente
217
+ setTimeout(() => {
218
+ process.stdin.removeListener('data', onData);
219
+ if (process.stdin.isTTY && wasRaw !== undefined) {
220
+ try { process.stdin.setRawMode(wasRaw); } catch {}
221
+ }
222
+ resolve();
223
+ }, POLL_INTERVAL * MAX_POLLS + 1000);
224
+ });
200
225
 
201
226
  for (let i = 0; i < MAX_POLLS; i++) {
202
- await new Promise(r => setTimeout(r, POLL_INTERVAL));
227
+ await Promise.race([
228
+ new Promise(r => setTimeout(r, POLL_INTERVAL)),
229
+ skipPromise,
230
+ ]);
231
+ if (skipped) break;
203
232
  try {
204
233
  const wkRes = await axios.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
205
- const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
234
+ const integrations = wkRes.data?.integrations || [];
206
235
 
207
- // Buscar integraciones nuevas del tipo correcto
208
- const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
209
- const newOnes = integrations.filter((ig: any) =>
210
- !prevIntegrationIds.has(ig.id) && ig.type === targetType
211
- );
236
+ // Buscar integraciones nuevas (cualquier ID que no existia antes)
237
+ const newOnes = integrations.filter((ig: any) => !prevIntegrationIds.has(ig.id));
212
238
 
213
239
  if (newOnes.length > 0) {
214
- detected = newOnes[0];
240
+ // Preferir la que coincida con el tipo solicitado
241
+ const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
242
+ const matchingNew = newOnes.find((ig: any) => ig.type === targetType);
243
+ detected = matchingNew || newOnes[0];
215
244
  break;
216
245
  }
217
246
  } catch {
218
247
  // Ignorar errores de poll individual
219
248
  }
220
249
  const elapsed = Math.floor(((i + 1) * POLL_INTERVAL) / 1000);
221
- pollSpinner.text = chalk.gray(`Esperando conexion... ${elapsed}s`);
250
+ pollSpinner.text = chalk.gray(`Esperando conexion... ${elapsed}s (Enter para saltar)`);
222
251
  }
223
252
 
224
253
  if (detected) {
225
- pollSpinner.succeed(chalk.hex('#4ade80')(`Conexion detectada: ${detected.aliasName || detected.id} (${channelLabel})`));
254
+ const detectedName = detected.aliasName || detected.cellphoneNumberFormat || detected.cellphoneNumber || detected.srcName || detected.id;
255
+ pollSpinner.succeed(chalk.hex('#4ade80')(`Conexion detectada: ${detectedName} (${channelLabel})`));
226
256
 
227
257
  const { associate } = await (inquirer as any).prompt([{
228
258
  type: 'confirm', name: 'associate',
@@ -238,7 +268,7 @@ async function connectChannelFlow(ctx: WizardContext): Promise<AgentChannel[]> {
238
268
  console.log(chalk.hex('#4ade80')(' Canal asociado correctamente.'));
239
269
  }
240
270
  } else {
241
- pollSpinner.warn(chalk.hex('#FFA726')('Timeout: no se detecto una conexion.'));
271
+ pollSpinner.warn(chalk.hex('#FFA726')(skipped ? 'Polling omitido.' : 'Timeout: no se detecto una conexion.'));
242
272
  const { action } = await (inquirer as any).prompt([{
243
273
  type: 'list', name: 'action',
244
274
  message: 'Que deseas hacer?',
@@ -551,16 +581,14 @@ export async function runAgentWizard(zone: string, workspaceId?: string, apiKey?
551
581
  const aiConfig = await (inquirer as any).prompt([
552
582
  { type: 'list', name: 'model', message: 'Modelo:', choices: models },
553
583
  { type: 'password', name: 'apiToken', message: 'API Token:', mask: '*', validate: (v: string) => v.length > 0 || 'Requerido' },
554
- { type: 'number', name: 'temperature', message: 'Temperatura (0-2):', default: 0.7 },
555
- { type: 'number', name: 'maxTokens', message: 'Max tokens (1024-16384):', default: 4096 },
556
584
  ]);
557
585
 
558
586
  aiProviders.push({
559
587
  provider: ai.provider,
560
588
  model: aiConfig.model,
561
589
  apiToken: aiConfig.apiToken,
562
- temperature: aiConfig.temperature,
563
- maxTokens: aiConfig.maxTokens,
590
+ temperature: 0.7,
591
+ maxTokens: 4096,
564
592
  isDefault: true,
565
593
  });
566
594
  }