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,835 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { collectAmbiguousCorridors, collectBorderRuns, collectLabelRouteClearance, collectRouteRhythmIssues, routeBudgetMetrics } from '../renderers/shared/geometry.mjs';
6
+ import {
7
+ DESKTOP_READABILITY_VIEWPORT,
8
+ DESKTOP_READER_DIAGRAM_WIDTH,
9
+ MIN_PROJECTED_NODE_TEXT_PX,
10
+ projectedNodeTextPx,
11
+ } from '../renderers/shared/desktop-readability.mjs';
12
+
13
+ const input = process.argv[2];
14
+
15
+ if (!input || input === '-h' || input === '--help') {
16
+ console.error('Usage: node scripts/check-render-output.mjs <diagram.html>');
17
+ process.exit(input ? 0 : 2);
18
+ }
19
+
20
+ const htmlPath = path.resolve(input);
21
+ let html;
22
+ try {
23
+ html = fs.readFileSync(htmlPath, 'utf8');
24
+ } catch (err) {
25
+ console.error(JSON.stringify({
26
+ ok: false,
27
+ file: htmlPath,
28
+ checks: [{ name: 'file_readable', ok: false, details: [err.message] }],
29
+ }, null, 2));
30
+ process.exit(1);
31
+ }
32
+
33
+ const checks = [];
34
+ let composition = {
35
+ schemaVersion: 1,
36
+ profile: 'standard',
37
+ status: 'pass',
38
+ summary: { errors: 0, warnings: 0 },
39
+ metrics: {
40
+ properCrossings: 0,
41
+ ambiguousCorridors: 0,
42
+ containerBorderRuns: 0,
43
+ labelRouteClearanceIssues: 0,
44
+ minLabelRouteClearance: null,
45
+ maxBends: 0,
46
+ routesOverSuggestedBends: 0,
47
+ maxStretch: null,
48
+ routesOverSuggestedStretch: 0,
49
+ minSegmentPx: null,
50
+ minInteriorSegmentPx: null,
51
+ shortSegmentCount: 0,
52
+ shortEndpointSegmentCount: 0,
53
+ shortInteriorSegmentCount: 0,
54
+ microSegmentCount: 0,
55
+ desktopReadabilityIssues: 0,
56
+ minProjectedNodeTextPx: null,
57
+ },
58
+ suggestedLimits: { bendsPerRelationship: 2, stretch: 1.35, segmentPx: 16, microSegmentPx: 8 },
59
+ issues: [],
60
+ };
61
+
62
+ function addCheck(name, ok, details = []) {
63
+ checks.push({ name, ok, details });
64
+ }
65
+
66
+ const svgMatches = [...html.matchAll(/<svg\b[\s\S]*?<\/svg>/gi)];
67
+ addCheck('single_svg', svgMatches.length === 1, [`found ${svgMatches.length} <svg> block(s)`]);
68
+
69
+ if (svgMatches.length === 1) {
70
+ const svg = svgMatches[0][0];
71
+ const svgRoot = svg.match(/<svg\b[^>]*>/i)?.[0] || '';
72
+ const svgAttrs = parseAttrs(svgRoot);
73
+ const qualityProfile = svgAttrs['data-quality-profile'] || 'standard';
74
+ const qualityGatesEnforced = svgAttrs['data-quality-gates'] !== 'advisory';
75
+ addCheck('finite_svg', !/\b(?:NaN|undefined|Infinity|-Infinity)\b/.test(svg));
76
+ const legendStart = svg.indexOf('<!-- Legend -->');
77
+ const beforeLegend = legendStart >= 0 ? svg.slice(0, legendStart) : svg;
78
+ const desktopReadabilityIssue = collectDesktopReadability(svgAttrs, beforeLegend);
79
+ const arrows = collectArrows(beforeLegend);
80
+ const diagonal = arrows.flatMap((arrow) => diagonalStraightSegments(arrow).map((segment) => ({ arrow, ...segment })));
81
+ addCheck(
82
+ 'orthogonal_arrows',
83
+ diagonal.length === 0,
84
+ diagonal.map(({ arrow, segmentIndex }) => `${arrow.kind} ${arrow.index} segment ${segmentIndex + 1}: ${arrow.raw}`),
85
+ );
86
+ const relationshipCrossings = collectRelationshipCrossings(arrows);
87
+ const compositionFrames = collectCompositionFrames(beforeLegend);
88
+ const containerBorderRuns = collectBorderRuns({
89
+ routedRelations: arrows
90
+ .filter((arrow) => arrow.from && arrow.to && arrow.borderSegments.length)
91
+ .map((arrow) => ({
92
+ relation: arrow,
93
+ relationIndex: arrow.index,
94
+ segments: arrow.borderSegments,
95
+ })),
96
+ frames: compositionFrames,
97
+ });
98
+ const routedRelationships = arrows
99
+ .filter((arrow) => arrow.from && arrow.to && arrow.routePoints.length)
100
+ .map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints }));
101
+ const routeMetrics = routeBudgetMetrics({ routedRelations: routedRelationships });
102
+ const routeRhythmIssues = collectRouteRhythmIssues({ routedRelations: routedRelationships });
103
+ const ambiguousCorridors = collectAmbiguousCorridors({ routedRelations: routedRelationships });
104
+ const relationshipLabels = collectRelationshipLabelMasks(beforeLegend, arrows);
105
+ const labelClearanceThreshold = qualityProfile === 'showcase' ? 4 : 2;
106
+ const labelRouteMeasurements = collectLabelRouteClearance({
107
+ labels: relationshipLabels,
108
+ routedRelations: arrows.map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints })),
109
+ threshold: Number.MAX_VALUE,
110
+ });
111
+ const labelRouteClearance = collectLabelRouteClearance({
112
+ labels: relationshipLabels,
113
+ routedRelations: arrows.map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints })),
114
+ threshold: labelClearanceThreshold,
115
+ });
116
+ const crossingIsError = qualityProfile === 'showcase';
117
+ const corridorIsError = qualityProfile === 'showcase';
118
+ const rhythmIsError = qualityProfile === 'showcase';
119
+ const labelClearanceIsError = qualityProfile === 'showcase';
120
+ const desktopReadabilityIsError = qualityProfile === 'showcase';
121
+ const compositionErrors = (qualityGatesEnforced ? containerBorderRuns.length : 0)
122
+ + (crossingIsError ? relationshipCrossings.length : 0)
123
+ + (corridorIsError ? ambiguousCorridors.length : 0)
124
+ + (labelClearanceIsError ? labelRouteClearance.length : 0)
125
+ + (rhythmIsError ? routeRhythmIssues.length : 0)
126
+ + (desktopReadabilityIsError && desktopReadabilityIssue ? 1 : 0);
127
+ const compositionWarnings = (qualityGatesEnforced ? 0 : containerBorderRuns.length)
128
+ + (crossingIsError ? 0 : relationshipCrossings.length)
129
+ + (corridorIsError ? 0 : ambiguousCorridors.length)
130
+ + (labelClearanceIsError ? 0 : labelRouteClearance.length)
131
+ + (rhythmIsError ? 0 : routeRhythmIssues.length)
132
+ + (desktopReadabilityIsError || !desktopReadabilityIssue ? 0 : 1);
133
+ composition = {
134
+ schemaVersion: 1,
135
+ profile: qualityProfile,
136
+ status: compositionErrors ? 'fail' : 'pass',
137
+ summary: {
138
+ errors: compositionErrors,
139
+ warnings: compositionWarnings,
140
+ },
141
+ metrics: {
142
+ properCrossings: relationshipCrossings.length,
143
+ ambiguousCorridors: ambiguousCorridors.length,
144
+ containerBorderRuns: containerBorderRuns.length,
145
+ labelRouteClearanceIssues: labelRouteClearance.length,
146
+ minLabelRouteClearance: labelRouteMeasurements.length
147
+ ? Math.round(Math.min(...labelRouteMeasurements.map((hit) => hit.clearance)) * 10) / 10
148
+ : null,
149
+ desktopReadabilityIssues: desktopReadabilityIssue ? 1 : 0,
150
+ minProjectedNodeTextPx: desktopReadabilityIssue?.projectedFontPx ?? null,
151
+ ...roundedRouteMetrics(routeMetrics),
152
+ },
153
+ suggestedLimits: { bendsPerRelationship: 2, stretch: 1.35, segmentPx: 16, microSegmentPx: 8 },
154
+ issues: [
155
+ ...containerBorderRuns.map((hit) => ({
156
+ severity: qualityGatesEnforced ? 'error' : 'warning',
157
+ code: 'composition/container-border-run',
158
+ relationship: relationshipRecord(hit.relation),
159
+ frame: frameRecord(hit.frame),
160
+ side: hit.side,
161
+ segmentIndex: hit.segmentIndex,
162
+ overlapLength: Math.round(hit.overlapLength * 10) / 10,
163
+ from: hit.overlapStart.map((value) => Math.round(value * 10) / 10),
164
+ to: hit.overlapEnd.map((value) => Math.round(value * 10) / 10),
165
+ })),
166
+ ...labelRouteClearance.map((hit) => ({
167
+ severity: labelClearanceIsError ? 'error' : 'warning',
168
+ code: 'composition/label-route-clearance',
169
+ label: hit.label?.label || hit.labelRelation?.label || '',
170
+ labelRelationship: relationshipRecord(hit.labelRelation),
171
+ otherRelationship: relationshipRecord(hit.otherRelation),
172
+ segmentIndex: hit.segmentIndex,
173
+ labelRect: roundedRect(hit.rect),
174
+ clearance: Math.round(hit.clearance * 10) / 10,
175
+ intersectionLength: Math.round((hit.intersectionLength || 0) * 10) / 10,
176
+ threshold: hit.threshold,
177
+ from: hit.start.map((value) => Math.round(value * 10) / 10),
178
+ to: hit.end.map((value) => Math.round(value * 10) / 10),
179
+ })),
180
+ ...relationshipCrossings.map((hit) => ({
181
+ severity: crossingIsError ? 'error' : 'warning',
182
+ code: 'composition/proper-crossing',
183
+ relationship: relationshipRecord(hit.left),
184
+ otherRelationship: relationshipRecord(hit.right),
185
+ point: hit.point.map((value) => Math.round(value * 10) / 10),
186
+ })),
187
+ ...ambiguousCorridors.map((hit) => ({
188
+ severity: corridorIsError ? 'error' : 'warning',
189
+ code: 'composition/ambiguous-corridor',
190
+ relationship: relationshipRecord(hit.left.relation),
191
+ otherRelationship: relationshipRecord(hit.right.relation),
192
+ segmentIndex: hit.leftSegment,
193
+ otherSegmentIndex: hit.rightSegment,
194
+ overlapLength: Math.round(hit.overlapLength * 10) / 10,
195
+ from: hit.overlapStart.map((value) => Math.round(value * 10) / 10),
196
+ to: hit.overlapEnd.map((value) => Math.round(value * 10) / 10),
197
+ })),
198
+ ...routeRhythmIssues.map((hit) => ({
199
+ severity: rhythmIsError ? 'error' : 'warning',
200
+ code: hit.code,
201
+ relationship: relationshipRecord(hit.relation),
202
+ segmentIndex: hit.segmentIndex,
203
+ position: hit.position,
204
+ length: Math.round(hit.length * 10) / 10,
205
+ from: hit.start.map((value) => Math.round(value * 10) / 10),
206
+ to: hit.end.map((value) => Math.round(value * 10) / 10),
207
+ })),
208
+ ...(desktopReadabilityIssue ? [{
209
+ severity: desktopReadabilityIsError ? 'error' : 'warning',
210
+ code: 'composition/desktop-readability',
211
+ viewportWidth: DESKTOP_READABILITY_VIEWPORT.width,
212
+ viewportHeight: DESKTOP_READABILITY_VIEWPORT.height,
213
+ availableDiagramWidth: DESKTOP_READER_DIAGRAM_WIDTH,
214
+ viewBoxWidth: desktopReadabilityIssue.viewBoxWidth,
215
+ scale: desktopReadabilityIssue.scale,
216
+ text: desktopReadabilityIssue.text,
217
+ detail: desktopReadabilityIssue.detail,
218
+ sourceFontPx: desktopReadabilityIssue.sourceFontPx,
219
+ projectedFontPx: desktopReadabilityIssue.projectedFontPx,
220
+ minimumProjectedFontPx: MIN_PROJECTED_NODE_TEXT_PX,
221
+ }] : []),
222
+ ],
223
+ };
224
+ addCheck(
225
+ 'label_route_clearance',
226
+ !labelClearanceIsError || labelRouteClearance.length === 0,
227
+ labelRouteClearance.map((hit) => (
228
+ `[composition/label-route-clearance] ${qualityProfile} label "${hit.label?.label || hit.labelRelation?.label || ''}" on ${relationshipName(hit.labelRelation)} is ${Math.round(hit.clearance * 10) / 10}px from ${relationshipName(hit.otherRelation)} segment ${hit.segmentIndex} [${formatPoint(hit.start)}] -> [${formatPoint(hit.end)}]${hit.intersectionLength > 0 ? ` with ${Math.round(hit.intersectionLength * 10) / 10}px hidden by the mask` : ''} (minimum ${hit.threshold}px) — use renderer-supported label controls (message y for sequence; otherwise labelAt, labelDx, labelDy, or labelSegment), or adjust the other relationship route/via/channel.`
229
+ )),
230
+ );
231
+ addCheck(
232
+ 'relationship_crossings',
233
+ !crossingIsError || relationshipCrossings.length === 0,
234
+ relationshipCrossings.map((hit) => (
235
+ `[composition/proper-crossing] ${qualityProfile} ${relationshipName(hit.left)} crosses ${relationshipName(hit.right)} at [${formatPoint(hit.point)}]`
236
+ )),
237
+ );
238
+ addCheck(
239
+ 'relationship_corridors',
240
+ !corridorIsError || ambiguousCorridors.length === 0,
241
+ ambiguousCorridors.map((hit) => (
242
+ `[composition/ambiguous-corridor] ${qualityProfile} ${relationshipName(hit.left.relation)} shares a ${Math.round(hit.overlapLength * 10) / 10}px corridor with ${relationshipName(hit.right.relation)} at [${formatPoint(hit.overlapStart)}] -> [${formatPoint(hit.overlapEnd)}]`
243
+ )),
244
+ );
245
+ addCheck(
246
+ 'container_border_runs',
247
+ !qualityGatesEnforced || containerBorderRuns.length === 0,
248
+ containerBorderRuns.map((hit) => (
249
+ `[composition/container-border-run] ${relationshipName(hit.relation)} follows ${frameName(hit.frame)} ${hit.side} border for ${Math.round(hit.overlapLength * 10) / 10}px on segment ${hit.segmentIndex} [${formatPoint(hit.overlapStart)}] -> [${formatPoint(hit.overlapEnd)}]`
250
+ )),
251
+ );
252
+ addCheck(
253
+ 'route_rhythm',
254
+ !rhythmIsError || routeRhythmIssues.length === 0,
255
+ routeRhythmIssues.map((hit) => (
256
+ `[${hit.code}] ${qualityProfile} ${relationshipName(hit.relation)} has a ${Math.round(hit.length * 10) / 10}px ${hit.position} segment ${hit.segmentIndex} [${formatPoint(hit.start)}] -> [${formatPoint(hit.end)}]`
257
+ )),
258
+ );
259
+
260
+ if (legendStart >= 0) {
261
+ const legendFragment = svg.slice(legendStart);
262
+ const legendBoxes = collectLegendBoxes(legendFragment);
263
+ const collisions = collectLegendCollisions(arrows, legendBoxes);
264
+ addCheck(
265
+ 'legend_clearance',
266
+ collisions.length === 0,
267
+ collisions.map((hit) => `${hit.arrow.kind} ${hit.arrow.index} crosses legend ${hit.box.label}`),
268
+ );
269
+ } else {
270
+ addCheck('legend_clearance', true, ['no legend marker found']);
271
+ }
272
+ }
273
+
274
+ const ok = checks.every((check) => check.ok) && composition.status !== 'fail';
275
+ console.log(JSON.stringify({ ok, file: htmlPath, checks, composition }, null, 2));
276
+ process.exit(ok ? 0 : 1);
277
+
278
+ function collectArrows(fragment) {
279
+ const arrows = [];
280
+ let index = 0;
281
+
282
+ for (const tag of fragment.matchAll(/<(path|line)\b[^>]*>/gi)) {
283
+ const raw = tag[0];
284
+ if (!/\bclass="[^"]*\ba-(?:default|emphasis|security|dashed)\b/.test(raw)) continue;
285
+ if (!/\bmarker-end=/.test(raw)) continue;
286
+ const attrs = parseAttrs(raw);
287
+ const segments = tag[1].toLowerCase() === 'line'
288
+ ? lineSegments(attrs)
289
+ : pathSegments(attrs.d || '');
290
+ const borderSegments = tag[1].toLowerCase() === 'line'
291
+ ? segments
292
+ : straightPathSegments(attrs.d || '');
293
+ arrows.push({
294
+ kind: tag[1].toLowerCase(),
295
+ index: index += 1,
296
+ raw,
297
+ segments,
298
+ borderSegments,
299
+ routePoints: parseRoutePoints(attrs['data-composition-points']) || (
300
+ borderSegments.length ? [borderSegments[0].start, ...borderSegments.map((segment) => segment.end)] : []
301
+ ),
302
+ from: attrs['data-edge-from'] || attrs['data-composition-edge-from'],
303
+ to: attrs['data-edge-to'] || attrs['data-composition-edge-to'],
304
+ id: attrs['data-edge-id'] || attrs['data-composition-edge-id'],
305
+ key: attrs['data-edge-key'],
306
+ label: attrs['data-edge-label'],
307
+ offset: tag.index,
308
+ });
309
+ }
310
+
311
+ return arrows;
312
+ }
313
+
314
+ function collectRelationshipLabelMasks(fragment, arrows) {
315
+ const labels = [];
316
+ for (const match of fragment.matchAll(/<g\b[^>]*\bdata-edge-(?:key|id|from)="[^"]*"[^>]*>[\s\S]*?<\/g>/gi)) {
317
+ const group = match[0];
318
+ const groupAttrs = parseAttrs(group.match(/<g\b[^>]*>/i)?.[0] || '');
319
+ const rectTag = [...group.matchAll(/<rect\b[^>]*>/gi)]
320
+ .map((item) => item[0])
321
+ .find((tag) => /\bclass="[^"]*\bc-mask\b/.test(tag));
322
+ if (!rectTag) continue;
323
+ const attrs = parseAttrs(rectTag);
324
+ const rect = {
325
+ x: numberAttr(attrs, 'x'),
326
+ y: numberAttr(attrs, 'y'),
327
+ width: numberAttr(attrs, 'width'),
328
+ height: numberAttr(attrs, 'height'),
329
+ };
330
+ if (![rect.x, rect.y, rect.width, rect.height].every(Number.isFinite)) continue;
331
+ const groupStart = match.index;
332
+ const groupEnd = groupStart + group.length;
333
+ const containedOwner = arrows.find((arrow) => (
334
+ arrow.offset > groupStart
335
+ && arrow.offset < groupEnd
336
+ && arrow.from === groupAttrs['data-edge-from']
337
+ && arrow.to === groupAttrs['data-edge-to']
338
+ && (!groupAttrs['data-edge-id'] || !arrow.id || arrow.id === groupAttrs['data-edge-id'])
339
+ ));
340
+ const owner = arrows.find((arrow) => (
341
+ groupAttrs['data-edge-key'] !== undefined && arrow.key === groupAttrs['data-edge-key']
342
+ )) || containedOwner || arrows.find((arrow) => (
343
+ arrow.id === groupAttrs['data-edge-id']
344
+ && arrow.from === groupAttrs['data-edge-from']
345
+ && arrow.to === groupAttrs['data-edge-to']
346
+ ));
347
+ if (!owner) continue;
348
+ if (owner.key === undefined && groupAttrs['data-edge-key'] !== undefined) owner.key = groupAttrs['data-edge-key'];
349
+ if (!owner.id && groupAttrs['data-edge-id']) owner.id = groupAttrs['data-edge-id'];
350
+ if (!owner.label && groupAttrs['data-edge-label']) owner.label = groupAttrs['data-edge-label'];
351
+ labels.push({
352
+ relation: owner,
353
+ relationIndex: owner.index,
354
+ label: groupAttrs['data-edge-label'] || '',
355
+ rect,
356
+ });
357
+ }
358
+ return labels;
359
+ }
360
+
361
+ function roundedRect(rect) {
362
+ return Object.fromEntries(Object.entries(rect).map(([key, value]) => [key, Math.round(value * 10) / 10]));
363
+ }
364
+
365
+ function roundedRouteMetrics(metrics) {
366
+ return {
367
+ ...metrics,
368
+ maxStretch: metrics.maxStretch == null ? null : Math.round(metrics.maxStretch * 1000) / 1000,
369
+ minSegmentPx: metrics.minSegmentPx == null ? null : Math.round(metrics.minSegmentPx * 10) / 10,
370
+ minInteriorSegmentPx: metrics.minInteriorSegmentPx == null ? null : Math.round(metrics.minInteriorSegmentPx * 10) / 10,
371
+ };
372
+ }
373
+
374
+ function parseRoutePoints(value) {
375
+ if (!value) return null;
376
+ const points = value.split(';').map((pair) => pair.split(',').map(Number));
377
+ return points.length >= 2 && points.every(isPoint) ? points : null;
378
+ }
379
+
380
+ function collectRelationshipCrossings(arrows) {
381
+ const relationships = arrows.filter((arrow) => arrow.from && arrow.to && arrow.segments.length);
382
+ const crossings = [];
383
+ for (let leftIndex = 0; leftIndex < relationships.length; leftIndex += 1) {
384
+ const left = relationships[leftIndex];
385
+ for (let rightIndex = leftIndex + 1; rightIndex < relationships.length; rightIndex += 1) {
386
+ const right = relationships[rightIndex];
387
+ if ([left.from, left.to].some((id) => id === right.from || id === right.to)) continue;
388
+ let point = null;
389
+ for (const leftSegment of left.segments) {
390
+ for (const rightSegment of right.segments) {
391
+ point = properSegmentIntersection(leftSegment.start, leftSegment.end, rightSegment.start, rightSegment.end);
392
+ if (point) break;
393
+ }
394
+ if (point) break;
395
+ }
396
+ if (point) crossings.push({ left, right, point });
397
+ }
398
+ }
399
+ return crossings;
400
+ }
401
+
402
+ function relationshipName(arrow) {
403
+ return arrow.id
404
+ ? `relationship id "${arrow.id}" ("${arrow.from}" -> "${arrow.to}")`
405
+ : `relationship "${arrow.from}" -> "${arrow.to}"`;
406
+ }
407
+
408
+ function relationshipRecord(arrow) {
409
+ const stableIndex = Number(arrow.key);
410
+ return {
411
+ id: arrow.id,
412
+ from: arrow.from,
413
+ to: arrow.to,
414
+ label: arrow.label || '',
415
+ collectionIndex: Number.isInteger(stableIndex) && stableIndex >= 0 ? stableIndex : arrow.index - 1,
416
+ artifactIndex: arrow.index,
417
+ };
418
+ }
419
+
420
+ function collectCompositionFrames(fragment) {
421
+ const frames = [];
422
+ for (const match of fragment.matchAll(/<(rect|path|line)\b[^>]*>/gi)) {
423
+ const attrs = parseAttrs(match[0]);
424
+ const kind = attrs['data-composition-frame-kind'];
425
+ if (!kind) continue;
426
+ const identity = attrs['data-composition-frame-id'] || frames.length;
427
+ if (match[1].toLowerCase() === 'rect') {
428
+ const frame = {
429
+ kind,
430
+ id: identity,
431
+ x: numberAttr(attrs, 'x'),
432
+ y: numberAttr(attrs, 'y'),
433
+ width: numberAttr(attrs, 'width'),
434
+ height: numberAttr(attrs, 'height'),
435
+ radius: numberAttr(attrs, 'rx') || 0,
436
+ };
437
+ if ([frame.x, frame.y, frame.width, frame.height].every(Number.isFinite)) frames.push(frame);
438
+ continue;
439
+ }
440
+ const segments = match[1].toLowerCase() === 'line'
441
+ ? lineSegments(attrs)
442
+ : pathSegments(attrs.d || '');
443
+ for (const [segmentIndex, segment] of segments.entries()) {
444
+ frames.push({
445
+ kind,
446
+ id: segments.length > 1 ? `${identity}:${segmentIndex}` : identity,
447
+ shape: 'line',
448
+ start: segment.start,
449
+ end: segment.end,
450
+ });
451
+ }
452
+ }
453
+ return frames;
454
+ }
455
+
456
+ function frameName(frame) {
457
+ return `${frame.kind || 'frame'} "${frame.id}"`;
458
+ }
459
+
460
+ function frameRecord(frame) {
461
+ return { kind: frame.kind, id: frame.id };
462
+ }
463
+
464
+ function formatPoint(point) {
465
+ return point.map((value) => Math.round(value * 10) / 10).join(', ');
466
+ }
467
+
468
+ function lineSegments(attrs) {
469
+ const start = [numberAttr(attrs, 'x1'), numberAttr(attrs, 'y1')];
470
+ const end = [numberAttr(attrs, 'x2'), numberAttr(attrs, 'y2')];
471
+ if (!isPoint(start) || !isPoint(end)) return [];
472
+ return [{ start, end }];
473
+ }
474
+
475
+ function pathSegments(d) {
476
+ const points = pointsFromPath(d);
477
+ const segments = [];
478
+ for (let i = 1; i < points.length; i += 1) {
479
+ segments.push({ start: points[i - 1], end: points[i] });
480
+ }
481
+ return segments;
482
+ }
483
+
484
+ // Border runs use exact visible primitives. Non-collinear Q curves are never
485
+ // flattened into chords here: a tangent or sampled near-horizontal curve is
486
+ // not a structural border run. A fully collinear Q remains a straight visible
487
+ // primitive and is included.
488
+ function straightPathSegments(d) {
489
+ const tokens = d.match(/[MLHVQZmlhvqz]|[-+]?(?:\d*\.)?\d+(?:e[-+]?\d+)?/g) || [];
490
+ const segments = [];
491
+ let i = 0;
492
+ let command = '';
493
+ let current = [0, 0];
494
+ let start = null;
495
+ while (i < tokens.length) {
496
+ if (isCommand(tokens[i])) command = tokens[i++];
497
+ if (!command) break;
498
+ const absolute = command === command.toUpperCase();
499
+ switch (command.toUpperCase()) {
500
+ case 'M':
501
+ case 'L': {
502
+ let first = true;
503
+ while (i + 1 < tokens.length && !isCommand(tokens[i])) {
504
+ const point = [Number.parseFloat(tokens[i++]), Number.parseFloat(tokens[i++])];
505
+ if (!point.every(Number.isFinite)) break;
506
+ const next = absolute ? point : [current[0] + point[0], current[1] + point[1]];
507
+ if (command.toUpperCase() === 'L' || !first) segments.push({ start: current, end: next });
508
+ current = next;
509
+ if (!start) start = current;
510
+ first = false;
511
+ }
512
+ break;
513
+ }
514
+ case 'H': {
515
+ while (i < tokens.length && !isCommand(tokens[i])) {
516
+ const value = Number.parseFloat(tokens[i++]);
517
+ if (!Number.isFinite(value)) break;
518
+ const next = [absolute ? value : current[0] + value, current[1]];
519
+ segments.push({ start: current, end: next });
520
+ current = next;
521
+ }
522
+ break;
523
+ }
524
+ case 'V': {
525
+ while (i < tokens.length && !isCommand(tokens[i])) {
526
+ const value = Number.parseFloat(tokens[i++]);
527
+ if (!Number.isFinite(value)) break;
528
+ const next = [current[0], absolute ? value : current[1] + value];
529
+ segments.push({ start: current, end: next });
530
+ current = next;
531
+ }
532
+ break;
533
+ }
534
+ case 'Q': {
535
+ while (i + 3 < tokens.length && !isCommand(tokens[i])) {
536
+ const values = [0, 0, 0, 0].map(() => Number.parseFloat(tokens[i++]));
537
+ if (!values.every(Number.isFinite)) break;
538
+ const control = absolute ? values.slice(0, 2) : [current[0] + values[0], current[1] + values[1]];
539
+ const end = absolute ? values.slice(2, 4) : [current[0] + values[2], current[1] + values[3]];
540
+ if (Math.abs(crossProduct(current, control, end)) <= 1e-9) segments.push({ start: current, end });
541
+ current = end;
542
+ }
543
+ break;
544
+ }
545
+ case 'Z':
546
+ if (start) segments.push({ start: current, end: start });
547
+ current = start || current;
548
+ command = '';
549
+ break;
550
+ default:
551
+ return [];
552
+ }
553
+ }
554
+ return segments.filter(({ start: a, end: b }) => isPoint(a) && isPoint(b));
555
+ }
556
+
557
+ function diagonalStraightSegments(arrow) {
558
+ return arrow.borderSegments.flatMap(({ start, end }, segmentIndex) => (
559
+ Math.abs(start[0] - end[0]) > 0.01 && Math.abs(start[1] - end[1]) > 0.01
560
+ ? [{ segmentIndex, start, end }]
561
+ : []
562
+ ));
563
+ }
564
+
565
+ function collectLegendBoxes(fragment) {
566
+ const boxes = [];
567
+
568
+ for (const match of fragment.matchAll(/<rect\b[^>]*>/gi)) {
569
+ const attrs = parseAttrs(match[0]);
570
+ const x = numberAttr(attrs, 'x');
571
+ const y = numberAttr(attrs, 'y');
572
+ const width = numberAttr(attrs, 'width');
573
+ const height = numberAttr(attrs, 'height');
574
+ if ([x, y, width, height].every(Number.isFinite)) {
575
+ boxes.push({ x1: x, y1: y, x2: x + width, y2: y + height, label: `rect@${x},${y}` });
576
+ }
577
+ }
578
+
579
+ for (const match of fragment.matchAll(/<text\b([^>]*)>([\s\S]*?)<\/text>/gi)) {
580
+ const attrs = parseAttrs(match[1]);
581
+ const box = textBox(attrs, stripTags(match[2]).trim());
582
+ if (box) boxes.push(box);
583
+ }
584
+
585
+ return boxes;
586
+ }
587
+
588
+ function collectLegendCollisions(arrows, boxes) {
589
+ const collisions = [];
590
+ for (const arrow of arrows) {
591
+ for (const segment of arrow.segments) {
592
+ for (const box of boxes) {
593
+ if (segmentIntersectsBox(segment, padBox(box, 2))) {
594
+ collisions.push({ arrow, box });
595
+ }
596
+ }
597
+ }
598
+ }
599
+ return collisions;
600
+ }
601
+
602
+ function textBox(attrs, text) {
603
+ const x = numberAttr(attrs, 'x');
604
+ const y = numberAttr(attrs, 'y');
605
+ const fontSize = Number.parseFloat(attrs['font-size'] || '10');
606
+ if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(fontSize)) return null;
607
+ const width = estimatedTextWidth(text, fontSize);
608
+ const anchor = attrs['text-anchor'] || 'start';
609
+ let x1 = x;
610
+ if (anchor === 'middle') x1 = x - width / 2;
611
+ if (anchor === 'end') x1 = x - width;
612
+ return {
613
+ x1,
614
+ y1: y - fontSize,
615
+ x2: x1 + width,
616
+ y2: y + fontSize * 0.25,
617
+ label: text || `text@${x},${y}`,
618
+ };
619
+ }
620
+
621
+ function collectDesktopReadability(svgAttrs, fragment) {
622
+ const viewBox = String(svgAttrs.viewBox || '').trim().split(/[\s,]+/).map(Number);
623
+ const viewBoxWidth = viewBox.length === 4 ? viewBox[2] : Number.NaN;
624
+ if (!Number.isFinite(viewBoxWidth) || viewBoxWidth <= 0) return null;
625
+ const scale = Math.min(1, DESKTOP_READER_DIAGRAM_WIDTH / viewBoxWidth);
626
+ let worst = null;
627
+ for (const match of fragment.matchAll(/<text\b([^>]*)>([\s\S]*?)<\/text>/gi)) {
628
+ const primary = /\bdata-node-label(?:\s*=|\s|$)/i.test(match[1]);
629
+ const boundary = /\bdata-boundary-label(?:\s*=|\s|$)/i.test(match[1]);
630
+ const context = /\bdata-detail\s*=\s*"context"/i.test(match[1]);
631
+ if (!primary && !boundary && !context) continue;
632
+ const attrs = parseAttrs(match[1]);
633
+ const fontSize = Number.parseFloat(attrs['font-size'] || '');
634
+ if (!Number.isFinite(fontSize)) continue;
635
+ const projected = projectedNodeTextPx(fontSize, viewBoxWidth);
636
+ if (projected >= MIN_PROJECTED_NODE_TEXT_PX) continue;
637
+ const candidate = {
638
+ viewBoxWidth,
639
+ scale,
640
+ text: stripTags(match[2]).trim(),
641
+ detail: primary
642
+ ? 'primary'
643
+ : boundary ? 'boundary' : 'context',
644
+ sourceFontPx: fontSize,
645
+ projectedFontPx: projected,
646
+ };
647
+ if (!worst || candidate.projectedFontPx < worst.projectedFontPx) worst = candidate;
648
+ }
649
+ return worst;
650
+ }
651
+
652
+ function estimatedTextWidth(text, fontSize) {
653
+ let units = 0;
654
+ for (const char of text) units += char.charCodeAt(0) > 255 ? 1.8 : 0.62;
655
+ return Math.max(fontSize, units * fontSize);
656
+ }
657
+
658
+ function pointsFromPath(d) {
659
+ const tokens = d.match(/[MLHVQZmlhvqz]|[-+]?(?:\d*\.)?\d+(?:e[-+]?\d+)?/g) || [];
660
+ const points = [];
661
+ let i = 0;
662
+ let command = '';
663
+ let current = [0, 0];
664
+ let start = null;
665
+
666
+ while (i < tokens.length) {
667
+ if (isCommand(tokens[i])) command = tokens[i++];
668
+ if (!command) break;
669
+
670
+ const absolute = command === command.toUpperCase();
671
+ switch (command.toUpperCase()) {
672
+ case 'M':
673
+ case 'L': {
674
+ while (i + 1 < tokens.length && !isCommand(tokens[i])) {
675
+ const x = Number.parseFloat(tokens[i++]);
676
+ const y = Number.parseFloat(tokens[i++]);
677
+ if (!Number.isFinite(x) || !Number.isFinite(y)) break;
678
+ current = absolute ? [x, y] : [current[0] + x, current[1] + y];
679
+ points.push(current);
680
+ if (!start) start = current;
681
+ }
682
+ break;
683
+ }
684
+ case 'H': {
685
+ while (i < tokens.length && !isCommand(tokens[i])) {
686
+ const x = Number.parseFloat(tokens[i++]);
687
+ if (!Number.isFinite(x)) break;
688
+ current = absolute ? [x, current[1]] : [current[0] + x, current[1]];
689
+ points.push(current);
690
+ }
691
+ break;
692
+ }
693
+ case 'V': {
694
+ while (i < tokens.length && !isCommand(tokens[i])) {
695
+ const y = Number.parseFloat(tokens[i++]);
696
+ if (!Number.isFinite(y)) break;
697
+ current = absolute ? [current[0], y] : [current[0], current[1] + y];
698
+ points.push(current);
699
+ }
700
+ break;
701
+ }
702
+ case 'Q': {
703
+ while (i + 3 < tokens.length && !isCommand(tokens[i])) {
704
+ const controlX = Number.parseFloat(tokens[i++]);
705
+ const controlY = Number.parseFloat(tokens[i++]);
706
+ const endX = Number.parseFloat(tokens[i++]);
707
+ const endY = Number.parseFloat(tokens[i++]);
708
+ if (![controlX, controlY, endX, endY].every(Number.isFinite)) break;
709
+ const control = absolute
710
+ ? [controlX, controlY]
711
+ : [current[0] + controlX, current[1] + controlY];
712
+ const end = absolute
713
+ ? [endX, endY]
714
+ : [current[0] + endX, current[1] + endY];
715
+ const startPoint = current;
716
+ for (let step = 1; step <= 8; step += 1) {
717
+ const amount = step / 8;
718
+ const remaining = 1 - amount;
719
+ points.push([
720
+ remaining * remaining * startPoint[0] + 2 * remaining * amount * control[0] + amount * amount * end[0],
721
+ remaining * remaining * startPoint[1] + 2 * remaining * amount * control[1] + amount * amount * end[1],
722
+ ]);
723
+ }
724
+ current = end;
725
+ }
726
+ break;
727
+ }
728
+ case 'Z': {
729
+ if (start) points.push(start);
730
+ break;
731
+ }
732
+ default:
733
+ return [];
734
+ }
735
+ }
736
+
737
+ return points.filter(isPoint);
738
+ }
739
+
740
+ function properSegmentIntersection(a, b, c, d) {
741
+ const abC = crossProduct(a, b, c);
742
+ const abD = crossProduct(a, b, d);
743
+ const cdA = crossProduct(c, d, a);
744
+ const cdB = crossProduct(c, d, b);
745
+ const epsilon = 1e-9;
746
+ const opposite = (left, right) => (left > epsilon && right < -epsilon) || (left < -epsilon && right > epsilon);
747
+ if (!opposite(abC, abD) || !opposite(cdA, cdB)) return null;
748
+ const denominator = (a[0] - b[0]) * (c[1] - d[1]) - (a[1] - b[1]) * (c[0] - d[0]);
749
+ if (Math.abs(denominator) < epsilon) return null;
750
+ const ab = a[0] * b[1] - a[1] * b[0];
751
+ const cd = c[0] * d[1] - c[1] * d[0];
752
+ return [
753
+ (ab * (c[0] - d[0]) - (a[0] - b[0]) * cd) / denominator,
754
+ (ab * (c[1] - d[1]) - (a[1] - b[1]) * cd) / denominator,
755
+ ];
756
+ }
757
+
758
+ function crossProduct(a, b, c) {
759
+ return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
760
+ }
761
+
762
+ function segmentIntersectsBox(segment, box) {
763
+ const { start, end } = segment;
764
+ if (pointInsideBox(start, box) || pointInsideBox(end, box)) return true;
765
+ const edges = [
766
+ [[box.x1, box.y1], [box.x2, box.y1]],
767
+ [[box.x2, box.y1], [box.x2, box.y2]],
768
+ [[box.x2, box.y2], [box.x1, box.y2]],
769
+ [[box.x1, box.y2], [box.x1, box.y1]],
770
+ ];
771
+ return edges.some(([a, b]) => segmentsIntersect(start, end, a, b));
772
+ }
773
+
774
+ function segmentsIntersect(a, b, c, d) {
775
+ const o1 = orientation(a, b, c);
776
+ const o2 = orientation(a, b, d);
777
+ const o3 = orientation(c, d, a);
778
+ const o4 = orientation(c, d, b);
779
+
780
+ if (o1 !== o2 && o3 !== o4) return true;
781
+ if (o1 === 0 && onSegment(a, c, b)) return true;
782
+ if (o2 === 0 && onSegment(a, d, b)) return true;
783
+ if (o3 === 0 && onSegment(c, a, d)) return true;
784
+ if (o4 === 0 && onSegment(c, b, d)) return true;
785
+ return false;
786
+ }
787
+
788
+ function orientation(a, b, c) {
789
+ const value = (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1]);
790
+ if (Math.abs(value) < 1e-9) return 0;
791
+ return value > 0 ? 1 : 2;
792
+ }
793
+
794
+ function onSegment(a, b, c) {
795
+ return b[0] <= Math.max(a[0], c[0]) + 1e-9
796
+ && b[0] + 1e-9 >= Math.min(a[0], c[0])
797
+ && b[1] <= Math.max(a[1], c[1]) + 1e-9
798
+ && b[1] + 1e-9 >= Math.min(a[1], c[1]);
799
+ }
800
+
801
+ function pointInsideBox(point, box) {
802
+ return point[0] >= box.x1 && point[0] <= box.x2 && point[1] >= box.y1 && point[1] <= box.y2;
803
+ }
804
+
805
+ function padBox(box, padding) {
806
+ return {
807
+ ...box,
808
+ x1: box.x1 - padding,
809
+ y1: box.y1 - padding,
810
+ x2: box.x2 + padding,
811
+ y2: box.y2 + padding,
812
+ };
813
+ }
814
+
815
+ function parseAttrs(tag) {
816
+ const attrs = {};
817
+ for (const match of tag.matchAll(/([\w:-]+)\s*=\s*"([^"]*)"/g)) attrs[match[1]] = match[2];
818
+ return attrs;
819
+ }
820
+
821
+ function numberAttr(attrs, name) {
822
+ return Number.parseFloat(attrs[name]);
823
+ }
824
+
825
+ function isCommand(token) {
826
+ return /^[A-Za-z]$/.test(token);
827
+ }
828
+
829
+ function isPoint(point) {
830
+ return Array.isArray(point) && point.length === 2 && point.every(Number.isFinite);
831
+ }
832
+
833
+ function stripTags(value) {
834
+ return value.replace(/<[^>]*>/g, '');
835
+ }