xonecode 0.33.0 → 0.35.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/{EditorDeFichero-H_kGeZt2.js → EditorDeFichero-CGZ6uZPa.js} +1 -1
- package/apps/web/dist/assets/index-BBQH-l_3.css +1 -0
- package/apps/web/dist/assets/index-DqYXrrxo.js +499 -0
- package/apps/web/dist/assets/{php-CMFQiZgk.js → php-DTPkbJvq.js} +1 -1
- package/apps/web/dist/assets/{ruby-Dj3BOBHc.js → ruby-D1wBOK7G.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/config/fuentesEnRed.js +80 -0
- package/dist/agent/config/fuentesEnRed.js.map +1 -0
- package/dist/agent/dispositivos/cajasDeMaqueta.js +90 -2
- package/dist/agent/dispositivos/cajasDeMaqueta.js.map +1 -1
- package/dist/agent/dispositivos/geometriaEnDisco.js +85 -3
- package/dist/agent/dispositivos/geometriaEnDisco.js.map +1 -1
- package/dist/agent/grafo/criticaVisual.js +43 -37
- package/dist/agent/grafo/criticaVisual.js.map +1 -1
- package/dist/agent/grafo/fuentesDeGoogle.js +133 -0
- package/dist/agent/grafo/fuentesDeGoogle.js.map +1 -0
- package/dist/agent/grafo/incorporarAdjunto.js +52 -42
- package/dist/agent/grafo/incorporarAdjunto.js.map +1 -1
- package/dist/agent/grafo/perfiles.js +2 -0
- package/dist/agent/grafo/perfiles.js.map +1 -1
- package/dist/agent/motores/trueforge/capacidades.js +9 -6
- package/dist/agent/motores/trueforge/capacidades.js.map +1 -1
- package/dist/agent/motores/trueforge/informesDeHijos.js +39 -7
- package/dist/agent/motores/trueforge/informesDeHijos.js.map +1 -1
- package/dist/agent/motores/trueforge/memoriaDeEspecialistas.js +75 -37
- package/dist/agent/motores/trueforge/memoriaDeEspecialistas.js.map +1 -1
- package/dist/agent/motores/trueforge/memoriaTrueforge.js +24 -4
- package/dist/agent/motores/trueforge/memoriaTrueforge.js.map +1 -1
- package/dist/agent/motores/trueforge/modeloLangchain.js +28 -4
- package/dist/agent/motores/trueforge/modeloLangchain.js.map +1 -1
- package/dist/agent/motores/trueforge/proponerTareas.js +67 -0
- package/dist/agent/motores/trueforge/proponerTareas.js.map +1 -0
- package/dist/agent/motores/trueforge/sesionTrueforge.js +159 -15
- package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -1
- package/dist/agent/sesiones/adjuntosDeSesion.js +68 -1
- package/dist/agent/sesiones/adjuntosDeSesion.js.map +1 -1
- package/dist/agent/subagentes/agentesEnDisco.js +12 -4
- package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
- package/dist/agent/tareas/aumentador.js +4 -3
- package/dist/agent/tareas/aumentador.js.map +1 -1
- package/dist/agent/tareas/juezDeTarea.js +53 -1
- package/dist/agent/tareas/juezDeTarea.js.map +1 -1
- package/dist/agent/turno/informeDeTraza.js +2 -1
- package/dist/agent/turno/informeDeTraza.js.map +1 -1
- package/dist/agent/turno/interrupts.js +12 -0
- package/dist/agent/turno/interrupts.js.map +1 -1
- package/dist/agent/turno/resumenDeTool.js +4 -0
- package/dist/agent/turno/resumenDeTool.js.map +1 -1
- package/dist/agent/turno/turnoReal.js +3 -0
- package/dist/agent/turno/turnoReal.js.map +1 -1
- package/dist/cli/consola.js.map +1 -1
- package/dist/cli/main.js +4 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tui/transcript.js +5 -0
- package/dist/cli/tui/transcript.js.map +1 -1
- package/dist/core/actos.js.map +1 -1
- package/dist/core/agentes.js +10 -0
- package/dist/core/agentes.js.map +1 -1
- package/dist/core/analisisDeSesion.js +1 -1
- package/dist/core/analisisDeSesion.js.map +1 -1
- package/dist/core/descripcionDePantalla.js +26 -13
- package/dist/core/descripcionDePantalla.js.map +1 -1
- package/dist/core/entrega.js +31 -2
- package/dist/core/entrega.js.map +1 -1
- package/dist/core/estiloMedido.js +21 -1
- package/dist/core/estiloMedido.js.map +1 -1
- package/dist/core/fuentes.js +174 -0
- package/dist/core/fuentes.js.map +1 -0
- package/dist/core/geometriaDePantalla.js +101 -1
- package/dist/core/geometriaDePantalla.js.map +1 -1
- package/dist/core/modoDeEscritura.js +4 -1
- package/dist/core/modoDeEscritura.js.map +1 -1
- package/dist/core/notify.js +4 -0
- package/dist/core/notify.js.map +1 -1
- package/dist/core/ports.js +35 -0
- package/dist/core/ports.js.map +1 -1
- package/dist/core/repartoDeEncargo.js +110 -0
- package/dist/core/repartoDeEncargo.js.map +1 -0
- package/dist/core/shellDeAgente.js +23 -0
- package/dist/core/shellDeAgente.js.map +1 -1
- package/dist/core/tareas.js +62 -1
- package/dist/core/tareas.js.map +1 -1
- package/dist/core/turno.js +15 -0
- package/dist/core/turno.js.map +1 -1
- package/dist/web/servidor/arranque.js +171 -14
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/consolaWeb.js +5 -0
- package/dist/web/servidor/consolaWeb.js.map +1 -1
- package/dist/web/servidor/corredorDeTareas.js +15 -2
- package/dist/web/servidor/corredorDeTareas.js.map +1 -1
- package/dist/web/servidor/interrupcion.js +52 -0
- package/dist/web/servidor/interrupcion.js.map +1 -0
- package/dist/web/servidor/pielWeb.js +36 -0
- package/dist/web/servidor/pielWeb.js.map +1 -1
- package/dist/web/servidor/transporte.js +1 -0
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +43 -2
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +1 -1
- package/skills/xone-development/references/css/de-una-maqueta-a-xone.md +6 -4
- package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +4 -4
- package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +4 -4
- package/apps/web/dist/assets/index-CWBaotdZ.css +0 -1
- package/apps/web/dist/assets/index-DnGuOvbb.js +0 -499
|
@@ -59,16 +59,20 @@ import { anuncioDeSkills } from "./skillsTrueforge.js";
|
|
|
59
59
|
import { capabilitiesDe, capacidadDeFecha, capacidadDeFicheros, capacidadDeAvisoDeVueltas, capacidadDeInstrucciones, capacidadDeNotas, capacidadDeConectores, capacidadDePropias, capacidadDeRecortes, capacidadesDelEspecialista, clasesDeTools, toolsDe, } from "./capacidades.js";
|
|
60
60
|
import { crearConectoresDeSesion, tarjetaDeRemota } from "./toolsDeConectores.js";
|
|
61
61
|
import { CONECTOR_STITCH, crearTraerDeStitch } from "./traerDeStitch.js";
|
|
62
|
+
import { crearProponerTareas, REPARTIR_EN_TAREAS } from "./proponerTareas.js";
|
|
63
|
+
import { avisoDeReparto } from "../../../core/repartoDeEncargo.js";
|
|
64
|
+
import { leerTareasDelPlan, RUTA_DE_TASKS } from "../../../core/tareasDelPlan.js";
|
|
62
65
|
import { esDeLaMaqueta } from "../../../core/stitch.js";
|
|
63
66
|
import { recibeConectores } from "../../../core/conectores.js";
|
|
64
67
|
import { buscarMaqueta, medirContraMaqueta, resumenDeMedida, textoDeMedidaAutomatica, ultimaCaptura } from "./medidaAutomatica.js";
|
|
65
|
-
import { anotarEscritura, capacidadDeInformesDeHijos, escrituraConExito, textoDelInforme } from "./informesDeHijos.js";
|
|
68
|
+
import { anotarEscritura, capacidadDeInformesDeHijos, esEscrituraBinaria, escrituraConExito, textoDelInforme } from "./informesDeHijos.js";
|
|
66
69
|
import { crearDiagnosticoDeTools } from "../../turno/diagnosticoDeTools.js";
|
|
67
70
|
import { encenderTrazaDeErrores } from "../../trazaDeErroresEnDisco.js";
|
|
68
71
|
import { anotarPaso } from "../../../core/trazaDeErrores.js";
|
|
69
72
|
import { entornoConDepuracion } from "../../turno/depuracion.js";
|
|
70
73
|
import { detalleDe, parametrosDe } from "../../turno/resumenDeTool.js";
|
|
71
|
-
import {
|
|
74
|
+
import { lineaDeComprobacion, TOPE_DE_COMPROBACIONES_AL_JUEZ } from "../../../core/entrega.js";
|
|
75
|
+
import { apartarMemoria, cargarMemoria, fotoSaneada, guardarMemoria, saldarColgadas, textoDeInterrupcion, textoDeMemoriaDescartada } from "./memoriaTrueforge.js";
|
|
72
76
|
import { crearNota, sobrantes } from "./notas.js";
|
|
73
77
|
import { crearMemoriaDeEspecialistas } from "./memoriaDeEspecialistas.js";
|
|
74
78
|
import { crearEsperas } from "./esperas.js";
|
|
@@ -83,13 +87,14 @@ import { hechosDelProyectoDe } from "../../navegacion/hechosEnDisco.js";
|
|
|
83
87
|
import { conHechosDelProyecto } from "../../../core/hechosDelProyecto.js";
|
|
84
88
|
import { crearBusquedaRegex } from "../../grafo/busquedaRegex.js";
|
|
85
89
|
import { crearBuscarIcono, recibeBuscarIcono } from "../../grafo/buscarIcono.js";
|
|
90
|
+
import { crearBuscarFuente, crearTraerFuente, recibeFuentes } from "../../grafo/fuentesDeGoogle.js";
|
|
86
91
|
import { crearGenerarFondoSvg, recibeGenerarFondo } from "../../grafo/generarFondoSvg.js";
|
|
87
92
|
import { crearCopiarArtefacto } from "../../grafo/copiarArtefacto.js";
|
|
88
93
|
import { crearMarcarCriteriosDelPlan } from "../../grafo/marcarCriteriosDelPlan.js";
|
|
89
94
|
import { crearUnirSecciones } from "../../grafo/unirSecciones.js";
|
|
90
95
|
import { crearIncorporarAdjunto, recibeIncorporarAdjunto } from "../../grafo/incorporarAdjunto.js";
|
|
91
96
|
import { crearCriticaVisual } from "../../grafo/criticaVisual.js";
|
|
92
|
-
import { crearCompararCapturas } from "../../grafo/compararCapturas.js";
|
|
97
|
+
import { crearCompararCapturas, NOMBRE_COMPARAR_CAPTURAS } from "../../grafo/compararCapturas.js";
|
|
93
98
|
import { crearAtributosXone, NOMBRE_ATRIBUTOS_XONE } from "../../grafo/atributosXone.js";
|
|
94
99
|
import { crearDiferenciaDeCapturas } from "../../grafo/diferenciaDeCapturas.js";
|
|
95
100
|
import { crearLectorDeReferencias, crearLocalizadorDeHtmlDeMaqueta } from "../../grafo/lectorDeReferencias.js";
|
|
@@ -272,7 +277,7 @@ export function textoDelBucle(llama, opciones = {}) {
|
|
|
272
277
|
...(puedeDiseñar
|
|
273
278
|
? [
|
|
274
279
|
"El LAYOUT y el CSS son TUYOS: si la pantalla se ve mal, lo arreglas tú, no se lo pasas a nadie ni lo devuelves al que te",
|
|
275
|
-
"encargó. `designer-xone` solo hace RECURSOS —iconos de una biblioteca y fondos SVG en `icons/`—: pídeselos juntos, con para",
|
|
280
|
+
"encargó. `designer-xone` solo hace RECURSOS —iconos de una biblioteca y fondos SVG en `icons/`, y las fuentes en `fonts/`—: pídeselos juntos, con para",
|
|
276
281
|
"qué control, tamaño en píxeles y colores, y usa los nombres que te devuelva. No le pidas que toque el `.xne` ni el CSS: no puede.",
|
|
277
282
|
"Los recursos te llegan con una TABLA (fichero → control → atributo → tamaño → si lleva el símbolo dentro): úsala y no abras",
|
|
278
283
|
"los SVG para enterarte de lo que ya dice.",
|
|
@@ -294,8 +299,18 @@ export function textoDelBucle(llama, opciones = {}) {
|
|
|
294
299
|
"de la tarea en el `TASKS.md` comprobadas, (2) la app arranca y hace lo que pide, y (3) con diseño, la distancia que mide",
|
|
295
300
|
"`comparar_capturas` por debajo del 10 % en vertical y en horizontal, que ENCAJE en la pantalla (cada borde del contenido a",
|
|
296
301
|
"un 3 % o menos del de la maqueta: que llegue a los lados y abajo como ella), y el crítico sin diferencias de forma ni de estructura.",
|
|
297
|
-
|
|
298
|
-
|
|
302
|
+
// Con el puerto de fuentes la tipografía SÍ se reproduce: se trae a `fonts/` (`fuentesDeGoogle.ts`). Sin él, sigue fuera.
|
|
303
|
+
...(opciones.conFuentes === true
|
|
304
|
+
? [
|
|
305
|
+
"Lo que XOne NO puede reproducir no cuenta y no lo persigas: el desenfoque de fondo y las animaciones; una sombra o un",
|
|
306
|
+
"degradado se aproximan con un SVG. La TIPOGRAFÍA del diseño sí: si la maqueta declara una fuente, sus .ttf van a `fonts/`",
|
|
307
|
+
"(pídeselos a designer-xone con los recursos, o tráelos tú con `buscar_fuente`/`traer_fuente`) y se usa con `fontname`;",
|
|
308
|
+
"para verla en el aparato hay que DESPLEGAR entero. Tienes TRES vueltas de corregir y volver a comprobar para",
|
|
309
|
+
]
|
|
310
|
+
: [
|
|
311
|
+
"Lo que XOne NO puede reproducir no cuenta y no lo persigas: las tipografías del diseño (no hay .ttf), el desenfoque de fondo y",
|
|
312
|
+
"las animaciones; una sombra o un degradado se aproximan con un SVG. Tienes TRES vueltas de corregir y volver a comprobar para",
|
|
313
|
+
]),
|
|
299
314
|
"llegar; si al agotarlas algo",
|
|
300
315
|
"sigue sin cumplirse, devuelve el trabajo diciendo QUÉ falta, con lo que midieron el crítico y la medida tal cual. Devolver antes",
|
|
301
316
|
"porque «ya funciona» es dejar el trabajo a medias. Al devolver cuenta lo que se midió: el juicio final no es tuyo, y el arnés",
|
|
@@ -329,7 +344,9 @@ export function notaDeDelegacion(agentes, opciones = {}) {
|
|
|
329
344
|
"cada encargo a developer-xone lleva el CRITERIO ESCRITO y MEDIBLE: qué casillas del plan tiene que dejar comprobadas, qué",
|
|
330
345
|
"tiene que hacer la app, y, si hay diseño, que la distancia de `comparar_capturas` quede por debajo del 10 % en vertical y en",
|
|
331
346
|
"horizontal, que ENCAJE en la pantalla (cada borde a un 3 % o menos del de la maqueta) y que el crítico no señale diferencias de forma o de estructura (di dónde está la maqueta). No se puede pedir",
|
|
332
|
-
|
|
347
|
+
opciones.conFuentes === true
|
|
348
|
+
? "lo que XOne no reproduce —el desenfoque de fondo, las animaciones—; la tipografía del diseño sí (sus .ttf a `fonts/`). Sin criterio, devolverá el"
|
|
349
|
+
: "lo que XOne no reproduce —las tipografías del diseño, el desenfoque de fondo, las animaciones—. Sin criterio, devolverá el",
|
|
333
350
|
"trabajo en cuanto funcione. No le encargues a device-controller comprobar SU",
|
|
334
351
|
"trabajo, ni a designer-xone lo visual de su pantalla (designer-xone no puede tocar un `.xne` ni el CSS): llama tú al diseñador",
|
|
335
352
|
"para los RECURSOS que la pantalla necesite, antes del desarrollador. Lo que developer-xone te devuelva es lo que él vio y midió, no un veredicto: el juicio final es tuyo y del arnés.",
|
|
@@ -475,6 +492,8 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
475
492
|
/** Lo que escribió cada hijo en su encargo, quién lo llamó, y los informes que esperan a ese padre (`informesDeHijos.ts`). */
|
|
476
493
|
const escritosDeCadaHilo = new Map();
|
|
477
494
|
const padreDeHilo = new Map();
|
|
495
|
+
/** Qué hijo nació de cada `create_sub_agent` del raíz (id de la llamada → hilo): la foto a mitad de turno lo nombra. */
|
|
496
|
+
const hiloDeLlamadaDelRaiz = new Map();
|
|
478
497
|
const informesPendientes = new Map();
|
|
479
498
|
/** Las escrituras pedidas y aún sin respuesta, por hilo e id: la respuesta de una aprobada llega en OTRO `paso`. */
|
|
480
499
|
const escriturasEnVuelo = new Map();
|
|
@@ -497,9 +516,52 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
497
516
|
/** Lo que el agente dejó en `/artefactos/` y aún no se ha anunciado: un artefacto se escribe
|
|
498
517
|
* SIN aprobación, así que tiene que ANUNCIARSE, como en deepagents. */
|
|
499
518
|
const artefactosPorAnunciar = [];
|
|
519
|
+
/** Las propuestas de reparto (`proponer_tareas`) que aún no se han anunciado: van a la persona como evento. */
|
|
520
|
+
const propuestasPorAnunciar = [];
|
|
521
|
+
/** Los planes por los que ya se recordó el reparto: una vez por plan, no en cada vuelta del analista. */
|
|
522
|
+
const planesRecordados = new Set();
|
|
523
|
+
/**
|
|
524
|
+
* El recordatorio de repartir (`core/repartoDeEncargo.ts#avisoDeReparto`) cuando un hijo del raíz deja escrito un
|
|
525
|
+
* `TASKS.md` grande, y solo si esta sesión puede proponer. Se lee el plan por el MISMO backend del agente; si no se
|
|
526
|
+
* puede leer, no se recuerda nada (es un recordatorio, no una regla).
|
|
527
|
+
*/
|
|
528
|
+
const avisoDeRepartoTras = async (escritos) => {
|
|
529
|
+
if (opciones.puedeProponerTareas !== true)
|
|
530
|
+
return undefined;
|
|
531
|
+
const planes = [];
|
|
532
|
+
for (const ruta of escritos.keys()) {
|
|
533
|
+
if (!RUTA_DE_TASKS.test(ruta) || planesRecordados.has(ruta))
|
|
534
|
+
continue;
|
|
535
|
+
try {
|
|
536
|
+
const r = (await backend.read(ruta, 0, 100_000));
|
|
537
|
+
if (typeof r.content !== "string")
|
|
538
|
+
continue;
|
|
539
|
+
planes.push({ ruta, tareas: leerTareasDelPlan(r.content).tareas.length });
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
// Sin plan legible no hay recordatorio.
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
const aviso = avisoDeReparto(planes);
|
|
546
|
+
if (aviso !== undefined)
|
|
547
|
+
for (const p of planes)
|
|
548
|
+
planesRecordados.add(p.ruta);
|
|
549
|
+
return aviso;
|
|
550
|
+
};
|
|
500
551
|
/** Las IMÁGENES que dejó el turno en curso, para el crítico de pantalla. Se vacía al empezar
|
|
501
552
|
* cada turno: una captura de antes enseña la pantalla de antes. */
|
|
502
553
|
let capturasDelTurno = [];
|
|
554
|
+
/** Lo que dieron las comprobaciones visuales del turno, una línea cada una, para el juez de QA (`ResultadoDeTurno`). */
|
|
555
|
+
let comprobacionesDelTurno = [];
|
|
556
|
+
const anotarComprobacion = (linea) => {
|
|
557
|
+
comprobacionesDelTurno = [...comprobacionesDelTurno, linea].slice(-TOPE_DE_COMPROBACIONES_AL_JUEZ);
|
|
558
|
+
};
|
|
559
|
+
function* propuestasPendientes() {
|
|
560
|
+
while (propuestasPorAnunciar.length > 0) {
|
|
561
|
+
const p = propuestasPorAnunciar.shift();
|
|
562
|
+
yield { tipo: "propuesta-de-tareas", motivo: p.motivo, tareas: p.tareas };
|
|
563
|
+
}
|
|
564
|
+
}
|
|
503
565
|
const anotarArtefacto = (a) => {
|
|
504
566
|
artefactosPorAnunciar.push(a);
|
|
505
567
|
// La MAQUETA traída (`/artefactos/diseno/`) no es una captura del aparato: el crítico de pantalla
|
|
@@ -663,7 +725,8 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
663
725
|
// La maqueta casi nunca está en /artefactos/: la trae la persona (/adjuntos/) o vive en /diseno/.
|
|
664
726
|
leerReferencia: lectorDeReferencias,
|
|
665
727
|
// La GEOMETRÍA: el árbol guardado con la captura, y las cajas de la maqueta si trae `code.html`.
|
|
666
|
-
|
|
728
|
+
// Por nombre y, si se renombró o convirtió (`sips … --out menu.png`), por los PÍXELES de la original (`geometriaEnDisco.ts`).
|
|
729
|
+
leerGeometria: async (nombre) => geometriaDeCaptura(carpetaDeHotswap(carpeta), nombre, { carpetaDeArtefactos: carpeta, decodificar: decodificarImagen }),
|
|
667
730
|
cajasDeMaqueta: async (imagen, bytes) => {
|
|
668
731
|
const html = localizadorDeHtml(imagen);
|
|
669
732
|
const medidas = medidasDeImagen(bytes);
|
|
@@ -719,6 +782,9 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
719
782
|
...herramientasDeJuicio(),
|
|
720
783
|
...(carpeta === undefined ? [] : [crearTraerDeLaMaquina({ carpeta, alEscribir: anotarArtefacto })]),
|
|
721
784
|
...traerDeStitch(),
|
|
785
|
+
...(opciones.puedeProponerTareas === true
|
|
786
|
+
? [crearProponerTareas((p) => void propuestasPorAnunciar.push(p))]
|
|
787
|
+
: []),
|
|
722
788
|
];
|
|
723
789
|
const propiasDe = (agente) => [
|
|
724
790
|
crearBusquedaRegex(backend),
|
|
@@ -743,6 +809,14 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
743
809
|
...(opciones.iconos !== undefined && recibeBuscarIcono(agente)
|
|
744
810
|
? [crearBuscarIcono(opciones.iconos)]
|
|
745
811
|
: []),
|
|
812
|
+
// Las fuentes de la maqueta (Google Fonts) a `fonts/`: al desarrollador y al diseñador (`recibeFuentes`), con el
|
|
813
|
+
// puerto. `traer_fuente` ESCRIBE un binario: `capacidadesDelEspecialista` la pone en `requireApprovalForTools`.
|
|
814
|
+
...(opciones.fuentes !== undefined && recibeFuentes(agente)
|
|
815
|
+
? [
|
|
816
|
+
crearBuscarFuente(opciones.fuentes),
|
|
817
|
+
crearTraerFuente(opciones.fuentes, { raiz, perfil: agente }),
|
|
818
|
+
]
|
|
819
|
+
: []),
|
|
746
820
|
// Fondos SVG: pura y sin red, sin puerto; a quien escribe el proyecto, como deepagents.
|
|
747
821
|
...(recibeGenerarFondo(agente) ? [crearGenerarFondoSvg()] : []),
|
|
748
822
|
// ¿Cambió la zona tras el toque? Al conductor, que es quien saca las capturas: comprueba una
|
|
@@ -913,6 +987,9 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
913
987
|
const hiloDelPadre = params.parent?.thread_id;
|
|
914
988
|
if (hiloDelPadre !== undefined && hiloDelPadre !== "")
|
|
915
989
|
padreDeHilo.set(params.threadId, hiloDelPadre);
|
|
990
|
+
const llamadaDelPadre = params.parent?.tool_call_id;
|
|
991
|
+
if (hiloDelPadre === HILO_RAIZ && llamadaDelPadre !== undefined)
|
|
992
|
+
hiloDeLlamadaDelRaiz.set(llamadaDelPadre, params.threadId);
|
|
916
993
|
nacimientoDeHilo.set(params.threadId, Date.now());
|
|
917
994
|
quienEs.set(params.threadId, agente?.nombre ?? params.request.name);
|
|
918
995
|
if (agente !== undefined)
|
|
@@ -957,7 +1034,7 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
957
1034
|
"",
|
|
958
1035
|
nota,
|
|
959
1036
|
anuncioDeSkills(agente, catalogo),
|
|
960
|
-
...(conBucleDelDesarrollador && (agente.llama?.length ?? 0) > 0 ? ["", textoDelBucle(agente.llama ?? [], { conCritica: carpeta !== undefined })] : []),
|
|
1037
|
+
...(conBucleDelDesarrollador && (agente.llama?.length ?? 0) > 0 ? ["", textoDelBucle(agente.llama ?? [], { conCritica: carpeta !== undefined, conFuentes: opciones.fuentes !== undefined })] : []),
|
|
961
1038
|
]
|
|
962
1039
|
.filter((l) => l !== undefined)
|
|
963
1040
|
.join("\n")
|
|
@@ -1052,7 +1129,7 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1052
1129
|
hijosConMemoria.clear();
|
|
1053
1130
|
const definicion = {
|
|
1054
1131
|
modelClient: llm,
|
|
1055
|
-
instruction: [IDIOMA_DE_LA_RESPUESTA, SIN_HABLAR_DEL_HARNESS, promptOrquestador(especialistas()), notaDeDelegacion(especialistas(), { conIconos: opciones.iconos !== undefined, conComparacion: carpeta !== undefined, conMemoria: conMemoriaDeEspecialistas, conBucle: conBucleDelDesarrollador, conEsperas })].filter((l) => l !== "").join("\n\n"),
|
|
1132
|
+
instruction: [IDIOMA_DE_LA_RESPUESTA, SIN_HABLAR_DEL_HARNESS, promptOrquestador(especialistas()), notaDeDelegacion(especialistas(), { conIconos: opciones.iconos !== undefined, conFuentes: opciones.fuentes !== undefined, conComparacion: carpeta !== undefined, conMemoria: conMemoriaDeEspecialistas, conBucle: conBucleDelDesarrollador, conEsperas }), opciones.puedeProponerTareas === true ? REPARTIR_EN_TAREAS : ""].filter((l) => l !== "").join("\n\n"),
|
|
1056
1133
|
// Por TURNO, porque el raíz se rehace desde su foto al final de cada uno (ver `turno`).
|
|
1057
1134
|
iterationLimit: LIMITE_DE_LLAMADAS_DEL_RAIZ,
|
|
1058
1135
|
};
|
|
@@ -1113,6 +1190,51 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1113
1190
|
* de terminal no lo pasa, la misma regla que el checkpoint de deepagents.
|
|
1114
1191
|
*/
|
|
1115
1192
|
const persistir = opciones.hilo !== undefined;
|
|
1193
|
+
/**
|
|
1194
|
+
* **La foto A MITAD de turno.** La del `finally` no basta: un corte DURO —el proceso muere, sin
|
|
1195
|
+
* cierre ordenado— no pasa por él, y medido en el incidente que lo motiva, un turno de 45 minutos
|
|
1196
|
+
* se perdió entero, mensaje de la persona incluido, aunque los ficheros sí habían cambiado.
|
|
1197
|
+
* deepagents no lo sufre: su checkpointer guarda cada paso.
|
|
1198
|
+
*
|
|
1199
|
+
* Se guarda en cada añadido del RAÍZ —el primero es el mensaje de la persona— y cada vez que un
|
|
1200
|
+
* hijo completa una escritura, porque lo escrito no toca el contexto del raíz y la foto lo nombra.
|
|
1201
|
+
* `toSnapshot()` es seguro aquí: la librería SUSTITUYE el contexto (`concat`), nunca lo muta, y
|
|
1202
|
+
* guardar es atómico. Las tool calls abiertas se saldan con el texto de una INTERRUPCIÓN
|
|
1203
|
+
* (`textoDeInterrupcion`), no con el de un turno cortado: tras un corte, «vuelve a pedirlo»
|
|
1204
|
+
* duplicaría lo que el especialista ya dejó en el disco. El turno que acaba bien la PISA con la
|
|
1205
|
+
* del `finally`, así que esta foto solo se lee si el proceso murió. Nunca tumba un turno.
|
|
1206
|
+
*/
|
|
1207
|
+
let ultimaAMitad;
|
|
1208
|
+
const escritosDeLaRama = (hijo) => {
|
|
1209
|
+
const deLaRama = (h) => {
|
|
1210
|
+
for (let actual = h; actual !== undefined; actual = padreDeHilo.get(actual))
|
|
1211
|
+
if (actual === hijo)
|
|
1212
|
+
return true;
|
|
1213
|
+
return false;
|
|
1214
|
+
};
|
|
1215
|
+
return [...new Set([...escritosDeCadaHilo].filter(([h]) => deLaRama(h)).flatMap(([, cambios]) => [...cambios.keys()]))];
|
|
1216
|
+
};
|
|
1217
|
+
const guardarAMitad = () => {
|
|
1218
|
+
if (!persistir || raizActual === undefined)
|
|
1219
|
+
return;
|
|
1220
|
+
const foto = raizActual.toSnapshot();
|
|
1221
|
+
const escritos = [...escritosDeCadaHilo.values()].reduce((n, cambios) => n + cambios.size, 0);
|
|
1222
|
+
if (ultimaAMitad?.context === foto.context && ultimaAMitad.escritos === escritos)
|
|
1223
|
+
return;
|
|
1224
|
+
ultimaAMitad = { context: foto.context, escritos };
|
|
1225
|
+
const textoDe = (id) => {
|
|
1226
|
+
const hijo = hiloDeLlamadaDelRaiz.get(id);
|
|
1227
|
+
if (hijo === undefined)
|
|
1228
|
+
return textoDeInterrupcion({ escritos: [] });
|
|
1229
|
+
return textoDeInterrupcion({ especialista: especialistaDeHilo.get(hijo) ?? quienEs.get(hijo) ?? hijo, escritos: escritosDeLaRama(hijo) });
|
|
1230
|
+
};
|
|
1231
|
+
try {
|
|
1232
|
+
guardarMemoria(raiz, hilo, { ...foto, context: saldarColgadas(foto.context, undefined, textoDe) });
|
|
1233
|
+
}
|
|
1234
|
+
catch {
|
|
1235
|
+
// Sin la foto de a mitad el turno sigue: lo peor es lo de antes, perderlo si el proceso muere.
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1116
1238
|
/** El aviso de una memoria que existía y no se entendió: sale en el PRIMER turno y se gasta. */
|
|
1117
1239
|
let avisoDeMemoria;
|
|
1118
1240
|
/**
|
|
@@ -1180,6 +1302,9 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1180
1302
|
async function* paso(lote, senal, pendientes, preguntas = []) {
|
|
1181
1303
|
for await (const _ of orquestador.send(lote))
|
|
1182
1304
|
void _;
|
|
1305
|
+
// Lo que acaba de entrar en el raíz —el mensaje de la persona, una aprobación, una reparación—
|
|
1306
|
+
// ya está a salvo antes de la primera llamada al modelo.
|
|
1307
|
+
guardarAMitad();
|
|
1183
1308
|
const llamadas = new Map();
|
|
1184
1309
|
// El razonamiento de los especialistas, juntado por hilo hasta que su mensaje se completa.
|
|
1185
1310
|
const pensamientos = new Map();
|
|
@@ -1188,6 +1313,8 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1188
1313
|
while (!r.done) {
|
|
1189
1314
|
const evento = r.value;
|
|
1190
1315
|
const deHilo = evento.thread_id ?? HILO_RAIZ;
|
|
1316
|
+
if (deHilo === HILO_RAIZ && evento.type === "internal.agent.context.append")
|
|
1317
|
+
guardarAMitad();
|
|
1191
1318
|
if (evento.type === "internal.agent.context.append" && Array.isArray(evento.output)) {
|
|
1192
1319
|
for (const m of evento.output) {
|
|
1193
1320
|
for (const t of m.tool_calls ?? []) {
|
|
@@ -1199,8 +1326,9 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1199
1326
|
args = {};
|
|
1200
1327
|
}
|
|
1201
1328
|
llamadas.set(claveDe(deHilo, t.id), { nombre: t.function.name, args });
|
|
1202
|
-
if (t.function.name === "write_file" || t.function.name === "edit_file")
|
|
1329
|
+
if (t.function.name === "write_file" || t.function.name === "edit_file" || esEscrituraBinaria(t.function.name)) {
|
|
1203
1330
|
escriturasEnVuelo.set(claveDe(deHilo, t.id), { nombre: t.function.name, args });
|
|
1331
|
+
}
|
|
1204
1332
|
if (t.function.name === "xone_critica_visual")
|
|
1205
1333
|
ultimaCriticaDeHilo.set(deHilo, Date.now());
|
|
1206
1334
|
// La traza: la MISMA lista blanca que el evento (`detalleDe`, `parametrosDe`), nunca
|
|
@@ -1222,17 +1350,22 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1222
1350
|
if (evento.type === "tool.response" && evento.tool_call_id !== undefined) {
|
|
1223
1351
|
// Cuánto METIÓ en el contexto lo que devolvió: los caracteres, nunca el contenido.
|
|
1224
1352
|
const llamada = llamadas.get(claveDe(deHilo, evento.tool_call_id));
|
|
1353
|
+
// Las comprobaciones VISUALES, para el juez: lo que dijeron, medido aquí y no contado por el agente.
|
|
1354
|
+
if (llamada !== undefined && (llamada.nombre === NOMBRE_COMPARAR_CAPTURAS || llamada.nombre === "xone_critica_visual") && typeof evento.content === "string") {
|
|
1355
|
+
anotarComprobacion(lineaDeComprobacion(llamada.nombre, detalleDe(llamada.nombre, llamada.args), evento.content));
|
|
1356
|
+
}
|
|
1225
1357
|
const chars = typeof evento.content === "string" ? evento.content.length : 0;
|
|
1226
1358
|
diagnostico?.resultado?.(llamada?.nombre, llamada === undefined ? undefined : detalleDe(llamada.nombre, llamada.args), chars);
|
|
1227
1359
|
// Lo que ESCRIBIÓ este hilo, para decírselo a quien lo llamó al terminar (`informesDeHijos.ts`).
|
|
1228
1360
|
const escritura = escriturasEnVuelo.get(claveDe(deHilo, evento.tool_call_id));
|
|
1229
1361
|
if (escritura !== undefined) {
|
|
1230
1362
|
escriturasEnVuelo.delete(claveDe(deHilo, evento.tool_call_id));
|
|
1231
|
-
if (deHilo !== HILO_RAIZ && escrituraConExito(evento.content)) {
|
|
1363
|
+
if (deHilo !== HILO_RAIZ && escrituraConExito(evento.content, escritura.nombre)) {
|
|
1232
1364
|
const cambios = escritosDeCadaHilo.get(deHilo) ?? new Map();
|
|
1233
1365
|
anotarEscritura(cambios, escritura.nombre, escritura.args);
|
|
1234
1366
|
escritosDeCadaHilo.set(deHilo, cambios);
|
|
1235
1367
|
ultimaEscrituraDeHilo.set(deHilo, Date.now());
|
|
1368
|
+
guardarAMitad();
|
|
1236
1369
|
}
|
|
1237
1370
|
}
|
|
1238
1371
|
}
|
|
@@ -1251,8 +1384,11 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1251
1384
|
const nombre = especialistaDeHilo.get(deHilo);
|
|
1252
1385
|
const quien = especialistas().find((a) => a.nombre === nombre);
|
|
1253
1386
|
const medida = medidaTrasProbar(deHilo, hiloPadre, quien);
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1387
|
+
const escritos = escritosDeCadaHilo.get(deHilo) ?? new Map();
|
|
1388
|
+
const informe = medida ??
|
|
1389
|
+
textoDelInforme(quienEs.get(deHilo) ?? deHilo, escritos, quien !== undefined && quien.motor === "modelo" && clasesDeTools(quien) === "escribe", ultimaMedidaDeHilo.get(deHilo));
|
|
1390
|
+
const reparto = hiloPadre === HILO_RAIZ ? await avisoDeRepartoTras(escritos) : undefined;
|
|
1391
|
+
const texto = reparto === undefined ? informe : [informe, reparto].filter((t) => t !== undefined).join("\n\n");
|
|
1256
1392
|
escritosDeCadaHilo.delete(deHilo);
|
|
1257
1393
|
nacimientoDeHilo.delete(deHilo);
|
|
1258
1394
|
if (texto !== undefined)
|
|
@@ -1307,8 +1443,10 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1307
1443
|
yield* eventos;
|
|
1308
1444
|
while (artefactosPorAnunciar.length > 0)
|
|
1309
1445
|
yield { tipo: "artefacto", artefacto: artefactosPorAnunciar.shift() };
|
|
1446
|
+
yield* propuestasPendientes();
|
|
1310
1447
|
r = await it.next();
|
|
1311
1448
|
}
|
|
1449
|
+
yield* propuestasPendientes();
|
|
1312
1450
|
const resultado = r.value;
|
|
1313
1451
|
for (const accion of resultado.required_actions ?? []) {
|
|
1314
1452
|
// Dos interrupciones distintas, y no se mezclan: una APROBACIÓN decide sobre una escritura
|
|
@@ -1346,6 +1484,7 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1346
1484
|
const trackerAlEmpezar = { input: tracker.input, output: tracker.output, cache: tracker.cache, calls: tracker.calls };
|
|
1347
1485
|
externosDelTurno = 0;
|
|
1348
1486
|
capturasDelTurno = [];
|
|
1487
|
+
comprobacionesDelTurno = [];
|
|
1349
1488
|
/** El encargo de ESTE turno tal cual se pidió, y el mismo con la última pregunta y su
|
|
1350
1489
|
* respuesta al lado, que es lo que se juzga y se repara (ver `flujo`). Ausente = no consta. */
|
|
1351
1490
|
let encargoDelTurno;
|
|
@@ -1575,7 +1714,7 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1575
1714
|
escribioProyecto = cambios.length > 0;
|
|
1576
1715
|
if (!salida.limpia) {
|
|
1577
1716
|
if (sinResolver > 0)
|
|
1578
|
-
motivoSinVerificar = "quedaron escrituras sin resolver";
|
|
1717
|
+
motivoSinVerificar = cortadoPorTope ? `se agotó el tope de ${tope} rondas de escritura` : "quedaron escrituras sin resolver";
|
|
1579
1718
|
return;
|
|
1580
1719
|
}
|
|
1581
1720
|
veredicto = "no-corrio";
|
|
@@ -1627,6 +1766,9 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1627
1766
|
try {
|
|
1628
1767
|
const bytes = readFileSync(join(carpeta, captura.nombre));
|
|
1629
1768
|
const visual = await opciones.criticaVisual({ base64: bytes.toString("base64"), mime: captura.mime ?? "image/png" }, captura.nombre);
|
|
1769
|
+
anotarComprobacion(lineaDeComprobacion("crítico de pantalla del harness, al cerrar", captura.nombre, visual.veredicto === "rojo" && visual.observaciones.length > 0
|
|
1770
|
+
? `rojo, ${visual.observaciones.length} defecto(s): ${visual.observaciones.join("; ")}`
|
|
1771
|
+
: visual.veredicto));
|
|
1630
1772
|
if (visual.veredicto === "rojo" && visual.observaciones.length > 0) {
|
|
1631
1773
|
observacionesVisuales = visual.observaciones;
|
|
1632
1774
|
yield {
|
|
@@ -1806,6 +1948,8 @@ export async function abrirSesionTrueforge(opciones) {
|
|
|
1806
1948
|
cortadoPorTope,
|
|
1807
1949
|
verificador: veredicto,
|
|
1808
1950
|
pendientes: sinResolver,
|
|
1951
|
+
...(cortadoPorTope ? { topeAgotado: tope } : {}),
|
|
1952
|
+
...(comprobacionesDelTurno.length === 0 ? {} : { comprobacionesVisuales: comprobacionesDelTurno }),
|
|
1809
1953
|
...(hallazgosDelTurno.length === 0 ? {} : { hallazgos: hallazgosDelTurno }),
|
|
1810
1954
|
...(preexistentesDelTurno === undefined ? {} : { preexistentes: preexistentesDelTurno }),
|
|
1811
1955
|
...(motivoSinVerificar === undefined ? {} : { motivoSinVerificar }),
|