xonecode 0.5.0 → 0.6.0
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/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +32 -0
- package/apps/web/dist/assets/index-DBZTodio.js +477 -0
- package/apps/web/dist/assets/{index-BB3SamhR.css → index-rqecK6s2.css} +1 -1
- package/apps/web/dist/assets/{php-D_2--9WK.js → php-BBij3Lhc.js} +1 -1
- package/apps/web/dist/assets/{ruby-DSHSDbk1.js → ruby-Dq2YEaLo.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/cloudstudio/cloudstudioClient.js.map +1 -0
- package/dist/agent/{cloudstudioMcp.js → cloudstudio/cloudstudioMcp.js} +5 -5
- package/dist/agent/cloudstudio/cloudstudioMcp.js.map +1 -0
- package/dist/agent/{descarga.js → cloudstudio/descarga.js} +3 -3
- package/dist/agent/cloudstudio/descarga.js.map +1 -0
- package/dist/agent/cloudstudio/manifiesto.js.map +1 -0
- package/dist/agent/{subida.js → cloudstudio/subida.js} +3 -3
- package/dist/agent/cloudstudio/subida.js.map +1 -0
- package/dist/agent/{zip.js → cloudstudio/zip.js} +1 -1
- package/dist/agent/cloudstudio/zip.js.map +1 -0
- package/dist/agent/{authEnDisco.js → config/authEnDisco.js} +3 -3
- package/dist/agent/config/authEnDisco.js.map +1 -0
- package/dist/agent/{catalogoModelos.js → config/catalogoModelos.js} +2 -1
- package/dist/agent/config/catalogoModelos.js.map +1 -0
- package/dist/agent/{configEnDisco.js → config/configEnDisco.js} +6 -6
- package/dist/agent/config/configEnDisco.js.map +1 -0
- package/dist/agent/{crearProyecto.js → config/crearProyecto.js} +2 -2
- package/dist/agent/config/crearProyecto.js.map +1 -0
- package/dist/agent/config/entorno.js.map +1 -0
- package/dist/agent/config/gemini.js.map +1 -0
- package/dist/agent/{modelos.js → config/modelos.js} +17 -3
- package/dist/agent/config/modelos.js.map +1 -0
- package/dist/agent/{modelosDeMotor.js → config/modelosDeMotor.js} +1 -1
- package/dist/agent/config/modelosDeMotor.js.map +1 -0
- package/dist/agent/{persona.js → config/persona.js} +1 -1
- package/dist/agent/config/persona.js.map +1 -0
- package/dist/agent/{settingsEnDisco.js → config/settingsEnDisco.js} +2 -2
- package/dist/agent/config/settingsEnDisco.js.map +1 -0
- package/dist/agent/{versionEnDisco.js → config/versionEnDisco.js} +8 -4
- package/dist/agent/config/versionEnDisco.js.map +1 -0
- package/dist/agent/dispositivos/arranqueDeEmulador.js +146 -0
- package/dist/agent/dispositivos/arranqueDeEmulador.js.map +1 -0
- package/dist/agent/{dispositivosEnMaquina.js → dispositivos/dispositivosEnMaquina.js} +93 -6
- package/dist/agent/dispositivos/dispositivosEnMaquina.js.map +1 -0
- package/dist/agent/dispositivos/hotswap.js.map +1 -0
- package/dist/agent/dispositivos/instalacionEnMaquina.js.map +1 -0
- package/dist/agent/{lanzamientoEnMaquina.js → dispositivos/lanzamientoEnMaquina.js} +1 -1
- package/dist/agent/dispositivos/lanzamientoEnMaquina.js.map +1 -0
- package/dist/agent/{paqueteDelProyecto.js → dispositivos/paqueteDelProyecto.js} +5 -5
- package/dist/agent/dispositivos/paqueteDelProyecto.js.map +1 -0
- package/dist/agent/dispositivos/procesosEnMaquina.js.map +1 -0
- package/dist/agent/{arbolDeProyecto.js → grafo/arbolDeProyecto.js} +2 -2
- package/dist/agent/grafo/arbolDeProyecto.js.map +1 -0
- package/dist/agent/{artefactosEnDisco.js → grafo/artefactosEnDisco.js} +2 -2
- package/dist/agent/grafo/artefactosEnDisco.js.map +1 -0
- package/dist/agent/{busquedaRegex.js → grafo/busquedaRegex.js} +41 -1
- package/dist/agent/grafo/busquedaRegex.js.map +1 -0
- package/dist/agent/grafo/excluirTools.js +82 -0
- package/dist/agent/grafo/excluirTools.js.map +1 -0
- package/dist/agent/{memoriaDeProyecto.js → grafo/memoriaDeProyecto.js} +1 -1
- package/dist/agent/grafo/memoriaDeProyecto.js.map +1 -0
- package/dist/agent/grafo/navegacionXone.js +198 -0
- package/dist/agent/grafo/navegacionXone.js.map +1 -0
- package/dist/agent/{perfiles.js → grafo/perfiles.js} +51 -8
- package/dist/agent/grafo/perfiles.js.map +1 -0
- package/dist/agent/{proyecto.js → grafo/proyecto.js} +207 -24
- package/dist/agent/grafo/proyecto.js.map +1 -0
- package/dist/agent/grafo/skills.js +393 -0
- package/dist/agent/grafo/skills.js.map +1 -0
- package/dist/agent/{xoneAgent.js → grafo/xoneAgent.js} +196 -67
- package/dist/agent/grafo/xoneAgent.js.map +1 -0
- package/dist/agent/navegacion/indiceEnDisco.js +21 -0
- package/dist/agent/navegacion/indiceEnDisco.js.map +1 -0
- package/dist/agent/navegacion/modeloDeProyecto.js +228 -0
- package/dist/agent/navegacion/modeloDeProyecto.js.map +1 -0
- package/dist/agent/raizDelPaquete.js +56 -0
- package/dist/agent/raizDelPaquete.js.map +1 -0
- package/dist/agent/{checkpointer.js → sesiones/checkpointer.js} +2 -2
- package/dist/agent/sesiones/checkpointer.js.map +1 -0
- package/dist/agent/sesiones/git.js.map +1 -0
- package/dist/agent/{gitSync.js → sesiones/gitSync.js} +3 -3
- package/dist/agent/sesiones/gitSync.js.map +1 -0
- package/dist/agent/{sesionGit.js → sesiones/sesionGit.js} +2 -2
- package/dist/agent/sesiones/sesionGit.js.map +1 -0
- package/dist/agent/{agentesEnDisco.js → subagentes/agentesEnDisco.js} +304 -86
- package/dist/agent/subagentes/agentesEnDisco.js.map +1 -0
- package/dist/agent/subagentes/consumoExterno.js.map +1 -0
- package/dist/agent/subagentes/escrituraDeCodex.js.map +1 -0
- package/dist/agent/{escrituraDeOpencode.js → subagentes/escrituraDeOpencode.js} +1 -1
- package/dist/agent/subagentes/escrituraDeOpencode.js.map +1 -0
- package/dist/agent/{escrituraExterna.js → subagentes/escrituraExterna.js} +6 -6
- package/dist/agent/subagentes/escrituraExterna.js.map +1 -0
- package/dist/agent/subagentes/subagenteCodex.js.map +1 -0
- package/dist/agent/subagentes/subagenteExterno.js.map +1 -0
- package/dist/agent/subagentes/subagenteOpencode.js.map +1 -0
- package/dist/agent/{aumentador.js → tareas/aumentador.js} +2 -2
- package/dist/agent/tareas/aumentador.js.map +1 -0
- package/dist/agent/{juezDeTarea.js → tareas/juezDeTarea.js} +5 -5
- package/dist/agent/tareas/juezDeTarea.js.map +1 -0
- package/dist/agent/{tareasEnDisco.js → tareas/tareasEnDisco.js} +4 -4
- package/dist/agent/tareas/tareasEnDisco.js.map +1 -0
- package/dist/agent/turno/diagnosticoDeTools.js.map +1 -0
- package/dist/agent/{guionizado.js → turno/guionizado.js} +1 -1
- package/dist/agent/turno/guionizado.js.map +1 -0
- package/dist/agent/turno/informeDeTraza.js +222 -0
- package/dist/agent/turno/informeDeTraza.js.map +1 -0
- package/dist/agent/turno/inspectorDePrompt.js +205 -0
- package/dist/agent/turno/inspectorDePrompt.js.map +1 -0
- package/dist/agent/{instantanea.js → turno/instantanea.js} +7 -2
- package/dist/agent/turno/instantanea.js.map +1 -0
- package/dist/agent/{interrupts.js → turno/interrupts.js} +2 -2
- package/dist/agent/turno/interrupts.js.map +1 -0
- package/dist/agent/turno/mensajes.js.map +1 -0
- package/dist/agent/turno/normalizar.js.map +1 -0
- package/dist/agent/{puente.js → turno/puente.js} +47 -3
- package/dist/agent/turno/puente.js.map +1 -0
- package/dist/agent/turno/resumenDeContexto.js +176 -0
- package/dist/agent/turno/resumenDeContexto.js.map +1 -0
- package/dist/agent/{resumenDeTool.js → turno/resumenDeTool.js} +15 -0
- package/dist/agent/turno/resumenDeTool.js.map +1 -0
- package/dist/agent/turno/textoDeTool.js.map +1 -0
- package/dist/agent/{turnoReal.js → turno/turnoReal.js} +38 -14
- package/dist/agent/turno/turnoReal.js.map +1 -0
- package/dist/agent/turno/verificador.js.map +1 -0
- package/dist/cli/config.js +1 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/consola.js +9 -9
- package/dist/cli/consola.js.map +1 -1
- package/dist/cli/describe.js +2 -2
- package/dist/cli/describe.js.map +1 -1
- package/dist/cli/doctor.js +1 -1
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/fuentesDeDisco.js +29 -0
- package/dist/cli/fuentesDeDisco.js.map +1 -0
- package/dist/cli/main.js +37 -28
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/run.js +32 -10
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/traza.js +48 -0
- package/dist/cli/traza.js.map +1 -0
- package/dist/cli/tui/correrTui.js +4 -4
- package/dist/cli/tui/correrTui.js.map +1 -1
- package/dist/cli/verify.js +1 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/core/actos.js +1 -1
- package/dist/core/adjuntos.js +2 -2
- package/dist/core/agentes.js +145 -7
- package/dist/core/agentes.js.map +1 -1
- package/dist/core/artefactos.js +4 -4
- package/dist/core/config.js +1 -1
- package/dist/core/contextos.js +12 -1
- package/dist/core/contextos.js.map +1 -1
- package/dist/core/descargas.js +1 -1
- package/dist/core/dispositivos.js +53 -3
- package/dist/core/dispositivos.js.map +1 -1
- package/dist/core/esqueleto.js +1 -1
- package/dist/core/modelos.js +16 -3
- package/dist/core/modelos.js.map +1 -1
- package/dist/core/navegacion.js +134 -0
- package/dist/core/navegacion.js.map +1 -0
- package/dist/core/notify.js +5 -0
- package/dist/core/notify.js.map +1 -1
- package/dist/core/planDeSubida.js +1 -1
- package/dist/core/settings.js +2 -2
- package/dist/core/shellDeAgente.js +99 -0
- package/dist/core/shellDeAgente.js.map +1 -0
- package/dist/core/skills.js +158 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/zipDeSkill.js +107 -0
- package/dist/core/zipDeSkill.js.map +1 -0
- package/dist/vendor/sqliteSaver.js +389 -0
- package/dist/vendor/sqliteSaver.js.map +1 -0
- package/dist/web/servidor/arranque.js +531 -47
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/corredorDeTareas.js +3 -3
- package/dist/web/servidor/corredorDeTareas.js.map +1 -1
- package/dist/web/servidor/sesiones.js +4 -4
- package/dist/web/servidor/transporte.js +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +7 -7
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +9 -5
- package/skills/archify/SKILL.md +25 -2
- package/skills/artifacts-builder/SKILL.md +23 -0
- package/skills/xone-hotswap/SKILL.md +74 -0
- package/skills/xone-hotswap/scripts/xone-arrancar-ios +85 -0
- package/skills/xone-hotswap/scripts/xone-desplegar-android +411 -0
- package/skills/xone-hotswap/scripts/xone-hotswap +171 -0
- package/skills/xone-hotswap/scripts/xone-log-android +102 -0
- package/skills/xone-hotswap/scripts/xone-reiniciar-android +104 -0
- package/apps/web/dist/assets/index-CFYAoHdw.js +0 -477
- package/dist/agent/agentesEnDisco.js.map +0 -1
- package/dist/agent/arbolDeProyecto.js.map +0 -1
- package/dist/agent/artefactosEnDisco.js.map +0 -1
- package/dist/agent/aumentador.js.map +0 -1
- package/dist/agent/authEnDisco.js.map +0 -1
- package/dist/agent/busquedaRegex.js.map +0 -1
- package/dist/agent/catalogoModelos.js.map +0 -1
- package/dist/agent/checkpointer.js.map +0 -1
- package/dist/agent/cloudstudioClient.js.map +0 -1
- package/dist/agent/cloudstudioMcp.js.map +0 -1
- package/dist/agent/configEnDisco.js.map +0 -1
- package/dist/agent/consumoExterno.js.map +0 -1
- package/dist/agent/crearProyecto.js.map +0 -1
- package/dist/agent/descarga.js.map +0 -1
- package/dist/agent/diagnosticoDeTools.js.map +0 -1
- package/dist/agent/dispositivosEnMaquina.js.map +0 -1
- package/dist/agent/entorno.js.map +0 -1
- package/dist/agent/escrituraDeCodex.js.map +0 -1
- package/dist/agent/escrituraDeOpencode.js.map +0 -1
- package/dist/agent/escrituraExterna.js.map +0 -1
- package/dist/agent/gemini.js.map +0 -1
- package/dist/agent/git.js.map +0 -1
- package/dist/agent/gitSync.js.map +0 -1
- package/dist/agent/guionizado.js.map +0 -1
- package/dist/agent/hotswap.js.map +0 -1
- package/dist/agent/instalacionEnMaquina.js.map +0 -1
- package/dist/agent/instantanea.js.map +0 -1
- package/dist/agent/interrupts.js.map +0 -1
- package/dist/agent/juezDeTarea.js.map +0 -1
- package/dist/agent/lanzamientoEnMaquina.js.map +0 -1
- package/dist/agent/manifiesto.js.map +0 -1
- package/dist/agent/memoriaDeProyecto.js.map +0 -1
- package/dist/agent/mensajes.js.map +0 -1
- package/dist/agent/modelos.js.map +0 -1
- package/dist/agent/modelosDeMotor.js.map +0 -1
- package/dist/agent/normalizar.js.map +0 -1
- package/dist/agent/paqueteDelProyecto.js.map +0 -1
- package/dist/agent/perfiles.js.map +0 -1
- package/dist/agent/persona.js.map +0 -1
- package/dist/agent/procesosEnMaquina.js.map +0 -1
- package/dist/agent/proyecto.js.map +0 -1
- package/dist/agent/puente.js.map +0 -1
- package/dist/agent/resumenDeContexto.js +0 -30
- package/dist/agent/resumenDeContexto.js.map +0 -1
- package/dist/agent/resumenDeTool.js.map +0 -1
- package/dist/agent/sesionGit.js.map +0 -1
- package/dist/agent/settingsEnDisco.js.map +0 -1
- package/dist/agent/skills.js +0 -65
- package/dist/agent/skills.js.map +0 -1
- package/dist/agent/subagenteCodex.js.map +0 -1
- package/dist/agent/subagenteExterno.js.map +0 -1
- package/dist/agent/subagenteOpencode.js.map +0 -1
- package/dist/agent/subida.js.map +0 -1
- package/dist/agent/tareasEnDisco.js.map +0 -1
- package/dist/agent/textoDeTool.js.map +0 -1
- package/dist/agent/turnoReal.js.map +0 -1
- package/dist/agent/verificador.js.map +0 -1
- package/dist/agent/versionEnDisco.js.map +0 -1
- package/dist/agent/xoneAgent.js.map +0 -1
- package/dist/agent/zip.js.map +0 -1
- /package/dist/agent/{cloudstudioClient.js → cloudstudio/cloudstudioClient.js} +0 -0
- /package/dist/agent/{manifiesto.js → cloudstudio/manifiesto.js} +0 -0
- /package/dist/agent/{entorno.js → config/entorno.js} +0 -0
- /package/dist/agent/{gemini.js → config/gemini.js} +0 -0
- /package/dist/agent/{hotswap.js → dispositivos/hotswap.js} +0 -0
- /package/dist/agent/{instalacionEnMaquina.js → dispositivos/instalacionEnMaquina.js} +0 -0
- /package/dist/agent/{procesosEnMaquina.js → dispositivos/procesosEnMaquina.js} +0 -0
- /package/dist/agent/{git.js → sesiones/git.js} +0 -0
- /package/dist/agent/{consumoExterno.js → subagentes/consumoExterno.js} +0 -0
- /package/dist/agent/{escrituraDeCodex.js → subagentes/escrituraDeCodex.js} +0 -0
- /package/dist/agent/{subagenteCodex.js → subagentes/subagenteCodex.js} +0 -0
- /package/dist/agent/{subagenteExterno.js → subagentes/subagenteExterno.js} +0 -0
- /package/dist/agent/{subagenteOpencode.js → subagentes/subagenteOpencode.js} +0 -0
- /package/dist/agent/{diagnosticoDeTools.js → turno/diagnosticoDeTools.js} +0 -0
- /package/dist/agent/{mensajes.js → turno/mensajes.js} +0 -0
- /package/dist/agent/{normalizar.js → turno/normalizar.js} +0 -0
- /package/dist/agent/{textoDeTool.js → turno/textoDeTool.js} +0 -0
- /package/dist/agent/{verificador.js → turno/verificador.js} +0 -0
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { createDeepAgent, createFilesystemMiddleware } from "deepagents";
|
|
2
|
-
import { promptDeAgente, repartirSkills } from "
|
|
2
|
+
import { MAPA_DEL_PROYECTO, promptDeAgente, repartirSkills } from "../../core/agentes.js";
|
|
3
3
|
import { RunnableLambda } from "@langchain/core/runnables";
|
|
4
4
|
import { AIMessage } from "@langchain/core/messages";
|
|
5
5
|
import { MemorySaver } from "@langchain/langgraph";
|
|
6
|
-
import { backendDeAgente } from "./proyecto.js";
|
|
7
|
-
import { permisosDe, hitlDe } from "./perfiles.js";
|
|
6
|
+
import { backendDeAgente, entornoDeLaShellDelProyecto } from "./proyecto.js";
|
|
7
|
+
import { permisosDe, hitlDe, montajeDeFicheros, puedeEjecutar } from "./perfiles.js";
|
|
8
8
|
import { crearBusquedaRegex } from "./busquedaRegex.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
9
|
+
import { crearNavegacionXone } from "./navegacionXone.js";
|
|
10
|
+
import { indiceEnDisco } from "../navegacion/indiceEnDisco.js";
|
|
11
|
+
import { inventarioDelProyecto } from "../subagentes/escrituraExterna.js";
|
|
12
|
+
import { middlewareTextoDeTool } from "../turno/textoDeTool.js";
|
|
13
|
+
import { resumenConEncargo, topeDeLlamadas, topeDeTools } from "../turno/resumenDeContexto.js";
|
|
14
|
+
import { inspectorDePrompt } from "../turno/inspectorDePrompt.js";
|
|
15
|
+
import { excluirTools, toolsQueNoUsa } from "./excluirTools.js";
|
|
16
|
+
import { createTokenTrackingMiddleware, } from "../../vendor/tokenTracking.js";
|
|
13
17
|
/**
|
|
14
18
|
* El prompt del orquestador, GENERADO a partir de los subagentes que hay.
|
|
15
19
|
*
|
|
@@ -36,17 +40,32 @@ export function promptOrquestador(agentes) {
|
|
|
36
40
|
const hay = (n) => agentes.some((a) => a.nombre === n);
|
|
37
41
|
return [
|
|
38
42
|
"Eres el orquestador de un harness de desarrollo para la plataforma XOne.",
|
|
43
|
+
// El mapa lo ve él TAMBIÉN, y no solo los especialistas: desde que contesta lo que puede
|
|
44
|
+
// en vez de delegarlo todo, es quien más lo necesita.
|
|
45
|
+
MAPA_DEL_PROYECTO,
|
|
39
46
|
// Decía «NO tienes herramientas», y era falso: tiene las seis de fichero. Ahora son de
|
|
40
47
|
// SOLO LECTURA (`PERFIL_DEL_ORQUESTADOR`), así que la frase dice lo que de verdad puede.
|
|
41
|
-
|
|
48
|
+
//
|
|
49
|
+
// Y decía «tu único trabajo es delegar», que era falso por el otro lado y CARO: medido con
|
|
50
|
+
// el banco (`docs/bancos/2026-09-17-base.json`), la misma pregunta de estructura costaba
|
|
51
|
+
// 9.462 tokens contestada aquí y 38.198 delegada, con la MISMA respuesta buena. Delegar es
|
|
52
|
+
// un viaje entero de ida y vuelta con el prompt de un especialista detrás, así que para lo
|
|
53
|
+
// que se resuelve con un `grep` no compra nada. La regla es explícita en las dos
|
|
54
|
+
// direcciones porque «puedes leer» a secas no le quitaba la orden de delegar siempre.
|
|
55
|
+
"NO tienes herramientas para MODIFICAR nada, pero SÍ para LEER y BUSCAR.",
|
|
56
|
+
"Si la pregunta se contesta mirando el proyecto —dónde se declara algo, qué colecciones hay,",
|
|
57
|
+
"qué valor tiene un atributo, qué fichero incluye a cuál—, CONTÉSTALA TÚ: busca con `grep` y",
|
|
58
|
+
"lee lo justo. Delegar cuesta varias veces más y no la contesta mejor.",
|
|
59
|
+
"Delega cuando haya que ESCRIBIR ficheros (tú no puedes), cuando el encargo tenga varios",
|
|
60
|
+
"pasos, o cuando haga falta el criterio de un especialista.",
|
|
42
61
|
agentes.length === 0
|
|
43
62
|
? "AVISO: ahora mismo no hay ningún especialista dado de alta, así que no puedes delegar en nadie. Dilo en vez de intentar resolverlo tú."
|
|
44
63
|
: `Los especialistas disponibles son: ${agentes.map((a) => a.nombre).join(", ")}. Elige por su descripción.`,
|
|
45
|
-
hay("
|
|
46
|
-
? "Para diagramas o esquemas de la app, delega en `
|
|
64
|
+
hay("analyst-xone") && hay("designer-xone")
|
|
65
|
+
? "Para diagramas o esquemas de la app, delega en `designer-xone`; si deben reflejar el código real, encarga PRIMERO el análisis a `analyst-xone` y usa su resultado antes de dibujar."
|
|
47
66
|
: "",
|
|
48
67
|
"Los especialistas no comparten el transcript: al encadenarlos, incluye en la descripción",
|
|
49
|
-
"de la siguiente `task` un bloque `HANDOFF DE
|
|
68
|
+
"de la siguiente `task` un bloque `HANDOFF DE ANÁLISIS` compacto con los hechos verificados,",
|
|
50
69
|
"rutas/evidencias y lagunas. No pidas al siguiente especialista redescubrir esos hechos.",
|
|
51
70
|
"Cuando varias tareas sean independientes, delégalas EN EL MISMO mensaje para",
|
|
52
71
|
"que corran a la vez.",
|
|
@@ -61,13 +80,23 @@ export function promptOrquestador(agentes) {
|
|
|
61
80
|
* No crean herramientas ni rebajan permisos: hacen explícito el destino correcto
|
|
62
81
|
* para que una skill no confunda su propia carpeta de instrucciones con la salida.
|
|
63
82
|
*/
|
|
83
|
+
/**
|
|
84
|
+
* **`read_file` NO está aquí, y es deliberado.**
|
|
85
|
+
*
|
|
86
|
+
* Una descripción propia REEMPLAZA la de la librería, no se suma a ella, así que la nuestra
|
|
87
|
+
* —que solo hablaba de coste— borraba tres cosas que deepagents ya dice y que no son nuestras
|
|
88
|
+
* de decir: que la salida lleva una cabecera de formato **que no hay que reinyectar al
|
|
89
|
+
* editar** (eso es CORRECCIÓN, no ahorro), que conviene pedir varias lecturas en una misma
|
|
90
|
+
* respuesta, y que un resultado grande se descarga a `/large_tool_results/` y se pagina desde
|
|
91
|
+
* ahí. Medido al comparar dos parches suyos: entre `1.13.2` y `1.13.5` ese formato CAMBIÓ
|
|
92
|
+
* —de prefijos de número de línea a una cabecera `@@ … @@`— y con él la advertencia. Una copia
|
|
93
|
+
* nuestra habría quedado describiendo un formato que ya no existe, sin un error que leer.
|
|
94
|
+
*
|
|
95
|
+
* La regla: lo que describe la TOOL es de la librería y se actualiza con ella; lo que decimos
|
|
96
|
+
* nosotros es cómo QUEREMOS usarla, y eso vive en el prompt del especialista
|
|
97
|
+
* (`core/agentes.ts#promptDeAgente`), donde no compite con nada.
|
|
98
|
+
*/
|
|
64
99
|
export const DESCRIPCIONES_FICHEROS = {
|
|
65
|
-
read_file: [
|
|
66
|
-
"Lee únicamente el fragmento de un fichero necesario para responder.",
|
|
67
|
-
"Indica siempre `offset` y `limit`; para el reconocimiento inicial usa",
|
|
68
|
-
"`offset=0, limit=50`. No releas la misma ruta y el mismo rango: usa la",
|
|
69
|
-
"evidencia ya obtenida o una página distinta solo si hace falta.",
|
|
70
|
-
].join(" "),
|
|
71
100
|
write_file: [
|
|
72
101
|
"Escribe un fichero del proyecto en una ruta absoluta.",
|
|
73
102
|
"Para diagramas, esquemas, arquitecturas y flujos: carga primero la skill `archify`;",
|
|
@@ -89,9 +118,11 @@ export const DESCRIPCIONES_FICHEROS = {
|
|
|
89
118
|
"Busca texto LITERAL (no regex) de forma progresiva para ahorrar contexto.",
|
|
90
119
|
"Primero acota con `path` y `glob`; para localizar candidatos usa",
|
|
91
120
|
"`output_mode=\"files_with_matches\"` o `output_mode=\"count\"`.",
|
|
92
|
-
"Usa `output_mode=\"content\"` solo con un patrón específico y
|
|
93
|
-
"
|
|
121
|
+
"Usa `output_mode=\"content\"` solo con un patrón específico: devuelve la ruta y el NÚMERO",
|
|
122
|
+
"DE LÍNEA de cada coincidencia, así que lee después con `read_file` ALREDEDOR de esa línea",
|
|
123
|
+
"(`offset` = línea menos 5), nunca desde el principio del fichero. La búsqueda devuelve",
|
|
94
124
|
"como máximo 100 coincidencias salvo que justifiques subir `max_count`.",
|
|
125
|
+
"Varias búsquedas independientes van en el MISMO mensaje, igual que las lecturas.",
|
|
95
126
|
].join(" "),
|
|
96
127
|
};
|
|
97
128
|
/**
|
|
@@ -107,7 +138,7 @@ export const DESCRIPCIONES_FICHEROS = {
|
|
|
107
138
|
* no consume toda la ventana antes de que actúe el resumen de conversación.
|
|
108
139
|
*
|
|
109
140
|
* **Esa carpeta se monta FUERA del proyecto** (`core/descargas.ts`,
|
|
110
|
-
* `agent/proyecto.ts#backendConDescargas`), y hasta el 10-09-2026 no: la escribe la librería
|
|
141
|
+
* `agent/grafo/proyecto.ts#backendConDescargas`), y hasta el 10-09-2026 no: la escribe la librería
|
|
111
142
|
* llamando al backend directamente, esa ruta no estaba montada en ninguna parte y caía en el
|
|
112
143
|
* `FilesystemBackend` de la raíz. Medido en el AppDemo real del usuario, 26 KB de salida
|
|
113
144
|
* cruda de una tool dentro de la app XOne y commiteados. Bajar este tope no era el arreglo:
|
|
@@ -132,16 +163,50 @@ export const OPCIONES_BUSQUEDA_FICHEROS = {
|
|
|
132
163
|
* ocupar el nombre lo sustituye en el catálogo (`agent/generalPurpose.test.ts`).
|
|
133
164
|
* 4. **El HITL va en las tools de fichero**, que en la v1 son las que escriben.
|
|
134
165
|
*/
|
|
166
|
+
/** El inspector, o nada: `inspectorDePrompt` devuelve `undefined` si no se ha pedido. */
|
|
167
|
+
function inspector(raiz, origen) {
|
|
168
|
+
const mw = inspectorDePrompt(raiz, origen);
|
|
169
|
+
return mw === undefined ? [] : [mw];
|
|
170
|
+
}
|
|
135
171
|
export async function construirAgente(opciones) {
|
|
136
172
|
// Las cuatro capas y su orden están en `backendDeAgente`, que vive en `proyecto.ts` para
|
|
137
173
|
// poder PROBARSE: aquí no había forma, porque `construirAgente` se simula en todos los
|
|
138
174
|
// tests que lo tocan y el cableado se quedaba sin nadie mirándolo.
|
|
139
|
-
|
|
175
|
+
/**
|
|
176
|
+
* El cargador del índice de navegación, con la RAÍZ ya fijada.
|
|
177
|
+
*
|
|
178
|
+
* Entra por opción para poder doblarse en un test, y con su omisión real puesta aquí —no en
|
|
179
|
+
* el llamador— por el patrón de fallo de siempre: compuesto arriba, en un cierre que todos
|
|
180
|
+
* los tests simulan, el cableado quedaría escrito y sin probar. `xoneAgent.navegacion.test.ts`
|
|
181
|
+
* lo mira desde fuera.
|
|
182
|
+
*
|
|
183
|
+
* La raíz NO entra por parámetro de la tool: si el modelo pudiera decir sobre qué carpeta
|
|
184
|
+
* pregunta, esto sería una tool que lee cualquier sitio de la máquina.
|
|
185
|
+
*/
|
|
186
|
+
const cargarIndice = opciones.navegacion ?? indiceEnDisco(opciones.raiz);
|
|
187
|
+
const comunes = {
|
|
140
188
|
raiz: opciones.raiz,
|
|
141
189
|
ficheros: opciones.ficheros,
|
|
142
190
|
...(opciones.artefactos === undefined ? {} : { artefactos: opciones.artefactos }),
|
|
143
191
|
...(opciones.adjuntos === undefined ? {} : { adjuntos: opciones.adjuntos }),
|
|
144
|
-
}
|
|
192
|
+
};
|
|
193
|
+
const backend = backendDeAgente(comunes);
|
|
194
|
+
/**
|
|
195
|
+
* El backend CON shell, y solo si alguien lo va a usar.
|
|
196
|
+
*
|
|
197
|
+
* Se construye aparte porque es otra cadena entera: la base ejecuta, y eso cambia lo que
|
|
198
|
+
* la librería registra (`execute`) y lo que se le puede pasar (`permissions` lanza junto a
|
|
199
|
+
* un backend ejecutable). Que sea `undefined` cuando nadie declara `ejecucion` no es una
|
|
200
|
+
* optimización: es lo que hace que el caso normal sea, byte a byte, el de antes.
|
|
201
|
+
*/
|
|
202
|
+
const conShell = opciones.agentes.some((a) => puedeEjecutar(a))
|
|
203
|
+
? backendDeAgente({
|
|
204
|
+
...comunes,
|
|
205
|
+
ejecucion: {
|
|
206
|
+
entorno: entornoDeLaShellDelProyecto(opciones.raiz, opciones.artefactos?.carpeta),
|
|
207
|
+
},
|
|
208
|
+
})
|
|
209
|
+
: undefined;
|
|
145
210
|
// Si no hay tracker, no se añade el middleware: es opcional a propósito arriba.
|
|
146
211
|
const middlewareTracker = (origen) => opciones.tracker
|
|
147
212
|
? [
|
|
@@ -195,7 +260,7 @@ export async function construirAgente(opciones) {
|
|
|
195
260
|
/**
|
|
196
261
|
* Lo que diga su `.md`, y nada más. Es la PRIMERA de dos puertas: con esto en
|
|
197
262
|
* cierto, cada escritura pasa además por la política de la sesión y por las
|
|
198
|
-
* guardas de ruta (`agent/escrituraExterna.ts`). Un agente de solo lectura no
|
|
263
|
+
* guardas de ruta (`agent/subagentes/escrituraExterna.ts`). Un agente de solo lectura no
|
|
199
264
|
* llega a preguntar.
|
|
200
265
|
*/
|
|
201
266
|
permitirEscritura: !agente.soloLectura,
|
|
@@ -211,53 +276,109 @@ export async function construirAgente(opciones) {
|
|
|
211
276
|
}
|
|
212
277
|
const subagentes = opciones.agentes
|
|
213
278
|
.filter((a) => a.motor === "modelo")
|
|
214
|
-
.map((perfil) =>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
:
|
|
256
|
-
|
|
279
|
+
.map((perfil) => {
|
|
280
|
+
// Una vez por perfil: con qué backend ve los ficheros, con qué permisos y con qué tools.
|
|
281
|
+
const ficheros = montajeDeFicheros(perfil, {
|
|
282
|
+
normal: backend,
|
|
283
|
+
...(conShell === undefined ? {} : { conShell }),
|
|
284
|
+
});
|
|
285
|
+
return {
|
|
286
|
+
name: perfil.nombre,
|
|
287
|
+
description: perfil.descripcion,
|
|
288
|
+
systemPrompt: promptDeAgente(perfil, repartirSkills(perfil, catalogoDeSkills)),
|
|
289
|
+
// Los subagentes no heredan las skills del orquestador. Se entregan como fuentes
|
|
290
|
+
// directas para mantener cada perfil limitado a su catálogo declarado.
|
|
291
|
+
skills: rutasDeSkills(perfil, catalogoDeSkills),
|
|
292
|
+
// `tools` solo lleva tools PROPIAS. Pasarle los NOMBRES de las de fichero las sustituía
|
|
293
|
+
// por cadenas, dejando al especialista sin ninguna capacidad real. Las de fichero las
|
|
294
|
+
// monta el middleware; regex_search es una tool real y confinada al mismo backend.
|
|
295
|
+
/**
|
|
296
|
+
* Las dos tools propias, y contestan preguntas DISTINTAS: `regex_search` busca TEXTO y
|
|
297
|
+
* `xone_navegacion` contesta sobre el modelo ya resuelto. Un `mapcol` encuentra su
|
|
298
|
+
* colección aunque el nombre salga en otros veinte sitios, y el inventario cuesta 141
|
|
299
|
+
* tokens donde leer los `.xne` cuesta 18.000 (medido sobre un proyecto real).
|
|
300
|
+
*
|
|
301
|
+
* A los CINCO especialistas y no a unos pocos: los cinco trabajan sobre un proyecto XOne
|
|
302
|
+
* y la pregunta que esto abarata —«qué hay aquí»— se la hacen todos. El esquema es de una
|
|
303
|
+
* operación enumerada y un nombre, que es poco en cada llamada; el orquestador NO la
|
|
304
|
+
* recibe, porque no tiene tools propias y delega.
|
|
305
|
+
*/
|
|
306
|
+
tools: [crearBusquedaRegex(ficheros.backend), crearNavegacionXone(cargarIndice, opciones.ficheros)],
|
|
307
|
+
//
|
|
308
|
+
// Las tools de fichero las monta el `FilesystemMiddleware` a partir del backend, y
|
|
309
|
+
// quien las acota por NOMBRE es su propia opción `tools` (con la restricción de que
|
|
310
|
+
// `read_file` tiene que estar siempre). Aquí el solo-lectura se impone con
|
|
311
|
+
// `permissions`, que la librería aplica sobre `ls`, `read_file`, `write_file`,
|
|
312
|
+
// `edit_file`, `glob` y `grep` — o sea, sobre todas las que importan.
|
|
313
|
+
/**
|
|
314
|
+
* **Ausente para quien EJECUTA**, y por la misma razón que en el middleware: deepagents
|
|
315
|
+
* lanza `ConfigurationError` al combinar `permissions` con un backend ejecutable. Dejarlo
|
|
316
|
+
* aquí «por si acaso» no añadiría una barrera, tumbaría la construcción del agente.
|
|
317
|
+
*/
|
|
318
|
+
...(ficheros.permissions === undefined ? {} : { permissions: ficheros.permissions }),
|
|
319
|
+
interruptOn: hitlDe(perfil),
|
|
320
|
+
// En CADA especialista, no solo en el orquestador: son ellos los que llaman a las
|
|
321
|
+
// tools de fichero, así que es su siguiente llamada al modelo la que reventaba.
|
|
322
|
+
// El nombre coincide con el middleware por defecto de DeepAgents y lo sustituye: así
|
|
323
|
+
// aplica tanto al especialista como al orquestador.
|
|
324
|
+
middleware: [
|
|
325
|
+
createFilesystemMiddleware({
|
|
326
|
+
// Quién se lleva la shell, con qué permisos y con qué tools lo decide una función
|
|
327
|
+
// pura y probada (`perfiles.ts#montajeDeFicheros`), no un `if` aquí dentro.
|
|
328
|
+
...ficheros,
|
|
329
|
+
customToolDescriptions: DESCRIPCIONES_FICHEROS,
|
|
330
|
+
...OPCIONES_BUSQUEDA_FICHEROS,
|
|
331
|
+
}),
|
|
332
|
+
// El tope es del ESPECIALISTA y no del orquestador: el que contesta al usuario no
|
|
333
|
+
// puede quedarse a medias, y el que hace un encargo acotado sí debe. Ver
|
|
334
|
+
// `resumenDeContexto.ts#topeDeLlamadas`.
|
|
335
|
+
topeDeLlamadas(),
|
|
336
|
+
// Y el de TOOLS, que es el que acota lo que se ACUMULA: 43 resultados en el contexto
|
|
337
|
+
// hicieron que la última llamada costara ocho veces la primera.
|
|
338
|
+
topeDeTools(),
|
|
339
|
+
// Los DOS, y en su orden, que es lo que `resumenConEncargo` garantiza: el resumen
|
|
340
|
+
// se lleva el encargo por delante al cruzar el umbral, y el segundo lo devuelve.
|
|
341
|
+
// Sobre el backend del PERFIL: quien tiene shell descarga en SU cadena, que es la que
|
|
342
|
+
// tiene montadas `/large_tool_results/` y `/conversation_history/` con su misma raíz.
|
|
343
|
+
...resumenConEncargo(ficheros.backend),
|
|
344
|
+
middlewareTextoDeTool(),
|
|
345
|
+
...middlewareTracker(perfil.nombre),
|
|
346
|
+
// El ÚLTIMO, y por eso ve la petición ya pasada por todos los de arriba: el resumen, la
|
|
347
|
+
// devolución del encargo y la conversión de los `ToolMessage`. Puesto delante enseñaría
|
|
348
|
+
// lo que otros van a cambiar después, que es la mentira de un inspector.
|
|
349
|
+
...inspector(opciones.raiz, perfil.nombre),
|
|
350
|
+
],
|
|
351
|
+
// El modelo que fije el agente en su fichero, y si no lo fija, el del papel que le
|
|
352
|
+
// toca por lo que hace: `rapido` para el que solo lee, `trabajo` para el que escribe.
|
|
353
|
+
// Fijarlo es la excepción y no la norma — un agente con modelo escrito se queda ahí
|
|
354
|
+
// aunque el usuario cambie el suyo con `/modelo`, que es justo lo que quiere quien
|
|
355
|
+
// escribe «este revisor corre con Claude» y no lo que quiere nadie más.
|
|
356
|
+
model: perfil.modelo === undefined
|
|
357
|
+
? opciones.modelos.paraPapel(perfil.soloLectura ? "rapido" : "trabajo")
|
|
358
|
+
: opciones.modelos.paraModelo(perfil.modelo),
|
|
359
|
+
};
|
|
360
|
+
});
|
|
257
361
|
return createDeepAgent({
|
|
258
362
|
model: opciones.modelos.paraPapel("rapido"),
|
|
259
363
|
systemPrompt: promptOrquestador(opciones.agentes),
|
|
260
364
|
backend,
|
|
365
|
+
/**
|
|
366
|
+
* **El orquestador SÍ la lleva, y eso lo decidió una medida que tumbó lo contrario.**
|
|
367
|
+
*
|
|
368
|
+
* La primera versión se la dio solo a los especialistas con el argumento de que el
|
|
369
|
+
* orquestador delega. Medido sobre un proyecto real con la pregunta que motivó la tool
|
|
370
|
+
* —«¿cuántas colecciones tiene mi proyecto?»—: **no delegó**. La contestó él, con `ls`,
|
|
371
|
+
* `glob`, `grep` y `read_file`, en once llamadas y ~88k tokens, y la tool no llegó a
|
|
372
|
+
* estar disponible porque vivía en los subagentes. O sea que el razonamiento era bueno y
|
|
373
|
+
* el comportamiento otro, que es justo lo que este repo prefiere medir antes que suponer.
|
|
374
|
+
*
|
|
375
|
+
* No le abre nada: es de LECTURA y el orquestador ya lee (`permisosDe` le deja
|
|
376
|
+
* `read`/`ls`/`glob`/`grep` y le deniega el disco entero para escribir). Lo que cambia es
|
|
377
|
+
* el precio de orientarse. Su esquema viaja en cada llamada suya —y eso no es gratis,
|
|
378
|
+
* `excluirTools` existe por eso—, pero es una operación enumerada y un nombre frente a
|
|
379
|
+
* las once llamadas que sustituye.
|
|
380
|
+
*/
|
|
381
|
+
tools: [crearNavegacionXone(cargarIndice, opciones.ficheros)],
|
|
261
382
|
interruptOn: hitlDe(PERFIL_DEL_ORQUESTADOR),
|
|
262
383
|
checkpointer: opciones.checkpointer ?? new MemorySaver(),
|
|
263
384
|
// El contenido de los `ToolMessage` va como TEXTO al modelo. Sin esto, un turno real
|
|
@@ -296,9 +417,17 @@ export async function construirAgente(opciones) {
|
|
|
296
417
|
customToolDescriptions: DESCRIPCIONES_FICHEROS,
|
|
297
418
|
...OPCIONES_BUSQUEDA_FICHEROS,
|
|
298
419
|
}),
|
|
299
|
-
|
|
420
|
+
// Los DOS, y en su orden, que es lo que `resumenConEncargo` garantiza: el resumen
|
|
421
|
+
// se lleva el encargo por delante al cruzar el umbral, y el segundo lo devuelve.
|
|
422
|
+
...resumenConEncargo(backend),
|
|
423
|
+
// Los esquemas de las tools que NO puede usar son el 25 % de su cabecera, y la cabecera
|
|
424
|
+
// es el 87 % de cada llamada (`inspectorDePrompt`). `permissions` acota el permiso; el
|
|
425
|
+
// esquema viaja igual, así que esto lo quita del prompt Y sigue rechazando la llamada.
|
|
426
|
+
// La frontera sigue siendo `permisosDe`: ver `excluirTools.ts`.
|
|
427
|
+
excluirTools(toolsQueNoUsa(PERFIL_DEL_ORQUESTADOR)),
|
|
300
428
|
middlewareTextoDeTool(),
|
|
301
429
|
...middlewareTracker("orquestador"),
|
|
430
|
+
...inspector(opciones.raiz, "orquestador"),
|
|
302
431
|
],
|
|
303
432
|
subagents: [
|
|
304
433
|
...subagentes,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xoneAgent.js","sourceRoot":"","sources":["../../../src/agent/grafo/xoneAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// **Import PROFUNDO, y no es una optimización: es un requisito medido.** El barril
|
|
2
|
+
// (`xone-linter`) reexporta también su RUNTIME —VM, HTTP, dispositivo y una conexión SQLite
|
|
3
|
+
// con *top-level await*—, y eso revienta bajo `tsx`, que es el lanzador de desarrollo
|
|
4
|
+
// (`./bin/xonecode`): «Top-level await is currently not supported with the cjs output
|
|
5
|
+
// format». Por la ruta del modelo no hay ningún `await` de módulo, así que entra limpio — y
|
|
6
|
+
// de paso no se arrastra medio runtime para leer un XML.
|
|
7
|
+
import { XoneProject } from "xone-linter/dist/project/XoneProject.js";
|
|
8
|
+
import { construirIndice } from "../../core/navegacion.js";
|
|
9
|
+
import { modeloDeNavegacion } from "./modeloDeProyecto.js";
|
|
10
|
+
/**
|
|
11
|
+
* Devuelve el cargador del índice de una raíz. La raíz se fija al crearlo y NO entra por
|
|
12
|
+
* parámetro en cada consulta: si el modelo pudiera decir sobre qué proyecto preguntar,
|
|
13
|
+
* tendríamos una tool que lee cualquier carpeta de la máquina.
|
|
14
|
+
*/
|
|
15
|
+
export function indiceEnDisco(raiz) {
|
|
16
|
+
return async (ficheros) => {
|
|
17
|
+
const proyecto = await XoneProject.load(raiz);
|
|
18
|
+
return construirIndice(modeloDeNavegacion(proyecto.model, raiz, ficheros));
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=indiceEnDisco.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indiceEnDisco.js","sourceRoot":"","sources":["../../../src/agent/navegacion/indiceEnDisco.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4FAA4F;AAC5F,sFAAsF;AACtF,sFAAsF;AACtF,4FAA4F;AAC5F,yDAAyD;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAwB,MAAM,uBAAuB,CAAC;AA2BjF;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,eAAe,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAwB,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChG,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { relative, sep } from "node:path";
|
|
2
|
+
import { puedeLeerRuta } from "../grafo/perfiles.js";
|
|
3
|
+
import { esVistaAplanada } from "../grafo/proyecto.js";
|
|
4
|
+
/**
|
|
5
|
+
* La ruta VIRTUAL de una absoluta del proyecto, o `undefined` si se sale de él.
|
|
6
|
+
*
|
|
7
|
+
* Lexical y no `realpath`: este módulo es la traducción, no la barrera del disco — quien
|
|
8
|
+
* necesite cerrar los enlaces simbólicos lo hace donde se abre el fichero. Aquí lo que se
|
|
9
|
+
* impide es que una ruta de FUERA se presente como si fuera del proyecto.
|
|
10
|
+
*/
|
|
11
|
+
export function rutaVirtualDelProyecto(raiz, absoluta) {
|
|
12
|
+
const rel = relative(raiz, absoluta);
|
|
13
|
+
if (rel === "" || rel.startsWith("..") || rel.startsWith(sep + ".."))
|
|
14
|
+
return undefined;
|
|
15
|
+
// Absoluta de otra unidad: `relative` la devuelve absoluta y no empieza por `..`.
|
|
16
|
+
if (rel.startsWith(sep) || /^[A-Za-z]:/.test(rel))
|
|
17
|
+
return undefined;
|
|
18
|
+
return "/" + rel.split(sep).join("/");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Traduce el modelo del linter al nuestro, filtrando lo que no se puede enseñar.
|
|
22
|
+
*
|
|
23
|
+
* `ficheros` son las rutas virtuales del proyecto, las mismas que ve el agente: hacen falta
|
|
24
|
+
* para reconocer una vista aplanada (`X.xml` con un `X.xne` al lado), que es una regla que
|
|
25
|
+
* depende del conjunto y no de la ruta sola.
|
|
26
|
+
*/
|
|
27
|
+
export function modeloDeNavegacion(delLinter, raiz, ficheros) {
|
|
28
|
+
const colecciones = [];
|
|
29
|
+
for (const coll of delLinter.colls ?? []) {
|
|
30
|
+
const nombre = coll.name;
|
|
31
|
+
const absoluta = coll.location?.file;
|
|
32
|
+
if (nombre === undefined || nombre === "" || absoluta === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
const fichero = rutaVirtualDelProyecto(raiz, absoluta);
|
|
35
|
+
// Fuera del proyecto, denegada o vista aplanada: no entra en el índice. Un símbolo que
|
|
36
|
+
// el agente no puede abrir es peor que uno que falta — le manda a leer donde no debe.
|
|
37
|
+
if (fichero === undefined || !puedeLeerRuta(fichero) || esVistaAplanada(fichero, ficheros))
|
|
38
|
+
continue;
|
|
39
|
+
const campos = (coll.props ?? [])
|
|
40
|
+
.filter((p) => typeof p.name === "string" && p.name !== "")
|
|
41
|
+
.map((p) => ({ nombre: p.name, ...(p.type === undefined ? {} : { tipo: p.type }) }));
|
|
42
|
+
colecciones.push({
|
|
43
|
+
nombre,
|
|
44
|
+
fichero,
|
|
45
|
+
campos,
|
|
46
|
+
referencias: referenciasDe(coll, nombre),
|
|
47
|
+
// Un `onchange` lleva el campo que lo dispara: sin él no se sabe a qué reacciona, y eso
|
|
48
|
+
// es justo lo que hace falta antes de tocarlo.
|
|
49
|
+
eventos: (coll.events ?? [])
|
|
50
|
+
.filter((e) => typeof e.name === "string" && e.name !== "")
|
|
51
|
+
.map((e) => (e.triggerProp === undefined || e.triggerProp === "" ? e.name : `${e.name}(${e.triggerProp})`)),
|
|
52
|
+
nodos: nombresDe(coll.nodes),
|
|
53
|
+
conexiones: nombresDe(coll.connections),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
colecciones,
|
|
58
|
+
// El inventario entra como criba de la señal débil: sin él, «un literal que coincide con
|
|
59
|
+
// una colección» sería «cualquier literal». Por eso va DESPUÉS de componer las colecciones.
|
|
60
|
+
referenciasDeScript: referenciasDeScript(delLinter, raiz, ficheros, new Set(colecciones.map((c) => c.nombre.toLowerCase()))),
|
|
61
|
+
app: {
|
|
62
|
+
entrada: [...(delLinter.app?.entryPoints ?? [])],
|
|
63
|
+
login: [...(delLinter.app?.loginColls ?? [])],
|
|
64
|
+
// La URL de un estilo es del PROYECTO (`default.css`), no una ruta de la máquina: la
|
|
65
|
+
// declara el propio `app.xml` y por eso viaja tal cual.
|
|
66
|
+
estilos: (delLinter.app?.styles ?? [])
|
|
67
|
+
.map((e) => e.url)
|
|
68
|
+
.filter((u) => typeof u === "string" && u !== ""),
|
|
69
|
+
conexiones: nombresDe(delLinter.app?.connections),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Los `name` que existen de verdad, de una lista que puede traerlos a medias. */
|
|
74
|
+
function nombresDe(lista) {
|
|
75
|
+
return (lista ?? []).map((x) => x.name).filter((n) => typeof n === "string" && n !== "");
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Lo que una colección apunta hacia fuera.
|
|
79
|
+
*
|
|
80
|
+
* Los cuatro atributos son los que `xone-linter` ya valida en su `CrossReferenceRule`, y esa
|
|
81
|
+
* coincidencia es deliberada: **la semántica de qué significa `mapcol` vive en UN sitio**.
|
|
82
|
+
* Reescribirla aquí crearía un segundo sitio donde decidirlo, y el día que divergieran el
|
|
83
|
+
* linter diría una cosa y el agente otra sobre el mismo proyecto.
|
|
84
|
+
*
|
|
85
|
+
* `mapfld` y `linkedfield` se cuelgan del `mapcol` de su propio prop, que es lo que les da
|
|
86
|
+
* sentido: un `mapfld` sin `mapcol` no apunta a nada que se pueda nombrar.
|
|
87
|
+
*/
|
|
88
|
+
function referenciasDe(coll, nombre) {
|
|
89
|
+
const salida = [];
|
|
90
|
+
const hereda = coll.attributes?.["inherits"];
|
|
91
|
+
if (hereda !== undefined && hereda !== "") {
|
|
92
|
+
salida.push({ desde: nombre, por: "inherits", hacia: hereda });
|
|
93
|
+
}
|
|
94
|
+
for (const contenido of coll.contents ?? []) {
|
|
95
|
+
if (contenido.src !== undefined && contenido.src !== "") {
|
|
96
|
+
salida.push({ desde: nombre, por: "contents", hacia: contenido.src });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const prop of coll.props ?? []) {
|
|
100
|
+
if (typeof prop.name !== "string" || prop.name === "")
|
|
101
|
+
continue;
|
|
102
|
+
const desde = `${nombre}.${prop.name}`;
|
|
103
|
+
const mapcol = prop.attributes?.["mapcol"];
|
|
104
|
+
if (mapcol === undefined || mapcol === "")
|
|
105
|
+
continue;
|
|
106
|
+
salida.push({ desde, por: "mapcol", hacia: mapcol });
|
|
107
|
+
for (const clave of ["mapfld", "linkedfield"]) {
|
|
108
|
+
const campo = prop.attributes?.[clave];
|
|
109
|
+
if (campo !== undefined && campo !== "") {
|
|
110
|
+
salida.push({ desde, por: clave, hacia: `${mapcol}.${campo}` });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return salida;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Cómo una app XOne llega de verdad a una colección, que no es con `mapcol`.
|
|
118
|
+
*
|
|
119
|
+
* **Medido sobre un proyecto real**, y fue lo que cambió el alcance de la tool. Hay DOS
|
|
120
|
+
* señales, y van separadas a propósito porque no valen lo mismo:
|
|
121
|
+
*
|
|
122
|
+
* 1. **`appData.getCollection("X")` — señal FUERTE** (`por: "script"`). Es una llamada con su
|
|
123
|
+
* literal: la forma en que se nombra una colección desde ES5. Los botones del menú abren
|
|
124
|
+
* así (`onclick="javascript:var o=appData.getCollection('Deportes')…"`), y sin esto «¿quién
|
|
125
|
+
* usa Deportes?» contestaba «nadie» con dos botones apuntándole.
|
|
126
|
+
* 2. **Un literal que COINCIDE con el nombre de una colección — señal DÉBIL**
|
|
127
|
+
* (`por: "mencion"`). Existe porque la cadena real puede tener tres saltos:
|
|
128
|
+
* `method="ExecuteNode(abrirColl('ConsolaReplica'))"` → un nodo con `<param name="coll">` →
|
|
129
|
+
* `irColl(coll)` → `getCollection(collname)` + `pushValue(obj)`. El nombre solo aparece
|
|
130
|
+
* como literal en el PRIMER salto, y perseguir la cadena sería atarse a cómo se llaman los
|
|
131
|
+
* ayudantes de UN proyecto (`irColl`, `abrirColl`, `openMenu`), que no son de XOne.
|
|
132
|
+
*
|
|
133
|
+
* **Y se marcan distinto porque la confianza es distinta.** Una llamada resuelta y una cadena
|
|
134
|
+
* que coincide con un nombre no son lo mismo, y fundirlas haría que la segunda se leyera con
|
|
135
|
+
* la autoridad de la primera. Medido sobre el proyecto real: la débil añade cinco referencias
|
|
136
|
+
* y todas resultaron ciertas, pero eso no la convierte en la fuerte.
|
|
137
|
+
*
|
|
138
|
+
* **Límites declarados**: ninguna de las dos ve un nombre compuesto en ejecución ni dice en qué
|
|
139
|
+
* LÍNEA está —para eso harían falta rangos—, y la débil no puede distinguir un nombre de
|
|
140
|
+
* colección de una cadena que se le parece.
|
|
141
|
+
*/
|
|
142
|
+
const LLAMADA_A_COLECCION = /getCollection\s*\(\s*['"]([^'"]+)['"]\s*\)/gi;
|
|
143
|
+
/** Cualquier literal de cadena con forma de identificador. La criba es el inventario. */
|
|
144
|
+
const LITERAL_DE_CADENA = /['"]([A-Za-z_][A-Za-z0-9_]{2,40})['"]/g;
|
|
145
|
+
/** Todos los sitios del proyecto donde hay script, con su origen ya traducido. */
|
|
146
|
+
function trozosDeScript(delLinter, raiz) {
|
|
147
|
+
const trozos = [];
|
|
148
|
+
for (const coll of delLinter.colls ?? []) {
|
|
149
|
+
const nombre = coll.name;
|
|
150
|
+
const absoluta = coll.location?.file;
|
|
151
|
+
if (nombre === undefined || absoluta === undefined)
|
|
152
|
+
continue;
|
|
153
|
+
const fichero = rutaVirtualDelProyecto(raiz, absoluta);
|
|
154
|
+
if (fichero === undefined)
|
|
155
|
+
continue;
|
|
156
|
+
for (const prop of coll.props ?? []) {
|
|
157
|
+
if (typeof prop.name !== "string" || prop.name === "")
|
|
158
|
+
continue;
|
|
159
|
+
const desde = `${nombre}.${prop.name}`;
|
|
160
|
+
for (const evento of prop.inlineEvents ?? []) {
|
|
161
|
+
trozos.push({ desde, fichero, duena: nombre, texto: String(evento.script ?? "") });
|
|
162
|
+
}
|
|
163
|
+
// **El atributo `method` cuenta**, y no es un detalle: es donde vive
|
|
164
|
+
// `ExecuteNode(abrirColl('ConsolaReplica'))`, o sea la única aparición literal de esa
|
|
165
|
+
// colección en todo el proyecto. Sin mirarlo, el botón de información no referencia nada.
|
|
166
|
+
const metodo = prop.attributes?.["method"];
|
|
167
|
+
if (metodo !== undefined && metodo !== "") {
|
|
168
|
+
trozos.push({ desde, fichero, duena: nombre, texto: metodo });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const evento of [...(coll.events ?? []), ...(coll.nodes ?? [])]) {
|
|
172
|
+
const desde = `${nombre}:${evento.name ?? "(evento)"}`;
|
|
173
|
+
for (const accion of evento.actions ?? []) {
|
|
174
|
+
for (const texto of [accion.script, accion.value]) {
|
|
175
|
+
if (texto !== undefined && texto !== "")
|
|
176
|
+
trozos.push({ desde, fichero, duena: nombre, texto });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Los `.js` sueltos. Sus claves son rutas RELATIVAS al proyecto, así que la virtual es
|
|
182
|
+
// directa. No tienen colección dueña: un `.js` puede nombrar a cualquiera.
|
|
183
|
+
for (const [ruta, texto] of delLinter.jsFiles ?? new Map()) {
|
|
184
|
+
const virtual = "/" + String(ruta).split(/[\\/]/).filter(Boolean).join("/");
|
|
185
|
+
trozos.push({ desde: virtual, fichero: virtual, texto: String(texto) });
|
|
186
|
+
}
|
|
187
|
+
return trozos;
|
|
188
|
+
}
|
|
189
|
+
function referenciasDeScript(delLinter, raiz, ficheros, conocidas) {
|
|
190
|
+
const salida = [];
|
|
191
|
+
const anotar = (desde, por, hacia, fichero) => {
|
|
192
|
+
if (!puedeLeerRuta(fichero) || esVistaAplanada(fichero, ficheros))
|
|
193
|
+
return;
|
|
194
|
+
// Sin repetir: un mismo botón puede nombrar la colección dos veces en la misma línea.
|
|
195
|
+
if (salida.some((r) => r.desde === desde && r.hacia === hacia && r.fichero === fichero))
|
|
196
|
+
return;
|
|
197
|
+
salida.push({ desde, por, hacia, fichero });
|
|
198
|
+
};
|
|
199
|
+
for (const trozo of trozosDeScript(delLinter, raiz)) {
|
|
200
|
+
const fuertes = new Set();
|
|
201
|
+
for (const x of trozo.texto.matchAll(LLAMADA_A_COLECCION)) {
|
|
202
|
+
fuertes.add(x[1].toLowerCase());
|
|
203
|
+
anotar(trozo.desde, "script", x[1], trozo.fichero);
|
|
204
|
+
}
|
|
205
|
+
for (const x of trozo.texto.matchAll(LITERAL_DE_CADENA)) {
|
|
206
|
+
const literal = x[1];
|
|
207
|
+
const clave = literal.toLowerCase();
|
|
208
|
+
// Solo si es el nombre de una colección que EXISTE: el inventario es la criba, y sin
|
|
209
|
+
// ella esto sería «cualquier cadena del proyecto».
|
|
210
|
+
if (!conocidas.has(clave))
|
|
211
|
+
continue;
|
|
212
|
+
// Ya la cogió la señal fuerte en este mismo trozo: no se degrada a mención.
|
|
213
|
+
if (fuertes.has(clave))
|
|
214
|
+
continue;
|
|
215
|
+
/**
|
|
216
|
+
* **Una colección que se nombra a sí misma no cuenta.** Medido: de las menciones que
|
|
217
|
+
* aparecían en el proyecto real, la mayoría eran los scripts de `ConsolaReplica`
|
|
218
|
+
* diciendo «ConsolaReplica» — en un SQL, en un mensaje, en un refresco. Como respuesta a
|
|
219
|
+
* «¿quién usa X?» eso es ruido, y ruido que sale en TODAS las colecciones con scripts.
|
|
220
|
+
*/
|
|
221
|
+
if (trozo.duena !== undefined && trozo.duena.toLowerCase() === clave)
|
|
222
|
+
continue;
|
|
223
|
+
anotar(trozo.desde, "mencion", literal, trozo.fichero);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return salida;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=modeloDeProyecto.js.map
|