xonecode 0.6.0 → 0.8.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/apps/web/dist/assets/{index-rqecK6s2.css → index-Boak51UP.css} +1 -1
- package/apps/web/dist/assets/index-Cg28x6nG.js +477 -0
- package/apps/web/dist/assets/{php-BBij3Lhc.js → php-Cu6F_QCJ.js} +1 -1
- package/apps/web/dist/assets/{ruby-Dq2YEaLo.js → ruby-BiqQPoC6.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/cloudstudio/cloudstudioClient.js +10 -0
- package/dist/agent/cloudstudio/cloudstudioClient.js.map +1 -1
- package/dist/agent/cloudstudio/descarga.js +14 -4
- package/dist/agent/cloudstudio/descarga.js.map +1 -1
- package/dist/agent/cloudstudio/ramaActiva.js +11 -0
- package/dist/agent/cloudstudio/ramaActiva.js.map +1 -0
- package/dist/agent/cloudstudio/subida.js +13 -4
- package/dist/agent/cloudstudio/subida.js.map +1 -1
- package/dist/agent/config/catalogoModelos.js +45 -0
- package/dist/agent/config/catalogoModelos.js.map +1 -1
- package/dist/agent/config/modelos.js +103 -12
- package/dist/agent/config/modelos.js.map +1 -1
- package/dist/agent/config/mudanzaEnDisco.js +121 -0
- package/dist/agent/config/mudanzaEnDisco.js.map +1 -0
- package/dist/agent/config/selectorEnMaquina.js +45 -0
- package/dist/agent/config/selectorEnMaquina.js.map +1 -0
- package/dist/agent/config/settingsEnDisco.js +35 -0
- package/dist/agent/config/settingsEnDisco.js.map +1 -1
- package/dist/agent/dispositivos/juezVisual.js +152 -0
- package/dist/agent/dispositivos/juezVisual.js.map +1 -0
- package/dist/agent/dispositivos/sensorDeArranque.js +154 -0
- package/dist/agent/dispositivos/sensorDeArranque.js.map +1 -0
- package/dist/agent/exportarPdf.js +140 -0
- package/dist/agent/exportarPdf.js.map +1 -0
- package/dist/agent/grafo/criticaVisual.js +115 -0
- package/dist/agent/grafo/criticaVisual.js.map +1 -0
- package/dist/agent/grafo/navegacionXone.js +37 -4
- package/dist/agent/grafo/navegacionXone.js.map +1 -1
- package/dist/agent/grafo/perfiles.js +52 -9
- package/dist/agent/grafo/perfiles.js.map +1 -1
- package/dist/agent/grafo/proyecto.js +74 -7
- package/dist/agent/grafo/proyecto.js.map +1 -1
- package/dist/agent/grafo/skills.js +32 -0
- package/dist/agent/grafo/skills.js.map +1 -1
- package/dist/agent/grafo/xoneAgent.js +103 -13
- package/dist/agent/grafo/xoneAgent.js.map +1 -1
- package/dist/agent/navegacion/estilosEnDisco.js +110 -0
- package/dist/agent/navegacion/estilosEnDisco.js.map +1 -0
- package/dist/agent/navegacion/hechosEnDisco.js +26 -0
- package/dist/agent/navegacion/hechosEnDisco.js.map +1 -0
- package/dist/agent/navegacion/indiceEnDisco.js +15 -0
- package/dist/agent/navegacion/indiceEnDisco.js.map +1 -1
- package/dist/agent/subagentes/agentesEnDisco.js +85 -24
- package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
- package/dist/agent/subagentes/escrituraExterna.js +53 -0
- package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
- package/dist/agent/subagentes/pluginDeSkills.js +99 -0
- package/dist/agent/subagentes/pluginDeSkills.js.map +1 -0
- package/dist/agent/subagentes/subagenteExterno.js +48 -0
- package/dist/agent/subagentes/subagenteExterno.js.map +1 -1
- package/dist/agent/subagentes/subagenteOpencode.js +53 -1
- package/dist/agent/subagentes/subagenteOpencode.js.map +1 -1
- package/dist/agent/tareas/juezDeTarea.js +1 -1
- package/dist/agent/tareas/juezDeTarea.js.map +1 -1
- package/dist/agent/tareas/tareasEnDisco.js +49 -0
- package/dist/agent/tareas/tareasEnDisco.js.map +1 -1
- package/dist/agent/turno/diagnosticoDeTools.js +5 -1
- package/dist/agent/turno/diagnosticoDeTools.js.map +1 -1
- package/dist/agent/turno/informeDeTraza.js +27 -4
- package/dist/agent/turno/informeDeTraza.js.map +1 -1
- package/dist/agent/turno/puente.js +24 -1
- package/dist/agent/turno/puente.js.map +1 -1
- package/dist/agent/turno/resumenDeContexto.js +88 -4
- package/dist/agent/turno/resumenDeContexto.js.map +1 -1
- package/dist/agent/turno/resumenDeTool.js +18 -0
- package/dist/agent/turno/resumenDeTool.js.map +1 -1
- package/dist/agent/turno/rubrica.js +91 -0
- package/dist/agent/turno/rubrica.js.map +1 -0
- package/dist/agent/turno/turnoReal.js +172 -11
- package/dist/agent/turno/turnoReal.js.map +1 -1
- package/dist/cli/consola.js +63 -0
- package/dist/cli/consola.js.map +1 -1
- package/dist/cli/main.js +51 -4
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/run.js +8 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/core/agentes.js +111 -9
- package/dist/core/agentes.js.map +1 -1
- package/dist/core/esfuerzo.js +141 -0
- package/dist/core/esfuerzo.js.map +1 -0
- package/dist/core/estilos.js +78 -0
- package/dist/core/estilos.js.map +1 -0
- package/dist/core/exportacion.js +140 -0
- package/dist/core/exportacion.js.map +1 -0
- package/dist/core/hechosDelProyecto.js +87 -0
- package/dist/core/hechosDelProyecto.js.map +1 -0
- package/dist/core/logDeDispositivo.js +143 -0
- package/dist/core/logDeDispositivo.js.map +1 -0
- package/dist/core/modelos.js +32 -0
- package/dist/core/modelos.js.map +1 -1
- package/dist/core/mudanzaDeWorkspace.js +93 -0
- package/dist/core/mudanzaDeWorkspace.js.map +1 -0
- package/dist/core/planes.js +70 -0
- package/dist/core/planes.js.map +1 -0
- package/dist/core/ports.js +4 -0
- package/dist/core/ports.js.map +1 -1
- package/dist/core/rubrica.js +90 -0
- package/dist/core/rubrica.js.map +1 -0
- package/dist/core/selectorDeCarpeta.js +87 -0
- package/dist/core/selectorDeCarpeta.js.map +1 -0
- package/dist/core/settings.js +54 -5
- package/dist/core/settings.js.map +1 -1
- package/dist/core/shellDeAgente.js +45 -0
- package/dist/core/shellDeAgente.js.map +1 -1
- package/dist/core/topeAgotado.js +69 -0
- package/dist/core/topeAgotado.js.map +1 -0
- package/dist/web/servidor/arranque.js +324 -9
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/sesiones.js +30 -2
- package/dist/web/servidor/sesiones.js.map +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +55 -6
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +2 -1
- package/skills/xone-hotswap/SKILL.md +31 -9
- package/skills/xone-hotswap/scripts/xone-arrancar-android +202 -0
- package/skills/xone-hotswap/scripts/xone-captura-android +93 -0
- package/skills/xone-hotswap/scripts/xone-desplegar-android +28 -0
- package/skills/xone-hotswap/scripts/xone-hotswap +39 -9
- package/skills/xone-hotswap/scripts/xone-reiniciar-android +28 -0
- package/skills/xone-plan-builder/SKILL.md +22 -4
- package/skills/xone-spec-builder/SKILL.md +37 -7
- package/apps/web/dist/assets/index-DBZTodio.js +0 -477
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convertir un documento del proyecto a PDF, imprimiéndolo con un NAVEGADOR.
|
|
3
|
+
*
|
|
4
|
+
* El porqué de que esto lo haga el harness y no el agente está en `core/exportacion.ts`.
|
|
5
|
+
* Aquí está lo que toca disco, y tres decisiones que no son de forma:
|
|
6
|
+
*
|
|
7
|
+
* - **El navegador se busca en una lista CERRADA de rutas conocidas**, igual que las
|
|
8
|
+
* herramientas de `core/dispositivos.ts`: lo que no está en la lista no se lanza. Y su RUTA
|
|
9
|
+
* se queda en el host — por el cable viaja que hay navegador o que no, nunca dónde.
|
|
10
|
+
* - **Se imprime SIN JavaScript** (`--blink-settings=scriptEnabled=false`). Un `.md` o un
|
|
11
|
+
* `.html` del proyecto puede traer un `<script>` dentro, y un PDF no necesita ejecutar
|
|
12
|
+
* nada: es la misma razón por la que un artefacto se sirve en un iframe con origen opaco.
|
|
13
|
+
* - **El HTML intermedio se escribe FUERA del proyecto.** Dentro entraría en git, en el
|
|
14
|
+
* commit de cada turno y en la siguiente subida a CloudStudio — un fichero de andamiaje en
|
|
15
|
+
* la app del cliente.
|
|
16
|
+
*/
|
|
17
|
+
import { execFile } from "node:child_process";
|
|
18
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
19
|
+
import { tmpdir } from "node:os";
|
|
20
|
+
import { basename, join, resolve } from "node:path";
|
|
21
|
+
import { conPoliticaSinScripts, documentoImprimible, esMarkdown, motivoDeExportacionInaceptable, rutaDePdf, } from "../core/exportacion.js";
|
|
22
|
+
import { motivoDeRutaInaceptable } from "./grafo/arbolDeProyecto.js";
|
|
23
|
+
/**
|
|
24
|
+
* Dónde puede estar un navegador que sepa imprimir. Lista CERRADA y en este orden.
|
|
25
|
+
*
|
|
26
|
+
* Son todos Chromium por dentro, que es el que trae `--print-to-pdf`: Safari y Firefox no
|
|
27
|
+
* tienen equivalente en línea de comandos, así que no están y no es un olvido.
|
|
28
|
+
*/
|
|
29
|
+
export const NAVEGADORES_CONOCIDOS = [
|
|
30
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
31
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
32
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
33
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
|
34
|
+
"/usr/bin/chromium",
|
|
35
|
+
"/usr/bin/chromium-browser",
|
|
36
|
+
"/usr/bin/google-chrome",
|
|
37
|
+
"/usr/bin/google-chrome-stable",
|
|
38
|
+
];
|
|
39
|
+
/** El primero que exista, o AUSENTE. Ausente = aquí no se puede imprimir, y se DICE con el
|
|
40
|
+
* remedio: no hay forma de adivinar que lo que falta es un navegador. */
|
|
41
|
+
export function navegadorParaImprimir(existe = existsSync) {
|
|
42
|
+
return NAVEGADORES_CONOCIDOS.find((ruta) => existe(ruta));
|
|
43
|
+
}
|
|
44
|
+
/** Qué decir cuando no hay ninguno. Vive aquí y no en quien llama para que las tres pieles
|
|
45
|
+
* digan lo mismo. */
|
|
46
|
+
export const SIN_NAVEGADOR = "no encuentro un navegador con el que imprimir. El PDF se genera con Chrome, Chromium, Edge o Brave " +
|
|
47
|
+
"en modo headless; instala uno y vuelve a intentarlo.";
|
|
48
|
+
/**
|
|
49
|
+
* Exporta `ruta` (relativa al proyecto) a un PDF hermano. Nunca LANZA.
|
|
50
|
+
*
|
|
51
|
+
* Las barreras son las MISMAS que usa la pestaña Ficheros y en el mismo orden: la criba de
|
|
52
|
+
* balde sobre el texto (`motivoDeRutaInaceptable`) y luego el camino REAL, porque un enlace
|
|
53
|
+
* simbólico dentro de la raíz puede apuntar fuera. No hay una segunda copia de esas reglas
|
|
54
|
+
* aquí: un segundo sitio donde decidir sobre una ruta es un segundo sitio donde el
|
|
55
|
+
* fail-closed puede dejar de estarlo.
|
|
56
|
+
*/
|
|
57
|
+
export async function exportarAPdf(opciones) {
|
|
58
|
+
const malaRuta = motivoDeRutaInaceptable(opciones.ruta);
|
|
59
|
+
if (malaRuta !== undefined)
|
|
60
|
+
return { error: malaRuta };
|
|
61
|
+
const malaExtension = motivoDeExportacionInaceptable(opciones.ruta);
|
|
62
|
+
if (malaExtension !== undefined)
|
|
63
|
+
return { error: malaExtension };
|
|
64
|
+
const navegador = opciones.navegador ?? (opciones.buscarNavegador ?? navegadorParaImprimir)();
|
|
65
|
+
if (navegador === undefined)
|
|
66
|
+
return { error: SIN_NAVEGADOR };
|
|
67
|
+
const origen = resolve(opciones.raiz, opciones.ruta);
|
|
68
|
+
if (!existsSync(origen))
|
|
69
|
+
return { error: `«${opciones.ruta}» no está en el proyecto` };
|
|
70
|
+
let fuente;
|
|
71
|
+
try {
|
|
72
|
+
fuente = readFileSync(origen, "utf8");
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// El mensaje de Node lleva la ruta absoluta y esto viaja por el cable (`sinRutas`).
|
|
76
|
+
return { error: `no se pudo leer «${opciones.ruta}»` };
|
|
77
|
+
}
|
|
78
|
+
let cuerpo;
|
|
79
|
+
try {
|
|
80
|
+
cuerpo = esMarkdown(opciones.ruta) ? await (opciones.aHtml ?? marcadoAHtml)(fuente) : fuente;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { error: `no se pudo convertir «${opciones.ruta}»` };
|
|
84
|
+
}
|
|
85
|
+
// Fuera del proyecto: dentro entraría en git, en el commit del turno y en la subida.
|
|
86
|
+
const taller = mkdtempSync(join(tmpdir(), "xonecode-pdf-"));
|
|
87
|
+
const html = join(taller, "documento.html");
|
|
88
|
+
const destino = resolve(opciones.raiz, rutaDePdf(opciones.ruta));
|
|
89
|
+
try {
|
|
90
|
+
writeFileSync(html, esMarkdown(opciones.ruta)
|
|
91
|
+
? documentoImprimible(cuerpo, basename(opciones.ruta))
|
|
92
|
+
: // Un `.html` no pasa por la plantilla, así que se le inyecta la política aparte. No
|
|
93
|
+
// se envuelve dentro de la nuestra: meter un documento entero en nuestro `<body>`
|
|
94
|
+
// lo rompería.
|
|
95
|
+
conPoliticaSinScripts(cuerpo), "utf8");
|
|
96
|
+
await (opciones.imprimir ?? lanzarNavegador)(navegador, [
|
|
97
|
+
"--headless",
|
|
98
|
+
"--disable-gpu",
|
|
99
|
+
// **Aquí NO va ningún flag para desactivar JavaScript**, y no es un olvido: medido
|
|
100
|
+
// contra el Chrome instalado, ni `--disable-javascript` ni
|
|
101
|
+
// `--blink-settings=scriptEnabled=false` lo desactivan — y el segundo además hace que
|
|
102
|
+
// `--print-to-pdf` no escriba nada, en silencio y saliendo con 0. Lo que sí funciona es
|
|
103
|
+
// la CSP del documento (`POLITICA_SIN_SCRIPTS`).
|
|
104
|
+
"--no-pdf-header-footer",
|
|
105
|
+
`--print-to-pdf=${destino}`,
|
|
106
|
+
`file://${html}`,
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const motivo = error instanceof Error ? error.message : String(error);
|
|
111
|
+
return { error: `el navegador no pudo imprimir: ${motivo}` };
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
// El taller se borra pase lo que pase: son ficheros nuestros en un temporal.
|
|
115
|
+
rmSync(taller, { recursive: true, force: true });
|
|
116
|
+
}
|
|
117
|
+
// «Terminó bien» y «hay PDF» son dos cosas: el navegador sale con 0 aunque no escriba nada.
|
|
118
|
+
// Es la misma regla que ya usa la instalación de dispositivos — manda la MEDIDA, no el
|
|
119
|
+
// código de salida.
|
|
120
|
+
if (!existsSync(destino))
|
|
121
|
+
return { error: "el navegador terminó sin escribir ningún PDF" };
|
|
122
|
+
return { ruta: rutaDePdf(opciones.ruta) };
|
|
123
|
+
}
|
|
124
|
+
/** `marked` cargado perezosamente, por lo dicho arriba. */
|
|
125
|
+
async function marcadoAHtml(markdown) {
|
|
126
|
+
const { marked } = await import("marked");
|
|
127
|
+
return marked.parse(markdown, { async: false });
|
|
128
|
+
}
|
|
129
|
+
function lanzarNavegador(navegador, argumentos) {
|
|
130
|
+
return new Promise((resolver, rechazar) => {
|
|
131
|
+
execFile(navegador, [...argumentos], { timeout: TOPE_DE_IMPRESION_MS }, (error) =>
|
|
132
|
+
// Su stderr trae avisos del sistema gráfico incluso cuando todo va bien, así que lo que
|
|
133
|
+
// se mira es el error del proceso y después si el fichero está.
|
|
134
|
+
error === null ? resolver() : rechazar(error));
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/** Un documento largo con tablas tarda segundos, no minutos; un navegador que no vuelve en
|
|
138
|
+
* este plazo está colgado y no imprimiendo. */
|
|
139
|
+
export const TOPE_DE_IMPRESION_MS = 2 * 60 * 1000;
|
|
140
|
+
//# sourceMappingURL=exportarPdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exportarPdf.js","sourceRoot":"","sources":["../../src/agent/exportarPdf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { tool } from "@langchain/core/tools";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { esRutaDeArtefacto, mimeDeArtefacto, nombreDeArtefacto } from "../../core/artefactos.js";
|
|
4
|
+
import { juzgarPantalla, TOPE_DE_PETICIONES, } from "../dispositivos/juezVisual.js";
|
|
5
|
+
/**
|
|
6
|
+
* `xone_critica_visual`: enseñarle una captura al crítico y traer su veredicto.
|
|
7
|
+
*
|
|
8
|
+
* **Por qué es una TOOL y no un paso del cierre.** El crítico necesita PEDIR pantallas —juzga
|
|
9
|
+
* la captura que le den, así que si el conductor fotografió el login, dictamina sobre el
|
|
10
|
+
* login—, y quien puede ir a buscarlas es el conductor. Las tres formas de resolver eso se
|
|
11
|
+
* midieron contra los invariantes del repo y dos se caen solas:
|
|
12
|
+
*
|
|
13
|
+
* - Que el conductor haga de crítico es que el que trabaja se puntúe a sí mismo. Es lo que
|
|
14
|
+
* `juezDeTarea` ya prohíbe por escrito —«a un modelo se le puede pedir que avise y a veces
|
|
15
|
+
* no avisa»— y lo que el prompt del conductor tiene prohibido («no digas que hiciste un
|
|
16
|
+
* paso que no hiciste»). Medido el mismo día: un turno describió los 19 botones de una
|
|
17
|
+
* pantalla leyéndolos del `.xne` y se leía como si los hubiera visto.
|
|
18
|
+
* - Que el crítico conduzca el aparato es darle una shell, y el invariante es «backend con
|
|
19
|
+
* shell, exactamente UNO»: una shell no pasa por `permisosDe` ni por el `virtualMode`, o
|
|
20
|
+
* sea que concederla es conceder la máquina — y precisamente al que existe para ser
|
|
21
|
+
* independiente.
|
|
22
|
+
*
|
|
23
|
+
* Queda ésta: el crítico **pide por nombre** y el orquestador vuelve a delegar en el
|
|
24
|
+
* conductor. La tool no toca el aparato, no escribe nada y solo lee de la carpeta de
|
|
25
|
+
* artefactos de la sesión.
|
|
26
|
+
*
|
|
27
|
+
* **La guarda de ruta se RE-APLICA a mano**, como en las otras dos tools propias: una tool de
|
|
28
|
+
* LangChain añadida por xonecode NO pasa por el middleware de permisos, así que sin esto sería
|
|
29
|
+
* una forma de leer cualquier fichero de la máquina y mandárselo a un modelo.
|
|
30
|
+
*/
|
|
31
|
+
const Entrada = z.object({
|
|
32
|
+
captura: z
|
|
33
|
+
.string()
|
|
34
|
+
.describe("La ruta virtual de la captura, siempre bajo /artefactos/ (la que anunció el evento)"),
|
|
35
|
+
pantalla: z
|
|
36
|
+
.string()
|
|
37
|
+
.describe("De qué pantalla o colección es la captura, para que el crítico sepa qué mira"),
|
|
38
|
+
});
|
|
39
|
+
export function crearCriticaVisual(deps) {
|
|
40
|
+
return tool(async (entrada) => {
|
|
41
|
+
// Lista BLANCA de forma, sobre el TEXTO que escribe el modelo. `esRutaDeArtefacto` no es
|
|
42
|
+
// un `startsWith`: comprueba la forma entera.
|
|
43
|
+
if (!esRutaDeArtefacto(entrada.captura)) {
|
|
44
|
+
return `«${entrada.captura}» no es una captura de esta sesión. Solo puedo mirar lo que hay bajo /artefactos/.`;
|
|
45
|
+
}
|
|
46
|
+
const nombre = nombreDeArtefacto(entrada.captura);
|
|
47
|
+
const mime = mimeDeArtefacto(nombre);
|
|
48
|
+
if (mime === undefined || !mime.startsWith("image/")) {
|
|
49
|
+
return `«${nombre}» no es una imagen, así que no hay nada que mirar.`;
|
|
50
|
+
}
|
|
51
|
+
let bytes;
|
|
52
|
+
try {
|
|
53
|
+
bytes = await deps.leerArtefacto(nombre);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// El mensaje de un error de Node lleva la ruta absoluta y esto va al modelo: solo el
|
|
57
|
+
// nombre del error. Y se DEVUELVE, no se lanza: que falte una captura no puede
|
|
58
|
+
// llevarse el turno por delante.
|
|
59
|
+
return `No pude abrir «${nombre}» (${error instanceof Error ? error.name : "error"}).`;
|
|
60
|
+
}
|
|
61
|
+
let veredicto;
|
|
62
|
+
try {
|
|
63
|
+
veredicto = await juzgarPantalla({ base64: bytes.toString("base64"), mime }, { pantalla: entrada.pantalla }, deps.invocar);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Fallo del ENTORNO —sin modelo, sin clave, sin red—: se dice, y no se convierte en un
|
|
67
|
+
// veredicto. Un rojo inventado culparía al trabajo de un problema de la máquina.
|
|
68
|
+
return `No se pudo consultar al crítico visual: ${error instanceof Error ? error.message : "error"}`;
|
|
69
|
+
}
|
|
70
|
+
const lineas = [`Veredicto visual de «${entrada.pantalla}»: ${veredicto.veredicto}.`];
|
|
71
|
+
if (veredicto.observaciones.length > 0) {
|
|
72
|
+
/**
|
|
73
|
+
* **El aviso no es cortesía: está medido.** Seis vueltas sobre la misma captura
|
|
74
|
+
* describieron un texto CORTADO como «girado 180°», y pedirle en el prompt que no
|
|
75
|
+
* diagnostique no lo evitó. A dónde apunta sí acertó las seis veces. Sin esta línea,
|
|
76
|
+
* el desarrollador se pone a buscar una rotación que no existe.
|
|
77
|
+
*/
|
|
78
|
+
lineas.push("Lo que dice que ve (la REDACCIÓN no es fiable: describe mal la causa. Fíate de QUÉ", "control señala, no de su explicación, y míralo tú):");
|
|
79
|
+
for (const o of veredicto.observaciones)
|
|
80
|
+
lineas.push(`- ${o}`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* **Un rojo tiene que ENTERAR a alguien, y el sitio fuerte es aquí.**
|
|
84
|
+
*
|
|
85
|
+
* La regla de «lo que salga vuelve a `developer-xone`» vive en el prompt del
|
|
86
|
+
* orquestador, o sea a miles de tokens del momento en que llega el veredicto. Eso es
|
|
87
|
+
* una sugerencia. Este repo ya tiene escrito que «los avisos de honestidad son código,
|
|
88
|
+
* no prompt», y el patrón para que un modelo haga lo siguiente es el de
|
|
89
|
+
* `xone_navegacion` cuando no sabe contestar: se devuelve el PASO SIGUIENTE escrito, no
|
|
90
|
+
* un consejo — a un modelo al que se le dice qué hacer sin decirle cómo se le inventa
|
|
91
|
+
* los argumentos.
|
|
92
|
+
*
|
|
93
|
+
* **Límite declarado, y es el que queda abierto**: esto no es un tope. No puede serlo
|
|
94
|
+
* desde aquí, porque la tool se construye por SESIÓN y no por turno, así que no tiene
|
|
95
|
+
* dónde contar las vueltas. Lo que acota hoy es que cada arreglo pasa por una
|
|
96
|
+
* aprobación humana. Un tope de verdad exige que el bucle lo lleve el harness
|
|
97
|
+
* (`conVerificacion`), y eso pide conducir el aparato desde código — medido: no se
|
|
98
|
+
* puede, porque llegar a una pantalla necesita abrir cajones y mirar el árbol.
|
|
99
|
+
*/
|
|
100
|
+
if (veredicto.veredicto === "rojo") {
|
|
101
|
+
lineas.push("Esto es un defecto del proyecto SIN ARREGLAR: no lo cuentes y ya está. Encárgaselo a", "`developer-xone` pasándole estas observaciones tal cual, y cuando lo haya corregido", "manda otra vez al conductor a esta misma pantalla y vuelve a llamarme con la captura", "nueva. No des la pantalla por buena hasta que yo la vea en verde.");
|
|
102
|
+
}
|
|
103
|
+
if (veredicto.necesito.length > 0) {
|
|
104
|
+
lineas.push(`Necesita ver ${veredicto.necesito.length === 1 ? "otra pantalla" : "otras pantallas"} para dictaminar: ${veredicto.necesito.join(", ")}.`, `Encarga al conductor que llegue ahí y capture, y vuelve a llamarme con esa captura (como mucho ${TOPE_DE_PETICIONES} veces).`);
|
|
105
|
+
}
|
|
106
|
+
return lineas.join("\n");
|
|
107
|
+
}, {
|
|
108
|
+
name: "xone_critica_visual",
|
|
109
|
+
description: "Enseña una captura de pantalla del aparato a un revisor visual y devuelve qué se ve " +
|
|
110
|
+
"mal: texto cortado, controles solapados o fuera de la pantalla, cosas ilegibles. " +
|
|
111
|
+
"Ve lo que ninguna comprobación estática puede ver. Puede pedir otras pantallas.",
|
|
112
|
+
schema: Entrada,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=criticaVisual.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criticaVisual.js","sourceRoot":"","sources":["../../../src/agent/grafo/criticaVisual.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { tool } from "@langchain/core/tools";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { partirNombre } from "../../core/navegacion.js";
|
|
3
4
|
import { llamadaDeBusqueda } from "./busquedaRegex.js";
|
|
5
|
+
import { pintarEstiloDeProp } from "../../core/estilos.js";
|
|
4
6
|
/**
|
|
5
7
|
* `xone_navegacion`: preguntar por la ESTRUCTURA del proyecto sin leer ficheros.
|
|
6
8
|
*
|
|
@@ -36,16 +38,19 @@ export const LIMITES_NAVEGACION = {
|
|
|
36
38
|
};
|
|
37
39
|
const ESQUEMA = z.object({
|
|
38
40
|
operacion: z
|
|
39
|
-
.enum(["inventario", "definicion", "referencias", "campos", "detalle", "app", "problemas"])
|
|
41
|
+
.enum(["inventario", "definicion", "referencias", "campos", "detalle", "app", "problemas", "estilos"])
|
|
40
42
|
.describe("inventario: todas las colecciones. definicion: dónde se declara. referencias: quién la usa. " +
|
|
41
43
|
"campos: los campos de una colección. detalle: todo de una (campos, eventos, nodos, conexiones). " +
|
|
42
|
-
"app: por dónde arranca la aplicación, login y estilos. problemas: referencias rotas y colecciones que no usa nadie"
|
|
44
|
+
"app: por dónde arranca la aplicación, login y estilos. problemas: referencias rotas y colecciones que no usa nadie. " +
|
|
45
|
+
"estilos: qué estilo acaba aplicándosele a un control y de qué clase y fichero sale — resuelve la cascada, " +
|
|
46
|
+
"que es lo que no se puede averiguar leyendo una hoja de arriba abajo"),
|
|
43
47
|
nombre: z
|
|
44
48
|
.string()
|
|
45
49
|
.min(1)
|
|
46
50
|
.max(200)
|
|
47
51
|
.optional()
|
|
48
|
-
.describe("`Coleccion` o `Coleccion.CAMPO`. No hace falta en `inventario`"
|
|
52
|
+
.describe("`Coleccion` o `Coleccion.CAMPO`. No hace falta en `inventario`. En `estilos` tiene que ser " +
|
|
53
|
+
"`Coleccion.CONTROL`"),
|
|
49
54
|
});
|
|
50
55
|
/** Recorta y DICE lo que se dejó fuera. */
|
|
51
56
|
function recortar(lista, tope, pinta) {
|
|
@@ -61,7 +66,7 @@ const pintarReferencia = (r) => `${r.desde} --${r.por}--> ${r.hacia} ${r.ficher
|
|
|
61
66
|
* pueda decir sobre QUÉ proyecto pregunta: si pudiera, esto sería una tool que lee cualquier
|
|
62
67
|
* carpeta de la máquina.
|
|
63
68
|
*/
|
|
64
|
-
export function crearNavegacionXone(cargar, ficheros) {
|
|
69
|
+
export function crearNavegacionXone(cargar, ficheros, cargarEstilos) {
|
|
65
70
|
return tool(async (entrada) => {
|
|
66
71
|
let indice;
|
|
67
72
|
try {
|
|
@@ -127,6 +132,34 @@ export function crearNavegacionXone(cargar, ficheros) {
|
|
|
127
132
|
}
|
|
128
133
|
return recortar(campos, LIMITES_NAVEGACION.campos, pintarDeclaracion);
|
|
129
134
|
}
|
|
135
|
+
if (entrada.operacion === "estilos") {
|
|
136
|
+
/**
|
|
137
|
+
* **La capa que no tenía índice.** Medido sobre diez pasadas del mismo encargo visual:
|
|
138
|
+
* el turno se iba en 30-42 `grep` de los cuales ~22 de cada 30 eran la MISMA clase con
|
|
139
|
+
* variantes (`xnTituloHeaderC`, `.xnTituloHeader`, `xnHeader`…), más cinco ficheros CSS
|
|
140
|
+
* y varios `.xne` ajenos buscando ejemplos. Nada de eso lo contestaba este índice,
|
|
141
|
+
* porque indexa el modelo `.xne` y el arreglo visual vive en los estilos.
|
|
142
|
+
*
|
|
143
|
+
* La cascada la resuelve `xone-linter` (`Stylesheet.lookup`, fiel a
|
|
144
|
+
* `FindStylesheetByClassName`), no nosotros: ver `agent/navegacion/estilosEnDisco.ts`.
|
|
145
|
+
*/
|
|
146
|
+
if (cargarEstilos === undefined) {
|
|
147
|
+
return "Esta operación no está disponible en este montaje: no se cableó el resolvedor de estilos.";
|
|
148
|
+
}
|
|
149
|
+
const { coleccion, campo } = partirNombre(nombre);
|
|
150
|
+
if (campo === undefined || campo === "") {
|
|
151
|
+
return ("`estilos` necesita el control, no solo la colección: escríbelo como " +
|
|
152
|
+
"`Coleccion.CONTROL`. Con `detalle Coleccion` sale la lista de sus campos.");
|
|
153
|
+
}
|
|
154
|
+
const estilo = await cargarEstilos(coleccion, campo);
|
|
155
|
+
if (estilo === undefined) {
|
|
156
|
+
// Ni la coll ni el prop: se dice cómo averiguar CUÁL de las dos falta, en vez de
|
|
157
|
+
// dejar al agente probando nombres. Misma postura que `detalle`.
|
|
158
|
+
return (`No encuentro el control «${nombre}». Prueba \`detalle ${coleccion}\` para ver sus ` +
|
|
159
|
+
`campos, o búscalo como texto:\n${llamadaDeBusqueda(campo)}`);
|
|
160
|
+
}
|
|
161
|
+
return pintarEstiloDeProp(estilo);
|
|
162
|
+
}
|
|
130
163
|
if (entrada.operacion === "detalle") {
|
|
131
164
|
const d = indice.detalle(nombre);
|
|
132
165
|
// `undefined` y no un detalle vacío: «no existe» y «existe y está vacía» son dos
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navegacionXone.js","sourceRoot":"","sources":["../../../src/agent/grafo/navegacionXone.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"navegacionXone.js","sourceRoot":"","sources":["../../../src/agent/grafo/navegacionXone.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* monta su aprobación humana. Un `.md` puede cambiar el prompt de un agente; no puede
|
|
9
9
|
* concederle leer `/.env`.
|
|
10
10
|
*/
|
|
11
|
+
import { esRutaDeArtefacto, RUTA_ARTEFACTOS } from "../../core/artefactos.js";
|
|
12
|
+
import { esRutaDePlan, RUTA_PLANES } from "../../core/planes.js";
|
|
11
13
|
import { artefactoFueraDeSitio } from "../../core/artefactos.js";
|
|
12
14
|
/** Las tools de fichero que monta deepagents sobre el backend. */
|
|
13
15
|
export const TOOLS_LECTURA = ["ls", "read_file", "glob", "grep"];
|
|
@@ -54,14 +56,35 @@ export function permisosDe(perfil) {
|
|
|
54
56
|
const base = [...DENEGADO_SIEMPRE];
|
|
55
57
|
if (!perfil.soloLectura)
|
|
56
58
|
return base;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
/**
|
|
60
|
+
* **Un agente de SOLO LECTURA sí puede dejar ARTEFACTOS, y la medida que lo permite está
|
|
61
|
+
* hecha.** Este `/**` también denegaba `/artefactos/**`, así que un productor sin shell no
|
|
62
|
+
* podía dejar nada escrito —un análisis, un plan, un informe— aunque no tocara el proyecto.
|
|
63
|
+
* `device-controller` los deja por otro camino, un comando, que no pasa por aquí, y por eso
|
|
64
|
+
* su anuncio vive aparte (`proyecto.ts#anunciarArtefactosDeLaShell`).
|
|
65
|
+
*
|
|
66
|
+
* La duda que quedaba anotada era si un `allow` haría algo o sería decorativo. **Medido
|
|
67
|
+
* contra la librería**: `decidePathAccess` es *first-match-wins* con default permisivo, y su
|
|
68
|
+
* propio docstring lo dice. O sea que la excepción funciona **si va delante** del `deny`
|
|
69
|
+
* general — y por eso el orden de estas tres líneas no es estilo, es la regla.
|
|
70
|
+
*
|
|
71
|
+
* Va DETRÁS de `DENEGADO_SIEMPRE` a propósito: con first-match-wins, eso es lo que mantiene
|
|
72
|
+
* ganando a `/.env`, `/.git` y `/.xonecode`. Delante de ellas, un patrón más ancho escrito
|
|
73
|
+
* mañana los abriría.
|
|
74
|
+
*
|
|
75
|
+
* Y lo que concede está acotado por construcción: `/artefactos/` no es del proyecto, no
|
|
76
|
+
* entra en git, no sube a CloudStudio, no pasa por aprobación —por eso se ANUNCIA con su
|
|
77
|
+
* evento— y `artefactoFueraDeSitio` ya impide que nada de ahí acabe dentro de la app.
|
|
78
|
+
*/
|
|
79
|
+
return [
|
|
80
|
+
...base,
|
|
81
|
+
{ operations: ["write"], paths: [`${RUTA_ARTEFACTOS}**`], mode: "allow" },
|
|
82
|
+
// Y los PLANES, por lo mismo: quien analiza escribe el plan y quien desarrolla marca ahí
|
|
83
|
+
// lo hecho, así que los dos tienen que poder escribir — y ninguno de los dos está tocando
|
|
84
|
+
// el proyecto. `.xonecode/planes/` no entra en git ni sube a CloudStudio.
|
|
85
|
+
{ operations: ["write"], paths: [`${RUTA_PLANES}**`], mode: "allow" },
|
|
86
|
+
{ operations: ["write"], paths: ["/**"], mode: "deny" },
|
|
87
|
+
];
|
|
65
88
|
}
|
|
66
89
|
/**
|
|
67
90
|
* Las tools de fichero de un agente con EJECUCIÓN.
|
|
@@ -195,13 +218,33 @@ export function hitlDe(perfil) {
|
|
|
195
218
|
*
|
|
196
219
|
* Lo que pasa después es lo que se busca: la tool corre, el backend devuelve su `{error}` con
|
|
197
220
|
* la ruta buena, y el modelo reintenta en `/artefactos/`.
|
|
221
|
+
*
|
|
222
|
+
* **Y un SEGUNDO motivo, que es de coherencia y no de relajación**: tampoco se pregunta por lo
|
|
223
|
+
* que NO ES EL PROYECTO —`/artefactos/` y `/planes/`—. No es una excepción nueva: un perfil de
|
|
224
|
+
* SOLO LECTURA ya escribe esas dos rutas sin aprobación ninguna, porque `hitlDe` le devuelve
|
|
225
|
+
* `{}` y sus `permissions` lo confinan exactamente ahí. O sea que la misma ruta no se aprobaba
|
|
226
|
+
* para el analista y sí para el desarrollador, y eso no es una barrera: es una incoherencia que
|
|
227
|
+
* se paga cara — medido, el desarrollador fue a marcar como hecha una tarea de un plan, salió
|
|
228
|
+
* un modal, se rechazó, y el plan se quedó viejo en silencio. En una tarea de fondo no hay
|
|
229
|
+
* nadie que pulse, así que el plan NUNCA se marcaría.
|
|
230
|
+
*
|
|
231
|
+
* Ninguna de las dos rutas es la app del cliente: no entran en el commit del turno, no van a
|
|
232
|
+
* git y no suben a CloudStudio. Lo que sigue intacto es lo único que importa: **por un fichero
|
|
233
|
+
* del PROYECTO siempre se pregunta**, y el test lo comprueba ruta a ruta.
|
|
198
234
|
*/
|
|
199
235
|
export function seDetieneEn(peticion) {
|
|
200
236
|
const args = peticion?.toolCall?.args;
|
|
201
237
|
const ruta = args?.["file_path"];
|
|
202
238
|
if (typeof ruta !== "string")
|
|
203
239
|
return true;
|
|
240
|
+
// (1) Lo que el backend va a rechazar de todas formas: un modal cuyo único final posible es
|
|
241
|
+
// un rechazo enseña a aprobar sin mirar.
|
|
242
|
+
if (artefactoFueraDeSitio(ruta) !== undefined)
|
|
243
|
+
return false;
|
|
244
|
+
// (2) Lo que NO es el proyecto. Ver la cabecera: esto quita una incoherencia, no una barrera.
|
|
245
|
+
if (esRutaDeArtefacto(ruta) || esRutaDePlan(ruta))
|
|
246
|
+
return false;
|
|
204
247
|
// Ante la duda, se PREGUNTA: es la dirección conservadora de siempre.
|
|
205
|
-
return
|
|
248
|
+
return true;
|
|
206
249
|
}
|
|
207
250
|
//# sourceMappingURL=perfiles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perfiles.js","sourceRoot":"","sources":["../../../src/agent/grafo/perfiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAC1E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,WAAW,CAAU,CAAC;AAgBpE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAU;QACtC,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC;QAC/E,IAAI,EAAE,MAAe;KACtB;IACD,wFAAwF;IACxF,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE;IAC3F;;;;;;;;;;;;;;;;;;OAkBG;IACH,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE;CAChG,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,MAA2B;IACpD,MAAM,IAAI,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IACrC
|
|
1
|
+
{"version":3,"file":"perfiles.js","sourceRoot":"","sources":["../../../src/agent/grafo/perfiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAC1E,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,WAAW,CAAU,CAAC;AAgBpE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAU;QACtC,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,CAAC;QAC/E,IAAI,EAAE,MAAe;KACtB;IACD,wFAAwF;IACxF,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE;IAC3F;;;;;;;;;;;;;;;;;;OAkBG;IACH,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE;CAChG,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,MAA2B;IACpD,MAAM,IAAI,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IACrC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO;QACL,GAAG,IAAI;QACP,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,GAAG,eAAe,IAAI,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE;QAC3F,yFAAyF;QACzF,0FAA0F;QAC1F,0EAA0E;QAC1E,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,GAAG,WAAW,IAAI,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE;QACvF,EAAE,UAAU,EAAE,CAAC,OAAO,CAAU,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE;KAC1E,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAU,CAAC;AAQ3F;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,MAA4B;IACxD,OAAO,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA4B,EAC5B,QAAqC;IAErC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC9D,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,CAAC,CACN,IAAI,KAAK,OAAO;QAChB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,uFAAuF;QACvF,0FAA0F;QAC1F,0FAA0F;QAC1F,uFAAuF;QACvF,0CAA0C;QAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,IAAI,KAAK,OAAO;QAChB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,IAAI,KAAK,YAAY;QACrB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,OAAO,CAAC,MAA2B;IACjD,OAAO,MAAM,CAAC,WAAW;QACvB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC;QACpB,CAAC,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,eAAe,CAAC,CAAC;AAC7C,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,GAA2B;IACzC,UAAU,EAAE,kCAAkC;IAC9C,SAAS,EAAE,mCAAmC;CAC/C,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CAAC,MAA2B;IAChD,IAAI,MAAM,CAAC,WAAW;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,MAAM,GAAsC,EAAE,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,GAAG;YACb,gBAAgB,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;YACvC,mFAAmF;YACnF,sFAAsF;YACtF,WAAW,EAAE,IAAI,MAAM,CAAC,MAAM,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE;YACpE,IAAI,EAAE,WAAW;SAClB,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,WAAW,CAAC,QAAiB;IAC3C,MAAM,IAAI,GAAI,QAAqE,EAAE,QAAQ,EAAE,IAAI,CAAC;IACpG,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC;IACjC,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC1C,4FAA4F;IAC5F,6CAA6C;IAC7C,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC5D,8FAA8F;IAC9F,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAChE,sEAAsE;IACtE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { CompositeBackend, FilesystemBackend, LocalShellBackend } from "deepagents";
|
|
4
4
|
import { RUTA_MEMORIA_INTERNA, RUTA_MEMORIA_VIRTUAL } from "./memoriaDeProyecto.js";
|
|
5
5
|
import { RAIZ_SKILLS, skillsConRuta, skillsMontables } from "./skills.js";
|
|
6
6
|
import { artefactoFueraDeSitio, mimeDeArtefacto, nombreDeArtefacto, RUTA_ARTEFACTOS, } from "../../core/artefactos.js";
|
|
7
7
|
import { RUTA_ADJUNTOS } from "../../core/adjuntos.js";
|
|
8
|
-
import {
|
|
8
|
+
import { CARPETA_DE_PLANES, RUTA_PLANES } from "../../core/planes.js";
|
|
9
|
+
import { entornoDeShell, variablesDeAndroid } from "../../core/shellDeAgente.js";
|
|
10
|
+
import { localizadorDeAndroid } from "../dispositivos/dispositivosEnMaquina.js";
|
|
9
11
|
import { RUTAS_DE_DESCARGA, carpetaDeDescargas, descargaFueraDeSitio, porQueNoEsDelProyecto, } from "../../core/descargas.js";
|
|
10
12
|
/**
|
|
11
13
|
* El backend del proyecto: confinado, y sin las vistas aplanadas.
|
|
@@ -66,7 +68,19 @@ export function backendDelProyectoConShell(raiz, entorno) {
|
|
|
66
68
|
* backend y que `cargarAgentes`: una skill instalada con la consola abierta no alcanza a la
|
|
67
69
|
* sesión en curso, que es el límite ya anotado en CLAUDE.md y no uno nuevo.
|
|
68
70
|
*/
|
|
69
|
-
export function entornoDeLaShellDelProyecto(raiz, artefactos
|
|
71
|
+
export function entornoDeLaShellDelProyecto(raiz, artefactos,
|
|
72
|
+
/**
|
|
73
|
+
* El buscador de binarios del SDK de Android. Entra por parámetro **solo** para que un test
|
|
74
|
+
* pueda ver que está montado: esta función toca `process.env` y `existsSync`, así que sin
|
|
75
|
+
* inyectarlo la composición viviría donde ningún test la alcanza — el patrón de fallo que
|
|
76
|
+
* este repo lleva contadas nueve veces. En producción no lo pasa nadie.
|
|
77
|
+
*/
|
|
78
|
+
enSdk = localizadorDeAndroid({
|
|
79
|
+
plataforma: process.platform,
|
|
80
|
+
entorno: process.env,
|
|
81
|
+
home: process.env["HOME"] ?? "",
|
|
82
|
+
existe: (ruta) => existsSync(ruta),
|
|
83
|
+
}).enSdk) {
|
|
70
84
|
// `skillsConRuta` y no `skillsMontables`: aquélla deja fuera las de SERIE —su raíz se cuelga
|
|
71
85
|
// entera en el backend— y una shell necesita la ruta real de todas. Sin esto, los scripts de
|
|
72
86
|
// las skills de serie no llegan al PATH y el agente se queda buscándolos por el disco.
|
|
@@ -78,6 +92,9 @@ export function entornoDeLaShellDelProyecto(raiz, artefactos) {
|
|
|
78
92
|
// va aquí porque `entornoDeShell` es puro: prometer en el PATH una carpeta que no está es
|
|
79
93
|
// el botón muerto de siempre, solo que en una variable de entorno.
|
|
80
94
|
binarios: skills.map((s) => join(s.dir, "scripts")).filter((d) => existsSync(d)),
|
|
95
|
+
// Sin esto, `xone-arrancar-android` tendría que adivinar dónde está el SDK: en un Mac con
|
|
96
|
+
// Homebrew `emulator` no está en el PATH y `ANDROID_HOME` suele estar vacía.
|
|
97
|
+
android: variablesDeAndroid(enSdk),
|
|
81
98
|
...(artefactos === undefined ? {} : { artefactos }),
|
|
82
99
|
});
|
|
83
100
|
}
|
|
@@ -155,6 +172,30 @@ export function backendConAdjuntos(backend, carpeta) {
|
|
|
155
172
|
[RUTA_ADJUNTOS]: new FilesystemBackend({ rootDir: carpeta, virtualMode: true }),
|
|
156
173
|
});
|
|
157
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Cuelga `/planes/` de `.xonecode/planes/`, en el repo LOCAL.
|
|
177
|
+
*
|
|
178
|
+
* El porqué de ese sitio está en `core/planes.ts`. Lo que aporta esto es el montaje, y tiene
|
|
179
|
+
* las mismas dos trampas que `/artefactos/` y `/skills/`:
|
|
180
|
+
*
|
|
181
|
+
* - **La barra final es obligatoria**: `CompositeBackend` la retira antes de delegar, y sin
|
|
182
|
+
* ella reconstruye `//favoritos/PLAN.md`, que `FilesystemBackend` interpreta fuera de su
|
|
183
|
+
* raíz.
|
|
184
|
+
* - **La carpeta NO se crea al montar**: la crea `FilesystemBackend.write` la primera vez que
|
|
185
|
+
* se escribe. Un proyecto en el que nadie ha planificado no tiene por qué tener la carpeta.
|
|
186
|
+
*
|
|
187
|
+
* Y una diferencia con los artefactos que es el motivo de que exista: esto **no se anuncia**.
|
|
188
|
+
* Un artefacto se enseña una vez; un plan se escribe, se lee y se ACTUALIZA por varios
|
|
189
|
+
* especialistas a lo largo de varios turnos, así que un evento por escritura sería ruido.
|
|
190
|
+
*/
|
|
191
|
+
export function backendConPlanes(backend, raiz) {
|
|
192
|
+
return new CompositeBackend(backend, {
|
|
193
|
+
[RUTA_PLANES]: new FilesystemBackend({
|
|
194
|
+
rootDir: join(raiz, CARPETA_DE_PLANES),
|
|
195
|
+
virtualMode: true,
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
158
199
|
/**
|
|
159
200
|
* Cuelga `/artefactos/` de la carpeta de la SESIÓN, fuera del proyecto.
|
|
160
201
|
*
|
|
@@ -328,12 +369,18 @@ export function backendDeAgente(opciones) {
|
|
|
328
369
|
? conArtefactos
|
|
329
370
|
: backendConDescargas(conArtefactos, opciones.artefactos.carpeta);
|
|
330
371
|
const conAdjuntos = opciones.adjuntos === undefined ? conDescargas : backendConAdjuntos(conDescargas, opciones.adjuntos);
|
|
372
|
+
/**
|
|
373
|
+
* Los PLANES van SIEMPRE, sin depender de la sesión: cuelgan del repo local
|
|
374
|
+
* (`.xonecode/planes/`) y no de la carpeta de una sesión, porque un plan se escribe un día y
|
|
375
|
+
* se implementa otro. Es la diferencia con los artefactos, que mueren con su sesión.
|
|
376
|
+
*/
|
|
377
|
+
const conPlanes = backendConPlanes(conAdjuntos, opciones.raiz);
|
|
331
378
|
// Lo que deje un COMANDO en la carpeta de artefactos también se anuncia. Sin esto, la
|
|
332
379
|
// captura que escribe un script existe en el disco y no existe para nadie: el evento
|
|
333
380
|
// `artefacto` lo emite el Proxy de `write`/`edit`, y una shell no pasa por ahí.
|
|
334
381
|
return opciones.ejecucion === undefined || opciones.artefactos === undefined
|
|
335
|
-
?
|
|
336
|
-
: anunciarArtefactosDeLaShell(
|
|
382
|
+
? conPlanes
|
|
383
|
+
: anunciarArtefactosDeLaShell(conPlanes, opciones.artefactos.carpeta, opciones.artefactos.alEscribir);
|
|
337
384
|
}
|
|
338
385
|
/**
|
|
339
386
|
* Anuncia lo que un COMANDO deja en la carpeta de artefactos.
|
|
@@ -347,8 +394,18 @@ export function backendDeAgente(opciones) {
|
|
|
347
394
|
*
|
|
348
395
|
* **Se compara una FOTO de antes con una de después** (nombre → tamaño + mtime) en vez de
|
|
349
396
|
* fiarse de lo que el comando diga que hizo. Un comando puede escribir tres ficheros, o
|
|
350
|
-
* ninguno, o pisar el de antes; lo único que lo sabe es la carpeta.
|
|
351
|
-
*
|
|
397
|
+
* ninguno, o pisar el de antes; lo único que lo sabe es la carpeta.
|
|
398
|
+
*
|
|
399
|
+
* **Y la carpeta se CREA aquí, antes de correr el comando.** Es la excepción a «no se crea
|
|
400
|
+
* al montar», y la pagó una captura: `$XONECODE_ARTEFACTOS` la crea `FilesystemBackend.write`
|
|
401
|
+
* la primera vez que el agente escribe un artefacto por una TOOL, y una shell no pasa por
|
|
402
|
+
* ahí — así que en una sesión que no había dibujado nada, el `writeFileSync` del script de
|
|
403
|
+
* captura reventaba con ENOENT (reproducido) y el modelo se replegaba a dejar el `.png` en
|
|
404
|
+
* la raíz del proyecto, que es justo lo que la regla existe para impedir. El sitio es este y
|
|
405
|
+
* no el script: quien SABE que va a correr una shell y DÓNDE está la carpeta es el harness,
|
|
406
|
+
* y arreglarlo en el script lo dejaría arreglado en uno de cinco —y en ninguna skill del
|
|
407
|
+
* usuario—, que es el patrón de fallo de siempre. Se crea solo cuando hay ejecución, así que
|
|
408
|
+
* una sesión de los otros cuatro especialistas sigue sin carpeta vacía.
|
|
352
409
|
*/
|
|
353
410
|
export function anunciarArtefactosDeLaShell(backend, carpeta, alEscribir) {
|
|
354
411
|
const foto = () => {
|
|
@@ -380,6 +437,16 @@ export function anunciarArtefactosDeLaShell(backend, carpeta, alEscribir) {
|
|
|
380
437
|
if (prop !== "execute")
|
|
381
438
|
return valor.bind(destino);
|
|
382
439
|
return async (...args) => {
|
|
440
|
+
try {
|
|
441
|
+
// Antes de la foto: si el comando es el que escribe la captura, la carpeta tiene
|
|
442
|
+
// que existir YA. Un fallo al crearla no puede tumbar el comando —se podía correr
|
|
443
|
+
// sin carpeta antes de esto—, así que se traga y la foto sigue tolerando su
|
|
444
|
+
// ausencia.
|
|
445
|
+
mkdirSync(carpeta, { recursive: true });
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// Sin carpeta no hay artefactos que anunciar, y el comando no es asunto suyo.
|
|
449
|
+
}
|
|
383
450
|
const antes = foto();
|
|
384
451
|
try {
|
|
385
452
|
return await valor.apply(destino, args);
|