bimmo-cli 2.0.1 → 2.0.3
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/package.json +2 -2
- package/src/interface.js +134 -92
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bimmo-cli",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "🌿 Plataforma de
|
|
3
|
+
"version": "2.0.3",
|
|
4
|
+
"description": "🌿 Plataforma de IA universal com modo Normal, Agentes Especialistas e Enxames (Swarms). Suporte a Auto-Edit, Contexto Inteligente e interrupção inteligente.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"bimmo": "bin/bimmo"
|
|
7
7
|
},
|
package/src/interface.js
CHANGED
|
@@ -25,7 +25,10 @@ const gray = chalk.gray;
|
|
|
25
25
|
const bold = chalk.bold;
|
|
26
26
|
const yellow = chalk.yellow;
|
|
27
27
|
|
|
28
|
-
let currentMode = 'chat';
|
|
28
|
+
let currentMode = 'chat';
|
|
29
|
+
let activePersona = null;
|
|
30
|
+
let exitCounter = 0;
|
|
31
|
+
let exitTimer = null;
|
|
29
32
|
|
|
30
33
|
async function processInput(input) {
|
|
31
34
|
const parts = input.split(' ');
|
|
@@ -93,10 +96,11 @@ async function processInput(input) {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
function getModeStyle() {
|
|
99
|
+
const personaLabel = activePersona ? `[${activePersona.toUpperCase()}] ` : '';
|
|
96
100
|
switch (currentMode) {
|
|
97
|
-
case 'plan': return yellow.bold(
|
|
98
|
-
case 'edit': return chalk.red.bold(
|
|
99
|
-
default: return lavender.bold(
|
|
101
|
+
case 'plan': return yellow.bold(`${personaLabel}[PLAN] `);
|
|
102
|
+
case 'edit': return chalk.red.bold(`${personaLabel}[EDIT] `);
|
|
103
|
+
default: return lavender.bold(`${personaLabel}[CHAT] `);
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
106
|
|
|
@@ -112,37 +116,66 @@ export async function startInteractive() {
|
|
|
112
116
|
|
|
113
117
|
let provider = createProvider(config);
|
|
114
118
|
const orchestrator = new SwarmOrchestrator(config);
|
|
115
|
-
|
|
119
|
+
let messages = [];
|
|
120
|
+
|
|
121
|
+
const resetMessages = () => {
|
|
122
|
+
messages = [];
|
|
123
|
+
const projectContext = getProjectContext();
|
|
124
|
+
messages.push({ role: 'system', content: projectContext });
|
|
125
|
+
if (activePersona) {
|
|
126
|
+
const agent = (config.agents || {})[activePersona];
|
|
127
|
+
if (agent) {
|
|
128
|
+
messages.push({ role: 'system', content: `Sua persona atual é: ${agent.name}. Sua tarefa: ${agent.role}` });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
116
132
|
|
|
117
|
-
|
|
118
|
-
messages.push({
|
|
119
|
-
role: 'system',
|
|
120
|
-
content: projectContext
|
|
121
|
-
});
|
|
133
|
+
resetMessages();
|
|
122
134
|
|
|
123
135
|
console.clear();
|
|
124
136
|
console.log(lavender(figlet.textSync('bimmo')));
|
|
125
137
|
console.log(lavender('─'.repeat(60)));
|
|
126
|
-
console.log(green(` Perfil
|
|
138
|
+
console.log(green(` Perfil: ${bold(config.activeProfile || 'Padrão')} • IA: ${bold(config.provider.toUpperCase())}`));
|
|
127
139
|
console.log(green(` Modelo: ${bold(config.model)}`));
|
|
128
|
-
console.log(gray(' /chat | /plan | /edit | /swarm | /
|
|
140
|
+
console.log(gray(' /chat | /plan | /edit | /swarm | /use [agente] | /help'));
|
|
129
141
|
console.log(lavender('─'.repeat(60)) + '\n');
|
|
130
142
|
|
|
131
|
-
console.log(lavender('👋 Olá!
|
|
143
|
+
console.log(lavender('👋 Olá! Estou pronto. No que posso ajudar?\n'));
|
|
144
|
+
|
|
145
|
+
// Handler Global de SIGINT para o modo ocioso (Idle)
|
|
146
|
+
process.on('SIGINT', () => {
|
|
147
|
+
exitCounter++;
|
|
148
|
+
if (exitCounter === 1) {
|
|
149
|
+
console.log(gray('\n(Pressione Ctrl+C novamente para sair)'));
|
|
150
|
+
if (exitTimer) clearTimeout(exitTimer);
|
|
151
|
+
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(lavender('\n👋 BIMMO encerrando sessão. Até logo!\n'));
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
132
157
|
|
|
133
158
|
readline.emitKeypressEvents(process.stdin);
|
|
134
159
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
135
160
|
|
|
136
161
|
while (true) {
|
|
137
162
|
const modeIndicator = getModeStyle();
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
let input;
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const answers = await inquirer.prompt([
|
|
167
|
+
{
|
|
168
|
+
type: 'input',
|
|
169
|
+
name: 'input',
|
|
170
|
+
message: modeIndicator + green('Você'),
|
|
171
|
+
prefix: '→',
|
|
172
|
+
}
|
|
173
|
+
]);
|
|
174
|
+
input = answers.input;
|
|
175
|
+
} catch (e) {
|
|
176
|
+
// Inquirer joga erro no Ctrl+C se não for tratado
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
146
179
|
|
|
147
180
|
const rawInput = input.trim();
|
|
148
181
|
const cmd = rawInput.toLowerCase();
|
|
@@ -161,28 +194,41 @@ export async function startInteractive() {
|
|
|
161
194
|
if (profileName && switchProfile(profileName)) {
|
|
162
195
|
config = getConfig();
|
|
163
196
|
provider = createProvider(config);
|
|
164
|
-
console.log(green(`\n✓
|
|
165
|
-
|
|
166
|
-
} else {
|
|
167
|
-
console.log(chalk.red(`\n✖ Perfil "${profileName}" não encontrado.\n`));
|
|
197
|
+
console.log(green(`\n✓ Perfil "${bold(profileName)}" ativado!`));
|
|
198
|
+
continue;
|
|
168
199
|
}
|
|
200
|
+
console.log(chalk.red(`\n✖ Perfil não encontrado.\n`));
|
|
169
201
|
continue;
|
|
170
202
|
}
|
|
171
203
|
|
|
172
|
-
if (cmd.startsWith('/
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
204
|
+
if (cmd.startsWith('/use ')) {
|
|
205
|
+
const agentName = rawInput.split(' ')[1];
|
|
206
|
+
const agents = config.agents || {};
|
|
207
|
+
if (agentName === 'normal' || agentName === 'default') {
|
|
208
|
+
activePersona = null;
|
|
209
|
+
console.log(lavender(`\n✓ Voltando para o Modo Normal.\n`));
|
|
210
|
+
resetMessages();
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (agents[agentName]) {
|
|
214
|
+
activePersona = agentName;
|
|
215
|
+
const agent = agents[agentName];
|
|
216
|
+
if (switchProfile(agent.profile)) {
|
|
217
|
+
config = getConfig();
|
|
218
|
+
provider = createProvider(config);
|
|
219
|
+
}
|
|
220
|
+
currentMode = agent.mode || 'chat';
|
|
221
|
+
console.log(green(`\n✓ Agora você está falando com o Agente: ${bold(agentName)}`));
|
|
222
|
+
console.log(gray(` Task: ${agent.role.substring(0, 100)}...\n`));
|
|
223
|
+
resetMessages();
|
|
224
|
+
} else {
|
|
225
|
+
console.log(chalk.red(`\n✖ Agente "${agentName}" não encontrado.\n`));
|
|
179
226
|
}
|
|
180
227
|
continue;
|
|
181
228
|
}
|
|
182
229
|
|
|
183
230
|
if (cmd === '/clear') {
|
|
184
|
-
|
|
185
|
-
messages.push({ role: 'system', content: getProjectContext() });
|
|
231
|
+
resetMessages();
|
|
186
232
|
console.clear();
|
|
187
233
|
console.log(lavender('✓ Histórico limpo, contexto preservado.\n'));
|
|
188
234
|
continue;
|
|
@@ -190,14 +236,18 @@ export async function startInteractive() {
|
|
|
190
236
|
|
|
191
237
|
if (cmd === '/help') {
|
|
192
238
|
console.log(gray(`
|
|
193
|
-
Comandos
|
|
239
|
+
Comandos de Modo:
|
|
194
240
|
/chat /plan /edit → Mudar modo de operação
|
|
195
|
-
/
|
|
196
|
-
/
|
|
197
|
-
/swarm →
|
|
198
|
-
|
|
241
|
+
/use [agente] → Usar um Agente Especialista
|
|
242
|
+
/use normal → Voltar para o chat normal
|
|
243
|
+
/swarm → Rodar fluxos complexos
|
|
244
|
+
|
|
245
|
+
Gerenciamento:
|
|
246
|
+
/switch [nome] → Mudar perfil de IA completo
|
|
247
|
+
/model [nome] → Mudar modelo atual
|
|
248
|
+
/config → Perfis e Agentes
|
|
199
249
|
/init → Inicializar .bimmorc.json
|
|
200
|
-
@
|
|
250
|
+
@arquivo → Ler arquivo ou imagem
|
|
201
251
|
`));
|
|
202
252
|
continue;
|
|
203
253
|
}
|
|
@@ -207,56 +257,32 @@ Comandos Disponíveis:
|
|
|
207
257
|
if (cmd === '/swarm') {
|
|
208
258
|
const agents = config.agents || {};
|
|
209
259
|
const agentList = Object.keys(agents);
|
|
210
|
-
|
|
211
260
|
if (agentList.length < 2) {
|
|
212
|
-
console.log(chalk.yellow('\
|
|
261
|
+
console.log(chalk.yellow('\nCrie pelo menos 2 Agentes em /config primeiro.\n'));
|
|
213
262
|
continue;
|
|
214
263
|
}
|
|
215
|
-
|
|
216
264
|
const { swarmAction } = await inquirer.prompt([{
|
|
217
265
|
type: 'list',
|
|
218
266
|
name: 'swarmAction',
|
|
219
|
-
message: '
|
|
220
|
-
choices: ['
|
|
267
|
+
message: 'Tipo de Enxame:',
|
|
268
|
+
choices: ['Sequencial (A → B)', 'Hierárquico (Líder + Workers)', 'Voltar']
|
|
221
269
|
}]);
|
|
222
|
-
|
|
223
270
|
if (swarmAction === 'Voltar') continue;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
type: 'checkbox',
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
choices: agentList
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (selectedAgents.length < 2) {
|
|
236
|
-
console.log(chalk.red('\nSelecione pelo menos 2 agentes.\n'));
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
const finalResult = await orchestrator.runSequential(selectedAgents, goal);
|
|
242
|
-
console.log(lavender('\n=== RESULTADO FINAL DO ENXAME ===\n'));
|
|
243
|
-
console.log(marked(finalResult));
|
|
244
|
-
} catch (e) {
|
|
245
|
-
console.error(chalk.red(`\nErro no Enxame: ${e.message}`));
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (swarmAction === 'Rodar Enxame Hierárquico') {
|
|
250
|
-
const { manager } = await inquirer.prompt([{ type: 'list', name: 'manager', message: 'Selecione o Agente Líder (Manager):', choices: agentList }]);
|
|
251
|
-
const { workers } = await inquirer.prompt([{ type: 'checkbox', name: 'workers', message: 'Selecione os Workers:', choices: agentList.filter(a => a !== manager) }]);
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
const finalResult = await orchestrator.runHierarchical(manager, workers, goal);
|
|
255
|
-
console.log(lavender('\n=== RESULTADO FINAL DO ENXAME ===\n'));
|
|
256
|
-
console.log(marked(finalResult));
|
|
257
|
-
} catch (e) {
|
|
258
|
-
console.error(chalk.red(`\nErro no Enxame: ${e.message}`));
|
|
271
|
+
const { goal } = await inquirer.prompt([{ type: 'input', name: 'goal', message: 'Objetivo do enxame:' }]);
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
let result;
|
|
275
|
+
if (swarmAction.includes('Sequencial')) {
|
|
276
|
+
const { selectedAgents } = await inquirer.prompt([{ type: 'checkbox', name: 'selectedAgents', message: 'Ordem dos agentes:', choices: agentList }]);
|
|
277
|
+
result = await orchestrator.runSequential(selectedAgents, goal);
|
|
278
|
+
} else {
|
|
279
|
+
const { manager } = await inquirer.prompt([{ type: 'list', name: 'manager', message: 'Líder:', choices: agentList }]);
|
|
280
|
+
const { workers } = await inquirer.prompt([{ type: 'checkbox', name: 'workers', message: 'Workers:', choices: agentList.filter(a => a !== manager) }]);
|
|
281
|
+
result = await orchestrator.runHierarchical(manager, workers, goal);
|
|
259
282
|
}
|
|
283
|
+
console.log(lavender('\n=== RESULTADO FINAL ===\n') + marked(result));
|
|
284
|
+
} catch (e) {
|
|
285
|
+
console.error(chalk.red(`\nErro: ${e.message}`));
|
|
260
286
|
}
|
|
261
287
|
continue;
|
|
262
288
|
}
|
|
@@ -264,14 +290,19 @@ Comandos Disponíveis:
|
|
|
264
290
|
if (rawInput === '') continue;
|
|
265
291
|
|
|
266
292
|
const controller = new AbortController();
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
293
|
+
|
|
294
|
+
// Handler local para SIGINT durante o processamento da IA
|
|
295
|
+
const localInterruptHandler = () => {
|
|
296
|
+
controller.abort();
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// Remove temporariamente o handler global de saída
|
|
300
|
+
process.removeAllListeners('SIGINT');
|
|
301
|
+
process.on('SIGINT', localInterruptHandler);
|
|
271
302
|
|
|
272
303
|
let modeInstr = "";
|
|
273
|
-
if (currentMode === 'plan') modeInstr = "\n[MODO PLAN]
|
|
274
|
-
else if (currentMode === 'edit') modeInstr = "\n[MODO EDIT]
|
|
304
|
+
if (currentMode === 'plan') modeInstr = "\n[MODO PLAN] Apenas analise.";
|
|
305
|
+
else if (currentMode === 'edit') modeInstr = "\n[MODO EDIT] Aplique as mudanças agora.";
|
|
275
306
|
|
|
276
307
|
const content = await processInput(rawInput);
|
|
277
308
|
messages.push({
|
|
@@ -280,7 +311,7 @@ Comandos Disponíveis:
|
|
|
280
311
|
});
|
|
281
312
|
|
|
282
313
|
const spinner = ora({
|
|
283
|
-
text: lavender(`bimmo
|
|
314
|
+
text: lavender(`bimmo pensando... (Ctrl+C para interromper)`),
|
|
284
315
|
color: currentMode === 'edit' ? 'red' : 'magenta'
|
|
285
316
|
}).start();
|
|
286
317
|
|
|
@@ -299,11 +330,22 @@ Comandos Disponíveis:
|
|
|
299
330
|
console.log(yellow('\n\n⚠️ Operação interrompida pelo usuário.\n'));
|
|
300
331
|
messages.pop();
|
|
301
332
|
} else {
|
|
302
|
-
console.error(chalk.red('\n✖ Erro
|
|
333
|
+
console.error(chalk.red('\n✖ Erro:') + ' ' + err.message + '\n');
|
|
303
334
|
}
|
|
304
335
|
} finally {
|
|
305
|
-
|
|
306
|
-
process.
|
|
336
|
+
// Restaura o handler global de saída
|
|
337
|
+
process.removeListener('SIGINT', localInterruptHandler);
|
|
338
|
+
process.on('SIGINT', () => {
|
|
339
|
+
exitCounter++;
|
|
340
|
+
if (exitCounter === 1) {
|
|
341
|
+
console.log(gray('\n(Pressione Ctrl+C novamente para sair)'));
|
|
342
|
+
if (exitTimer) clearTimeout(exitTimer);
|
|
343
|
+
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
344
|
+
} else {
|
|
345
|
+
console.log(lavender('\n👋 BIMMO encerrando sessão. Até logo!\n'));
|
|
346
|
+
process.exit(0);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
307
349
|
}
|
|
308
350
|
}
|
|
309
|
-
}
|
|
351
|
+
}
|