bimmo-cli 4.0.4 → 4.0.6

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/interface.js +42 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bimmo-cli",
3
- "version": "4.0.4",
3
+ "version": "4.0.6",
4
4
  "description": "🌿 Plataforma de IA universal profissional com interface React (Ink) pura.",
5
5
  "bin": {
6
6
  "bimmo": "bin/bimmo"
package/src/interface.js CHANGED
@@ -90,12 +90,12 @@ const Message = ({ role, content, displayContent }) => {
90
90
  );
91
91
  };
92
92
 
93
- const AutocompleteSuggestions = ({ suggestions }) => (
93
+ const AutocompleteSuggestions = ({ suggestions, selectedIndex }) => (
94
94
  h(Box, { flexDirection: 'column', borderStyle: 'round', borderColor: THEME.border, paddingX: 1, marginBottom: 1 },
95
- h(Text, { color: THEME.gray, dimColor: true, italic: true }, 'Sugestões (TAB):'),
95
+ h(Text, { color: THEME.gray, dimColor: true, italic: true }, 'Sugestões (↑↓ navega, TAB seleciona):'),
96
96
  suggestions.map((f, i) => (
97
- h(Text, { key: i, color: i === 0 ? THEME.green : THEME.gray },
98
- `${f.isDir ? '📁' : '📄'} ${f.rel}${f.isDir ? '/' : ''}`
97
+ h(Text, { key: i, color: i === selectedIndex ? THEME.green : THEME.gray, bold: i === selectedIndex },
98
+ `${i === selectedIndex ? '› ' : ' '}${f.isDir ? '📁' : '📄'} ${f.rel}${f.isDir ? '/' : ''}`
99
99
  )
100
100
  ))
101
101
  )
@@ -128,6 +128,7 @@ const BimmoApp = ({ initialConfig }) => {
128
128
  const [messages, setMessages] = useState([]);
129
129
  const [staticMessages, setStaticMessages] = useState([]); // Para mensagens antigas
130
130
  const [input, setInput] = useState('');
131
+ const [selectedIndex, setSelectedIndex] = useState(0);
131
132
  const [isThinking, setIsThinking] = useState(false);
132
133
  const [thinkingMessage, setThinkingMessage] = useState('bimmo pensando...');
133
134
  const [exitCounter, setExitCounter] = useState(0);
@@ -151,18 +152,33 @@ const BimmoApp = ({ initialConfig }) => {
151
152
  const dir = p.includes('/') ? p.substring(0, p.lastIndexOf('/')) : '.';
152
153
  const filter = p.includes('/') ? p.substring(p.lastIndexOf('/') + 1) : p;
153
154
  const absDir = path.resolve(process.cwd(), dir);
154
- if (!fs.existsSync(absDir)) return [];
155
- return fs.readdirSync(absDir)
155
+ if (!fs.existsSync(absDir) || !fs.statSync(absDir).isDirectory()) return [];
156
+
157
+ const files = fs.readdirSync(absDir)
156
158
  .filter(f => f.startsWith(filter) && !f.startsWith('.') && f !== 'node_modules')
157
- .slice(0, 5)
158
- .map(f => ({
159
- name: f,
160
- isDir: fs.statSync(path.join(absDir, f)).isDirectory(),
161
- rel: path.join(dir === '.' ? '' : dir, f)
162
- }));
159
+ .map(f => {
160
+ const fullPath = path.join(absDir, f);
161
+ const isDir = fs.statSync(fullPath).isDirectory();
162
+ return {
163
+ name: f,
164
+ isDir,
165
+ rel: path.join(dir === '.' ? '' : dir, f)
166
+ };
167
+ });
168
+
169
+ // Ordena: pastas primeiro, depois arquivos
170
+ return files.sort((a, b) => {
171
+ if (a.isDir && !b.isDir) return -1;
172
+ if (!a.isDir && b.isDir) return 1;
173
+ return a.name.localeCompare(b.name);
174
+ }).slice(0, 10);
163
175
  } catch (e) { return []; }
164
176
  }, [input]);
165
177
 
178
+ useEffect(() => {
179
+ setSelectedIndex(0);
180
+ }, [filePreview.length]);
181
+
166
182
  const handleSubmit = async (val) => {
167
183
  const rawInput = val.trim();
168
184
  if (!rawInput) return;
@@ -278,10 +294,20 @@ const BimmoApp = ({ initialConfig }) => {
278
294
  }
279
295
  }
280
296
  if (key.tab && filePreview.length > 0) {
297
+ const selected = filePreview[selectedIndex] || filePreview[0];
281
298
  const words = input.split(' ');
282
- words[words.length - 1] = `@${filePreview[0].rel}${filePreview[0].isDir ? '/' : ''}`;
299
+ words[words.length - 1] = `@${selected.rel}${selected.isDir ? '/' : ''}`;
283
300
  setInput(words.join(' '));
284
301
  }
302
+
303
+ if (filePreview.length > 0) {
304
+ if (key.downArrow) {
305
+ setSelectedIndex(prev => (prev + 1) % filePreview.length);
306
+ }
307
+ if (key.upArrow) {
308
+ setSelectedIndex(prev => (prev - 1 + filePreview.length) % filePreview.length);
309
+ }
310
+ }
285
311
  });
286
312
 
287
313
  return (
@@ -300,10 +326,9 @@ const BimmoApp = ({ initialConfig }) => {
300
326
  )
301
327
  ),
302
328
 
303
- filePreview.length > 0 && h(AutocompleteSuggestions, { suggestions: filePreview }),
304
-
305
- h(Box, { borderStyle: 'round', borderColor: isThinking ? THEME.gray : THEME.lavender, paddingX: 1 },
306
- h(Text, { bold: true, color: mode === 'edit' ? THEME.red : mode === 'plan' ? THEME.cyan : THEME.lavender },
329
+ filePreview.length > 0 && h(AutocompleteSuggestions, { suggestions: filePreview, selectedIndex }),
330
+
331
+ h(Box, { borderStyle: 'round', borderColor: isThinking ? THEME.gray : THEME.lavender, paddingX: 1 }, h(Text, { bold: true, color: mode === 'edit' ? THEME.red : mode === 'plan' ? THEME.cyan : THEME.lavender },
307
332
  `${activePersona ? `[${activePersona.toUpperCase()}] ` : ''}› `
308
333
  ),
309
334
  h(TextInput, {