bimmo-cli 2.2.10 → 2.2.11
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 +36 -30
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bimmo-cli",
|
|
3
|
-
"version": "2.2.
|
|
4
|
-
"description": "🌿 Plataforma de IA universal profissional com Agentes e Swarms. Suporte a Autocomplete real-time
|
|
3
|
+
"version": "2.2.11",
|
|
4
|
+
"description": "🌿 Plataforma de IA universal profissional com Agentes e Swarms. Suporte a Autocomplete real-time robusto, Diffs e Contexto Inteligente.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"bimmo": "bin/bimmo"
|
|
7
7
|
},
|
package/src/interface.js
CHANGED
|
@@ -8,6 +8,7 @@ import path from 'path';
|
|
|
8
8
|
import mime from 'mime-types';
|
|
9
9
|
import readline from 'readline';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
|
+
import { stripVTControlCharacters } from 'util';
|
|
11
12
|
|
|
12
13
|
import { getConfig, configure, updateActiveModel, switchProfile } from './config.js';
|
|
13
14
|
import { createProvider } from './providers/factory.js';
|
|
@@ -39,9 +40,6 @@ let activePersona = null;
|
|
|
39
40
|
let exitCounter = 0;
|
|
40
41
|
let exitTimer = null;
|
|
41
42
|
|
|
42
|
-
/**
|
|
43
|
-
* Coleta arquivos para preview e completion (Nível Gemini-CLI)
|
|
44
|
-
*/
|
|
45
43
|
function getFilesForPreview(partialPath) {
|
|
46
44
|
try {
|
|
47
45
|
let p = partialPath.startsWith('@') ? partialPath.slice(1) : partialPath;
|
|
@@ -127,37 +125,44 @@ export async function startInteractive() {
|
|
|
127
125
|
|
|
128
126
|
const clearPreview = () => {
|
|
129
127
|
if (currentPreviewLines > 0) {
|
|
130
|
-
// Move para
|
|
128
|
+
// Move o cursor para o início da primeira linha de preview
|
|
129
|
+
readline.moveCursor(process.stdout, 0, 1);
|
|
131
130
|
for (let i = 0; i < currentPreviewLines; i++) {
|
|
132
|
-
process.stdout.write('\n');
|
|
133
131
|
readline.clearLine(process.stdout, 0);
|
|
132
|
+
readline.moveCursor(process.stdout, 0, 1);
|
|
134
133
|
}
|
|
135
|
-
|
|
134
|
+
// Volta o cursor para a posição original
|
|
135
|
+
readline.moveCursor(process.stdout, 0, -(currentPreviewLines + 1));
|
|
136
136
|
currentPreviewLines = 0;
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
const showPreview = () => {
|
|
141
|
-
clearPreview();
|
|
142
141
|
const words = rl.line.split(' ');
|
|
143
142
|
const lastWord = words[words.length - 1];
|
|
144
143
|
|
|
145
144
|
if (lastWord.startsWith('@')) {
|
|
146
145
|
const files = getFilesForPreview(lastWord);
|
|
147
146
|
if (files.length > 0) {
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
clearPreview();
|
|
148
|
+
const displayFiles = files.slice(0, 10);
|
|
150
149
|
|
|
150
|
+
// Move cursor para o final da linha atual e pula linha
|
|
151
151
|
process.stdout.write('\n');
|
|
152
|
-
const displayFiles = files.slice(0, 10);
|
|
153
152
|
displayFiles.forEach(f => {
|
|
154
153
|
process.stdout.write(gray(` ${f.isDir ? '📁' : '📄'} ${f.name}\n`));
|
|
155
154
|
});
|
|
156
|
-
currentPreviewLines = displayFiles.length
|
|
155
|
+
currentPreviewLines = displayFiles.length;
|
|
157
156
|
|
|
158
|
-
//
|
|
159
|
-
process.stdout
|
|
157
|
+
// Retorna o cursor para a posição exata de escrita
|
|
158
|
+
readline.moveCursor(process.stdout, 0, -(currentPreviewLines + 1));
|
|
159
|
+
const promptWidth = stripVTControlCharacters(rl.getPrompt()).length;
|
|
160
|
+
readline.cursorTo(process.stdout, (promptWidth + rl.line.length) % (process.stdout.columns || 80));
|
|
161
|
+
} else {
|
|
162
|
+
clearPreview();
|
|
160
163
|
}
|
|
164
|
+
} else {
|
|
165
|
+
clearPreview();
|
|
161
166
|
}
|
|
162
167
|
};
|
|
163
168
|
|
|
@@ -171,22 +176,7 @@ export async function startInteractive() {
|
|
|
171
176
|
rl.prompt();
|
|
172
177
|
};
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
if (key && (key.name === 'return' || key.name === 'enter')) return;
|
|
176
|
-
setImmediate(() => showPreview());
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
rl.on('SIGINT', () => {
|
|
180
|
-
if (exitCounter === 0) {
|
|
181
|
-
exitCounter++;
|
|
182
|
-
process.stdout.write(`\n${gray('(Pressione Ctrl+C novamente para sair)')}\n`);
|
|
183
|
-
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
184
|
-
displayPrompt();
|
|
185
|
-
} else { process.exit(0); }
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
displayPrompt();
|
|
189
|
-
|
|
179
|
+
// Escuta teclas de forma segura
|
|
190
180
|
rl.on('line', async (input) => {
|
|
191
181
|
clearPreview();
|
|
192
182
|
const rawInput = input.trim();
|
|
@@ -220,7 +210,6 @@ export async function startInteractive() {
|
|
|
220
210
|
// PROCESSAMENTO IA
|
|
221
211
|
const controller = new AbortController();
|
|
222
212
|
const abortHandler = () => controller.abort();
|
|
223
|
-
process.removeListener('SIGINT', () => {});
|
|
224
213
|
process.on('SIGINT', abortHandler);
|
|
225
214
|
|
|
226
215
|
let modeInstr = "";
|
|
@@ -258,4 +247,21 @@ export async function startInteractive() {
|
|
|
258
247
|
displayPrompt();
|
|
259
248
|
}
|
|
260
249
|
});
|
|
250
|
+
|
|
251
|
+
// Listener de tecla para o preview
|
|
252
|
+
process.stdin.on('keypress', (s, key) => {
|
|
253
|
+
if (key && (key.name === 'return' || key.name === 'enter')) return;
|
|
254
|
+
setImmediate(() => showPreview());
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
rl.on('SIGINT', () => {
|
|
258
|
+
if (exitCounter === 0) {
|
|
259
|
+
exitCounter++;
|
|
260
|
+
process.stdout.write(`\n${gray('(Pressione novamente para sair)')}\n`);
|
|
261
|
+
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
262
|
+
displayPrompt();
|
|
263
|
+
} else { process.exit(0); }
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
displayPrompt();
|
|
261
267
|
}
|