xonecode 0.6.0 → 0.8.1

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 (130) hide show
  1. package/apps/web/dist/assets/{index-rqecK6s2.css → index-Boak51UP.css} +1 -1
  2. package/apps/web/dist/assets/index-Cg28x6nG.js +477 -0
  3. package/apps/web/dist/assets/{php-BBij3Lhc.js → php-Cu6F_QCJ.js} +1 -1
  4. package/apps/web/dist/assets/{ruby-Dq2YEaLo.js → ruby-BiqQPoC6.js} +1 -1
  5. package/apps/web/dist/index.html +2 -2
  6. package/dist/agent/cloudstudio/cloudstudioClient.js +10 -0
  7. package/dist/agent/cloudstudio/cloudstudioClient.js.map +1 -1
  8. package/dist/agent/cloudstudio/cloudstudioMcp.js +84 -8
  9. package/dist/agent/cloudstudio/cloudstudioMcp.js.map +1 -1
  10. package/dist/agent/cloudstudio/descarga.js +14 -4
  11. package/dist/agent/cloudstudio/descarga.js.map +1 -1
  12. package/dist/agent/cloudstudio/ramaActiva.js +11 -0
  13. package/dist/agent/cloudstudio/ramaActiva.js.map +1 -0
  14. package/dist/agent/cloudstudio/subida.js +13 -4
  15. package/dist/agent/cloudstudio/subida.js.map +1 -1
  16. package/dist/agent/config/catalogoModelos.js +45 -0
  17. package/dist/agent/config/catalogoModelos.js.map +1 -1
  18. package/dist/agent/config/modelos.js +103 -12
  19. package/dist/agent/config/modelos.js.map +1 -1
  20. package/dist/agent/config/mudanzaEnDisco.js +121 -0
  21. package/dist/agent/config/mudanzaEnDisco.js.map +1 -0
  22. package/dist/agent/config/selectorEnMaquina.js +45 -0
  23. package/dist/agent/config/selectorEnMaquina.js.map +1 -0
  24. package/dist/agent/config/settingsEnDisco.js +35 -0
  25. package/dist/agent/config/settingsEnDisco.js.map +1 -1
  26. package/dist/agent/dispositivos/juezVisual.js +152 -0
  27. package/dist/agent/dispositivos/juezVisual.js.map +1 -0
  28. package/dist/agent/dispositivos/sensorDeArranque.js +154 -0
  29. package/dist/agent/dispositivos/sensorDeArranque.js.map +1 -0
  30. package/dist/agent/exportarPdf.js +140 -0
  31. package/dist/agent/exportarPdf.js.map +1 -0
  32. package/dist/agent/grafo/criticaVisual.js +115 -0
  33. package/dist/agent/grafo/criticaVisual.js.map +1 -0
  34. package/dist/agent/grafo/navegacionXone.js +37 -4
  35. package/dist/agent/grafo/navegacionXone.js.map +1 -1
  36. package/dist/agent/grafo/perfiles.js +52 -9
  37. package/dist/agent/grafo/perfiles.js.map +1 -1
  38. package/dist/agent/grafo/proyecto.js +74 -7
  39. package/dist/agent/grafo/proyecto.js.map +1 -1
  40. package/dist/agent/grafo/skills.js +32 -0
  41. package/dist/agent/grafo/skills.js.map +1 -1
  42. package/dist/agent/grafo/xoneAgent.js +103 -13
  43. package/dist/agent/grafo/xoneAgent.js.map +1 -1
  44. package/dist/agent/navegacion/estilosEnDisco.js +110 -0
  45. package/dist/agent/navegacion/estilosEnDisco.js.map +1 -0
  46. package/dist/agent/navegacion/hechosEnDisco.js +26 -0
  47. package/dist/agent/navegacion/hechosEnDisco.js.map +1 -0
  48. package/dist/agent/navegacion/indiceEnDisco.js +15 -0
  49. package/dist/agent/navegacion/indiceEnDisco.js.map +1 -1
  50. package/dist/agent/subagentes/agentesEnDisco.js +85 -24
  51. package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
  52. package/dist/agent/subagentes/escrituraExterna.js +53 -0
  53. package/dist/agent/subagentes/escrituraExterna.js.map +1 -1
  54. package/dist/agent/subagentes/pluginDeSkills.js +99 -0
  55. package/dist/agent/subagentes/pluginDeSkills.js.map +1 -0
  56. package/dist/agent/subagentes/subagenteExterno.js +48 -0
  57. package/dist/agent/subagentes/subagenteExterno.js.map +1 -1
  58. package/dist/agent/subagentes/subagenteOpencode.js +53 -1
  59. package/dist/agent/subagentes/subagenteOpencode.js.map +1 -1
  60. package/dist/agent/tareas/juezDeTarea.js +1 -1
  61. package/dist/agent/tareas/juezDeTarea.js.map +1 -1
  62. package/dist/agent/tareas/tareasEnDisco.js +49 -0
  63. package/dist/agent/tareas/tareasEnDisco.js.map +1 -1
  64. package/dist/agent/turno/diagnosticoDeTools.js +5 -1
  65. package/dist/agent/turno/diagnosticoDeTools.js.map +1 -1
  66. package/dist/agent/turno/informeDeTraza.js +27 -4
  67. package/dist/agent/turno/informeDeTraza.js.map +1 -1
  68. package/dist/agent/turno/puente.js +24 -1
  69. package/dist/agent/turno/puente.js.map +1 -1
  70. package/dist/agent/turno/resumenDeContexto.js +88 -4
  71. package/dist/agent/turno/resumenDeContexto.js.map +1 -1
  72. package/dist/agent/turno/resumenDeTool.js +18 -0
  73. package/dist/agent/turno/resumenDeTool.js.map +1 -1
  74. package/dist/agent/turno/rubrica.js +91 -0
  75. package/dist/agent/turno/rubrica.js.map +1 -0
  76. package/dist/agent/turno/turnoReal.js +172 -11
  77. package/dist/agent/turno/turnoReal.js.map +1 -1
  78. package/dist/cli/consola.js +63 -0
  79. package/dist/cli/consola.js.map +1 -1
  80. package/dist/cli/main.js +51 -4
  81. package/dist/cli/main.js.map +1 -1
  82. package/dist/cli/run.js +8 -0
  83. package/dist/cli/run.js.map +1 -1
  84. package/dist/core/agentes.js +111 -9
  85. package/dist/core/agentes.js.map +1 -1
  86. package/dist/core/esfuerzo.js +141 -0
  87. package/dist/core/esfuerzo.js.map +1 -0
  88. package/dist/core/estilos.js +78 -0
  89. package/dist/core/estilos.js.map +1 -0
  90. package/dist/core/exportacion.js +140 -0
  91. package/dist/core/exportacion.js.map +1 -0
  92. package/dist/core/hechosDelProyecto.js +87 -0
  93. package/dist/core/hechosDelProyecto.js.map +1 -0
  94. package/dist/core/logDeDispositivo.js +143 -0
  95. package/dist/core/logDeDispositivo.js.map +1 -0
  96. package/dist/core/modelos.js +32 -0
  97. package/dist/core/modelos.js.map +1 -1
  98. package/dist/core/mudanzaDeWorkspace.js +93 -0
  99. package/dist/core/mudanzaDeWorkspace.js.map +1 -0
  100. package/dist/core/planes.js +70 -0
  101. package/dist/core/planes.js.map +1 -0
  102. package/dist/core/ports.js +4 -0
  103. package/dist/core/ports.js.map +1 -1
  104. package/dist/core/rubrica.js +90 -0
  105. package/dist/core/rubrica.js.map +1 -0
  106. package/dist/core/selectorDeCarpeta.js +87 -0
  107. package/dist/core/selectorDeCarpeta.js.map +1 -0
  108. package/dist/core/settings.js +54 -5
  109. package/dist/core/settings.js.map +1 -1
  110. package/dist/core/shellDeAgente.js +45 -0
  111. package/dist/core/shellDeAgente.js.map +1 -1
  112. package/dist/core/topeAgotado.js +69 -0
  113. package/dist/core/topeAgotado.js.map +1 -0
  114. package/dist/web/servidor/arranque.js +324 -9
  115. package/dist/web/servidor/arranque.js.map +1 -1
  116. package/dist/web/servidor/sesiones.js +30 -2
  117. package/dist/web/servidor/sesiones.js.map +1 -1
  118. package/dist/web/servidor/transporte.js.map +1 -1
  119. package/dist/web/servidor/vestibulo.js +55 -6
  120. package/dist/web/servidor/vestibulo.js.map +1 -1
  121. package/package.json +2 -1
  122. package/skills/xone-hotswap/SKILL.md +31 -9
  123. package/skills/xone-hotswap/scripts/xone-arrancar-android +202 -0
  124. package/skills/xone-hotswap/scripts/xone-captura-android +93 -0
  125. package/skills/xone-hotswap/scripts/xone-desplegar-android +28 -0
  126. package/skills/xone-hotswap/scripts/xone-hotswap +39 -9
  127. package/skills/xone-hotswap/scripts/xone-reiniciar-android +28 -0
  128. package/skills/xone-plan-builder/SKILL.md +22 -4
  129. package/skills/xone-spec-builder/SKILL.md +37 -7
  130. package/apps/web/dist/assets/index-DBZTodio.js +0 -477
@@ -0,0 +1,154 @@
1
+ /**
2
+ * El APARATO como sensor del bucle de reparación: ¿qué dice la app al arrancar?
3
+ *
4
+ * Es la tercera fuente de hallazgos, y contesta una pregunta que las otras dos no pueden.
5
+ * `xone-simulator validate` mira la estructura y `smoke` ejecuta el ciclo de vida en un
6
+ * runtime de Node; ninguno de los dos sabe si la app ARRANCA en un Android de verdad, con su
7
+ * SQLite, sus recursos y su Rhino. Medido sobre AppDemo: el simulador daba verde y el aparato
8
+ * decía `Invalid resource ID 0x6000000N` cinco veces distintas.
9
+ *
10
+ * CUATRO REGLAS, y las cuatro salieron de medir:
11
+ *
12
+ * - **Despliega SIEMPRE antes de leer.** Sin eso el log sería de la versión anterior del
13
+ * proyecto, y devolverle al agente errores que ya arregló es la peor clase de feedback:
14
+ * plausible y falso. El despliegue en caliente costó 5 s sobre un `pixel8`.
15
+ * - **El buffer se vacía ANTES de reiniciar.** Es lo que ya hace `xone-desplegar-android` por
16
+ * su cuenta y por el mismo motivo: si no, lo que se lee es la excepción del intento
17
+ * anterior, que es la forma más fácil de creer que algo sigue roto cuando ya no lo está.
18
+ * - **Sin aparato es fallo del ENTORNO, no un rojo.** La misma familia que
19
+ * `ErrorDelSimulador`: un informe rojo diría «tu proyecto está mal» cuando lo que pasa es
20
+ * que no hay móvil enchufado. Y **no se arranca uno solo**: levantar un emulador cuesta
21
+ * minutos de la máquina de alguien, y esa decisión no la toma un sensor — para eso está
22
+ * `xone-arrancar-android`, que el agente puede llamar.
23
+ * - **Solo ve la pantalla de ENTRADA, y se declara.** El despliegue reinicia la app, así que
24
+ * lo que se lee es lo que pasa al arrancar. Para tener hallazgos de una colección concreta
25
+ * hay que NAVEGAR hasta ella, y eso es trabajo del `device-controller` dentro del turno, no
26
+ * de un sensor automático.
27
+ *
28
+ * Todo entra por dependencias: `npm test` no puede necesitar un aparato.
29
+ */
30
+ import { execFile } from "node:child_process";
31
+ import { existsSync } from "node:fs";
32
+ import { join } from "node:path";
33
+ import { hallazgosDeLog } from "../../core/logDeDispositivo.js";
34
+ import { RAIZ_SKILLS } from "../grafo/skills.js";
35
+ import { localizadorDeAndroid, TOPES_MS } from "./dispositivosEnMaquina.js";
36
+ import { parsearAdbDevices } from "../../core/dispositivos.js";
37
+ /** No se pudo PREGUNTARLE al aparato. Entorno, no proyecto. */
38
+ export class ErrorDelAparato extends Error {
39
+ constructor(motivo) {
40
+ super(motivo);
41
+ this.name = "ErrorDelAparato";
42
+ }
43
+ }
44
+ /**
45
+ * Despliega y devuelve lo que el aparato dijo, en la forma que el bucle ya consume.
46
+ *
47
+ * **Verde es que no hay hallazgos DE LA APP.** Lo de la plataforma viaja en el informe —no se
48
+ * tira nunca, ver `core/logDeDispositivo.ts`— pero como `warning`, así que no pinta el turno
49
+ * de rojo: son quejas de Android sobre sí mismo y nadie las puede arreglar desde un `.xne`.
50
+ */
51
+ export async function arranqueEnDispositivo(raiz, deps) {
52
+ if (!(await deps.hayAparato())) {
53
+ throw new ErrorDelAparato("no hay ningún aparato conectado, así que no se ha podido probar el arranque");
54
+ }
55
+ await deps.limpiarLog();
56
+ const despliegue = await deps.desplegar(raiz);
57
+ if (!despliegue.ok) {
58
+ /**
59
+ * Que el despliegue falle NO es un proyecto roto: puede ser el túnel, el canal o que el
60
+ * host no esté instalado. Se lanza, y quien llama lo dice como aviso — igual que el
61
+ * binario del simulador que falta.
62
+ */
63
+ throw new ErrorDelAparato(`no se pudo desplegar en el aparato: ${despliegue.detalle}`);
64
+ }
65
+ const { aHallazgosDelTurno } = hallazgosDeLog(await deps.leerLog());
66
+ const hallazgos = aHallazgosDelTurno();
67
+ return { verde: !hallazgos.some((h) => h.severidad === "error"), hallazgos };
68
+ }
69
+ /** El host de XOne en Android. Vive aquí y en los scripts de la skill, que son otro proceso. */
70
+ const PAQUETE = "com.xone.android.framework";
71
+ /**
72
+ * Cuánto se le da al despliegue. El script hace la cadena entera —túnel, ZIP, subida,
73
+ * reinicio, lanzamiento y comprobación de que la app está VIVA— y sobre un `pixel8` en
74
+ * caliente tardó 5 s con un proyecto de 6,8 MB. El tope es para el caso frío con un proyecto
75
+ * grande, y por debajo del tope de reloj de un comando del harness.
76
+ */
77
+ export const TOPE_DE_DESPLIEGUE_MS = 300_000;
78
+ /**
79
+ * El sensor de verdad: `adb` para el log y el script de la skill para el despliegue.
80
+ *
81
+ * **El despliegue NO se reimplementa aquí.** `xone-desplegar-android` ya es la cadena medida
82
+ * —y la única que sabe que hay que reiniciar con `SetupActivity` y no con `.mainEntry`, y que
83
+ * el ZIP va sin `.xonecode`—. Reescribirla sería un segundo sitio donde esa secuencia puede
84
+ * divergir, que es como este repo se ha roto siempre.
85
+ */
86
+ export function sensorDeArranqueReal() {
87
+ const { enSdk } = localizadorDeAndroid({
88
+ plataforma: process.platform,
89
+ entorno: process.env,
90
+ home: process.env["HOME"] ?? "",
91
+ existe: (ruta) => existsSync(ruta),
92
+ });
93
+ const adb = enSdk("adb", "platform-tools");
94
+ const correr = (binario, args, ms) => new Promise((resolver, rechazar) => {
95
+ execFile(binario, args, { timeout: ms, maxBuffer: 64 * 1024 * 1024 }, (error, stdout) => {
96
+ if (error !== null)
97
+ rechazar(error);
98
+ else
99
+ resolver(stdout);
100
+ });
101
+ });
102
+ const exigirAdb = () => {
103
+ if (adb === undefined)
104
+ throw new ErrorDelAparato("no encuentro «adb»: ni en el PATH ni en el SDK");
105
+ return adb;
106
+ };
107
+ return {
108
+ hayAparato: async () => {
109
+ try {
110
+ return parsearAdbDevices(await correr(exigirAdb(), ["devices"], TOPES_MS.adb)).some((d) => d.estado === "conectado");
111
+ }
112
+ catch {
113
+ // No poder preguntar no es «no hay»: se dice arriba, con su motivo.
114
+ throw new ErrorDelAparato("no se pudo preguntar a adb qué aparatos hay");
115
+ }
116
+ },
117
+ limpiarLog: async () => {
118
+ await correr(exigirAdb(), ["logcat", "-c"], TOPES_MS.adb);
119
+ },
120
+ desplegar: async (raiz) => {
121
+ const script = join(RAIZ_SKILLS, "xone-hotswap", "scripts", "xone-desplegar-android");
122
+ if (!existsSync(script))
123
+ return { ok: false, detalle: "falta xone-desplegar-android en el paquete" };
124
+ try {
125
+ // El `cwd` es la raíz del proyecto: el script empaqueta lo que hay ahí.
126
+ await new Promise((resolver, rechazar) => {
127
+ execFile(process.execPath, [script], { cwd: raiz, timeout: TOPE_DE_DESPLIEGUE_MS, maxBuffer: 16 * 1024 * 1024 }, (error) => (error === null ? resolver() : rechazar(error)));
128
+ });
129
+ return { ok: true, detalle: "" };
130
+ }
131
+ catch (error) {
132
+ // Una línea, no el volcado: esto va a un aviso del turno.
133
+ const texto = error instanceof Error ? error.message : String(error);
134
+ return { ok: false, detalle: texto.split("\n")[0] ?? "falló el despliegue" };
135
+ }
136
+ },
137
+ leerLog: async () => {
138
+ const pid = (await correr(exigirAdb(), ["shell", "pidof", PAQUETE], TOPES_MS.adb))
139
+ .trim()
140
+ .split(/\s+/)[0];
141
+ if (pid === undefined || pid === "") {
142
+ /**
143
+ * La app NO está viva tras desplegar. Es un hecho del proyecto y no del entorno —el
144
+ * despliegue dijo que sí—, así que no se lanza: se devuelve lo que haya sin acotar por
145
+ * PID, que es donde estará la traza de la muerte. Filtrar por un PID que ya no existe
146
+ * se llevaría por delante justo esa traza.
147
+ */
148
+ return correr(exigirAdb(), ["logcat", "-d", "-t", "400"], TOPES_MS.adb);
149
+ }
150
+ return correr(exigirAdb(), ["logcat", "-d", "--pid", pid], TOPES_MS.adb);
151
+ },
152
+ };
153
+ }
154
+ //# sourceMappingURL=sensorDeArranque.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensorDeArranque.js","sourceRoot":"","sources":["../../../src/agent/dispositivos/sensorDeArranque.ts"],"names":[],"mappings":"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"}
@@ -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":"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"}
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
- // OJO: este `/**` también deniega `/artefactos/**`, así que un agente de SOLO LECTURA no
58
- // puede dejar una captura CON UNA TOOL DE FICHERO. `device-controller` la deja igual, pero
59
- // por otro camino —un comando, que no pasa por aquí— y por eso el anuncio del artefacto
60
- // tuvo que ir aparte (`proyecto.ts#anunciarArtefactosDeLaShell`). Si algún día hace falta
61
- // un productor de solo lectura SIN shell, la excepción va aquí, y antes hay que medir el
62
- // orden de reglas de deepagents (¿gana la primera que casa, o gana la denegación?), porque
63
- // de eso depende que un `allow` sobre `/artefactos/**` haga algo o sea decorativo.
64
- return [...base, { operations: ["write"], paths: ["/**"], mode: "deny" }];
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 artefactoFueraDeSitio(ruta) === undefined;
248
+ return true;
206
249
  }
207
250
  //# sourceMappingURL=perfiles.js.map