xonecode 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (406) hide show
  1. package/README.md +49 -7
  2. package/THIRD_PARTY_NOTICES.md +128 -0
  3. package/apps/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  4. package/apps/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  5. package/apps/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  6. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  7. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  8. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  9. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  10. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  11. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  12. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  13. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  14. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  15. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  16. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  17. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  18. package/apps/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  19. package/apps/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  20. package/apps/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  21. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  22. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  23. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  24. package/apps/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  25. package/apps/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  26. package/apps/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  27. package/apps/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  28. package/apps/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  29. package/apps/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  30. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  31. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  32. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  33. package/apps/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  34. package/apps/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  35. package/apps/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  36. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  37. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  38. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  39. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  40. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  41. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  42. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  43. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  44. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  45. package/apps/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  46. package/apps/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  47. package/apps/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  48. package/apps/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  49. package/apps/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  50. package/apps/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  51. package/apps/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  52. package/apps/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  53. package/apps/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  54. package/apps/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  55. package/apps/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  56. package/apps/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  57. package/apps/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  58. package/apps/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  59. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  60. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  61. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  62. package/apps/web/dist/assets/c-BIGW1oBm.js +1 -0
  63. package/apps/web/dist/assets/cpp-DddhVWhK.js +1 -0
  64. package/apps/web/dist/assets/csharp-DSvCPggb.js +1 -0
  65. package/apps/web/dist/assets/css-CLj8gQPS.js +1 -0
  66. package/apps/web/dist/assets/go-C27-OAKa.js +1 -0
  67. package/apps/web/dist/assets/html-CfGypltT.js +1 -0
  68. package/apps/web/dist/assets/index-BB3SamhR.css +1 -0
  69. package/apps/web/dist/assets/index-CFYAoHdw.js +477 -0
  70. package/apps/web/dist/assets/ini-BEwlwnbL.js +1 -0
  71. package/apps/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  72. package/apps/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  73. package/apps/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  74. package/apps/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  75. package/apps/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  76. package/apps/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  77. package/apps/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  78. package/apps/web/dist/assets/java-CylS5w8V.js +1 -0
  79. package/apps/web/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  80. package/apps/web/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  81. package/apps/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  82. package/apps/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  83. package/apps/web/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  84. package/apps/web/dist/assets/kotlin-BdnUsdx6.js +1 -0
  85. package/apps/web/dist/assets/less-B1dDrJ26.js +1 -0
  86. package/apps/web/dist/assets/lua-BaeVxFsk.js +1 -0
  87. package/apps/web/dist/assets/markdown-Cvjx9yec.js +1 -0
  88. package/apps/web/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  89. package/apps/web/dist/assets/php-D_2--9WK.js +1 -0
  90. package/apps/web/dist/assets/python-B6aJPvgy.js +1 -0
  91. package/apps/web/dist/assets/ruby-DSHSDbk1.js +1 -0
  92. package/apps/web/dist/assets/rust-B1yitclQ.js +1 -0
  93. package/apps/web/dist/assets/scss-D5BDwBP9.js +1 -0
  94. package/apps/web/dist/assets/sql-CRqJ_cUM.js +1 -0
  95. package/apps/web/dist/assets/swift-C2oV4EkX.js +1 -0
  96. package/apps/web/dist/assets/toml-vGWfd6FD.js +1 -0
  97. package/apps/web/dist/assets/xml-sdJ4AIDG.js +1 -0
  98. package/apps/web/dist/assets/yaml-Buea-lGh.js +1 -0
  99. package/apps/web/dist/iconos/xonecode.png +0 -0
  100. package/apps/web/dist/index.html +20 -0
  101. package/dist/agent/agentesEnDisco.js +539 -0
  102. package/dist/agent/agentesEnDisco.js.map +1 -0
  103. package/dist/agent/arbolDeProyecto.js +245 -0
  104. package/dist/agent/arbolDeProyecto.js.map +1 -0
  105. package/dist/agent/artefactosEnDisco.js +139 -0
  106. package/dist/agent/artefactosEnDisco.js.map +1 -0
  107. package/dist/agent/aumentador.js +175 -0
  108. package/dist/agent/aumentador.js.map +1 -0
  109. package/dist/agent/authEnDisco.js +76 -1
  110. package/dist/agent/authEnDisco.js.map +1 -1
  111. package/dist/agent/busquedaRegex.js +92 -0
  112. package/dist/agent/busquedaRegex.js.map +1 -0
  113. package/dist/agent/catalogoModelos.js +345 -0
  114. package/dist/agent/catalogoModelos.js.map +1 -0
  115. package/dist/agent/checkpointer.js +127 -0
  116. package/dist/agent/checkpointer.js.map +1 -0
  117. package/dist/agent/cloudstudioClient.js +194 -0
  118. package/dist/agent/cloudstudioClient.js.map +1 -0
  119. package/dist/agent/cloudstudioMcp.js +722 -0
  120. package/dist/agent/cloudstudioMcp.js.map +1 -0
  121. package/dist/agent/configEnDisco.js +309 -11
  122. package/dist/agent/configEnDisco.js.map +1 -1
  123. package/dist/agent/consumoExterno.js +99 -0
  124. package/dist/agent/consumoExterno.js.map +1 -0
  125. package/dist/agent/descarga.js +149 -0
  126. package/dist/agent/descarga.js.map +1 -0
  127. package/dist/agent/diagnosticoDeTools.js +51 -0
  128. package/dist/agent/diagnosticoDeTools.js.map +1 -0
  129. package/dist/agent/dispositivosEnMaquina.js +596 -0
  130. package/dist/agent/dispositivosEnMaquina.js.map +1 -0
  131. package/dist/agent/escrituraDeCodex.js +134 -0
  132. package/dist/agent/escrituraDeCodex.js.map +1 -0
  133. package/dist/agent/escrituraDeOpencode.js +80 -0
  134. package/dist/agent/escrituraDeOpencode.js.map +1 -0
  135. package/dist/agent/escrituraExterna.js +742 -0
  136. package/dist/agent/escrituraExterna.js.map +1 -0
  137. package/dist/agent/gemini.js +81 -0
  138. package/dist/agent/gemini.js.map +1 -0
  139. package/dist/agent/git.js +83 -0
  140. package/dist/agent/git.js.map +1 -0
  141. package/dist/agent/gitSync.js +441 -0
  142. package/dist/agent/gitSync.js.map +1 -0
  143. package/dist/agent/hotswap.js +448 -0
  144. package/dist/agent/hotswap.js.map +1 -0
  145. package/dist/agent/instalacionEnMaquina.js +252 -0
  146. package/dist/agent/instalacionEnMaquina.js.map +1 -0
  147. package/dist/agent/instantanea.js +7 -10
  148. package/dist/agent/instantanea.js.map +1 -1
  149. package/dist/agent/interrupts.js +11 -2
  150. package/dist/agent/interrupts.js.map +1 -1
  151. package/dist/agent/juezDeTarea.js +345 -0
  152. package/dist/agent/juezDeTarea.js.map +1 -0
  153. package/dist/agent/lanzamientoEnMaquina.js +377 -0
  154. package/dist/agent/lanzamientoEnMaquina.js.map +1 -0
  155. package/dist/agent/manifiesto.js +59 -0
  156. package/dist/agent/manifiesto.js.map +1 -0
  157. package/dist/agent/memoriaDeProyecto.js +60 -0
  158. package/dist/agent/memoriaDeProyecto.js.map +1 -0
  159. package/dist/agent/modelos.js +105 -17
  160. package/dist/agent/modelos.js.map +1 -1
  161. package/dist/agent/modelosDeMotor.js +204 -0
  162. package/dist/agent/modelosDeMotor.js.map +1 -0
  163. package/dist/agent/paqueteDelProyecto.js +181 -0
  164. package/dist/agent/paqueteDelProyecto.js.map +1 -0
  165. package/dist/agent/perfiles.js +92 -31
  166. package/dist/agent/perfiles.js.map +1 -1
  167. package/dist/agent/persona.js +40 -0
  168. package/dist/agent/persona.js.map +1 -0
  169. package/dist/agent/procesosEnMaquina.js +204 -0
  170. package/dist/agent/procesosEnMaquina.js.map +1 -0
  171. package/dist/agent/proyecto.js +311 -13
  172. package/dist/agent/proyecto.js.map +1 -1
  173. package/dist/agent/puente.js +63 -6
  174. package/dist/agent/puente.js.map +1 -1
  175. package/dist/agent/resumenDeContexto.js +30 -0
  176. package/dist/agent/resumenDeContexto.js.map +1 -0
  177. package/dist/agent/resumenDeTool.js +64 -18
  178. package/dist/agent/resumenDeTool.js.map +1 -1
  179. package/dist/agent/sesionGit.js +481 -0
  180. package/dist/agent/sesionGit.js.map +1 -0
  181. package/dist/agent/settingsEnDisco.js +189 -0
  182. package/dist/agent/settingsEnDisco.js.map +1 -0
  183. package/dist/agent/subagenteCodex.js +368 -0
  184. package/dist/agent/subagenteCodex.js.map +1 -0
  185. package/dist/agent/subagenteExterno.js +423 -0
  186. package/dist/agent/subagenteExterno.js.map +1 -0
  187. package/dist/agent/subagenteOpencode.js +389 -0
  188. package/dist/agent/subagenteOpencode.js.map +1 -0
  189. package/dist/agent/subida.js +202 -0
  190. package/dist/agent/subida.js.map +1 -0
  191. package/dist/agent/tareasEnDisco.js +466 -0
  192. package/dist/agent/tareasEnDisco.js.map +1 -0
  193. package/dist/agent/turnoReal.js +663 -50
  194. package/dist/agent/turnoReal.js.map +1 -1
  195. package/dist/agent/versionEnDisco.js +48 -0
  196. package/dist/agent/versionEnDisco.js.map +1 -0
  197. package/dist/agent/xoneAgent.js +290 -49
  198. package/dist/agent/xoneAgent.js.map +1 -1
  199. package/dist/agent/zip.js +52 -0
  200. package/dist/agent/zip.js.map +1 -0
  201. package/dist/cli/acuseDeModelo.js +30 -0
  202. package/dist/cli/acuseDeModelo.js.map +1 -0
  203. package/dist/cli/aprobar.js +55 -2
  204. package/dist/cli/aprobar.js.map +1 -1
  205. package/dist/cli/config.js +9 -13
  206. package/dist/cli/config.js.map +1 -1
  207. package/dist/cli/consola.js +750 -19
  208. package/dist/cli/consola.js.map +1 -1
  209. package/dist/cli/main.js +740 -81
  210. package/dist/cli/main.js.map +1 -1
  211. package/dist/cli/markdown.js +188 -2
  212. package/dist/cli/markdown.js.map +1 -1
  213. package/dist/cli/run.js +32 -4
  214. package/dist/cli/run.js.map +1 -1
  215. package/dist/cli/stdio.js +46 -19
  216. package/dist/cli/stdio.js.map +1 -1
  217. package/dist/cli/tema.js +96 -8
  218. package/dist/cli/tema.js.map +1 -1
  219. package/dist/cli/tokens.js +29 -0
  220. package/dist/cli/tokens.js.map +1 -0
  221. package/dist/cli/tui/app.js +171 -0
  222. package/dist/cli/tui/app.js.map +1 -0
  223. package/dist/cli/tui/aprobarTui.js +80 -0
  224. package/dist/cli/tui/aprobarTui.js.map +1 -0
  225. package/dist/cli/tui/barra.js +37 -0
  226. package/dist/cli/tui/barra.js.map +1 -0
  227. package/dist/cli/tui/correrTui.js +478 -0
  228. package/dist/cli/tui/correrTui.js.map +1 -0
  229. package/dist/cli/tui/entrada.js +166 -0
  230. package/dist/cli/tui/entrada.js.map +1 -0
  231. package/dist/cli/tui/filas.js +24 -0
  232. package/dist/cli/tui/filas.js.map +1 -0
  233. package/dist/cli/tui/logo.js +49 -0
  234. package/dist/cli/tui/logo.js.map +1 -0
  235. package/dist/cli/tui/pielTui.js +14 -0
  236. package/dist/cli/tui/pielTui.js.map +1 -0
  237. package/dist/cli/tui/raton.js +126 -0
  238. package/dist/cli/tui/raton.js.map +1 -0
  239. package/dist/cli/tui/sidebar.js +86 -0
  240. package/dist/cli/tui/sidebar.js.map +1 -0
  241. package/dist/cli/tui/store.js +143 -0
  242. package/dist/cli/tui/store.js.map +1 -0
  243. package/dist/cli/tui/tarjeta.js +19 -0
  244. package/dist/cli/tui/tarjeta.js.map +1 -0
  245. package/dist/cli/tui/temaInk.js +114 -0
  246. package/dist/cli/tui/temaInk.js.map +1 -0
  247. package/dist/cli/tui/transcript.js +254 -0
  248. package/dist/cli/tui/transcript.js.map +1 -0
  249. package/dist/cli/wizardInicial.js +240 -0
  250. package/dist/cli/wizardInicial.js.map +1 -0
  251. package/dist/core/actos.js +113 -0
  252. package/dist/core/actos.js.map +1 -0
  253. package/dist/core/adjuntos.js +97 -0
  254. package/dist/core/adjuntos.js.map +1 -0
  255. package/dist/core/agentes.js +227 -0
  256. package/dist/core/agentes.js.map +1 -0
  257. package/dist/core/artefactos.js +149 -0
  258. package/dist/core/artefactos.js.map +1 -0
  259. package/dist/core/cloudstudio.js +7 -0
  260. package/dist/core/cloudstudio.js.map +1 -0
  261. package/dist/core/config.js +212 -5
  262. package/dist/core/config.js.map +1 -1
  263. package/dist/core/contextos.js +53 -1
  264. package/dist/core/contextos.js.map +1 -1
  265. package/dist/core/descargas.js +106 -0
  266. package/dist/core/descargas.js.map +1 -0
  267. package/dist/core/descriptoresDeApp.js +279 -0
  268. package/dist/core/descriptoresDeApp.js.map +1 -0
  269. package/dist/core/dispositivos.js +466 -0
  270. package/dist/core/dispositivos.js.map +1 -0
  271. package/dist/core/entrega.js +141 -0
  272. package/dist/core/entrega.js.map +1 -0
  273. package/dist/core/entrelazar.js +90 -0
  274. package/dist/core/entrelazar.js.map +1 -0
  275. package/dist/core/esqueleto.js +10 -0
  276. package/dist/core/esqueleto.js.map +1 -1
  277. package/dist/core/modelos.js +235 -3
  278. package/dist/core/modelos.js.map +1 -1
  279. package/dist/core/notify.js +27 -9
  280. package/dist/core/notify.js.map +1 -1
  281. package/dist/core/planDeSubida.js +127 -0
  282. package/dist/core/planDeSubida.js.map +1 -0
  283. package/dist/core/ports.js +189 -1
  284. package/dist/core/ports.js.map +1 -1
  285. package/dist/core/puedeLanzarse.js +239 -0
  286. package/dist/core/puedeLanzarse.js.map +1 -0
  287. package/dist/core/rutaVirtual.js +42 -0
  288. package/dist/core/rutaVirtual.js.map +1 -0
  289. package/dist/core/settings.js +246 -0
  290. package/dist/core/settings.js.map +1 -0
  291. package/dist/core/tareas.js +230 -0
  292. package/dist/core/tareas.js.map +1 -0
  293. package/dist/core/textos.js +36 -0
  294. package/dist/core/textos.js.map +1 -0
  295. package/dist/core/turno.js +56 -8
  296. package/dist/core/turno.js.map +1 -1
  297. package/dist/core/version.js +31 -0
  298. package/dist/core/version.js.map +1 -0
  299. package/dist/vendor/tokenTracking.js +22 -1
  300. package/dist/vendor/tokenTracking.js.map +1 -1
  301. package/dist/web/servidor/arranque.js +3964 -0
  302. package/dist/web/servidor/arranque.js.map +1 -0
  303. package/dist/web/servidor/consolaDeTarea.js +161 -0
  304. package/dist/web/servidor/consolaDeTarea.js.map +1 -0
  305. package/dist/web/servidor/consolaWeb.js +389 -0
  306. package/dist/web/servidor/consolaWeb.js.map +1 -0
  307. package/dist/web/servidor/corredorDeTareas.js +1119 -0
  308. package/dist/web/servidor/corredorDeTareas.js.map +1 -0
  309. package/dist/web/servidor/pielWeb.js +269 -0
  310. package/dist/web/servidor/pielWeb.js.map +1 -0
  311. package/dist/web/servidor/servidor.js +257 -0
  312. package/dist/web/servidor/servidor.js.map +1 -0
  313. package/dist/web/servidor/sesiones.js +440 -0
  314. package/dist/web/servidor/sesiones.js.map +1 -0
  315. package/dist/web/servidor/transporte.js +169 -0
  316. package/dist/web/servidor/transporte.js.map +1 -0
  317. package/dist/web/servidor/vestibulo.js +1276 -0
  318. package/dist/web/servidor/vestibulo.js.map +1 -0
  319. package/package.json +30 -8
  320. package/skills/archify/LICENSE +22 -0
  321. package/skills/archify/SKILL.md +109 -0
  322. package/skills/archify/THIRD_PARTY_NOTICES.md +56 -0
  323. package/skills/archify/assets/template.html +14787 -0
  324. package/skills/archify/bin/archify.mjs +1990 -0
  325. package/skills/archify/bin/open-artifact.mjs +86 -0
  326. package/skills/archify/bin/preview.mjs +648 -0
  327. package/skills/archify/bin/visual-check.mjs +829 -0
  328. package/skills/archify/brand-marks/README.md +31 -0
  329. package/skills/archify/brand-marks/catalog.json +131 -0
  330. package/skills/archify/delta/architecture-delta.mjs +1214 -0
  331. package/skills/archify/examples/agent-run.lifecycle.json +71 -0
  332. package/skills/archify/examples/agent-tool-call.workflow.json +94 -0
  333. package/skills/archify/examples/async-job-roundtrip.sequence.json +61 -0
  334. package/skills/archify/examples/brand-aware-delivery.architecture.json +47 -0
  335. package/skills/archify/examples/cache-miss-request.sequence.json +81 -0
  336. package/skills/archify/examples/checkout-platform.base.architecture.json +31 -0
  337. package/skills/archify/examples/checkout-platform.head.architecture.json +31 -0
  338. package/skills/archify/examples/dataflow-product-analytics.html +14898 -0
  339. package/skills/archify/examples/deployment-release.lifecycle.json +49 -0
  340. package/skills/archify/examples/event-stream.dataflow.json +57 -0
  341. package/skills/archify/examples/incident-response.workflow.json +64 -0
  342. package/skills/archify/examples/lifecycle-agent-run.html +14847 -0
  343. package/skills/archify/examples/product-analytics.dataflow.json +76 -0
  344. package/skills/archify/examples/production-deployment.architecture.json +71 -0
  345. package/skills/archify/examples/release-delivery.workflow.json +62 -0
  346. package/skills/archify/examples/sequence-cache-miss-request.html +14913 -0
  347. package/skills/archify/examples/web-app-rendered.html +14862 -0
  348. package/skills/archify/examples/web-app.architecture.json +46 -0
  349. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +14904 -0
  350. package/skills/archify/migrations/workflow-v2.mjs +279 -0
  351. package/skills/archify/package.json +17 -0
  352. package/skills/archify/recipes/scenarios.mjs +391 -0
  353. package/skills/archify/references/authoring-contract.md +198 -0
  354. package/skills/archify/references/brand-marks.md +69 -0
  355. package/skills/archify/references/delivery-contract.md +116 -0
  356. package/skills/archify/references/viewer-runtime.md +45 -0
  357. package/skills/archify/renderers/architecture/grid.mjs +62 -0
  358. package/skills/archify/renderers/architecture/render-architecture.mjs +1078 -0
  359. package/skills/archify/renderers/dataflow/README.md +104 -0
  360. package/skills/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  361. package/skills/archify/renderers/lifecycle/README.md +115 -0
  362. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  363. package/skills/archify/renderers/sequence/README.md +114 -0
  364. package/skills/archify/renderers/sequence/render-sequence.mjs +453 -0
  365. package/skills/archify/renderers/shared/brand-marks.mjs +563 -0
  366. package/skills/archify/renderers/shared/cli.mjs +218 -0
  367. package/skills/archify/renderers/shared/desktop-readability.mjs +26 -0
  368. package/skills/archify/renderers/shared/diagnostics.mjs +127 -0
  369. package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
  370. package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  371. package/skills/archify/renderers/shared/generated-validators.mjs +13 -0
  372. package/skills/archify/renderers/shared/geometry.mjs +1423 -0
  373. package/skills/archify/renderers/shared/i18n.mjs +594 -0
  374. package/skills/archify/renderers/shared/layout-report.mjs +40 -0
  375. package/skills/archify/renderers/shared/legend.mjs +217 -0
  376. package/skills/archify/renderers/shared/output-path.mjs +321 -0
  377. package/skills/archify/renderers/shared/repository-evidence.mjs +235 -0
  378. package/skills/archify/renderers/shared/text-fit.mjs +49 -0
  379. package/skills/archify/renderers/shared/utils.mjs +232 -0
  380. package/skills/archify/renderers/shared/validator.mjs +86 -0
  381. package/skills/archify/renderers/workflow/README.md +223 -0
  382. package/skills/archify/renderers/workflow/render-workflow.mjs +35 -0
  383. package/skills/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  384. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  385. package/skills/archify/schemas/README.md +211 -0
  386. package/skills/archify/schemas/architecture.schema.json +176 -0
  387. package/skills/archify/schemas/common.schema.json +115 -0
  388. package/skills/archify/schemas/dataflow.schema.json +243 -0
  389. package/skills/archify/schemas/lifecycle.schema.json +266 -0
  390. package/skills/archify/schemas/sequence.schema.json +223 -0
  391. package/skills/archify/schemas/workflow.schema.json +428 -0
  392. package/skills/archify/scripts/check-render-output.mjs +835 -0
  393. package/skills/archify/scripts/check-update.mjs +1667 -0
  394. package/skills/archify/scripts/render-examples.mjs +26 -0
  395. package/skills/archify/scripts/update-contract.mjs +182 -0
  396. package/skills/archify/skill-release.json +10 -0
  397. package/skills/artifacts-builder/SKILL.md +120 -0
  398. package/skills/artifacts-builder/reference/diagramas.md +123 -0
  399. package/skills/artifacts-builder/reference/estilo.md +123 -0
  400. package/skills/artifacts-builder/reference/exportar-pdf.md +56 -0
  401. package/skills/artifacts-builder/reference/graficas.md +22 -0
  402. package/skills/artifacts-builder/scripts/bundle_artifact.py +109 -0
  403. package/skills/artifacts-builder/scripts/validate_artifact.py +345 -0
  404. package/skills/xone-hotswap/SKILL.md +185 -0
  405. package/skills/xone-hotswap/references/comandos.md +706 -0
  406. package/skills/xone-hotswap/references/conexion-y-despliegue.md +226 -0
@@ -0,0 +1,115 @@
1
+ # Lifecycle Renderer
2
+
3
+ Render `diagram_type: "lifecycle"` JSON files into the standard Archify HTML
4
+ template.
5
+
6
+ ```bash
7
+ node archify/renderers/lifecycle/render-lifecycle.mjs input.lifecycle.json output.html
8
+ ```
9
+
10
+ The renderer validates input against `archify/schemas/lifecycle.schema.json`
11
+ with the bundled standalone validator. No dependency installation is required.
12
+
13
+ If `output.html` is omitted, the renderer uses `meta.output` from the JSON file
14
+ or falls back to `lifecycle.html` in the current working directory.
15
+
16
+ ## Input
17
+
18
+ Lifecycle JSON files must set:
19
+
20
+ ```json
21
+ {
22
+ "schema_version": 1,
23
+ "diagram_type": "lifecycle",
24
+ "meta": {
25
+ "title": "Agent Run Lifecycle",
26
+ "viewBox": [980, 660]
27
+ },
28
+ "lanes": [],
29
+ "states": [],
30
+ "transitions": [],
31
+ "cards": []
32
+ }
33
+ ```
34
+
35
+ Lane ids are semantic and reserved: a lane with id `main` is required and maps
36
+ to the top phase band; `terminal` maps to the bottom outcome band; every other
37
+ lane id (up to 4 lanes total) shares the single middle event band. The three
38
+ band headers render from your lane labels — the middle band joins the labels of
39
+ all event lanes with ` + `. A complete worked example lives at
40
+ `archify/examples/agent-run.lifecycle.json`.
41
+
42
+ The schema lives at:
43
+
44
+ ```text
45
+ archify/schemas/lifecycle.schema.json
46
+ ```
47
+
48
+ ## Legend
49
+
50
+ The default legend derives kinds from `states[].type`. Supported
51
+ `meta.legend.entries` keys, in stable order, are `start`, `active`, `waiting`,
52
+ `decision`, `success`, `failure`, `neutral`, and `external`. Labels and
53
+ visibility may be overridden through the shared legend contract; only kinds
54
+ backed by rendered states receive Semantic Legend controls.
55
+
56
+ ## Layout budget
57
+
58
+ | Band | Lane id | Top y | Column centers | Default state |
59
+ |------|---------|-------|----------------|---------------|
60
+ | Phase | `main` (required) | 126 | `col` 0–4 → x = 94, 248, 402, 556, 710 | 118×62 |
61
+ | Event | any other id | 278 | `col` 0–2 → x = 402, 556, 710 | 126×58 |
62
+ | Outcome | `terminal` | 450 | `col` 0–2 → x = 402, 556, 710 | 118×58 |
63
+
64
+ Event and terminal columns are intentionally offset from the main rail:
65
+ event/terminal `col: N` uses the same x coordinate as main `col: N + 2`.
66
+ For example, lower-band columns 0, 1, and 2 align beneath main columns 2, 3,
67
+ and 4 respectively.
68
+
69
+ | Constant | Value |
70
+ |----------|-------|
71
+ | viewBox | default `[980, 660]`; schema minimum `[420, 566]` |
72
+ | State area | x within `[32, width − 32]`; state bottom at or above `height − 122` |
73
+ | State spacing | ≥10px between any two states — checked across lanes, because all event lanes share one band; separate same-band states with `col` or `yOffset` |
74
+ | Transition length | ≥32px between endpoints |
75
+ | Legend row | final baseline y = height − 36; extra measured rows wrap upward |
76
+
77
+ The primary lifecycle rail runs along the phase band and extends to the
78
+ furthest occupied phase column. Route presets for transitions: `straight`,
79
+ `drop` (bend at `channelY`, defaulting to the vertical midpoint),
80
+ `bottom-channel`, `top-channel`, `right-channel`, `left-channel`, explicit
81
+ `via` points, or the default `auto`. Multi-segment transitions get rounded
82
+ corners; tune them with `cornerRadius` (default 10, `0` for sharp bends).
83
+
84
+ ## Design Rules
85
+
86
+ - Treat lifecycle diagrams as a phase map, not a dense state-transition graph.
87
+ - Put the primary lifecycle on one horizontal rail using the `main` lane.
88
+ - Use `step` labels for ordered phases, such as `01`, `02`, and `03`.
89
+ - Use lower lanes only for interruptions, recovery, and terminal exits.
90
+ - Keep transition labels out of the main SVG unless the label is essential;
91
+ prefer node labels, tags, legend entries, and summary cards.
92
+ - Avoid diagonal and crossing lines. Terminal exits should drop vertically from
93
+ their source event whenever possible.
94
+ - Use `success` for completion, `failure` for failure/terminal exits,
95
+ `waiting` for pauses, and `decision` for quality gates.
96
+
97
+ Schema violations exit non-zero with path-prefixed messages annotated with the
98
+ element's id or label. The renderer additionally fails when it can detect
99
+ layout problems, including a missing `main` lane, duplicate state IDs, unknown
100
+ lanes, unknown transition endpoints, states outside the lifecycle area,
101
+ overlapping states (including across lanes), labels colliding with states or
102
+ other labels, labels wider than their state, unreadably short transitions, or
103
+ transitions crossing unrelated states (2px Clean Flow clearance). Lifecycle
104
+ bands remain intentional pass-through containers.
105
+ Text width is estimated CJK-aware: fullwidth glyphs count as two units.
106
+
107
+ Set `meta.quality_profile` to `showcase` for polished delivery. Unrelated proper
108
+ X crossings then fail with `composition/proper-crossing`; default `standard`
109
+ keeps them as artifact-receipt warnings. The final artifact check samples
110
+ rounded `Q` corners. Collinear corridors remain outside the proper-X rule, but
111
+ a separate gate warns in `standard` and fails in `showcase` when unrelated
112
+ transitions overlap for at least 8px. Shared semantic endpoints, point touches,
113
+ and shorter overlaps remain valid. Showcase also rejects any route segment
114
+ below 8px and any interior turn segment below 16px; ordinary 8–15px endpoint
115
+ stubs remain valid.
@@ -0,0 +1,561 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { esc, renderDefinitions, renderSemanticSigil, textUnits } from '../shared/utils.mjs';
4
+ import { animateAttr, focusEdgeAttrs, focusNodeAttrs, focusNodeTitle, loadDiagramWithBrandMarks, writeDiagram, svgAccessibleText, svgRootAttrs } from '../shared/cli.mjs';
5
+ import { throwDiagnosticProblems } from '../shared/diagnostics.mjs';
6
+ import { resolveLegend, renderLegend as renderResolvedLegend } from '../shared/legend.mjs';
7
+ import { availableNodeTextWidth, fittedNodeFontSize, minimumNodeTextWidth } from '../shared/text-fit.mjs';
8
+ import { brandLabelFitWidth, brandMarkFor, brandMetadataFor, brandTopRailProblem, renderBrandMark } from '../shared/brand-marks.mjs';
9
+ import { translateMessage as i18nText } from '../shared/i18n.mjs';
10
+ import {
11
+ asArray,
12
+ isFinitePoint,
13
+ rectsOverlap,
14
+ cleanEndpointSideProblems,
15
+ cleanFlowProblems,
16
+ cleanCrossingProblems,
17
+ cleanAmbiguousCorridorProblems,
18
+ cleanBorderRunProblems,
19
+ cleanRouteRhythmProblems,
20
+ cleanLabelRouteClearanceProblems,
21
+ suggestLabelObstacleFix,
22
+ suggestLabelPairFix,
23
+ anchor,
24
+ automaticPortSpread,
25
+ defaultFromSide,
26
+ defaultToSide,
27
+ chosenSide,
28
+ roundedPath,
29
+ routePointsValue,
30
+ labelPoint,
31
+ arrowClassMap,
32
+ variantAccent
33
+ } from '../shared/geometry.mjs';
34
+
35
+ const stateTextFit = {
36
+ sublabelPreferred: 7,
37
+ sublabelMinimum: 6,
38
+ tagPreferred: 7,
39
+ tagMinimum: 6,
40
+ };
41
+
42
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
43
+ const { diagram: lifecycle, template, outPath } = await loadDiagramWithBrandMarks({
44
+ rendererDir: __dirname,
45
+ diagramType: 'lifecycle',
46
+ defaultExample: 'agent-run.lifecycle.json'
47
+ });
48
+
49
+ const viewBox = lifecycle.meta?.viewBox || [980, 660];
50
+ const layout = {
51
+ phaseY: 126,
52
+ eventY: 278,
53
+ outcomeY: 450,
54
+ phaseW: 118,
55
+ phaseH: 62,
56
+ eventW: 126,
57
+ eventH: 58,
58
+ outcomeW: 118,
59
+ outcomeH: 58,
60
+ phaseXs: [94, 248, 402, 556, 710],
61
+ eventXs: [402, 556, 710],
62
+ outcomeXs: [402, 556, 710]
63
+ };
64
+
65
+ const typeClass = {
66
+ start: 'c-frontend',
67
+ active: 'c-backend',
68
+ waiting: 'c-cloud',
69
+ decision: 'c-security',
70
+ success: 'c-database',
71
+ failure: 'c-security',
72
+ neutral: 'c-external',
73
+ external: 'c-external'
74
+ };
75
+
76
+ const textClass = {
77
+ start: 't-frontend',
78
+ active: 't-backend',
79
+ waiting: 't-cloud',
80
+ decision: 't-security',
81
+ success: 't-database',
82
+ failure: 't-security',
83
+ neutral: 't-muted',
84
+ external: 't-muted'
85
+ };
86
+
87
+ function legendY() {
88
+ return viewBox[1] - 36;
89
+ }
90
+
91
+ // Keep the authored state-placement contract independent from the measured
92
+ // legend's lower baseline. Moving legend chrome must not admit new state
93
+ // geometry into the reserved outcome/legend band.
94
+ function lifecycleAreaBottom() {
95
+ return viewBox[1] - 122;
96
+ }
97
+
98
+ // Lane semantics are fixed: lane id "main" maps to the top phase band, lane id
99
+ // "terminal" maps to the bottom outcome band, and every other lane shares the
100
+ // middle event band (separated visually via yOffset).
101
+ function bandFor(lane) {
102
+ if (lane === 'main') return 'phase';
103
+ if (lane === 'terminal') return 'outcome';
104
+ return 'event';
105
+ }
106
+
107
+ function measureState(state) {
108
+ const isPhase = bandFor(state.lane) === 'phase';
109
+ const isOutcome = bandFor(state.lane) === 'outcome';
110
+ const width = state.width || (isPhase ? layout.phaseW : isOutcome ? layout.outcomeW : layout.eventW);
111
+ const height = state.height || (isPhase ? layout.phaseH : isOutcome ? layout.outcomeH : layout.eventH);
112
+ const xs = isPhase ? layout.phaseXs : isOutcome ? layout.outcomeXs : layout.eventXs;
113
+ const cx = xs[state.col] ?? xs[xs.length - 1];
114
+ const y = (
115
+ isPhase ? layout.phaseY :
116
+ isOutcome ? layout.outcomeY :
117
+ layout.eventY
118
+ ) + (state.yOffset || 0);
119
+ return {
120
+ ...state,
121
+ width,
122
+ height,
123
+ x: cx - width / 2,
124
+ y,
125
+ cx,
126
+ cy: y + height / 2
127
+ };
128
+ }
129
+
130
+ const states = new Map(asArray(lifecycle.states).map((state) => [state.id, measureState(state)]));
131
+ const laneLabels = new Map(asArray(lifecycle.lanes).map((lane) => [lane.id, lane.label]));
132
+ const stateSteps = new Map();
133
+ for (const [index, transition] of asArray(lifecycle.transitions).entries()) {
134
+ if (!stateSteps.has(transition.from)) stateSteps.set(transition.from, index);
135
+ if (!stateSteps.has(transition.to)) stateSteps.set(transition.to, index + 1);
136
+ }
137
+ for (const [index, state] of asArray(lifecycle.states).entries()) {
138
+ if (!stateSteps.has(state.id)) stateSteps.set(state.id, index);
139
+ }
140
+
141
+ function validateLifecycle() {
142
+ const problems = [];
143
+ if (states.size !== asArray(lifecycle.states).length) problems.push('State ids must be unique.');
144
+
145
+ // The three bands are fixed at y=112/264/436. Preserve the original
146
+ // outcome/legend reserve even though measured legend rows now sit lower.
147
+ if (lifecycleAreaBottom() + 4 < 448) {
148
+ problems.push(`viewBox height ${viewBox[1]} is too short for the fixed band layout — set meta.viewBox[1] to at least 566.`);
149
+ }
150
+
151
+ const laneIds = new Set(asArray(lifecycle.lanes).map((lane) => lane.id));
152
+ if (laneIds.size !== asArray(lifecycle.lanes).length) problems.push('Lane ids must be unique.');
153
+ if (!laneIds.has('main')) {
154
+ problems.push('Lifecycle diagrams need a lane with id "main" (the phase rail). Lane ids "main" and "terminal" are reserved: "main" maps to the top phase band, "terminal" to the bottom outcome band, and all other lanes share the middle event band.');
155
+ }
156
+
157
+ for (const state of states.values()) {
158
+ if (!laneIds.has(state.lane)) {
159
+ problems.push(`State "${state.id}" uses unknown lane "${state.lane}".`);
160
+ continue;
161
+ }
162
+ const band = bandFor(state.lane);
163
+ const maxCol = band === 'phase'
164
+ ? layout.phaseXs.length
165
+ : band === 'outcome'
166
+ ? layout.outcomeXs.length
167
+ : layout.eventXs.length;
168
+ if (!Number.isInteger(state.col) || state.col < 0 || state.col >= maxCol) {
169
+ problems.push(`State "${state.id}" uses invalid column ${state.col} — the ${band} band has integer columns 0..${maxCol - 1}.`);
170
+ continue;
171
+ }
172
+ if (!isFinitePoint(state.x, state.y, state.cx, state.cy)) {
173
+ problems.push(`State "${state.id}" produced non-finite coordinates — check col, width, height, and yOffset are numbers.`);
174
+ continue;
175
+ }
176
+ if (state.x < 32 || state.x + state.width > viewBox[0] - 32) {
177
+ problems.push(`State "${state.id}" exceeds the horizontal bounds of the diagram — reduce state.width or increase meta.viewBox[0].`);
178
+ }
179
+ if (state.y < 64 || state.y + state.height > lifecycleAreaBottom()) {
180
+ problems.push(`State "${state.id}" exceeds the vertical lifecycle area — keep y between 64 and ${lifecycleAreaBottom()} (adjust yOffset or increase meta.viewBox[1]).`);
181
+ }
182
+ const estLabelW = textUnits(state.label) * 6.2;
183
+ if (estLabelW > state.width + 6) {
184
+ problems.push(`Label "${state.label}" (~${Math.round(estLabelW)}px) is wider than state "${state.id}" (${state.width}px) — shorten the label or increase state.width.`);
185
+ }
186
+ const brandRailProblem = brandTopRailProblem(state, state.width, 8, 'State');
187
+ if (brandRailProblem) problems.push(brandRailProblem);
188
+ // sublabel and tag render as single unwrapped <text> elements; shrink-to-fit
189
+ // handles the ordinary case, this rejects what it cannot rescue.
190
+ const availableTextW = availableNodeTextWidth(state.width);
191
+ for (const [field, value, minimum] of [
192
+ ['Sublabel', state.sublabel, stateTextFit.sublabelMinimum],
193
+ ['Tag', state.tag, stateTextFit.tagMinimum],
194
+ ]) {
195
+ if (!value) continue;
196
+ const minimumW = minimumNodeTextWidth(value, minimum);
197
+ if (minimumW > availableTextW) {
198
+ problems.push(`${field} "${value}" needs ~${Math.ceil(minimumW)}px at the ${minimum}px legible minimum, but state "${state.id}" provides ${availableTextW}px — shorten the ${field.toLowerCase()} or increase state.width.`);
199
+ }
200
+ }
201
+ }
202
+
203
+ // All non-main/non-terminal lanes share the same y band, so the overlap
204
+ // check must run across lanes — not per-lane.
205
+ const allStates = [...states.values()];
206
+ for (let i = 0; i < allStates.length; i += 1) {
207
+ for (let j = i + 1; j < allStates.length; j += 1) {
208
+ if (rectsOverlap(allStates[i], allStates[j], 10)) {
209
+ problems.push(`States "${allStates[i].id}" and "${allStates[j].id}" are less than 10px apart — move one to another col or separate them with yOffset (lanes other than "main"/"terminal" share one band).`);
210
+ }
211
+ }
212
+ }
213
+
214
+ for (const transition of asArray(lifecycle.transitions)) {
215
+ if (!states.has(transition.from)) problems.push(`Transition "${transition.label || transition.from}" references unknown source "${transition.from}".`);
216
+ if (!states.has(transition.to)) problems.push(`Transition "${transition.label || transition.to}" references unknown target "${transition.to}".`);
217
+ if (states.has(transition.from) && states.has(transition.to)) {
218
+ const routed = pathFor(transition);
219
+ const [start, end] = [routed.points[0], routed.points[routed.points.length - 1]];
220
+ const distance = Math.hypot(end[0] - start[0], end[1] - start[1]);
221
+ if (distance < 32) problems.push(`Transition "${transition.label || `${transition.from}->${transition.to}`}" is too short (${Math.round(distance)}px; minimum 32px) — route it through a channel or drop its label.`);
222
+ }
223
+ }
224
+
225
+ // Authored via points are authoritative in schema v1, including under a
226
+ // quality profile. Preserve and render them exactly: applying the endpoint
227
+ // gate would either reject an existing typed input or require silently
228
+ // falsifying its geometry. Automatic routes still receive the side gate.
229
+ problems.push(...cleanEndpointSideProblems({
230
+ relations: lifecycle.transitions,
231
+ endpointIds: new Set(states.keys()),
232
+ pathFor,
233
+ diagramType: 'lifecycle',
234
+ relationCollection: 'transitions',
235
+ fromSideFor: (transition) => transitionSides(transition).fromSide,
236
+ toSideFor: (transition) => transitionSides(transition).toSide,
237
+ shouldCheckRelation: (transition) => !Array.isArray(transition.via),
238
+ routeHint: 'keep automatic routing, or choose fromSide/toSide and via points whose first and final segments cross state borders perpendicularly',
239
+ }));
240
+ problems.push(...cleanFlowProblems({
241
+ relations: lifecycle.transitions,
242
+ obstacles: states.values(),
243
+ pathFor,
244
+ diagramType: 'lifecycle',
245
+ relationCollection: 'transitions',
246
+ obstacleKind: 'state',
247
+ routeHint: 'adjust fromSide/toSide, set route/via or channelX/channelY, or move the state with col/yOffset'
248
+ }));
249
+ problems.push(...cleanCrossingProblems({
250
+ relations: lifecycle.transitions,
251
+ endpointIds: new Set(states.keys()),
252
+ pathFor,
253
+ diagramType: 'lifecycle',
254
+ relationCollection: 'transitions',
255
+ profile: lifecycle.meta?.quality_profile,
256
+ routeHint: 'adjust route/via or channelX/channelY so the transitions use separate lifecycle corridors'
257
+ }));
258
+ problems.push(...cleanAmbiguousCorridorProblems({
259
+ relations: lifecycle.transitions,
260
+ endpointIds: new Set(states.keys()),
261
+ pathFor,
262
+ diagramType: 'lifecycle',
263
+ relationCollection: 'transitions',
264
+ profile: lifecycle.meta?.quality_profile,
265
+ routeHint: 'adjust route/via or channelX/channelY so unrelated transitions do not visually merge'
266
+ }));
267
+ // Lifecycle bands are dashed reading guides, not closed containers. Keep the
268
+ // shared contract wired with an explicit empty frame set so future typed
269
+ // lifecycle containers cannot accidentally inherit presentation geometry.
270
+ problems.push(...cleanBorderRunProblems({
271
+ relations: lifecycle.transitions,
272
+ endpointIds: new Set(states.keys()),
273
+ frames: [],
274
+ pathFor,
275
+ diagramType: 'lifecycle',
276
+ relationCollection: 'transitions',
277
+ profile: lifecycle.meta?.quality_profile
278
+ }));
279
+ problems.push(...cleanRouteRhythmProblems({
280
+ relations: lifecycle.transitions,
281
+ endpointIds: new Set(states.keys()),
282
+ pathFor,
283
+ diagramType: 'lifecycle',
284
+ relationCollection: 'transitions',
285
+ profile: lifecycle.meta?.quality_profile,
286
+ routeHint: 'move route/via or channel coordinates so each lifecycle turn has a readable run-up'
287
+ }));
288
+
289
+ const labelRects = [];
290
+ for (const [transitionIndex, transition] of asArray(lifecycle.transitions).entries()) {
291
+ if (!transition.label || !states.has(transition.from) || !states.has(transition.to)) continue;
292
+ const [lx, ly] = labelPoint(transition, pathFor(transition).points);
293
+ const longestLine = Math.max(textUnits(transition.label), textUnits(transition.note || ''));
294
+ const width = Math.max(32, longestLine * 4.9 + 12);
295
+ const height = transition.note ? 27 : 16;
296
+ labelRects.push({ relation: transition, relationIndex: transitionIndex, label: transition.label, x: lx - width / 2, y: ly - 11, width, height, lx, ly });
297
+ }
298
+ for (const rect of labelRects) {
299
+ for (const state of states.values()) {
300
+ if (rectsOverlap(rect, state, -2)) {
301
+ problems.push(`Label "${rect.label}" overlaps state "${state.id}" — adjust labelDx/labelDy/labelSegment or set labelAt.\n${suggestLabelObstacleFix(rect, rect.lx, rect.ly, state, 'state')}`);
302
+ }
303
+ }
304
+ }
305
+ for (let i = 0; i < labelRects.length; i += 1) {
306
+ for (let j = i + 1; j < labelRects.length; j += 1) {
307
+ if (rectsOverlap(labelRects[i], labelRects[j], -2)) {
308
+ problems.push(`Labels "${labelRects[i].label}" and "${labelRects[j].label}" overlap — adjust labelDx/labelDy.\n${suggestLabelPairFix(labelRects[i], labelRects[j])}`);
309
+ }
310
+ }
311
+ }
312
+ problems.push(...cleanLabelRouteClearanceProblems({
313
+ relations: lifecycle.transitions,
314
+ labels: labelRects,
315
+ endpointIds: new Set(states.keys()),
316
+ pathFor,
317
+ diagramType: 'lifecycle',
318
+ relationCollection: 'transitions',
319
+ profile: lifecycle.meta?.quality_profile,
320
+ }));
321
+
322
+ if (problems.length) {
323
+ throwDiagnosticProblems('Lifecycle layout validation failed', problems, {
324
+ subject: { diagramType: 'lifecycle' },
325
+ });
326
+ }
327
+ }
328
+
329
+ function routeVia(transition, from, to, start, end, fromSide, toSide) {
330
+ if (transition.via) return transition.via;
331
+ switch (transition.route || 'auto') {
332
+ case 'straight':
333
+ return [];
334
+ case 'drop': {
335
+ const y = transition.channelY ?? (start[1] + end[1]) / 2;
336
+ return [[start[0], y], [end[0], y]];
337
+ }
338
+ case 'bottom-channel': {
339
+ const y = transition.channelY ?? Math.max(from.y + from.height, to.y + to.height) + 34;
340
+ return [[start[0], y], [end[0], y]];
341
+ }
342
+ case 'top-channel': {
343
+ const y = transition.channelY ?? Math.min(from.y, to.y) - 28;
344
+ return [[start[0], y], [end[0], y]];
345
+ }
346
+ case 'right-channel': {
347
+ const x = transition.channelX ?? Math.max(from.x + from.width, to.x + to.width) + 36;
348
+ return [[x, start[1]], [x, end[1]]];
349
+ }
350
+ case 'left-channel': {
351
+ const x = transition.channelX ?? Math.min(from.x, to.x) - 36;
352
+ return [[x, start[1]], [x, end[1]]];
353
+ }
354
+ case 'auto':
355
+ default: {
356
+ if (start[0] === end[0] || start[1] === end[1]) return [];
357
+ const fromVertical = fromSide === 'top' || fromSide === 'bottom';
358
+ const toVertical = toSide === 'top' || toSide === 'bottom';
359
+ if (fromVertical !== toVertical) {
360
+ return [fromVertical ? [start[0], end[1]] : [end[0], start[1]]];
361
+ }
362
+ if (fromVertical) {
363
+ const y = transition.channelY ?? (start[1] + end[1]) / 2;
364
+ return [[start[0], y], [end[0], y]];
365
+ }
366
+ const x = transition.channelX ?? (start[0] + end[0]) / 2;
367
+ return [[x, start[1]], [x, end[1]]];
368
+ }
369
+ }
370
+ }
371
+
372
+ const pathCache = new Map();
373
+
374
+ function transitionSides(transition) {
375
+ const from = states.get(transition.from);
376
+ const to = states.get(transition.to);
377
+ return {
378
+ fromSide: chosenSide(transition.fromSide, defaultFromSide(from, to)),
379
+ toSide: chosenSide(transition.toSide, defaultToSide(from, to)),
380
+ };
381
+ }
382
+
383
+ const automaticPorts = automaticPortSpread(lifecycle.transitions, states, {
384
+ sideFor: (transition, endpoint) => transitionSides(transition)[endpoint === 'source' ? 'fromSide' : 'toSide'],
385
+ });
386
+
387
+ function pathFor(transition) {
388
+ if (pathCache.has(transition)) return pathCache.get(transition);
389
+ const from = states.get(transition.from);
390
+ const to = states.get(transition.to);
391
+ const ports = automaticPorts.get(transition);
392
+ const { fromSide, toSide } = transitionSides(transition);
393
+ const start = ports?.from || anchor(from, fromSide);
394
+ const end = ports?.to || anchor(to, toSide);
395
+ let via = routeVia(transition, from, to, start, end, fromSide, toSide);
396
+ if (ports && !via.length && Math.abs(start[0] - end[0]) >= 4 && Math.abs(start[1] - end[1]) >= 4) {
397
+ const midX = (start[0] + end[0]) / 2;
398
+ via = [[midX, start[1]], [midX, end[1]]];
399
+ }
400
+ const points = [start, ...via, end];
401
+ const routed = {
402
+ d: roundedPath(points, transition.cornerRadius ?? 10),
403
+ points
404
+ };
405
+ pathCache.set(transition, routed);
406
+ return routed;
407
+ }
408
+
409
+ function bandTitles() {
410
+ const lanes = asArray(lifecycle.lanes);
411
+ const mainLane = lanes.find((lane) => lane.id === 'main');
412
+ const terminalLane = lanes.find((lane) => lane.id === 'terminal');
413
+ const eventLanes = lanes.filter((lane) => lane.id !== 'main' && lane.id !== 'terminal');
414
+ return [
415
+ mainLane?.label || 'Lifecycle phases',
416
+ eventLanes.length ? eventLanes.map((lane) => lane.label).join(' + ') : 'Interruptions + recovery',
417
+ terminalLane?.label || 'Outcomes'
418
+ ];
419
+ }
420
+
421
+ function renderBands() {
422
+ const right = viewBox[0] - 72;
423
+ const titles = bandTitles();
424
+ return ` <path d="M 72 112 L ${right} 112" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
425
+ <text x="72" y="100" class="t-dim" font-size="10" font-weight="600">01 / ${esc(titles[0])}</text>
426
+ <path d="M 72 264 L ${right} 264" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
427
+ <text x="72" y="252" class="t-dim" font-size="10" font-weight="600">02 / ${esc(titles[1])}</text>
428
+ <path d="M 72 436 L ${right} 436" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
429
+ <text x="72" y="424" class="t-dim" font-size="10" font-weight="600">03 / ${esc(titles[2])}</text>`;
430
+ }
431
+
432
+ function renderState(state) {
433
+ const fill = typeClass[state.type] || typeClass.neutral;
434
+ const accent = textClass[state.type] || 't-muted';
435
+ const hasSub = state.sublabel != null && state.sublabel !== '';
436
+ const sub = hasSub
437
+ ? `\n <text data-detail="context" x="${state.cx}" y="${state.y + 37}" class="t-muted" font-size="${fittedNodeFontSize(state.sublabel, state.width, stateTextFit.sublabelPreferred, stateTextFit.sublabelMinimum)}" text-anchor="middle">${esc(state.sublabel)}</text>`
438
+ : '';
439
+ const tag = state.tag
440
+ ? `\n <text data-detail="fine" x="${state.cx}" y="${state.y + state.height - 11}" class="${accent}" font-size="${fittedNodeFontSize(state.tag, state.width, stateTextFit.tagPreferred, stateTextFit.tagMinimum)}" text-anchor="middle">${esc(state.tag)}</text>`
441
+ : '';
442
+ const hasBrand = Boolean(brandMarkFor(state));
443
+ const step = state.step
444
+ ? `\n <text data-detail="fine" x="${state.x + (hasBrand ? 23 : 10)}" y="${state.y + 14}" class="${accent}" font-size="7" font-weight="700">${esc(state.step)}</text>`
445
+ : '';
446
+ const brand = renderBrandMark(state, { x: state.x + state.width - 22, y: state.y + 6 });
447
+ const labelFontSize = fittedNodeFontSize(state.label, brandLabelFitWidth(state, state.width), 10, 8);
448
+ const passport = {
449
+ kind: state.type,
450
+ sublabel: state.sublabel,
451
+ tag: state.tag,
452
+ context: laneLabels.get(state.lane) || i18nText(lifecycle.meta.locale, 'node.context.lifecycle'),
453
+ ...brandMetadataFor(state),
454
+ };
455
+ return ` <g ${focusNodeAttrs(state.id, state.label, passport, lifecycle.meta.locale)}>
456
+ ${focusNodeTitle(state.label, passport)}
457
+ <rect x="${state.x}" y="${state.y}" width="${state.width}" height="${state.height}" rx="7" class="c-mask"/>
458
+ <rect x="${state.x}" y="${state.y}" width="${state.width}" height="${state.height}" rx="7" class="${fill}"${animateAttr(lifecycle.meta, 'node', stateSteps.get(state.id))} stroke-width="1.5"/>
459
+ ${renderSemanticSigil(state.type, { x: hasBrand ? state.x + 6 : state.x + state.width - 17, y: state.y + 6 })}${brand ? `\n ${brand}` : ''}${step}
460
+ <text data-node-label=""${hasSub ? ' data-detail-anchor=""' : ''} x="${state.cx}" y="${state.y + 21}" class="t-primary" font-size="${labelFontSize}" font-weight="600" text-anchor="middle">${esc(state.label)}</text>${sub}${tag}
461
+ </g>`;
462
+ }
463
+
464
+ function renderTransitionPath(transition, index) {
465
+ const [cls, marker] = arrowClassMap[transition.variant || 'default'] || arrowClassMap.default;
466
+ const routed = pathFor(transition);
467
+ const strokeWidth = transition.width || (transition.variant === 'emphasis' ? 2 : 1.1);
468
+ return ` <path ${focusEdgeAttrs(transition.from, transition.to, transition.label, index, transition.id)} data-composition-points="${routePointsValue(routed.points)}" d="${routed.d}" class="${cls}"${animateAttr(lifecycle.meta, 'edge', index)} stroke-width="${strokeWidth}" marker-end="url(#${marker})"/>`;
469
+ }
470
+
471
+ function renderTransitionLabel(transition, index) {
472
+ if (!transition.label) return '';
473
+ const routed = pathFor(transition);
474
+ const [lx, ly] = labelPoint(transition, routed.points);
475
+ const longestLine = Math.max(textUnits(transition.label), textUnits(transition.note || ''));
476
+ const labelW = Math.max(32, longestLine * 4.9 + 12);
477
+ const labelH = transition.note ? 27 : 16;
478
+ const note = transition.note
479
+ ? `\n <text data-detail="fine" x="${lx}" y="${ly + 11}" class="t-dim" font-size="7" text-anchor="middle">${esc(transition.note)}</text>`
480
+ : '';
481
+ return ` <g data-detail="context" ${focusEdgeAttrs(transition.from, transition.to, transition.label, index, transition.id)}>
482
+ <rect x="${lx - labelW / 2}" y="${ly - 11}" width="${labelW}" height="${labelH}" rx="4" class="c-mask"/>
483
+ <text x="${lx}" y="${ly}" class="${variantAccent(transition.variant)}" font-size="8" text-anchor="middle">${esc(transition.label)}</text>${note}
484
+ </g>`;
485
+ }
486
+
487
+ const LEGEND_CATALOG = [
488
+ 'start',
489
+ 'active',
490
+ 'waiting',
491
+ 'decision',
492
+ 'success',
493
+ 'failure',
494
+ 'neutral',
495
+ 'external',
496
+ ].map((kind) => ({ kind, label: i18nText(lifecycle.meta.locale, `legend.lifecycle.${kind}`) }));
497
+
498
+ function renderLegend() {
499
+ const presentKinds = new Set([...states.values()].map((state) => state.type));
500
+ const entries = resolveLegend(lifecycle.meta?.legend, LEGEND_CATALOG, presentKinds);
501
+ return renderResolvedLegend({
502
+ entries,
503
+ locale: lifecycle.meta.locale,
504
+ layout: {
505
+ x: 40,
506
+ baselineY: legendY(),
507
+ width: viewBox[0] - 80,
508
+ minTitleY: lifecycleAreaBottom() + 8,
509
+ unfit: lifecycle.meta?.legend === undefined ? 'hide' : 'error',
510
+ diagramType: 'lifecycle',
511
+ },
512
+ renderSwatch: (entry) => `<rect x="${entry.x}" y="${entry.baseline - 8}" width="14" height="9" rx="2" class="${typeClass[entry.kind] || 'c-external'}" stroke-width="1"/>`,
513
+ });
514
+ }
515
+
516
+ function renderLifecycleRail() {
517
+ const mainCols = [...states.values()]
518
+ .filter((state) => bandFor(state.lane) === 'phase')
519
+ .map((state) => state.col);
520
+ if (!mainCols.length) return '';
521
+ const railEnd = layout.phaseXs[Math.max(...mainCols)] + 38;
522
+ return ` <path d="M 154 ${layout.phaseY + 31} L ${railEnd} ${layout.phaseY + 31}" class="a-emphasis" stroke-width="2.2" marker-end="url(#arrowhead-emphasis)"/>`;
523
+ }
524
+
525
+ function renderSvg() {
526
+ return ` <svg viewBox="0 0 ${viewBox[0]} ${viewBox[1]}" ${svgRootAttrs(lifecycle.meta)}>
527
+ ${svgAccessibleText(lifecycle.meta, 'lifecycle')}
528
+ ${renderDefinitions()}
529
+
530
+ <!-- Background Grid -->
531
+ <rect width="100%" height="100%" fill="url(#grid)" />
532
+
533
+ <!-- Lifecycle bands -->
534
+ ${renderBands()}
535
+
536
+ <!-- Primary lifecycle rail -->
537
+ ${renderLifecycleRail()}
538
+
539
+ <!-- Transition paths -->
540
+ ${asArray(lifecycle.transitions).map(renderTransitionPath).join('\n')}
541
+
542
+ <!-- States -->
543
+ ${[...states.values()].map(renderState).join('\n\n')}
544
+
545
+ <!-- Transition labels -->
546
+ ${asArray(lifecycle.transitions).map(renderTransitionLabel).join('\n')}
547
+
548
+ <!-- Legend -->
549
+ ${renderLegend()}
550
+ </svg>`;
551
+ }
552
+
553
+ validateLifecycle();
554
+ writeDiagram({
555
+ outPath,
556
+ template,
557
+ diagramType: 'lifecycle',
558
+ meta: lifecycle.meta,
559
+ svg: renderSvg(),
560
+ cards: lifecycle.cards,
561
+ });