xonecode 0.5.0 → 0.6.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 (266) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +32 -0
  3. package/apps/web/dist/assets/index-DBZTodio.js +477 -0
  4. package/apps/web/dist/assets/{index-BB3SamhR.css → index-rqecK6s2.css} +1 -1
  5. package/apps/web/dist/assets/{php-D_2--9WK.js → php-BBij3Lhc.js} +1 -1
  6. package/apps/web/dist/assets/{ruby-DSHSDbk1.js → ruby-Dq2YEaLo.js} +1 -1
  7. package/apps/web/dist/index.html +2 -2
  8. package/dist/agent/cloudstudio/cloudstudioClient.js.map +1 -0
  9. package/dist/agent/{cloudstudioMcp.js → cloudstudio/cloudstudioMcp.js} +5 -5
  10. package/dist/agent/cloudstudio/cloudstudioMcp.js.map +1 -0
  11. package/dist/agent/{descarga.js → cloudstudio/descarga.js} +3 -3
  12. package/dist/agent/cloudstudio/descarga.js.map +1 -0
  13. package/dist/agent/cloudstudio/manifiesto.js.map +1 -0
  14. package/dist/agent/{subida.js → cloudstudio/subida.js} +3 -3
  15. package/dist/agent/cloudstudio/subida.js.map +1 -0
  16. package/dist/agent/{zip.js → cloudstudio/zip.js} +1 -1
  17. package/dist/agent/cloudstudio/zip.js.map +1 -0
  18. package/dist/agent/{authEnDisco.js → config/authEnDisco.js} +3 -3
  19. package/dist/agent/config/authEnDisco.js.map +1 -0
  20. package/dist/agent/{catalogoModelos.js → config/catalogoModelos.js} +2 -1
  21. package/dist/agent/config/catalogoModelos.js.map +1 -0
  22. package/dist/agent/{configEnDisco.js → config/configEnDisco.js} +6 -6
  23. package/dist/agent/config/configEnDisco.js.map +1 -0
  24. package/dist/agent/{crearProyecto.js → config/crearProyecto.js} +2 -2
  25. package/dist/agent/config/crearProyecto.js.map +1 -0
  26. package/dist/agent/config/entorno.js.map +1 -0
  27. package/dist/agent/config/gemini.js.map +1 -0
  28. package/dist/agent/{modelos.js → config/modelos.js} +17 -3
  29. package/dist/agent/config/modelos.js.map +1 -0
  30. package/dist/agent/{modelosDeMotor.js → config/modelosDeMotor.js} +1 -1
  31. package/dist/agent/config/modelosDeMotor.js.map +1 -0
  32. package/dist/agent/{persona.js → config/persona.js} +1 -1
  33. package/dist/agent/config/persona.js.map +1 -0
  34. package/dist/agent/{settingsEnDisco.js → config/settingsEnDisco.js} +2 -2
  35. package/dist/agent/config/settingsEnDisco.js.map +1 -0
  36. package/dist/agent/{versionEnDisco.js → config/versionEnDisco.js} +8 -4
  37. package/dist/agent/config/versionEnDisco.js.map +1 -0
  38. package/dist/agent/dispositivos/arranqueDeEmulador.js +146 -0
  39. package/dist/agent/dispositivos/arranqueDeEmulador.js.map +1 -0
  40. package/dist/agent/{dispositivosEnMaquina.js → dispositivos/dispositivosEnMaquina.js} +93 -6
  41. package/dist/agent/dispositivos/dispositivosEnMaquina.js.map +1 -0
  42. package/dist/agent/dispositivos/hotswap.js.map +1 -0
  43. package/dist/agent/dispositivos/instalacionEnMaquina.js.map +1 -0
  44. package/dist/agent/{lanzamientoEnMaquina.js → dispositivos/lanzamientoEnMaquina.js} +1 -1
  45. package/dist/agent/dispositivos/lanzamientoEnMaquina.js.map +1 -0
  46. package/dist/agent/{paqueteDelProyecto.js → dispositivos/paqueteDelProyecto.js} +5 -5
  47. package/dist/agent/dispositivos/paqueteDelProyecto.js.map +1 -0
  48. package/dist/agent/dispositivos/procesosEnMaquina.js.map +1 -0
  49. package/dist/agent/{arbolDeProyecto.js → grafo/arbolDeProyecto.js} +2 -2
  50. package/dist/agent/grafo/arbolDeProyecto.js.map +1 -0
  51. package/dist/agent/{artefactosEnDisco.js → grafo/artefactosEnDisco.js} +2 -2
  52. package/dist/agent/grafo/artefactosEnDisco.js.map +1 -0
  53. package/dist/agent/{busquedaRegex.js → grafo/busquedaRegex.js} +41 -1
  54. package/dist/agent/grafo/busquedaRegex.js.map +1 -0
  55. package/dist/agent/grafo/excluirTools.js +82 -0
  56. package/dist/agent/grafo/excluirTools.js.map +1 -0
  57. package/dist/agent/{memoriaDeProyecto.js → grafo/memoriaDeProyecto.js} +1 -1
  58. package/dist/agent/grafo/memoriaDeProyecto.js.map +1 -0
  59. package/dist/agent/grafo/navegacionXone.js +198 -0
  60. package/dist/agent/grafo/navegacionXone.js.map +1 -0
  61. package/dist/agent/{perfiles.js → grafo/perfiles.js} +51 -8
  62. package/dist/agent/grafo/perfiles.js.map +1 -0
  63. package/dist/agent/{proyecto.js → grafo/proyecto.js} +207 -24
  64. package/dist/agent/grafo/proyecto.js.map +1 -0
  65. package/dist/agent/grafo/skills.js +393 -0
  66. package/dist/agent/grafo/skills.js.map +1 -0
  67. package/dist/agent/{xoneAgent.js → grafo/xoneAgent.js} +196 -67
  68. package/dist/agent/grafo/xoneAgent.js.map +1 -0
  69. package/dist/agent/navegacion/indiceEnDisco.js +21 -0
  70. package/dist/agent/navegacion/indiceEnDisco.js.map +1 -0
  71. package/dist/agent/navegacion/modeloDeProyecto.js +228 -0
  72. package/dist/agent/navegacion/modeloDeProyecto.js.map +1 -0
  73. package/dist/agent/raizDelPaquete.js +56 -0
  74. package/dist/agent/raizDelPaquete.js.map +1 -0
  75. package/dist/agent/{checkpointer.js → sesiones/checkpointer.js} +2 -2
  76. package/dist/agent/sesiones/checkpointer.js.map +1 -0
  77. package/dist/agent/sesiones/git.js.map +1 -0
  78. package/dist/agent/{gitSync.js → sesiones/gitSync.js} +3 -3
  79. package/dist/agent/sesiones/gitSync.js.map +1 -0
  80. package/dist/agent/{sesionGit.js → sesiones/sesionGit.js} +2 -2
  81. package/dist/agent/sesiones/sesionGit.js.map +1 -0
  82. package/dist/agent/{agentesEnDisco.js → subagentes/agentesEnDisco.js} +304 -86
  83. package/dist/agent/subagentes/agentesEnDisco.js.map +1 -0
  84. package/dist/agent/subagentes/consumoExterno.js.map +1 -0
  85. package/dist/agent/subagentes/escrituraDeCodex.js.map +1 -0
  86. package/dist/agent/{escrituraDeOpencode.js → subagentes/escrituraDeOpencode.js} +1 -1
  87. package/dist/agent/subagentes/escrituraDeOpencode.js.map +1 -0
  88. package/dist/agent/{escrituraExterna.js → subagentes/escrituraExterna.js} +6 -6
  89. package/dist/agent/subagentes/escrituraExterna.js.map +1 -0
  90. package/dist/agent/subagentes/subagenteCodex.js.map +1 -0
  91. package/dist/agent/subagentes/subagenteExterno.js.map +1 -0
  92. package/dist/agent/subagentes/subagenteOpencode.js.map +1 -0
  93. package/dist/agent/{aumentador.js → tareas/aumentador.js} +2 -2
  94. package/dist/agent/tareas/aumentador.js.map +1 -0
  95. package/dist/agent/{juezDeTarea.js → tareas/juezDeTarea.js} +5 -5
  96. package/dist/agent/tareas/juezDeTarea.js.map +1 -0
  97. package/dist/agent/{tareasEnDisco.js → tareas/tareasEnDisco.js} +4 -4
  98. package/dist/agent/tareas/tareasEnDisco.js.map +1 -0
  99. package/dist/agent/turno/diagnosticoDeTools.js.map +1 -0
  100. package/dist/agent/{guionizado.js → turno/guionizado.js} +1 -1
  101. package/dist/agent/turno/guionizado.js.map +1 -0
  102. package/dist/agent/turno/informeDeTraza.js +222 -0
  103. package/dist/agent/turno/informeDeTraza.js.map +1 -0
  104. package/dist/agent/turno/inspectorDePrompt.js +205 -0
  105. package/dist/agent/turno/inspectorDePrompt.js.map +1 -0
  106. package/dist/agent/{instantanea.js → turno/instantanea.js} +7 -2
  107. package/dist/agent/turno/instantanea.js.map +1 -0
  108. package/dist/agent/{interrupts.js → turno/interrupts.js} +2 -2
  109. package/dist/agent/turno/interrupts.js.map +1 -0
  110. package/dist/agent/turno/mensajes.js.map +1 -0
  111. package/dist/agent/turno/normalizar.js.map +1 -0
  112. package/dist/agent/{puente.js → turno/puente.js} +47 -3
  113. package/dist/agent/turno/puente.js.map +1 -0
  114. package/dist/agent/turno/resumenDeContexto.js +176 -0
  115. package/dist/agent/turno/resumenDeContexto.js.map +1 -0
  116. package/dist/agent/{resumenDeTool.js → turno/resumenDeTool.js} +15 -0
  117. package/dist/agent/turno/resumenDeTool.js.map +1 -0
  118. package/dist/agent/turno/textoDeTool.js.map +1 -0
  119. package/dist/agent/{turnoReal.js → turno/turnoReal.js} +38 -14
  120. package/dist/agent/turno/turnoReal.js.map +1 -0
  121. package/dist/agent/turno/verificador.js.map +1 -0
  122. package/dist/cli/config.js +1 -1
  123. package/dist/cli/config.js.map +1 -1
  124. package/dist/cli/consola.js +9 -9
  125. package/dist/cli/consola.js.map +1 -1
  126. package/dist/cli/describe.js +2 -2
  127. package/dist/cli/describe.js.map +1 -1
  128. package/dist/cli/doctor.js +1 -1
  129. package/dist/cli/doctor.js.map +1 -1
  130. package/dist/cli/fuentesDeDisco.js +29 -0
  131. package/dist/cli/fuentesDeDisco.js.map +1 -0
  132. package/dist/cli/main.js +37 -28
  133. package/dist/cli/main.js.map +1 -1
  134. package/dist/cli/run.js +32 -10
  135. package/dist/cli/run.js.map +1 -1
  136. package/dist/cli/traza.js +48 -0
  137. package/dist/cli/traza.js.map +1 -0
  138. package/dist/cli/tui/correrTui.js +4 -4
  139. package/dist/cli/tui/correrTui.js.map +1 -1
  140. package/dist/cli/verify.js +1 -1
  141. package/dist/cli/verify.js.map +1 -1
  142. package/dist/core/actos.js +1 -1
  143. package/dist/core/adjuntos.js +2 -2
  144. package/dist/core/agentes.js +145 -7
  145. package/dist/core/agentes.js.map +1 -1
  146. package/dist/core/artefactos.js +4 -4
  147. package/dist/core/config.js +1 -1
  148. package/dist/core/contextos.js +12 -1
  149. package/dist/core/contextos.js.map +1 -1
  150. package/dist/core/descargas.js +1 -1
  151. package/dist/core/dispositivos.js +53 -3
  152. package/dist/core/dispositivos.js.map +1 -1
  153. package/dist/core/esqueleto.js +1 -1
  154. package/dist/core/modelos.js +16 -3
  155. package/dist/core/modelos.js.map +1 -1
  156. package/dist/core/navegacion.js +134 -0
  157. package/dist/core/navegacion.js.map +1 -0
  158. package/dist/core/notify.js +5 -0
  159. package/dist/core/notify.js.map +1 -1
  160. package/dist/core/planDeSubida.js +1 -1
  161. package/dist/core/settings.js +2 -2
  162. package/dist/core/shellDeAgente.js +99 -0
  163. package/dist/core/shellDeAgente.js.map +1 -0
  164. package/dist/core/skills.js +158 -0
  165. package/dist/core/skills.js.map +1 -0
  166. package/dist/core/zipDeSkill.js +107 -0
  167. package/dist/core/zipDeSkill.js.map +1 -0
  168. package/dist/vendor/sqliteSaver.js +389 -0
  169. package/dist/vendor/sqliteSaver.js.map +1 -0
  170. package/dist/web/servidor/arranque.js +531 -47
  171. package/dist/web/servidor/arranque.js.map +1 -1
  172. package/dist/web/servidor/corredorDeTareas.js +3 -3
  173. package/dist/web/servidor/corredorDeTareas.js.map +1 -1
  174. package/dist/web/servidor/sesiones.js +4 -4
  175. package/dist/web/servidor/transporte.js +1 -1
  176. package/dist/web/servidor/transporte.js.map +1 -1
  177. package/dist/web/servidor/vestibulo.js +7 -7
  178. package/dist/web/servidor/vestibulo.js.map +1 -1
  179. package/package.json +9 -5
  180. package/skills/archify/SKILL.md +25 -2
  181. package/skills/artifacts-builder/SKILL.md +23 -0
  182. package/skills/xone-hotswap/SKILL.md +74 -0
  183. package/skills/xone-hotswap/scripts/xone-arrancar-ios +85 -0
  184. package/skills/xone-hotswap/scripts/xone-desplegar-android +411 -0
  185. package/skills/xone-hotswap/scripts/xone-hotswap +171 -0
  186. package/skills/xone-hotswap/scripts/xone-log-android +102 -0
  187. package/skills/xone-hotswap/scripts/xone-reiniciar-android +104 -0
  188. package/apps/web/dist/assets/index-CFYAoHdw.js +0 -477
  189. package/dist/agent/agentesEnDisco.js.map +0 -1
  190. package/dist/agent/arbolDeProyecto.js.map +0 -1
  191. package/dist/agent/artefactosEnDisco.js.map +0 -1
  192. package/dist/agent/aumentador.js.map +0 -1
  193. package/dist/agent/authEnDisco.js.map +0 -1
  194. package/dist/agent/busquedaRegex.js.map +0 -1
  195. package/dist/agent/catalogoModelos.js.map +0 -1
  196. package/dist/agent/checkpointer.js.map +0 -1
  197. package/dist/agent/cloudstudioClient.js.map +0 -1
  198. package/dist/agent/cloudstudioMcp.js.map +0 -1
  199. package/dist/agent/configEnDisco.js.map +0 -1
  200. package/dist/agent/consumoExterno.js.map +0 -1
  201. package/dist/agent/crearProyecto.js.map +0 -1
  202. package/dist/agent/descarga.js.map +0 -1
  203. package/dist/agent/diagnosticoDeTools.js.map +0 -1
  204. package/dist/agent/dispositivosEnMaquina.js.map +0 -1
  205. package/dist/agent/entorno.js.map +0 -1
  206. package/dist/agent/escrituraDeCodex.js.map +0 -1
  207. package/dist/agent/escrituraDeOpencode.js.map +0 -1
  208. package/dist/agent/escrituraExterna.js.map +0 -1
  209. package/dist/agent/gemini.js.map +0 -1
  210. package/dist/agent/git.js.map +0 -1
  211. package/dist/agent/gitSync.js.map +0 -1
  212. package/dist/agent/guionizado.js.map +0 -1
  213. package/dist/agent/hotswap.js.map +0 -1
  214. package/dist/agent/instalacionEnMaquina.js.map +0 -1
  215. package/dist/agent/instantanea.js.map +0 -1
  216. package/dist/agent/interrupts.js.map +0 -1
  217. package/dist/agent/juezDeTarea.js.map +0 -1
  218. package/dist/agent/lanzamientoEnMaquina.js.map +0 -1
  219. package/dist/agent/manifiesto.js.map +0 -1
  220. package/dist/agent/memoriaDeProyecto.js.map +0 -1
  221. package/dist/agent/mensajes.js.map +0 -1
  222. package/dist/agent/modelos.js.map +0 -1
  223. package/dist/agent/modelosDeMotor.js.map +0 -1
  224. package/dist/agent/normalizar.js.map +0 -1
  225. package/dist/agent/paqueteDelProyecto.js.map +0 -1
  226. package/dist/agent/perfiles.js.map +0 -1
  227. package/dist/agent/persona.js.map +0 -1
  228. package/dist/agent/procesosEnMaquina.js.map +0 -1
  229. package/dist/agent/proyecto.js.map +0 -1
  230. package/dist/agent/puente.js.map +0 -1
  231. package/dist/agent/resumenDeContexto.js +0 -30
  232. package/dist/agent/resumenDeContexto.js.map +0 -1
  233. package/dist/agent/resumenDeTool.js.map +0 -1
  234. package/dist/agent/sesionGit.js.map +0 -1
  235. package/dist/agent/settingsEnDisco.js.map +0 -1
  236. package/dist/agent/skills.js +0 -65
  237. package/dist/agent/skills.js.map +0 -1
  238. package/dist/agent/subagenteCodex.js.map +0 -1
  239. package/dist/agent/subagenteExterno.js.map +0 -1
  240. package/dist/agent/subagenteOpencode.js.map +0 -1
  241. package/dist/agent/subida.js.map +0 -1
  242. package/dist/agent/tareasEnDisco.js.map +0 -1
  243. package/dist/agent/textoDeTool.js.map +0 -1
  244. package/dist/agent/turnoReal.js.map +0 -1
  245. package/dist/agent/verificador.js.map +0 -1
  246. package/dist/agent/versionEnDisco.js.map +0 -1
  247. package/dist/agent/xoneAgent.js.map +0 -1
  248. package/dist/agent/zip.js.map +0 -1
  249. /package/dist/agent/{cloudstudioClient.js → cloudstudio/cloudstudioClient.js} +0 -0
  250. /package/dist/agent/{manifiesto.js → cloudstudio/manifiesto.js} +0 -0
  251. /package/dist/agent/{entorno.js → config/entorno.js} +0 -0
  252. /package/dist/agent/{gemini.js → config/gemini.js} +0 -0
  253. /package/dist/agent/{hotswap.js → dispositivos/hotswap.js} +0 -0
  254. /package/dist/agent/{instalacionEnMaquina.js → dispositivos/instalacionEnMaquina.js} +0 -0
  255. /package/dist/agent/{procesosEnMaquina.js → dispositivos/procesosEnMaquina.js} +0 -0
  256. /package/dist/agent/{git.js → sesiones/git.js} +0 -0
  257. /package/dist/agent/{consumoExterno.js → subagentes/consumoExterno.js} +0 -0
  258. /package/dist/agent/{escrituraDeCodex.js → subagentes/escrituraDeCodex.js} +0 -0
  259. /package/dist/agent/{subagenteCodex.js → subagentes/subagenteCodex.js} +0 -0
  260. /package/dist/agent/{subagenteExterno.js → subagentes/subagenteExterno.js} +0 -0
  261. /package/dist/agent/{subagenteOpencode.js → subagentes/subagenteOpencode.js} +0 -0
  262. /package/dist/agent/{diagnosticoDeTools.js → turno/diagnosticoDeTools.js} +0 -0
  263. /package/dist/agent/{mensajes.js → turno/mensajes.js} +0 -0
  264. /package/dist/agent/{normalizar.js → turno/normalizar.js} +0 -0
  265. /package/dist/agent/{textoDeTool.js → turno/textoDeTool.js} +0 -0
  266. /package/dist/agent/{verificador.js → turno/verificador.js} +0 -0
@@ -1,15 +1,19 @@
1
1
  import { createDeepAgent, createFilesystemMiddleware } from "deepagents";
2
- import { promptDeAgente, repartirSkills } from "../core/agentes.js";
2
+ import { MAPA_DEL_PROYECTO, promptDeAgente, repartirSkills } from "../../core/agentes.js";
3
3
  import { RunnableLambda } from "@langchain/core/runnables";
4
4
  import { AIMessage } from "@langchain/core/messages";
5
5
  import { MemorySaver } from "@langchain/langgraph";
6
- import { backendDeAgente } from "./proyecto.js";
7
- import { permisosDe, hitlDe } from "./perfiles.js";
6
+ import { backendDeAgente, entornoDeLaShellDelProyecto } from "./proyecto.js";
7
+ import { permisosDe, hitlDe, montajeDeFicheros, puedeEjecutar } from "./perfiles.js";
8
8
  import { crearBusquedaRegex } from "./busquedaRegex.js";
9
- import { inventarioDelProyecto } from "./escrituraExterna.js";
10
- import { middlewareTextoDeTool } from "./textoDeTool.js";
11
- import { resumenDeContexto } from "./resumenDeContexto.js";
12
- import { createTokenTrackingMiddleware, } from "../vendor/tokenTracking.js";
9
+ import { crearNavegacionXone } from "./navegacionXone.js";
10
+ import { indiceEnDisco } from "../navegacion/indiceEnDisco.js";
11
+ import { inventarioDelProyecto } from "../subagentes/escrituraExterna.js";
12
+ import { middlewareTextoDeTool } from "../turno/textoDeTool.js";
13
+ import { resumenConEncargo, topeDeLlamadas, topeDeTools } from "../turno/resumenDeContexto.js";
14
+ import { inspectorDePrompt } from "../turno/inspectorDePrompt.js";
15
+ import { excluirTools, toolsQueNoUsa } from "./excluirTools.js";
16
+ import { createTokenTrackingMiddleware, } from "../../vendor/tokenTracking.js";
13
17
  /**
14
18
  * El prompt del orquestador, GENERADO a partir de los subagentes que hay.
15
19
  *
@@ -36,17 +40,32 @@ export function promptOrquestador(agentes) {
36
40
  const hay = (n) => agentes.some((a) => a.nombre === n);
37
41
  return [
38
42
  "Eres el orquestador de un harness de desarrollo para la plataforma XOne.",
43
+ // El mapa lo ve él TAMBIÉN, y no solo los especialistas: desde que contesta lo que puede
44
+ // en vez de delegarlo todo, es quien más lo necesita.
45
+ MAPA_DEL_PROYECTO,
39
46
  // Decía «NO tienes herramientas», y era falso: tiene las seis de fichero. Ahora son de
40
47
  // SOLO LECTURA (`PERFIL_DEL_ORQUESTADOR`), así que la frase dice lo que de verdad puede.
41
- "NO tienes herramientas para MODIFICAR nada: tu único trabajo es entender la petición y delegar.",
48
+ //
49
+ // Y decía «tu único trabajo es delegar», que era falso por el otro lado y CARO: medido con
50
+ // el banco (`docs/bancos/2026-09-17-base.json`), la misma pregunta de estructura costaba
51
+ // 9.462 tokens contestada aquí y 38.198 delegada, con la MISMA respuesta buena. Delegar es
52
+ // un viaje entero de ida y vuelta con el prompt de un especialista detrás, así que para lo
53
+ // que se resuelve con un `grep` no compra nada. La regla es explícita en las dos
54
+ // direcciones porque «puedes leer» a secas no le quitaba la orden de delegar siempre.
55
+ "NO tienes herramientas para MODIFICAR nada, pero SÍ para LEER y BUSCAR.",
56
+ "Si la pregunta se contesta mirando el proyecto —dónde se declara algo, qué colecciones hay,",
57
+ "qué valor tiene un atributo, qué fichero incluye a cuál—, CONTÉSTALA TÚ: busca con `grep` y",
58
+ "lee lo justo. Delegar cuesta varias veces más y no la contesta mejor.",
59
+ "Delega cuando haya que ESCRIBIR ficheros (tú no puedes), cuando el encargo tenga varios",
60
+ "pasos, o cuando haga falta el criterio de un especialista.",
42
61
  agentes.length === 0
43
62
  ? "AVISO: ahora mismo no hay ningún especialista dado de alta, así que no puedes delegar en nadie. Dilo en vez de intentar resolverlo tú."
44
63
  : `Los especialistas disponibles son: ${agentes.map((a) => a.nombre).join(", ")}. Elige por su descripción.`,
45
- hay("planner") && hay("mockup")
46
- ? "Para diagramas o esquemas de la app, delega en `mockup`; si deben reflejar el código real, encarga PRIMERO el análisis a `planner` y usa su resultado antes de dibujar."
64
+ hay("analyst-xone") && hay("designer-xone")
65
+ ? "Para diagramas o esquemas de la app, delega en `designer-xone`; si deben reflejar el código real, encarga PRIMERO el análisis a `analyst-xone` y usa su resultado antes de dibujar."
47
66
  : "",
48
67
  "Los especialistas no comparten el transcript: al encadenarlos, incluye en la descripción",
49
- "de la siguiente `task` un bloque `HANDOFF DE PLANNER` compacto con los hechos verificados,",
68
+ "de la siguiente `task` un bloque `HANDOFF DE ANÁLISIS` compacto con los hechos verificados,",
50
69
  "rutas/evidencias y lagunas. No pidas al siguiente especialista redescubrir esos hechos.",
51
70
  "Cuando varias tareas sean independientes, delégalas EN EL MISMO mensaje para",
52
71
  "que corran a la vez.",
@@ -61,13 +80,23 @@ export function promptOrquestador(agentes) {
61
80
  * No crean herramientas ni rebajan permisos: hacen explícito el destino correcto
62
81
  * para que una skill no confunda su propia carpeta de instrucciones con la salida.
63
82
  */
83
+ /**
84
+ * **`read_file` NO está aquí, y es deliberado.**
85
+ *
86
+ * Una descripción propia REEMPLAZA la de la librería, no se suma a ella, así que la nuestra
87
+ * —que solo hablaba de coste— borraba tres cosas que deepagents ya dice y que no son nuestras
88
+ * de decir: que la salida lleva una cabecera de formato **que no hay que reinyectar al
89
+ * editar** (eso es CORRECCIÓN, no ahorro), que conviene pedir varias lecturas en una misma
90
+ * respuesta, y que un resultado grande se descarga a `/large_tool_results/` y se pagina desde
91
+ * ahí. Medido al comparar dos parches suyos: entre `1.13.2` y `1.13.5` ese formato CAMBIÓ
92
+ * —de prefijos de número de línea a una cabecera `@@ … @@`— y con él la advertencia. Una copia
93
+ * nuestra habría quedado describiendo un formato que ya no existe, sin un error que leer.
94
+ *
95
+ * La regla: lo que describe la TOOL es de la librería y se actualiza con ella; lo que decimos
96
+ * nosotros es cómo QUEREMOS usarla, y eso vive en el prompt del especialista
97
+ * (`core/agentes.ts#promptDeAgente`), donde no compite con nada.
98
+ */
64
99
  export const DESCRIPCIONES_FICHEROS = {
65
- read_file: [
66
- "Lee únicamente el fragmento de un fichero necesario para responder.",
67
- "Indica siempre `offset` y `limit`; para el reconocimiento inicial usa",
68
- "`offset=0, limit=50`. No releas la misma ruta y el mismo rango: usa la",
69
- "evidencia ya obtenida o una página distinta solo si hace falta.",
70
- ].join(" "),
71
100
  write_file: [
72
101
  "Escribe un fichero del proyecto en una ruta absoluta.",
73
102
  "Para diagramas, esquemas, arquitecturas y flujos: carga primero la skill `archify`;",
@@ -89,9 +118,11 @@ export const DESCRIPCIONES_FICHEROS = {
89
118
  "Busca texto LITERAL (no regex) de forma progresiva para ahorrar contexto.",
90
119
  "Primero acota con `path` y `glob`; para localizar candidatos usa",
91
120
  "`output_mode=\"files_with_matches\"` o `output_mode=\"count\"`.",
92
- "Usa `output_mode=\"content\"` solo con un patrón específico y lee después",
93
- "el fragmento necesario con `read_file` (offset y limit). La búsqueda devuelve",
121
+ "Usa `output_mode=\"content\"` solo con un patrón específico: devuelve la ruta y el NÚMERO",
122
+ "DE LÍNEA de cada coincidencia, así que lee después con `read_file` ALREDEDOR de esa línea",
123
+ "(`offset` = línea menos 5), nunca desde el principio del fichero. La búsqueda devuelve",
94
124
  "como máximo 100 coincidencias salvo que justifiques subir `max_count`.",
125
+ "Varias búsquedas independientes van en el MISMO mensaje, igual que las lecturas.",
95
126
  ].join(" "),
96
127
  };
97
128
  /**
@@ -107,7 +138,7 @@ export const DESCRIPCIONES_FICHEROS = {
107
138
  * no consume toda la ventana antes de que actúe el resumen de conversación.
108
139
  *
109
140
  * **Esa carpeta se monta FUERA del proyecto** (`core/descargas.ts`,
110
- * `agent/proyecto.ts#backendConDescargas`), y hasta el 10-09-2026 no: la escribe la librería
141
+ * `agent/grafo/proyecto.ts#backendConDescargas`), y hasta el 10-09-2026 no: la escribe la librería
111
142
  * llamando al backend directamente, esa ruta no estaba montada en ninguna parte y caía en el
112
143
  * `FilesystemBackend` de la raíz. Medido en el AppDemo real del usuario, 26 KB de salida
113
144
  * cruda de una tool dentro de la app XOne y commiteados. Bajar este tope no era el arreglo:
@@ -132,16 +163,50 @@ export const OPCIONES_BUSQUEDA_FICHEROS = {
132
163
  * ocupar el nombre lo sustituye en el catálogo (`agent/generalPurpose.test.ts`).
133
164
  * 4. **El HITL va en las tools de fichero**, que en la v1 son las que escriben.
134
165
  */
166
+ /** El inspector, o nada: `inspectorDePrompt` devuelve `undefined` si no se ha pedido. */
167
+ function inspector(raiz, origen) {
168
+ const mw = inspectorDePrompt(raiz, origen);
169
+ return mw === undefined ? [] : [mw];
170
+ }
135
171
  export async function construirAgente(opciones) {
136
172
  // Las cuatro capas y su orden están en `backendDeAgente`, que vive en `proyecto.ts` para
137
173
  // poder PROBARSE: aquí no había forma, porque `construirAgente` se simula en todos los
138
174
  // tests que lo tocan y el cableado se quedaba sin nadie mirándolo.
139
- const backend = backendDeAgente({
175
+ /**
176
+ * El cargador del índice de navegación, con la RAÍZ ya fijada.
177
+ *
178
+ * Entra por opción para poder doblarse en un test, y con su omisión real puesta aquí —no en
179
+ * el llamador— por el patrón de fallo de siempre: compuesto arriba, en un cierre que todos
180
+ * los tests simulan, el cableado quedaría escrito y sin probar. `xoneAgent.navegacion.test.ts`
181
+ * lo mira desde fuera.
182
+ *
183
+ * La raíz NO entra por parámetro de la tool: si el modelo pudiera decir sobre qué carpeta
184
+ * pregunta, esto sería una tool que lee cualquier sitio de la máquina.
185
+ */
186
+ const cargarIndice = opciones.navegacion ?? indiceEnDisco(opciones.raiz);
187
+ const comunes = {
140
188
  raiz: opciones.raiz,
141
189
  ficheros: opciones.ficheros,
142
190
  ...(opciones.artefactos === undefined ? {} : { artefactos: opciones.artefactos }),
143
191
  ...(opciones.adjuntos === undefined ? {} : { adjuntos: opciones.adjuntos }),
144
- });
192
+ };
193
+ const backend = backendDeAgente(comunes);
194
+ /**
195
+ * El backend CON shell, y solo si alguien lo va a usar.
196
+ *
197
+ * Se construye aparte porque es otra cadena entera: la base ejecuta, y eso cambia lo que
198
+ * la librería registra (`execute`) y lo que se le puede pasar (`permissions` lanza junto a
199
+ * un backend ejecutable). Que sea `undefined` cuando nadie declara `ejecucion` no es una
200
+ * optimización: es lo que hace que el caso normal sea, byte a byte, el de antes.
201
+ */
202
+ const conShell = opciones.agentes.some((a) => puedeEjecutar(a))
203
+ ? backendDeAgente({
204
+ ...comunes,
205
+ ejecucion: {
206
+ entorno: entornoDeLaShellDelProyecto(opciones.raiz, opciones.artefactos?.carpeta),
207
+ },
208
+ })
209
+ : undefined;
145
210
  // Si no hay tracker, no se añade el middleware: es opcional a propósito arriba.
146
211
  const middlewareTracker = (origen) => opciones.tracker
147
212
  ? [
@@ -195,7 +260,7 @@ export async function construirAgente(opciones) {
195
260
  /**
196
261
  * Lo que diga su `.md`, y nada más. Es la PRIMERA de dos puertas: con esto en
197
262
  * cierto, cada escritura pasa además por la política de la sesión y por las
198
- * guardas de ruta (`agent/escrituraExterna.ts`). Un agente de solo lectura no
263
+ * guardas de ruta (`agent/subagentes/escrituraExterna.ts`). Un agente de solo lectura no
199
264
  * llega a preguntar.
200
265
  */
201
266
  permitirEscritura: !agente.soloLectura,
@@ -211,53 +276,109 @@ export async function construirAgente(opciones) {
211
276
  }
212
277
  const subagentes = opciones.agentes
213
278
  .filter((a) => a.motor === "modelo")
214
- .map((perfil) => ({
215
- name: perfil.nombre,
216
- description: perfil.descripcion,
217
- systemPrompt: promptDeAgente(perfil, repartirSkills(perfil, catalogoDeSkills)),
218
- // Los subagentes no heredan las skills del orquestador. Se entregan como fuentes
219
- // directas para mantener cada perfil limitado a su catálogo declarado.
220
- skills: rutasDeSkills(perfil, catalogoDeSkills),
221
- // `tools` solo lleva tools PROPIAS. Pasarle los NOMBRES de las de fichero las sustituía
222
- // por cadenas, dejando al especialista sin ninguna capacidad real. Las de fichero las
223
- // monta el middleware; regex_search es una tool real y confinada al mismo backend.
224
- tools: [crearBusquedaRegex(backend)],
225
- //
226
- // Las tools de fichero las monta el `FilesystemMiddleware` a partir del backend, y
227
- // quien las acota por NOMBRE es su propia opción `tools` (con la restricción de que
228
- // `read_file` tiene que estar siempre). Aquí el solo-lectura se impone con
229
- // `permissions`, que la librería aplica sobre `ls`, `read_file`, `write_file`,
230
- // `edit_file`, `glob` y `grep` — o sea, sobre todas las que importan.
231
- permissions: permisosDe(perfil),
232
- interruptOn: hitlDe(perfil),
233
- // En CADA especialista, no solo en el orquestador: son ellos los que llaman a las
234
- // tools de fichero, así que es su siguiente llamada al modelo la que reventaba.
235
- // El nombre coincide con el middleware por defecto de DeepAgents y lo sustituye: así
236
- // aplica tanto al especialista como al orquestador.
237
- middleware: [
238
- createFilesystemMiddleware({
239
- backend,
240
- permissions: permisosDe(perfil),
241
- customToolDescriptions: DESCRIPCIONES_FICHEROS,
242
- ...OPCIONES_BUSQUEDA_FICHEROS,
243
- }),
244
- resumenDeContexto(backend),
245
- middlewareTextoDeTool(),
246
- ...middlewareTracker(perfil.nombre),
247
- ],
248
- // El modelo que fije el agente en su fichero, y si no lo fija, el del papel que le
249
- // toca por lo que hace: `rapido` para el que solo lee, `trabajo` para el que escribe.
250
- // Fijarlo es la excepción y no la norma — un agente con modelo escrito se queda ahí
251
- // aunque el usuario cambie el suyo con `/modelo`, que es justo lo que quiere quien
252
- // escribe «este revisor corre con Claude» y no lo que quiere nadie más.
253
- model: perfil.modelo === undefined
254
- ? opciones.modelos.paraPapel(perfil.soloLectura ? "rapido" : "trabajo")
255
- : opciones.modelos.paraModelo(perfil.modelo),
256
- }));
279
+ .map((perfil) => {
280
+ // Una vez por perfil: con qué backend ve los ficheros, con qué permisos y con qué tools.
281
+ const ficheros = montajeDeFicheros(perfil, {
282
+ normal: backend,
283
+ ...(conShell === undefined ? {} : { conShell }),
284
+ });
285
+ return {
286
+ name: perfil.nombre,
287
+ description: perfil.descripcion,
288
+ systemPrompt: promptDeAgente(perfil, repartirSkills(perfil, catalogoDeSkills)),
289
+ // Los subagentes no heredan las skills del orquestador. Se entregan como fuentes
290
+ // directas para mantener cada perfil limitado a su catálogo declarado.
291
+ skills: rutasDeSkills(perfil, catalogoDeSkills),
292
+ // `tools` solo lleva tools PROPIAS. Pasarle los NOMBRES de las de fichero las sustituía
293
+ // por cadenas, dejando al especialista sin ninguna capacidad real. Las de fichero las
294
+ // monta el middleware; regex_search es una tool real y confinada al mismo backend.
295
+ /**
296
+ * Las dos tools propias, y contestan preguntas DISTINTAS: `regex_search` busca TEXTO y
297
+ * `xone_navegacion` contesta sobre el modelo ya resuelto. Un `mapcol` encuentra su
298
+ * colección aunque el nombre salga en otros veinte sitios, y el inventario cuesta 141
299
+ * tokens donde leer los `.xne` cuesta 18.000 (medido sobre un proyecto real).
300
+ *
301
+ * A los CINCO especialistas y no a unos pocos: los cinco trabajan sobre un proyecto XOne
302
+ * y la pregunta que esto abarata —«qué hay aquí»— se la hacen todos. El esquema es de una
303
+ * operación enumerada y un nombre, que es poco en cada llamada; el orquestador NO la
304
+ * recibe, porque no tiene tools propias y delega.
305
+ */
306
+ tools: [crearBusquedaRegex(ficheros.backend), crearNavegacionXone(cargarIndice, opciones.ficheros)],
307
+ //
308
+ // Las tools de fichero las monta el `FilesystemMiddleware` a partir del backend, y
309
+ // quien las acota por NOMBRE es su propia opción `tools` (con la restricción de que
310
+ // `read_file` tiene que estar siempre). Aquí el solo-lectura se impone con
311
+ // `permissions`, que la librería aplica sobre `ls`, `read_file`, `write_file`,
312
+ // `edit_file`, `glob` y `grep` — o sea, sobre todas las que importan.
313
+ /**
314
+ * **Ausente para quien EJECUTA**, y por la misma razón que en el middleware: deepagents
315
+ * lanza `ConfigurationError` al combinar `permissions` con un backend ejecutable. Dejarlo
316
+ * aquí «por si acaso» no añadiría una barrera, tumbaría la construcción del agente.
317
+ */
318
+ ...(ficheros.permissions === undefined ? {} : { permissions: ficheros.permissions }),
319
+ interruptOn: hitlDe(perfil),
320
+ // En CADA especialista, no solo en el orquestador: son ellos los que llaman a las
321
+ // tools de fichero, así que es su siguiente llamada al modelo la que reventaba.
322
+ // El nombre coincide con el middleware por defecto de DeepAgents y lo sustituye: así
323
+ // aplica tanto al especialista como al orquestador.
324
+ middleware: [
325
+ createFilesystemMiddleware({
326
+ // Quién se lleva la shell, con qué permisos y con qué tools lo decide una función
327
+ // pura y probada (`perfiles.ts#montajeDeFicheros`), no un `if` aquí dentro.
328
+ ...ficheros,
329
+ customToolDescriptions: DESCRIPCIONES_FICHEROS,
330
+ ...OPCIONES_BUSQUEDA_FICHEROS,
331
+ }),
332
+ // El tope es del ESPECIALISTA y no del orquestador: el que contesta al usuario no
333
+ // puede quedarse a medias, y el que hace un encargo acotado sí debe. Ver
334
+ // `resumenDeContexto.ts#topeDeLlamadas`.
335
+ topeDeLlamadas(),
336
+ // Y el de TOOLS, que es el que acota lo que se ACUMULA: 43 resultados en el contexto
337
+ // hicieron que la última llamada costara ocho veces la primera.
338
+ topeDeTools(),
339
+ // Los DOS, y en su orden, que es lo que `resumenConEncargo` garantiza: el resumen
340
+ // se lleva el encargo por delante al cruzar el umbral, y el segundo lo devuelve.
341
+ // Sobre el backend del PERFIL: quien tiene shell descarga en SU cadena, que es la que
342
+ // tiene montadas `/large_tool_results/` y `/conversation_history/` con su misma raíz.
343
+ ...resumenConEncargo(ficheros.backend),
344
+ middlewareTextoDeTool(),
345
+ ...middlewareTracker(perfil.nombre),
346
+ // El ÚLTIMO, y por eso ve la petición ya pasada por todos los de arriba: el resumen, la
347
+ // devolución del encargo y la conversión de los `ToolMessage`. Puesto delante enseñaría
348
+ // lo que otros van a cambiar después, que es la mentira de un inspector.
349
+ ...inspector(opciones.raiz, perfil.nombre),
350
+ ],
351
+ // El modelo que fije el agente en su fichero, y si no lo fija, el del papel que le
352
+ // toca por lo que hace: `rapido` para el que solo lee, `trabajo` para el que escribe.
353
+ // Fijarlo es la excepción y no la norma — un agente con modelo escrito se queda ahí
354
+ // aunque el usuario cambie el suyo con `/modelo`, que es justo lo que quiere quien
355
+ // escribe «este revisor corre con Claude» y no lo que quiere nadie más.
356
+ model: perfil.modelo === undefined
357
+ ? opciones.modelos.paraPapel(perfil.soloLectura ? "rapido" : "trabajo")
358
+ : opciones.modelos.paraModelo(perfil.modelo),
359
+ };
360
+ });
257
361
  return createDeepAgent({
258
362
  model: opciones.modelos.paraPapel("rapido"),
259
363
  systemPrompt: promptOrquestador(opciones.agentes),
260
364
  backend,
365
+ /**
366
+ * **El orquestador SÍ la lleva, y eso lo decidió una medida que tumbó lo contrario.**
367
+ *
368
+ * La primera versión se la dio solo a los especialistas con el argumento de que el
369
+ * orquestador delega. Medido sobre un proyecto real con la pregunta que motivó la tool
370
+ * —«¿cuántas colecciones tiene mi proyecto?»—: **no delegó**. La contestó él, con `ls`,
371
+ * `glob`, `grep` y `read_file`, en once llamadas y ~88k tokens, y la tool no llegó a
372
+ * estar disponible porque vivía en los subagentes. O sea que el razonamiento era bueno y
373
+ * el comportamiento otro, que es justo lo que este repo prefiere medir antes que suponer.
374
+ *
375
+ * No le abre nada: es de LECTURA y el orquestador ya lee (`permisosDe` le deja
376
+ * `read`/`ls`/`glob`/`grep` y le deniega el disco entero para escribir). Lo que cambia es
377
+ * el precio de orientarse. Su esquema viaja en cada llamada suya —y eso no es gratis,
378
+ * `excluirTools` existe por eso—, pero es una operación enumerada y un nombre frente a
379
+ * las once llamadas que sustituye.
380
+ */
381
+ tools: [crearNavegacionXone(cargarIndice, opciones.ficheros)],
261
382
  interruptOn: hitlDe(PERFIL_DEL_ORQUESTADOR),
262
383
  checkpointer: opciones.checkpointer ?? new MemorySaver(),
263
384
  // El contenido de los `ToolMessage` va como TEXTO al modelo. Sin esto, un turno real
@@ -296,9 +417,17 @@ export async function construirAgente(opciones) {
296
417
  customToolDescriptions: DESCRIPCIONES_FICHEROS,
297
418
  ...OPCIONES_BUSQUEDA_FICHEROS,
298
419
  }),
299
- resumenDeContexto(backend),
420
+ // Los DOS, y en su orden, que es lo que `resumenConEncargo` garantiza: el resumen
421
+ // se lleva el encargo por delante al cruzar el umbral, y el segundo lo devuelve.
422
+ ...resumenConEncargo(backend),
423
+ // Los esquemas de las tools que NO puede usar son el 25 % de su cabecera, y la cabecera
424
+ // es el 87 % de cada llamada (`inspectorDePrompt`). `permissions` acota el permiso; el
425
+ // esquema viaja igual, así que esto lo quita del prompt Y sigue rechazando la llamada.
426
+ // La frontera sigue siendo `permisosDe`: ver `excluirTools.ts`.
427
+ excluirTools(toolsQueNoUsa(PERFIL_DEL_ORQUESTADOR)),
300
428
  middlewareTextoDeTool(),
301
429
  ...middlewareTracker("orquestador"),
430
+ ...inspector(opciones.raiz, "orquestador"),
302
431
  ],
303
432
  subagents: [
304
433
  ...subagentes,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xoneAgent.js","sourceRoot":"","sources":["../../../src/agent/grafo/xoneAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAe,MAAM,uBAAuB,CAAC;AAEvG,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAoB,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAA4B,MAAM,eAAe,CAAC;AAC/G,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAqB,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EACL,6BAA6B,GAG9B,MAAM,+BAA+B,CAAC;AA+DvC;;;;;;;;;;;;GAYG;AACH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAExG,MAAM,UAAU,iBAAiB,CAAC,OAA0B;IAC1D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACxE,OAAO;QACL,0EAA0E;QAC1E,yFAAyF;QACzF,sDAAsD;QACtD,iBAAiB;QACjB,uFAAuF;QACvF,yFAAyF;QACzF,EAAE;QACF,2FAA2F;QAC3F,yFAAyF;QACzF,2FAA2F;QAC3F,2FAA2F;QAC3F,iFAAiF;QACjF,sFAAsF;QACtF,yEAAyE;QACzE,6FAA6F;QAC7F,6FAA6F;QAC7F,uEAAuE;QACvE,yFAAyF;QACzF,4DAA4D;QAC5D,OAAO,CAAC,MAAM,KAAK,CAAC;YAClB,CAAC,CAAC,wIAAwI;YAC1I,CAAC,CAAC,sCAAsC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B;QAC9G,GAAG,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,eAAe,CAAC;YACzC,CAAC,CAAC,qLAAqL;YACvL,CAAC,CAAC,EAAE;QACN,0FAA0F;QAC1F,6FAA6F;QAC7F,yFAAyF;QACzF,8EAA8E;QAC9E,sBAAsB;QACtB,oFAAoF;KACrF;SACE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;SACvB,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,UAAU,EAAE;QACV,uDAAuD;QACvD,qFAAqF;QACrF,qFAAqF;QACrF,kEAAkE;QAClE,sFAAsF;QACtF,0FAA0F;QAC1F,wFAAwF;QACxF,wEAAwE;QACxE,0CAA0C;QAC1C,kGAAkG;KACnG,CAAC,IAAI,CAAC,GAAG,CAAC;IACX,SAAS,EAAE;QACT,kEAAkE;QAClE,wFAAwF;QACxF,+DAA+D;KAChE,CAAC,IAAI,CAAC,GAAG,CAAC;IACX,IAAI,EAAE;QACJ,2EAA2E;QAC3E,kEAAkE;QAClE,iEAAiE;QACjE,2FAA2F;QAC3F,2FAA2F;QAC3F,wFAAwF;QACxF,wEAAwE;QACxE,kFAAkF;KACnF,CAAC,IAAI,CAAC,GAAG,CAAC;CACZ,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,YAAY,EAAE,GAAG;IACjB,yBAAyB,EAAE,KAAK;CACxB,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,yFAAyF;AACzF,SAAS,SAAS,CAAC,IAAY,EAAE,MAAc;IAC7C,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAA2B;IAC/D,yFAAyF;IACzF,uFAAuF;IACvF,mEAAmE;IACnE;;;;;;;;;;OAUG;IACH,MAAM,YAAY,GAAiB,QAAQ,CAAC,UAAU,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEvF,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,GAAG,CAAC,QAAQ,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC;QACjF,GAAG,CAAC,QAAQ,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC;KAC5E,CAAC;IACF,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAEzC;;;;;;;OAOG;IACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,eAAe,CAAC;YACd,GAAG,OAAO;YACV,SAAS,EAAE;gBACT,OAAO,EAAE,2BAA2B,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;aAClF;SACF,CAAC;QACJ,CAAC,CAAC,SAAS,CAAC;IAEd,gFAAgF;IAChF,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,EAAE,CAC3C,QAAQ,CAAC,OAAO;QACd,CAAC,CAAC;YACE,6BAA6B,CAC3B,QAAQ,CAAC,OAAO,EAChB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,cAAc,CAAC,CAC1E;SACF;QACH,CAAC,CAAC,EAAE,CAAC;IAET,yFAAyF;IACzF,kEAAkE;IAClE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAElF;;;;;;;;;;;OAWG;IACH,MAAM,QAAQ,GAAG,EAAE,CAAC;IACpB,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,KAAqB,CAAC;QAC3C,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAAE,SAAS;QACnE,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC,MAAM;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAqC,EAAE,EAAE;gBAC5E,gFAAgF;gBAChF,mFAAmF;gBACnF,oFAAoF;gBACpF,iDAAiD;gBACjD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxC,MAAM,KAAK,GAAG,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;gBACnG,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,MAAM,CAAC;oBACnD,KAAK;oBACL,GAAG,EAAE,QAAQ,CAAC,IAAI;oBAClB;;;;;uBAKG;oBACH,aAAa,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,OAAO,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;oBACnI,KAAK;oBACL,gFAAgF;oBAChF,0DAA0D;oBAC1D,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;oBACjE;;;;;uBAKG;oBACH,iBAAiB,EAAE,CAAC,MAAM,CAAC,WAAW;oBACtC,iFAAiF;oBACjF,2EAA2E;oBAC3E,6EAA6E;oBAC7E,yCAAyC;oBACzC,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CAAC,CAAC;gBACH,OAAO,EAAE,QAAQ,EAAE,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAC9C,CAAC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;SACnC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAChB,yFAAyF;QACzF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE;YACzC,MAAM,EAAE,OAAO;YACf,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;SAChD,CAAC,CAAC;QACH,OAAO;YACP,IAAI,EAAE,MAAM,CAAC,MAAM;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,cAAc,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;YAC9E,iFAAiF;YACjF,uEAAuE;YACvE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,gBAAgB,CAAC;YAC/C,wFAAwF;YACxF,sFAAsF;YACtF,mFAAmF;YACnF;;;;;;;;;;eAUG;YACH,KAAK,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnG,EAAE;YACF,mFAAmF;YACnF,oFAAoF;YACpF,2EAA2E;YAC3E,+EAA+E;YAC/E,sEAAsE;YACtE;;;;eAIG;YACH,GAAG,CAAC,QAAQ,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;YACpF,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC;YAC3B,kFAAkF;YAClF,gFAAgF;YAChF,qFAAqF;YACrF,oDAAoD;YACpD,UAAU,EAAE;gBACV,0BAA0B,CAAC;oBACzB,kFAAkF;oBAClF,4EAA4E;oBAC5E,GAAG,QAAQ;oBACX,sBAAsB,EAAE,sBAAsB;oBAC9C,GAAG,0BAA0B;iBAC9B,CAAC;gBACF,kFAAkF;gBAClF,yEAAyE;gBACzE,yCAAyC;gBACzC,cAAc,EAAE;gBAChB,qFAAqF;gBACrF,gEAAgE;gBAChE,WAAW,EAAE;gBACb,kFAAkF;gBAClF,iFAAiF;gBACjF,sFAAsF;gBACtF,sFAAsF;gBACtF,GAAG,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACtC,qBAAqB,EAAE;gBACvB,GAAG,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC;gBACnC,wFAAwF;gBACxF,wFAAwF;gBACxF,yEAAyE;gBACzE,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;aAC3C;YACD,mFAAmF;YACnF,sFAAsF;YACtF,oFAAoF;YACpF,mFAAmF;YACnF,wEAAwE;YACxE,KAAK,EACH,MAAM,CAAC,MAAM,KAAK,SAAS;gBACzB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;gBACvE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC;SAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,eAAe,CAAC;QACrB,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC3C,YAAY,EAAE,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC;QACjD,OAAO;QACP;;;;;;;;;;;;;;;WAeG;QACH,KAAK,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC7D,WAAW,EAAE,MAAM,CAAC,sBAAsB,CAAC;QAC3C,YAAY,EAAE,QAAQ,CAAC,YAAY,IAAI,IAAI,WAAW,EAAE;QACxD,qFAAqF;QACrF,oFAAoF;QACpF,0EAA0E;QAC1E,2DAA2D;QAC3D,UAAU,EAAE;YACV,0BAA0B,CAAC;gBACzB,OAAO;gBACP;;;;;;;;;;;;;;;;;;;;;;;;mBAwBG;gBACH,WAAW,EAAE,UAAU,CAAC,sBAAsB,CAAC;gBAC/C,sBAAsB,EAAE,sBAAsB;gBAC9C,GAAG,0BAA0B;aAC9B,CAAC;YACF,kFAAkF;YAClF,iFAAiF;YACjF,GAAG,iBAAiB,CAAC,OAAO,CAAC;YAC7B,wFAAwF;YACxF,uFAAuF;YACvF,uFAAuF;YACvF,gEAAgE;YAChE,YAAY,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;YACnD,qBAAqB,EAAE;YACvB,GAAG,iBAAiB,CAAC,aAAa,CAAC;YACnC,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;SAC3C;QACD,SAAS,EAAE;YACT,GAAG,UAAU;YACb,GAAG,QAAQ;YACX;gBACE,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,6HAA6H;gBAC1I,YAAY,EAAE,4GAA4G;gBAC1H,KAAK,EAAE,EAAE;aACV;SACF;QACD,8DAA8D;KACxD,CAAC,CAAC;AACZ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,WAAgC;IAC5E,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC;AACrG,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,WAAgC,EAChC,cAA2B;IAE3B,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,cAAc,EAAE,EAAE,CAAC;IACrB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ // **Import PROFUNDO, y no es una optimización: es un requisito medido.** El barril
2
+ // (`xone-linter`) reexporta también su RUNTIME —VM, HTTP, dispositivo y una conexión SQLite
3
+ // con *top-level await*—, y eso revienta bajo `tsx`, que es el lanzador de desarrollo
4
+ // (`./bin/xonecode`): «Top-level await is currently not supported with the cjs output
5
+ // format». Por la ruta del modelo no hay ningún `await` de módulo, así que entra limpio — y
6
+ // de paso no se arrastra medio runtime para leer un XML.
7
+ import { XoneProject } from "xone-linter/dist/project/XoneProject.js";
8
+ import { construirIndice } from "../../core/navegacion.js";
9
+ import { modeloDeNavegacion } from "./modeloDeProyecto.js";
10
+ /**
11
+ * Devuelve el cargador del índice de una raíz. La raíz se fija al crearlo y NO entra por
12
+ * parámetro en cada consulta: si el modelo pudiera decir sobre qué proyecto preguntar,
13
+ * tendríamos una tool que lee cualquier carpeta de la máquina.
14
+ */
15
+ export function indiceEnDisco(raiz) {
16
+ return async (ficheros) => {
17
+ const proyecto = await XoneProject.load(raiz);
18
+ return construirIndice(modeloDeNavegacion(proyecto.model, raiz, ficheros));
19
+ };
20
+ }
21
+ //# sourceMappingURL=indiceEnDisco.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indiceEnDisco.js","sourceRoot":"","sources":["../../../src/agent/navegacion/indiceEnDisco.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4FAA4F;AAC5F,sFAAsF;AACtF,sFAAsF;AACtF,4FAA4F;AAC5F,yDAAyD;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AACtE,OAAO,EAAE,eAAe,EAA2B,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAwB,MAAM,uBAAuB,CAAC;AA2BjF;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,KAAK,EAAE,QAAQ,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,eAAe,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAwB,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChG,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,228 @@
1
+ import { relative, sep } from "node:path";
2
+ import { puedeLeerRuta } from "../grafo/perfiles.js";
3
+ import { esVistaAplanada } from "../grafo/proyecto.js";
4
+ /**
5
+ * La ruta VIRTUAL de una absoluta del proyecto, o `undefined` si se sale de él.
6
+ *
7
+ * Lexical y no `realpath`: este módulo es la traducción, no la barrera del disco — quien
8
+ * necesite cerrar los enlaces simbólicos lo hace donde se abre el fichero. Aquí lo que se
9
+ * impide es que una ruta de FUERA se presente como si fuera del proyecto.
10
+ */
11
+ export function rutaVirtualDelProyecto(raiz, absoluta) {
12
+ const rel = relative(raiz, absoluta);
13
+ if (rel === "" || rel.startsWith("..") || rel.startsWith(sep + ".."))
14
+ return undefined;
15
+ // Absoluta de otra unidad: `relative` la devuelve absoluta y no empieza por `..`.
16
+ if (rel.startsWith(sep) || /^[A-Za-z]:/.test(rel))
17
+ return undefined;
18
+ return "/" + rel.split(sep).join("/");
19
+ }
20
+ /**
21
+ * Traduce el modelo del linter al nuestro, filtrando lo que no se puede enseñar.
22
+ *
23
+ * `ficheros` son las rutas virtuales del proyecto, las mismas que ve el agente: hacen falta
24
+ * para reconocer una vista aplanada (`X.xml` con un `X.xne` al lado), que es una regla que
25
+ * depende del conjunto y no de la ruta sola.
26
+ */
27
+ export function modeloDeNavegacion(delLinter, raiz, ficheros) {
28
+ const colecciones = [];
29
+ for (const coll of delLinter.colls ?? []) {
30
+ const nombre = coll.name;
31
+ const absoluta = coll.location?.file;
32
+ if (nombre === undefined || nombre === "" || absoluta === undefined)
33
+ continue;
34
+ const fichero = rutaVirtualDelProyecto(raiz, absoluta);
35
+ // Fuera del proyecto, denegada o vista aplanada: no entra en el índice. Un símbolo que
36
+ // el agente no puede abrir es peor que uno que falta — le manda a leer donde no debe.
37
+ if (fichero === undefined || !puedeLeerRuta(fichero) || esVistaAplanada(fichero, ficheros))
38
+ continue;
39
+ const campos = (coll.props ?? [])
40
+ .filter((p) => typeof p.name === "string" && p.name !== "")
41
+ .map((p) => ({ nombre: p.name, ...(p.type === undefined ? {} : { tipo: p.type }) }));
42
+ colecciones.push({
43
+ nombre,
44
+ fichero,
45
+ campos,
46
+ referencias: referenciasDe(coll, nombre),
47
+ // Un `onchange` lleva el campo que lo dispara: sin él no se sabe a qué reacciona, y eso
48
+ // es justo lo que hace falta antes de tocarlo.
49
+ eventos: (coll.events ?? [])
50
+ .filter((e) => typeof e.name === "string" && e.name !== "")
51
+ .map((e) => (e.triggerProp === undefined || e.triggerProp === "" ? e.name : `${e.name}(${e.triggerProp})`)),
52
+ nodos: nombresDe(coll.nodes),
53
+ conexiones: nombresDe(coll.connections),
54
+ });
55
+ }
56
+ return {
57
+ colecciones,
58
+ // El inventario entra como criba de la señal débil: sin él, «un literal que coincide con
59
+ // una colección» sería «cualquier literal». Por eso va DESPUÉS de componer las colecciones.
60
+ referenciasDeScript: referenciasDeScript(delLinter, raiz, ficheros, new Set(colecciones.map((c) => c.nombre.toLowerCase()))),
61
+ app: {
62
+ entrada: [...(delLinter.app?.entryPoints ?? [])],
63
+ login: [...(delLinter.app?.loginColls ?? [])],
64
+ // La URL de un estilo es del PROYECTO (`default.css`), no una ruta de la máquina: la
65
+ // declara el propio `app.xml` y por eso viaja tal cual.
66
+ estilos: (delLinter.app?.styles ?? [])
67
+ .map((e) => e.url)
68
+ .filter((u) => typeof u === "string" && u !== ""),
69
+ conexiones: nombresDe(delLinter.app?.connections),
70
+ },
71
+ };
72
+ }
73
+ /** Los `name` que existen de verdad, de una lista que puede traerlos a medias. */
74
+ function nombresDe(lista) {
75
+ return (lista ?? []).map((x) => x.name).filter((n) => typeof n === "string" && n !== "");
76
+ }
77
+ /**
78
+ * Lo que una colección apunta hacia fuera.
79
+ *
80
+ * Los cuatro atributos son los que `xone-linter` ya valida en su `CrossReferenceRule`, y esa
81
+ * coincidencia es deliberada: **la semántica de qué significa `mapcol` vive en UN sitio**.
82
+ * Reescribirla aquí crearía un segundo sitio donde decidirlo, y el día que divergieran el
83
+ * linter diría una cosa y el agente otra sobre el mismo proyecto.
84
+ *
85
+ * `mapfld` y `linkedfield` se cuelgan del `mapcol` de su propio prop, que es lo que les da
86
+ * sentido: un `mapfld` sin `mapcol` no apunta a nada que se pueda nombrar.
87
+ */
88
+ function referenciasDe(coll, nombre) {
89
+ const salida = [];
90
+ const hereda = coll.attributes?.["inherits"];
91
+ if (hereda !== undefined && hereda !== "") {
92
+ salida.push({ desde: nombre, por: "inherits", hacia: hereda });
93
+ }
94
+ for (const contenido of coll.contents ?? []) {
95
+ if (contenido.src !== undefined && contenido.src !== "") {
96
+ salida.push({ desde: nombre, por: "contents", hacia: contenido.src });
97
+ }
98
+ }
99
+ for (const prop of coll.props ?? []) {
100
+ if (typeof prop.name !== "string" || prop.name === "")
101
+ continue;
102
+ const desde = `${nombre}.${prop.name}`;
103
+ const mapcol = prop.attributes?.["mapcol"];
104
+ if (mapcol === undefined || mapcol === "")
105
+ continue;
106
+ salida.push({ desde, por: "mapcol", hacia: mapcol });
107
+ for (const clave of ["mapfld", "linkedfield"]) {
108
+ const campo = prop.attributes?.[clave];
109
+ if (campo !== undefined && campo !== "") {
110
+ salida.push({ desde, por: clave, hacia: `${mapcol}.${campo}` });
111
+ }
112
+ }
113
+ }
114
+ return salida;
115
+ }
116
+ /**
117
+ * Cómo una app XOne llega de verdad a una colección, que no es con `mapcol`.
118
+ *
119
+ * **Medido sobre un proyecto real**, y fue lo que cambió el alcance de la tool. Hay DOS
120
+ * señales, y van separadas a propósito porque no valen lo mismo:
121
+ *
122
+ * 1. **`appData.getCollection("X")` — señal FUERTE** (`por: "script"`). Es una llamada con su
123
+ * literal: la forma en que se nombra una colección desde ES5. Los botones del menú abren
124
+ * así (`onclick="javascript:var o=appData.getCollection('Deportes')…"`), y sin esto «¿quién
125
+ * usa Deportes?» contestaba «nadie» con dos botones apuntándole.
126
+ * 2. **Un literal que COINCIDE con el nombre de una colección — señal DÉBIL**
127
+ * (`por: "mencion"`). Existe porque la cadena real puede tener tres saltos:
128
+ * `method="ExecuteNode(abrirColl('ConsolaReplica'))"` → un nodo con `<param name="coll">` →
129
+ * `irColl(coll)` → `getCollection(collname)` + `pushValue(obj)`. El nombre solo aparece
130
+ * como literal en el PRIMER salto, y perseguir la cadena sería atarse a cómo se llaman los
131
+ * ayudantes de UN proyecto (`irColl`, `abrirColl`, `openMenu`), que no son de XOne.
132
+ *
133
+ * **Y se marcan distinto porque la confianza es distinta.** Una llamada resuelta y una cadena
134
+ * que coincide con un nombre no son lo mismo, y fundirlas haría que la segunda se leyera con
135
+ * la autoridad de la primera. Medido sobre el proyecto real: la débil añade cinco referencias
136
+ * y todas resultaron ciertas, pero eso no la convierte en la fuerte.
137
+ *
138
+ * **Límites declarados**: ninguna de las dos ve un nombre compuesto en ejecución ni dice en qué
139
+ * LÍNEA está —para eso harían falta rangos—, y la débil no puede distinguir un nombre de
140
+ * colección de una cadena que se le parece.
141
+ */
142
+ const LLAMADA_A_COLECCION = /getCollection\s*\(\s*['"]([^'"]+)['"]\s*\)/gi;
143
+ /** Cualquier literal de cadena con forma de identificador. La criba es el inventario. */
144
+ const LITERAL_DE_CADENA = /['"]([A-Za-z_][A-Za-z0-9_]{2,40})['"]/g;
145
+ /** Todos los sitios del proyecto donde hay script, con su origen ya traducido. */
146
+ function trozosDeScript(delLinter, raiz) {
147
+ const trozos = [];
148
+ for (const coll of delLinter.colls ?? []) {
149
+ const nombre = coll.name;
150
+ const absoluta = coll.location?.file;
151
+ if (nombre === undefined || absoluta === undefined)
152
+ continue;
153
+ const fichero = rutaVirtualDelProyecto(raiz, absoluta);
154
+ if (fichero === undefined)
155
+ continue;
156
+ for (const prop of coll.props ?? []) {
157
+ if (typeof prop.name !== "string" || prop.name === "")
158
+ continue;
159
+ const desde = `${nombre}.${prop.name}`;
160
+ for (const evento of prop.inlineEvents ?? []) {
161
+ trozos.push({ desde, fichero, duena: nombre, texto: String(evento.script ?? "") });
162
+ }
163
+ // **El atributo `method` cuenta**, y no es un detalle: es donde vive
164
+ // `ExecuteNode(abrirColl('ConsolaReplica'))`, o sea la única aparición literal de esa
165
+ // colección en todo el proyecto. Sin mirarlo, el botón de información no referencia nada.
166
+ const metodo = prop.attributes?.["method"];
167
+ if (metodo !== undefined && metodo !== "") {
168
+ trozos.push({ desde, fichero, duena: nombre, texto: metodo });
169
+ }
170
+ }
171
+ for (const evento of [...(coll.events ?? []), ...(coll.nodes ?? [])]) {
172
+ const desde = `${nombre}:${evento.name ?? "(evento)"}`;
173
+ for (const accion of evento.actions ?? []) {
174
+ for (const texto of [accion.script, accion.value]) {
175
+ if (texto !== undefined && texto !== "")
176
+ trozos.push({ desde, fichero, duena: nombre, texto });
177
+ }
178
+ }
179
+ }
180
+ }
181
+ // Los `.js` sueltos. Sus claves son rutas RELATIVAS al proyecto, así que la virtual es
182
+ // directa. No tienen colección dueña: un `.js` puede nombrar a cualquiera.
183
+ for (const [ruta, texto] of delLinter.jsFiles ?? new Map()) {
184
+ const virtual = "/" + String(ruta).split(/[\\/]/).filter(Boolean).join("/");
185
+ trozos.push({ desde: virtual, fichero: virtual, texto: String(texto) });
186
+ }
187
+ return trozos;
188
+ }
189
+ function referenciasDeScript(delLinter, raiz, ficheros, conocidas) {
190
+ const salida = [];
191
+ const anotar = (desde, por, hacia, fichero) => {
192
+ if (!puedeLeerRuta(fichero) || esVistaAplanada(fichero, ficheros))
193
+ return;
194
+ // Sin repetir: un mismo botón puede nombrar la colección dos veces en la misma línea.
195
+ if (salida.some((r) => r.desde === desde && r.hacia === hacia && r.fichero === fichero))
196
+ return;
197
+ salida.push({ desde, por, hacia, fichero });
198
+ };
199
+ for (const trozo of trozosDeScript(delLinter, raiz)) {
200
+ const fuertes = new Set();
201
+ for (const x of trozo.texto.matchAll(LLAMADA_A_COLECCION)) {
202
+ fuertes.add(x[1].toLowerCase());
203
+ anotar(trozo.desde, "script", x[1], trozo.fichero);
204
+ }
205
+ for (const x of trozo.texto.matchAll(LITERAL_DE_CADENA)) {
206
+ const literal = x[1];
207
+ const clave = literal.toLowerCase();
208
+ // Solo si es el nombre de una colección que EXISTE: el inventario es la criba, y sin
209
+ // ella esto sería «cualquier cadena del proyecto».
210
+ if (!conocidas.has(clave))
211
+ continue;
212
+ // Ya la cogió la señal fuerte en este mismo trozo: no se degrada a mención.
213
+ if (fuertes.has(clave))
214
+ continue;
215
+ /**
216
+ * **Una colección que se nombra a sí misma no cuenta.** Medido: de las menciones que
217
+ * aparecían en el proyecto real, la mayoría eran los scripts de `ConsolaReplica`
218
+ * diciendo «ConsolaReplica» — en un SQL, en un mensaje, en un refresco. Como respuesta a
219
+ * «¿quién usa X?» eso es ruido, y ruido que sale en TODAS las colecciones con scripts.
220
+ */
221
+ if (trozo.duena !== undefined && trozo.duena.toLowerCase() === clave)
222
+ continue;
223
+ anotar(trozo.desde, "mencion", literal, trozo.fichero);
224
+ }
225
+ }
226
+ return salida;
227
+ }
228
+ //# sourceMappingURL=modeloDeProyecto.js.map