elffuss-code / js /tools /index.js
KikoCis's picture
Elffuss Code — browser IDE with a local AI agent (WebGPU)
b30b7c5 verified
Raw
History Blame Contribute Delete
4.59 kB
// Registro de herramientas de Elffuss Code: proyecto abierto + shell + web.
import * as code from './code.js';
import * as shell from '../shell.js';
import * as web from './web.js';
export { code };
// El terminal (UI) se engancha aquí para reflejar lo que ejecuta la elfa.
let onTerminalEcho = () => {};
export function setTerminalEcho(fn) { onTerminalEcho = fn; }
export const TOOLS = {
'code.tree': { desc: 'Ver el árbol de archivos del proyecto', params: { path: 'subcarpeta (opcional)', depth: 'niveles (3)' }, run: a => code.tree(a) },
'code.read': { desc: 'Leer un archivo del proyecto. Sin más parámetros, lo lee ENTERO. Para ficheros grandes, pagina de 100 en 100 líneas con offset (offset:101 = siguiente página tras la primera). Para ir directo a donde dio un resultado de code.search (que ya incluye número de línea), usa around:N — trae ~100 líneas centradas en la línea N, con cada línea numerada (N→contenido) para poder citarla o editarla con precisión', params: { path: 'ruta relativa', offset: 'línea 1-based donde empezar (opcional)', limit: 'líneas a devolver, 100 por defecto (opcional)', around: 'centra la página en esta línea, p.ej. la que dio code.search (opcional)' }, run: a => code.read(a) },
'code.write': { desc: 'Escribir/crear un archivo (contenido COMPLETO; se refleja al instante en el editor). Para cambios PEQUEÑOS en un fichero YA existente, usa mejor code.edit', params: { path: 'ruta', content: 'contenido íntegro' }, run: a => code.write(a) },
'code.edit': { desc: 'Editar PARTE de un fichero existente sin reescribirlo entero: sustituye "search" (copia literal de unas pocas líneas, con contexto suficiente para ser única en el fichero) por "replace". Preferible a code.write para cambios pequeños/medianos — más rápido y sin riesgo de perder el resto del fichero. Si falla (no encuentra el punto con confianza), relee el fichero y reintenta con un search más ajustado', params: { path: 'ruta', search: 'texto exacto a sustituir', replace: 'texto nuevo' }, run: a => code.edit(a) },
'code.search': { desc: 'Buscar texto en el proyecto (grep)', params: { query: 'texto', ext: 'filtro extensión (opcional)' }, run: a => code.search(a) },
'terminal.run': { desc: 'Ejecutar un comando de shell sobre los ficheros del proyecto (ls, cat, grep, find, mkdir, echo>fichero, git status…). node/npm/python REALES si el usuario tiene un Bridge local conectado (⚙ Ajustes → 🔌 Bridge local); si no está conectado, el propio resultado lo indica', params: { command: 'la línea de comando' }, run: async a => { const out = await shell.runForAgent(a.command || ''); onTerminalEcho(a.command || '', out); return out; } },
'web.search': { desc: 'Buscar en internet (docs, errores, APIs) — devuelve títulos, URLs y fragmentos', params: { query: 'qué buscar' }, run: a => web.search(a) },
'web.fetch': { desc: 'Leer el contenido de texto de una URL (documentación, referencia)', params: { url: 'https://…' }, run: a => web.fetchUrl(a) },
};
export function toolHelp() {
return Object.entries(TOOLS).map(([n, t]) =>
`- ${n}(${Object.keys(t.params).join(', ')}): ${t.desc}`).join('\n');
}
export async function runTool(name, args) {
const tool = TOOLS[name];
if (!tool) throw new Error(`Herramienta desconocida: ${name}`);
return tool.run(args || {});
}
// CONTEXTO AHORA del IDE: proyecto, archivo abierto y árbol resumido.
export async function snapshot() {
const { projectName, currentFile } = code.current();
const parts = [
'Fecha y hora: ' + new Date().toLocaleString(),
'Proyecto abierto: ' + (projectName || 'ninguno'),
'Archivo abierto en el editor: ' + (currentFile || 'ninguno'),
];
try { parts.push('Árbol del proyecto (resumen):\n' + await code.tree({ depth: 2 })); }
catch { /* aún sin proyecto */ }
// GROUNDING: incluye el contenido REAL de los archivos clave (README, config)
// para que el modelo NO alucine sobre el proyecto — el heal no domina las
// herramientas code.* así que le damos el material masticado.
for (const key of ['README.md', 'readme.md', 'package.json', 'pyproject.toml', 'Cargo.toml', 'go.mod']) {
try { const body = await code.read({ path: key }); parts.push(`Contenido REAL de ${key}:\n${body.slice(0, 1400)}`); break; } catch { /* siguiente */ }
}
if (currentFile) {
try {
const body = await code.read({ path: currentFile });
parts.push(`Contenido REAL del archivo abierto ${currentFile}:\n` + body.slice(0, 2000));
} catch { /* borrado */ }
}
return parts.join('\n');
}