xonecode 0.38.41 → 0.39.2

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 (334) hide show
  1. package/apps/web/dist/assets/{EditorDeFichero-B5qtmfKO.js → EditorDeFichero-BeWDctgN.js} +1 -1
  2. package/apps/web/dist/assets/{index-C6XoIOQg.js → index-B-6cDRAV.js} +20 -20
  3. package/apps/web/dist/assets/{php-I6JfbNBQ.js → php-D3QdOnb8.js} +1 -1
  4. package/apps/web/dist/assets/{ruby-DlqXDLOX.js → ruby-DDAcW-Z2.js} +1 -1
  5. package/apps/web/dist/index.html +1 -1
  6. package/dist/agent/cloudstudio/cloudstudioClient.d.ts +29 -0
  7. package/dist/agent/cloudstudio/cloudstudioMcp.d.ts +414 -0
  8. package/dist/agent/cloudstudio/conexionDeServidor.d.ts +37 -0
  9. package/dist/agent/cloudstudio/conexionDeServidor.js +63 -0
  10. package/dist/agent/cloudstudio/conexionDeServidor.js.map +1 -0
  11. package/dist/agent/cloudstudio/crearRama.d.ts +15 -0
  12. package/dist/agent/cloudstudio/crearRama.js +16 -0
  13. package/dist/agent/cloudstudio/crearRama.js.map +1 -0
  14. package/dist/agent/cloudstudio/descarga.d.ts +44 -0
  15. package/dist/agent/cloudstudio/manifiesto.d.ts +25 -0
  16. package/dist/agent/cloudstudio/ramaActiva.d.ts +24 -0
  17. package/dist/agent/cloudstudio/subida.d.ts +61 -0
  18. package/dist/agent/cloudstudio/subida.js +7 -1
  19. package/dist/agent/cloudstudio/subida.js.map +1 -1
  20. package/dist/agent/cloudstudio/validarTrasDescarga.d.ts +13 -0
  21. package/dist/agent/cloudstudio/zip.d.ts +13 -0
  22. package/dist/agent/conectores/conectoresEnDisco.d.ts +47 -0
  23. package/dist/agent/conectores/gestorJira.d.ts +50 -0
  24. package/dist/agent/conectores/gestorNotion.d.ts +45 -0
  25. package/dist/agent/conectores/proveedorDeConector.d.ts +43 -0
  26. package/dist/agent/conectores/servicioDeConectores.d.ts +112 -0
  27. package/dist/agent/config/authEnDisco.d.ts +43 -0
  28. package/dist/agent/config/catalogoModelos.d.ts +79 -0
  29. package/dist/agent/config/configEnDisco.d.ts +235 -0
  30. package/dist/agent/config/crearProyecto.d.ts +20 -0
  31. package/dist/agent/config/diagnosticoDeNodeEnMaquina.d.ts +44 -0
  32. package/dist/agent/config/ecoDeRazonamiento.d.ts +104 -0
  33. package/dist/agent/config/entorno.d.ts +83 -0
  34. package/dist/agent/config/fuentesEnRed.d.ts +12 -0
  35. package/dist/agent/config/gemini.d.ts +5 -0
  36. package/dist/agent/config/iconosEnRed.d.ts +10 -0
  37. package/dist/agent/config/identidadEnDisco.d.ts +27 -0
  38. package/dist/agent/config/modelos.d.ts +77 -0
  39. package/dist/agent/config/modelosDeMotor.d.ts +52 -0
  40. package/dist/agent/config/mudanzaEnDisco.d.ts +99 -0
  41. package/dist/agent/config/persona.d.ts +1 -0
  42. package/dist/agent/config/selectorEnMaquina.d.ts +35 -0
  43. package/dist/agent/config/settingsEnDisco.d.ts +206 -0
  44. package/dist/agent/config/versionEnDisco.d.ts +17 -0
  45. package/dist/agent/dispositivos/arranqueDeEmulador.d.ts +60 -0
  46. package/dist/agent/dispositivos/cajasDeMaqueta.d.ts +61 -0
  47. package/dist/agent/dispositivos/decodificarImagen.d.ts +21 -0
  48. package/dist/agent/dispositivos/descargaDeHerramientas.d.ts +44 -0
  49. package/dist/agent/dispositivos/dispositivosEnMaquina.d.ts +161 -0
  50. package/dist/agent/dispositivos/geometriaEnDisco.d.ts +17 -0
  51. package/dist/agent/dispositivos/hotswap.d.ts +194 -0
  52. package/dist/agent/dispositivos/instalacionEnMaquina.d.ts +156 -0
  53. package/dist/agent/dispositivos/juezVisual.d.ts +144 -0
  54. package/dist/agent/dispositivos/lanzamientoEnMaquina.d.ts +197 -0
  55. package/dist/agent/dispositivos/paqueteDelProyecto.d.ts +28 -0
  56. package/dist/agent/dispositivos/procesosEnMaquina.d.ts +154 -0
  57. package/dist/agent/dispositivos/recargaEnAparato.d.ts +30 -0
  58. package/dist/agent/dispositivos/sensorDeArranque.d.ts +42 -0
  59. package/dist/agent/exportarPdf.d.ts +72 -0
  60. package/dist/agent/grafo/aprendido.d.ts +28 -0
  61. package/dist/agent/grafo/arbolDeProyecto.d.ts +205 -0
  62. package/dist/agent/grafo/artefactosEnDisco.d.ts +35 -0
  63. package/dist/agent/grafo/atributosXone.d.ts +31 -0
  64. package/dist/agent/grafo/buscarIcono.d.ts +32 -0
  65. package/dist/agent/grafo/busquedaRegex.d.ts +56 -0
  66. package/dist/agent/grafo/codificacionDelProyecto.d.ts +7 -0
  67. package/dist/agent/grafo/compararCapturas.d.ts +22 -0
  68. package/dist/agent/grafo/copiarArtefacto.d.ts +64 -0
  69. package/dist/agent/grafo/criticaVisual.d.ts +60 -0
  70. package/dist/agent/grafo/describirImagen.d.ts +79 -0
  71. package/dist/agent/grafo/diferenciaDeCapturas.d.ts +33 -0
  72. package/dist/agent/grafo/ejecucionCancelable.d.ts +45 -0
  73. package/dist/agent/grafo/escriturasEnSerie.d.ts +31 -0
  74. package/dist/agent/grafo/excluirTools.d.ts +37 -0
  75. package/dist/agent/grafo/fuentesDeGoogle.d.ts +37 -0
  76. package/dist/agent/grafo/generarFondoSvg.d.ts +52 -0
  77. package/dist/agent/grafo/incorporarAdjunto.d.ts +98 -0
  78. package/dist/agent/grafo/lectorDeReferencias.d.ts +28 -0
  79. package/dist/agent/grafo/marcarCriteriosDelPlan.d.ts +47 -0
  80. package/dist/agent/grafo/memoriaDeProyecto.d.ts +15 -0
  81. package/dist/agent/grafo/navegacionXone.d.ts +60 -0
  82. package/dist/agent/grafo/opcionesDeFicheros.d.ts +23 -0
  83. package/dist/agent/grafo/perfiles.d.ts +225 -0
  84. package/dist/agent/grafo/proyecto.d.ts +450 -0
  85. package/dist/agent/grafo/skills.d.ts +181 -0
  86. package/dist/agent/grafo/traerDeLaMaquina.d.ts +60 -0
  87. package/dist/agent/grafo/unirSecciones.d.ts +20 -0
  88. package/dist/agent/grafo/validacionXone.d.ts +35 -0
  89. package/dist/agent/grafo/validarFicheroXone.d.ts +33 -0
  90. package/dist/agent/grafo/xoneAgent.d.ts +166 -0
  91. package/dist/agent/motores/motoresLocales.d.ts +87 -0
  92. package/dist/agent/motores/trueforge/capacidades.d.ts +183 -0
  93. package/dist/agent/motores/trueforge/convertirAP.d.ts +38 -0
  94. package/dist/agent/motores/trueforge/detencion.d.ts +70 -0
  95. package/dist/agent/motores/trueforge/esperas.d.ts +38 -0
  96. package/dist/agent/motores/trueforge/eventosTrueforge.d.ts +56 -0
  97. package/dist/agent/motores/trueforge/informesDeHijos.d.ts +48 -0
  98. package/dist/agent/motores/trueforge/medidaAutomatica.d.ts +37 -0
  99. package/dist/agent/motores/trueforge/medidaAutomatica.js +4 -2
  100. package/dist/agent/motores/trueforge/medidaAutomatica.js.map +1 -1
  101. package/dist/agent/motores/trueforge/memoriaDeEspecialistas.d.ts +60 -0
  102. package/dist/agent/motores/trueforge/memoriaTrueforge.d.ts +131 -0
  103. package/dist/agent/motores/trueforge/metricasTrueforge.d.ts +45 -0
  104. package/dist/agent/motores/trueforge/modeloExterno.d.ts +9 -0
  105. package/dist/agent/motores/trueforge/modeloLangchain.d.ts +69 -0
  106. package/dist/agent/motores/trueforge/notas.d.ts +48 -0
  107. package/dist/agent/motores/trueforge/proponerTareas.d.ts +30 -0
  108. package/dist/agent/motores/trueforge/recortes.d.ts +47 -0
  109. package/dist/agent/motores/trueforge/resumenSeguro.d.ts +33 -0
  110. package/dist/agent/motores/trueforge/sesionTrueforge.d.ts +273 -0
  111. package/dist/agent/motores/trueforge/sesionTrueforge.js +32 -15
  112. package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -1
  113. package/dist/agent/motores/trueforge/skillsTrueforge.d.ts +16 -0
  114. package/dist/agent/motores/trueforge/toolsDeConectores.d.ts +36 -0
  115. package/dist/agent/motores/trueforge/toolsDeFichero.d.ts +146 -0
  116. package/dist/agent/motores/trueforge/toolsPropias.d.ts +38 -0
  117. package/dist/agent/motores/trueforge/traerDeStitch.d.ts +63 -0
  118. package/dist/agent/motores/trueforge/trueforge.d.ts +35 -0
  119. package/dist/agent/navegacion/estilosEnDisco.d.ts +41 -0
  120. package/dist/agent/navegacion/hechosEnDisco.d.ts +19 -0
  121. package/dist/agent/navegacion/indiceEnDisco.d.ts +50 -0
  122. package/dist/agent/navegacion/modeloDeProyecto.d.ts +86 -0
  123. package/dist/agent/planesEnDisco.d.ts +18 -0
  124. package/dist/agent/publicarPlan.d.ts +20 -0
  125. package/dist/agent/raizDelPaquete.d.ts +9 -0
  126. package/dist/agent/remoto/ngrokEnMaquina.d.ts +44 -0
  127. package/dist/agent/remoto/puenteWebSocket.d.ts +59 -0
  128. package/dist/agent/remoto/tunelNgrok.d.ts +31 -0
  129. package/dist/agent/renombrarSobre.d.ts +14 -0
  130. package/dist/agent/sesiones/adjuntosDeSesion.d.ts +64 -0
  131. package/dist/agent/sesiones/baseDeFichero.d.ts +9 -0
  132. package/dist/agent/sesiones/checkpointer.d.ts +146 -0
  133. package/dist/agent/sesiones/git.d.ts +66 -0
  134. package/dist/agent/sesiones/gitSync.d.ts +264 -0
  135. package/dist/agent/sesiones/memoriaDeHilo.d.ts +4 -0
  136. package/dist/agent/sesiones/modeloDelCambio.d.ts +7 -0
  137. package/dist/agent/sesiones/parcheEnTexto.d.ts +9 -0
  138. package/dist/agent/sesiones/sesionGit.d.ts +155 -0
  139. package/dist/agent/subagentes/actividadDeCodex.d.ts +8 -0
  140. package/dist/agent/subagentes/agentesEnDisco.d.ts +198 -0
  141. package/dist/agent/subagentes/consumoExterno.d.ts +83 -0
  142. package/dist/agent/subagentes/ejecutableEnWindows.d.ts +53 -0
  143. package/dist/agent/subagentes/escrituraDeCodex.d.ts +94 -0
  144. package/dist/agent/subagentes/escrituraDeOpencode.d.ts +67 -0
  145. package/dist/agent/subagentes/escrituraExterna.d.ts +419 -0
  146. package/dist/agent/subagentes/pluginDeSkills.d.ts +84 -0
  147. package/dist/agent/subagentes/subagenteCodex.d.ts +76 -0
  148. package/dist/agent/subagentes/subagenteExterno.d.ts +169 -0
  149. package/dist/agent/subagentes/subagenteOpencode.d.ts +126 -0
  150. package/dist/agent/tareas/aumentador.d.ts +99 -0
  151. package/dist/agent/tareas/juezDeTarea.d.ts +64 -0
  152. package/dist/agent/tareas/reflejoEnElGestor.d.ts +38 -0
  153. package/dist/agent/tareas/sondeoDelGestor.d.ts +49 -0
  154. package/dist/agent/tareas/tareasEnDisco.d.ts +141 -0
  155. package/dist/agent/trazaDeErroresEnDisco.d.ts +10 -0
  156. package/dist/agent/turno/depuracion.d.ts +1 -0
  157. package/dist/agent/turno/diagnosticoDeTools.d.ts +124 -0
  158. package/dist/agent/turno/ficherosDelProyecto.d.ts +10 -0
  159. package/dist/agent/turno/guionizado.d.ts +18 -0
  160. package/dist/agent/turno/informeDeTraza.d.ts +220 -0
  161. package/dist/agent/turno/inspectorDePrompt.d.ts +150 -0
  162. package/dist/agent/turno/instantanea.d.ts +16 -0
  163. package/dist/agent/turno/interrupts.d.ts +54 -0
  164. package/dist/agent/turno/juezDelTurnoConModelo.d.ts +26 -0
  165. package/dist/agent/turno/mensajes.d.ts +23 -0
  166. package/dist/agent/turno/normalizar.d.ts +15 -0
  167. package/dist/agent/turno/puente.d.ts +196 -0
  168. package/dist/agent/turno/registroDeFallos.d.ts +39 -0
  169. package/dist/agent/turno/resumenDeContexto.d.ts +269 -0
  170. package/dist/agent/turno/resumenDeTool.d.ts +33 -0
  171. package/dist/agent/turno/rubrica.d.ts +35 -0
  172. package/dist/agent/turno/sesionReal.d.ts +89 -0
  173. package/dist/agent/turno/textoDeTool.d.ts +19 -0
  174. package/dist/agent/turno/turnoReal.d.ts +210 -0
  175. package/dist/agent/turno/verificacion.d.ts +85 -0
  176. package/dist/agent/turno/verificador.d.ts +66 -0
  177. package/dist/bin.d.ts +2 -0
  178. package/dist/cli/acuseDeModelo.d.ts +18 -0
  179. package/dist/cli/aprobar.d.ts +162 -0
  180. package/dist/cli/config.d.ts +17 -0
  181. package/dist/cli/consola.d.ts +473 -0
  182. package/dist/cli/describe.d.ts +7 -0
  183. package/dist/cli/doctor.d.ts +8 -0
  184. package/dist/cli/fuentesDeDisco.d.ts +25 -0
  185. package/dist/cli/main.d.ts +291 -0
  186. package/dist/cli/markdown.d.ts +126 -0
  187. package/dist/cli/panel.d.ts +38 -0
  188. package/dist/cli/podar.d.ts +38 -0
  189. package/dist/cli/run.d.ts +30 -0
  190. package/dist/cli/spinner.d.ts +37 -0
  191. package/dist/cli/stdio.d.ts +94 -0
  192. package/dist/cli/tema.d.ts +68 -0
  193. package/dist/cli/tokens.d.ts +16 -0
  194. package/dist/cli/traza.d.ts +19 -0
  195. package/dist/cli/tui/app.d.ts +23 -0
  196. package/dist/cli/tui/aprobarTui.d.ts +46 -0
  197. package/dist/cli/tui/barra.d.ts +43 -0
  198. package/dist/cli/tui/correrTui.d.ts +119 -0
  199. package/dist/cli/tui/entrada.d.ts +14 -0
  200. package/dist/cli/tui/filas.d.ts +13 -0
  201. package/dist/cli/tui/logo.d.ts +20 -0
  202. package/dist/cli/tui/pielTui.d.ts +15 -0
  203. package/dist/cli/tui/raton.d.ts +68 -0
  204. package/dist/cli/tui/sidebar.d.ts +63 -0
  205. package/dist/cli/tui/store.d.ts +102 -0
  206. package/dist/cli/tui/tarjeta.d.ts +8 -0
  207. package/dist/cli/tui/temaInk.d.ts +67 -0
  208. package/dist/cli/tui/transcript.d.ts +32 -0
  209. package/dist/cli/verify.d.ts +9 -0
  210. package/dist/cli/wizardInicial.d.ts +59 -0
  211. package/dist/core/actos.d.ts +437 -0
  212. package/dist/core/adjuntos.d.ts +77 -0
  213. package/dist/core/agentes.d.ts +353 -0
  214. package/dist/core/analisisDeSesion.d.ts +63 -0
  215. package/dist/core/aprendido.d.ts +41 -0
  216. package/dist/core/artefactos.d.ts +74 -0
  217. package/dist/core/atributosXone.d.ts +53 -0
  218. package/dist/core/bitacora.d.ts +21 -0
  219. package/dist/core/cloudstudio.d.ts +168 -0
  220. package/dist/core/codificacion.d.ts +81 -0
  221. package/dist/core/comandoExterno.d.ts +49 -0
  222. package/dist/core/compararCapturas.d.ts +136 -0
  223. package/dist/core/conectores.d.ts +296 -0
  224. package/dist/core/config.d.ts +148 -0
  225. package/dist/core/contextos.d.ts +54 -0
  226. package/dist/core/convertirAP.d.ts +56 -0
  227. package/dist/core/copiaDeAvd.d.ts +44 -0
  228. package/dist/core/cssBienFormado.d.ts +22 -0
  229. package/dist/core/deps.d.ts +28 -0
  230. package/dist/core/descargas.d.ts +61 -0
  231. package/dist/core/descripcionDePantalla.d.ts +121 -0
  232. package/dist/core/descriptoresDeApp.d.ts +108 -0
  233. package/dist/core/diagnosticoDeNode.d.ts +51 -0
  234. package/dist/core/diff.d.ts +26 -0
  235. package/dist/core/diffDeColecciones.d.ts +54 -0
  236. package/dist/core/disenoVinculado.d.ts +17 -0
  237. package/dist/core/dispositivoDeSesion.d.ts +22 -0
  238. package/dist/core/dispositivoElegido.d.ts +17 -0
  239. package/dist/core/dispositivos.d.ts +469 -0
  240. package/dist/core/entrega.d.ts +341 -0
  241. package/dist/core/entrelazar.d.ts +48 -0
  242. package/dist/core/esfuerzo.d.ts +120 -0
  243. package/dist/core/esqueleto.d.ts +38 -0
  244. package/dist/core/estiloMedido.d.ts +70 -0
  245. package/dist/core/estilos.d.ts +76 -0
  246. package/dist/core/events.d.ts +218 -0
  247. package/dist/core/exportacion.d.ts +88 -0
  248. package/dist/core/fallos.d.ts +79 -0
  249. package/dist/core/fondosSvg.d.ts +115 -0
  250. package/dist/core/fotoDeColecciones.d.ts +45 -0
  251. package/dist/core/fuentes.d.ts +96 -0
  252. package/dist/core/geometriaDePantalla.d.ts +171 -0
  253. package/dist/core/gestorDeTareas.d.ts +295 -0
  254. package/dist/core/hechosDelProyecto.d.ts +70 -0
  255. package/dist/core/hotswap.d.ts +30 -0
  256. package/dist/core/iconos.d.ts +86 -0
  257. package/dist/core/identidadDeProveedor.d.ts +20 -0
  258. package/dist/core/idiomaDeLaRespuesta.d.ts +26 -0
  259. package/dist/core/imagenesDeDocumento.d.ts +40 -0
  260. package/dist/core/jsParaRhino.d.ts +3 -0
  261. package/dist/core/juezDelTurno.d.ts +95 -0
  262. package/dist/core/logDeDispositivo.d.ts +67 -0
  263. package/dist/core/memoria.d.ts +18 -0
  264. package/dist/core/metodoDeComparacionVisual.d.ts +20 -0
  265. package/dist/core/modelos.d.ts +198 -0
  266. package/dist/core/modoDeEscritura.d.ts +155 -0
  267. package/dist/core/motor.d.ts +43 -0
  268. package/dist/core/motoresLocales.d.ts +113 -0
  269. package/dist/core/mudanzaDeWorkspace.d.ts +112 -0
  270. package/dist/core/navegacion.d.ts +172 -0
  271. package/dist/core/notify.d.ts +77 -0
  272. package/dist/core/nucleoXone.d.ts +28 -0
  273. package/dist/core/panorama.d.ts +68 -0
  274. package/dist/core/paqueteDeSoporte.d.ts +100 -0
  275. package/dist/core/planDeSubida.d.ts +56 -0
  276. package/dist/core/planes.d.ts +53 -0
  277. package/dist/core/podaDeCheckpoint.d.ts +75 -0
  278. package/dist/core/ports.d.ts +1034 -0
  279. package/dist/core/puedeLanzarse.d.ts +181 -0
  280. package/dist/core/puertosDeAvd.d.ts +59 -0
  281. package/dist/core/recargaEnCaliente.d.ts +52 -0
  282. package/dist/core/referenciasDeImagen.d.ts +36 -0
  283. package/dist/core/remoto.d.ts +76 -0
  284. package/dist/core/repartoDeEncargo.d.ts +80 -0
  285. package/dist/core/rubrica.d.ts +78 -0
  286. package/dist/core/rutaVirtual.d.ts +29 -0
  287. package/dist/core/selectorDeCarpeta.d.ts +59 -0
  288. package/dist/core/serieDeEscrituras.d.ts +58 -0
  289. package/dist/core/settings.d.ts +421 -0
  290. package/dist/core/shellDeAgente.d.ts +177 -0
  291. package/dist/core/skills.d.ts +129 -0
  292. package/dist/core/stitch.d.ts +114 -0
  293. package/dist/core/tareas.d.ts +412 -0
  294. package/dist/core/tareasDelPlan.d.ts +123 -0
  295. package/dist/core/tareasEnElGestor.d.ts +117 -0
  296. package/dist/core/textos.d.ts +8 -0
  297. package/dist/core/topeAgotado.d.ts +55 -0
  298. package/dist/core/traerDeLaMaquina.d.ts +33 -0
  299. package/dist/core/trazaDeErrores.d.ts +83 -0
  300. package/dist/core/tunel.d.ts +45 -0
  301. package/dist/core/turno.d.ts +154 -0
  302. package/dist/core/validacionDeEscritura.d.ts +95 -0
  303. package/dist/core/verificacionDeSubida.d.ts +14 -0
  304. package/dist/core/version.d.ts +35 -0
  305. package/dist/core/xmlBienFormado.d.ts +23 -0
  306. package/dist/core/zipDeAdjunto.d.ts +28 -0
  307. package/dist/core/zipDeSkill.d.ts +74 -0
  308. package/dist/lib/tareaAutonoma.d.ts +36 -0
  309. package/dist/lib/tareaAutonoma.js +259 -0
  310. package/dist/lib/tareaAutonoma.js.map +1 -0
  311. package/dist/lib.d.ts +31 -0
  312. package/dist/lib.js +28 -0
  313. package/dist/lib.js.map +1 -0
  314. package/dist/vendor/hitl.d.ts +69 -0
  315. package/dist/vendor/skillLoaders/catalog.d.ts +27 -0
  316. package/dist/vendor/sqliteSaver.d.ts +22 -0
  317. package/dist/vendor/tokenTracking.d.ts +22 -0
  318. package/dist/web/servidor/arranque.d.ts +1372 -0
  319. package/dist/web/servidor/consolaDeTarea.d.ts +166 -0
  320. package/dist/web/servidor/consolaWeb.d.ts +142 -0
  321. package/dist/web/servidor/corredorDeTareas.d.ts +395 -0
  322. package/dist/web/servidor/datosDeCierre.d.ts +4 -0
  323. package/dist/web/servidor/interrupcion.d.ts +39 -0
  324. package/dist/web/servidor/pielWeb.d.ts +32 -0
  325. package/dist/web/servidor/puenteRemoto.d.ts +80 -0
  326. package/dist/web/servidor/servidor.d.ts +53 -0
  327. package/dist/web/servidor/sesiones.d.ts +342 -0
  328. package/dist/web/servidor/soporte.d.ts +65 -0
  329. package/dist/web/servidor/soporte.js +2 -0
  330. package/dist/web/servidor/soporte.js.map +1 -1
  331. package/dist/web/servidor/transporte.d.ts +2751 -0
  332. package/dist/web/servidor/vestibulo.d.ts +952 -0
  333. package/dist/web/servidor/visorOpenui.d.ts +33 -0
  334. package/package.json +9 -1
@@ -0,0 +1,2751 @@
1
+ /**
2
+ * SSE del servidor al cliente, `POST /accion` del cliente al servidor.
3
+ *
4
+ * No es WebSocket a propósito: aquí hay UN stream, no un mux de streams lógicos con
5
+ * decenas de clientes hablando a la vez. Con SSE la reconexión es trivial porque el
6
+ * servidor guarda la lista de actos y la reemite entera; con WS habría que reimplementar
7
+ * generaciones y reanudación para no ganar nada.
8
+ *
9
+ * La regla que gobierna este fichero: **el contenido de fichero y el diff viajan en UN
10
+ * solo mensaje**, `aprobacion`, que es el paso donde el humano DECIDE sobre ellos. Ni los
11
+ * actos ni la traza de emisión los tocan, y por eso `emitir` no registra ese mensaje: lo
12
+ * guarda quien lo tiene en vuelo, que lo suelta en cuanto hay decisión.
13
+ */
14
+ import type { PlanEnDisco } from "../../agent/planesEnDisco.js";
15
+ import type { EsquemaDelProyecto, MapeoDeEstados, TareaDelGestor, TransicionDelGestor, Vinculo } from "../../core/gestorDeTareas.js";
16
+ import type { CambiosDeUnaColeccion } from "../../core/diffDeColecciones.js";
17
+ import type { FotoDeColecciones } from "../../core/fotoDeColecciones.js";
18
+ import type { InformeDeDispositivos, NombreDeHerramienta } from "../../core/dispositivos.js";
19
+ import type { AjustesDeDispositivos } from "../../core/settings.js";
20
+ import type { Acto, ConsumoDeTurno, ConsumoPorModelo } from "../../core/actos.js";
21
+ import type { Tarea } from "../../core/tareas.js";
22
+ import type { PendienteDeAprobacion } from "../../core/events.js";
23
+ import type { LineaDeDiff } from "../../core/diff.js";
24
+ import type { SelectorDeConsola } from "../../cli/consola.js";
25
+ import type { DecisionDeConsola } from "../../cli/aprobar.js";
26
+ import type { OpcionDeEntorno, PasoDelVestibulo } from "./vestibulo.js";
27
+ import type { DispositivoElegido } from "./sesiones.js";
28
+ import type { Esfuerzo } from "../../core/esfuerzo.js";
29
+ import type { ConectorDelCable, DefinicionDeConector, FilaDeCatalogo } from "../../core/conectores.js";
30
+ import type { EstadoDeMotorLocal } from "../../core/motoresLocales.js";
31
+ import type { DiagnosticoDeNode } from "../../core/diagnosticoDeNode.js";
32
+ /** El vínculo del proyecto con su gestor, tal como cruza el cable: el del `config.json` más el
33
+ * nombre del sitio si esta ejecución ya lo sabe (lo dijo `sitios()`), y el del PROYECTO si ya
34
+ * lo nombró el gestor (IXCODE-15: en Notion `proyecto` es un `collection://…` que no se lee).
35
+ * Ausente = no consta. */
36
+ /** El vínculo tal como cruza: con su mapeo de estados y el interruptor del disparo (la puerta 2), que se editan en el panel. */
37
+ export type VinculoDelCable = Vinculo & {
38
+ nombreDelSitio?: string;
39
+ nombreDelProyecto?: string;
40
+ estados?: MapeoDeEstados;
41
+ automatico?: boolean;
42
+ revisarEncargo?: boolean;
43
+ };
44
+ /**
45
+ * El informe de `core/dispositivos.ts`. **La `ruta` de cada herramienta solo cruza para
46
+ * `adb`/`emulator`** —la excepción declarada, igual que el workspace— y se quita en el
47
+ * código (`arranque.ts#sinRutas`) para `xcrun`/`devicectl`, que se quedan en el host: este
48
+ * cable puede ir por un túnel (`--anfitrion`) y esas dos nunca tuvieron un motivo para
49
+ * cruzarlo.
50
+ */
51
+ export type InformeDeDispositivosDelCable = InformeDeDispositivos;
52
+ /**
53
+ * Una sesión tal como viaja dentro del alta de un proyecto. **Sin la raíz**: la fila de la
54
+ * barra no la pinta, y una ruta de la máquina no cruza este cable (`sinRutas`).
55
+ * Redeclarada en `apps/web/src/tipos.ts`, como `TareaDelCable`.
56
+ *
57
+ * Tiene nombre propio, y no es cosmético: `tipos.test.ts` comprueba que los campos de los dos
58
+ * lados son los MISMOS, y una fila escrita dentro de otra interfaz no se puede comparar —
59
+ * el test la ve como parte del alta y no como un tipo. Nombrarla es lo que hace posible que
60
+ * un campo que se añada en el host y no en el cliente salga rojo en vez de quedarse mudo.
61
+ */
62
+ export interface SesionDelCable {
63
+ id: string;
64
+ titulo: string;
65
+ /**
66
+ * Cuándo se tocó por última vez, en ISO. Es lo que ordena la lista y lo que la barra pinta
67
+ * a la derecha de cada fila. Ausente = el índice no lo dice (una entrada corrupta): la fila
68
+ * se pinta sin sello y se ordena la última.
69
+ */
70
+ ultimoTurno?: string;
71
+ /**
72
+ * Esta conversación la abrió una TAREA de fondo, no una persona (`EntradaIndice.tarea`).
73
+ * Viaja un booleano y no el id: la fila lleva una marca y no el nombre de la tarea, así que
74
+ * el id se queda en el host.
75
+ *
76
+ * **Ausente es «no consta», no «es un chat»**: no la lleva ninguna sesión anterior a esta
77
+ * marca. Se pinta liso porque liso es lo conservador, no porque conste que sea de una
78
+ * persona — igual que `compartido` en un proyecto.
79
+ */
80
+ deTarea?: true;
81
+ /**
82
+ * Esa conversación tiene un turno EN MARCHA ahora mismo, sea o no la que se está mirando.
83
+ * Es lo que hace visible que cambiar de sesión ya no interrumpe nada: el agente sigue
84
+ * trabajando en la de antes y la barra lo dice.
85
+ *
86
+ * Va en el ALTA y no en un mensaje propio porque el alta se reemite en los dos flancos de
87
+ * cada turno —de cualquiera de las consolas vivas—, que es exactamente cuando esto cambia.
88
+ *
89
+ * **Ausente es «no consta que esté trabajando»**, y eso incluye dos casos que no se pueden
90
+ * distinguir desde aquí: la sesión no tiene consola viva, o la tiene y está ociosa. Para lo
91
+ * que la barra pinta da igual; afirmar lo contrario, no.
92
+ */
93
+ trabajando?: true;
94
+ /**
95
+ * Lo que ha gastado la sesión ENTERA: los deltas de sus turnos, sumados. Es un ACUMULADO,
96
+ * así que solo crece, y no lleva `ventana` —«cuánto ocupa el historial ahora» es una
97
+ * pregunta de la sesión ABIERTA, y congelada en una cerrada sería un «ahora» de hace días
98
+ * (lo quita `core/actos.ts#acumularTotales`)—.
99
+ *
100
+ * **Ausente es «no consta», nunca cero**: no lo trae ninguna sesión anterior a esto que la
101
+ * siembra no haya alcanzado. Un `{0,0}` afirmaría que la sesión salió gratis, y con él la
102
+ * barra pintaría un `↑0 ↓0` que nadie ha medido.
103
+ */
104
+ consumo?: ConsumoDeTurno;
105
+ /**
106
+ * La CLAVE del ticket de Jira al que quedó ligada esta sesión (`"IXCODE-12"`), si tiene
107
+ * uno (`EntradaIndice.ticket`, IXCODE-11). Solo la clave, y no el objeto entero: es lo
108
+ * único que la fila de la barra tiene que pintar; el conector y el sitio se quedan en el
109
+ * host hasta que algo necesite componer la URL pública.
110
+ */
111
+ ticket?: string;
112
+ /**
113
+ * IXCODE-15: el CONECTOR de ese ticket (`"jira"`, `"notion"`), solo con `ticket`. Es con quien
114
+ * se cierra la tarea —no con el gestor vinculado ahora—, y de él sale el rótulo «Cerrar en …».
115
+ */
116
+ ticketConector?: string;
117
+ }
118
+ /**
119
+ * Las seis fases de un lanzamiento, EN ORDEN, y los cinco estados en que puede estar.
120
+ *
121
+ * **Se declaran aquí, en el cable, y no se importan de `agent/dispositivos/lanzamientoEnMaquina.ts`**, que es
122
+ * quien las recorre. El motivo es el de siempre en este fichero: el cable tiene su vocabulario
123
+ * CERRADO, y quien lo cierra es esta constante — la lista blanca del store del cliente y la
124
+ * validación del servidor se escriben contra ESTA lista, así que un valor que no esté aquí no
125
+ * llega a la pantalla. Importarlas ataría el contrato del cable al módulo que hoy lo cumple, y
126
+ * el día que ese módulo añada una fase el cable la aceptaría sin que nadie hubiera decidido si
127
+ * el cliente sabe pintarla.
128
+ *
129
+ * **Y por eso mismo hay un test que las ata** (`arranque.test.ts`: «las fases del cable son las
130
+ * que corre la máquina»): la lista de aquí no puede quedarse corta respecto de la de allí, o el
131
+ * recorrido se quedaría sin emitir justo la fase que alguien acaba de añadir.
132
+ *
133
+ * **`corriendo` no está en `EstadoDeLanzamiento` de la máquina, y aquí sí.** Allí el estado es un
134
+ * DESENLACE —cuatro formas de acabar—, porque `lanzarEnDispositivo` devuelve un resultado; aquí
135
+ * hay además un RECORRIDO EN VIVO, que es lo que permite que la pestaña enseñe en qué fase va
136
+ * en vez de un botón apagado sin explicación.
137
+ */
138
+ export declare const FASES_DEL_LANZAMIENTO: readonly ["comprobando", "empaquetando", "subiendo", "reiniciando", "lanzando", "comprobando-arranque"];
139
+ export type FaseDelLanzamiento = (typeof FASES_DEL_LANZAMIENTO)[number];
140
+ export declare const ESTADOS_DEL_LANZAMIENTO: readonly ["corriendo", "ok", "fallo", "cancelada", "colgada"];
141
+ export type EstadoDelLanzamiento = (typeof ESTADOS_DEL_LANZAMIENTO)[number];
142
+ export type MensajeAlCliente = {
143
+ clase: "acto";
144
+ acto: Acto;
145
+ }
146
+ /**
147
+ * SUSTITUYE el último acto del cliente. Existe porque `pielWeb.alActo` avisa también
148
+ * de ACTUALIZACIONES: el cierre de una racha de tools reemplaza a su apertura dentro
149
+ * del mismo acto `herramientas` (`core/actos.ts#conLineaDeTool`). Un cliente que
150
+ * anexara a ciegas enseñaría las dos líneas para siempre.
151
+ *
152
+ * Solo se emite cuando el acto que cambia ES el último; si algo se escribió después,
153
+ * el transporte manda una `reemision` entera — sustituir «el último» tocaría otro acto.
154
+ */
155
+ | {
156
+ clase: "sustitucion";
157
+ acto: Acto;
158
+ }
159
+ /** El transcript completo: lo que recibe quien (re)conecta, y el arreglo de cualquier desajuste. */
160
+ | {
161
+ clase: "reemision";
162
+ actos: Acto[];
163
+ }
164
+ /**
165
+ * La sesión remota: el interruptor (`habilitado`, de `settings.remoto` o `XONECODE_REMOTO=1`, que
166
+ * es `porEntorno` y no se apaga desde Ajustes) y el estado del puente. La `url` lleva
167
+ * el SECRETO en el fragmento: es el TERCER secreto del cable, tras `leerSecreto` y el `codigo` de `motorLocal`, y por eso
168
+ * `remoto` no está en la lista de salida del puente (`core/remoto.ts`).
169
+ */
170
+ | {
171
+ clase: "remoto";
172
+ estado: "apagada" | "abriendo" | "activa" | "reconectando" | "error";
173
+ habilitado?: boolean;
174
+ porEntorno?: true;
175
+ url?: string;
176
+ moviles?: number;
177
+ motivo?: string;
178
+ /** Por dónde sale: el servidor manda siempre la vía en vigor; un cliente que no la reciba (servidor antiguo) la lee como ngrok. */
179
+ via?: "servidor" | "ngrok";
180
+ /**
181
+ * Lo medido de ngrok, solo si el diálogo lo necesita. `cuenta` = hay authtoken en SU
182
+ * configuración (nunca el token ni la ruta, que no cruzan). `instalado` = el SDK de ngrok, que viene con
183
+ * xonecode, CARGA: no hay receta para instalarlo aparte.
184
+ * `motivo` = por qué falló la última acción de ngrok (authtoken o dominio): SOLO un texto
185
+ * fijo nuestro (`MOTIVOS_DEL_TUNEL` o el rechazo del dominio), nunca lo tecleado ni lo que
186
+ * contestó ngrok. Lo quita la siguiente acción que sale bien.
187
+ */
188
+ ngrok?: {
189
+ instalado: boolean;
190
+ cuenta: boolean;
191
+ dominio?: string;
192
+ motivo?: string;
193
+ };
194
+ }
195
+ /**
196
+ * El saludo, SUELTO del `alta`. `agent/config/persona.ts#nombreDePersona` no depende de
197
+ * ninguna cuenta ni de ningún login —es `git config`/`os.userInfo()`, local y ya
198
+ * resuelto al construir el vestíbulo—, pero el `alta` solo se manda DESPUÉS de que
199
+ * `conducirCuenta()` termina (`arranque.ts#anunciarAlta`), que puede tardar lo que
200
+ * tarde un humano en elegir modelo y teclear una clave. Sin este mensaje, medido: la
201
+ * pantalla decía «Hola» a secas durante TODO el paso de cuenta, con el nombre ya
202
+ * resuelto y sin ningún sitio por el que viajar hasta que la cuenta se resolviera —
203
+ * un saludo que se sabe y no se dice. Se manda una vez, al conectar, antes de
204
+ * `conducirCuenta()`. `alta.nombre` (más abajo) sigue llevando el MISMO dato — no
205
+ * porque quede alguna conexión sin ver este mensaje (el SSE arranca de cero en cada
206
+ * conexión y siempre lo manda primero), sino porque quitarlo de `alta` cambiaría ese
207
+ * contrato y su test, y eso no es parte de este arreglo.
208
+ */
209
+ | {
210
+ clase: "bienvenida";
211
+ nombre?: string;
212
+ }
213
+ /**
214
+ * Una pregunta a la que hay que contestar.
215
+ *
216
+ * **`decision` es la FORMA, y ausente significa texto libre**, que es lo que ha sido
217
+ * siempre: el cliente pinta un campo y lo que se teclea vuelve como `respuesta`. Con
218
+ * `decision` puesta la respuesta es sí o no y no se teclea nada — la tarjeta enseña
219
+ * `lineas` (el plan de la subida, las mismas líneas que ya fueron por `acto` de sistema)
220
+ * y dos botones, y contesta por la MISMA puerta de siempre: `"s"` autoriza y el resto
221
+ * rechaza (`interpretAnswer`).
222
+ *
223
+ * No se deduce del enunciado: el `[s/N]` es sintaxis, y una piel rica que lo leyera para
224
+ * decidir si pone botones se rompería el día que alguien reescriba el prompt — con un
225
+ * editor donde hacía falta un botón, o con dos botones sobre una pregunta abierta, y sin
226
+ * ningún error que lo delate.
227
+ */
228
+ | {
229
+ clase: "pregunta";
230
+ texto: string;
231
+ decision?: DecisionDeConsola;
232
+ } | {
233
+ clase: "selector";
234
+ selector: SelectorDeConsola;
235
+ }
236
+ /**
237
+ * Los modelos: cuál está en vigor, cuál queda por defecto, y qué se puede elegir.
238
+ *
239
+ * **Son DOS preguntas y por eso son dos campos.** `actual` es lo que resuelve el papel
240
+ * `trabajo` con las fuentes de la sesión ABIERTA, no lo que diga un fichero: `/modelo`
241
+ * cambia el modelo en caliente sin escribir nada, así que releer la configuración
242
+ * contaría lo de antes. Ausente = no hay sesión de proyecto y por tanto no hay modelo en
243
+ * vigor que afirmar — el cliente enseña «Elige modelo» en vez de inventarse una fila, que
244
+ * es la regla del harness de DeepSeek: «no stale row is synthesized».
245
+ *
246
+ * `porDefecto` es otra cosa: el que usarán las sesiones NUEVAS, resuelto contra el
247
+ * `config.json` global. Existe porque el compositor y Ajustes no preguntan lo mismo —una
248
+ * sesión puede llevar encima un `/modelo` en caliente y el defecto seguir siendo otro—, y
249
+ * meterlos en un campo solo enseñaría una de las dos como si fuera la otra. Y se manda
250
+ * TAMBIÉN sin sesión abierta, que es justo donde se configura: sin él, Ajustes diría «sin
251
+ * elegir» sobre una máquina que sí tiene un defecto escrito.
252
+ *
253
+ * `modelos` de un proveedor viaja SOLO cuando alguien lo ha pedido (`clase: "catalogo"`):
254
+ * el catálogo es una llamada de red por proveedor y consultarlos todos al conectar sería
255
+ * gastar cinco peticiones para pintar un menú que quizá nadie abra. `error` es el fallo
256
+ * de ESE proveedor y no tumba a los demás — se lista inservible y el resto sigue
257
+ * elegible.
258
+ */
259
+ | {
260
+ clase: "modelos";
261
+ actual?: string;
262
+ porDefecto?: string;
263
+ proveedores: ProveedorDeModelos[];
264
+ /**
265
+ * Qué esfuerzo admite el modelo EN VIGOR y cuál está puesto en la sesión.
266
+ *
267
+ * Viaja con los modelos y no en un mensaje propio porque cambia en los mismos
268
+ * instantes: los niveles dependen del modelo, así que un `/modelo` que no lo trajera
269
+ * dejaría la pastilla ofreciendo los del modelo de antes. Mismo motivo por el que la
270
+ * ventana de contexto viaja dentro de `consumo`.
271
+ *
272
+ * Ausente = no hay nada que afirmar (sin sesión, o el modelo no lo admite), y
273
+ * entonces la pastilla no se pinta.
274
+ */
275
+ esfuerzo?: {
276
+ niveles: Esfuerzo[];
277
+ actual?: Esfuerzo;
278
+ nota?: string;
279
+ };
280
+ }
281
+ /**
282
+ * Los proyectos de UN entorno registrado, en respuesta a la acción «proyectos» de un
283
+ * mensaje de entorno. Lleva el `entorno` dentro porque el cliente los guarda por
284
+ * entorno: son las casillas de una pestaña concreta de Ajustes, y una lista sin dueño se
285
+ * acabaría pintando bajo el nombre de otro servidor.
286
+ *
287
+ * **`proyectos` ausente y `error` puesto no es una lista vacía**: «no se pudo preguntar»
288
+ * no es «este entorno no tiene proyectos», y la pestaña tiene que poder decir lo primero
289
+ * en vez de afirmar lo segundo. El fallo es de ESE entorno y no tumba a los demás —la
290
+ * regla del catálogo de modelos: un desvío, no un callejón—, así que tampoco se pinta un
291
+ * aviso global ni se toca el entorno activo.
292
+ *
293
+ * No va en el `alta` a propósito, aunque `registrados` viaje ahí: el alta se reemite en
294
+ * los dos flancos de cada turno, y meter estas listas dentro obligaría a cachearlas en el
295
+ * proceso. Sin caché hay UNA sola fuente, así que la pestaña no puede contradecir a la
296
+ * barra cuando alguien cree un proyecto en Studio.
297
+ */
298
+ | {
299
+ clase: "proyectosDeEntorno";
300
+ entorno: string;
301
+ proyectos?: ProyectoDeEntorno[];
302
+ error?: string;
303
+ }
304
+ /**
305
+ * Cómo fue el último alta o baja de proveedor personalizado.
306
+ *
307
+ * El motivo viaja EN un mensaje propio y no por `informar`, por lo mismo que el aviso
308
+ * del selector durante el alta: la ventana de ajustes no pinta el transcript, así que un
309
+ * fallo contado como acto de sistema sería mudo justo donde hay que leerlo. `hecho` es
310
+ * lo que deja al formulario cerrarse solo cuando la cosa salió bien.
311
+ */
312
+ | {
313
+ clase: "proveedor";
314
+ hecho: boolean;
315
+ motivo?: string;
316
+ }
317
+ /**
318
+ * Hay un turno EN VUELO, o dejó de haberlo.
319
+ *
320
+ * El cliente lo necesita para dos cosas que no puede deducir sin mentir: apagar el
321
+ * compositor mientras el agente trabaja —mandar una segunda petición encima solo la
322
+ * encola sin decirlo— y convertir la flecha de enviar en un botón de parar. Deducirlo de
323
+ * los actos (¿llegó un `fin` después del último `usuario`?) fallaría justo cuando importa:
324
+ * un turno que revienta no siempre deja `fin`.
325
+ */
326
+ /** `detenible`: el turno en marcha admite DETENER y replanificar. Ausente = no. */
327
+ | {
328
+ clase: "turno";
329
+ activo: boolean;
330
+ detenible?: true;
331
+ }
332
+ /**
333
+ * Lo que lleva consumido la sesión, en sus DOS cuentas.
334
+ *
335
+ * Separadas y no sumadas: los del grafo van contra la clave de API del usuario y los del
336
+ * agente externo contra su suscripción del producto. Sumar tokens es defendible; sumar su
337
+ * coste sería la cifra que miente, así que aquí solo viajan tokens y viajan aparte.
338
+ *
339
+ * Se emite en cada cambio y también al conectar, porque una pestaña que llega a mitad de
340
+ * sesión no vio los anteriores. Ausente = no consta (no hay sesión, o es el de pega) y
341
+ * entonces el cliente NO pinta un cero.
342
+ */
343
+ | {
344
+ clase: "consumo";
345
+ modelo: {
346
+ entrada: number;
347
+ salida: number;
348
+ cache: number;
349
+ };
350
+ externo: {
351
+ entrada: number;
352
+ salida: number;
353
+ cache: number;
354
+ };
355
+ /**
356
+ * Cuánto ocupa la VENTANA ahora, y su tope si se sabe. Otra pregunta que los
357
+ * acumulados: aquéllos dicen lo que la sesión ha costado y esto cuánto margen queda.
358
+ *
359
+ * `tope` ausente es «no se sabe», y entonces no se pinta denominador ni porcentaje —
360
+ * con Ollama no hay tope A PROPÓSITO (cada modelo local trae el suyo), y un
361
+ * porcentaje sobre un número inventado es una mentira con forma de cifra.
362
+ */
363
+ ventana: {
364
+ usado: number;
365
+ tope?: number;
366
+ };
367
+ /**
368
+ * Lo mismo, POR MODELO: un especialista puede correr en otro modelo que el raíz. Ausente =
369
+ * no consta (una sesión de antes, o un motor que no lo mide); lo gastado antes de medirlo
370
+ * llega bajo `SIN_DESGLOSE`, así que las filas suman el total.
371
+ */
372
+ porModelo?: ConsumoPorModelo;
373
+ }
374
+ /**
375
+ * Se está ABRIENDO algo: una sesión, o un proyecto que además hay que descargar.
376
+ *
377
+ * Lo dice el SERVIDOR y no lo deduce el cliente, por el mismo motivo que `turno`: solo
378
+ * este lado sabe cuándo empieza y cuándo acaba, y aquí el rango va de «unos cientos de
379
+ * milisegundos» (abrir una copia local: foto de git, checkpointer, sesiones) a «minutos»
380
+ * (descargar el proyecto entero). Deducirlo de que llegue un `alta` nuevo fallaría justo
381
+ * cuando importa: un fallo al abrir también anuncia alta, y una apertura sobre el
382
+ * proyecto que YA estaba activo no cambia nada en él.
383
+ *
384
+ * `activo: false` es el otro flanco y va en un `finally`, así que salir por un error
385
+ * también lo apaga — un indicador de actividad que se queda encendido para siempre es
386
+ * peor que no tenerlo.
387
+ */
388
+ | {
389
+ clase: "abriendo";
390
+ activo: boolean;
391
+ /** Qué se está abriendo, para poder señalarlo en su fila. Solo con `activo`. */
392
+ proyecto?: string;
393
+ sesion?: string;
394
+ /**
395
+ * El entorno que se está MUDANDO, cuando lo que viaja no es una apertura sino un
396
+ * cambio de entorno activo.
397
+ *
398
+ * Va aparte de `proyecto` y no en su lugar porque el cambio de entorno no abre nada
399
+ * del árbol: vacía la lista entera y la vuelve a traer del otro servidor. Y es un
400
+ * campo y no un `activo: true` pelado porque el cliente tiene que poder ENSEÑAR el
401
+ * que se ha pedido: sin eso el `<select>`, que va controlado por el `alta` —y el
402
+ * `alta` solo llega al final—, se queda clavado en el valor viejo durante toda la
403
+ * espera, y la elección se lee como que no ha entrado. Medido: 1,5 s.
404
+ */
405
+ entorno?: string;
406
+ /** Además hay que BAJARLO: es la espera larga, y la que hay que decir con palabras. */
407
+ descargando?: true;
408
+ }
409
+ /**
410
+ * Los subagentes dados de alta, para la ventana de ajustes.
411
+ *
412
+ * Se manda entero cada vez que cambia —son pocos y pequeños— en vez de mandar deltas:
413
+ * una lista de cinco elementos no justifica un protocolo de diferencias, y un delta
414
+ * perdido dejaría la ventana enseñando un agente que ya no existe.
415
+ *
416
+ * `problemas` son los `.md` que no se pudieron leer, con su motivo. Van por el cable y no
417
+ * solo al log del servidor porque quien los tiene que arreglar está mirando ESTA ventana:
418
+ * un agente que no aparece y nadie dice por qué se lee como que la aplicación lo perdió.
419
+ */
420
+ | {
421
+ clase: "agentes";
422
+ agentes: AgenteDelCable[];
423
+ problemas: string[];
424
+ }
425
+ /**
426
+ * Las skills en vigor, para la ventana de ajustes y para el editor de un subagente.
427
+ *
428
+ * Se manda entera cada vez que cambia —son pocas y el cuerpo solo viaja de las del
429
+ * usuario— en vez de mandar deltas, por lo mismo que `agentes`: un delta perdido dejaría
430
+ * la ventana enseñando una skill que ya no existe, y un subagente marcando una casilla que
431
+ * no tiene detrás ningún fichero.
432
+ *
433
+ * `problemas` son las carpetas que no se pudieron leer, con su motivo, y significa SOLO
434
+ * eso: que una del usuario tape a una de serie no es un problema, es la forma de afinarla
435
+ * sin editar donde el `npm install` la pisaría.
436
+ */
437
+ | {
438
+ clase: "skills";
439
+ skills: SkillDelCable[];
440
+ problemas: string[];
441
+ }
442
+ /**
443
+ * El cuerpo de UNA skill, pedido a mano (`clase: "cuerpoDeSkill"` del cliente).
444
+ *
445
+ * Va aparte y no dentro del `skills` por lo que ese tipo explica: las de serie son
446
+ * ficheros grandes y mandarlas todas en la ráfaga de bienvenida cuesta cientos de
447
+ * kilobytes para un formulario que nadie puede guardar. Aquí se paga solo la que se abre.
448
+ *
449
+ * `cuerpo` ausente = no se pudo leer, y entonces se DICE: una ficha que se abre en blanco
450
+ * se lee como que la skill está vacía.
451
+ */
452
+ | {
453
+ clase: "cuerpoDeSkill";
454
+ nombre: string;
455
+ cuerpo?: string;
456
+ error?: string;
457
+ }
458
+ /**
459
+ * La cola de tareas entera. Va a TODOS los clientes, como la foto de la máquina y por lo
460
+ * mismo: la cola es de la máquina. `corriendoAqui` es falso en el segundo proceso, y es lo
461
+ * que deja decir que este kanban no avanza.
462
+ *
463
+ * **Y `ejecutaOtroProceso` es la otra mitad, porque «no soy yo» y «no hay nadie»
464
+ * significan lo contrario**: el primero manda a esperar —una tarea creada aquí arrancará
465
+ * cuando ese proceso mire la cola— y el segundo dice que no va a pasar nada hasta que
466
+ * alguna consola tome el relevo. Con un solo booleano, el aviso mandaba a esperar a un
467
+ * proceso que puede no existir. **Ausente = no se sabe** (el cerrojo ni se pudo mirar, o
468
+ * esta ejecución no tiene corredor), y entonces no se afirma ninguna de las dos.
469
+ * **El pid no viaja**: es un dato de la máquina y no le dice nada a quien lo lee.
470
+ */
471
+ | {
472
+ clase: "tareas";
473
+ lista: TareaDelCable[];
474
+ concurrencia: number;
475
+ corriendoAqui: boolean;
476
+ ejecutaOtroProceso?: boolean;
477
+ }
478
+ /**
479
+ * Dónde se bajan las copias locales: la ruta ENTERA.
480
+ *
481
+ * **Es la excepción NOMBRADA a `sinRutas`**, y la única del cable. No se puede esquivar:
482
+ * el campo de Ajustes tiene que enseñar la carpeta que hay puesta, y una ruta que no se
483
+ * enseña no se puede comprobar ni elegir. Se probó a mandarla abreviada con `~` para que el
484
+ * caso normal no llevara el nombre de la cuenta del sistema, y no se sostiene: la cabecera
485
+ * de esta misma consola ya saluda por el nombre del usuario (`clase: "bienvenida"`), así que
486
+ * el `~` no tapaba nada que no estuviera ya y a cambio dejaba en pantalla una ruta que no se
487
+ * puede leer de un vistazo.
488
+ *
489
+ * Va en la ráfaga de bienvenida por lo mismo que los modelos y las skills: Ajustes se
490
+ * puede abrir en cuanto conecta, y un campo vacío se lee como «no hay nada puesto».
491
+ */
492
+ | {
493
+ clase: "workspace";
494
+ ruta: string;
495
+ puedeElegir?: boolean;
496
+ }
497
+ /**
498
+ * La carpeta que la persona eligió en el diálogo del sistema, para PONERLA EN EL CAMPO —
499
+ * no para guardarla. `ruta` AUSENTE = no eligió ninguna (canceló, o no se pudo abrir el
500
+ * diálogo), y entonces el campo se queda como estaba.
501
+ *
502
+ * **Elegir y guardar son dos actos, y por eso son dos mensajes.** Guardar desde el propio
503
+ * diálogo dejaría el ajuste escrito antes de que nadie hubiera leído la ruta entera, y en
504
+ * un campo cuyo único trabajo es que la ruta se pueda leer eso sería quitarle el trabajo.
505
+ */
506
+ | {
507
+ clase: "carpetaElegida";
508
+ ruta?: string;
509
+ }
510
+ /**
511
+ * Cómo va la MUDANZA de las copias al cambiar el workspace, y cómo acabó. `progreso` mientras
512
+ * dura (fase, y el proyecto por NOMBRE y entorno: ninguna ruta de la máquina), `resultado`
513
+ * una vez al final. Los dos ausentes no viajan nunca.
514
+ */
515
+ | {
516
+ clase: "mudanzaDeWorkspace";
517
+ progreso?: {
518
+ fase: "comprobar" | "copiar" | "verificar" | "borrar";
519
+ proyecto?: string;
520
+ entorno?: string;
521
+ indice?: number;
522
+ total?: number;
523
+ };
524
+ resultado?: {
525
+ estado: "hecho";
526
+ mudadas: number;
527
+ restos: string[];
528
+ avisos: string[];
529
+ } | {
530
+ estado: "rechazado";
531
+ motivo: string;
532
+ };
533
+ }
534
+ /**
535
+ * La casilla «Depurar» de Ajustes > General: si las dos trazas opt-in van encendidas sin
536
+ * variable de entorno. Va en la ráfaga de bienvenida por lo mismo que el workspace.
537
+ *
538
+ * `activa` es el valor YA RESUELTO (`core/settings.ts#depuracionActiva`): ausente en
539
+ * `settings.json` llega como `true`, la omisión de esta etapa de pruebas.
540
+ */
541
+ | {
542
+ clase: "depuracion";
543
+ activa: boolean;
544
+ }
545
+ /**
546
+ * El modo con que NACEN las sesiones nuevas en cualquier proyecto (IXCODE-31, Ajustes >
547
+ * General). Va en la ráfaga de bienvenida por lo mismo que «Depurar». Ya RESUELTO: ausente en
548
+ * `settings.json` llega como `supervisado`. El de cada proyecto, que gana sobre éste, viaja en
549
+ * la foto del resumen (`FotoDelResumen.modoDeEscritura`).
550
+ */
551
+ | {
552
+ clase: "modoPorDefecto";
553
+ modo: "supervisado" | "autonomo";
554
+ }
555
+ /**
556
+ * El aparato con que NACEN las sesiones nuevas, de una persona y de una tarea (IXCODE-51,
557
+ * Ajustes > General). Va en la ráfaga por lo mismo que el modo. Sin `dispositivo` = ninguno
558
+ * elegido, que no es lo mismo que no recibir el mensaje (entonces el control no se pinta).
559
+ */
560
+ | {
561
+ clase: "dispositivoPorDefecto";
562
+ dispositivo?: DispositivoElegido;
563
+ }
564
+ /**
565
+ * El catálogo de conectores MCP y los que esta consola tiene AÑADIDOS, para la sección de
566
+ * Ajustes. Va en la ráfaga de bienvenida por lo mismo que el workspace: Ajustes se puede
567
+ * abrir en cuanto conecta, y solo si la opción `conectores` está puesta — «un control sin
568
+ * dato detrás no se pinta».
569
+ *
570
+ * `catalogo` viaja SIN la `url` de cada servidor: no hace falta en pantalla, y así no hay
571
+ * una ruta remota que discutir por este cable.
572
+ *
573
+ * `ilegible`/`error` son los mismos campos que da `ServicioDeConectores.lista()`. Un fallo
574
+ * NO va por `informar`, que no llega al navegador desde el vestíbulo, y Ajustes se abre sin
575
+ * proyecto.
576
+ */
577
+ | {
578
+ clase: "conectores";
579
+ catalogo: FilaDeCatalogo[];
580
+ conectores: ConectorDelCable[];
581
+ desconocidos: string[];
582
+ ilegible?: true;
583
+ error?: string;
584
+ }
585
+ /**
586
+ * Cómo fue la última augmentación pedida (`{clase:"tarea", accion:"augmentar"}`): el
587
+ * encargo que propone el modelo, o por qué no se pudo. Nunca los dos a la vez.
588
+ */
589
+ | {
590
+ clase: "tarea";
591
+ accion: "augmentado";
592
+ encargo: string;
593
+ } | {
594
+ clase: "tarea";
595
+ accion: "augmentado";
596
+ error: string;
597
+ }
598
+ /**
599
+ * Un trozo del transcript de la sesión de una TAREA que alguien está mirando en vivo.
600
+ *
601
+ * **No es un segundo registro** (decisión 3 del diseño): son los MISMOS actos que se
602
+ * guardan en el `.jsonl` de esa sesión, los mismos que se leen al abrirla después. La
603
+ * lista sale de los actos y nunca del disco, igual que la de artefactos.
604
+ *
605
+ * Va SOLO al cliente que lo pidió y no a todos: el transcript de una tarea no puede
606
+ * aparecer en el chat de quien está trabajando en otra cosa. Y lleva el `tarea` delante
607
+ * porque por el mismo cable puede llegar el transcript de la sesión propia: sin la
608
+ * etiqueta, los actos de una tarea de fondo se mezclarían con la conversación.
609
+ *
610
+ * Los tres `via` son los tres mensajes del transcript de siempre, con otro nombre:
611
+ * `todos` es la reemisión entera (al empezar a mirar y cuando el servidor reemite),
612
+ * `alta` un acto nuevo al final, y `sustitucion` el último que cambió (el cierre de una
613
+ * racha de tools sustituye a su apertura). `actos` es SIEMPRE una lista: con `alta` y
614
+ * `sustitucion`, de un solo elemento — un campo opcional por cada forma habría sido un
615
+ * «ausente no es vacío» de más en la lista blanca del store.
616
+ */
617
+ | {
618
+ clase: "mirada";
619
+ tarea: string;
620
+ via: "todos" | "alta" | "sustitucion";
621
+ actos: Acto[];
622
+ }
623
+ /**
624
+ * Qué hay en la MÁQUINA para probar la app: el sistema, las herramientas de Android e
625
+ * iOS (adb, emulator, xcrun/simctl, devicectl) con su estado, y a qué dispositivos y
626
+ * simuladores se llega (`core/dispositivos.ts`).
627
+ *
628
+ * Es una FOTO con su hora (`medido`), no un estado en vivo: se toma al conectar el primer
629
+ * cliente y cuando alguien pide actualizarla (el mensaje «dispositivos» del cliente). No se
630
+ * sondea en bucle porque `adb devices` arranca el demonio de adb y `xcrun` puede tardar
631
+ * segundos — un panel que se refresca solo cada pocos segundos lanzaría procesos en la
632
+ * máquina del usuario sin que nadie lo pidiera.
633
+ */
634
+ | {
635
+ clase: "dispositivos";
636
+ informe: InformeDeDispositivosDelCable;
637
+ /**
638
+ * Cómo acabó el último «Arrancar» de un emulador, si hubo uno.
639
+ *
640
+ * Viaja CON la foto nueva a propósito: el resultado de arrancar no es el código de
641
+ * salida de `emulator` —que vuelve enseguida— sino que el aparato APAREZCA, y eso es lo
642
+ * que dice la foto. Así las dos cosas llegan juntas y no se pueden leer desfasadas.
643
+ *
644
+ * **Ausente = no se ha pedido ninguno**, que no es «salió bien». Y un `ok: false` trae
645
+ * su línea: un botón que no hace nada y no lo dice es lo que esto viene a evitar.
646
+ */
647
+ arranque?: {
648
+ avd: string;
649
+ ok: boolean;
650
+ detalle: string;
651
+ };
652
+ /**
653
+ * Qué dispositivo tiene elegido CADA consola abierta, y de qué proyecto es: con dos
654
+ * proyectos sobre dos emuladores, la pastilla del chat avisa «lo usa Tienda» en el aparato ajeno.
655
+ * `proyecto` es el nombre de su carpeta —el que enseña la barra—, nunca una ruta. Una
656
+ * consola sin dispositivo elegido no aparece.
657
+ */
658
+ enUso?: {
659
+ id: string;
660
+ proyecto: string;
661
+ }[];
662
+ /**
663
+ * Qué destinos se miran (`core/settings.ts#AjustesDeDispositivos`). Viaja CON la
664
+ * foto porque las dos cosas se leen juntas: una herramienta «desactivada» solo se
665
+ * entiende sabiendo qué interruptor la apagó. **Ausente = nadie ha elegido**, y
666
+ * entonces se miran todos; un `false` es una elección.
667
+ */
668
+ ajustes: AjustesDeDispositivos;
669
+ }
670
+ /**
671
+ * Los ficheros que ESTA sesión ha tocado, y el parche de uno.
672
+ *
673
+ * `via` no es decoración, y son TRES cosas distintas: «git» es «comparado, y esto es lo
674
+ * que hay»; «sin-empezar» es que la sesión todavía no ha volcado ningún acto, así que no
675
+ * ha tocado nada y se sabe; «sin-marca» es que NO se sabe —la sesión se abrió sin git
676
+ * usable, o antes de que esto existiera—. Fundir las tres en una lista vacía haría que
677
+ * «todavía no has hecho nada» y «no se puede saber» se leyeran igual, y la segunda haría
678
+ * creer que un turno no escribió cuando lo que pasa es que no hay con qué comparar.
679
+ */
680
+ /**
681
+ * Lo que ha tocado la sesión. `via` dice CÓMO se ha medido, y desde el 10-09-2026 son
682
+ * cuatro y no tres: `git` es atribución por COMMIT (lo que hizo esta sesión) y
683
+ * `desde-apertura` es la medida vieja —todo lo que ha cambiado en la copia desde que se
684
+ * abrió, de quien sea—, que es lo único posible en una sesión sin sello. Colapsarlas
685
+ * dejaría la pestaña rotulada «Sesión» sobre el trabajo de una tarea de fondo, que es el
686
+ * fallo que se vio en pantalla.
687
+ */
688
+ | {
689
+ clase: "revision";
690
+ via: "git" | "desde-apertura" | "sin-marca" | "sin-empezar";
691
+ ficheros: FicheroTocado[];
692
+ /** Commits de OTRAS sesiones entre los de esta: la lista es exacta, un parche puede
693
+ * traer hunks ajenos. Ausente = ninguno, o no se pudo medir. */
694
+ mezclados?: number;
695
+ } | {
696
+ clase: "parche";
697
+ ruta: string;
698
+ texto: string;
699
+ recortado: boolean;
700
+ }
701
+ /**
702
+ * TODO lo pendiente de subir a CloudStudio del proyecto abierto (la pestaña Sincronización del
703
+ * panel), o por qué no se pudo medir. Lo que git aún no sigue va marcado `sinCommitear`.
704
+ */
705
+ | {
706
+ clase: "pendientesDeSubida";
707
+ ficheros?: FicheroTocado[];
708
+ error?: string;
709
+ }
710
+ /**
711
+ * El diff de UN fichero pendiente contra CloudStudio. `negado` = la ruta no se enseña (la
712
+ * regla del lector), y entonces no viaja texto.
713
+ */
714
+ | {
715
+ clase: "parcheDeSubida";
716
+ ruta: string;
717
+ texto: string;
718
+ recortado: boolean;
719
+ negado?: string;
720
+ }
721
+ /**
722
+ * Lo que cambió en el MODELO de un `.xne` de Revisión (`core/diffDeColecciones.ts`), entre el
723
+ * mismo «antes» que su parche y ahora. Sin `cambios` y con `error` si no se pudo
724
+ * reconstruir; `cambios` vacío es «ningún cambio que el modelo vea».
725
+ */
726
+ | {
727
+ clase: "modeloDelCambio";
728
+ ruta: string;
729
+ cambios?: CambiosDeUnaColeccion[];
730
+ error?: string;
731
+ }
732
+ /**
733
+ * El árbol del proyecto abierto (pestaña Ficheros): rutas relativas, ordenadas y ya
734
+ * filtradas por la misma regla que ve el agente (`agent/grafo/arbolDeProyecto.ts`). `error`
735
+ * solo si no se pudo listar, y entonces `rutas` va vacía. Y el contenido de UN fichero,
736
+ * de solo lectura: sin `texto` si es binario o si la ruta se rechazó, con el motivo.
737
+ */
738
+ | {
739
+ clase: "arbol";
740
+ rutas: string[];
741
+ recortado: boolean;
742
+ error?: string;
743
+ }
744
+ /**
745
+ * El modelo XOne del proyecto abierto (pestaña Colecciones), del MISMO índice que
746
+ * `xone_navegacion`: rutas virtuales y nombres, nunca rutas de la máquina. Sin `foto` y con
747
+ * `error` si no se pudo leer.
748
+ */
749
+ | {
750
+ clase: "colecciones";
751
+ foto?: FotoDeColecciones;
752
+ error?: string;
753
+ }
754
+ /**
755
+ * Los planes del proyecto abierto (`.xonecode/planes/`, pestaña Planes): sus ficheros, las
756
+ * tareas leídas de su `TASKS.md` y el texto de su `PLAN.md`. Es lo que el plan DICE —estado y
757
+ * casillas las marca el modelo—. Sin `planes` y con `error` si no se pudo leer.
758
+ */
759
+ | {
760
+ clase: "planes";
761
+ planes?: PlanEnDisco[];
762
+ error?: string;
763
+ }
764
+ /**
765
+ * El gestor de tareas del proyecto abierto (IXCODE-11, panel del proyecto): UN mensaje con
766
+ * campos opcionales, como `planes`, y cada acción del cliente rellena el suyo. `error` dice
767
+ * QUÉ acción falló, porque el panel espera la respuesta de una en concreto. Nunca viaja un
768
+ * correo, un token ni una ruta de la máquina: del asignado, solo el nombre visible.
769
+ */
770
+ | {
771
+ clase: "gestor";
772
+ /** `admiteMias` (IXCODE-15): si el gestor VINCULADO sabe filtrar «asignadas a mí». Se
773
+ * decidió AL VINCULAR y se lee del `config.json`, sin red. Viaja SIEMPRE con vínculo y
774
+ * nunca sin él. */
775
+ estado?: {
776
+ conectores: string[];
777
+ vinculo?: VinculoDelCable;
778
+ admiteMias?: boolean;
779
+ };
780
+ sitios?: {
781
+ conector: string;
782
+ lista: {
783
+ id: string;
784
+ nombre: string;
785
+ }[];
786
+ };
787
+ proyectos?: {
788
+ sitio: string;
789
+ lista: {
790
+ clave: string;
791
+ nombre: string;
792
+ }[];
793
+ };
794
+ /** IXCODE-15: la respuesta de `buscarProyectos`, con el `texto` que se buscó (para no
795
+ * pintar una respuesta vieja). En Notion `proyecto` es el id de la BASE: se manda a
796
+ * `describir`, NO a `vincular`. */
797
+ busqueda?: {
798
+ conector: string;
799
+ texto: string;
800
+ lista: {
801
+ proyecto: string;
802
+ nombre: string;
803
+ ruta?: string;
804
+ }[];
805
+ };
806
+ /** IXCODE-15: la respuesta de `describir`. `pedido` es lo que se mandó; con `esquema`, lo
807
+ * que hay que mandar a `vincular` es `esquema.proyecto` (el data source ya resuelto). Con
808
+ * `motivo`, esa base no vale como gestor —la acción salió bien; no es un `error`—. */
809
+ descripcion?: {
810
+ conector: string;
811
+ pedido: string;
812
+ } & ({
813
+ esquema: EsquemaDelProyecto;
814
+ } | {
815
+ motivo: string;
816
+ });
817
+ /** `cuando`: la hora del SERVIDOR a la que se preguntó, para decir «hace N min».
818
+ * `mias` viaja SOLO cuando la lista es la de «asignadas a mí»: el cliente pinta lo que
819
+ * el servidor contestó, no lo que pidió. */
820
+ pendientes?: {
821
+ cuando: number;
822
+ texto?: string;
823
+ mias?: true;
824
+ lista: TareaDelGestor[];
825
+ };
826
+ /** La descripción de UNA tarea, para desplegarla en su fila antes de empezar. De solo
827
+ * LECTURA: solo la clave y el texto, nada más de la ficha. */
828
+ ficha?: {
829
+ clave: string;
830
+ descripcion: string;
831
+ };
832
+ /** El texto que el compositor PROPONE: lo envía la persona, no sale solo. */
833
+ borrador?: {
834
+ clave: string;
835
+ texto: string;
836
+ };
837
+ /**
838
+ * Las transiciones disponibles de una tarea (Task 10, IXCODE-11), para «empezar» —con
839
+ * `transicion`— y para «cerrar». `propuesta` es el id que `transicionPropuesta` sugiere
840
+ * (la persona puede elegir otra o ninguna); ausente si ninguna encaja.
841
+ */
842
+ transiciones?: {
843
+ clave: string;
844
+ para: "empezar" | "cerrar";
845
+ lista: TransicionDelGestor[];
846
+ propuesta?: string;
847
+ };
848
+ /**
849
+ * El comentario de cierre PROPUESTO para la tarea de la sesión ABIERTA: lo compone
850
+ * `comentarioDeCierre` desde lo que el harness sabe de la sesión (`datosDeCierre`). La
851
+ * persona lo EDITA antes de mandar `cerrar`; nada se escribe todavía.
852
+ */
853
+ cierre?: {
854
+ clave: string;
855
+ comentario: string;
856
+ };
857
+ /**
858
+ * El resultado de `cerrar`: se llega aquí solo si `comentar` no falló —si falla, sale
859
+ * `error` en su lugar, así que `comento` es siempre `true`—, y `transicion` viaja SOLO
860
+ * si además se aplicó una. Si la transición pedida FALLÓ, su motivo va en
861
+ * `falloDeTransicion` (y `transicion` no viaja): el comentario ya está escrito, y un
862
+ * `error` a secas invitaría a repetir el cierre y comentar dos veces.
863
+ */
864
+ cerrado?: {
865
+ clave: string;
866
+ comento: boolean;
867
+ transicion?: string;
868
+ falloDeTransicion?: string;
869
+ };
870
+ /** `clave` solo en el de `ficha`: dice de QUÉ tarea es la descripción que no se pudo leer.
871
+ * IXCODE-15: `texto` solo en el de `buscarProyectos` (QUÉ búsqueda falló) y `pedido` solo en
872
+ * el de `describir` (QUÉ base): el cliente no pinta el fallo de una búsqueda o base que ya
873
+ * no tiene delante. */
874
+ error?: {
875
+ accion: string;
876
+ motivo: string;
877
+ clave?: string;
878
+ texto?: string;
879
+ pedido?: string;
880
+ };
881
+ } | ({
882
+ clase: "fichero";
883
+ } & FicheroDelProyecto)
884
+ /**
885
+ * La respuesta a guardar un fichero desde el editor de la pestaña Ficheros: con `huella` se
886
+ * escribió y esa es la nueva; con `error`, no se tocó nada. Va a TODOS los clientes: otra pestaña
887
+ * con el mismo fichero abierto se entera de que el disco cambió.
888
+ */
889
+ | {
890
+ clase: "ficheroGuardado";
891
+ ruta: string;
892
+ id: string;
893
+ huella?: string;
894
+ error?: string;
895
+ }
896
+ /**
897
+ * Lo que pasó al llevar un fichero guardado al aparato de la sesión (recarga en caliente). Va
898
+ * SIEMPRE después de su `ficheroGuardado` y aparte: el guardado no depende del aparato. `texto`
899
+ * es la frase hecha (`core/recargaEnCaliente.ts#textoDeRecarga`); `tipo`, cómo se aplicó.
900
+ */
901
+ | {
902
+ clase: "recargaEnAparato";
903
+ ruta: string;
904
+ estado: "aplicada" | "relanzar" | "relanzada" | "sin-app" | "desplegando" | "desplegada" | "ocupado" | "no-aplica" | "fallo";
905
+ tipo?: "coleccion" | "js" | "css" | "relanzar" | "no-aplica";
906
+ texto: string;
907
+ }
908
+ /** La base de comparación de un fichero, para las marcas del margen del editor. */
909
+ | ({
910
+ clase: "baseDeFichero";
911
+ } & BaseDelFichero)
912
+ /**
913
+ * El estado de sincronización del proyecto abierto (pestaña CloudStudio). Los campos van en
914
+ * `EstadoDeSync`, aquí arriba, para poder compararlos con los del cliente.
915
+ */
916
+ | ({
917
+ clase: "sync";
918
+ } & EstadoDeSync)
919
+ /**
920
+ * El contenido de un ARTEFACTO de la sesión, con la MISMA forma que un fichero del
921
+ * proyecto — a propósito: así los visores del cliente son los de la pestaña Ficheros y no
922
+ * una segunda familia de componentes para lo mismo. La `ruta` que trae es la VIRTUAL
923
+ * (`/artefactos/<nombre>`), que es la que el cliente ya conoce por el acto.
924
+ *
925
+ * El HTML no viaja por aquí para VERSE —eso lo pinta un iframe contra `GET /artefacto`,
926
+ * que es la única forma de darle un documento—, sino para leer su fuente cuando se pide.
927
+ */
928
+ | ({
929
+ clase: "artefacto";
930
+ } & FicheroDelProyecto)
931
+ /**
932
+ * Cómo va el paso de receta que se está EJECUTANDO, o cómo acabó.
933
+ *
934
+ * Va a TODOS los clientes, como la foto de la máquina y por lo mismo: la máquina es la
935
+ * misma para todos, y un `sdkmanager` corriendo lo está para las dos pestañas. `lineas` es
936
+ * la COLA del log —lo último, no todo—: un `sdkmanager` verboso son miles de líneas y el
937
+ * cable no es un sitio donde guardarlas.
938
+ */
939
+ | {
940
+ clase: "instalacion";
941
+ receta: string;
942
+ paso: number;
943
+ titulo: string;
944
+ estado: "corriendo" | "ok" | "fallo" | "cancelada" | "colgada";
945
+ lineas: string[];
946
+ ms: number;
947
+ motivo?: string;
948
+ }
949
+ /**
950
+ * El veredicto de «¿se puede lanzar la app del proyecto abierto, en su dispositivo?».
951
+ *
952
+ * **Va a la consola que lo PIDIÓ, no a todos los clientes** — la regla contraria a
953
+ * `dispositivos` e `instalacion`, y no por descuido: la máquina es la misma para todos, pero
954
+ * el PROYECTO no. Es el reparto de `revision` y `arbol`: se pide, se contesta, y NO entra en
955
+ * la ráfaga de bienvenida, porque una pestaña que acaba de abrirse no tiene por qué recibir
956
+ * el veredicto de un proyecto que a lo mejor ya no es el suyo.
957
+ *
958
+ * **`faltas` son FRASES ya escritas** (`core/puedeLanzarse.ts#motivoDeBloqueo`), no las causas
959
+ * crudas: el cliente no es fuente sobre qué se puede lanzar, y componer aquí «falta el
960
+ * framework en tal dispositivo» sería una segunda redacción de la misma regla, que es donde
961
+ * las dos divergen. `listo` es `faltas.length === 0` y viaja igualmente porque es lo que
962
+ * decide si el botón se pinta.
963
+ */
964
+ | {
965
+ clase: "lanzable";
966
+ /** El nombre del proyecto abierto. Un SEGMENTO, no una ruta: `sinRutas`. */
967
+ proyecto: string;
968
+ listo: boolean;
969
+ /** Vacío cuando `listo`. Una LISTA y no la primera: se arregla lo que falta una a una. */
970
+ faltas: string[];
971
+ /**
972
+ * El nombre de la app, el que dice el `name=` de `app.ini`. Ausente = no consta, y sin
973
+ * él no hay a qué lanzar: `launchApplication` la pide por nombre.
974
+ */
975
+ app?: string;
976
+ /**
977
+ * El dispositivo de la sesión tal y como salió de la última MEDIDA —id, nombre,
978
+ * plataforma y clase, y nada más—, que es la foto que ya viaja en `alta.dispositivoActivo`
979
+ * y en `sesiones[].dispositivo`. Ausente = ninguno elegido, o uno que ya no está.
980
+ */
981
+ dispositivo?: DispositivoElegido;
982
+ /**
983
+ * CUÁNDO se midió esto. Un veredicto sin fecha es una promesa sin fecha: el framework se
984
+ * mide al conectar y al pulsar «volver a mirar», así que un «todo listo» de hace media
985
+ * hora sobre un aparato que se acaba de desenchufar es exactamente el botón muerto que
986
+ * esta pestaña existe para no pintar.
987
+ */
988
+ medido: string;
989
+ }
990
+ /**
991
+ * Cómo va el lanzamiento de la app, o cómo acabó. Va a la consola que lo pidió, por lo mismo
992
+ * que `lanzable`.
993
+ *
994
+ * **`lineas` es la COLA del recorrido y no todo**: lo que suelta `adb` al subir un ZIP son
995
+ * miles de líneas, y este cable no es un sitio donde guardarlas. `ms` son los milisegundos
996
+ * desde que arrancó, y viaja porque un recorrido sin tiempo se lee como un cuelgue.
997
+ *
998
+ * `motivo` solo cuando lo hay: en `ok` no hay nada que decir, y un `motivo: ""` invitaría a
999
+ * pintar una línea vacía al lado del visto bueno.
1000
+ */
1001
+ | {
1002
+ clase: "lanzamiento";
1003
+ /** El nombre del proyecto, si se sabe CUÁL. Ausente = no había ninguno que nombrar. */
1004
+ proyecto?: string;
1005
+ dispositivo?: DispositivoElegido;
1006
+ fase: FaseDelLanzamiento;
1007
+ estado: EstadoDelLanzamiento;
1008
+ lineas: string[];
1009
+ ms: number;
1010
+ motivo?: string;
1011
+ }
1012
+ /** Lo que ofrece un motor externo. `error` en vez de una lista vacía muda: un desplegable
1013
+ * vacío sin motivo se lee como que la ventana está rota. */
1014
+ | {
1015
+ clase: "modelosDeMotor";
1016
+ motor: string;
1017
+ modelos: {
1018
+ id: string;
1019
+ nombre: string;
1020
+ }[];
1021
+ error?: string;
1022
+ }
1023
+ /** El diagnóstico de Node de Ajustes → General (`core/diagnosticoDeNode.ts`): una foto, sin rutas de la máquina. */
1024
+ | {
1025
+ clase: "diagnosticoNode";
1026
+ diagnostico: DiagnosticoDeNode;
1027
+ }
1028
+ /**
1029
+ * El diseño vinculado de un proyecto: `vinculo` (null = sin vínculo), los `proyectos` de Stitch para elegir, las
1030
+ * `pantallas` con miniatura, o un `error`. Cada mensaje trae solo lo que se pidió. `proyecto` = de qué proyecto XOne.
1031
+ */
1032
+ | {
1033
+ clase: "diseno";
1034
+ proyecto?: string;
1035
+ vinculo?: {
1036
+ proyecto: string;
1037
+ nombre: string;
1038
+ } | null;
1039
+ proyectos?: {
1040
+ name: string;
1041
+ title: string;
1042
+ }[];
1043
+ pantallas?: {
1044
+ name: string;
1045
+ title: string;
1046
+ miniatura?: string;
1047
+ }[];
1048
+ error?: string;
1049
+ }
1050
+ /**
1051
+ * La foto de los motores locales (Claude Code, Codex, OpenCode) para Ajustes → Motores locales:
1052
+ * si están, con qué sesión, la última prueba y el login en curso. Entera en cada cambio, como
1053
+ * `dispositivos`. Ni rutas, ni el correo de la cuenta, ni el enlace de autorización.
1054
+ */
1055
+ | {
1056
+ clase: "motoresLocales";
1057
+ motores: EstadoDeMotorLocal[];
1058
+ } | {
1059
+ clase: "secreto";
1060
+ pregunta: string;
1061
+ }
1062
+ /**
1063
+ * El alta que FALTA, para el wizard del navegador. `pasos` sale de
1064
+ * `vestibulo.ts#pasosPendientes`, que los calcula preguntándole al sistema y nunca a una
1065
+ * marca de «primer arranque»; vacío significa que no hay alta que hacer y el cliente no
1066
+ * pinta el wizard — pero puede seguir sin haber proyecto abierto, ver `proyectoAbierto`
1067
+ * más abajo. Cambio de rumbo del usuario: «proyecto» ya NO puede aparecer en `pasos`
1068
+ * (sigue siendo un `paso` válido del lado del `MensajeDelCliente`, para abrir uno desde
1069
+ * la barra lateral, pero no bloquea la entrada al dashboard).
1070
+ *
1071
+ * `proyectos` y `ramas` llegan vacíos hasta que hay entorno (y proyecto) elegidos: son
1072
+ * dos consultas a CloudStudio y no se pueden inventar. Lista vacía es «todavía no lo
1073
+ * sé», que es la verdad, y no un dato de relleno.
1074
+ *
1075
+ * **La clave de API NO viaja aquí.** El paso de cuenta lo conduce
1076
+ * `vestibulo.pasoDeCuenta()` sobre `seleccionar` y `leerSecreto`, así que la clave sigue
1077
+ * entrando por el mensaje de clase «secreto» y por ninguno más — el mismo trato que
1078
+ * documentan `consolaWeb.ts#leerSecreto` y la cabecera de `Wizard.tsx`.
1079
+ */
1080
+ | {
1081
+ clase: "alta";
1082
+ pasos: PasoDelVestibulo[];
1083
+ /**
1084
+ * **Qué está preparando el arranque AHORA. Ausente = ya está listo.**
1085
+ *
1086
+ * Existe porque `proyectos: []` no distingue «todavía no lo he preguntado» de «no hay
1087
+ * ninguno», y de esa ambigüedad salía un Escritorio que entraba vacío y se rellenaba
1088
+ * delante del usuario. Con este campo el cliente se queda en el lienzo hasta que el
1089
+ * arranque termina, y mientras puede DECIR qué hace en vez de estar un segundo y medio
1090
+ * en silencio.
1091
+ *
1092
+ * Es la FASE y no un booleano por lo mismo que `Fase` en el turno: un «espera» sin
1093
+ * decir a qué se parece a estar colgado. Y va como texto ya redactado por el servidor,
1094
+ * que es quien sabe el nombre del entorno al que está llamando.
1095
+ *
1096
+ * Lo que acota la espera es un PLAZO (`MS_DE_PREPARACION`), no la confianza en que el
1097
+ * MCP conteste: si no contesta, se entra igual y el `aviso` dice por qué. Medido: con
1098
+ * un MCP que descarta paquetes, sin plazo el lienzo se queda para siempre.
1099
+ */
1100
+ preparando?: string;
1101
+ proveedores: {
1102
+ id: string;
1103
+ nombre: string;
1104
+ }[];
1105
+ entornos: OpcionDeEntorno[];
1106
+ /**
1107
+ * Los entornos REGISTRADOS de verdad (`settings.json`), que no son los OFRECIDOS de
1108
+ * `entornos` —esa es la lista fija de los dos oficiales más «otro», y sirve para
1109
+ * prerrellenar la URL del alta—. Hacía falta desde que el registro deduce la
1110
+ * identidad del host: un on-premise registrado no aparece en la ofrecida por ningún
1111
+ * lado, y la barra lateral llevaba enseñando la ofrecida como si fuera ésta.
1112
+ */
1113
+ registrados: EntornoRegistrado[];
1114
+ /**
1115
+ * El id del proyecto ABIERTO ahora mismo, y el de su sesión.
1116
+ *
1117
+ * `proyectoAbierto` (booleano, más abajo) dice SI hay uno; estos dicen CUÁL, que es
1118
+ * otra pregunta y la que necesita la barra para marcar la fila. Se resuelven
1119
+ * comparando la raíz de la consola abierta con la que le tocaría a cada proyecto
1120
+ * (`raizDeProyecto`), no guardando un id aparte: dos fuentes para lo mismo divergen
1121
+ * en cuanto una se olvide de actualizarse.
1122
+ *
1123
+ * `sesionActiva` puede faltar con un proyecto abierto, y no es un fallo: el id de
1124
+ * sesión no existe hasta que se vuelca el primer acto (`ConsolaDeProyecto.sesion`),
1125
+ * así que una sesión recién empezada todavía no tiene nada que marcar — igual que
1126
+ * tampoco aparece en la lista de sesiones guardadas.
1127
+ */
1128
+ proyectoActivo?: string;
1129
+ sesionActiva?: string;
1130
+ /**
1131
+ * Con qué dispositivo trabaja la sesión abierta. Ausente = ninguno elegido.
1132
+ *
1133
+ * Viaja la FOTO y no solo el id porque los ids no son estables —`emulator-5554` es un
1134
+ * puerto, y un teléfono se desenchufa—: al reabrir una sesión, el selector puede decir
1135
+ * «iPhone 16 · no está ahora» en vez de un serial crudo o nada. Si está a mano AHORA
1136
+ * no se manda: eso lo resuelve el cliente contra la última medida, que es la única que
1137
+ * lo sabe en este instante.
1138
+ */
1139
+ dispositivoActivo?: {
1140
+ id: string;
1141
+ nombre: string;
1142
+ plataforma: "android" | "ios";
1143
+ clase: "emulador" | "simulador" | "fisico";
1144
+ };
1145
+ /**
1146
+ * La sesión abierta es una RELECTURA: se reabrió y del hilo no queda memoria
1147
+ * (`ConsolaDeProyecto.historica`, que lo PREGUNTA al checkpointer del proyecto en vez
1148
+ * de darlo por hecho — una sesión con checkpoint continúa y no lleva esta marca; la
1149
+ * llevan las de antes de que hubiera checkpointer y aquellas cuyo primer turno nunca
1150
+ * llegó a correr). Deja de serlo en el primer turno nuevo,
1151
+ * y el alta se reanuncia en ese flanco. Solo viaja cuando es cierto: ausente es «no».
1152
+ * Sin esto el cliente pintaba una conversación y un compositor activo como si se
1153
+ * pudiera seguir hablando, que es lo que el propio `CLAUDE.md` dice que no pasa.
1154
+ */
1155
+ historica?: boolean;
1156
+ /**
1157
+ * El modo de escritura de la SESIÓN abierta: `supervisado` (cada escritura con su
1158
+ * diff) o `autonomo` (se aplican solas). Ver `core/modoDeEscritura.ts`.
1159
+ *
1160
+ * **Ausente = no hay sesión abierta**, y por eso la pastilla no se pinta: un control
1161
+ * sin dato detrás no se pinta. Nunca significa «supervisado» — una sesión abierta
1162
+ * siempre trae el suyo, porque el servidor resuelve la omisión antes de emitir.
1163
+ *
1164
+ * Viaja en el alta y no solo en el aviso del turno porque quien se sienta hoy tiene
1165
+ * que saber en qué modo está ANTES de pedir nada, no después con los ficheros ya
1166
+ * cambiados. Y viaja el MODO y no un booleano porque es lo que la pastilla pinta.
1167
+ */
1168
+ modoDeEscritura?: "supervisado" | "autonomo";
1169
+ /**
1170
+ * Lo que YA estaba sin commitear en el proyecto cuando se abrió esta consola
1171
+ * (`agent/sesiones/gitSync.ts#trabajoSinCommitear`, medido en el instante de abrir).
1172
+ *
1173
+ * Ausente = no hay nada que decir, y son las tres respuestas que se callan a
1174
+ * propósito: el árbol estaba limpio, no hay git con qué mirar (todo proyecto
1175
+ * OFFLINE), o la medida falló. Ninguna de las tres es un aviso.
1176
+ *
1177
+ * Va la lista y no un número: quien lo lee tiene que poder reconocer si eso es suyo,
1178
+ * de otra sesión o de una tarea, y un contador a secas es el aviso que enseña a
1179
+ * ignorar los avisos. `ficheros` viene ACOTADA —el alta se reemite en los dos flancos
1180
+ * de cada turno y la frase no puede llevar trescientos nombres— y `total` es la cifra
1181
+ * entera, que es lo que impide leer los que caben como si fueran todos.
1182
+ *
1183
+ * La medida es del instante de ABRIR y no cambia con los reanuncios, a propósito: así
1184
+ * no puede contar como «de otro» lo que esta misma sesión —o esta tarea— acabe de
1185
+ * escribir.
1186
+ */
1187
+ trabajoAlAbrir?: {
1188
+ ficheros: string[];
1189
+ total: number;
1190
+ };
1191
+ /**
1192
+ * De qué entorno son los `proyectos` de este mensaje. Ausente = todavía de ninguno
1193
+ * (nadie ha elegido y no había ninguno registrado que poblar). El cliente lo NECESITA
1194
+ * para no tener que asumir «el primero de la lista», que es lo que hacía y era una
1195
+ * suposición que se rompía en cuanto había dos.
1196
+ */
1197
+ entornoActivo?: string;
1198
+ /**
1199
+ * Los proyectos del entorno, con las SESIONES que ya tiene su copia local (vacío si
1200
+ * no se ha bajado nunca). Van en el mismo mensaje porque la barra los pinta juntos:
1201
+ * un proyecto sin sus sesiones es una fila que no se puede abrir por donde se dejó.
1202
+ */
1203
+ proyectos: {
1204
+ id: string;
1205
+ nombre: string;
1206
+ /**
1207
+ * Compartido CONTIGO por otra persona (`shared` de `studio_list_projects`).
1208
+ * **Ausente no es «es tuyo»**: es que el servidor no lo dijo, y entonces no se
1209
+ * pinta etiqueta ninguna — afirmar que todos son propios porque un endpoint viejo
1210
+ * calló sería la clase de dato inventado que esta consola no consiente.
1211
+ *
1212
+ * Es un booleano y NO el correo del propietario, que viaja en la misma respuesta
1213
+ * (`suser`): para distinguir lo propio de lo compartido basta con esto, y quién lo
1214
+ * compartió es un dato de una persona que esta pantalla no necesita.
1215
+ */
1216
+ compartido?: boolean;
1217
+ /** Fecha ISO del último acceso (`last` de `studio_list_projects`). Ausente = no
1218
+ * consta — no todos los proyectos lo traen. */
1219
+ ultimoAcceso?: string;
1220
+ sesiones?: SesionDelCable[];
1221
+ /** La copia local YA existe: se puede abrir sin bajar nada ni preguntar rama. */
1222
+ local?: boolean;
1223
+ /** La rama de la que se bajó la copia local. Ausente = sin copia, o no consta. */
1224
+ rama?: string;
1225
+ /**
1226
+ * La copia local tiene un icono de app que se puede enseñar (`app.ini`), servido por
1227
+ * `RUTA_ICONO_DEL_PROYECTO`. Un booleano y no la ruta: ninguna ruta sale del host.
1228
+ * Ausente = sin copia, sin icono, o no consta; la barra pinta entonces la carpeta.
1229
+ */
1230
+ icono?: true;
1231
+ /**
1232
+ * Alguna sesión de este proyecto tiene un turno EN MARCHA ahora mismo.
1233
+ *
1234
+ * No se DERIVA de `sesiones[].trabajando`, y ahí está el motivo de que exista: una
1235
+ * sesión nueva no tiene fila en el índice hasta que vuelca su primer acto —o sea al
1236
+ * final del turno—, así que el caso más común (abrir, pedir algo, irse a otro
1237
+ * proyecto) no habría marcado ni la fila ni el proyecto, y en la barra no se vería
1238
+ * nada en ninguna parte.
1239
+ *
1240
+ * De aquí cuelga además que las OTRAS sesiones de ese proyecto no se puedan abrir
1241
+ * mientras dure: una copia de trabajo no aguanta dos conversaciones, y el servidor
1242
+ * lo declina (`motivoDeProyectoTrabajando`). Decirlo antes del clic es lo que evita
1243
+ * el botón muerto.
1244
+ */
1245
+ trabajando?: true;
1246
+ }[];
1247
+ ramas: string[];
1248
+ /** El id del proyecto del que son las `ramas`. Ausente = no hay ramas, o no consta. */
1249
+ ramasDe?: string;
1250
+ /**
1251
+ * Qué falló en el paso anterior. Ausente = no falló nada.
1252
+ *
1253
+ * Viaja EN el alta y no solo como acto porque el fallo pertenece al paso que lo
1254
+ * produjo. Medido en el navegador: el acto de sistema aterriza en la Trayectoria —la
1255
+ * pestaña que el usuario no está mirando— mientras el wizard repinta el mismo paso
1256
+ * sin una palabra, que es exactamente el fallo mudo que se quería quitar.
1257
+ */
1258
+ aviso?: string;
1259
+ /**
1260
+ * El saludo (`agent/config/persona.ts#nombreDePersona`). Viaja SUELTO en este mensaje, no
1261
+ * dentro de ningún acto: `Bienvenida.tsx` lo pinta y nada más, así que no entra en
1262
+ * el `.jsonl` de una sesión ni en el transcript. Ausente = sin nombre que saludar.
1263
+ */
1264
+ nombre?: string;
1265
+ /**
1266
+ * Si hay un proyecto abierto AHORA MISMO en esta conexión. Hace falta desde que el
1267
+ * paso de proyecto salió del alta: antes, `pasos: []` solo pasaba con un proyecto
1268
+ * ya abierto, y esa implicación bastaba para que el cliente supiera si pintar la
1269
+ * maqueta completa o el alta. Ahora `pasos: []` pasa en cuanto cuenta y entorno
1270
+ * están resueltos, CON o SIN proyecto abierto —el proyecto se elige en la barra—,
1271
+ * así que hace falta decirlo aparte para que el centro sepa si esperar una elección
1272
+ * o pintar la sesión de verdad.
1273
+ */
1274
+ proyectoAbierto: boolean;
1275
+ /**
1276
+ * El `modo` del `.xonecode/config.json` del proyecto abierto, para la pastilla de
1277
+ * la cabecera. **Ausente cuando no se sabe**, y eso incluye tres casos que no se
1278
+ * distinguen desde aquí: no hay proyecto abierto, el fichero no se pudo leer, o
1279
+ * lleva un valor que no es ninguno de los dos. Ausente NO significa «offline»:
1280
+ * pintar «offline» sobre un fichero que no se pudo leer sería afirmar lo que no se
1281
+ * sabe, que es la misma clase de mentira que un alias de color inventado. Es lo
1282
+ * único que se le extrae al config: ni la URL del entorno, ni el proyecto, ni la
1283
+ * rama, que son datos del despliegue y no tienen por qué acabar en el transcript.
1284
+ */
1285
+ modo?: "offline" | "cloud";
1286
+ }
1287
+ /** El ÚNICO mensaje que lleva contenido de fichero: es el paso donde se DECIDE sobre él. */
1288
+ | {
1289
+ clase: "aprobacion";
1290
+ pendientes: PendienteDeAprobacion[];
1291
+ ficheros: Record<string, string>;
1292
+ diffs: Record<string, LineaDeDiff[]>;
1293
+ };
1294
+ /**
1295
+ * Un proveedor, tal y como lo ve el selector de modelos.
1296
+ *
1297
+ * `credencial` es literal y tiene TRES valores porque hay tres cosas distintas que decir:
1298
+ * «puesta» solo si la credencial está confirmada, «falta» solo si se sabe que no está, y
1299
+ * «nativa» para quien no necesita ninguna (Ollama local). Pintarle un punto rojo a Ollama
1300
+ * sería inventarse un problema, y uno verde, un permiso.
1301
+ */
1302
+ /**
1303
+ * Un entorno ya registrado, con la elección de qué proyectos suyos se enseñan.
1304
+ *
1305
+ * `proyectos` AUSENTE no es «ninguno»: es que nadie lo ha dicho, y entonces la barra aplica
1306
+ * su omisión (los primeros `PROYECTOS_POR_OMISION`). Una lista vacía sí es una elección.
1307
+ */
1308
+ export interface EntornoRegistrado extends OpcionDeEntorno {
1309
+ proyectos?: string[];
1310
+ /** Los fijados arriba de la barra (`Entorno.fijados`). Ausente = ninguno. */
1311
+ fijados?: string[];
1312
+ /** Cuántas carpetas de proyecto tiene en el workspace. Ausente = no se pudo mirar, que no
1313
+ * es cero: con cero la casilla de borrarlas no se ofrece. */
1314
+ copias?: number;
1315
+ }
1316
+ /**
1317
+ * Un proyecto de un entorno, para elegir si se enseña. Es menos de lo que lleva un proyecto
1318
+ * del `alta`: sin `sesiones`, porque una sesión es de la COPIA LOCAL y aquí solo se decide
1319
+ * qué aparece en la barra. Lo que no hace falta, no viaja.
1320
+ */
1321
+ export interface ProyectoDeEntorno {
1322
+ id: string;
1323
+ nombre: string;
1324
+ /** Compartido contigo por otra persona. Ausente no es «es tuyo»: es que no se dijo. */
1325
+ compartido?: boolean;
1326
+ /** Fecha ISO del último acceso (`last` de `studio_list_projects`). Ausente = no consta. */
1327
+ ultimoAcceso?: string;
1328
+ }
1329
+ /** Un fichero de la sesión. `mas`/`menos` faltan en un binario: git no cuenta líneas ahí, y
1330
+ * poner cero diría que no cambió nada. */
1331
+ export interface FicheroTocado {
1332
+ ruta: string;
1333
+ clase: "nuevo" | "modificado" | "borrado";
1334
+ mas?: number;
1335
+ menos?: number;
1336
+ /** Hay cambios en este fichero que nadie ha commiteado, así que no se pueden atribuir a
1337
+ * esta sesión ni a otra (`agent/sesiones/sesionGit.ts#FicheroDeSesion`). Viaja para poder DECIRLO
1338
+ * en la fila: el turno en vuelo commitea al terminar, y esta es la única marca que
1339
+ * distingue «lo escribió esta sesión» de «esto está aquí y no consta de quién es». */
1340
+ sinCommitear?: true;
1341
+ /**
1342
+ * ¿Sigue pendiente de subir a CloudStudio? Lo decide el SERVIDOR en la misma foto que la
1343
+ * lista (`arranque.ts#marcarPendientes`), no el cliente cruzando dos mensajes que llegan en
1344
+ * momentos distintos. AUSENTE = no se pudo medir (proyecto sin CloudStudio, o la medida
1345
+ * falló), y entonces Revisión enseña todo en vez de esconder sobre una pregunta sin contestar.
1346
+ */
1347
+ pendiente?: boolean;
1348
+ }
1349
+ /** Un fichero del proyecto tal como viaja. Redeclarado en `apps/web/src/tipos.ts`. */
1350
+ export interface FicheroDelProyecto {
1351
+ /** La ruta tal como se pidió, nunca la resuelta en disco. */
1352
+ ruta: string;
1353
+ texto?: string;
1354
+ recortado: boolean;
1355
+ binario: boolean;
1356
+ bytes: number;
1357
+ codificacion?: "utf-8" | "latin1";
1358
+ /**
1359
+ * El MIME, solo si la ruta es una imagen que el visor sabe pintar. Viaja aunque los bytes
1360
+ * NO vengan: es lo que distingue «una imagen demasiado grande» de «un binario cualquiera».
1361
+ */
1362
+ mime?: string;
1363
+ /** La imagen entera, si cupo en el tope. Nunca recortada: media imagen no se abre. */
1364
+ base64?: string;
1365
+ /**
1366
+ * Solo en un markdown que enlaza imágenes del proyecto: el texto con esos enlaces apuntando a la
1367
+ * ruta que las sirve, para la VISTA (`arbolDeProyecto.ts#vistaDeMarkdown`). `texto` es la fuente.
1368
+ */
1369
+ vista?: string;
1370
+ /**
1371
+ * El sha256 de los bytes en disco, solo con el texto ENTERO en UTF-8
1372
+ * (`arbolDeProyecto.ts#huellaDeContenido`). Vuelve al guardar: si el disco ya no coincide, no se
1373
+ * escribe nada.
1374
+ */
1375
+ huella?: string;
1376
+ error?: string;
1377
+ }
1378
+ /**
1379
+ * La versión de un fichero contra la que el editor pinta sus marcas (`agent/sesiones/baseDeFichero.ts`).
1380
+ * `texto` = había una versión; `vacio` = en esa base no existía; `sinBase` = no hay con qué comparar,
1381
+ * y por qué. Redeclarado en `apps/web/src/tipos.ts`.
1382
+ */
1383
+ export interface BaseDelFichero {
1384
+ ruta: string;
1385
+ base: "sesion" | "commit";
1386
+ texto?: string;
1387
+ vacio?: true;
1388
+ sinBase?: string;
1389
+ }
1390
+ /**
1391
+ * El estado de sincronización del proyecto abierto (pestaña CloudStudio): de qué rama es y
1392
+ * cuántos ficheros quedan por subir. Redeclarado en `apps/web/src/tipos.ts`.
1393
+ *
1394
+ * **`proyecto` y `rama` ausentes no son «cero pendientes»**: son «este proyecto no está dado
1395
+ * de alta en CloudStudio» —o le falta la rama del alta—, que es un estado y no un contador a
1396
+ * cero. Son las dos preguntas que la pestaña tiene que poder contestar por separado, y por
1397
+ * eso no se rellenan con cadenas vacías.
1398
+ *
1399
+ * `pendientes` se mide contra la ref de seguimiento que dejó la última descarga
1400
+ * (`refs/remotes/cloudstudio/<rama>`), que es LA MISMA cuenta que da `/sync estado` —
1401
+ * `agent/sesiones/gitSync.ts#cambiosPendientes`, el mismo que decide qué sube el plan—. `error` solo
1402
+ * cuando no se pudo medir, y entonces `pendientes` no viene: un cero que nadie ha contado es
1403
+ * la cifra inventada de siempre.
1404
+ *
1405
+ * Es interfaz con nombre y no campos sueltos dentro de la unión por lo de siempre: los
1406
+ * campos de un mensaje EMBEBIDO en otro no se pueden comparar con `camposDeInterfaz`, y ese
1407
+ * es el test que vigila que el cliente no se quede con la mitad del contrato.
1408
+ */
1409
+ /**
1410
+ * La foto del resumen de un proyecto, tal como vuelve en la respuesta de `accion: "resumen"`.
1411
+ *
1412
+ * `tareas` son los IDS de las tareas de la cola cuya raíz es la de este proyecto: la tarea no
1413
+ * lleva su entorno, así que filtrarla por id en el cliente dejaría pasar la de otro entorno.
1414
+ * `sync` es la MISMA medida que la banda de CloudStudio (`lecturaDeSync`), y AUSENTE cuando no
1415
+ * hay copia bajada — que no es lo mismo que «nada por subir».
1416
+ */
1417
+ export interface FotoDelResumen {
1418
+ tareas: string[];
1419
+ sync?: EstadoDeSync;
1420
+ /**
1421
+ * El modo con que nacen las sesiones nuevas de ESTE proyecto (IXCODE-31). Presente solo con
1422
+ * copia bajada —sin ella no hay `config.json` que lo guarde—; `proyecto` ausente dentro es
1423
+ * «como el global», que no es lo mismo que no saberlo.
1424
+ */
1425
+ modoDeEscritura?: {
1426
+ proyecto?: "supervisado" | "autonomo";
1427
+ };
1428
+ }
1429
+ export interface EstadoDeSync {
1430
+ proyecto?: string;
1431
+ rama?: string;
1432
+ pendientes?: number;
1433
+ /**
1434
+ * De los `pendientes`, cuántos tocó ESTA sesión.
1435
+ *
1436
+ * Existe porque `pendientes` se mide contra la rama y la lista de Revisión contra la
1437
+ * sesión: son dos referencias distintas, así que las dos cifras pueden no tocarse. Medido
1438
+ * en el AppDemo del usuario el 16-09-2026, mirando la pantalla: la banda decía «3 ficheros
1439
+ * por subir» y la sesión de delante había hecho UN cambio —borrar un fichero que otra
1440
+ * había creado, así que el alta y el borrado se anulaban— que no entraba en el plan NI
1441
+ * PODÍA ENTRAR. Los dos números no discrepaban: eran de dos trabajos sin nada en común.
1442
+ *
1443
+ * **Ausente no es cero, y la diferencia es la de siempre.** Ausente = no se puede atribuir
1444
+ * (sin sesión abierta, o una sesión sin sello, que es la que solo se puede medir «desde que
1445
+ * abriste» y ahí dentro está el trabajo de cualquiera). Cero = se atribuyó y NINGUNO de los
1446
+ * pendientes es suyo, que es un hecho medido y justo el que hace falta para entender la
1447
+ * pantalla. Rellenar lo ausente con un cero diría «esta sesión no ha hecho nada» sobre una
1448
+ * sesión de la que no se sabe qué hizo.
1449
+ */
1450
+ deLaSesion?: number;
1451
+ error?: string;
1452
+ }
1453
+ /**
1454
+ * Una tarea tal como viaja. **Sin la raíz del proyecto**: viajan su id y su nombre, que es
1455
+ * lo que la interfaz necesita — la ruta se queda en el host, igual que `Herramienta.ruta` de
1456
+ * `xcrun`/`devicectl` (`adb`/`emulator` sí cruzan, ver `InformeDeDispositivosDelCable`).
1457
+ * Redeclarada en `apps/web/src/tipos.ts`.
1458
+ */
1459
+ export interface TareaDelCable {
1460
+ id: string;
1461
+ proyecto: string;
1462
+ proyectoNombre: string;
1463
+ titulo: string;
1464
+ peticion: string;
1465
+ encargo: string;
1466
+ adjuntos: {
1467
+ nombre: string;
1468
+ bytes: number;
1469
+ mime?: string;
1470
+ }[];
1471
+ estado: "nuevo" | "en-proceso" | "requiere-atencion" | "terminada";
1472
+ motivo?: string;
1473
+ sesion?: string;
1474
+ /** El id de la tarea ANTERIOR de su cadena (`Tarea.tras`): esta no arranca hasta que aquella termine. */
1475
+ tras?: string;
1476
+ creada: string;
1477
+ empezada?: string;
1478
+ acabada?: string;
1479
+ /**
1480
+ * Lo que la tarea AUTORIZÓ escribir sin que nadie lo aprobara, con ruta relativa al
1481
+ * proyecto (`core/tareas.ts#Tarea.autorizadas`). **No es lo mismo que lo que cambió en el
1482
+ * disco** —una ruta que las guardas de sitio rechazan sale aquí sin haberse escrito—: la
1483
+ * verdad sobre el disco la tiene la pestaña Revisión, con la ref de esta `sesion`. Ausente
1484
+ * = no consta (la tarea no llegó a correr un turno); `[]` = corrió y no autorizó ninguna.
1485
+ */
1486
+ autorizadas?: string[];
1487
+ /**
1488
+ * El historial de lo que el desarrollador contestó mientras la tarea esperaba feedback
1489
+ * (`core/tareas.ts#Tarea.feedback`). Ausente = nunca se le pidió nada. `consumido` dice
1490
+ * si ya se le mandó al agente en un turno.
1491
+ */
1492
+ feedback?: {
1493
+ texto: string;
1494
+ creado: string;
1495
+ consumido: boolean;
1496
+ }[];
1497
+ /**
1498
+ * El veredicto del juez de QA (`core/entrega.ts#VeredictoDeTarea`), y con él la
1499
+ * SALVEDAD: con qué condición de menos se entregó.
1500
+ *
1501
+ * **Sin esto, «Terminada» no distingue tres cosas distintas** —F1 de la revisión final—:
1502
+ * que el juez la aprobó con el verificador en verde, que se entregó SIN NADA que
1503
+ * verificar (una tarea de solo lectura: la salvedad), y —con `terminadaAMano`— que la dio
1504
+ * por buena una persona. El campo se guardaba en el índice de tareas desde que existe la
1505
+ * puerta de entrega y se quedaba en el host: la mitad del contrato en `core/` y en disco,
1506
+ * y la mitad que una persona lee sin cablear.
1507
+ *
1508
+ * **Y viaja completo porque no puede llevar nada más que texto para leer.** Medido en
1509
+ * `agent/tareas/juezDeTarea.ts#promptDelJuez`: el juez recibe el encargo, las rutas RELATIVAS de
1510
+ * lo autorizado y los hallazgos del verificador (código, fichero relativo, línea,
1511
+ * mensaje) — no hay un solo `readFile` en ese módulo, así que su prosa no puede citar el
1512
+ * contenido de un fichero ni una ruta de la máquina. El `resumen` ya cruzaba el cable de
1513
+ * todos modos: para un veredicto rojo va dentro del `motivo`.
1514
+ */
1515
+ veredicto?: {
1516
+ veredicto: "verde" | "rojo" | "indeterminado";
1517
+ resumen: string;
1518
+ hallazgos?: string[];
1519
+ salvedad?: string;
1520
+ };
1521
+ /**
1522
+ * La dio por buena una PERSONA («Dar por bueno»), no la puerta de entrega
1523
+ * (`core/tareas.ts#Tarea.terminadaAMano`). Ausente = no consta.
1524
+ */
1525
+ terminadaAMano?: boolean;
1526
+ /**
1527
+ * Con qué se CERRÓ (`core/entrega.ts#cierreDeLaEntrega`): lo crítico y las observaciones, lo que dice el comentario
1528
+ * de cierre del ticket. Ausente = se entregó sin nada que decir (o se cerró antes de que existiera).
1529
+ */
1530
+ cierre?: {
1531
+ criticos: string[];
1532
+ observaciones: string[];
1533
+ };
1534
+ /**
1535
+ * El ticket del gestor de tareas en el que vive (`core/tareas.ts#TicketDeTarea`). Cruzan la CLAVE, el conector (de él
1536
+ * sale el nombre que se enseña: «Jira»), el enlace y el aviso de lo último que no se pudo escribir; el `sitio` y el
1537
+ * `proyecto` del gestor se quedan en el host, como los de una sesión ligada a un ticket.
1538
+ */
1539
+ ticket?: {
1540
+ clave: string;
1541
+ conector: string;
1542
+ url?: string;
1543
+ aviso?: string;
1544
+ };
1545
+ /** La pantalla de Stitch elegida para la tarea: su `name` y su título (no es una ruta de la máquina). */
1546
+ pantallaDeStitch?: {
1547
+ name: string;
1548
+ titulo: string;
1549
+ proyecto?: string;
1550
+ };
1551
+ }
1552
+ /**
1553
+ * Una `Tarea` del índice traducida a lo que viaja. **La raíz del proyecto se queda aquí.**
1554
+ *
1555
+ * **Vive en este fichero, exportada, y eso es el arreglo de F1.** Era una copia de campos a
1556
+ * mano enterrada en el cierre de `montarRutas` (`arranque.ts`), a mil líneas del tipo que
1557
+ * traduce y dentro de algo que todos sus tests doblan — o sea el patrón de fallo que
1558
+ * `CLAUDE.md` documenta cinco veces en esta misma tanda: «si una regla de producción se
1559
+ * compone dentro de algo que los tests simulan, esa regla no está probada: está escrita».
1560
+ * `veredicto` se cayó aquí y en el store del cliente sin que nada se pusiera rojo. Ahora
1561
+ * `transporte.test.ts` recorre los campos de `Tarea` y exige decisión explícita por cada
1562
+ * uno.
1563
+ *
1564
+ * Campo a campo, y también DENTRO del veredicto: un `...tarea.veredicto` dejaría pasar sin
1565
+ * nombrar el campo que alguien le añada mañana a `VeredictoDeTarea`.
1566
+ */
1567
+ export declare function filaDeTarea(t: Tarea): TareaDelCable;
1568
+ export interface ProveedorDeModelos {
1569
+ id: string;
1570
+ /**
1571
+ * Cómo se ESCRIBE, que no es el id. Lo pone el servidor (`core/modelos.ts#nombreDeProveedor`)
1572
+ * y no el cliente: capitalizar un id en el navegador daría «Xai» y «Ollama-cloud».
1573
+ */
1574
+ nombre: string;
1575
+ credencial: "puesta" | "falta" | "nativa";
1576
+ /**
1577
+ * La credencial está en `auth.json` — o sea, es NUESTRA y se puede borrar desde la
1578
+ * interfaz. Una que solo viene del entorno no lleva esta marca: desexportar la shell de
1579
+ * nadie no está a nuestro alcance, y ofrecer un botón que no puede cumplir sería peor
1580
+ * que no ofrecerlo. Misma disciplina que el harness de DeepSeek, que solo retira la
1581
+ * credencial cuya referencia puede demostrar suya.
1582
+ */
1583
+ enFichero?: boolean;
1584
+ /** Lo declaró el usuario (`custom:<slug>`), no viene de serie. */
1585
+ personalizado?: boolean;
1586
+ /** Su URL base, SOLO en los personalizados: es lo que tecleó el usuario y lo que hay que
1587
+ * ver al lado de su clave para saber a dónde va. Los de serie la tienen en el repo. */
1588
+ baseUrl?: string;
1589
+ /** Ausente = todavía no se ha consultado su catálogo. Vacío = lo dijo y no ofrece nada. */
1590
+ /**
1591
+ * Los modelos que sirve, con los niveles de ESFUERZO que admite cada uno.
1592
+ *
1593
+ * `esfuerzos` lo calcula el SERVIDOR con la tabla de `core/esfuerzo.ts`: la frontera
1594
+ * prohíbe que el cliente importe de `src/`, y una copia declarada de una tabla que crece
1595
+ * cada vez que se mide un modelo nuevo es un sitio donde quedarse viejo en silencio.
1596
+ * Ausente = ese modelo no admite ninguno, y entonces no se pinta el control.
1597
+ */
1598
+ modelos?: {
1599
+ id: string;
1600
+ nombre?: string;
1601
+ esfuerzos?: Esfuerzo[];
1602
+ }[];
1603
+ /** El catálogo de ESTE proveedor falló. Nunca lleva la clave ni el cuerpo remoto. */
1604
+ error?: string;
1605
+ }
1606
+ export type MensajeDelCliente =
1607
+ /**
1608
+ * `detener`: el botón DETENER y replanificar — `texto` puede ir vacío.
1609
+ * `adjuntos` (IXCODE-7): los NOMBRES que ya se subieron con `POST /adjunto?para=sesion` antes
1610
+ * de mandar este mensaje — nunca bytes por el cable, el molde de siempre.
1611
+ */
1612
+ {
1613
+ clase: "prosa";
1614
+ texto: string;
1615
+ detener?: true;
1616
+ adjuntos?: string[];
1617
+ }
1618
+ /**
1619
+ * «Ponme este modelo», dicho por un control de la interfaz: `proveedor/modelo` y nada
1620
+ * más.
1621
+ *
1622
+ * El cliente NO manda comandos. Podría mandar la prosa `/modelo <id>` —es el mismo
1623
+ * efecto— y estuvo escrito así un rato, pero eso son dos mentiras pequeñas: el transcript
1624
+ * se apunta un acto de USUARIO que nadie tecleó (y de ahí sale el título de la sesión), y
1625
+ * la interfaz queda hablando en la sintaxis de otra piel. Lo que viaja es la intención;
1626
+ * CÓMO se aplica es cosa del servidor, y hoy es reusando el manejador de `COMANDOS` que
1627
+ * ya comparten el terminal y la TUI — la función se comparte, la sintaxis no se exporta.
1628
+ */
1629
+ | {
1630
+ clase: "modelo";
1631
+ id: string;
1632
+ }
1633
+ /**
1634
+ * Cuánto razona el modelo de esta sesión. `nivel` ausente = quitarlo.
1635
+ *
1636
+ * La INTENCIÓN y no la sintaxis, como el modelo: el servidor la aplica encolando el
1637
+ * manejador de `/esfuerzo` que ya comparten el terminal y la TUI. Mandar la prosa
1638
+ * apuntaría en el transcript un acto de usuario que nadie tecleó.
1639
+ *
1640
+ * El nivel NO se comprueba aquí contra el modelo en vigor: se guarda en la sesión y
1641
+ * `construirModelo` lo omite mientras no aplique. Así, cambiar de modelo a uno que sí lo
1642
+ * admite lo recupera solo, en vez de obligar a volver a elegirlo.
1643
+ */
1644
+ | {
1645
+ clase: "esfuerzo";
1646
+ nivel?: Esfuerzo;
1647
+ }
1648
+ /**
1649
+ * El MODO DE ESCRITURA de la sesión abierta: supervisado o autónomo.
1650
+ *
1651
+ * La INTENCIÓN y no la sintaxis, como el modelo y el esfuerzo: el servidor la aplica
1652
+ * encolando el manejador de `/aprobacion` que ya comparten el terminal y la TUI. Un
1653
+ * segundo camino para lo mismo es donde el hueco de política podría reabrirse.
1654
+ *
1655
+ * Lo que el modo gobierna son las escrituras LOCALES: la subida a CloudStudio conserva
1656
+ * su plan y su aprobación en los dos modos, y las guardas de RUTA no se tocan.
1657
+ */
1658
+ | {
1659
+ clase: "modoDeEscritura";
1660
+ modo: "supervisado" | "autonomo";
1661
+ }
1662
+ /**
1663
+ * Abrir una sesión de un proyecto: la que se nombra, o una NUEVA si no se nombra ninguna.
1664
+ *
1665
+ * Es la acción de la barra lateral, y no pasa por el alta: si la copia local ya existe no
1666
+ * hay nada que dar de alta ni rama que preguntar — se abre y ya. Si no existe, el
1667
+ * servidor contesta con las ramas por el camino del alta, que es el que sabe bajarla.
1668
+ */
1669
+ | {
1670
+ clase: "sesion";
1671
+ proyecto: string;
1672
+ sesion?: string;
1673
+ }
1674
+ /**
1675
+ * Lo que se hace con una sesión GUARDADA desde el menú de su fila: borrarla o ponerle
1676
+ * nombre. Va aparte de abrir (arriba) y no como un campo opcional de aquel, porque son
1677
+ * verbos distintos con consecuencias distintas: uno abre y los otros dos escriben en el
1678
+ * índice del proyecto — y borrar, además, puede cerrar la consola si es la sesión abierta.
1679
+ *
1680
+ * `titulo` solo lo lleva «renombrar», y vacío se rechaza en el servidor: dejar el título en
1681
+ * blanco devolvería la sesión al régimen automático y el siguiente turno la rebautizaría
1682
+ * con la primera frase, borrando en silencio el nombre que puso una persona.
1683
+ */
1684
+ | {
1685
+ clase: "sesionAccion";
1686
+ accion: "borrar";
1687
+ proyecto: string;
1688
+ sesion: string;
1689
+ } | {
1690
+ clase: "sesionAccion";
1691
+ accion: "renombrar";
1692
+ proyecto: string;
1693
+ sesion: string;
1694
+ titulo: string;
1695
+ }
1696
+ /** Qué proyectos de un entorno se enseñan en la barra. Lista vacía = ninguno, que es una
1697
+ * elección; para volver a la omisión no hay mensaje, porque no hay «deshacer» que pedir. */
1698
+ | {
1699
+ clase: "entorno";
1700
+ accion: "visibles";
1701
+ entorno: string;
1702
+ proyectos: string[];
1703
+ }
1704
+ /** Qué proyectos de un entorno van FIJADOS arriba de la barra, en su grupo. La lista
1705
+ * ENTERA, no un «fija este»: el cliente la compone y el servidor la guarda tal cual, el
1706
+ * mismo trato que `visibles`. Vacía = ninguno fijado. */
1707
+ | {
1708
+ clase: "entorno";
1709
+ accion: "fijados";
1710
+ entorno: string;
1711
+ proyectos: string[];
1712
+ }
1713
+ /**
1714
+ * Borrar la COPIA LOCAL de un proyecto del entorno activo: vuelve a «sin descargar», y con
1715
+ * ella se van sus sesiones, su historial, sus artefactos y lo que no se haya subido.
1716
+ *
1717
+ * `proyecto` es el ID del listado, no una ruta: la carpeta la compone el servidor a partir
1718
+ * del nombre que ÉL tiene para ese id. Contesta **409 con `{ motivo }`** si no se puede
1719
+ * ahora (un turno en vuelo, una tarea de fondo sin terminar), igual que `olvidar`.
1720
+ */
1721
+ | {
1722
+ clase: "copiaLocal";
1723
+ accion: "borrar";
1724
+ proyecto: string;
1725
+ }
1726
+ /** Abrir la carpeta de la copia local en el explorador de ficheros de la máquina del
1727
+ * servidor. Mismo trato que `borrar`: el ID, nunca una ruta; 409 con `{ motivo }` si no. */
1728
+ | {
1729
+ clase: "copiaLocal";
1730
+ accion: "abrirCarpeta";
1731
+ proyecto: string;
1732
+ }
1733
+ /** Pedir la FOTO del resumen del proyecto. Contesta 200 con un `FotoDelResumen` en la propia
1734
+ * respuesta, o 409 con `{ motivo }`. Mismo trato que `borrar`: el ID, nunca una ruta. */
1735
+ | {
1736
+ clase: "copiaLocal";
1737
+ accion: "resumen";
1738
+ proyecto: string;
1739
+ }
1740
+ /** Fijar —o quitar, sin `modo`— el modo con que nacen las sesiones nuevas de este proyecto
1741
+ * (IXCODE-31). 200 con `{ proyecto? }`, 409 con `{ motivo }` sin copia o con un id ajeno, y
1742
+ * 400 con un modo que no existe. Mismo trato que `resumen`: el ID, nunca una ruta. */
1743
+ | {
1744
+ clase: "copiaLocal";
1745
+ accion: "modoDeEscritura";
1746
+ proyecto: string;
1747
+ modo?: "supervisado" | "autonomo";
1748
+ }
1749
+ /** Fijar el modo con que nacen las sesiones nuevas en cualquier proyecto (Ajustes > General). */
1750
+ | {
1751
+ clase: "modoPorDefecto";
1752
+ modo: "supervisado" | "autonomo";
1753
+ }
1754
+ /** Fijar —o quitar, sin `id`— el aparato de las sesiones nuevas (IXCODE-51). Solo el ID: el resto
1755
+ * sale de la última MEDIDA, como en la pastilla. */
1756
+ | {
1757
+ clase: "dispositivoPorDefecto";
1758
+ id?: string;
1759
+ }
1760
+ /** LEER una conversación sin abrirle consola (IXCODE-36): 200 con `{actos}`, o 409 con `{motivo}`. */
1761
+ | {
1762
+ clase: "leerSesion";
1763
+ proyecto: string;
1764
+ sesion: string;
1765
+ }
1766
+ /** La pestaña Soporte: chats y tareas del proyecto con su análisis previo (`soporte.ts`). */
1767
+ | {
1768
+ clase: "soporte";
1769
+ accion: "listar";
1770
+ proyecto: string;
1771
+ }
1772
+ /**
1773
+ * Quitar un entorno registrado. El servidor contesta **409 con `{ motivo }`** si no se puede
1774
+ * ahora (un proyecto suyo abierto, una tarea sin terminar): la negativa vive allí, y así el
1775
+ * cliente la enseña sin llevar una copia de la regla. Sus copias locales se quedan.
1776
+ */
1777
+ | {
1778
+ clase: "entorno";
1779
+ accion: "olvidar";
1780
+ entorno: string;
1781
+ /** Borrar además `<workspace>/<entorno>/` entera. Solo con la casilla marcada y el
1782
+ * nombre escrito; ausente = las copias se quedan. */
1783
+ borrarCopias?: boolean;
1784
+ }
1785
+ /**
1786
+ * Ponerle NOMBRE a un entorno registrado: el alias con el que se lee en la barra y en su
1787
+ * pestaña de Ajustes. Se escribe a mano porque hasta ahora el nombre lo deducía el
1788
+ * servidor al conectarse, y el «Otro» de un on-premise se quedaba con su host por nombre
1789
+ * para siempre.
1790
+ *
1791
+ * **El `id` NO viaja**: es lo que identifica al entorno —segmento de su carpeta en el
1792
+ * workspace, hueco de sus credenciales— y renombrar no lo toca, así que el cable no puede
1793
+ * ni sugerir que cambie.
1794
+ *
1795
+ * El servidor contesta **409 con `{ motivo }`** si el nombre no vale, igual que `olvidar`.
1796
+ * La regla es SUYA (`core/settings.ts#motivoDeNombreDeEntornoInaceptable`) y la vuelve a
1797
+ * aplicar aunque el cliente ya la tenga —la frontera prohíbe compartir el módulo, así que
1798
+ * `Ajustes.tsx` lleva su copia DECLARADA, para poder avisar mientras se teclea—: la copia
1799
+ * es comodidad, y la negativa que manda es esta, con su motivo en la mano. Dos entornos con
1800
+ * el mismo nombre SÍ se admiten; que se repitan se advierte en la pantalla, que es donde se
1801
+ * ven los dos.
1802
+ */
1803
+ | {
1804
+ clase: "entorno";
1805
+ accion: "renombrar";
1806
+ entorno: string;
1807
+ nombre: string;
1808
+ }
1809
+ /** Cambiar de entorno ACTIVO: el de cuyos proyectos se habla. Trae su listado consigo. */
1810
+ | {
1811
+ clase: "entorno";
1812
+ accion: "activo";
1813
+ entorno: string;
1814
+ }
1815
+ /**
1816
+ * «Dime qué proyectos tiene ESTE entorno», sin hacerlo activo. Es lo que necesita la
1817
+ * pestaña de un entorno en Ajustes para poder marcar sus casillas, y la diferencia con
1818
+ * `activo` es justo lo que la hace usable: abrir Ajustes a elegir proyectos es MIRAR, y
1819
+ * mudar el entorno activo le cambiaría la barra lateral —y los proyectos de los que se
1820
+ * habla— a quien esté trabajando en otro servidor.
1821
+ *
1822
+ * Se pide al abrir esa pestaña y no antes, por lo mismo que el catálogo de un proveedor
1823
+ * (`clase: "catalogo"`): cada uno es una conexión con CloudStudio (OAuth + `initialize` +
1824
+ * `studio_list_projects`), y consultarlos todos al conectar sería gastar una petición por
1825
+ * entorno para pintar unas casillas que quizá nadie abra. La respuesta es
1826
+ * `proyectosDeEntorno`, con su lista o con su `error`.
1827
+ */
1828
+ | {
1829
+ clase: "entorno";
1830
+ accion: "proyectos";
1831
+ entorno: string;
1832
+ }
1833
+ /**
1834
+ * La respuesta a una `pregunta`. `seleccion` solo la manda el diálogo de una decisión
1835
+ * `seleccionable` (la subida a CloudStudio): las rutas que la persona dejó marcadas.
1836
+ * Ausente = el plan entero, o una pregunta que no deja elegir.
1837
+ */
1838
+ | {
1839
+ clase: "respuesta";
1840
+ texto: string;
1841
+ seleccion?: string[];
1842
+ }
1843
+ /**
1844
+ * La respuesta a `seleccionar`. **Sin `id` (o con `id: null`) es CANCELAR**, que es
1845
+ * exactamente lo que `seleccionar` ya devuelve al desconectarse y al vencer su plazo — en
1846
+ * el terminal cancelar es una salida de primera clase («número, Enter cancela»), así que
1847
+ * la web no puede tener menos. Se aprovecha esta clase en vez de añadir otra: el contrato
1848
+ * del cable no crece y la traducción a `undefined` vive en un solo sitio
1849
+ * (`consolaWeb.ts#recibir`). `undefined` viaja como la AUSENCIA del campo, porque
1850
+ * `JSON.stringify` descarta las claves con ese valor; `null` se admite porque es lo que
1851
+ * escribiría un cliente que lo serialice explícitamente, y dice lo mismo.
1852
+ *
1853
+ * Un `id` vacío o desconocido NO es cancelar: es un id que no existe, y así se lo pasa a
1854
+ * quien llamó. Traducirlo aquí a cancelación convertiría el bug de un cliente en un
1855
+ * usuario que se echó atrás.
1856
+ */
1857
+ | {
1858
+ clase: "eleccion";
1859
+ id?: string | null;
1860
+ } | {
1861
+ clase: "secreto";
1862
+ valor: string;
1863
+ }
1864
+ /**
1865
+ * Un paso del alta, resuelto por el wizard. Es UNA clase y no tres porque los tres son
1866
+ * el mismo trámite —el alta— y quien la atiende es un solo sitio (`web/servidor/arranque.ts`);
1867
+ * tres clases obligarían a mantener tres ramas del cable de acuerdo entre sí sin ganar
1868
+ * nada.
1869
+ *
1870
+ * Con `paso` «proyecto» y SIN `rama` no se abre nada: significa «he elegido proyecto,
1871
+ * dime sus ramas», y el servidor contesta con otro mensaje de alta con `ramas` llenas.
1872
+ * Es lo que evita inventarse las ramas del primer proyecto de la lista antes de que
1873
+ * nadie haya elegido — el mismo «lista vacía, no dato inventado» del otro extremo.
1874
+ *
1875
+ * Aquí NO hay campo para la clave de API: el paso de cuenta va por «secreto».
1876
+ */
1877
+ | {
1878
+ clase: "alta";
1879
+ paso: PasoDelVestibulo;
1880
+ entorno?: {
1881
+ id: string;
1882
+ nombre: string;
1883
+ url: string;
1884
+ };
1885
+ proyecto?: string;
1886
+ rama?: string;
1887
+ }
1888
+ /**
1889
+ * El valor es el `Decision["type"]` que el pendiente declara en `decisionesPermitidas`,
1890
+ * no una respuesta tecleada: el cliente son botones. `consolaWeb` lo traduce a la
1891
+ * respuesta que `interpretAnswer` entiende, en vez de comparar cadenas por su cuenta.
1892
+ */
1893
+ /**
1894
+ * «Dime qué modelos sirve este proveedor.» Se pide al abrir el menú de ese proveedor y no
1895
+ * antes: cada uno es una llamada de red. La respuesta es otro mensaje `modelos` con ese
1896
+ * proveedor ya relleno — o con su `error` puesto, que también es una respuesta.
1897
+ */
1898
+ | {
1899
+ clase: "catalogo";
1900
+ proveedor: string;
1901
+ }
1902
+ /**
1903
+ * Vuelve a mirar qué dispositivos y simuladores hay. La respuesta viaja por el SSE como
1904
+ * `dispositivos`, a todos los clientes: la máquina es la misma para todos.
1905
+ */
1906
+ | {
1907
+ clase: "dispositivos";
1908
+ /**
1909
+ * Con `ajustes` se GUARDAN antes de volver a medir; sin ellos solo se vuelve a medir.
1910
+ * Es el mismo mensaje para las dos cosas porque configurar sin remedir dejaría la
1911
+ * pantalla enseñando la foto de la configuración anterior.
1912
+ */
1913
+ ajustes?: AjustesDeDispositivos;
1914
+ /**
1915
+ * Instala una herramienta que falta, y después se vuelve a medir. El comando NO viaja
1916
+ * del cliente: viaja el NOMBRE de la herramienta y el servidor decide qué lanzar
1917
+ * (`INSTALADORES`, tabla cerrada) — un comando que llegue por el cable es una shell
1918
+ * abierta en la máquina del usuario.
1919
+ */
1920
+ instalar?: NombreDeHerramienta;
1921
+ /**
1922
+ * Abre la carpeta que contiene el binario de esta herramienta en el explorador del
1923
+ * SISTEMA donde corre la consola — el mismo límite que el selector de carpeta del
1924
+ * workspace: con la consola por un túnel, el botón no sirve. Solo `adb`/`emulator`
1925
+ * tienen una ruta que abrir; no vuelve a medir ni cambia ningún estado.
1926
+ */
1927
+ abrirRuta?: NombreDeHerramienta;
1928
+ }
1929
+ /**
1930
+ * Con qué dispositivo trabaja la sesión abierta. Viaja el ID y nada más: el servidor lo
1931
+ * resuelve contra la última medida y guarda la foto — un nombre que llegue del cliente no
1932
+ * es una fuente sobre la máquina. Sin `id`, se quita la elección.
1933
+ */
1934
+ | {
1935
+ clase: "dispositivo";
1936
+ id?: string;
1937
+ }
1938
+ /**
1939
+ * «Arranca este AVD.» El nombre y nada más: el servidor comprueba que esté en SU última
1940
+ * medida antes de ejecutar nada, así que por aquí no entra un nombre a ciegas.
1941
+ *
1942
+ * La respuesta es el `dispositivos` de siempre, con la foto nueva y el `arranque` dentro:
1943
+ * arrancar acaba en una medida, no en un acuse.
1944
+ */
1945
+ | {
1946
+ clase: "arrancarEmulador";
1947
+ avd: string;
1948
+ }
1949
+ /**
1950
+ * «Crea un AVD con este nombre.» El servidor valida el nombre (forma, y que no exista en SU
1951
+ * última medida) antes de lanzar `avdmanager`, y lo cuenta como un paso de receta
1952
+ * (`instalacion` con `receta: "crear-avd"`): comparten el cerrojo, uno a la vez.
1953
+ */
1954
+ | {
1955
+ clase: "crearEmulador";
1956
+ nombre: string;
1957
+ base?: string;
1958
+ conDatos?: boolean;
1959
+ }
1960
+ /** Elimina un AVD por su nombre: el servidor lo comprueba contra SU medida (existe, no es el único, está apagado). */
1961
+ | {
1962
+ clase: "eliminarEmulador";
1963
+ avd: string;
1964
+ }
1965
+ /**
1966
+ * Lo de UN AVD: el puerto local del túnel de hotswap y si arranca sin ventana. El AVD tiene
1967
+ * que estar en la última medida y el puerto no puede ser de otro; la respuesta es el
1968
+ * `dispositivos` de siempre, con los `ajustes` nuevos.
1969
+ */
1970
+ | {
1971
+ clase: "ajusteDeAvd";
1972
+ avd: string;
1973
+ puerto?: number;
1974
+ sinVentana?: boolean;
1975
+ }
1976
+ /** «Para este emulador.» El ID de la medida, y solo si es un emulador; después se remide. */
1977
+ | {
1978
+ clase: "pararEmulador";
1979
+ id: string;
1980
+ }
1981
+ /**
1982
+ * VERIFICAR la conexión con un dispositivo: hablarle y esperar respuesta.
1983
+ *
1984
+ * Viaja el ID y nada más, la misma regla que `dispositivo`: el servidor lo resuelve contra
1985
+ * la última MEDIDA y de ahí saca la plataforma y la clase, que son las que deciden qué
1986
+ * comando se lanza. Un id que no esté en la medida se ignora — es una foto vieja del
1987
+ * cliente, no un error.
1988
+ *
1989
+ * **Es un mensaje propio y no un campo de `dispositivos`**, aunque las dos cosas acaben
1990
+ * emitiendo el informe: `dispositivos` significa «vuelve a MEDIR», y una medida nueva se
1991
+ * lleva por construcción todas las verificaciones —viven con la foto—. O sea que meterlo
1992
+ * ahí habría borrado la verificación que se acaba de hacer.
1993
+ */
1994
+ | {
1995
+ clase: "conexion";
1996
+ id: string;
1997
+ }
1998
+ /**
1999
+ * La credencial de un proveedor, desde la ventana de ajustes.
2000
+ *
2001
+ * «pedir» hace que el servidor PREGUNTE por ella (`leerSecreto`), así que la clave sigue
2002
+ * viajando por el ÚNICO mensaje del cable que la lleva («secreto») y este mensaje no la
2003
+ * toca. «borrar» la quita de `auth.json`.
2004
+ *
2005
+ * Podría haber viajado como la prosa `/provider <id>`, que es el mismo diálogo, pero esa
2006
+ * ruta necesita el lazo de `correrConsola` — y el lazo solo existe con un proyecto
2007
+ * abierto. La ventana de ajustes se abre antes, así que tiene su propio mensaje.
2008
+ */
2009
+ | {
2010
+ clase: "credencial";
2011
+ accion: "pedir" | "borrar";
2012
+ proveedor: string;
2013
+ }
2014
+ /**
2015
+ * Dar de alta o retirar un proveedor de modelos PERSONALIZADO: un endpoint compatible
2016
+ * con OpenAI que declara el usuario.
2017
+ *
2018
+ * La clave NO viaja aquí. El alta escribe nombre y URL en el `config.json` global, y la
2019
+ * credencial se pone después con el mismo `{clase:"credencial", accion:"pedir"}` que los
2020
+ * de serie — o sea, por el único mensaje del cable que la lleva. Que sean dos pasos y no
2021
+ * un formulario de tres campos es deliberado: un tercer campo con la clave dentro sería
2022
+ * un segundo camino para lo mismo, y el que menos garantías da.
2023
+ *
2024
+ * El identificador no se teclea: lo deriva el servidor del nombre
2025
+ * (`core/modelos.ts#slugDesdeNombre`). La baja va por ese identificador, que es lo que
2026
+ * la fila conoce.
2027
+ */
2028
+ | {
2029
+ clase: "proveedor";
2030
+ accion: "alta";
2031
+ nombre: string;
2032
+ baseUrl: string;
2033
+ } | {
2034
+ clase: "proveedor";
2035
+ accion: "baja";
2036
+ slug: string;
2037
+ }
2038
+ /**
2039
+ * Dar de alta, cambiar o borrar un subagente.
2040
+ *
2041
+ * `ambito` decide en qué carpeta se escribe, y viaja explícito en vez de deducirse de si
2042
+ * hay proyecto abierto: con uno abierto valen las dos, y adivinar cuál quiere el usuario
2043
+ * es cómo un «revisor» que quería para todos los proyectos acaba escondido en uno.
2044
+ */
2045
+ | {
2046
+ clase: "agente";
2047
+ /**
2048
+ * `restaurar` devuelve un agente de serie a como lo entregamos, y ocupa el sitio del
2049
+ * `borrar` en esos: borrarlo no lo resiembra —la marca recuerda que se entregó—, así
2050
+ * que era perderlo para siempre. El servidor RECHAZA un `borrar` de uno de serie:
2051
+ * esconderle el icono al cliente es presentación, no una guarda.
2052
+ */
2053
+ accion: "guardar" | "borrar" | "restaurar";
2054
+ ambito: "global" | "proyecto";
2055
+ agente: AgenteDelCable;
2056
+ /**
2057
+ * El nombre de ANTES, solo en un renombrado. Ausente = el nombre no cambia, que es lo
2058
+ * que manda un alta y una edición normal.
2059
+ *
2060
+ * Va en el `guardar` y no en una cuarta acción porque renombrar ES guardar: el
2061
+ * formulario permite cambiar el nombre y la descripción en la misma pulsación, y dos
2062
+ * mensajes serían dos escrituras que pueden quedarse a medias. Lo decide el servidor
2063
+ * comparándolo con `agente.nombre`: si son iguales, no hay renombrado.
2064
+ */
2065
+ renombrandoDe?: string;
2066
+ }
2067
+ /**
2068
+ * Dar de alta, cambiar o borrar una skill del USUARIO.
2069
+ *
2070
+ * El mismo molde que `agente`, y las dos diferencias no son de forma:
2071
+ *
2072
+ * - **No hay `restaurar`.** Una skill de serie vive dentro del paquete instalado y nunca
2073
+ * se copia a la casa del usuario, así que no hay marca que recordar ni nada que
2074
+ * reponer: lo que la consola ofrece sobre una de serie es COPIARLA, que es un `guardar`
2075
+ * normal con otro nombre.
2076
+ * - **El servidor RECHAZA guardar o borrar con el nombre de una de serie.** Esconderle el
2077
+ * botón al cliente es presentación, no una guarda; la barrera está aquí.
2078
+ */
2079
+ | {
2080
+ clase: "skill";
2081
+ accion: "guardar" | "borrar";
2082
+ ambito: "global" | "proyecto";
2083
+ skill: SkillDelCable;
2084
+ /** El nombre de ANTES, solo en un renombrado. Ausente = no cambia. Como en `agente`. */
2085
+ renombrandoDe?: string;
2086
+ }
2087
+ /** El cuerpo de una skill, bajo demanda: al abrir su ficha o al copiar una de serie. */
2088
+ | {
2089
+ clase: "cuerpoDeSkill";
2090
+ nombre: string;
2091
+ }
2092
+ /** Parar el turno en vuelo. Aborta el `stream` del grafo (`SesionReal.cancelar`) y deja
2093
+ * la sesión viva: es parar ESTO, no cerrar la conversación. */
2094
+ | {
2095
+ clase: "cancelar";
2096
+ }
2097
+ /** La sesión remota: encenderla, revocar su enlace (apagar y volver a encender) o apagarla. */
2098
+ | {
2099
+ clase: "remoto";
2100
+ accion: "encender" | "revocar" | "apagar";
2101
+ }
2102
+ /** El interruptor de Ajustes: escribe `remoto.habilitado`; desactivar apaga antes lo encendido. */
2103
+ | {
2104
+ clase: "remoto";
2105
+ accion: "habilitar";
2106
+ valor: boolean;
2107
+ }
2108
+ /** Elegir la vía (solo apagada o en error), pedir el authtoken de ngrok (llega por `leerSecreto`) o fijar su dominio. */
2109
+ | {
2110
+ clase: "remoto";
2111
+ accion: "via";
2112
+ via: "servidor" | "ngrok";
2113
+ }
2114
+ /** Con `authtoken`, el tecleado en Ajustes; sin él, se pide por `leerSecreto`. Es un SECRETO del cable:
2115
+ * no se apunta, no se devuelve y no sale más que hacia `guardarAuthtoken`. */
2116
+ | {
2117
+ clase: "remoto";
2118
+ accion: "authtoken";
2119
+ authtoken?: string;
2120
+ } | {
2121
+ clase: "remoto";
2122
+ accion: "dominio";
2123
+ dominio: string;
2124
+ }
2125
+ /** Pide lo que la sesión abierta ha tocado, o el parche de un fichero concreto. */
2126
+ | {
2127
+ clase: "revision";
2128
+ ruta?: string;
2129
+ }
2130
+ /** Lo pendiente de subir (sin `ruta`) o el diff de uno (con `ruta`). */
2131
+ | {
2132
+ clase: "pendientesDeSubida";
2133
+ ruta?: string;
2134
+ }
2135
+ /** Pide el diff SEMÁNTICO de un `.xne` de Revisión. */
2136
+ | {
2137
+ clase: "modeloDelCambio";
2138
+ ruta: string;
2139
+ }
2140
+ /** Pide el árbol del proyecto abierto, o el contenido de una ruta relativa a su raíz. */
2141
+ | {
2142
+ clase: "arbol";
2143
+ }
2144
+ /** Pide la foto del modelo XOne del proyecto abierto (pestaña Colecciones). */
2145
+ | {
2146
+ clase: "colecciones";
2147
+ }
2148
+ /** Pide los planes del proyecto abierto (pestaña Planes). */
2149
+ | {
2150
+ clase: "planes";
2151
+ }
2152
+ /**
2153
+ * El gestor de tareas del proyecto abierto (IXCODE-11). Leer (`estado`, `sitios`,
2154
+ * `proyectos`, `pendientes`), vincular y desvincular el proyecto del gestor, marcar qué
2155
+ * conectores usa, y `empezar`: abre una sesión NUEVA ligada a esa tarea y contesta con el
2156
+ * borrador para el compositor. Nada de esto escribe en el gestor todavía.
2157
+ */
2158
+ | {
2159
+ clase: "gestor";
2160
+ accion: "estado";
2161
+ } | {
2162
+ clase: "gestor";
2163
+ accion: "sitios";
2164
+ conector: string;
2165
+ } | {
2166
+ clase: "gestor";
2167
+ accion: "proyectos";
2168
+ conector: string;
2169
+ sitio: string;
2170
+ }
2171
+ /** IXCODE-15, de solo LECTURA: buscar proyectos por texto (Notion: sus bases). */
2172
+ | {
2173
+ clase: "gestor";
2174
+ accion: "buscarProyectos";
2175
+ conector: string;
2176
+ texto: string;
2177
+ }
2178
+ /** IXCODE-15, de solo LECTURA: lo que se entiende del esquema de un proyecto antes de vincularlo. */
2179
+ | {
2180
+ clase: "gestor";
2181
+ accion: "describir";
2182
+ conector: string;
2183
+ proyecto: string;
2184
+ } | {
2185
+ clase: "gestor";
2186
+ accion: "vincular";
2187
+ conector: string;
2188
+ sitio: string;
2189
+ proyecto: string;
2190
+ } | {
2191
+ clase: "gestor";
2192
+ accion: "desvincular";
2193
+ }
2194
+ /** Los estados del flujo del proyecto vinculado y el mapeo propuesto, contestados en la respuesta (la puerta 2). */
2195
+ | {
2196
+ clase: "gestor";
2197
+ accion: "estadosDelFlujo";
2198
+ }
2199
+ /** Guardar el mapeo de estados y el interruptor del disparo del vínculo (la puerta 2). */
2200
+ | {
2201
+ clase: "gestor";
2202
+ accion: "ajustarVinculo";
2203
+ estados: MapeoDeEstados;
2204
+ automatico: boolean;
2205
+ revisarEncargo?: boolean;
2206
+ } | {
2207
+ clase: "gestor";
2208
+ accion: "usarConector";
2209
+ conector: string;
2210
+ usar: boolean;
2211
+ } | {
2212
+ clase: "gestor";
2213
+ accion: "pendientes";
2214
+ texto?: string;
2215
+ mias?: boolean;
2216
+ }
2217
+ /** La descripción de una tarea (la fila desplegada del panel). De solo LECTURA. */
2218
+ | {
2219
+ clase: "gestor";
2220
+ accion: "ficha";
2221
+ clave: string;
2222
+ }
2223
+ /**
2224
+ * Task 10 (IXCODE-11): las ÚNICAS cuatro acciones que ESCRIBEN en Jira, siempre por un
2225
+ * mensaje EXPLÍCITO del cliente —la persona aprobó una tarjeta—, nunca solas. `transiciones`
2226
+ * es de solo LECTURA (pide la lista); `empezar` con `transicion` transiciona ANTES de abrir
2227
+ * la sesión; `borradorDeCierre` también es de solo lectura (compone el texto, no lo manda);
2228
+ * `cerrar` comenta y, si hay `transicion`, transiciona.
2229
+ */
2230
+ | {
2231
+ clase: "gestor";
2232
+ accion: "transiciones";
2233
+ clave: string;
2234
+ para: "empezar" | "cerrar";
2235
+ } | {
2236
+ clase: "gestor";
2237
+ accion: "empezar";
2238
+ clave: string;
2239
+ transicion?: string;
2240
+ } | {
2241
+ clase: "gestor";
2242
+ accion: "borradorDeCierre";
2243
+ } | {
2244
+ clase: "gestor";
2245
+ accion: "cerrar";
2246
+ comentario: string;
2247
+ transicion?: string;
2248
+ } | {
2249
+ clase: "fichero";
2250
+ ruta: string;
2251
+ }
2252
+ /**
2253
+ * Guardar lo que la persona editó. La única escritura del cliente en un fichero del proyecto:
2254
+ * sin tarjeta de aprobación porque lo teclea ella, con las guardas de ruta de leer y negada con
2255
+ * un turno o una tarea en marcha en esa raíz. `huella` es la del fichero que se cargó, y
2256
+ * `proyecto` el `proyectoActivo` con que se ABRIÓ la edición: si el foco ya es otro, se niega.
2257
+ */
2258
+ | {
2259
+ clase: "guardarFichero";
2260
+ ruta: string;
2261
+ texto: string;
2262
+ huella: string;
2263
+ id: string;
2264
+ proyecto: string;
2265
+ /** Tras guardar, llevarlo al aparato de la sesión. Nunca hace fallar el guardado. */
2266
+ recargar?: true;
2267
+ }
2268
+ /** Pedir la base de comparación de un fichero: la foto del inicio de la sesión o el último commit. */
2269
+ | {
2270
+ clase: "baseDeFichero";
2271
+ ruta: string;
2272
+ base: "sesion" | "commit";
2273
+ }
2274
+ /**
2275
+ * La sincronización con CloudStudio del proyecto abierto (pestaña CloudStudio).
2276
+ * `estado` pide la medida; `subir` y `bajar` son las dos acciones de `/sync`.
2277
+ *
2278
+ * Viaja la INTENCIÓN, no la sintaxis: el servidor las aplica encolando `/sync <accion>`
2279
+ * en el lazo (`arranque.ts#atenderSync`), así que el plan, la guarda de árbol sucio y la
2280
+ * aprobación salen por donde ya salían — la aprobación es la pregunta de siempre, que es
2281
+ * la que autoriza la escritura. Un `git push` desde el cliente no existiría ni aunque
2282
+ * quisiéramos: la copia la mueve `agent/cloudstudio/subida.ts` llamando a las tools MCP.
2283
+ */
2284
+ | {
2285
+ clase: "sync";
2286
+ accion: "estado" | "subir" | "bajar";
2287
+ }
2288
+ /**
2289
+ * El contenido de un artefacto de la sesión abierta. Se pide por NOMBRE y no por ruta: la
2290
+ * carpeta la compone el servidor con el id del hilo, y aceptar una ruta del cliente sería
2291
+ * abrir a negociación justo la parte que es una barrera.
2292
+ */
2293
+ /** Con `proyecto` y `sesion`: el de esa conversación, que se LEE sin consola, contestado en la propia respuesta. */
2294
+ | {
2295
+ clase: "artefacto";
2296
+ nombre: string;
2297
+ proyecto?: string;
2298
+ sesion?: string;
2299
+ }
2300
+ /**
2301
+ * Ejecuta —o cancela— un paso de una receta de instalación.
2302
+ *
2303
+ * Viajan el NOMBRE de la receta y el NÚMERO del paso, nunca un comando ni un binario: un
2304
+ * comando que llegue del cliente es una shell abierta en la máquina del usuario. Qué se
2305
+ * lanza lo decide una tabla cerrada del host (`agent/dispositivos/instalacionEnMaquina.ts`).
2306
+ */
2307
+ | {
2308
+ clase: "receta";
2309
+ id: string;
2310
+ paso: number;
2311
+ accion: "ejecutar" | "cancelar";
2312
+ }
2313
+ /** Los modelos que ofrece un MOTOR externo, para el desplegable de un subagente. Se pide
2314
+ * bajo demanda: el de Codex se le pregunta a él, y eso arranca un proceso. */
2315
+ | {
2316
+ clase: "modelosDeMotor";
2317
+ motor: string;
2318
+ }
2319
+ /** Medir el diagnóstico de Node (Ajustes → General, «Comprobar»). */
2320
+ | {
2321
+ clase: "diagnosticoNode";
2322
+ }
2323
+ /** El diseño vinculado (Stitch): leer, listar proyectos, vincular, desvincular o listar sus pantallas. */
2324
+ | {
2325
+ clase: "diseno";
2326
+ accion: "estado" | "proyectos" | "desvincular" | "pantallas";
2327
+ proyecto?: string;
2328
+ } | {
2329
+ clase: "diseno";
2330
+ accion: "vincular";
2331
+ proyecto?: string;
2332
+ vinculo: {
2333
+ proyecto: string;
2334
+ nombre: string;
2335
+ };
2336
+ }
2337
+ /**
2338
+ * Una acción sobre un motor local. La INTENCIÓN, no el comando: qué binario y con qué
2339
+ * argumentos lo decide el servidor (`agent/motores/motoresLocales.ts`). `codigo` es el que la
2340
+ * web de Claude enseña al terminar cuando el navegador no pudo volver solo: va al `stdin` del
2341
+ * `auth login` en curso y a ningún otro sitio.
2342
+ */
2343
+ | {
2344
+ clase: "motorLocal";
2345
+ accion: "medir" | "probar" | "login" | "codigo" | "cancelar" | "navegador" | "consola" | "modelo";
2346
+ motor?: string;
2347
+ modo?: "claudeai" | "console";
2348
+ codigo?: string;
2349
+ /** Con `accion: "modelo"`: el elegido (`proveedor/modelo`); ausente o vacío lo quita. */
2350
+ modelo?: string;
2351
+ }
2352
+ /**
2353
+ * Las acciones sobre una tarea. Viaja el ID del proyecto y su nombre, NUNCA su raíz: es
2354
+ * una ruta de la máquina, y el cable puede ir por un túnel.
2355
+ */
2356
+ /**
2357
+ * `borrador` es el identificador bajo el que ya se subieron los adjuntos por
2358
+ * `POST /adjunto` — los bytes tienen que estar en disco ANTES de crear la tarea, porque
2359
+ * crear la encola y el corredor puede arrancarla en el acto. El servidor lo ADOPTA como
2360
+ * id de la tarea si es un segmento llano y no es ya una tarea; los adjuntos los lee del
2361
+ * disco, nunca de lo que diga el cliente.
2362
+ */
2363
+ | {
2364
+ clase: "tarea";
2365
+ accion: "crear";
2366
+ proyecto: string;
2367
+ peticion: string; /** Vacío o ausente = lo prepara el servidor al encolar. */
2368
+ encargo?: string;
2369
+ borrador?: string;
2370
+ pantallaDeStitch?: {
2371
+ name: string;
2372
+ titulo: string;
2373
+ };
2374
+ } | {
2375
+ clase: "tarea";
2376
+ accion: "augmentar";
2377
+ proyecto: string;
2378
+ peticion: string;
2379
+ borrador?: string;
2380
+ pantallaDeStitch?: {
2381
+ name: string;
2382
+ titulo: string;
2383
+ };
2384
+ }
2385
+ /**
2386
+ * Una PROPUESTA de tareas encadenadas (el acto `propuesta-de-tareas`): encolarla en orden o
2387
+ * descartarla. Viaja el id de la propuesta y, al encolar, los encargos que la persona revisó (la
2388
+ * petición del orquestador, que no se vuelve a redactar), UNO por tarea y en orden; títulos, peticiones y adjuntos los saca el servidor del
2389
+ * acto, nunca del cliente. Encolar contesta en la propia respuesta: `{encoladas, faltan?}` o 409
2390
+ * con `{motivo}`.
2391
+ */
2392
+ /** `enChat`: se descarta para hacerlo en ESTA conversación; el cliente manda luego la prosa que lo pide. */
2393
+ | {
2394
+ clase: "tarea";
2395
+ accion: "descartarPropuesta";
2396
+ proyecto: string;
2397
+ propuesta: string;
2398
+ enChat?: true;
2399
+ } | {
2400
+ clase: "tarea";
2401
+ accion: "crearEncadenadas";
2402
+ proyecto: string;
2403
+ propuesta: string;
2404
+ encargos: string[];
2405
+ }
2406
+ /**
2407
+ * «Se edita la tarea y se agrega el feedback del usuario» (§0 del diseño): la respuesta a
2408
+ * una tarea «esperando feedback», que la devuelve al lazo en su MISMO hilo. Es su propia
2409
+ * variante y no un tercer campo opcional en `reintentar` porque lleva `texto` y las otras
2410
+ * tres no llevan nada — un campo que solo tiene sentido en una de cuatro acciones es la
2411
+ * misma mentira por omisión que una lista vacía rellenada.
2412
+ */
2413
+ | {
2414
+ clase: "tarea";
2415
+ accion: "feedback";
2416
+ id: string;
2417
+ texto: string;
2418
+ }
2419
+ /**
2420
+ * «Continuar» una tarea aparcada sin escribir nada (entra en su hilo `TEXTO_DE_CONTINUAR`), y «Arrancar ahora» una
2421
+ * `nuevo` que no espera a ninguna anterior: la persona CEDE el proyecto —se cierra su consola de ahí si no está
2422
+ * trabajando— y la tarea arranca. Las dos contestan 409 con `{motivo}` si no se puede.
2423
+ */
2424
+ | {
2425
+ clase: "tarea";
2426
+ accion: "continuar";
2427
+ id: string;
2428
+ } | {
2429
+ clase: "tarea";
2430
+ accion: "arrancarAhora";
2431
+ id: string;
2432
+ }
2433
+ /** Editar el encargo de una tarea que todavía no ha arrancado (IXCODE-52). 204, o 409 con `{motivo}`. */
2434
+ | {
2435
+ clase: "tarea";
2436
+ accion: "encargo";
2437
+ id: string;
2438
+ encargo: string;
2439
+ peticion?: string;
2440
+ pantallaDeStitch?: {
2441
+ name: string;
2442
+ titulo: string;
2443
+ } | null;
2444
+ }
2445
+ /** Volver a preparar el encargo desde la petición editada, SIN guardarlo (IXCODE-53). 200 con `{encargo}`, o 409 con `{motivo}`. */
2446
+ | {
2447
+ clase: "tarea";
2448
+ accion: "regenerarEncargo";
2449
+ id: string;
2450
+ peticion: string;
2451
+ }
2452
+ /** Con qué gestor vivirá una tarea nueva de ese proyecto: contestado en la propia respuesta, `{gestor?: {conector, proyecto}}`. */
2453
+ | {
2454
+ clase: "tarea";
2455
+ accion: "destino";
2456
+ proyecto: string;
2457
+ }
2458
+ /** «Mirar ahora»: una pasada del sondeo del gestor (la puerta 2), contestada con lo que hizo. */
2459
+ | {
2460
+ clase: "tarea";
2461
+ accion: "mirarGestor";
2462
+ }
2463
+ /** PARAR una tarea en marcha sin borrarla (IXCODE-50): queda aparcada con su conversación. 204, o 409 con `{motivo}`. */
2464
+ | {
2465
+ clase: "tarea";
2466
+ accion: "parar";
2467
+ id: string;
2468
+ } | {
2469
+ clase: "tarea";
2470
+ accion: "reintentar" | "descartar" | "terminar";
2471
+ id: string;
2472
+ }
2473
+ /** Cambia el tope de concurrencia de la cola de tareas. */
2474
+ | {
2475
+ clase: "tareas";
2476
+ concurrencia: number;
2477
+ }
2478
+ /**
2479
+ * Elige dónde se bajan las copias locales. Acepta `~/…` y absolutas; la regla de qué vale
2480
+ * es `core/settings.ts#motivoDeWorkspaceInaceptable`, y se aplica en el SERVIDOR además de
2481
+ * en la pantalla — el cliente lleva su copia DECLARADA, como la de la URL de un entorno y
2482
+ * la del slug de un subagente, porque la frontera prohíbe compartir módulo.
2483
+ *
2484
+ * **MUDA lo que ya está bajado** (`vestibulo.mudarWorkspace`), en dos actos: `planear`
2485
+ * contesta en la PROPIA respuesta qué se movería o por qué no se puede, sin tocar nada; sin
2486
+ * `accion` (o con `aplicar`) se cambia de verdad, y el recorrido llega por
2487
+ * `mudanzaDeWorkspace`.
2488
+ */
2489
+ | {
2490
+ clase: "workspace";
2491
+ ruta: string;
2492
+ accion?: "planear" | "aplicar";
2493
+ }
2494
+ /** Cambia la casilla «Depurar» de Ajustes > General. */
2495
+ | {
2496
+ clase: "depuracion";
2497
+ activa: boolean;
2498
+ }
2499
+ /** Abre el selector de carpeta NATIVO **de la máquina donde corre la consola** — ver
2500
+ * `core/selectorDeCarpeta.ts` para por qué no lo puede poner el navegador. */
2501
+ | {
2502
+ clase: "elegirCarpeta";
2503
+ }
2504
+ /**
2505
+ * Empezar (`ver: true`) o dejar de mirar en vivo lo que hace una tarea.
2506
+ *
2507
+ * **`cliente` es lo que hace que esto sea por CLIENTE y no una emisión a todos.** El SSE
2508
+ * y el `POST /accion` son dos peticiones distintas, así que el único sitio con un sumidero
2509
+ * en la mano es la ruta del SSE: sin un identificador, el servidor no podría saber a qué
2510
+ * pestaña engancharle la mirada, y tendría que mandarle el transcript de la tarea a todo
2511
+ * el mundo. Lo elige el cliente —una vez por conexión— igual que elige el id de una tarea
2512
+ * al subirle un adjunto por `POST /adjunto`, y se valida como un segmento llano; uno que
2513
+ * no conste es un fallo de lookup y no un error que contar.
2514
+ *
2515
+ * `ver` es explícito y no «ausente = dejar de mirar»: son dos intenciones opuestas y
2516
+ * confundirlas dejaría un sumidero enganchado a un turno que nadie mira.
2517
+ */
2518
+ | {
2519
+ clase: "mirar";
2520
+ tarea: string;
2521
+ ver: boolean;
2522
+ cliente: string;
2523
+ }
2524
+ /**
2525
+ * Vuelve a MEDIR si se puede lanzar la app del proyecto abierto, y contesta con un `lanzable`.
2526
+ *
2527
+ * Sin datos, y no es una comodidad: el veredicto se compone de la elección de dispositivo de
2528
+ * la SESIÓN, de la última medida de la máquina y de los descriptores del PROYECTO abierto —
2529
+ * tres cosas que el navegador no tiene y sobre las que no es fuente. Que el cliente pudiera
2530
+ * mandar «lanza el proyecto X en el aparato Y» sería abrir a negociación justo lo que decide
2531
+ * si se lanza o no.
2532
+ */
2533
+ | {
2534
+ clase: "revisarLanzamiento";
2535
+ }
2536
+ /**
2537
+ * Lanza la app del proyecto abierto en el dispositivo de la sesión.
2538
+ *
2539
+ * **Sin datos tampoco, y aquí es la regla entera**: ni el dispositivo, ni el nombre de la app,
2540
+ * ni una ruta, ni siquiera el proyecto — los tres primeros son datos sobre la máquina y sobre
2541
+ * el proyecto, y el cuarto lo resuelve el servidor de la consola que atiende. Y el servidor
2542
+ * **revalida antes de empezar**: entre el veredicto y este clic pueden pasar minutos, y un
2543
+ * `lanzarApp` sobre un proyecto que ya no cumple se contesta con un `lanzamiento` en `fallo`,
2544
+ * no lanzando a ciegas.
2545
+ */
2546
+ | {
2547
+ clase: "lanzarApp";
2548
+ }
2549
+ /**
2550
+ * Para el lanzamiento en curso. Es parar ESTO, no cerrar nada — la misma distinción que
2551
+ * `cancelar` con un turno: el recorrido queda en `cancelada` con lo que ya se había contado.
2552
+ *
2553
+ * Un lanzamiento a la vez por consola, así que no lleva id: no hay dos entre los que elegir.
2554
+ */
2555
+ | {
2556
+ clase: "cancelarLanzamiento";
2557
+ }
2558
+ /**
2559
+ * Llevar un fichero ya guardado al aparato de la sesión. `probar`: si la app no corre, desplegar
2560
+ * el proyecto entero (lo de Ejecutar). `relanzar`: relanzar la app (lo que pide un CSS).
2561
+ */
2562
+ | {
2563
+ clase: "recargarEnAparato";
2564
+ ruta: string;
2565
+ probar?: true;
2566
+ relanzar?: true;
2567
+ }
2568
+ /**
2569
+ * Una acción sobre UN conector: añadirlo, quitarlo, probarlo, autorizarlo, desconectarlo o
2570
+ * darlo de alta a mano. Una `accion` que no sea una de esas seis se rechaza con 400 y no hace
2571
+ * nada.
2572
+ *
2573
+ * **Son DOS formas y no una con campos opcionales**, porque `crear` no lleva `id`: el id lo
2574
+ * DERIVA el servidor del nombre (y por eso tampoco se puede elegir desde fuera, que sería
2575
+ * dejar que el cliente nombre una clave de fichero). Su `definicion` viaja sin comprobar por
2576
+ * tipo —un cliente puede mentir sobre lo que el tipo promete— y quien la mira de verdad es
2577
+ * `definicionDelCable` en el servidor.
2578
+ *
2579
+ * El resultado NO viaja en la respuesta: `probar` y `autorizar` corren en segundo plano
2580
+ * (red, o esperar al navegador) y lo que cambien llega por el `conectores` que sigue, vía
2581
+ * `alCambiar` del servicio — el mismo molde que `dispositivo`/`conexion`.
2582
+ */
2583
+ | {
2584
+ clase: "conector";
2585
+ accion: "crear";
2586
+ definicion: DefinicionDeConector;
2587
+ } | {
2588
+ clase: "conector";
2589
+ accion: "anadir" | "quitar" | "probar" | "autorizar" | "desconectar";
2590
+ id: string;
2591
+ } | {
2592
+ clase: "decision";
2593
+ decisiones: Record<string, string>;
2594
+ };
2595
+ /**
2596
+ * Un subagente tal y como viaja: los campos del `.md` y de dónde salió.
2597
+ *
2598
+ * `origen` es de solo lectura —lo pone el servidor al leer— y sirve para que la ventana
2599
+ * pueda decir si un agente viene del global o del proyecto, que es lo que explica por qué
2600
+ * editarlo aquí no afecta a los demás proyectos.
2601
+ */
2602
+ export interface AgenteDelCable {
2603
+ nombre: string;
2604
+ descripcion: string;
2605
+ motor: string;
2606
+ modelo?: string;
2607
+ soloLectura: boolean;
2608
+ /**
2609
+ * Si puede EJECUTAR comandos en la máquina. **Ausente es que no**: es una capacidad, y una
2610
+ * capacidad que se concede por omisión es la que nadie decidió conceder.
2611
+ *
2612
+ * Solo tiene efecto con `motor: "modelo"`; en los tres externos la shell está cerrada a
2613
+ * propósito y esto no la abre, así que la ventana lo dice en vez de pintar una casilla
2614
+ * marcada que no hace nada.
2615
+ */
2616
+ ejecucion?: boolean;
2617
+ /**
2618
+ * Cuánto razona su modelo antes de contestar. Ausente = no se manda el parámetro.
2619
+ *
2620
+ * Solo tiene efecto con `motor: "modelo"`: en los tres externos el modelo lo construye el
2621
+ * hijo en su proceso y un campo nuestro no llega hasta allí. Qué niveles admite depende
2622
+ * del modelo elegido (`core/esfuerzo.ts`), y por eso la ventana lo pinta pegado a él.
2623
+ */
2624
+ esfuerzo?: Esfuerzo;
2625
+ skills: string[];
2626
+ instrucciones: string;
2627
+ origen?: string;
2628
+ /**
2629
+ * De quién es el fichero, que NO es lo mismo que `origen` —esa es la carpeta— y decide qué
2630
+ * botón lleva la tarjeta: ausente, la papelera; `modificada`, «Restaurar el de serie».
2631
+ * Los tres estados y su porqué, en `core/agentes.ts#AgenteCargado`.
2632
+ */
2633
+ semilla?: "intacta" | "modificada";
2634
+ }
2635
+ /**
2636
+ * Una skill tal como viaja: nunca su carpeta, que es una ruta de la máquina (`sinRutas`).
2637
+ *
2638
+ * **`cuerpo` solo lo llevan las del usuario, y su ausencia significa «esta no se edita».**
2639
+ * Las de serie son nueve ficheros que pueden pasar de veinte mil caracteres cada uno: si
2640
+ * viajaran todas en la ráfaga de bienvenida, abrir la consola costaría cientos de kilobytes
2641
+ * para rellenar un formulario que nadie puede guardar. Se piden una a una cuando alguien
2642
+ * quiere verlas o copiarlas (`clase: "cuerpoDeSkill"`), que es cuando el coste se justifica.
2643
+ *
2644
+ * `origen` dice de DÓNDE sale y es de solo lectura: separa las dos pestañas y explica por
2645
+ * qué editar la del proyecto no toca a los demás proyectos. `ficheros` son los anexos por
2646
+ * NOMBRE y sin contenido — una skill puede ser una carpeta entera, y una ventana que solo
2647
+ * enseña el `SKILL.md` haría creer que editarlo es editarla toda.
2648
+ */
2649
+ export interface SkillDelCable {
2650
+ nombre: string;
2651
+ descripcion: string;
2652
+ origen: "serie" | "global" | "proyecto";
2653
+ tokens: number;
2654
+ ficheros: string[];
2655
+ /**
2656
+ * El frontmatter del `SKILL.md` tal cual, sin los `---`.
2657
+ *
2658
+ * Viaja SIEMPRE —también en las de serie— y no con el cuerpo, porque son cuatro líneas y
2659
+ * es lo que contesta «qué declara este fichero»: `description` no es lo único que puede
2660
+ * haber ahí (`archify` lleva `license` y un bloque `metadata`), y enseñar solo la
2661
+ * descripción haría creer que eso es todo. Al guardar vuelve, y `escribirSkill` conserva
2662
+ * las claves que no entendemos en vez de borrárselas al usuario en silencio.
2663
+ */
2664
+ frontmatter?: string;
2665
+ /** Ausente en las de serie, y en la que se está creando. Ver arriba. */
2666
+ cuerpo?: string;
2667
+ }
2668
+ /** A dónde escribe el SSE. Ausente = no hay nadie al otro lado. */
2669
+ export type Sumidero = (mensaje: MensajeAlCliente) => void;
2670
+ export interface Transporte {
2671
+ /**
2672
+ * Un cliente abre el SSE. Devuelve los actos que hay que reemitirLE: quien registra la
2673
+ * ruta los manda como una `reemision` con su propia escritura —solo a ese sumidero—, así
2674
+ * que esto NO los emite; hacerlo se los mandaría también a los demás clientes, que ya
2675
+ * tienen el transcript.
2676
+ *
2677
+ * **Se admite más de uno.** Antes había UNA ranura y el último en conectar desplazaba al
2678
+ * anterior en silencio: la pestaña vieja se quedaba con el SSE abierto y sin recibir
2679
+ * nada, así que su interfaz se congelaba en el último estado que le llegó —medido con
2680
+ * una pestaña local y otra por un túnel: el menú de modelos se quedaba en «consultando…»
2681
+ * para siempre porque la respuesta se la llevaba la otra—. Un servidor que acepta la
2682
+ * conexión tiene que hablarle.
2683
+ */
2684
+ conectar(enviar?: Sumidero): readonly Acto[];
2685
+ /**
2686
+ * Un SSE se cae, o se cierra una pestaña. Con el sumidero se dice CUÁL se va; sin él se
2687
+ * van todos (es lo que hace `cerrar`).
2688
+ *
2689
+ * Fail-closed sigue significando lo mismo, pero sobre el conjunto: quien espera respuesta
2690
+ * deja de esperar cuando se va el ÚLTIMO cliente, no el primero. Cortar a la primera baja
2691
+ * rechazaría la aprobación que otra pestaña abierta todavía tiene delante.
2692
+ */
2693
+ desconectar(enviar?: Sumidero): void;
2694
+ /**
2695
+ * El cable se MUDA a otra consola: se sueltan los sumideros y NADA más.
2696
+ *
2697
+ * La diferencia con `desconectar` es toda la razón de que exista, y es de significado, no
2698
+ * de implementación: `desconectar` afirma «se ha ido el humano» —despierta con la cadena
2699
+ * vacía a todo el que esperaba respuesta y da por rechazada la aprobación que hubiera
2700
+ * delante—, y eso es cierto cuando el SSE se cae y FALSO cuando alguien cambia de sesión
2701
+ * en la barra teniendo esta con un turno corriendo: la persona sigue ahí, mirando otra
2702
+ * cosa. Con `soltar`, `conectado()` sigue diciendo que hay alguien —así que su aprobación
2703
+ * espera su plazo en vez de rechazarse sola— y lo que se emita mientras tanto no llega a
2704
+ * ningún socket, que es exactamente lo que se quiere: los actos de un turno de segundo
2705
+ * plano no pueden aparecer en la conversación que se está mirando.
2706
+ *
2707
+ * Los MIRONES no se sueltan: los quita `dejarDeMirar`, y aquí la consola no se cierra
2708
+ * —su socket sigue vivo—, al contrario que en `desconectar()` sin sumidero.
2709
+ */
2710
+ soltar(enviar?: Sumidero): void;
2711
+ /** ¿Queda alguien al otro lado? Es lo que `consolaWeb.eof()` usa para saber si hay humano. */
2712
+ conectado(): boolean;
2713
+ /**
2714
+ * Alguien MIRA lo que esta consola pinta, sin ser su cliente. Devuelve el transcript de
2715
+ * ese instante, igual que `conectar` y por lo mismo: emitirlo aquí se lo mandaría también
2716
+ * a los demás, que ya lo tienen.
2717
+ *
2718
+ * Es un conjunto APARTE del de los clientes, y las dos diferencias son el motivo de que
2719
+ * exista en vez de reusar `conectar`:
2720
+ * - **No cuenta como cliente**, así que `conectado()` —y con él `consolaWeb.eof()`— sigue
2721
+ * diciendo la verdad. Medido antes de escribir esto: con un `conectar` de más, el
2722
+ * `eof()` de la consola de una tarea de fondo pasaba de `true` a `false`, o sea «hay un
2723
+ * humano al que preguntar». Y no lo hay: esta vista es de SOLO lectura, no tiene
2724
+ * compositor y nadie puede contestar una pregunta ni aprobar una escritura desde ahí.
2725
+ * Irse el último mirón tampoco dispara `alDesconectar`: no ha dejado a nadie sin
2726
+ * contestar.
2727
+ * - **Recibe SOLO el transcript** (`acto`, `sustitucion`, `reemision`). Por el transporte
2728
+ * de una consola de tarea viaja además el mensaje `turno` de los flancos —lo emite el
2729
+ * envoltorio del ejecutor sin mirar `alCable`, medido—, y ese mensaje apagaría el
2730
+ * compositor de quien mira por un turno que no es suyo. La lista es BLANCA a propósito:
2731
+ * una clase nueva no llega a un mirón hasta que alguien la nombre aquí.
2732
+ */
2733
+ mirar(enviar: Sumidero): readonly Acto[];
2734
+ /** Se va UN mirón. Los demás siguen: dos personas pueden mirar la misma tarea. */
2735
+ dejarDeMirar(enviar: Sumidero): void;
2736
+ /**
2737
+ * Produce un mensaje: lo anota en la traza y, si hay cliente, lo escribe. Anota aunque
2738
+ * no haya nadie porque la traza cuenta lo que el servidor PRODUJO — que es lo que los
2739
+ * tests de «esto no viaja» tienen que poder mirar.
2740
+ */
2741
+ emitir(mensaje: MensajeAlCliente): void;
2742
+ /**
2743
+ * La traza de todo lo producido MENOS la aprobación. No es una lista arbitraria: es la
2744
+ * frontera del invariante — el contenido de fichero está en el mensaje de aprobación y
2745
+ * en ninguna otra clase de mensaje, y así un test lo puede afirmar sobre todo el resto.
2746
+ */
2747
+ emitidos(): readonly MensajeAlCliente[];
2748
+ /** Se llama al desconectar: por aquí se despierta a todo el que esperaba respuesta. */
2749
+ alDesconectar(escucha: () => void): void;
2750
+ }
2751
+ export declare function crearTransporte(actos: () => readonly Acto[]): Transporte;