xonecode 0.1.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 (187) hide show
  1. package/README.md +167 -0
  2. package/dist/agent/authEnDisco.js +56 -0
  3. package/dist/agent/authEnDisco.js.map +1 -0
  4. package/dist/agent/configEnDisco.js +109 -0
  5. package/dist/agent/configEnDisco.js.map +1 -0
  6. package/dist/agent/crearProyecto.js +34 -0
  7. package/dist/agent/crearProyecto.js.map +1 -0
  8. package/dist/agent/entorno.js +124 -0
  9. package/dist/agent/entorno.js.map +1 -0
  10. package/dist/agent/guionizado.js +53 -0
  11. package/dist/agent/guionizado.js.map +1 -0
  12. package/dist/agent/instantanea.js +129 -0
  13. package/dist/agent/instantanea.js.map +1 -0
  14. package/dist/agent/interrupts.js +83 -0
  15. package/dist/agent/interrupts.js.map +1 -0
  16. package/dist/agent/mensajes.js +24 -0
  17. package/dist/agent/mensajes.js.map +1 -0
  18. package/dist/agent/modelos.js +42 -0
  19. package/dist/agent/modelos.js.map +1 -0
  20. package/dist/agent/normalizar.js +20 -0
  21. package/dist/agent/normalizar.js.map +1 -0
  22. package/dist/agent/perfiles.js +103 -0
  23. package/dist/agent/perfiles.js.map +1 -0
  24. package/dist/agent/proyecto.js +107 -0
  25. package/dist/agent/proyecto.js.map +1 -0
  26. package/dist/agent/puente.js +142 -0
  27. package/dist/agent/puente.js.map +1 -0
  28. package/dist/agent/resumenDeTool.js +48 -0
  29. package/dist/agent/resumenDeTool.js.map +1 -0
  30. package/dist/agent/skills.js +65 -0
  31. package/dist/agent/skills.js.map +1 -0
  32. package/dist/agent/textoDeTool.js +113 -0
  33. package/dist/agent/textoDeTool.js.map +1 -0
  34. package/dist/agent/turnoReal.js +173 -0
  35. package/dist/agent/turnoReal.js.map +1 -0
  36. package/dist/agent/verificador.js +65 -0
  37. package/dist/agent/verificador.js.map +1 -0
  38. package/dist/agent/xoneAgent.js +106 -0
  39. package/dist/agent/xoneAgent.js.map +1 -0
  40. package/dist/bin.js +9 -0
  41. package/dist/bin.js.map +1 -0
  42. package/dist/cli/aprobar.js +82 -0
  43. package/dist/cli/aprobar.js.map +1 -0
  44. package/dist/cli/config.js +133 -0
  45. package/dist/cli/config.js.map +1 -0
  46. package/dist/cli/consola.js +346 -0
  47. package/dist/cli/consola.js.map +1 -0
  48. package/dist/cli/describe.js +53 -0
  49. package/dist/cli/describe.js.map +1 -0
  50. package/dist/cli/doctor.js +45 -0
  51. package/dist/cli/doctor.js.map +1 -0
  52. package/dist/cli/main.js +520 -0
  53. package/dist/cli/main.js.map +1 -0
  54. package/dist/cli/markdown.js +90 -0
  55. package/dist/cli/markdown.js.map +1 -0
  56. package/dist/cli/run.js +164 -0
  57. package/dist/cli/run.js.map +1 -0
  58. package/dist/cli/spinner.js +89 -0
  59. package/dist/cli/spinner.js.map +1 -0
  60. package/dist/cli/stdio.js +193 -0
  61. package/dist/cli/stdio.js.map +1 -0
  62. package/dist/cli/tema.js +40 -0
  63. package/dist/cli/tema.js.map +1 -0
  64. package/dist/cli/verify.js +62 -0
  65. package/dist/cli/verify.js.map +1 -0
  66. package/dist/core/bitacora.js +30 -0
  67. package/dist/core/bitacora.js.map +1 -0
  68. package/dist/core/config.js +236 -0
  69. package/dist/core/config.js.map +1 -0
  70. package/dist/core/contextos.js +56 -0
  71. package/dist/core/contextos.js.map +1 -0
  72. package/dist/core/deps.js +51 -0
  73. package/dist/core/deps.js.map +1 -0
  74. package/dist/core/diff.js +79 -0
  75. package/dist/core/diff.js.map +1 -0
  76. package/dist/core/esqueleto.js +366 -0
  77. package/dist/core/esqueleto.js.map +1 -0
  78. package/dist/core/events.js +2 -0
  79. package/dist/core/events.js.map +1 -0
  80. package/dist/core/modelos.js +85 -0
  81. package/dist/core/modelos.js.map +1 -0
  82. package/dist/core/notify.js +106 -0
  83. package/dist/core/notify.js.map +1 -0
  84. package/dist/core/ports.js +114 -0
  85. package/dist/core/ports.js.map +1 -0
  86. package/dist/core/turno.js +127 -0
  87. package/dist/core/turno.js.map +1 -0
  88. package/dist/vendor/hitl.js +103 -0
  89. package/dist/vendor/hitl.js.map +1 -0
  90. package/dist/vendor/skillLoaders/catalog.js +74 -0
  91. package/dist/vendor/skillLoaders/catalog.js.map +1 -0
  92. package/dist/vendor/tokenTracking.js +58 -0
  93. package/dist/vendor/tokenTracking.js.map +1 -0
  94. package/package.json +41 -0
  95. package/skills/xone-debugging/SKILL.md +52 -0
  96. package/skills/xone-debugging/references/faq.md +561 -0
  97. package/skills/xone-debugging/references/troubleshooting-y-glosario.md +429 -0
  98. package/skills/xone-development/SKILL.md +105 -0
  99. package/skills/xone-development/references/anti-patrones.md +94 -0
  100. package/skills/xone-development/references/css/atributos-por-categoria.md +509 -0
  101. package/skills/xone-development/references/css/buenas-practicas-y-parser.md +419 -0
  102. package/skills/xone-development/references/css/dinamicos-cascada-y-componentes.md +550 -0
  103. package/skills/xone-development/references/css/patrones-material-y-temas.md +1140 -0
  104. package/skills/xone-development/references/css/propiedades-y-herencia.md +885 -0
  105. package/skills/xone-development/references/css/selectores-unidades-colores.md +840 -0
  106. package/skills/xone-development/references/datos/appdata-referencia-ampliada.md +457 -0
  107. package/skills/xone-development/references/datos/appdata.md +611 -0
  108. package/skills/xone-development/references/datos/http-sqlmanager-y-crypto.md +720 -0
  109. package/skills/xone-development/references/datos/http.md +366 -0
  110. package/skills/xone-development/references/datos/oauth2-y-replica.md +156 -0
  111. package/skills/xone-development/references/device/biometria-imagedrawing-y-otros.md +544 -0
  112. package/skills/xone-development/references/device/objetos-de-dispositivo.md +583 -0
  113. package/skills/xone-development/references/device/systemsettings-referencia-ampliada.md +396 -0
  114. package/skills/xone-development/references/device/systemsettings-y-permisos.md +342 -0
  115. package/skills/xone-development/references/fundamentos/conceptos-clave.md +695 -0
  116. package/skills/xone-development/references/fundamentos/configuracion-app-xml-ini-mappings.md +668 -0
  117. package/skills/xone-development/references/fundamentos/errores-comunes.md +312 -0
  118. package/skills/xone-development/references/fundamentos/navegacion-convenciones-y-primer-proyecto.md +576 -0
  119. package/skills/xone-development/references/fundamentos/plataforma-y-anatomia-de-proyecto.md +387 -0
  120. package/skills/xone-development/references/indice-completo.md +77 -0
  121. package/skills/xone-development/references/javascript/coleccion-error-y-usuario.md +260 -0
  122. package/skills/xone-development/references/javascript/debugging-y-best-practices.md +245 -0
  123. package/skills/xone-development/references/javascript/metodos-de-los-controles.md +556 -0
  124. package/skills/xone-development/references/javascript/metodos-nativos-de-la-vista.md +114 -0
  125. package/skills/xone-development/references/javascript/motor-js-y-contexto-de-ejecucion.md +319 -0
  126. package/skills/xone-development/references/javascript/objeto-ai-llm-en-dispositivo.md +358 -0
  127. package/skills/xone-development/references/javascript/objetos-creables-a-m.md +527 -0
  128. package/skills/xone-development/references/javascript/objetos-creables-n-z.md +385 -0
  129. package/skills/xone-development/references/javascript/patrones-criticos-seguridad-y-rendimiento.md +595 -0
  130. package/skills/xone-development/references/javascript/patrones-de-navegacion-datos-y-codigo.md +751 -0
  131. package/skills/xone-development/references/javascript/patrones-de-ui-voz-integracion-y-seguridad.md +701 -0
  132. package/skills/xone-development/references/javascript/plantillas-y-funciones-utilitarias.md +647 -0
  133. package/skills/xone-development/references/javascript/self-y-dataobject.md +449 -0
  134. package/skills/xone-development/references/javascript/singletons-globales.md +361 -0
  135. package/skills/xone-development/references/javascript/ui-catalogo-de-metodos.md +464 -0
  136. package/skills/xone-development/references/javascript/ui-gps-camara-y-multimedia.md +506 -0
  137. package/skills/xone-development/references/javascript/ui-navegacion-mensajes-y-vista.md +422 -0
  138. package/skills/xone-development/references/resumen-js-datos-dispositivo.md +80 -0
  139. package/skills/xone-development/references/resumen-xml-y-css.md +74 -0
  140. package/skills/xone-development/references/tipos-de-prop.md +28 -0
  141. package/skills/xone-development/references/xml-ui/asfilter-visibilidad-eventos-y-macros.md +576 -0
  142. package/skills/xone-development/references/xml-ui/atributos-coll-group-frame.md +235 -0
  143. package/skills/xone-development/references/xml-ui/atributos-method-macro-script-event-app.md +244 -0
  144. package/skills/xone-development/references/xml-ui/atributos-prop.md +439 -0
  145. package/skills/xone-development/references/xml-ui/contents-y-macros.md +392 -0
  146. package/skills/xone-development/references/xml-ui/errores-comunes-xml.md +245 -0
  147. package/skills/xone-development/references/xml-ui/estructura-y-nodo-coll.md +326 -0
  148. package/skills/xone-development/references/xml-ui/eventos-ciclo-de-vida-e-interaccion.md +704 -0
  149. package/skills/xone-development/references/xml-ui/eventos-sistema-login-y-personalizados.md +944 -0
  150. package/skills/xone-development/references/xml-ui/layouts-herencia-y-buenas-practicas.md +618 -0
  151. package/skills/xone-development/references/xml-ui/mapas.md +685 -0
  152. package/skills/xone-development/references/xml-ui/mappings-y-colecciones-separadas.md +148 -0
  153. package/skills/xone-development/references/xml-ui/nodos-group-y-frame.md +666 -0
  154. package/skills/xone-development/references/xml-ui/patrones-de-pantalla.md +643 -0
  155. package/skills/xone-development/references/xml-ui/prop-atributos-y-condiciones.md +298 -0
  156. package/skills/xone-development/references/xml-ui/prop-tipos-basicos.md +493 -0
  157. package/skills/xone-development/references/xml-ui/prop-tipos-combos-y-controles.md +664 -0
  158. package/skills/xone-development/references/xml-ui/prop-tipos-listas-y-mapas.md +412 -0
  159. package/skills/xone-plan-builder/SKILL.md +183 -0
  160. package/skills/xone-plan-builder/agents/openai.yaml +5 -0
  161. package/skills/xone-plan-builder/references/TASKS-FORMAT.md +132 -0
  162. package/skills/xone-project-generator/SKILL.md +111 -0
  163. package/skills/xone-project-generator/references/canonical-sizes.md +292 -0
  164. package/skills/xone-project-generator/references/colecciones-base.md +16 -0
  165. package/skills/xone-project-generator/references/convenciones-de-nombres.md +16 -0
  166. package/skills/xone-project-generator/references/ejemplos-por-sector-y-prohibiciones.md +140 -0
  167. package/skills/xone-project-generator/references/fase-3-estilos-css.md +597 -0
  168. package/skills/xone-project-generator/references/fase-6-colecciones.md +762 -0
  169. package/skills/xone-project-generator/references/fase-7-asfilter-e-integraciones.md +142 -0
  170. package/skills/xone-project-generator/references/fase-7-entidades-y-estructura-de-pantalla.md +494 -0
  171. package/skills/xone-project-generator/references/fase-7-plantilla-consola.md +477 -0
  172. package/skills/xone-project-generator/references/fase-7-plantillas-de-pantalla.md +302 -0
  173. package/skills/xone-project-generator/references/fase-7-viewmodes-graficos-y-listas.md +681 -0
  174. package/skills/xone-project-generator/references/fase-7-viewmodes-mapa-y-calendario.md +479 -0
  175. package/skills/xone-project-generator/references/fases-0-2-analisis-y-modelo-de-datos.md +350 -0
  176. package/skills/xone-project-generator/references/fases-10-12-readmes-y-validacion.md +194 -0
  177. package/skills/xone-project-generator/references/fases-4-5-estructura-y-configuracion.md +587 -0
  178. package/skills/xone-project-generator/references/fases-8-9-eventos-y-javascript.md +861 -0
  179. package/skills/xone-project-generator/references/flujo-de-generacion.md +67 -0
  180. package/skills/xone-project-generator/references/plantillas-estandar.md +98 -0
  181. package/skills/xone-project-generator/references/tamanos-canonicos.md +49 -0
  182. package/skills/xone-review/SKILL.md +189 -0
  183. package/skills/xone-spec-builder/SKILL.md +235 -0
  184. package/skills/xone-spec-builder/agents/openai.yaml +5 -0
  185. package/skills/xone-spec-builder/references/ADR-FORMAT.md +55 -0
  186. package/skills/xone-spec-builder/references/CONTEXT-FORMAT.md +42 -0
  187. package/skills/xone-spec-builder/references/PLAN-FORMAT.md +120 -0
@@ -0,0 +1,142 @@
1
+ import { normalizar } from "./normalizar.js";
2
+ import { Mensajes } from "./mensajes.js";
3
+ import { detalleDe } from "./resumenDeTool.js";
4
+ /** El texto de un mensaje, venga como venga. */
5
+ export function textoDe(msg) {
6
+ if (!msg || typeof msg !== "object")
7
+ return "";
8
+ const m = msg;
9
+ if (typeof m.text === "string")
10
+ return m.text;
11
+ const c = m.content;
12
+ if (typeof c === "string")
13
+ return c;
14
+ // Contenido en BLOQUES (Gemini con thinking): concatenar solo los de texto. Un
15
+ // `String(content)` daría el `repr` de la lista, razonamiento incluido, y el usuario
16
+ // vería basura donde esperaba una frase.
17
+ if (Array.isArray(c)) {
18
+ return c
19
+ .map((b) => (b && typeof b === "object" && typeof b.text === "string" ? b.text : ""))
20
+ .join("");
21
+ }
22
+ return "";
23
+ }
24
+ /** Los nombres de tool de un chunk de `updates`, con su detalle de la lista blanca. */
25
+ export function toolsDe(dato) {
26
+ if (!dato || typeof dato !== "object")
27
+ return [];
28
+ const salida = [];
29
+ for (const nodo of Object.values(dato)) {
30
+ const msgs = nodo?.messages;
31
+ if (!Array.isArray(msgs))
32
+ continue;
33
+ for (const m of msgs) {
34
+ const llamadas = m?.tool_calls;
35
+ if (Array.isArray(llamadas)) {
36
+ for (const l of llamadas) {
37
+ const n = l?.name;
38
+ if (typeof n === "string")
39
+ salida.push({ nombre: n, detalle: detalleDe(n, l.args) });
40
+ }
41
+ }
42
+ }
43
+ }
44
+ return salida;
45
+ }
46
+ /**
47
+ * ¿Este chunk lo emite el grafo PADRE, o un especialista?
48
+ *
49
+ * **Medido el 2026-08-30**, sobre un turno real con delegación. Los namespaces que
50
+ * llegan con `subgraphs: true` son exactamente tres formas:
51
+ *
52
+ * | namespace | quién | chunks |
53
+ * |----------------------------------------|---------------|-------:|
54
+ * | `["model_request:…"]` | el padre | 148 |
55
+ * | `["tools:…", "model_request:…"]` | un especialista | 745 |
56
+ * | `["tools:…", "tools:…"]` | tools de un especialista | 12 |
57
+ *
58
+ * Un especialista SIEMPRE lleva el segmento `tools:` delante, porque se le invoca con la
59
+ * tool `task`. Así que la frontera es la LONGITUD.
60
+ *
61
+ * **El fallo que esto cierra era mudo y caro.** Antes se descartaba todo `ns` no vacío,
62
+ * dando por hecho que el padre venía con `ns: []` — cierto para `updates`, FALSO para
63
+ * `messages`, que llegan con `["model_request:<uuid>"]`. Consecuencia: se descartaban
64
+ * TODOS los tokens, respuesta incluida. El turno corría entero, enseñaba sus tools,
65
+ * decía «sin cambios en el proyecto»… y no contestaba nada. Sin excepción y sin aviso.
66
+ *
67
+ * Y los números explican por qué el filtro tiene que existir: 745 chunks de especialista
68
+ * frente a 148 del padre. Emitirlos todos sería volcar el razonamiento interno de los
69
+ * especialistas encima de la respuesta.
70
+ */
71
+ export function esDelPadre(ns) {
72
+ return ns.length <= 1;
73
+ }
74
+ /**
75
+ * Convierte el stream del grafo en `DomainEvent`.
76
+ *
77
+ * **Se lee con `subgraphs: true`**, porque sin él lo que hacen los especialistas —que son
78
+ * grafos compilados invocados dentro de un nodo— no llega al padre, y el fallo es MUDO. El
79
+ * precio, medido: el chunk pasa de `[modo, dato]` a `[namespace, modo, dato]`, y de eso se
80
+ * encarga `normalizar`.
81
+ *
82
+ * Los tokens que se emiten son SOLO los del grafo padre. Los de un
83
+ * especialista son su razonamiento interno, no la respuesta: enseñarlos convierte la
84
+ * consola en un volcado. Su trabajo se cuenta por `tool`, que es lo que el usuario
85
+ * necesita ver mientras espera.
86
+ */
87
+ export async function* aEventos(stream, pendientes) {
88
+ const mensajes = new Mensajes();
89
+ try {
90
+ for await (const bruto of stream) {
91
+ const chunk = normalizar(bruto);
92
+ if (!chunk)
93
+ continue;
94
+ if (chunk.modo === "updates") {
95
+ for (const { nombre, detalle } of toolsDe(chunk.dato)) {
96
+ yield { tipo: "tool", nombre, ...(detalle !== undefined ? { detalle } : {}) };
97
+ }
98
+ continue;
99
+ }
100
+ if (chunk.modo === "messages") {
101
+ if (!esDelPadre(chunk.ns))
102
+ continue; // de un especialista: no es la respuesta
103
+ if (!Array.isArray(chunk.dato))
104
+ continue;
105
+ const [msg] = chunk.dato;
106
+ const texto = textoDe(msg);
107
+ const id = msg?.id;
108
+ const idTexto = typeof id === "string" ? id : undefined;
109
+ if (mensajes.trozo(idTexto, texto).pintar) {
110
+ yield { tipo: "token", texto, msgId: idTexto };
111
+ }
112
+ }
113
+ }
114
+ }
115
+ finally {
116
+ mensajes.fin();
117
+ // La pausa se consulta AL AGOTARSE el stream, no dentro del bucle: una pausa
118
+ // TERMINA el turno, así que el interrupt solo puede estar en el estado cuando el
119
+ // stream ya se ha acabado. Y solo si alguien pasó `pendientes`: sin el parámetro,
120
+ // el comportamiento es el de antes.
121
+ if (pendientes !== undefined) {
122
+ try {
123
+ const lista = await pendientes();
124
+ if (lista.length > 0) {
125
+ // Una sola `pausa` aunque vengan varios: con dos `task` en un turno quedan
126
+ // DOS interrupts a la vez, y dos eventos harían preguntar dos veces por lotes.
127
+ yield { tipo: "pausa", pendientes: lista };
128
+ }
129
+ }
130
+ catch (e) {
131
+ // No se traga: callarlo haría creer que no había nada que aprobar cuando en
132
+ // verdad no se pudo comprobar. Fallar entero tampoco: el turno ya acabó.
133
+ yield {
134
+ tipo: "aviso",
135
+ texto: `⚠ No se pudo comprobar si había algo pendiente de aprobación: ${e instanceof Error ? e.message : String(e)}`,
136
+ severidad: "grave",
137
+ };
138
+ }
139
+ }
140
+ }
141
+ }
142
+ //# sourceMappingURL=puente.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puente.js","sourceRoot":"","sources":["../../src/agent/puente.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * La LISTA BLANCA de la línea de estado: qué argumento de cada tool puede salir como
3
+ * `detalle` del evento `tool`.
4
+ *
5
+ * La regla dura está documentada en `core/events.ts`: ningún evento lleva argumentos de
6
+ * tool crudos, porque `write_file` lleva el contenido del fichero y una tool MCP lleva
7
+ * el bearer — enseñar el progreso no puede ser la forma de filtrar un secreto. Este
8
+ * módulo es la otra mitad de esa regla: no se FILTRA nada, se ELIGE a mano un campo por
9
+ * tool — una ruta o un patrón, nunca contenido — y lo que no está en la tabla no sale.
10
+ * Los nombres de campo son los de las tools de fichero de deepagents, verificados
11
+ * contra su dist (`file_path` con `path` normalizado, `pattern` en glob/grep).
12
+ */
13
+ /** El único campo permitido de cada tool. Sin entrada: nada sale. */
14
+ const CAMPO_SEGURO = {
15
+ read_file: "file_path",
16
+ write_file: "file_path",
17
+ edit_file: "file_path",
18
+ ls: "path",
19
+ glob: "pattern",
20
+ grep: "pattern",
21
+ };
22
+ /**
23
+ * El `detalle` de una llamada, o `undefined` si no hay nada permitido que contar.
24
+ *
25
+ * Los argumentos llegan como objeto o como cadena JSON (así viajan en las
26
+ * `tool_calls`); un JSON roto es una tool rota, no una excepción que tumbe el turno.
27
+ */
28
+ export function detalleDe(nombre, args) {
29
+ const campo = CAMPO_SEGURO[nombre];
30
+ if (campo === undefined)
31
+ return undefined;
32
+ let objeto = args;
33
+ if (typeof args === "string") {
34
+ try {
35
+ objeto = JSON.parse(args);
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ }
41
+ if (!objeto || typeof objeto !== "object")
42
+ return undefined;
43
+ const valor = objeto[campo];
44
+ // Una cadena vacía no describe nada, y un tipo raro (`file_path: 42`) tampoco:
45
+ // sin detalle es una respuesta válida.
46
+ return typeof valor === "string" && valor !== "" ? valor : undefined;
47
+ }
48
+ //# sourceMappingURL=resumenDeTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumenDeTool.js","sourceRoot":"","sources":["../../src/agent/resumenDeTool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,qEAAqE;AACrE,MAAM,YAAY,GAA2B;IAC3C,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,WAAW;IACtB,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,IAAa;IACrD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE1C,IAAI,MAAM,GAAY,IAAI,CAAC;IAC3B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAE5D,MAAM,KAAK,GAAI,MAAkC,CAAC,KAAK,CAAC,CAAC;IACzD,+EAA+E;IAC/E,uCAAuC;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { readdirSync, existsSync, readFileSync } from "node:fs";
2
+ import { join, dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parseFrontmatter } from "../vendor/skillLoaders/catalog.js";
5
+ /**
6
+ * Dónde viven las skills.
7
+ *
8
+ * Dos niveles arriba, y sirve igual desde `src/` (con tsx) que desde `dist/`: los dos
9
+ * cuelgan de la raíz del repo, así que `../../skills` acierta en ambos.
10
+ *
11
+ * Se resuelve contra ESTE módulo y no contra el cwd: en la v1 el cwd es el proyecto del
12
+ * cliente, así que un `./skills` relativo apuntaría al proyecto del usuario y el catálogo
13
+ * saldría vacío sin que nadie supiera por qué.
14
+ */
15
+ export const RAIZ_SKILLS = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "skills");
16
+ /** Estimación de coste. 4 caracteres por token es la regla de servilleta de siempre. */
17
+ export const tokensDe = (texto) => Math.ceil(texto.length / 4);
18
+ /**
19
+ * Las skills en disco. NO lleva la marca de doble: son las de verdad.
20
+ *
21
+ * El catálogo se lee UNA vez y se cachea: son seis ficheros que no cambian a mitad de
22
+ * turno, y releerlos por cada consulta convierte el catálogo en E/S dentro del lazo.
23
+ */
24
+ export class SkillsEnDisco {
25
+ raiz;
26
+ cache = null;
27
+ constructor(raiz = RAIZ_SKILLS) {
28
+ this.raiz = raiz;
29
+ }
30
+ catalogo() {
31
+ if (this.cache)
32
+ return this.cache;
33
+ if (!existsSync(this.raiz))
34
+ return (this.cache = []);
35
+ const salida = [];
36
+ for (const entrada of readdirSync(this.raiz)) {
37
+ const skillMd = join(this.raiz, entrada, "SKILL.md");
38
+ if (!existsSync(skillMd))
39
+ continue;
40
+ try {
41
+ const bruto = readFileSync(skillMd, "utf8");
42
+ const { data } = parseFrontmatter(bruto);
43
+ salida.push({
44
+ nombre: data.name ?? entrada,
45
+ descripcion: data.description ?? "",
46
+ tokens: tokensDe(bruto),
47
+ });
48
+ }
49
+ catch {
50
+ // Una skill ilegible no puede tumbar el catálogo entero: se queda fuera y las
51
+ // demás siguen. Que falte se ve en `xonecode skills`, que las cuenta.
52
+ }
53
+ }
54
+ return (this.cache = salida.sort((a, b) => a.nombre.localeCompare(b.nombre)));
55
+ }
56
+ cargar(nombre) {
57
+ const skillMd = join(this.raiz, nombre, "SKILL.md");
58
+ if (!existsSync(skillMd)) {
59
+ const hay = this.catalogo().map((s) => s.nombre).join(", ");
60
+ throw new Error(`no hay skill «${nombre}». Las que hay: ${hay || "(ninguna)"}`);
61
+ }
62
+ return readFileSync(skillMd, "utf8");
63
+ }
64
+ }
65
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/agent/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAY,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAGrE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAElG,wFAAwF;AACxF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IAGK;IAFrB,KAAK,GAAuB,IAAI,CAAC;IAEzC,YAA6B,OAAe,WAAW;QAA1B,SAAI,GAAJ,IAAI,CAAsB;IAAG,CAAC;IAE3D,QAAQ;QACN,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QAErD,MAAM,MAAM,GAAgB,EAAE,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;YACrD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,SAAS;YACnC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAC5C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACzC,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI,OAAO;oBAC5B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;oBACnC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC;iBACxB,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,8EAA8E;gBAC9E,sEAAsE;YACxE,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,CAAC,MAAc;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,mBAAmB,GAAG,IAAI,WAAW,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;CACF"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Convierte a TEXTO el contenido de los `ToolMessage` antes de mandárselo al modelo.
3
+ *
4
+ * ## El fallo que cierra, medido el 2026-08-30
5
+ *
6
+ * Un turno real reventaba con `Non string tool message content is not supported` tras
7
+ * 8-10 llamadas a tools. Reproducido con DOS modelos distintos —`glm-5.3-flash:cloud` y
8
+ * `qwen3.8:27b-mlx`, nube y local— y con la misma traza, lo que hacía pensar en un
9
+ * problema de langchain o de deepagents.
10
+ *
11
+ * **No lo era.** El mensaje sale de `@langchain/ollama/dist/utils.js:107`:
12
+ *
13
+ * ```js
14
+ * function convertToolMessageToOllama(message) {
15
+ * if (typeof message.content !== "string")
16
+ * throw new Error("Non string tool message content is not supported");
17
+ * ```
18
+ *
19
+ * O sea: es del PROVEEDOR, no del harness. Los dos modelos fallaban igual porque los dos
20
+ * eran Ollama. Su conversor no acepta contenido en bloques —que es lo que devuelven las
21
+ * tools de fichero de deepagents— y no lo convierte ni degrada: lanza.
22
+ *
23
+ * Y es una combinación que en este laboratorio importa: Ollama local es la vía por
24
+ * omisión (el coste manda), así que sin esto el harness no puede correr con su propio
25
+ * proveedor por defecto.
26
+ *
27
+ * ## Por qué se aplica SIEMPRE y no solo con Ollama
28
+ *
29
+ * Un `ToolMessage` de texto lo acepta cualquier proveedor, así que convertir de más no
30
+ * rompe a nadie. Condicionarlo al proveedor tendría dos costes: la rama solo se
31
+ * ejercitaría con Ollama —o sea, un camino que se rompe sin que ningún test lo note— y
32
+ * obligaría a este módulo a saber qué proveedor hay detrás, que es justo lo que los
33
+ * puertos existen para no tener que saber.
34
+ */
35
+ import { createMiddleware } from "langchain";
36
+ /** Un bloque de contenido: `{type:"text", text}` es el caso que hay que conservar. */
37
+ function textoDeBloque(bloque) {
38
+ if (typeof bloque === "string")
39
+ return bloque;
40
+ if (!bloque || typeof bloque !== "object")
41
+ return "";
42
+ const b = bloque;
43
+ if (typeof b.text === "string")
44
+ return b.text;
45
+ // Un bloque que no es de texto (una imagen, por ejemplo) no se puede meter en una
46
+ // cadena sin mentir sobre lo que es. Se declara en vez de perderlo en silencio.
47
+ return typeof b.type === "string" ? `[${b.type}]` : "";
48
+ }
49
+ /**
50
+ * El contenido de un mensaje, como cadena.
51
+ *
52
+ * `JSON.stringify` es el último recurso y no el primero: para bloques de texto daría
53
+ * `[{"type":"text","text":"…"}]`, y el modelo tendría que desenterrar el contenido de
54
+ * su propio envoltorio en cada llamada.
55
+ */
56
+ export function aTexto(contenido) {
57
+ if (typeof contenido === "string")
58
+ return contenido;
59
+ if (Array.isArray(contenido))
60
+ return contenido.map(textoDeBloque).join("");
61
+ if (contenido === null || contenido === undefined)
62
+ return "";
63
+ try {
64
+ return JSON.stringify(contenido);
65
+ }
66
+ catch {
67
+ return String(contenido);
68
+ }
69
+ }
70
+ /** ¿Es un `ToolMessage`? Se mira por las dos vías: el tipo de langchain y el campo. */
71
+ export function esMensajeDeTool(msg) {
72
+ if (!msg || typeof msg !== "object")
73
+ return false;
74
+ const m = msg;
75
+ if (m.type === "tool" || m.role === "tool")
76
+ return true;
77
+ return typeof m.tool_call_id === "string" && m.tool_call_id.length > 0;
78
+ }
79
+ /**
80
+ * Convierte los `ToolMessage` de la petición, sin tocar el historial.
81
+ *
82
+ * Va en `wrapModelCall` y no en `beforeModel` a propósito: lo que hay que arreglar es lo
83
+ * que SE MANDA, no lo que se guarda. Reescribir el estado perdería el contenido
84
+ * estructurado para todo lo demás —el rastreo, un proveedor que sí lo acepte— por un
85
+ * problema de un solo conversor.
86
+ */
87
+ export function middlewareTextoDeTool() {
88
+ return createMiddleware({
89
+ name: "TextoDeToolMiddleware",
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ wrapModelCall: (request, handler) => {
92
+ const mensajes = request?.messages;
93
+ if (!Array.isArray(mensajes))
94
+ return handler(request);
95
+ let hubo = false;
96
+ const convertidos = mensajes.map((m) => {
97
+ if (!esMensajeDeTool(m))
98
+ return m;
99
+ const msg = m;
100
+ if (typeof msg.content === "string")
101
+ return m;
102
+ hubo = true;
103
+ // Se clona: mutar el mensaje lo cambiaría también en el historial, que es
104
+ // exactamente lo que este middleware evita.
105
+ const copia = Object.create(Object.getPrototypeOf(msg));
106
+ Object.assign(copia, msg, { content: aTexto(msg.content) });
107
+ return copia;
108
+ });
109
+ return handler(hubo ? { ...request, messages: convertidos } : request);
110
+ },
111
+ });
112
+ }
113
+ //# sourceMappingURL=textoDeTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textoDeTool.js","sourceRoot":"","sources":["../../src/agent/textoDeTool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ import { readdirSync, statSync, existsSync, readFileSync } from "node:fs";
2
+ import { join, sep, resolve } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { HumanMessage } from "@langchain/core/messages";
5
+ import { Command, MemorySaver } from "@langchain/langgraph";
6
+ import { collectPending, MAX_APPROVAL_ROUNDS } from "../vendor/hitl.js";
7
+ import { aPendiente, ficheroDe, cambioDe, buildResume } from "./interrupts.js";
8
+ import { correrTurno } from "../core/turno.js";
9
+ import { tomarInstantanea } from "./instantanea.js";
10
+ import { construirAgente } from "./xoneAgent.js";
11
+ import { aEventos } from "./puente.js";
12
+ import { createTokenTracker } from "../vendor/tokenTracking.js";
13
+ /**
14
+ * Recorre la raíz y devuelve las rutas en el ESPACIO VIRTUAL del backend.
15
+ *
16
+ * Exportada porque la consola la usa para el completado de «@ficheros» (cli puede
17
+ * importar de agent; al revés no). El recorrido se hace EN CADA llamada a propósito:
18
+ * la lista no se cachea porque los ficheros cambian durante la sesión.
19
+ */
20
+ export function ficherosDelProyecto(raiz, prof = 0) {
21
+ if (prof > 4 || !existsSync(raiz))
22
+ return new Set();
23
+ const salida = new Set();
24
+ for (const entrada of readdirSync(raiz)) {
25
+ if (entrada === "node_modules" || entrada === ".git")
26
+ continue;
27
+ const ruta = join(raiz, entrada);
28
+ try {
29
+ if (statSync(ruta).isDirectory()) {
30
+ // La recursión devuelve rutas relativas al SUBDIRECTORIO: sin recoserle el
31
+ // nombre, «app/Clientes.xne» saldría como «/Clientes.xne» y el Set dejaría de
32
+ // responder por las vistas aplanadas ANIDADAS (este universo es el que consulta
33
+ // `esVistaAplanada`).
34
+ for (const f of ficherosDelProyecto(ruta, prof + 1))
35
+ salida.add(`/${entrada}${f}`);
36
+ }
37
+ else {
38
+ salida.add("/" + ruta.slice(raiz.length + 1).split(sep).join("/"));
39
+ }
40
+ }
41
+ catch {
42
+ // Un enlace roto o un permiso no tumba el arranque; el agente vivirá sin ese fichero.
43
+ }
44
+ }
45
+ return salida;
46
+ }
47
+ /**
48
+ * Abre una sesión real: agente, checkpointer, hilo y tracker se construyen UNA vez aquí, y
49
+ * viven en el cierre. Todo lo que sobreviva al primer turno tiene que salir de este cierre:
50
+ * reconstruir el agente fuera (o un `MemorySaver` nuevo por llamada) tiraría la conversación.
51
+ */
52
+ export async function abrirSesionReal(opciones) {
53
+ const { raiz, entorno } = opciones;
54
+ const checkpointer = new MemorySaver();
55
+ const tracker = createTokenTracker();
56
+ let modelos = opciones.modelos;
57
+ let hilo = `xonecode-${randomUUID()}`;
58
+ const construir = async () => construirAgente({
59
+ raiz,
60
+ ficheros: ficherosDelProyecto(raiz),
61
+ modelos,
62
+ skills: opciones.skills,
63
+ checkpointer: checkpointer,
64
+ tracker,
65
+ });
66
+ let agente = await construir();
67
+ /**
68
+ * Los pendientes de aprobación, del ESTADO y no del resultado del stream.
69
+ *
70
+ * Se leen los crudos (`collectPending`) y no solo los traducidos, porque de ellos sale la
71
+ * RUTA del fichero que se va a tocar (`ficheroDe`). Los argumentos NO se publican
72
+ * —`write_file` lleva el contenido entero—, pero aprobar a ciegas es peor que no aprobar,
73
+ * así que la ruta sí. Una sola llamada a `getState` para las dos cosas.
74
+ */
75
+ const leerPendientes = async () => {
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
+ const crudos = collectPending(await agente.getState({
78
+ configurable: { thread_id: hilo },
79
+ }));
80
+ const ficheros = new Map();
81
+ const diffs = new Map();
82
+ for (const c of crudos) {
83
+ const f = ficheroDe(c);
84
+ if (f)
85
+ ficheros.set(c.id, f);
86
+ // El ANTES es el disco: el interrupt pausa ANTES de escribir. La ruta viene del
87
+ // backend, que es relativo a la raíz del proyecto — y si no está en el disco, el
88
+ // fichero es nuevo y su «antes» es la cadena vacía, no un error.
89
+ const vista = cambioDe(c, (ruta) => {
90
+ try {
91
+ return readFileSync(resolve(raiz, ruta), "utf8");
92
+ }
93
+ catch {
94
+ return "";
95
+ }
96
+ });
97
+ if (vista)
98
+ diffs.set(c.id, vista.lineas);
99
+ }
100
+ return { lista: crudos.map(aPendiente), ficheros, diffs };
101
+ };
102
+ /**
103
+ * Un turno: foto del ANTES → stream con bucle de aprobación → diff contra esa foto.
104
+ *
105
+ * La foto es POR TURNO, no por sesión: con una sola, el diff del turno 3 incluiría lo que
106
+ * escribió el turno 1.
107
+ */
108
+ const turno = async (peticion, piel) => {
109
+ const instantanea = await tomarInstantanea(raiz, entorno.git);
110
+ let payload = { messages: [new HumanMessage(peticion)] };
111
+ let bitacora = null;
112
+ let ronda = 0;
113
+ // El bucle de aprobación, tal como está en `correrReal` (`cli/run.ts`): una pausa
114
+ // TERMINA la ronda, el interrupt queda en el estado, y se reanuda con un `Command`
115
+ // con las decisiones — también con rejects, que si no se resumen dejan el interrupt
116
+ // colgado para siempre y el modelo nunca llega a saber que se rechazó.
117
+ let cortadoPorTope = false;
118
+ while (true) {
119
+ ronda += 1;
120
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
+ const stream = await agente.stream(payload, {
122
+ configurable: { thread_id: hilo },
123
+ streamMode: ["updates", "messages"],
124
+ subgraphs: true,
125
+ });
126
+ bitacora = await correrTurno(aEventos(stream, async () => (await leerPendientes()).lista), piel, {
127
+ avisos: (b) => (b.corrio("verify") ? [] : ["⚠ el verificador no ha corrido en este turno"]),
128
+ });
129
+ const { lista, ficheros, diffs } = await leerPendientes();
130
+ if (lista.length === 0)
131
+ break;
132
+ // El tope existe porque un modelo que insiste tras cada rechazo convierte esto en un
133
+ // ciclo automático de ~200k tokens por ronda (medido en da04). Sin resumir: nada se
134
+ // aplica, pero el interrupt queda en el estado.
135
+ if (ronda >= MAX_APPROVAL_ROUNDS) {
136
+ piel.linea(`\n⚠ tope de ${MAX_APPROVAL_ROUNDS} rondas de aprobación agotado.`);
137
+ piel.linea(` quedaban ${lista.length} sin resolver, y NO se han aplicado.`);
138
+ cortadoPorTope = true;
139
+ break;
140
+ }
141
+ if (!opciones.pedirAprobacion) {
142
+ piel.linea(`\n⏸ ${lista.length} escritura(s) piden aprobación, y no hay quién apruebe.`);
143
+ piel.linea(" Nada se ha aprobado y nada se ha aplicado.");
144
+ break;
145
+ }
146
+ const decisiones = await opciones.pedirAprobacion(lista, ficheros, diffs);
147
+ payload = new Command({ resume: buildResume(decisiones) });
148
+ }
149
+ // El diff contra la foto de ESTE turno. Un turno que no tocó nada TIENE que verse igual.
150
+ const cambios = await instantanea.cambios();
151
+ // `cortadoPorTope` viaja en el retorno y no en la bitácora porque es lo que decide el
152
+ // CÓDIGO DE SALIDA de quien invoca: un turno que se quedó con escrituras sin resolver
153
+ // no es un éxito, y CI no puede leerlo como tal.
154
+ return { bitacora: bitacora, cambios, cortadoPorTope };
155
+ };
156
+ return {
157
+ turno,
158
+ /** Para `/modelo`: agente nuevo con los mismos hilo, checkpointer y tracker. */
159
+ async cambiarModelos(nuevos) {
160
+ modelos = nuevos;
161
+ agente = await construir();
162
+ },
163
+ /** Para `/nuevo`: solo cambia el hilo. El agente no se reconstruye. */
164
+ nuevoHilo(id) {
165
+ hilo = id ?? `xonecode-${randomUUID()}`;
166
+ },
167
+ tracker,
168
+ get hilo() {
169
+ return hilo;
170
+ },
171
+ };
172
+ }
173
+ //# sourceMappingURL=turnoReal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnoReal.js","sourceRoot":"","sources":["../../src/agent/turnoReal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const ejecutar = promisify(execFile);
4
+ /** La forma que emite `xone-simulator validate --json` (xone-linter 1.4.0). */
5
+ /**
6
+ * Cuando el simulador no pudo ni empezar. **Medido**: ante una ruta que no existe devuelve
7
+ * `{"success": false, "error": "No existe el directorio del proyecto: …"}` — sin `issues`,
8
+ * y **saliendo con código 0**, así que no lo caza ningún `catch` del proceso.
9
+ *
10
+ * Es un fallo del ENTORNO, no del proyecto, y por eso es una excepción y no un informe en
11
+ * rojo: un informe rojo dice «tu proyecto tiene errores», que aquí sería mentira.
12
+ */
13
+ export class ErrorDelSimulador extends Error {
14
+ }
15
+ /**
16
+ * De la salida del simulador al informe del harness. PURA: sin subprocesos.
17
+ *
18
+ * Separada de quien invoca el binario para poder probar la traducción con el fichero de
19
+ * `__oro__/` — es el patrón del puerto aplicado dentro del puerto, igual que el harness
20
+ * Python separa la función que recibe la sesión ya lista del puerto que la construye.
21
+ */
22
+ export function aInforme(salida) {
23
+ // La forma de fallo no trae `issues`. Sin esta guarda, `.map` de `undefined` reventaba
24
+ // con un TypeError que le llegaba al usuario TAL CUAL —«Cannot read properties of
25
+ // undefined (reading 'map')»— tapando el mensaje que el simulador ya daba claro.
26
+ if (!Array.isArray(salida.issues)) {
27
+ throw new ErrorDelSimulador(salida.error ?? "el simulador no devolvió hallazgos ni error");
28
+ }
29
+ const hallazgos = salida.issues.map((i) => ({
30
+ code: i.code,
31
+ severidad: i.severity,
32
+ mensaje: i.message,
33
+ fichero: i.location?.file ?? i.file,
34
+ linea: i.location?.line,
35
+ columna: i.location?.column,
36
+ }));
37
+ return { verde: salida.success, hallazgos };
38
+ }
39
+ /**
40
+ * El verificador real. NO lleva la marca `ES_DOBLE`: es de verdad, y `describe()` lo dirá.
41
+ *
42
+ * `validate` sale con código != 0 cuando encuentra errores, así que un fallo del proceso
43
+ * NO es un fallo del harness: es el resultado. Se distingue por si hubo JSON parseable —
44
+ * confundir las dos cosas es el patrón «fallo del proyecto != fallo del harness».
45
+ */
46
+ export class SimuladorVerifier {
47
+ binario;
48
+ constructor(binario = "xone-simulator") {
49
+ this.binario = binario;
50
+ }
51
+ async verificar(rutaProyecto) {
52
+ let stdout;
53
+ try {
54
+ ({ stdout } = await ejecutar(this.binario, ["validate", rutaProyecto, "--json"]));
55
+ }
56
+ catch (e) {
57
+ const conSalida = e;
58
+ if (!conSalida.stdout)
59
+ throw e; // el binario no está, o reventó de verdad
60
+ stdout = conSalida.stdout; // salió != 0 porque HAY hallazgos: es el resultado
61
+ }
62
+ return aInforme(JSON.parse(stdout));
63
+ }
64
+ }
65
+ //# sourceMappingURL=verificador.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verificador.js","sourceRoot":"","sources":["../../src/agent/verificador.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAErC,+EAA+E;AAC/E;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAiB/C;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,MAA0B;IACjD,uFAAuF;IACvF,kFAAkF;IAClF,iFAAiF;IACjF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,iBAAiB,CAAC,MAAM,CAAC,KAAK,IAAI,6CAA6C,CAAC,CAAC;IAC7F,CAAC;IACD,MAAM,SAAS,GAAe,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,QAAiC;QAC9C,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI;QACnC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI;QACvB,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM;KAC5B,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IACC;IAA7B,YAA6B,UAAU,gBAAgB;QAA1B,YAAO,GAAP,OAAO,CAAmB;IAAG,CAAC;IAE3D,KAAK,CAAC,SAAS,CAAC,YAAoB;QAClC,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACpF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,SAAS,GAAG,CAAwB,CAAC;YAC3C,IAAI,CAAC,SAAS,CAAC,MAAM;gBAAE,MAAM,CAAC,CAAC,CAAC,0CAA0C;YAC1E,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAM,mDAAmD;QACrF,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAuB,CAAC,CAAC;IAC5D,CAAC;CACF"}