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.
- package/README.md +49 -7
- package/THIRD_PARTY_NOTICES.md +128 -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/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 +30 -8
- 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,26 @@
|
|
|
1
|
+
// Re-render every bundled example from its JSON IR. Installed skills keep HTML
|
|
2
|
+
// beside the JSON examples; the development script passes the golden directory.
|
|
3
|
+
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const skillRoot = path.resolve(__dirname, '..');
|
|
10
|
+
const outputRoot = path.resolve(process.argv[2] || path.join(skillRoot, 'examples'));
|
|
11
|
+
|
|
12
|
+
const TARGETS = [
|
|
13
|
+
['workflow', 'agent-tool-call.workflow.json', 'workflow-agent-tool-call-rendered.html'],
|
|
14
|
+
['sequence', 'cache-miss-request.sequence.json', 'sequence-cache-miss-request.html'],
|
|
15
|
+
['dataflow', 'product-analytics.dataflow.json', 'dataflow-product-analytics.html'],
|
|
16
|
+
['lifecycle', 'agent-run.lifecycle.json', 'lifecycle-agent-run.html'],
|
|
17
|
+
['architecture', 'web-app.architecture.json', 'web-app-rendered.html'],
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
for (const [mode, input, output] of TARGETS) {
|
|
21
|
+
execFileSync(process.execPath, [
|
|
22
|
+
path.join(skillRoot, `renderers/${mode}/render-${mode}.mjs`),
|
|
23
|
+
path.join(skillRoot, 'examples', input),
|
|
24
|
+
path.join(outputRoot, output),
|
|
25
|
+
], { stdio: 'inherit' });
|
|
26
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
export const SKILL_ID = 'archify';
|
|
2
|
+
export const EXPECTED_REPOSITORY = 'https://github.com/tt-a1i/archify';
|
|
3
|
+
export const DEFAULT_MANIFEST_URL = 'https://tt-a1i.github.io/archify/skill-updates/archify/stable.json';
|
|
4
|
+
|
|
5
|
+
const CONTROL_OR_BIDI = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/u;
|
|
6
|
+
const HEX_40 = /^[a-f0-9]{40}$/;
|
|
7
|
+
const HEX_64 = /^[a-f0-9]{64}$/;
|
|
8
|
+
const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
9
|
+
const UTC_SECONDS = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
|
|
10
|
+
|
|
11
|
+
export class UpdateContractError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'UpdateContractError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isPlainObject(value) {
|
|
19
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function hasExactKeys(value, expected) {
|
|
23
|
+
return isPlainObject(value)
|
|
24
|
+
&& Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function parseSemver(value) {
|
|
28
|
+
if (typeof value !== 'string' || value.length > 128) {
|
|
29
|
+
throw new UpdateContractError(`invalid SemVer: ${JSON.stringify(value)}`);
|
|
30
|
+
}
|
|
31
|
+
const match = SEMVER.exec(value);
|
|
32
|
+
if (!match) throw new UpdateContractError(`invalid SemVer: ${JSON.stringify(value)}`);
|
|
33
|
+
const prerelease = match[4]?.split('.') ?? null;
|
|
34
|
+
if (prerelease?.some((identifier) => /^\d+$/.test(identifier)
|
|
35
|
+
&& identifier.length > 1 && identifier.startsWith('0'))) {
|
|
36
|
+
throw new UpdateContractError(`invalid SemVer: ${JSON.stringify(value)}`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
core: match.slice(1, 4),
|
|
40
|
+
prerelease,
|
|
41
|
+
build: match[5]?.split('.') ?? null,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function compareNumericIdentifiers(left, right) {
|
|
46
|
+
if (left.length !== right.length) return left.length < right.length ? -1 : 1;
|
|
47
|
+
if (left === right) return 0;
|
|
48
|
+
return left < right ? -1 : 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function comparePrerelease(left, right) {
|
|
52
|
+
if (left === null && right === null) return 0;
|
|
53
|
+
if (left === null) return 1;
|
|
54
|
+
if (right === null) return -1;
|
|
55
|
+
const length = Math.max(left.length, right.length);
|
|
56
|
+
for (let index = 0; index < length; index += 1) {
|
|
57
|
+
if (left[index] === undefined) return -1;
|
|
58
|
+
if (right[index] === undefined) return 1;
|
|
59
|
+
if (left[index] === right[index]) continue;
|
|
60
|
+
const leftNumeric = /^\d+$/.test(left[index]);
|
|
61
|
+
const rightNumeric = /^\d+$/.test(right[index]);
|
|
62
|
+
if (leftNumeric && rightNumeric) return compareNumericIdentifiers(left[index], right[index]);
|
|
63
|
+
if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
|
|
64
|
+
return left[index] < right[index] ? -1 : 1;
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function compareSemver(leftValue, rightValue) {
|
|
70
|
+
const left = parseSemver(leftValue);
|
|
71
|
+
const right = parseSemver(rightValue);
|
|
72
|
+
for (let index = 0; index < left.core.length; index += 1) {
|
|
73
|
+
const comparison = compareNumericIdentifiers(left.core[index], right.core[index]);
|
|
74
|
+
if (comparison !== 0) return comparison;
|
|
75
|
+
}
|
|
76
|
+
return comparePrerelease(left.prerelease, right.prerelease);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function releaseChannelForVersion(value) {
|
|
80
|
+
return parseSemver(value).prerelease ? 'development' : 'stable';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isStableCoreVersion(value) {
|
|
84
|
+
try {
|
|
85
|
+
const parsed = parseSemver(value);
|
|
86
|
+
return parsed.prerelease === null && parsed.build === null;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function validateCanonicalUtcTimestamp(value) {
|
|
93
|
+
if (typeof value !== 'string' || !UTC_SECONDS.test(value)) {
|
|
94
|
+
throw new UpdateContractError('publication time must use YYYY-MM-DDTHH:mm:ssZ');
|
|
95
|
+
}
|
|
96
|
+
const timestamp = Date.parse(value);
|
|
97
|
+
if (!Number.isFinite(timestamp)
|
|
98
|
+
|| new Date(timestamp).toISOString().replace('.000Z', 'Z') !== value) {
|
|
99
|
+
throw new UpdateContractError('publication time is not a real UTC calendar instant');
|
|
100
|
+
}
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function validateLocalRelease(value) {
|
|
105
|
+
if (!hasExactKeys(value, [
|
|
106
|
+
'schemaVersion', 'skillId', 'channel', 'version', 'source', 'updateManifestUrl',
|
|
107
|
+
])
|
|
108
|
+
|| value.schemaVersion !== 1
|
|
109
|
+
|| value.skillId !== SKILL_ID
|
|
110
|
+
|| !hasExactKeys(value.source, ['repository'])
|
|
111
|
+
|| value.source.repository !== EXPECTED_REPOSITORY
|
|
112
|
+
|| value.updateManifestUrl !== DEFAULT_MANIFEST_URL) {
|
|
113
|
+
throw new UpdateContractError('invalid local release identity');
|
|
114
|
+
}
|
|
115
|
+
const expectedChannel = releaseChannelForVersion(value.version);
|
|
116
|
+
if (value.channel !== expectedChannel) {
|
|
117
|
+
throw new UpdateContractError('local release channel does not match its version');
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
schemaVersion: value.schemaVersion,
|
|
121
|
+
skillId: value.skillId,
|
|
122
|
+
channel: value.channel,
|
|
123
|
+
version: value.version,
|
|
124
|
+
source: { repository: value.source.repository },
|
|
125
|
+
updateManifestUrl: value.updateManifestUrl,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function validateReleaseNotesUrl(value, version) {
|
|
130
|
+
if (!isStableCoreVersion(version)) {
|
|
131
|
+
throw new UpdateContractError('release notes require a stable core version');
|
|
132
|
+
}
|
|
133
|
+
const expected = `https://github.com/tt-a1i/archify/releases/tag/v${version}`;
|
|
134
|
+
if (value !== expected) {
|
|
135
|
+
throw new UpdateContractError('release notes URL is outside the exact trusted release path');
|
|
136
|
+
}
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function validateStableUpdateManifest(value) {
|
|
141
|
+
if (!hasExactKeys(value, [
|
|
142
|
+
'schemaVersion', 'skillId', 'channel', 'version', 'publishedAt', 'source',
|
|
143
|
+
'artifact', 'summary', 'releaseNotes', 'severity',
|
|
144
|
+
])
|
|
145
|
+
|| value.schemaVersion !== 1
|
|
146
|
+
|| value.skillId !== SKILL_ID
|
|
147
|
+
|| value.channel !== 'stable'
|
|
148
|
+
|| !isStableCoreVersion(value.version)
|
|
149
|
+
|| !hasExactKeys(value.source, ['repository', 'ref', 'treeSha'])
|
|
150
|
+
|| value.source.repository !== EXPECTED_REPOSITORY
|
|
151
|
+
|| value.source.ref !== `v${value.version}`
|
|
152
|
+
|| !HEX_40.test(value.source.treeSha)
|
|
153
|
+
|| !hasExactKeys(value.artifact, ['sha256'])
|
|
154
|
+
|| !HEX_64.test(value.artifact.sha256)) {
|
|
155
|
+
throw new UpdateContractError('invalid immutable stable release identity');
|
|
156
|
+
}
|
|
157
|
+
validateCanonicalUtcTimestamp(value.publishedAt);
|
|
158
|
+
if (typeof value.summary !== 'string' || value.summary.length < 1 || value.summary.length > 160
|
|
159
|
+
|| CONTROL_OR_BIDI.test(value.summary)) {
|
|
160
|
+
throw new UpdateContractError('invalid release summary');
|
|
161
|
+
}
|
|
162
|
+
validateReleaseNotesUrl(value.releaseNotes, value.version);
|
|
163
|
+
if (!['normal', 'security'].includes(value.severity)) {
|
|
164
|
+
throw new UpdateContractError('invalid update severity');
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
schemaVersion: value.schemaVersion,
|
|
168
|
+
skillId: value.skillId,
|
|
169
|
+
channel: value.channel,
|
|
170
|
+
version: value.version,
|
|
171
|
+
publishedAt: value.publishedAt,
|
|
172
|
+
source: {
|
|
173
|
+
repository: value.source.repository,
|
|
174
|
+
ref: value.source.ref,
|
|
175
|
+
treeSha: value.source.treeSha,
|
|
176
|
+
},
|
|
177
|
+
artifact: { sha256: value.artifact.sha256 },
|
|
178
|
+
summary: value.summary,
|
|
179
|
+
releaseNotes: value.releaseNotes,
|
|
180
|
+
severity: value.severity,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"skillId": "archify",
|
|
4
|
+
"channel": "development",
|
|
5
|
+
"version": "2.17.0-dev.1",
|
|
6
|
+
"source": {
|
|
7
|
+
"repository": "https://github.com/tt-a1i/archify"
|
|
8
|
+
},
|
|
9
|
+
"updateManifestUrl": "https://tt-a1i.github.io/archify/skill-updates/archify/stable.json"
|
|
10
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: artifacts-builder
|
|
3
|
+
description: "Build a self-contained interactive HTML artifact the user can view in the chat: dashboards, interactive charts, flow diagrams, filterable tables, printable reports. Use when a plain text answer would lose information that a visual or interactive piece would keep."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Artifacts Builder
|
|
7
|
+
|
|
8
|
+
You write ONE self-contained HTML file. No build step, no npm, no `execute` anywhere this
|
|
9
|
+
skill is mounted — nothing here runs a script.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. **Pick a character and paste the tokens** — `reference/estilo.md`, one table row, whole.
|
|
14
|
+
This is a STEP and not optional reading, and the reason is measured: while it lived under
|
|
15
|
+
"read when you need it" the builder **never opened it**, and every panel came out the same —
|
|
16
|
+
Inter, indigo accent, four different corner radii and zero CSS variables. Five tokens
|
|
17
|
+
(`--surface --surface-2 --ink --ink-muted --border --accent --radius`) and one row of the
|
|
18
|
+
character table are the whole decision; the file is 86 lines and it is the short one.
|
|
19
|
+
2. **Write** the HTML with `write_file` **en `/artefactos/<nombre>.html`** — nunca en la raíz
|
|
20
|
+
del proyecto. Esa carpeta no es del proyecto: no pasa por la aprobación humana, no entra
|
|
21
|
+
en git y no sube a CloudStudio. Un HTML escrito fuera de ella acaba DENTRO de la app XOne
|
|
22
|
+
del usuario, que no es lo que nadie pidió. Keep it ONE file: with no `execute` tool
|
|
23
|
+
anywhere here, there is no bundler to run. Inline local assets (fonts, images) as `data:`
|
|
24
|
+
URIs directly in the file you write, instead of splitting it and planning to combine the
|
|
25
|
+
pieces later.
|
|
26
|
+
3. **Entrega, según la tool que TENGAS:**
|
|
27
|
+
- **Si tienes `publish_artifact`** (el panel): `publish_artifact(path="/artifact.html",
|
|
28
|
+
title="…")`. Valida al publicar contra el contrato de abajo. Si lo rechaza, te dice
|
|
29
|
+
exactamente qué arreglar; corrige y reintenta. Para actualizar uno que ya publicaste,
|
|
30
|
+
pasa su `artifact_id` — el enlace del usuario no cambia.
|
|
31
|
+
- **Si tienes `renderizar_diagrama` en vez de `publish_artifact`** (el camino de
|
|
32
|
+
`documentar`): si lo que construiste es un DIAGRAMA (arquitectura, flujo, secuencia,
|
|
33
|
+
dataflow, lifecycle), no sigas este camino — usa la skill `archify` y llama a
|
|
34
|
+
`renderizar_diagrama(tipo, spec_json, ruta)`, que valida y coloca el fichero por ti.
|
|
35
|
+
Para cualquier OTRO artefacto (tabla, dashboard, gráfica que no es un diagrama de
|
|
36
|
+
archify), ya tienes `write_file`: escríbelo en `/artefactos/` — el contrato de abajo NO
|
|
37
|
+
aplica en este camino, es del sandbox del panel (ver su nota).
|
|
38
|
+
- **Si no tienes NINGUNA de las dos** (xonecode): `write_file` en
|
|
39
|
+
`/artefactos/<nombre>.html` y ya está. No inventes ninguna de las dos tools, y no
|
|
40
|
+
anuncies capacidades del panel —sandbox, enlace compartible, actualización por
|
|
41
|
+
`artifact_id`— que en este camino no existen. La entrega ES la escritura: la consola
|
|
42
|
+
anuncia el artefacto sola.
|
|
43
|
+
**Cuando la entrega confirme, HAS TERMINADO** — no reescribas el mismo artefacto otra vez.
|
|
44
|
+
|
|
45
|
+
## The contract — non-negotiable — solo si tienes `publish_artifact`
|
|
46
|
+
|
|
47
|
+
El artefacto corre en un sandbox cerrado. Esto lo hace cumplir el SERVIDOR de `publish_artifact`,
|
|
48
|
+
no la confianza — y por eso solo es cierto en este camino, no en el de `write_file`:
|
|
49
|
+
|
|
50
|
+
- **No network.** No `fetch`, `XMLHttpRequest`, `WebSocket`, `EventSource`, `sendBeacon`,
|
|
51
|
+
dynamic `import()`. Bake the data into the HTML as a JS constant.
|
|
52
|
+
- **Libraries only from** `https://cdnjs.cloudflare.com` or `https://cdn.jsdelivr.net`
|
|
53
|
+
(fonts: `fonts.googleapis.com` + `fonts.gstatic.com`). Pin an exact version.
|
|
54
|
+
- **Images**: `data:` URIs only. An external `<img src>` leaks data through its query string.
|
|
55
|
+
- **No** `<base>`, no external `<iframe>`, no external `<form action>`.
|
|
56
|
+
- **5 MB max.**
|
|
57
|
+
- **`localStorage` THROWS. Wrap every access in `try/catch` — or don't use it.** The widget
|
|
58
|
+
renders the artifact in an iframe with `sandbox="allow-scripts allow-downloads allow-modals"`
|
|
59
|
+
and **no `allow-same-origin`**, so the document has an opaque origin and merely *reading*
|
|
60
|
+
`localStorage` raises:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Failed to read the 'localStorage' property from 'Window':
|
|
64
|
+
The document is sandboxed and lacks the 'allow-same-origin' flag.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This is measured, not theoretical, and it is the **most expensive mistake in this list**
|
|
68
|
+
because it fails SILENTLY. A real panel died on `'theme' in localStorage` before
|
|
69
|
+
`mermaid.initialize(…)` ever ran, and the page looked perfect while the diagram stayed an
|
|
70
|
+
empty rectangle. `matchMedia('(prefers-color-scheme: dark)')` needs no storage for the theme;
|
|
71
|
+
if you really want to remember something per viewer, wrap it: `try { localStorage.setItem(k,
|
|
72
|
+
v) } catch {}`.
|
|
73
|
+
|
|
74
|
+
## El contrato del OTRO camino, `write_file` en `/artefactos/` (xonecode)
|
|
75
|
+
|
|
76
|
+
Este párrafo decía que sin `publish_artifact` no había sandbox: «el fichero queda tal cual en el
|
|
77
|
+
proyecto del cliente, sin iframe, sin lista blanca de CDN, `localStorage` no lanza ahí». **Es
|
|
78
|
+
falso desde que la consola los ABRE**, y era el error más caro que se podía dejar escrito: quien
|
|
79
|
+
lo leyera usaría `localStorage` y el diagrama moriría en silencio.
|
|
80
|
+
|
|
81
|
+
Aquí el sandbox lo impone el VISOR de la consola, no un servidor de publicación — y lo impone
|
|
82
|
+
igual. Medido en el navegador (2026-09-07) sobre un artefacto real, con el iframe en
|
|
83
|
+
`sandbox="allow-scripts"` y **sin** `allow-same-origin`:
|
|
84
|
+
|
|
85
|
+
- **`localStorage`, `sessionStorage` e `indexedDB` LANZAN `SecurityError`.** Los tres, no solo el
|
|
86
|
+
primero. Vale entera la advertencia de arriba, incluido por qué es el error más caro de la
|
|
87
|
+
lista: falla EN SILENCIO, con la página perfecta y el diagrama sin dibujar.
|
|
88
|
+
- **Las CDNs SÍ funcionan, con conexión.** `cdnjs.cloudflare.com` y `fonts.googleapis.com` /
|
|
89
|
+
`fonts.gstatic.com` contestaron 200 desde dentro del iframe. No hay lista blanca que cumplir
|
|
90
|
+
ni tope de 5 MB (el visor sirve hasta 20 MB) ni validador que rechace nada: lo que escribas es
|
|
91
|
+
lo que se verá. Usa esas dos CDNs igualmente.
|
|
92
|
+
- **Al ORIGEN de la consola no se llega.** Un `fetch` a cualquier ruta suya muere en el propio
|
|
93
|
+
navegador («from origin 'null' has been blocked by CORS»), así que sus tipografías
|
|
94
|
+
empaquetadas y sus rutas no están a tu alcance: da igual que estén ahí al lado.
|
|
95
|
+
- **Nada bloquea una petición a un tercero**, y justo por eso: no hagas ninguna que no
|
|
96
|
+
necesites. Hornea los datos dentro del HTML, como en el otro camino — un proyecto XOne puede
|
|
97
|
+
abrirse offline, y una petición saliente se lleva consigo lo que lleve en la URL.
|
|
98
|
+
|
|
99
|
+
## What you can use
|
|
100
|
+
|
|
101
|
+
React 18 (UMD), Tailwind, any chart library, mermaid, via CDN `<script>` tags — no bundler,
|
|
102
|
+
either path. **Con `publish_artifact`**, solo pasan `cdnjs.cloudflare.com` y `cdn.jsdelivr.net`
|
|
103
|
+
(`https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4`, NUNCA `cdn.tailwindcss.com`: no está en
|
|
104
|
+
la lista blanca). **Con `write_file`**, no hay lista blanca que cumplir — igual, usa esas dos
|
|
105
|
+
CDNs por defecto salvo que el proyecto ya traiga otra cosa.
|
|
106
|
+
|
|
107
|
+
## Read when you need it
|
|
108
|
+
|
|
109
|
+
- `reference/graficas.md` — interactive charts
|
|
110
|
+
- `reference/diagramas.md` — flow diagrams with mermaid
|
|
111
|
+
- `reference/exportar-pdf.md` — a working PDF export button
|
|
112
|
+
- `reference/estilo.md` — **el sistema visual (paso 1, no opcional)**: tokens, carácter, escala
|
|
113
|
+
|
|
114
|
+
## Rules of thumb
|
|
115
|
+
|
|
116
|
+
- Support dark and light: don't hardcode one color scheme.
|
|
117
|
+
- One page, one job. If it needs two unrelated screens, that's two artifacts (or two files).
|
|
118
|
+
- Bake enough data to be useful, not the whole dataset. Con `publish_artifact` el tope de 5 MB
|
|
119
|
+
lo impone el servidor; con `write_file` no hay tope impuesto, pero un fichero de datos entero
|
|
120
|
+
sigue siendo mala idea igual.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Diagramas de flujo
|
|
2
|
+
|
|
3
|
+
## Antes de escribir HTML: `archify` decide el diagrama
|
|
4
|
+
|
|
5
|
+
Si la petición es **solo** un diagrama, esquema, arquitectura, flujo, secuencia, data-flow o
|
|
6
|
+
ciclo de estados, **no uses esta skill**: carga únicamente **`archify`**. Es quien decide el
|
|
7
|
+
tipo de diagrama, qué evidencia del proyecto es relevante y cómo conservar nombres reales.
|
|
8
|
+
|
|
9
|
+
`artifacts-builder` participa únicamente cuando el usuario pide además un contenedor HTML
|
|
10
|
+
interactivo, dashboard, informe o tabla. En ese caso, espera a que `archify` haya decidido el
|
|
11
|
+
diagrama, crea su SVG y **lo incrusta inline** en el único HTML de este artefacto.
|
|
12
|
+
|
|
13
|
+
- La salida se guarda en `/artefactos/<nombre>.html`, nunca en la raíz del proyecto —de ahí
|
|
14
|
+
acabaría dentro de la app XOne del usuario, en git y en CloudStudio— ni en `/skills`, donde
|
|
15
|
+
viven solo instrucciones y recursos del harness.
|
|
16
|
+
- No inventes `renderizar_diagrama`, `publish_artifact` ni una ejecución de scripts si esas
|
|
17
|
+
herramientas no figuran en tu contexto. Con `write_file`, entrega el HTML autocontenido.
|
|
18
|
+
- Usa Mermaid únicamente cuando el usuario lo pida expresamente o cuando un SVG manual no aporte
|
|
19
|
+
claridad. Para el resto, `archify` es la fuente de decisión visual y semántica.
|
|
20
|
+
- Si el resultado combina análisis del proyecto y un diagrama, primero confirma los hechos con
|
|
21
|
+
el código; no dibujes componentes, rutas ni estados que no estén comprobados.
|
|
22
|
+
|
|
23
|
+
## Mermaid, solo cuando procede
|
|
24
|
+
|
|
25
|
+
Mermaid desde cdnjs. Sin red: el diagrama es texto dentro de la página. **Éste es el montaje
|
|
26
|
+
canónico** — copia el bloque entero, no la mitad:
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.0/mermaid.min.js"></script>
|
|
30
|
+
<pre class="mermaid">
|
|
31
|
+
flowchart LR
|
|
32
|
+
Login["LoginRest (login-coll)"] --> Entry["VisitasClientes_v2 (entry-point)"]
|
|
33
|
+
Entry --> Q{"¿Cliente nuevo?"}
|
|
34
|
+
Q -->|"Sí"| Alta["Clientes.xne"]
|
|
35
|
+
Q -->|"No"| DB[("gestion.db")]
|
|
36
|
+
</pre>
|
|
37
|
+
<style>
|
|
38
|
+
.mermaid { width: 100%; overflow-x: auto; }
|
|
39
|
+
.mermaid svg { width: 100%; height: auto; max-width: none; }
|
|
40
|
+
</style>
|
|
41
|
+
<script>
|
|
42
|
+
mermaid.initialize({
|
|
43
|
+
startOnLoad: true,
|
|
44
|
+
theme: "base", // el ÚNICO que acepta themeVariables
|
|
45
|
+
themeVariables: {
|
|
46
|
+
primaryColor: "#ffffff", // relleno del nodo → --surface
|
|
47
|
+
primaryTextColor: "#151a21", // texto del nodo → --ink
|
|
48
|
+
primaryBorderColor: "#d7dee6", // borde → --rule
|
|
49
|
+
lineColor: "#4e5a68", // flechas → --ink-soft
|
|
50
|
+
secondaryColor: "#eef2f6", // fondo de subgrafos → --surface-2
|
|
51
|
+
tertiaryColor: "#d9edf4", // lo acentuado → --accent-soft
|
|
52
|
+
fontFamily: "'IBM Plex Serif', Georgia, serif",
|
|
53
|
+
fontSize: "15px",
|
|
54
|
+
},
|
|
55
|
+
flowchart: { curve: "basis", nodeSpacing: 40, rankSpacing: 55, padding: 12 },
|
|
56
|
+
});
|
|
57
|
+
</script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Por qué ese bloque y no el de por omisión
|
|
61
|
+
|
|
62
|
+
Los defectos de mermaid pintan **nodos amarillo pastel con borde marrón, en escuadra y
|
|
63
|
+
apelotonados**: el diagrama parece de otro producto que el panel que lo rodea. Comprobado en un
|
|
64
|
+
navegador con 10.9.0, con el bloque de arriba el relleno del nodo sale `#ffffff`, el borde
|
|
65
|
+
`#d7dee6` y las flechas `#4e5a68` — o sea **los mismos tokens que el panel** (`estilo.md`).
|
|
66
|
+
|
|
67
|
+
- **`theme: "base"`**: con `default`, `dark` o `neutral`, `themeVariables` **se ignora**.
|
|
68
|
+
- **`curve: "basis"`**: aristas curvas en vez de en escuadra. El cambio de una línea que más
|
|
69
|
+
aire da.
|
|
70
|
+
- **`nodeSpacing`/`rankSpacing`**: los defectos (15/50) aprietan; 40/55 respira.
|
|
71
|
+
- **Los colores van A MANO, no como `var(--x)`**: mermaid los escribe dentro del SVG y no
|
|
72
|
+
resuelve variables CSS. Con tema oscuro, pásale el juego oscuro cuando
|
|
73
|
+
`matchMedia('(prefers-color-scheme: dark)').matches`.
|
|
74
|
+
- **Las dos líneas del `<style>`**: `overflow-x` en el BLOQUE (la página no debe scrollear en
|
|
75
|
+
horizontal) y `max-width: none` en el SVG, porque mermaid le escribe su tamaño natural y sin
|
|
76
|
+
eso se queda pequeño y centrado en un panel ancho.
|
|
77
|
+
|
|
78
|
+
## LO PRIMERO: toda etiqueta con `(` va ENTRE COMILLAS
|
|
79
|
+
|
|
80
|
+
Un paréntesis sin comillas es un error de SINTAXIS y **se lleva el diagrama entero**: la página
|
|
81
|
+
carga perfecta y en su sitio sale «Syntax error in text». Medido con `mermaid.parse`, y **en
|
|
82
|
+
10.9.0 y en 11.15.0 igual** — no es cosa de la versión:
|
|
83
|
+
|
|
84
|
+
| lo que escribes | |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `A[Mapeos (mapcol)]` | **ROMPE** |
|
|
87
|
+
| `A["Mapeos (mapcol)"]` | ✓ |
|
|
88
|
+
| `subgraph Vistas (contents)` | **ROMPE** |
|
|
89
|
+
| `subgraph S1 [Vistas (contents)]` | **ROMPE** — los corchetes NO salvan |
|
|
90
|
+
| `subgraph "Vistas (contents)"` | ✓ |
|
|
91
|
+
| `A[(Tabla (usuarios))]` | **ROMPE** · `DB[("Tabla (usuarios)")]` ✓ |
|
|
92
|
+
|
|
93
|
+
Y lo que **NO** rompe, comprobado igual: almohadillas (`A[Salida ##EXIT##]`), puntos
|
|
94
|
+
(`A[LoginColl.xne]`), acentos, `:`, `@` y texto en las flechas — las almohadillas se han acusado
|
|
95
|
+
en falso DOS veces. En un proyecto XOne los nombres traen paréntesis solos (`(mapcol)`,
|
|
96
|
+
`(contents)`, `(entry-point)`), así que la regla práctica es **comillas siempre**.
|
|
97
|
+
|
|
98
|
+
## Si el diagrama va en una PESTAÑA, `startOnLoad: true` lo deja en blanco
|
|
99
|
+
|
|
100
|
+
**Fallo real, medido**: dentro de un contenedor oculto mermaid produce un SVG de **0×0** y no
|
|
101
|
+
vuelve a dibujar al mostrarlo (visible al cargar da 563×427). El usuario ve un hueco y la
|
|
102
|
+
consola no dice nada. Con pestañas, acordeones o `<details>` cerrados: **`startOnLoad: false`, y
|
|
103
|
+
dibujar DESPUÉS de mostrar**.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const dibujados = new WeakSet();
|
|
107
|
+
async function mostrarPestana(panel) {
|
|
108
|
+
panel.style.display = 'block'; // primero VISIBLE
|
|
109
|
+
for (const nodo of panel.querySelectorAll('.mermaid')) {
|
|
110
|
+
if (dibujados.has(nodo)) continue; // una sola vez por nodo
|
|
111
|
+
dibujados.add(nodo);
|
|
112
|
+
await mermaid.run({ nodes: [nodo] }); // y AHORA se dibuja
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
De `0×0` a `278×105`. Tres detalles: **el orden no es negociable** (`display: block` ANTES de
|
|
118
|
+
`mermaid.run`; al revés vuelve a dar 0×0) · **`run({ nodes: [...] })` y no `run()` a secas**
|
|
119
|
+
(sin `nodes` reprocesa la página entera) · **una sola vez por nodo** (mermaid sustituye el
|
|
120
|
+
`<pre>` por el SVG, así que un segundo pase no tiene texto que parsear).
|
|
121
|
+
|
|
122
|
+
Diagnóstico rápido: «Syntax error in text» → un paréntesis sin comillas. Hueco en blanco SIN
|
|
123
|
+
error → el contenedor oculto. Nunca las almohadillas.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# El estilo es un SISTEMA: pega los tokens, elige un carácter
|
|
2
|
+
|
|
3
|
+
Este fichero era una lista de consejos y se incumplía entera. Medido en un panel real
|
|
4
|
+
(2026-09-01): decía «evita Inter» y salió `Inter`; decía «evita los morados» y salieron índigo
|
|
5
|
+
`#6366f1` + púrpura + rosa; decía «una escala» y salieron cuatro radios sueltos; y cero
|
|
6
|
+
variables CSS. **Un consejo no es un sistema**: lo que sigue se pega y se acabó.
|
|
7
|
+
|
|
8
|
+
## Los tokens, y el tema en TRES bloques
|
|
9
|
+
|
|
10
|
+
**El de por omisión**, elegido por el usuario el 2026-09-01: fondo casi blanco frío, tinta negra
|
|
11
|
+
azulada, acento azul petróleo y el **cuerpo en SERIF**, que es lo que le quita la cara de
|
|
12
|
+
plantilla. Pega el bloque tal cual y no uses ningún color más.
|
|
13
|
+
|
|
14
|
+
```html
|
|
15
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wght@500;600;700&family=IBM+Plex+Serif:ital,wght@0,400;0,600;1,400&family=IBM+Plex+Mono:wght@400;500&display=swap">
|
|
16
|
+
<style>
|
|
17
|
+
:root {
|
|
18
|
+
--ground:#f6f8fa; --surface:#ffffff; --surface-2:#eef2f6; /* página / tarjeta / elevado */
|
|
19
|
+
--ink:#151a21; --ink-soft:#4e5a68; --rule:#d7dee6; /* texto / apoyo / separador */
|
|
20
|
+
--accent:#0e6c88; --accent-soft:#d9edf4; /* SOLO lo que actúa o mide */
|
|
21
|
+
--alerta:#8d3b2d; --alerta-soft:#f5e3df; /* lo retirado, lo que falla */
|
|
22
|
+
--display:'Archivo','Helvetica Neue',Arial,sans-serif;
|
|
23
|
+
--body:'IBM Plex Serif',Georgia,serif;
|
|
24
|
+
--mono:'IBM Plex Mono','SF Mono',Menlo,monospace;
|
|
25
|
+
--radius:6px;
|
|
26
|
+
}
|
|
27
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
|
|
28
|
+
--ground:#11151a; --surface:#171c23; --surface-2:#1e242c;
|
|
29
|
+
--ink:#e5e9ef; --ink-soft:#9aa7b6; --rule:#2c343e;
|
|
30
|
+
--accent:#58b6d2; --accent-soft:#16323d; --alerta:#d98a7b; --alerta-soft:#35211d;
|
|
31
|
+
} }
|
|
32
|
+
:root[data-theme="dark"] { /* las MISMAS seis líneas de arriba, repetidas */ }
|
|
33
|
+
body { background:var(--ground); color:var(--ink); font-family:var(--body);
|
|
34
|
+
font-size:17px; line-height:1.65; margin:0; }
|
|
35
|
+
</style>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Los tres bloques son tres ESTADOS y hacen falta los tres**: el visor puede no decir nada (gana
|
|
39
|
+
`prefers-color-scheme`), decir `data-theme="dark"` o decir `data-theme="light"` — y sin el
|
|
40
|
+
`:not([data-theme="light"])` un visor en claro dentro de un sistema oscuro sale oscuro. **Ningún
|
|
41
|
+
color puede tener su única definición dentro de un `@media`.**
|
|
42
|
+
|
|
43
|
+
Con Tailwind se usan tal cual: `bg-[var(--surface)]`, `text-[var(--ink-soft)]`,
|
|
44
|
+
`border-[var(--rule)]`, `rounded-[var(--radius)]`, `font-[var(--display)]`. Y el diagrama se
|
|
45
|
+
pinta con estos MISMOS tokens: `reference/diagramas.md`, sección del tema.
|
|
46
|
+
|
|
47
|
+
## El cuerpo en SERIF, los titulares en sans, los identificadores en mono
|
|
48
|
+
|
|
49
|
+
`IBM Plex Serif` a **17px / 1.65** para leer, `Archivo` para titulares y `IBM Plex Mono` para lo
|
|
50
|
+
que es un identificador (`app.xml`, `MAP_BT_MENU`, nombres de coll). Esa mezcla es lo contrario
|
|
51
|
+
del defecto —todo en Inter a 14px— y es la mitad del carácter.
|
|
52
|
+
|
|
53
|
+
Otros caracteres, si el contenido pide otra cosa. **Se toma la fila ENTERA:**
|
|
54
|
+
|
|
55
|
+
| carácter | display / cuerpo / mono | acento | radio |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| **documento** (el de arriba) | Archivo / IBM Plex Serif / IBM Plex Mono | `#0e6c88` petróleo | `6px` |
|
|
58
|
+
| **instrumento** | IBM Plex Sans / IBM Plex Sans / IBM Plex Mono | `#0f766e` teal | `4px` |
|
|
59
|
+
| **cuadro de mando** | Space Grotesk / Public Sans / IBM Plex Mono | `#1d4ed8` tinta | `10px` |
|
|
60
|
+
| **xonecode** (solo si el artefacto habla de la CONSOLA) | IBM Plex Sans / IBM Plex Sans / IBM Plex Mono | `#00a3e0` cian de marca | `6px` |
|
|
61
|
+
|
|
62
|
+
**Ninguna es Inter y ningún acento es índigo ni púrpura**, que es la otra mitad.
|
|
63
|
+
|
|
64
|
+
La fila **xonecode** es la excepción con dueño, y tiene su regla: el cian `#00a3e0` es el color
|
|
65
|
+
de marca MEDIDO (`apps/web/estilos/marca.css`, junto al azul `#083b56` de las superficies de
|
|
66
|
+
marca), y se usa **solo cuando el artefacto es sobre xonecode o sobre el harness** — un diagrama
|
|
67
|
+
de sus capas, un panel de su lazo de turno. Para el mockup de una pantalla XOne o para un
|
|
68
|
+
informe del proyecto del cliente, NO: ahí el tema es el de por omisión, y la app tiene su propio
|
|
69
|
+
CSS. Dos cosas que no son negociables en esa fila:
|
|
70
|
+
|
|
71
|
+
- **El cian es ACENTO y jamás sostiene texto.** Es la misma regla que la consola aplica sobre sí
|
|
72
|
+
misma: el relleno del botón primario es casi negro y el cian se reserva para la pestaña
|
|
73
|
+
elegida, el filo de la tarjeta viva, el punto de estado y la fila seleccionada. Un titular
|
|
74
|
+
cian sobre blanco no tiene contraste y es exactamente el aspecto que esta fila intenta evitar.
|
|
75
|
+
- **La tipografía de la consola —Inter— no está en el menú**, y por dos motivos a la vez: la
|
|
76
|
+
regla de arriba de este mismo fichero, y que sus fuentes empaquetadas **no se pueden cargar**
|
|
77
|
+
desde el artefacto (el iframe tiene origen opaco y no llega al origen de la consola; medido).
|
|
78
|
+
Se usa IBM Plex Sans, que es un instrumento y viene de Google Fonts como el resto.
|
|
79
|
+
|
|
80
|
+
## El ancho: la PÁGINA no lleva `max-width`
|
|
81
|
+
|
|
82
|
+
**El artifact se pinta en un panel, no en una ventana de navegador**, y su ancho lo decide quien
|
|
83
|
+
mira — puede ser 1.700 px. Un `max-w-7xl mx-auto` en el contenedor exterior (que es lo que sale
|
|
84
|
+
por defecto) son **1.280 px centrados**: en ese panel deja **460 px de margen muerto** a los
|
|
85
|
+
lados, con el diagrama encogido en medio. Medido sobre un panel real, 2026-09-01.
|
|
86
|
+
|
|
87
|
+
- **Nada de `max-w-*` ni `mx-auto` en el envoltorio de la página.** Se respira con `padding`
|
|
88
|
+
(`p-6 md:p-8`), no estrechando.
|
|
89
|
+
- **La MEDIDA se limita solo en la PROSA**, que es donde de verdad importa: `max-w-prose` en los
|
|
90
|
+
párrafos largos. Una tabla, un diagrama o una rejilla de tarjetas quieren todo el ancho.
|
|
91
|
+
- **Y el SVG de un diagrama tiene que poder CRECER**: mermaid le pone un `max-width` propio que
|
|
92
|
+
lo deja a su tamaño natural. Ver `reference/diagramas.md`.
|
|
93
|
+
- **Y tiene que sobrevivir al panel ESTRECHO, que es el otro lado de lo mismo.** En la consola de
|
|
94
|
+
xonecode el artefacto se pinta en la columna central, con la barra lateral (280 px) y la lista
|
|
95
|
+
de artefactos (260 px) a los lados: en un portátil eso deja el iframe por debajo de 700 px. No
|
|
96
|
+
es motivo para estrechar la página —sigue sin `max-width`—, sino para que la rejilla ceda:
|
|
97
|
+
columnas que se apilan, tablas con su propio scroll horizontal, y ninguna medida fija en px
|
|
98
|
+
para el contenedor.
|
|
99
|
+
|
|
100
|
+
## Tres reglas duras
|
|
101
|
+
|
|
102
|
+
1. **UN radio por panel**, el de la fila que hayas elegido. La excepción única es `rounded-full`
|
|
103
|
+
para pastillas y avatares. Cuatro radios en una página es la firma de que nadie decidió.
|
|
104
|
+
2. **El acento SOLO para lo que actúa o mide**: el botón que se pulsa, la barra que crece, el
|
|
105
|
+
nodo activo. Si el título, los iconos y las etiquetas van del color de acento, no destaca
|
|
106
|
+
nada — y ése es el aspecto de plantilla que se intenta evitar.
|
|
107
|
+
3. **El fondo se PINTA, siempre y explícito** (`background: var(--ground)` en `body`). El visor
|
|
108
|
+
pinta su propio fondo detrás, así que un `body` transparente hereda el tema del anfitrión y
|
|
109
|
+
el texto puede acabar ilegible.
|
|
110
|
+
|
|
111
|
+
**Y no pongas un INTERRUPTOR de tema.** Los tres bloques de arriba ya cubren los tres estados,
|
|
112
|
+
así que no hace falta — y recordar la elección pide `localStorage`, que **LANZA** en el sandbox
|
|
113
|
+
del visor y se lleva el bloque `<script>` entero: la página se ve perfecta y el diagrama no
|
|
114
|
+
llega a dibujarse. Con `publish_artifact` lo rechaza además el validador. En la consola de
|
|
115
|
+
xonecode no hay validador que lo pare, así que el único que lo evita eres tú — y ahí está medido
|
|
116
|
+
(2026-09-07) que **los tres** almacenes lanzan `SecurityError`: `localStorage`, `sessionStorage`
|
|
117
|
+
e `indexedDB`. Ver `SKILL.md`, «El contrato del OTRO camino».
|
|
118
|
+
|
|
119
|
+
## Y lo de siempre
|
|
120
|
+
|
|
121
|
+
Una jerarquía de TRES tamaños y sostenerla · alineación a la izquierda salvo motivo (centrarlo
|
|
122
|
+
todo es la marca de fábrica) · espaciado 4/8/16/24 y nada entre medias · densidad al servicio
|
|
123
|
+
del dato: una tabla de 40 filas legible vale más que 6 tarjetas enormes con tres cifras.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Exportar a PDF
|
|
2
|
+
|
|
3
|
+
**La vía sencilla y fiable: `window.print()` con CSS de impresión.** No necesita librería, y el
|
|
4
|
+
widget de NappAI pinta el artifact en un iframe con `allow-modals`, que es lo que permite abrir
|
|
5
|
+
el diálogo de impresión desde dentro.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<button class="no-imprimir" onclick="window.print()">Exportar a PDF</button>
|
|
9
|
+
<style>
|
|
10
|
+
@media print {
|
|
11
|
+
.no-imprimir { display: none; }
|
|
12
|
+
body { background: #fff; color: #000; }
|
|
13
|
+
.pagina { break-inside: avoid; }
|
|
14
|
+
}
|
|
15
|
+
@page { margin: 15mm; }
|
|
16
|
+
</style>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
El usuario elige «Guardar como PDF» en el diálogo del navegador.
|
|
20
|
+
|
|
21
|
+
## Si el artifact tiene varias vistas, exporta SOLO la que se está viendo
|
|
22
|
+
|
|
23
|
+
Un panel con pestañas no debe imprimir las pestañas ocultas: salen paginas en blanco o, peor,
|
|
24
|
+
contenido que el usuario no estaba mirando. Marca lo imprimible y esconde el resto:
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<section class="vista" data-vista="resumen">…</section>
|
|
28
|
+
<section class="vista" data-vista="detalle" hidden>…</section>
|
|
29
|
+
|
|
30
|
+
<style>
|
|
31
|
+
@media print {
|
|
32
|
+
/* Solo la vista visible llega al PDF. */
|
|
33
|
+
.vista[hidden] { display: none !important; }
|
|
34
|
+
nav, .filtros, .no-imprimir { display: none; }
|
|
35
|
+
}
|
|
36
|
+
</style>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Si una vista **no** tiene sentido en papel —un mapa interactivo, un formulario— dilo en la
|
|
40
|
+
interfaz en vez de imprimirla mal: deshabilita el botón para esa vista, o añade un
|
|
41
|
+
`@media print` que la sustituya por una nota corta.
|
|
42
|
+
|
|
43
|
+
## Antes de dar el botón por bueno
|
|
44
|
+
|
|
45
|
+
- **Las gráficas se imprimen desde el canvas ya pintado.** Si la librería redibuja al cambiar el
|
|
46
|
+
tamaño, escucha `beforeprint` y fuerza un `resize`/`update`; si no, el PDF sale con la gráfica
|
|
47
|
+
del tamaño anterior.
|
|
48
|
+
- **Los colores de fondo se pierden.** El navegador no imprime fondos por omisión. Para una
|
|
49
|
+
tabla con filas alternas o un badge de color, usa `print-color-adjust: exact` en ese elemento.
|
|
50
|
+
- **Nada de `position: fixed`** en lo que deba salir: se repite o desaparece.
|
|
51
|
+
|
|
52
|
+
## Si generas el fichero desde JavaScript
|
|
53
|
+
|
|
54
|
+
jsPDF o html2pdf desde cdnjs. Ten en cuenta que la descarga dentro del iframe depende de
|
|
55
|
+
`allow-downloads`, que el widget sí pone. Aun así `window.print()` falla en menos sitios y no
|
|
56
|
+
gasta presupuesto del tope de 5 MB en una librería.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Gráficas interactivas
|
|
2
|
+
|
|
3
|
+
Chart.js desde cdnjs, versión fijada. Los datos van horneados: no hay red.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
|
|
7
|
+
<canvas id="ventas"></canvas>
|
|
8
|
+
<script>
|
|
9
|
+
const DATOS = [/* horneado en tiempo de generación */];
|
|
10
|
+
new Chart(document.getElementById('ventas'), {
|
|
11
|
+
type: 'bar',
|
|
12
|
+
data: { labels: DATOS.map(d => d.mes), datasets: [{ data: DATOS.map(d => d.total) }] },
|
|
13
|
+
options: { responsive: true, plugins: { legend: { display: false } } }
|
|
14
|
+
});
|
|
15
|
+
</script>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Interactividad sin red:** filtra el array en memoria y llama a `chart.update()`. Todo el
|
|
19
|
+
dataset ya está en la página.
|
|
20
|
+
|
|
21
|
+
**Tema:** lee `window.matchMedia('(prefers-color-scheme: dark)')` y pásale los colores a
|
|
22
|
+
`options.scales` y `options.plugins.legend.labels.color`.
|