xonecode 0.9.0 → 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.
- package/THIRD_PARTY_NOTICES.md +56 -0
- package/apps/web/dist/assets/index-BAyybSz-.css +1 -0
- package/apps/web/dist/assets/index-BNCMVjWv.js +485 -0
- package/apps/web/dist/assets/{php-DjRQ1K-w.js → php-DPbDT8rX.js} +1 -1
- package/apps/web/dist/assets/{ruby-BcLyZ3qi.js → ruby-Bfvws9R8.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/apps/web/dist/openui/visor.css +1 -0
- package/apps/web/dist/openui/visor.js +9113 -0
- package/dist/agent/exportarPdf.js +5 -1
- package/dist/agent/exportarPdf.js.map +1 -1
- package/dist/agent/grafo/arbolDeProyecto.js +66 -1
- package/dist/agent/grafo/arbolDeProyecto.js.map +1 -1
- package/dist/agent/grafo/memoriaDeProyecto.js +3 -2
- package/dist/agent/grafo/memoriaDeProyecto.js.map +1 -1
- package/dist/agent/grafo/navegacionXone.js +8 -3
- package/dist/agent/grafo/navegacionXone.js.map +1 -1
- package/dist/agent/grafo/proyecto.js +31 -15
- package/dist/agent/grafo/proyecto.js.map +1 -1
- package/dist/agent/grafo/unirSecciones.js +128 -0
- package/dist/agent/grafo/unirSecciones.js.map +1 -0
- package/dist/agent/grafo/xoneAgent.js +7 -0
- package/dist/agent/grafo/xoneAgent.js.map +1 -1
- package/dist/agent/motores/trueforge/capacidades.js +42 -1
- package/dist/agent/motores/trueforge/capacidades.js.map +1 -1
- package/dist/agent/motores/trueforge/eventosTrueforge.js +52 -7
- package/dist/agent/motores/trueforge/eventosTrueforge.js.map +1 -1
- package/dist/agent/motores/trueforge/modeloLangchain.js +5 -2
- package/dist/agent/motores/trueforge/modeloLangchain.js.map +1 -1
- package/dist/agent/motores/trueforge/sesionTrueforge.js +19 -2
- package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -1
- package/dist/agent/motores/trueforge/toolsDeFichero.js +3 -2
- package/dist/agent/motores/trueforge/toolsDeFichero.js.map +1 -1
- package/dist/agent/motores/trueforge/trueforge.js +1 -1
- package/dist/agent/motores/trueforge/trueforge.js.map +1 -1
- package/dist/agent/navegacion/indiceEnDisco.js +10 -1
- package/dist/agent/navegacion/indiceEnDisco.js.map +1 -1
- package/dist/agent/planesEnDisco.js +64 -0
- package/dist/agent/planesEnDisco.js.map +1 -0
- package/dist/agent/sesiones/modeloDelCambio.js +70 -0
- package/dist/agent/sesiones/modeloDelCambio.js.map +1 -0
- package/dist/agent/sesiones/sesionGit.js +14 -0
- package/dist/agent/sesiones/sesionGit.js.map +1 -1
- package/dist/agent/subagentes/agentesEnDisco.js +95 -5
- package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
- package/dist/agent/subagentes/escrituraExterna.js +8 -2
- package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
- package/dist/agent/subagentes/subagenteCodex.js +1 -1
- package/dist/agent/subagentes/subagenteCodex.js.map +1 -1
- package/dist/agent/subagentes/subagenteExterno.js +1 -1
- package/dist/agent/subagentes/subagenteExterno.js.map +1 -1
- package/dist/agent/subagentes/subagenteOpencode.js +1 -1
- package/dist/agent/subagentes/subagenteOpencode.js.map +1 -1
- package/dist/agent/turno/puente.js +17 -1
- package/dist/agent/turno/puente.js.map +1 -1
- package/dist/agent/turno/resumenDeContexto.js +17 -4
- package/dist/agent/turno/resumenDeContexto.js.map +1 -1
- package/dist/agent/turno/turnoReal.js +16 -2
- package/dist/agent/turno/turnoReal.js.map +1 -1
- package/dist/cli/tui/transcript.js +4 -0
- package/dist/cli/tui/transcript.js.map +1 -1
- package/dist/core/actos.js.map +1 -1
- package/dist/core/agentes.js +17 -0
- package/dist/core/agentes.js.map +1 -1
- package/dist/core/artefactos.js +22 -0
- package/dist/core/artefactos.js.map +1 -1
- package/dist/core/diffDeColecciones.js +84 -0
- package/dist/core/diffDeColecciones.js.map +1 -0
- package/dist/core/exportacion.js +6 -1
- package/dist/core/exportacion.js.map +1 -1
- package/dist/core/fotoDeColecciones.js +48 -0
- package/dist/core/fotoDeColecciones.js.map +1 -0
- package/dist/core/imagenesDeDocumento.js +88 -0
- package/dist/core/imagenesDeDocumento.js.map +1 -0
- package/dist/core/memoria.js +24 -0
- package/dist/core/memoria.js.map +1 -0
- package/dist/core/navegacion.js.map +1 -1
- package/dist/core/notify.js +23 -5
- package/dist/core/notify.js.map +1 -1
- package/dist/core/ports.js.map +1 -1
- package/dist/core/serieDeEscrituras.js +13 -0
- package/dist/core/serieDeEscrituras.js.map +1 -1
- package/dist/core/settings.js +17 -1
- package/dist/core/settings.js.map +1 -1
- package/dist/core/tareasDelPlan.js +103 -0
- package/dist/core/tareasDelPlan.js.map +1 -0
- package/dist/core/trazaDeErrores.js +42 -9
- package/dist/core/trazaDeErrores.js.map +1 -1
- package/dist/core/turno.js +34 -4
- package/dist/core/turno.js.map +1 -1
- package/dist/web/servidor/arranque.js +197 -1
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/pielWeb.js +63 -4
- package/dist/web/servidor/pielWeb.js.map +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/visorOpenui.js +63 -0
- package/dist/web/servidor/visorOpenui.js.map +1 -0
- package/package.json +1 -1
- package/skills/openui-builder/SKILL.md +48 -0
- package/apps/web/dist/assets/index-CtfT1BjI.css +0 -1
- package/apps/web/dist/assets/index-DqcZ7_Rx.js +0 -478
|
@@ -77,7 +77,14 @@ import { cambiosDeSesion, fotoDeApertura, olvidarSesion, parcheDeSesion } from "
|
|
|
77
77
|
import { commitDeTurno, cambiosPendientes, trabajoSinCommitear } from "../../agent/sesiones/gitSync.js";
|
|
78
78
|
import { marcarTareaDeSesion, sembrarConsumosPendientes } from "./sesiones.js";
|
|
79
79
|
import { RUTA_ARTEFACTOS, esRutaDeArtefacto } from "../../core/artefactos.js";
|
|
80
|
-
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";
|
|
81
88
|
import { leerArtefactoCrudo, leerArtefactoDeSesion, } from "../../agent/grafo/artefactosEnDisco.js";
|
|
82
89
|
import { CatalogoModelos, baseUrlDeOllama, baseUrlDeOllamaCloud, capacidadesDeOllama, } from "../../agent/config/catalogoModelos.js";
|
|
83
90
|
import { Modelos } from "../../agent/config/modelos.js";
|
|
@@ -163,6 +170,21 @@ export const MS_ENTRE_PROGRESOS = 250;
|
|
|
163
170
|
export function raizDelClientePorOmision() {
|
|
164
171
|
return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "apps", "web", "dist");
|
|
165
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
|
+
}
|
|
166
188
|
export const FALTA_EL_BUILD = "falta el build del cliente: ejecuta «npm run build:web»";
|
|
167
189
|
/** Tope del cuerpo de `POST /accion`. Generoso para una prosa larga, finito porque el
|
|
168
190
|
* cuerpo se acumula en memoria y un cliente roto no puede llenarla. */
|
|
@@ -2744,6 +2766,73 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
|
|
|
2744
2766
|
emitir({ clase: "arbol", rutas: [], recortado: false, error: "no se pudo listar el proyecto" });
|
|
2745
2767
|
}
|
|
2746
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
|
+
};
|
|
2747
2836
|
/**
|
|
2748
2837
|
* El contenido de una ruta del proyecto abierto. El lector decide si se puede enseñar.
|
|
2749
2838
|
*
|
|
@@ -3341,6 +3430,25 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
|
|
|
3341
3430
|
return;
|
|
3342
3431
|
}
|
|
3343
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
|
+
}
|
|
3344
3452
|
// Sin mime conocido se descarga en vez de adivinar. El nombre ya pasó la barrera de
|
|
3345
3453
|
// segmento llano, así que entre comillas no puede romper la cabecera.
|
|
3346
3454
|
const inline = !descargar && leido.mime !== undefined;
|
|
@@ -3356,6 +3464,67 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
|
|
|
3356
3464
|
});
|
|
3357
3465
|
respuesta.end(leido.datos);
|
|
3358
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
|
+
});
|
|
3359
3528
|
/**
|
|
3360
3529
|
* `POST /adjunto?tarea=<id>&nombre=<fichero>` — los BYTES de un adjunto de tarea.
|
|
3361
3530
|
*
|
|
@@ -3576,6 +3745,27 @@ export function montarRutas(servidor, vestibulo, opciones = {}) {
|
|
|
3576
3745
|
respuesta.end();
|
|
3577
3746
|
return;
|
|
3578
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
|
+
}
|
|
3579
3769
|
if (typeof mensaje === "object" &&
|
|
3580
3770
|
mensaje !== null &&
|
|
3581
3771
|
mensaje.clase === "sync" &&
|
|
@@ -4708,6 +4898,12 @@ export async function arrancarConsolaWeb(opciones) {
|
|
|
4708
4898
|
// El proyecto tal como lo ve el agente, para la pestaña Ficheros: mismo filtro, misma
|
|
4709
4899
|
// barrera de rutas (`agent/grafo/arbolDeProyecto.ts`).
|
|
4710
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),
|
|
4711
4907
|
leerFichero: leerFicheroDeProyecto,
|
|
4712
4908
|
leerArtefacto: leerArtefactoDeSesion,
|
|
4713
4909
|
leerArtefactoCrudo,
|