xonecode 0.8.46 → 0.11.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.
Files changed (147) hide show
  1. package/THIRD_PARTY_NOTICES.md +56 -0
  2. package/apps/web/dist/assets/index-BAyybSz-.css +1 -0
  3. package/apps/web/dist/assets/index-BNCMVjWv.js +485 -0
  4. package/apps/web/dist/assets/{php-Bx1jVads.js → php-DPbDT8rX.js} +1 -1
  5. package/apps/web/dist/assets/{ruby-L0I9KR6K.js → ruby-Bfvws9R8.js} +1 -1
  6. package/apps/web/dist/index.html +2 -2
  7. package/apps/web/dist/openui/visor.css +1 -0
  8. package/apps/web/dist/openui/visor.js +9113 -0
  9. package/dist/agent/exportarPdf.js +5 -1
  10. package/dist/agent/exportarPdf.js.map +1 -1
  11. package/dist/agent/grafo/arbolDeProyecto.js +67 -2
  12. package/dist/agent/grafo/arbolDeProyecto.js.map +1 -1
  13. package/dist/agent/grafo/memoriaDeProyecto.js +3 -2
  14. package/dist/agent/grafo/memoriaDeProyecto.js.map +1 -1
  15. package/dist/agent/grafo/navegacionXone.js +8 -3
  16. package/dist/agent/grafo/navegacionXone.js.map +1 -1
  17. package/dist/agent/grafo/opcionesDeFicheros.js +24 -0
  18. package/dist/agent/grafo/opcionesDeFicheros.js.map +1 -0
  19. package/dist/agent/grafo/perfiles.js +1 -1
  20. package/dist/agent/grafo/perfiles.js.map +1 -1
  21. package/dist/agent/grafo/proyecto.js +31 -15
  22. package/dist/agent/grafo/proyecto.js.map +1 -1
  23. package/dist/agent/grafo/unirSecciones.js +128 -0
  24. package/dist/agent/grafo/unirSecciones.js.map +1 -0
  25. package/dist/agent/grafo/xoneAgent.js +56 -51
  26. package/dist/agent/grafo/xoneAgent.js.map +1 -1
  27. package/dist/agent/motores/trueforge/capacidades.js +179 -0
  28. package/dist/agent/motores/trueforge/capacidades.js.map +1 -0
  29. package/dist/agent/motores/trueforge/eventosTrueforge.js +143 -0
  30. package/dist/agent/motores/trueforge/eventosTrueforge.js.map +1 -0
  31. package/dist/agent/motores/trueforge/memoriaTrueforge.js +336 -0
  32. package/dist/agent/motores/trueforge/memoriaTrueforge.js.map +1 -0
  33. package/dist/agent/motores/trueforge/metricasTrueforge.js +55 -0
  34. package/dist/agent/motores/trueforge/metricasTrueforge.js.map +1 -0
  35. package/dist/agent/motores/trueforge/modeloExterno.js +46 -0
  36. package/dist/agent/motores/trueforge/modeloExterno.js.map +1 -0
  37. package/dist/agent/motores/trueforge/modeloLangchain.js +152 -0
  38. package/dist/agent/motores/trueforge/modeloLangchain.js.map +1 -0
  39. package/dist/agent/motores/trueforge/recortes.js +121 -0
  40. package/dist/agent/motores/trueforge/recortes.js.map +1 -0
  41. package/dist/agent/motores/trueforge/sesionTrueforge.js +1062 -0
  42. package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -0
  43. package/dist/agent/motores/trueforge/skillsTrueforge.js +14 -0
  44. package/dist/agent/motores/trueforge/skillsTrueforge.js.map +1 -0
  45. package/dist/agent/motores/trueforge/toolsDeFichero.js +265 -0
  46. package/dist/agent/motores/trueforge/toolsDeFichero.js.map +1 -0
  47. package/dist/agent/motores/trueforge/toolsPropias.js +65 -0
  48. package/dist/agent/motores/trueforge/toolsPropias.js.map +1 -0
  49. package/dist/agent/motores/trueforge/trueforge.js +45 -0
  50. package/dist/agent/motores/trueforge/trueforge.js.map +1 -0
  51. package/dist/agent/navegacion/indiceEnDisco.js +10 -1
  52. package/dist/agent/navegacion/indiceEnDisco.js.map +1 -1
  53. package/dist/agent/planesEnDisco.js +64 -0
  54. package/dist/agent/planesEnDisco.js.map +1 -0
  55. package/dist/agent/sesiones/memoriaDeHilo.js +24 -0
  56. package/dist/agent/sesiones/memoriaDeHilo.js.map +1 -0
  57. package/dist/agent/sesiones/modeloDelCambio.js +70 -0
  58. package/dist/agent/sesiones/modeloDelCambio.js.map +1 -0
  59. package/dist/agent/sesiones/sesionGit.js +14 -0
  60. package/dist/agent/sesiones/sesionGit.js.map +1 -1
  61. package/dist/agent/subagentes/actividadDeCodex.js +60 -0
  62. package/dist/agent/subagentes/actividadDeCodex.js.map +1 -0
  63. package/dist/agent/subagentes/agentesEnDisco.js +95 -5
  64. package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
  65. package/dist/agent/subagentes/escrituraExterna.js +10 -2
  66. package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
  67. package/dist/agent/subagentes/subagenteCodex.js +20 -0
  68. package/dist/agent/subagentes/subagenteCodex.js.map +1 -1
  69. package/dist/agent/subagentes/subagenteExterno.js +269 -202
  70. package/dist/agent/subagentes/subagenteExterno.js.map +1 -1
  71. package/dist/agent/subagentes/subagenteOpencode.js +19 -2
  72. package/dist/agent/subagentes/subagenteOpencode.js.map +1 -1
  73. package/dist/agent/turno/diagnosticoDeTools.js +3 -0
  74. package/dist/agent/turno/diagnosticoDeTools.js.map +1 -1
  75. package/dist/agent/turno/ficherosDelProyecto.js +62 -0
  76. package/dist/agent/turno/ficherosDelProyecto.js.map +1 -0
  77. package/dist/agent/turno/informeDeTraza.js +28 -1
  78. package/dist/agent/turno/informeDeTraza.js.map +1 -1
  79. package/dist/agent/turno/puente.js +17 -1
  80. package/dist/agent/turno/puente.js.map +1 -1
  81. package/dist/agent/turno/resumenDeContexto.js +17 -4
  82. package/dist/agent/turno/resumenDeContexto.js.map +1 -1
  83. package/dist/agent/turno/resumenDeTool.js +3 -0
  84. package/dist/agent/turno/resumenDeTool.js.map +1 -1
  85. package/dist/agent/turno/sesionReal.js +2 -0
  86. package/dist/agent/turno/sesionReal.js.map +1 -0
  87. package/dist/agent/turno/turnoReal.js +55 -164
  88. package/dist/agent/turno/turnoReal.js.map +1 -1
  89. package/dist/agent/turno/verificacion.js +142 -0
  90. package/dist/agent/turno/verificacion.js.map +1 -0
  91. package/dist/cli/config.js +19 -0
  92. package/dist/cli/config.js.map +1 -1
  93. package/dist/cli/consola.js.map +1 -1
  94. package/dist/cli/main.js +35 -2
  95. package/dist/cli/main.js.map +1 -1
  96. package/dist/cli/tui/correrTui.js +1 -1
  97. package/dist/cli/tui/correrTui.js.map +1 -1
  98. package/dist/cli/tui/transcript.js +9 -0
  99. package/dist/cli/tui/transcript.js.map +1 -1
  100. package/dist/core/actos.js.map +1 -1
  101. package/dist/core/agentes.js +17 -0
  102. package/dist/core/agentes.js.map +1 -1
  103. package/dist/core/artefactos.js +22 -0
  104. package/dist/core/artefactos.js.map +1 -1
  105. package/dist/core/config.js +13 -0
  106. package/dist/core/config.js.map +1 -1
  107. package/dist/core/diffDeColecciones.js +84 -0
  108. package/dist/core/diffDeColecciones.js.map +1 -0
  109. package/dist/core/exportacion.js +6 -1
  110. package/dist/core/exportacion.js.map +1 -1
  111. package/dist/core/fotoDeColecciones.js +48 -0
  112. package/dist/core/fotoDeColecciones.js.map +1 -0
  113. package/dist/core/imagenesDeDocumento.js +88 -0
  114. package/dist/core/imagenesDeDocumento.js.map +1 -0
  115. package/dist/core/memoria.js +24 -0
  116. package/dist/core/memoria.js.map +1 -0
  117. package/dist/core/motor.js +41 -0
  118. package/dist/core/motor.js.map +1 -0
  119. package/dist/core/navegacion.js.map +1 -1
  120. package/dist/core/notify.js +23 -5
  121. package/dist/core/notify.js.map +1 -1
  122. package/dist/core/ports.js.map +1 -1
  123. package/dist/core/serieDeEscrituras.js +13 -0
  124. package/dist/core/serieDeEscrituras.js.map +1 -1
  125. package/dist/core/settings.js +17 -1
  126. package/dist/core/settings.js.map +1 -1
  127. package/dist/core/tareasDelPlan.js +103 -0
  128. package/dist/core/tareasDelPlan.js.map +1 -0
  129. package/dist/core/trazaDeErrores.js +42 -3
  130. package/dist/core/trazaDeErrores.js.map +1 -1
  131. package/dist/core/turno.js +44 -4
  132. package/dist/core/turno.js.map +1 -1
  133. package/dist/web/servidor/arranque.js +204 -5
  134. package/dist/web/servidor/arranque.js.map +1 -1
  135. package/dist/web/servidor/pielWeb.js +69 -4
  136. package/dist/web/servidor/pielWeb.js.map +1 -1
  137. package/dist/web/servidor/sesiones.js +11 -0
  138. package/dist/web/servidor/sesiones.js.map +1 -1
  139. package/dist/web/servidor/transporte.js.map +1 -1
  140. package/dist/web/servidor/vestibulo.js +23 -2
  141. package/dist/web/servidor/vestibulo.js.map +1 -1
  142. package/dist/web/servidor/visorOpenui.js +63 -0
  143. package/dist/web/servidor/visorOpenui.js.map +1 -0
  144. package/package.json +7 -2
  145. package/skills/openui-builder/SKILL.md +48 -0
  146. package/apps/web/dist/assets/index-GRwyotMV.js +0 -478
  147. package/apps/web/dist/assets/index-_cBVqq54.css +0 -1
@@ -27,6 +27,7 @@
27
27
  * modelo y lo guarda: un paso de cuenta que solo guardara la credencial dejaría `trabajo`
28
28
  * en la omisión (Ollama local) con una clave de Anthropic recién escrita al lado.
29
29
  */
30
+ import { hayMemoriaDeHilo, olvidarMemoriaDeHilo } from "../../agent/sesiones/memoriaDeHilo.js";
30
31
  import { existsSync, readFileSync } from "node:fs";
31
32
  import { lineaDeVersion } from "../../core/version.js";
32
33
  import { basename, dirname, join } from "node:path";
@@ -62,7 +63,7 @@ import { motivoDeClaveInaceptable } from "../../core/config.js";
62
63
  import { aplicarAuth, aplicarCredencialAlProceso, cargar, guardarModeloGlobal, } from "../../agent/config/configEnDisco.js";
63
64
  import { borrarCredencial, guardarCredencial } from "../../agent/config/authEnDisco.js";
64
65
  import { borrarProveedorPersonalizado, guardarProveedorPersonalizado, proveedoresPersonalizados, } from "../../agent/config/configEnDisco.js";
65
- import { crearCheckpointerDeProyecto, hayCheckpoint, mantenimientoDelCheckpointer, olvidarHilo, } from "../../agent/sesiones/checkpointer.js";
66
+ import { crearCheckpointerDeProyecto, mantenimientoDelCheckpointer, } from "../../agent/sesiones/checkpointer.js";
66
67
  import { resumenDePoda } from "../../core/podaDeCheckpoint.js";
67
68
  import { cargarSettings, guardarConcurrenciaDeTareas, guardarWorkspace as guardarWorkspaceEnDisco, guardarDispositivos, guardarEntorno as guardarEntornoEnDisco, olvidarEntornoDeSettings, copiasDeEntorno, borrarCopiasDeEntorno, } from "../../agent/config/settingsEnDisco.js";
68
69
  import { dentroDelWorkspace, expandirConCasa, motivoParaNoOlvidarEntorno, motivoDeWorkspaceInaceptable, } from "../../core/settings.js";
@@ -76,7 +77,14 @@ import { cambiosDeSesion, fotoDeApertura, olvidarSesion, parcheDeSesion } from "
76
77
  import { commitDeTurno, cambiosPendientes, trabajoSinCommitear } from "../../agent/sesiones/gitSync.js";
77
78
  import { marcarTareaDeSesion, sembrarConsumosPendientes } from "./sesiones.js";
78
79
  import { RUTA_ARTEFACTOS, esRutaDeArtefacto } from "../../core/artefactos.js";
79
- import { arbolDeProyecto, leerFicheroDeProyecto, motivoDeRutaInaceptable, } from "../../agent/grafo/arbolDeProyecto.js";
80
+ import { arbolDeProyecto, leerFicheroDeProyecto, mimeDeImagen, motivoDeRutaInaceptable, } from "../../agent/grafo/arbolDeProyecto.js";
81
+ import { modeloEnDisco } from "../../agent/navegacion/indiceEnDisco.js";
82
+ import { ficherosDelProyecto } from "../../agent/turno/ficherosDelProyecto.js";
83
+ import { fotoDeColecciones } from "../../core/fotoDeColecciones.js";
84
+ import { modeloDelCambio } from "../../agent/sesiones/modeloDelCambio.js";
85
+ import { planesDelProyecto } from "../../agent/planesEnDisco.js";
86
+ import { CSP_DE_OPENUI, documentoDeOpenui, esArtefactoOpenui } from "./visorOpenui.js";
87
+ import { RUTA_IMAGEN_DEL_PROYECTO } from "../../core/imagenesDeDocumento.js";
80
88
  import { leerArtefactoCrudo, leerArtefactoDeSesion, } from "../../agent/grafo/artefactosEnDisco.js";
81
89
  import { CatalogoModelos, baseUrlDeOllama, baseUrlDeOllamaCloud, capacidadesDeOllama, } from "../../agent/config/catalogoModelos.js";
82
90
  import { Modelos } from "../../agent/config/modelos.js";
@@ -162,6 +170,21 @@ export const MS_ENTRE_PROGRESOS = 250;
162
170
  export function raizDelClientePorOmision() {
163
171
  return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "apps", "web", "dist");
164
172
  }
173
+ /**
174
+ * El visor de OpenUI del build del cliente, o `undefined` si no está. Se lee en cada petición, como
175
+ * el resto del cliente: reconstruirlo se ve recargando, sin reiniciar el servidor.
176
+ */
177
+ export function leerVisorOpenui(raizDelCliente) {
178
+ try {
179
+ return {
180
+ js: readFileSync(join(raizDelCliente, "openui", "visor.js"), "utf8"),
181
+ css: readFileSync(join(raizDelCliente, "openui", "visor.css"), "utf8"),
182
+ };
183
+ }
184
+ catch {
185
+ return undefined;
186
+ }
187
+ }
165
188
  export const FALTA_EL_BUILD = "falta el build del cliente: ejecuta «npm run build:web»";
166
189
  /** Tope del cuerpo de `POST /accion`. Generoso para una prosa larga, finito porque el
167
190
  * cuerpo se acumula en memoria y un cliente roto no puede llenarla. */
@@ -2743,6 +2766,73 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
2743
2766
  emitir({ clase: "arbol", rutas: [], recortado: false, error: "no se pudo listar el proyecto" });
2744
2767
  }
2745
2768
  };
2769
+ /**
2770
+ * El diff semántico de un `.xne` de Revisión. Siempre CONTESTA —la fila abierta espera, y un
2771
+ * silencio la dejaría cargando para siempre—, y la ruta pasa por la MISMA barrera que la del
2772
+ * lector de Ficheros antes de llegar a git.
2773
+ */
2774
+ const atenderModeloDelCambio = async (ruta) => {
2775
+ const abierto = vestibulo.proyectoAbierto();
2776
+ const sesion = abierto?.sesion;
2777
+ const sinNada = (error) => emitir({ clase: "modeloDelCambio", ruta, error });
2778
+ if (abierto === undefined || opciones.modeloDelCambio === undefined)
2779
+ return sinNada("esta ejecución no sabe comparar el modelo");
2780
+ if (sesion === undefined)
2781
+ return sinNada("la sesión todavía no ha empezado");
2782
+ if (motivoDeRutaInaceptable(ruta) !== undefined)
2783
+ return sinNada("esa ruta no se enseña");
2784
+ try {
2785
+ const cambios = await opciones.modeloDelCambio(abierto.raiz, sesion, ruta);
2786
+ if (cambios === undefined)
2787
+ return sinNada("no hay con qué comparar");
2788
+ emitir({ clase: "modeloDelCambio", ruta, cambios });
2789
+ }
2790
+ catch (error) {
2791
+ informar(`no se pudo comparar el modelo (${codigoDe(error)})`);
2792
+ sinNada("no se pudo comparar el modelo");
2793
+ }
2794
+ };
2795
+ /**
2796
+ * Los planes del proyecto abierto. Mismas reglas que el árbol: sin proyecto no se contesta,
2797
+ * sin puerto se contesta con error, y el fallo viaja sin la ruta de la máquina.
2798
+ */
2799
+ const atenderPlanes = async () => {
2800
+ const abierto = vestibulo.proyectoAbierto();
2801
+ if (abierto === undefined)
2802
+ return;
2803
+ if (opciones.planesDelProyecto === undefined) {
2804
+ emitir({ clase: "planes", error: "esta ejecución no puede leer los planes" });
2805
+ return;
2806
+ }
2807
+ try {
2808
+ emitir({ clase: "planes", planes: opciones.planesDelProyecto(abierto.raiz) });
2809
+ }
2810
+ catch (error) {
2811
+ informar(`no se pudieron leer los planes (${codigoDe(error)})`);
2812
+ emitir({ clase: "planes", error: "no se pudieron leer los planes" });
2813
+ }
2814
+ };
2815
+ /**
2816
+ * La foto del modelo XOne del proyecto abierto. Mismas reglas que el árbol: sin proyecto no
2817
+ * se contesta, sin puerto se contesta con error —un «consultando…» eterno es un fallo mudo—,
2818
+ * y el fallo viaja sin la ruta de la máquina.
2819
+ */
2820
+ const atenderColecciones = async () => {
2821
+ const abierto = vestibulo.proyectoAbierto();
2822
+ if (abierto === undefined)
2823
+ return;
2824
+ if (opciones.coleccionesDelProyecto === undefined) {
2825
+ emitir({ clase: "colecciones", error: "esta ejecución no puede leer el modelo del proyecto" });
2826
+ return;
2827
+ }
2828
+ try {
2829
+ emitir({ clase: "colecciones", foto: await opciones.coleccionesDelProyecto(abierto.raiz) });
2830
+ }
2831
+ catch (error) {
2832
+ informar(`no se pudo leer el modelo del proyecto (${codigoDe(error)})`);
2833
+ emitir({ clase: "colecciones", error: "no se pudo leer el modelo del proyecto" });
2834
+ }
2835
+ };
2746
2836
  /**
2747
2837
  * El contenido de una ruta del proyecto abierto. El lector decide si se puede enseñar.
2748
2838
  *
@@ -3340,6 +3430,25 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
3340
3430
  return;
3341
3431
  }
3342
3432
  const descargar = query.get("descargar") !== null;
3433
+ // Un programa de OpenUI se VE dentro de su visor, en un documento autocontenido y sin red
3434
+ // (`visorOpenui.ts`). Descargarlo sigue dando el fichero tal cual.
3435
+ if (!descargar && esArtefactoOpenui(leido.nombre)) {
3436
+ const visor = opciones.visorOpenui?.();
3437
+ if (visor === undefined) {
3438
+ responder(503, "el visor de OpenUI no está construido: ejecuta «npm run build:web»");
3439
+ return;
3440
+ }
3441
+ const documento = Buffer.from(documentoDeOpenui(leido.datos.toString("utf8"), visor, leido.nombre), "utf8");
3442
+ respuesta.writeHead(200, {
3443
+ "Content-Type": "text/html; charset=utf-8",
3444
+ "Content-Length": documento.length,
3445
+ "Content-Security-Policy": CSP_DE_OPENUI,
3446
+ "X-Content-Type-Options": "nosniff",
3447
+ "Cache-Control": "no-store",
3448
+ });
3449
+ respuesta.end(documento);
3450
+ return;
3451
+ }
3343
3452
  // Sin mime conocido se descarga en vez de adivinar. El nombre ya pasó la barrera de
3344
3453
  // segmento llano, así que entre comillas no puede romper la cabecera.
3345
3454
  const inline = !descargar && leido.mime !== undefined;
@@ -3355,6 +3464,67 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
3355
3464
  });
3356
3465
  respuesta.end(leido.datos);
3357
3466
  });
3467
+ /**
3468
+ * `GET /imagen-del-proyecto?ruta=<relativa>` — una IMAGEN del proyecto abierto, para que un `.md`
3469
+ * de la pestaña Ficheros enseñe las suyas.
3470
+ *
3471
+ * Existe porque el visor de markdown solo pinta imágenes `http(s)` absolutas: un enlace relativo o
3472
+ * una `data:` se quedaban en su texto alternativo. La vista del documento reescribe cada enlace a
3473
+ * esta ruta (`arbolDeProyecto.ts#vistaDeMarkdown`), y aquí se sirve con la barrera de siempre:
3474
+ * - **Solo imágenes, por su extensión**, antes de leer nada: esto no es un lector de ficheros por
3475
+ * HTTP, y sin esa criba cualquier ruta que se enseñe se podría pedir por aquí.
3476
+ * - **Leída con `leerFichero`** —las dos barreras de la pestaña Ficheros, sobre el texto y sobre
3477
+ * el camino REAL, y su tope—, no con una copia de ellas.
3478
+ * - `Content-Security-Policy: sandbox`, `nosniff` y `no-store`: un `.svg` abierto a pelo en una
3479
+ * pestaña no ejecuta nada, el navegador no adivina el tipo, y una captura reescrita se ve nueva.
3480
+ */
3481
+ servidor.registrarRuta("GET", RUTA_IMAGEN_DEL_PROYECTO, async (peticion, respuesta) => {
3482
+ const responder = (codigo, texto) => {
3483
+ respuesta.writeHead(codigo, { "Content-Type": "text/plain; charset=utf-8" });
3484
+ respuesta.end(texto);
3485
+ };
3486
+ const ruta = new URLSearchParams((peticion.url ?? "").split("?")[1] ?? "").get("ruta");
3487
+ if (ruta === null || ruta === "") {
3488
+ responder(400, "falta la ruta");
3489
+ return;
3490
+ }
3491
+ if (mimeDeImagen(ruta) === undefined) {
3492
+ responder(403, "eso no es una imagen");
3493
+ return;
3494
+ }
3495
+ const abierto = vestibulo.proyectoAbierto();
3496
+ if (abierto === undefined || opciones.leerFichero === undefined) {
3497
+ responder(404, "no hay imagen");
3498
+ return;
3499
+ }
3500
+ let leido;
3501
+ try {
3502
+ leido = await opciones.leerFichero(abierto.raiz, ruta);
3503
+ }
3504
+ catch (error) {
3505
+ // Como en el resto: al cliente y a `informar` solo el código, nunca el mensaje de Node.
3506
+ informar(`no se pudo servir la imagen «${ruta}» (${codigoDe(error)})`);
3507
+ responder(500, "no se pudo leer");
3508
+ return;
3509
+ }
3510
+ if (leido.error !== undefined) {
3511
+ responder(leido.error === "no existe" ? 404 : 403, leido.error);
3512
+ return;
3513
+ }
3514
+ if (leido.base64 === undefined || leido.mime === undefined) {
3515
+ responder(413, "la imagen es demasiado grande");
3516
+ return;
3517
+ }
3518
+ const datos = Buffer.from(leido.base64, "base64");
3519
+ respuesta.writeHead(200, {
3520
+ "Content-Type": leido.mime,
3521
+ "Content-Length": datos.length,
3522
+ "Content-Security-Policy": "sandbox",
3523
+ "X-Content-Type-Options": "nosniff",
3524
+ "Cache-Control": "no-store",
3525
+ });
3526
+ respuesta.end(datos);
3527
+ });
3358
3528
  /**
3359
3529
  * `POST /adjunto?tarea=<id>&nombre=<fichero>` — los BYTES de un adjunto de tarea.
3360
3530
  *
@@ -3575,6 +3745,27 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
3575
3745
  respuesta.end();
3576
3746
  return;
3577
3747
  }
3748
+ if (typeof mensaje === "object" &&
3749
+ mensaje !== null &&
3750
+ mensaje.clase === "modeloDelCambio" &&
3751
+ typeof mensaje.ruta === "string") {
3752
+ void atenderModeloDelCambio(mensaje.ruta).catch(contar);
3753
+ respuesta.writeHead(204);
3754
+ respuesta.end();
3755
+ return;
3756
+ }
3757
+ if (typeof mensaje === "object" && mensaje !== null && mensaje.clase === "planes") {
3758
+ void atenderPlanes().catch(contar);
3759
+ respuesta.writeHead(204);
3760
+ respuesta.end();
3761
+ return;
3762
+ }
3763
+ if (typeof mensaje === "object" && mensaje !== null && mensaje.clase === "colecciones") {
3764
+ void atenderColecciones().catch(contar);
3765
+ respuesta.writeHead(204);
3766
+ respuesta.end();
3767
+ return;
3768
+ }
3578
3769
  if (typeof mensaje === "object" &&
3579
3770
  mensaje !== null &&
3580
3771
  mensaje.clase === "sync" &&
@@ -4592,7 +4783,7 @@ export async function arrancarConsolaWeb(opciones) {
4592
4783
  vestibulo: conVestibulo,
4593
4784
  tareasFabrica: opciones.tareas,
4594
4785
  informar,
4595
- olvidarHiloDeSesion: async (raiz, hilo) => olvidarHilo(crearCheckpointerDeProyecto(raiz), hilo),
4786
+ olvidarHiloDeSesion: olvidarMemoriaDeHilo,
4596
4787
  /**
4597
4788
  * El juez de QA de las tareas, con el papel `afilado` — el que `core/modelos.ts` le
4598
4789
  * reserva.
@@ -4707,6 +4898,12 @@ export async function arrancarConsolaWeb(opciones) {
4707
4898
  // El proyecto tal como lo ve el agente, para la pestaña Ficheros: mismo filtro, misma
4708
4899
  // barrera de rutas (`agent/grafo/arbolDeProyecto.ts`).
4709
4900
  arbolDelProyecto: async (raiz) => arbolDeProyecto(raiz),
4901
+ // El modelo XOne con el MISMO cargador y el mismo conjunto de ficheros que la tool, para
4902
+ // que la pestaña y el agente no contesten distinto sobre el mismo proyecto.
4903
+ coleccionesDelProyecto: async (raiz) => fotoDeColecciones(await modeloEnDisco(raiz)(ficherosDelProyecto(raiz))),
4904
+ modeloDelCambio,
4905
+ planesDelProyecto,
4906
+ visorOpenui: () => leerVisorOpenui(raizDelCliente),
4710
4907
  leerFichero: leerFicheroDeProyecto,
4711
4908
  leerArtefacto: leerArtefactoDeSesion,
4712
4909
  leerArtefactoCrudo,
@@ -4949,8 +5146,10 @@ function vestibuloReal(opciones, servidor, escribir, informar) {
4949
5146
  olvidarMarcaDeSesion: olvidarSesion,
4950
5147
  // La memoria del agente por hilo. `historica` deja de ser «se reabrió» para ser «no hay
4951
5148
  // checkpoint que cargar», y borrar una sesión se lleva también su checkpoint.
4952
- hayMemoriaDeHilo: async (raiz, hilo) => hayCheckpoint(crearCheckpointerDeProyecto(raiz), hilo),
4953
- olvidarMemoriaDeHilo: async (raiz, hilo) => olvidarHilo(crearCheckpointerDeProyecto(raiz), hilo),
5149
+ // Las dos memorias —la del checkpointer de deepagents y la foto de TrueForge—, en una función
5150
+ // exportada y probada (`memoriaDeHilo.ts`), no en dos lambdas de este cierre.
5151
+ hayMemoriaDeHilo,
5152
+ olvidarMemoriaDeHilo,
4954
5153
  entornos: settings.entornos,
4955
5154
  /**
4956
5155
  * Dónde se bajan las copias, RELEÍDO en cada uso y no resuelto aquí.