xonecode 0.3.0 → 0.5.1
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.
- package/README.md +50 -8
- package/THIRD_PARTY_NOTICES.md +160 -0
- package/apps/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/apps/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/apps/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/apps/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/apps/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/apps/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/apps/web/dist/assets/c-BIGW1oBm.js +1 -0
- package/apps/web/dist/assets/cpp-DddhVWhK.js +1 -0
- package/apps/web/dist/assets/csharp-DSvCPggb.js +1 -0
- package/apps/web/dist/assets/css-CLj8gQPS.js +1 -0
- package/apps/web/dist/assets/go-C27-OAKa.js +1 -0
- package/apps/web/dist/assets/html-CfGypltT.js +1 -0
- package/apps/web/dist/assets/index-BB3SamhR.css +1 -0
- package/apps/web/dist/assets/index-CFYAoHdw.js +477 -0
- package/apps/web/dist/assets/ini-BEwlwnbL.js +1 -0
- package/apps/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/apps/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/apps/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/apps/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/apps/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/apps/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/apps/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/apps/web/dist/assets/java-CylS5w8V.js +1 -0
- package/apps/web/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/apps/web/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/apps/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/apps/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/apps/web/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/apps/web/dist/assets/kotlin-BdnUsdx6.js +1 -0
- package/apps/web/dist/assets/less-B1dDrJ26.js +1 -0
- package/apps/web/dist/assets/lua-BaeVxFsk.js +1 -0
- package/apps/web/dist/assets/markdown-Cvjx9yec.js +1 -0
- package/apps/web/dist/assets/mdx-Cmh6b_Ma.js +1 -0
- package/apps/web/dist/assets/php-D_2--9WK.js +1 -0
- package/apps/web/dist/assets/python-B6aJPvgy.js +1 -0
- package/apps/web/dist/assets/ruby-DSHSDbk1.js +1 -0
- package/apps/web/dist/assets/rust-B1yitclQ.js +1 -0
- package/apps/web/dist/assets/scss-D5BDwBP9.js +1 -0
- package/apps/web/dist/assets/sql-CRqJ_cUM.js +1 -0
- package/apps/web/dist/assets/swift-C2oV4EkX.js +1 -0
- package/apps/web/dist/assets/toml-vGWfd6FD.js +1 -0
- package/apps/web/dist/assets/xml-sdJ4AIDG.js +1 -0
- package/apps/web/dist/assets/yaml-Buea-lGh.js +1 -0
- package/apps/web/dist/iconos/xonecode.png +0 -0
- package/apps/web/dist/index.html +20 -0
- package/dist/agent/agentesEnDisco.js +539 -0
- package/dist/agent/agentesEnDisco.js.map +1 -0
- package/dist/agent/arbolDeProyecto.js +245 -0
- package/dist/agent/arbolDeProyecto.js.map +1 -0
- package/dist/agent/artefactosEnDisco.js +139 -0
- package/dist/agent/artefactosEnDisco.js.map +1 -0
- package/dist/agent/aumentador.js +175 -0
- package/dist/agent/aumentador.js.map +1 -0
- package/dist/agent/authEnDisco.js +76 -1
- package/dist/agent/authEnDisco.js.map +1 -1
- package/dist/agent/busquedaRegex.js +92 -0
- package/dist/agent/busquedaRegex.js.map +1 -0
- package/dist/agent/catalogoModelos.js +345 -0
- package/dist/agent/catalogoModelos.js.map +1 -0
- package/dist/agent/checkpointer.js +127 -0
- package/dist/agent/checkpointer.js.map +1 -0
- package/dist/agent/cloudstudioClient.js +194 -0
- package/dist/agent/cloudstudioClient.js.map +1 -0
- package/dist/agent/cloudstudioMcp.js +722 -0
- package/dist/agent/cloudstudioMcp.js.map +1 -0
- package/dist/agent/configEnDisco.js +309 -11
- package/dist/agent/configEnDisco.js.map +1 -1
- package/dist/agent/consumoExterno.js +99 -0
- package/dist/agent/consumoExterno.js.map +1 -0
- package/dist/agent/descarga.js +149 -0
- package/dist/agent/descarga.js.map +1 -0
- package/dist/agent/diagnosticoDeTools.js +51 -0
- package/dist/agent/diagnosticoDeTools.js.map +1 -0
- package/dist/agent/dispositivosEnMaquina.js +596 -0
- package/dist/agent/dispositivosEnMaquina.js.map +1 -0
- package/dist/agent/escrituraDeCodex.js +134 -0
- package/dist/agent/escrituraDeCodex.js.map +1 -0
- package/dist/agent/escrituraDeOpencode.js +80 -0
- package/dist/agent/escrituraDeOpencode.js.map +1 -0
- package/dist/agent/escrituraExterna.js +742 -0
- package/dist/agent/escrituraExterna.js.map +1 -0
- package/dist/agent/gemini.js +81 -0
- package/dist/agent/gemini.js.map +1 -0
- package/dist/agent/git.js +83 -0
- package/dist/agent/git.js.map +1 -0
- package/dist/agent/gitSync.js +441 -0
- package/dist/agent/gitSync.js.map +1 -0
- package/dist/agent/hotswap.js +448 -0
- package/dist/agent/hotswap.js.map +1 -0
- package/dist/agent/instalacionEnMaquina.js +252 -0
- package/dist/agent/instalacionEnMaquina.js.map +1 -0
- package/dist/agent/instantanea.js +7 -10
- package/dist/agent/instantanea.js.map +1 -1
- package/dist/agent/interrupts.js +11 -2
- package/dist/agent/interrupts.js.map +1 -1
- package/dist/agent/juezDeTarea.js +345 -0
- package/dist/agent/juezDeTarea.js.map +1 -0
- package/dist/agent/lanzamientoEnMaquina.js +377 -0
- package/dist/agent/lanzamientoEnMaquina.js.map +1 -0
- package/dist/agent/manifiesto.js +59 -0
- package/dist/agent/manifiesto.js.map +1 -0
- package/dist/agent/memoriaDeProyecto.js +60 -0
- package/dist/agent/memoriaDeProyecto.js.map +1 -0
- package/dist/agent/modelos.js +105 -17
- package/dist/agent/modelos.js.map +1 -1
- package/dist/agent/modelosDeMotor.js +204 -0
- package/dist/agent/modelosDeMotor.js.map +1 -0
- package/dist/agent/paqueteDelProyecto.js +181 -0
- package/dist/agent/paqueteDelProyecto.js.map +1 -0
- package/dist/agent/perfiles.js +92 -31
- package/dist/agent/perfiles.js.map +1 -1
- package/dist/agent/persona.js +40 -0
- package/dist/agent/persona.js.map +1 -0
- package/dist/agent/procesosEnMaquina.js +204 -0
- package/dist/agent/procesosEnMaquina.js.map +1 -0
- package/dist/agent/proyecto.js +311 -13
- package/dist/agent/proyecto.js.map +1 -1
- package/dist/agent/puente.js +63 -6
- package/dist/agent/puente.js.map +1 -1
- package/dist/agent/resumenDeContexto.js +30 -0
- package/dist/agent/resumenDeContexto.js.map +1 -0
- package/dist/agent/resumenDeTool.js +64 -18
- package/dist/agent/resumenDeTool.js.map +1 -1
- package/dist/agent/sesionGit.js +481 -0
- package/dist/agent/sesionGit.js.map +1 -0
- package/dist/agent/settingsEnDisco.js +189 -0
- package/dist/agent/settingsEnDisco.js.map +1 -0
- package/dist/agent/subagenteCodex.js +368 -0
- package/dist/agent/subagenteCodex.js.map +1 -0
- package/dist/agent/subagenteExterno.js +423 -0
- package/dist/agent/subagenteExterno.js.map +1 -0
- package/dist/agent/subagenteOpencode.js +389 -0
- package/dist/agent/subagenteOpencode.js.map +1 -0
- package/dist/agent/subida.js +202 -0
- package/dist/agent/subida.js.map +1 -0
- package/dist/agent/tareasEnDisco.js +466 -0
- package/dist/agent/tareasEnDisco.js.map +1 -0
- package/dist/agent/turnoReal.js +663 -50
- package/dist/agent/turnoReal.js.map +1 -1
- package/dist/agent/versionEnDisco.js +48 -0
- package/dist/agent/versionEnDisco.js.map +1 -0
- package/dist/agent/xoneAgent.js +290 -49
- package/dist/agent/xoneAgent.js.map +1 -1
- package/dist/agent/zip.js +52 -0
- package/dist/agent/zip.js.map +1 -0
- package/dist/cli/acuseDeModelo.js +30 -0
- package/dist/cli/acuseDeModelo.js.map +1 -0
- package/dist/cli/aprobar.js +55 -2
- package/dist/cli/aprobar.js.map +1 -1
- package/dist/cli/config.js +9 -13
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/consola.js +750 -19
- package/dist/cli/consola.js.map +1 -1
- package/dist/cli/main.js +740 -81
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/markdown.js +188 -2
- package/dist/cli/markdown.js.map +1 -1
- package/dist/cli/run.js +32 -4
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/stdio.js +46 -19
- package/dist/cli/stdio.js.map +1 -1
- package/dist/cli/tema.js +96 -8
- package/dist/cli/tema.js.map +1 -1
- package/dist/cli/tokens.js +29 -0
- package/dist/cli/tokens.js.map +1 -0
- package/dist/cli/tui/app.js +171 -0
- package/dist/cli/tui/app.js.map +1 -0
- package/dist/cli/tui/aprobarTui.js +80 -0
- package/dist/cli/tui/aprobarTui.js.map +1 -0
- package/dist/cli/tui/barra.js +37 -0
- package/dist/cli/tui/barra.js.map +1 -0
- package/dist/cli/tui/correrTui.js +478 -0
- package/dist/cli/tui/correrTui.js.map +1 -0
- package/dist/cli/tui/entrada.js +166 -0
- package/dist/cli/tui/entrada.js.map +1 -0
- package/dist/cli/tui/filas.js +24 -0
- package/dist/cli/tui/filas.js.map +1 -0
- package/dist/cli/tui/logo.js +49 -0
- package/dist/cli/tui/logo.js.map +1 -0
- package/dist/cli/tui/pielTui.js +14 -0
- package/dist/cli/tui/pielTui.js.map +1 -0
- package/dist/cli/tui/raton.js +126 -0
- package/dist/cli/tui/raton.js.map +1 -0
- package/dist/cli/tui/sidebar.js +86 -0
- package/dist/cli/tui/sidebar.js.map +1 -0
- package/dist/cli/tui/store.js +143 -0
- package/dist/cli/tui/store.js.map +1 -0
- package/dist/cli/tui/tarjeta.js +19 -0
- package/dist/cli/tui/tarjeta.js.map +1 -0
- package/dist/cli/tui/temaInk.js +114 -0
- package/dist/cli/tui/temaInk.js.map +1 -0
- package/dist/cli/tui/transcript.js +254 -0
- package/dist/cli/tui/transcript.js.map +1 -0
- package/dist/cli/wizardInicial.js +240 -0
- package/dist/cli/wizardInicial.js.map +1 -0
- package/dist/core/actos.js +113 -0
- package/dist/core/actos.js.map +1 -0
- package/dist/core/adjuntos.js +97 -0
- package/dist/core/adjuntos.js.map +1 -0
- package/dist/core/agentes.js +227 -0
- package/dist/core/agentes.js.map +1 -0
- package/dist/core/artefactos.js +149 -0
- package/dist/core/artefactos.js.map +1 -0
- package/dist/core/cloudstudio.js +7 -0
- package/dist/core/cloudstudio.js.map +1 -0
- package/dist/core/config.js +212 -5
- package/dist/core/config.js.map +1 -1
- package/dist/core/contextos.js +53 -1
- package/dist/core/contextos.js.map +1 -1
- package/dist/core/descargas.js +106 -0
- package/dist/core/descargas.js.map +1 -0
- package/dist/core/descriptoresDeApp.js +279 -0
- package/dist/core/descriptoresDeApp.js.map +1 -0
- package/dist/core/dispositivos.js +466 -0
- package/dist/core/dispositivos.js.map +1 -0
- package/dist/core/entrega.js +141 -0
- package/dist/core/entrega.js.map +1 -0
- package/dist/core/entrelazar.js +90 -0
- package/dist/core/entrelazar.js.map +1 -0
- package/dist/core/esqueleto.js +10 -0
- package/dist/core/esqueleto.js.map +1 -1
- package/dist/core/modelos.js +235 -3
- package/dist/core/modelos.js.map +1 -1
- package/dist/core/notify.js +27 -9
- package/dist/core/notify.js.map +1 -1
- package/dist/core/planDeSubida.js +127 -0
- package/dist/core/planDeSubida.js.map +1 -0
- package/dist/core/ports.js +189 -1
- package/dist/core/ports.js.map +1 -1
- package/dist/core/puedeLanzarse.js +239 -0
- package/dist/core/puedeLanzarse.js.map +1 -0
- package/dist/core/rutaVirtual.js +42 -0
- package/dist/core/rutaVirtual.js.map +1 -0
- package/dist/core/settings.js +246 -0
- package/dist/core/settings.js.map +1 -0
- package/dist/core/tareas.js +230 -0
- package/dist/core/tareas.js.map +1 -0
- package/dist/core/textos.js +36 -0
- package/dist/core/textos.js.map +1 -0
- package/dist/core/turno.js +56 -8
- package/dist/core/turno.js.map +1 -1
- package/dist/core/version.js +31 -0
- package/dist/core/version.js.map +1 -0
- package/dist/vendor/sqliteSaver.js +389 -0
- package/dist/vendor/sqliteSaver.js.map +1 -0
- package/dist/vendor/tokenTracking.js +22 -1
- package/dist/vendor/tokenTracking.js.map +1 -1
- package/dist/web/servidor/arranque.js +3964 -0
- package/dist/web/servidor/arranque.js.map +1 -0
- package/dist/web/servidor/consolaDeTarea.js +161 -0
- package/dist/web/servidor/consolaDeTarea.js.map +1 -0
- package/dist/web/servidor/consolaWeb.js +389 -0
- package/dist/web/servidor/consolaWeb.js.map +1 -0
- package/dist/web/servidor/corredorDeTareas.js +1119 -0
- package/dist/web/servidor/corredorDeTareas.js.map +1 -0
- package/dist/web/servidor/pielWeb.js +269 -0
- package/dist/web/servidor/pielWeb.js.map +1 -0
- package/dist/web/servidor/servidor.js +257 -0
- package/dist/web/servidor/servidor.js.map +1 -0
- package/dist/web/servidor/sesiones.js +440 -0
- package/dist/web/servidor/sesiones.js.map +1 -0
- package/dist/web/servidor/transporte.js +169 -0
- package/dist/web/servidor/transporte.js.map +1 -0
- package/dist/web/servidor/vestibulo.js +1276 -0
- package/dist/web/servidor/vestibulo.js.map +1 -0
- package/package.json +33 -9
- package/skills/archify/LICENSE +22 -0
- package/skills/archify/SKILL.md +109 -0
- package/skills/archify/THIRD_PARTY_NOTICES.md +56 -0
- package/skills/archify/assets/template.html +14787 -0
- package/skills/archify/bin/archify.mjs +1990 -0
- package/skills/archify/bin/open-artifact.mjs +86 -0
- package/skills/archify/bin/preview.mjs +648 -0
- package/skills/archify/bin/visual-check.mjs +829 -0
- package/skills/archify/brand-marks/README.md +31 -0
- package/skills/archify/brand-marks/catalog.json +131 -0
- package/skills/archify/delta/architecture-delta.mjs +1214 -0
- package/skills/archify/examples/agent-run.lifecycle.json +71 -0
- package/skills/archify/examples/agent-tool-call.workflow.json +94 -0
- package/skills/archify/examples/async-job-roundtrip.sequence.json +61 -0
- package/skills/archify/examples/brand-aware-delivery.architecture.json +47 -0
- package/skills/archify/examples/cache-miss-request.sequence.json +81 -0
- package/skills/archify/examples/checkout-platform.base.architecture.json +31 -0
- package/skills/archify/examples/checkout-platform.head.architecture.json +31 -0
- package/skills/archify/examples/dataflow-product-analytics.html +14898 -0
- package/skills/archify/examples/deployment-release.lifecycle.json +49 -0
- package/skills/archify/examples/event-stream.dataflow.json +57 -0
- package/skills/archify/examples/incident-response.workflow.json +64 -0
- package/skills/archify/examples/lifecycle-agent-run.html +14847 -0
- package/skills/archify/examples/product-analytics.dataflow.json +76 -0
- package/skills/archify/examples/production-deployment.architecture.json +71 -0
- package/skills/archify/examples/release-delivery.workflow.json +62 -0
- package/skills/archify/examples/sequence-cache-miss-request.html +14913 -0
- package/skills/archify/examples/web-app-rendered.html +14862 -0
- package/skills/archify/examples/web-app.architecture.json +46 -0
- package/skills/archify/examples/workflow-agent-tool-call-rendered.html +14904 -0
- package/skills/archify/migrations/workflow-v2.mjs +279 -0
- package/skills/archify/package.json +17 -0
- package/skills/archify/recipes/scenarios.mjs +391 -0
- package/skills/archify/references/authoring-contract.md +198 -0
- package/skills/archify/references/brand-marks.md +69 -0
- package/skills/archify/references/delivery-contract.md +116 -0
- package/skills/archify/references/viewer-runtime.md +45 -0
- package/skills/archify/renderers/architecture/grid.mjs +62 -0
- package/skills/archify/renderers/architecture/render-architecture.mjs +1078 -0
- package/skills/archify/renderers/dataflow/README.md +104 -0
- package/skills/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- package/skills/archify/renderers/lifecycle/README.md +115 -0
- package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- package/skills/archify/renderers/sequence/README.md +114 -0
- package/skills/archify/renderers/sequence/render-sequence.mjs +453 -0
- package/skills/archify/renderers/shared/brand-marks.mjs +563 -0
- package/skills/archify/renderers/shared/cli.mjs +218 -0
- package/skills/archify/renderers/shared/desktop-readability.mjs +26 -0
- package/skills/archify/renderers/shared/diagnostics.mjs +127 -0
- package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
- package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
- package/skills/archify/renderers/shared/generated-validators.mjs +13 -0
- package/skills/archify/renderers/shared/geometry.mjs +1423 -0
- package/skills/archify/renderers/shared/i18n.mjs +594 -0
- package/skills/archify/renderers/shared/layout-report.mjs +40 -0
- package/skills/archify/renderers/shared/legend.mjs +217 -0
- package/skills/archify/renderers/shared/output-path.mjs +321 -0
- package/skills/archify/renderers/shared/repository-evidence.mjs +235 -0
- package/skills/archify/renderers/shared/text-fit.mjs +49 -0
- package/skills/archify/renderers/shared/utils.mjs +232 -0
- package/skills/archify/renderers/shared/validator.mjs +86 -0
- package/skills/archify/renderers/workflow/README.md +223 -0
- package/skills/archify/renderers/workflow/render-workflow.mjs +35 -0
- package/skills/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- package/skills/archify/schemas/README.md +211 -0
- package/skills/archify/schemas/architecture.schema.json +176 -0
- package/skills/archify/schemas/common.schema.json +115 -0
- package/skills/archify/schemas/dataflow.schema.json +243 -0
- package/skills/archify/schemas/lifecycle.schema.json +266 -0
- package/skills/archify/schemas/sequence.schema.json +223 -0
- package/skills/archify/schemas/workflow.schema.json +428 -0
- package/skills/archify/scripts/check-render-output.mjs +835 -0
- package/skills/archify/scripts/check-update.mjs +1667 -0
- package/skills/archify/scripts/render-examples.mjs +26 -0
- package/skills/archify/scripts/update-contract.mjs +182 -0
- package/skills/archify/skill-release.json +10 -0
- package/skills/artifacts-builder/SKILL.md +120 -0
- package/skills/artifacts-builder/reference/diagramas.md +123 -0
- package/skills/artifacts-builder/reference/estilo.md +123 -0
- package/skills/artifacts-builder/reference/exportar-pdf.md +56 -0
- package/skills/artifacts-builder/reference/graficas.md +22 -0
- package/skills/artifacts-builder/scripts/bundle_artifact.py +109 -0
- package/skills/artifacts-builder/scripts/validate_artifact.py +345 -0
- package/skills/xone-hotswap/SKILL.md +185 -0
- package/skills/xone-hotswap/references/comandos.md +706 -0
- 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
|
+
});
|