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.
Files changed (408) hide show
  1. package/README.md +50 -8
  2. package/THIRD_PARTY_NOTICES.md +160 -0
  3. package/apps/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  4. package/apps/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  5. package/apps/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  6. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  7. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  8. package/apps/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  9. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  10. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  11. package/apps/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  12. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  13. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  14. package/apps/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  15. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  16. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  17. package/apps/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  18. package/apps/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  19. package/apps/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  20. package/apps/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  21. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  22. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  23. package/apps/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  24. package/apps/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  25. package/apps/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  26. package/apps/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  27. package/apps/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  28. package/apps/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  29. package/apps/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  30. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  31. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  32. package/apps/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  33. package/apps/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  34. package/apps/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  35. package/apps/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  36. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  37. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  38. package/apps/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  39. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  40. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  41. package/apps/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  42. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  43. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  44. package/apps/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  45. package/apps/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  46. package/apps/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  47. package/apps/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  48. package/apps/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  49. package/apps/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  50. package/apps/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  51. package/apps/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  52. package/apps/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  53. package/apps/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  54. package/apps/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  55. package/apps/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  56. package/apps/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  57. package/apps/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  58. package/apps/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  59. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  60. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  61. package/apps/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  62. package/apps/web/dist/assets/c-BIGW1oBm.js +1 -0
  63. package/apps/web/dist/assets/cpp-DddhVWhK.js +1 -0
  64. package/apps/web/dist/assets/csharp-DSvCPggb.js +1 -0
  65. package/apps/web/dist/assets/css-CLj8gQPS.js +1 -0
  66. package/apps/web/dist/assets/go-C27-OAKa.js +1 -0
  67. package/apps/web/dist/assets/html-CfGypltT.js +1 -0
  68. package/apps/web/dist/assets/index-BB3SamhR.css +1 -0
  69. package/apps/web/dist/assets/index-CFYAoHdw.js +477 -0
  70. package/apps/web/dist/assets/ini-BEwlwnbL.js +1 -0
  71. package/apps/web/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  72. package/apps/web/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  73. package/apps/web/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  74. package/apps/web/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  75. package/apps/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  76. package/apps/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  77. package/apps/web/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  78. package/apps/web/dist/assets/java-CylS5w8V.js +1 -0
  79. package/apps/web/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  80. package/apps/web/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  81. package/apps/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  82. package/apps/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  83. package/apps/web/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  84. package/apps/web/dist/assets/kotlin-BdnUsdx6.js +1 -0
  85. package/apps/web/dist/assets/less-B1dDrJ26.js +1 -0
  86. package/apps/web/dist/assets/lua-BaeVxFsk.js +1 -0
  87. package/apps/web/dist/assets/markdown-Cvjx9yec.js +1 -0
  88. package/apps/web/dist/assets/mdx-Cmh6b_Ma.js +1 -0
  89. package/apps/web/dist/assets/php-D_2--9WK.js +1 -0
  90. package/apps/web/dist/assets/python-B6aJPvgy.js +1 -0
  91. package/apps/web/dist/assets/ruby-DSHSDbk1.js +1 -0
  92. package/apps/web/dist/assets/rust-B1yitclQ.js +1 -0
  93. package/apps/web/dist/assets/scss-D5BDwBP9.js +1 -0
  94. package/apps/web/dist/assets/sql-CRqJ_cUM.js +1 -0
  95. package/apps/web/dist/assets/swift-C2oV4EkX.js +1 -0
  96. package/apps/web/dist/assets/toml-vGWfd6FD.js +1 -0
  97. package/apps/web/dist/assets/xml-sdJ4AIDG.js +1 -0
  98. package/apps/web/dist/assets/yaml-Buea-lGh.js +1 -0
  99. package/apps/web/dist/iconos/xonecode.png +0 -0
  100. package/apps/web/dist/index.html +20 -0
  101. package/dist/agent/agentesEnDisco.js +539 -0
  102. package/dist/agent/agentesEnDisco.js.map +1 -0
  103. package/dist/agent/arbolDeProyecto.js +245 -0
  104. package/dist/agent/arbolDeProyecto.js.map +1 -0
  105. package/dist/agent/artefactosEnDisco.js +139 -0
  106. package/dist/agent/artefactosEnDisco.js.map +1 -0
  107. package/dist/agent/aumentador.js +175 -0
  108. package/dist/agent/aumentador.js.map +1 -0
  109. package/dist/agent/authEnDisco.js +76 -1
  110. package/dist/agent/authEnDisco.js.map +1 -1
  111. package/dist/agent/busquedaRegex.js +92 -0
  112. package/dist/agent/busquedaRegex.js.map +1 -0
  113. package/dist/agent/catalogoModelos.js +345 -0
  114. package/dist/agent/catalogoModelos.js.map +1 -0
  115. package/dist/agent/checkpointer.js +127 -0
  116. package/dist/agent/checkpointer.js.map +1 -0
  117. package/dist/agent/cloudstudioClient.js +194 -0
  118. package/dist/agent/cloudstudioClient.js.map +1 -0
  119. package/dist/agent/cloudstudioMcp.js +722 -0
  120. package/dist/agent/cloudstudioMcp.js.map +1 -0
  121. package/dist/agent/configEnDisco.js +309 -11
  122. package/dist/agent/configEnDisco.js.map +1 -1
  123. package/dist/agent/consumoExterno.js +99 -0
  124. package/dist/agent/consumoExterno.js.map +1 -0
  125. package/dist/agent/descarga.js +149 -0
  126. package/dist/agent/descarga.js.map +1 -0
  127. package/dist/agent/diagnosticoDeTools.js +51 -0
  128. package/dist/agent/diagnosticoDeTools.js.map +1 -0
  129. package/dist/agent/dispositivosEnMaquina.js +596 -0
  130. package/dist/agent/dispositivosEnMaquina.js.map +1 -0
  131. package/dist/agent/escrituraDeCodex.js +134 -0
  132. package/dist/agent/escrituraDeCodex.js.map +1 -0
  133. package/dist/agent/escrituraDeOpencode.js +80 -0
  134. package/dist/agent/escrituraDeOpencode.js.map +1 -0
  135. package/dist/agent/escrituraExterna.js +742 -0
  136. package/dist/agent/escrituraExterna.js.map +1 -0
  137. package/dist/agent/gemini.js +81 -0
  138. package/dist/agent/gemini.js.map +1 -0
  139. package/dist/agent/git.js +83 -0
  140. package/dist/agent/git.js.map +1 -0
  141. package/dist/agent/gitSync.js +441 -0
  142. package/dist/agent/gitSync.js.map +1 -0
  143. package/dist/agent/hotswap.js +448 -0
  144. package/dist/agent/hotswap.js.map +1 -0
  145. package/dist/agent/instalacionEnMaquina.js +252 -0
  146. package/dist/agent/instalacionEnMaquina.js.map +1 -0
  147. package/dist/agent/instantanea.js +7 -10
  148. package/dist/agent/instantanea.js.map +1 -1
  149. package/dist/agent/interrupts.js +11 -2
  150. package/dist/agent/interrupts.js.map +1 -1
  151. package/dist/agent/juezDeTarea.js +345 -0
  152. package/dist/agent/juezDeTarea.js.map +1 -0
  153. package/dist/agent/lanzamientoEnMaquina.js +377 -0
  154. package/dist/agent/lanzamientoEnMaquina.js.map +1 -0
  155. package/dist/agent/manifiesto.js +59 -0
  156. package/dist/agent/manifiesto.js.map +1 -0
  157. package/dist/agent/memoriaDeProyecto.js +60 -0
  158. package/dist/agent/memoriaDeProyecto.js.map +1 -0
  159. package/dist/agent/modelos.js +105 -17
  160. package/dist/agent/modelos.js.map +1 -1
  161. package/dist/agent/modelosDeMotor.js +204 -0
  162. package/dist/agent/modelosDeMotor.js.map +1 -0
  163. package/dist/agent/paqueteDelProyecto.js +181 -0
  164. package/dist/agent/paqueteDelProyecto.js.map +1 -0
  165. package/dist/agent/perfiles.js +92 -31
  166. package/dist/agent/perfiles.js.map +1 -1
  167. package/dist/agent/persona.js +40 -0
  168. package/dist/agent/persona.js.map +1 -0
  169. package/dist/agent/procesosEnMaquina.js +204 -0
  170. package/dist/agent/procesosEnMaquina.js.map +1 -0
  171. package/dist/agent/proyecto.js +311 -13
  172. package/dist/agent/proyecto.js.map +1 -1
  173. package/dist/agent/puente.js +63 -6
  174. package/dist/agent/puente.js.map +1 -1
  175. package/dist/agent/resumenDeContexto.js +30 -0
  176. package/dist/agent/resumenDeContexto.js.map +1 -0
  177. package/dist/agent/resumenDeTool.js +64 -18
  178. package/dist/agent/resumenDeTool.js.map +1 -1
  179. package/dist/agent/sesionGit.js +481 -0
  180. package/dist/agent/sesionGit.js.map +1 -0
  181. package/dist/agent/settingsEnDisco.js +189 -0
  182. package/dist/agent/settingsEnDisco.js.map +1 -0
  183. package/dist/agent/subagenteCodex.js +368 -0
  184. package/dist/agent/subagenteCodex.js.map +1 -0
  185. package/dist/agent/subagenteExterno.js +423 -0
  186. package/dist/agent/subagenteExterno.js.map +1 -0
  187. package/dist/agent/subagenteOpencode.js +389 -0
  188. package/dist/agent/subagenteOpencode.js.map +1 -0
  189. package/dist/agent/subida.js +202 -0
  190. package/dist/agent/subida.js.map +1 -0
  191. package/dist/agent/tareasEnDisco.js +466 -0
  192. package/dist/agent/tareasEnDisco.js.map +1 -0
  193. package/dist/agent/turnoReal.js +663 -50
  194. package/dist/agent/turnoReal.js.map +1 -1
  195. package/dist/agent/versionEnDisco.js +48 -0
  196. package/dist/agent/versionEnDisco.js.map +1 -0
  197. package/dist/agent/xoneAgent.js +290 -49
  198. package/dist/agent/xoneAgent.js.map +1 -1
  199. package/dist/agent/zip.js +52 -0
  200. package/dist/agent/zip.js.map +1 -0
  201. package/dist/cli/acuseDeModelo.js +30 -0
  202. package/dist/cli/acuseDeModelo.js.map +1 -0
  203. package/dist/cli/aprobar.js +55 -2
  204. package/dist/cli/aprobar.js.map +1 -1
  205. package/dist/cli/config.js +9 -13
  206. package/dist/cli/config.js.map +1 -1
  207. package/dist/cli/consola.js +750 -19
  208. package/dist/cli/consola.js.map +1 -1
  209. package/dist/cli/main.js +740 -81
  210. package/dist/cli/main.js.map +1 -1
  211. package/dist/cli/markdown.js +188 -2
  212. package/dist/cli/markdown.js.map +1 -1
  213. package/dist/cli/run.js +32 -4
  214. package/dist/cli/run.js.map +1 -1
  215. package/dist/cli/stdio.js +46 -19
  216. package/dist/cli/stdio.js.map +1 -1
  217. package/dist/cli/tema.js +96 -8
  218. package/dist/cli/tema.js.map +1 -1
  219. package/dist/cli/tokens.js +29 -0
  220. package/dist/cli/tokens.js.map +1 -0
  221. package/dist/cli/tui/app.js +171 -0
  222. package/dist/cli/tui/app.js.map +1 -0
  223. package/dist/cli/tui/aprobarTui.js +80 -0
  224. package/dist/cli/tui/aprobarTui.js.map +1 -0
  225. package/dist/cli/tui/barra.js +37 -0
  226. package/dist/cli/tui/barra.js.map +1 -0
  227. package/dist/cli/tui/correrTui.js +478 -0
  228. package/dist/cli/tui/correrTui.js.map +1 -0
  229. package/dist/cli/tui/entrada.js +166 -0
  230. package/dist/cli/tui/entrada.js.map +1 -0
  231. package/dist/cli/tui/filas.js +24 -0
  232. package/dist/cli/tui/filas.js.map +1 -0
  233. package/dist/cli/tui/logo.js +49 -0
  234. package/dist/cli/tui/logo.js.map +1 -0
  235. package/dist/cli/tui/pielTui.js +14 -0
  236. package/dist/cli/tui/pielTui.js.map +1 -0
  237. package/dist/cli/tui/raton.js +126 -0
  238. package/dist/cli/tui/raton.js.map +1 -0
  239. package/dist/cli/tui/sidebar.js +86 -0
  240. package/dist/cli/tui/sidebar.js.map +1 -0
  241. package/dist/cli/tui/store.js +143 -0
  242. package/dist/cli/tui/store.js.map +1 -0
  243. package/dist/cli/tui/tarjeta.js +19 -0
  244. package/dist/cli/tui/tarjeta.js.map +1 -0
  245. package/dist/cli/tui/temaInk.js +114 -0
  246. package/dist/cli/tui/temaInk.js.map +1 -0
  247. package/dist/cli/tui/transcript.js +254 -0
  248. package/dist/cli/tui/transcript.js.map +1 -0
  249. package/dist/cli/wizardInicial.js +240 -0
  250. package/dist/cli/wizardInicial.js.map +1 -0
  251. package/dist/core/actos.js +113 -0
  252. package/dist/core/actos.js.map +1 -0
  253. package/dist/core/adjuntos.js +97 -0
  254. package/dist/core/adjuntos.js.map +1 -0
  255. package/dist/core/agentes.js +227 -0
  256. package/dist/core/agentes.js.map +1 -0
  257. package/dist/core/artefactos.js +149 -0
  258. package/dist/core/artefactos.js.map +1 -0
  259. package/dist/core/cloudstudio.js +7 -0
  260. package/dist/core/cloudstudio.js.map +1 -0
  261. package/dist/core/config.js +212 -5
  262. package/dist/core/config.js.map +1 -1
  263. package/dist/core/contextos.js +53 -1
  264. package/dist/core/contextos.js.map +1 -1
  265. package/dist/core/descargas.js +106 -0
  266. package/dist/core/descargas.js.map +1 -0
  267. package/dist/core/descriptoresDeApp.js +279 -0
  268. package/dist/core/descriptoresDeApp.js.map +1 -0
  269. package/dist/core/dispositivos.js +466 -0
  270. package/dist/core/dispositivos.js.map +1 -0
  271. package/dist/core/entrega.js +141 -0
  272. package/dist/core/entrega.js.map +1 -0
  273. package/dist/core/entrelazar.js +90 -0
  274. package/dist/core/entrelazar.js.map +1 -0
  275. package/dist/core/esqueleto.js +10 -0
  276. package/dist/core/esqueleto.js.map +1 -1
  277. package/dist/core/modelos.js +235 -3
  278. package/dist/core/modelos.js.map +1 -1
  279. package/dist/core/notify.js +27 -9
  280. package/dist/core/notify.js.map +1 -1
  281. package/dist/core/planDeSubida.js +127 -0
  282. package/dist/core/planDeSubida.js.map +1 -0
  283. package/dist/core/ports.js +189 -1
  284. package/dist/core/ports.js.map +1 -1
  285. package/dist/core/puedeLanzarse.js +239 -0
  286. package/dist/core/puedeLanzarse.js.map +1 -0
  287. package/dist/core/rutaVirtual.js +42 -0
  288. package/dist/core/rutaVirtual.js.map +1 -0
  289. package/dist/core/settings.js +246 -0
  290. package/dist/core/settings.js.map +1 -0
  291. package/dist/core/tareas.js +230 -0
  292. package/dist/core/tareas.js.map +1 -0
  293. package/dist/core/textos.js +36 -0
  294. package/dist/core/textos.js.map +1 -0
  295. package/dist/core/turno.js +56 -8
  296. package/dist/core/turno.js.map +1 -1
  297. package/dist/core/version.js +31 -0
  298. package/dist/core/version.js.map +1 -0
  299. package/dist/vendor/sqliteSaver.js +389 -0
  300. package/dist/vendor/sqliteSaver.js.map +1 -0
  301. package/dist/vendor/tokenTracking.js +22 -1
  302. package/dist/vendor/tokenTracking.js.map +1 -1
  303. package/dist/web/servidor/arranque.js +3964 -0
  304. package/dist/web/servidor/arranque.js.map +1 -0
  305. package/dist/web/servidor/consolaDeTarea.js +161 -0
  306. package/dist/web/servidor/consolaDeTarea.js.map +1 -0
  307. package/dist/web/servidor/consolaWeb.js +389 -0
  308. package/dist/web/servidor/consolaWeb.js.map +1 -0
  309. package/dist/web/servidor/corredorDeTareas.js +1119 -0
  310. package/dist/web/servidor/corredorDeTareas.js.map +1 -0
  311. package/dist/web/servidor/pielWeb.js +269 -0
  312. package/dist/web/servidor/pielWeb.js.map +1 -0
  313. package/dist/web/servidor/servidor.js +257 -0
  314. package/dist/web/servidor/servidor.js.map +1 -0
  315. package/dist/web/servidor/sesiones.js +440 -0
  316. package/dist/web/servidor/sesiones.js.map +1 -0
  317. package/dist/web/servidor/transporte.js +169 -0
  318. package/dist/web/servidor/transporte.js.map +1 -0
  319. package/dist/web/servidor/vestibulo.js +1276 -0
  320. package/dist/web/servidor/vestibulo.js.map +1 -0
  321. package/package.json +33 -9
  322. package/skills/archify/LICENSE +22 -0
  323. package/skills/archify/SKILL.md +109 -0
  324. package/skills/archify/THIRD_PARTY_NOTICES.md +56 -0
  325. package/skills/archify/assets/template.html +14787 -0
  326. package/skills/archify/bin/archify.mjs +1990 -0
  327. package/skills/archify/bin/open-artifact.mjs +86 -0
  328. package/skills/archify/bin/preview.mjs +648 -0
  329. package/skills/archify/bin/visual-check.mjs +829 -0
  330. package/skills/archify/brand-marks/README.md +31 -0
  331. package/skills/archify/brand-marks/catalog.json +131 -0
  332. package/skills/archify/delta/architecture-delta.mjs +1214 -0
  333. package/skills/archify/examples/agent-run.lifecycle.json +71 -0
  334. package/skills/archify/examples/agent-tool-call.workflow.json +94 -0
  335. package/skills/archify/examples/async-job-roundtrip.sequence.json +61 -0
  336. package/skills/archify/examples/brand-aware-delivery.architecture.json +47 -0
  337. package/skills/archify/examples/cache-miss-request.sequence.json +81 -0
  338. package/skills/archify/examples/checkout-platform.base.architecture.json +31 -0
  339. package/skills/archify/examples/checkout-platform.head.architecture.json +31 -0
  340. package/skills/archify/examples/dataflow-product-analytics.html +14898 -0
  341. package/skills/archify/examples/deployment-release.lifecycle.json +49 -0
  342. package/skills/archify/examples/event-stream.dataflow.json +57 -0
  343. package/skills/archify/examples/incident-response.workflow.json +64 -0
  344. package/skills/archify/examples/lifecycle-agent-run.html +14847 -0
  345. package/skills/archify/examples/product-analytics.dataflow.json +76 -0
  346. package/skills/archify/examples/production-deployment.architecture.json +71 -0
  347. package/skills/archify/examples/release-delivery.workflow.json +62 -0
  348. package/skills/archify/examples/sequence-cache-miss-request.html +14913 -0
  349. package/skills/archify/examples/web-app-rendered.html +14862 -0
  350. package/skills/archify/examples/web-app.architecture.json +46 -0
  351. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +14904 -0
  352. package/skills/archify/migrations/workflow-v2.mjs +279 -0
  353. package/skills/archify/package.json +17 -0
  354. package/skills/archify/recipes/scenarios.mjs +391 -0
  355. package/skills/archify/references/authoring-contract.md +198 -0
  356. package/skills/archify/references/brand-marks.md +69 -0
  357. package/skills/archify/references/delivery-contract.md +116 -0
  358. package/skills/archify/references/viewer-runtime.md +45 -0
  359. package/skills/archify/renderers/architecture/grid.mjs +62 -0
  360. package/skills/archify/renderers/architecture/render-architecture.mjs +1078 -0
  361. package/skills/archify/renderers/dataflow/README.md +104 -0
  362. package/skills/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  363. package/skills/archify/renderers/lifecycle/README.md +115 -0
  364. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  365. package/skills/archify/renderers/sequence/README.md +114 -0
  366. package/skills/archify/renderers/sequence/render-sequence.mjs +453 -0
  367. package/skills/archify/renderers/shared/brand-marks.mjs +563 -0
  368. package/skills/archify/renderers/shared/cli.mjs +218 -0
  369. package/skills/archify/renderers/shared/desktop-readability.mjs +26 -0
  370. package/skills/archify/renderers/shared/diagnostics.mjs +127 -0
  371. package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
  372. package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  373. package/skills/archify/renderers/shared/generated-validators.mjs +13 -0
  374. package/skills/archify/renderers/shared/geometry.mjs +1423 -0
  375. package/skills/archify/renderers/shared/i18n.mjs +594 -0
  376. package/skills/archify/renderers/shared/layout-report.mjs +40 -0
  377. package/skills/archify/renderers/shared/legend.mjs +217 -0
  378. package/skills/archify/renderers/shared/output-path.mjs +321 -0
  379. package/skills/archify/renderers/shared/repository-evidence.mjs +235 -0
  380. package/skills/archify/renderers/shared/text-fit.mjs +49 -0
  381. package/skills/archify/renderers/shared/utils.mjs +232 -0
  382. package/skills/archify/renderers/shared/validator.mjs +86 -0
  383. package/skills/archify/renderers/workflow/README.md +223 -0
  384. package/skills/archify/renderers/workflow/render-workflow.mjs +35 -0
  385. package/skills/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  386. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  387. package/skills/archify/schemas/README.md +211 -0
  388. package/skills/archify/schemas/architecture.schema.json +176 -0
  389. package/skills/archify/schemas/common.schema.json +115 -0
  390. package/skills/archify/schemas/dataflow.schema.json +243 -0
  391. package/skills/archify/schemas/lifecycle.schema.json +266 -0
  392. package/skills/archify/schemas/sequence.schema.json +223 -0
  393. package/skills/archify/schemas/workflow.schema.json +428 -0
  394. package/skills/archify/scripts/check-render-output.mjs +835 -0
  395. package/skills/archify/scripts/check-update.mjs +1667 -0
  396. package/skills/archify/scripts/render-examples.mjs +26 -0
  397. package/skills/archify/scripts/update-contract.mjs +182 -0
  398. package/skills/archify/skill-release.json +10 -0
  399. package/skills/artifacts-builder/SKILL.md +120 -0
  400. package/skills/artifacts-builder/reference/diagramas.md +123 -0
  401. package/skills/artifacts-builder/reference/estilo.md +123 -0
  402. package/skills/artifacts-builder/reference/exportar-pdf.md +56 -0
  403. package/skills/artifacts-builder/reference/graficas.md +22 -0
  404. package/skills/artifacts-builder/scripts/bundle_artifact.py +109 -0
  405. package/skills/artifacts-builder/scripts/validate_artifact.py +345 -0
  406. package/skills/xone-hotswap/SKILL.md +185 -0
  407. package/skills/xone-hotswap/references/comandos.md +706 -0
  408. package/skills/xone-hotswap/references/conexion-y-despliegue.md +226 -0
@@ -0,0 +1,1990 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
5
+ import fs from 'node:fs';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import { fileURLToPath, pathToFileURL } from 'node:url';
9
+
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ const skillRoot = path.resolve(__dirname, '..');
12
+
13
+ const TYPES = new Set(['architecture', 'workflow', 'sequence', 'dataflow', 'lifecycle']);
14
+
15
+ function usage() {
16
+ return `Usage:
17
+ archify render <type> <input.json> [output.html] [--quality standard|showcase] [--repo-root path (architecture only)]
18
+ archify compare architecture <base.json> <head.json> [output.html] [--receipt path] [--json] [--quality standard|showcase] [--repo-root path]
19
+ archify deliver <type> <input.json> [output.html] [--json] [--open] [--quality standard|showcase] [--repo-root path (architecture only)]
20
+ archify preview <type> <input.json> [output.html] [--no-open] [--quality standard|showcase] [--repo-root path (architecture only)]
21
+ archify validate <type> <input.json> [--json] [--layout-json] [--quality standard|showcase] [--repo-root path (architecture only)]
22
+ archify migrate workflow <old.json> <new.json> --to-schema 2 [--json]
23
+ archify inspect <type> <input.json>
24
+ archify check <output.html>
25
+ archify visual-check <output.html> [--json]
26
+ archify guide [scenario or question] [--json] [--lang en|zh]
27
+ archify brands [name, alias, domain, or category] [--json]
28
+ archify brands capture <url> [--json]
29
+ archify examples
30
+ archify doctor
31
+ archify demo [output-directory]
32
+
33
+ Types:
34
+ architecture, workflow, sequence, dataflow, lifecycle
35
+ `;
36
+ }
37
+
38
+ function fail(message, code = 2) {
39
+ console.error(message);
40
+ process.exit(code);
41
+ }
42
+
43
+ function rendererPath(type) {
44
+ if (!TYPES.has(type)) {
45
+ fail(`Unknown diagram type "${type}". Expected one of: ${[...TYPES].join(', ')}`);
46
+ }
47
+ return path.join(skillRoot, 'renderers', type, `render-${type}.mjs`);
48
+ }
49
+
50
+ function runNode(args, options = {}) {
51
+ return spawnSync(process.execPath, args, {
52
+ cwd: options.cwd || process.cwd(),
53
+ encoding: 'utf8',
54
+ stdio: options.stdio || 'inherit',
55
+ env: options.env ? { ...process.env, ...options.env } : process.env,
56
+ });
57
+ }
58
+
59
+ function extractQualityArgs(args) {
60
+ const rest = [];
61
+ let quality;
62
+ for (let index = 0; index < args.length; index += 1) {
63
+ const arg = args[index];
64
+ if (arg === '--quality') {
65
+ quality = args[index + 1];
66
+ if (!quality || quality.startsWith('--')) fail('--quality requires standard or showcase.');
67
+ index += 1;
68
+ continue;
69
+ }
70
+ if (arg.startsWith('--quality=')) {
71
+ quality = arg.slice('--quality='.length);
72
+ if (!quality) fail('--quality requires standard or showcase.');
73
+ continue;
74
+ }
75
+ rest.push(arg);
76
+ }
77
+ if (quality !== undefined && !['standard', 'showcase'].includes(quality)) {
78
+ fail(`Unknown quality profile "${quality}". Expected standard or showcase.`);
79
+ }
80
+ return { rest, quality };
81
+ }
82
+
83
+ function extractRepoRootArgs(args) {
84
+ const rest = [];
85
+ let repoRoot;
86
+ for (let index = 0; index < args.length; index += 1) {
87
+ const arg = args[index];
88
+ if (arg === '--repo-root') {
89
+ repoRoot = args[index + 1];
90
+ if (!repoRoot || repoRoot.startsWith('--')) fail('--repo-root requires a repository path.');
91
+ index += 1;
92
+ continue;
93
+ }
94
+ if (arg.startsWith('--repo-root=')) {
95
+ repoRoot = arg.slice('--repo-root='.length);
96
+ if (!repoRoot) fail('--repo-root requires a repository path.');
97
+ continue;
98
+ }
99
+ rest.push(arg);
100
+ }
101
+ return { rest, repoRoot: repoRoot ? path.resolve(repoRoot) : undefined };
102
+ }
103
+
104
+ function rendererEnv(quality, repoRoot, diagnosticJson = false) {
105
+ return {
106
+ ...(quality ? { ARCHIFY_QUALITY_PROFILE: quality } : {}),
107
+ ...(repoRoot ? { ARCHIFY_REPO_ROOT: repoRoot } : {}),
108
+ ...(diagnosticJson ? { ARCHIFY_DIAGNOSTIC_FORMAT: 'json' } : {}),
109
+ };
110
+ }
111
+
112
+ function diagnostic({ code, message, subject = {}, evidence = {}, supportedFixes = [], severity = 'error' }) {
113
+ return {
114
+ code,
115
+ severity,
116
+ message,
117
+ subject,
118
+ evidence,
119
+ supportedFixes,
120
+ };
121
+ }
122
+
123
+ function inputDiagnostic(error, inputPath) {
124
+ const isSyntax = error instanceof SyntaxError;
125
+ return diagnostic({
126
+ code: isSyntax ? 'input/json-parse' : 'input/read',
127
+ message: isSyntax
128
+ ? `Input JSON could not be parsed: ${error.message}`
129
+ : `Input could not be read: ${error.message}`,
130
+ subject: { input: inputPath },
131
+ evidence: {
132
+ ...(error?.code ? { systemCode: error.code } : {}),
133
+ reason: error.message,
134
+ },
135
+ supportedFixes: [isSyntax
136
+ ? 'repair the JSON syntax and run validation again'
137
+ : 'provide one readable JSON input file'],
138
+ });
139
+ }
140
+
141
+ function rendererFailure(result) {
142
+ if (result.error) {
143
+ return {
144
+ error: 'Renderer process could not start.',
145
+ diagnostics: [diagnostic({
146
+ code: 'internal/renderer-process',
147
+ message: 'Renderer process could not start.',
148
+ evidence: { reason: result.error.message },
149
+ })],
150
+ };
151
+ }
152
+ try {
153
+ const payload = JSON.parse((result.stderr || '').trim());
154
+ if (payload?.ok === false && Array.isArray(payload.diagnostics) && payload.diagnostics.length) {
155
+ return {
156
+ error: payload.error || payload.diagnostics[0].message,
157
+ diagnostics: payload.diagnostics,
158
+ };
159
+ }
160
+ } catch {
161
+ // The diagnostic boundary is intentionally fail-closed. Never copy a raw
162
+ // Node stack into a machine receipt when a renderer exits unexpectedly.
163
+ }
164
+ return {
165
+ error: 'Renderer failed before emitting a structured diagnostic.',
166
+ diagnostics: [diagnostic({
167
+ code: 'internal/unclassified',
168
+ message: 'Renderer failed before emitting a structured diagnostic.',
169
+ evidence: { exitCode: result.status ?? 1 },
170
+ })],
171
+ };
172
+ }
173
+
174
+ const COMPOSITION_CHECKS = new Set([
175
+ 'label_route_clearance',
176
+ 'relationship_crossings',
177
+ 'relationship_corridors',
178
+ 'container_border_runs',
179
+ 'route_rhythm',
180
+ ]);
181
+
182
+ const CHECK_FIXES = {
183
+ single_svg: ['remove additional SVG roots so the artifact contains exactly one diagram SVG'],
184
+ finite_svg: ['replace non-finite coordinates before rendering again'],
185
+ orthogonal_arrows: ['use renderer-supported orthogonal routing controls'],
186
+ legend_clearance: ['move the route or enlarge the viewBox so relationships do not enter the legend'],
187
+ };
188
+
189
+ const COMPOSITION_FIXES = {
190
+ 'composition/proper-crossing': ['adjust route/via or channel coordinates so unrelated relationships use separate corridors'],
191
+ 'composition/ambiguous-corridor': ['adjust route/via or channel coordinates so unrelated relationships do not visually merge'],
192
+ 'composition/container-border-run': ['route across the frame perpendicularly through a clear opening'],
193
+ 'composition/label-route-clearance': ['adjust labelAt, labelDx, labelDy, labelSegment, message y, or the other relationship route'],
194
+ 'composition/desktop-readability': ['reduce the viewBox width, shorten node copy, widen affected nodes, or split the diagram so node context remains at least 6px at a 1440px desktop viewport'],
195
+ 'composition/micro-segment': ['move the route/channel/via point so every visible segment is at least 8px'],
196
+ 'composition/short-interior-segment': ['move the route/channel/via point so every interior turn has at least 16px'],
197
+ };
198
+
199
+ function checkerDiagnostics(checker) {
200
+ const diagnostics = [];
201
+ for (const issue of checker?.composition?.issues || []) {
202
+ if (issue.severity !== 'error') continue;
203
+ const { severity, code, relationship, ...evidence } = issue;
204
+ diagnostics.push(diagnostic({
205
+ code,
206
+ severity,
207
+ message: `Final artifact failed ${code}.`,
208
+ subject: relationship ? { relationship } : { check: 'composition' },
209
+ evidence,
210
+ supportedFixes: COMPOSITION_FIXES[code] || [],
211
+ }));
212
+ }
213
+ for (const check of checker?.checks || []) {
214
+ if (check.ok || COMPOSITION_CHECKS.has(check.name)) continue;
215
+ diagnostics.push(diagnostic({
216
+ code: `artifact/${check.name.replaceAll('_', '-')}`,
217
+ message: (check.details || []).find(Boolean) || `Final artifact failed ${check.name}.`,
218
+ subject: { check: check.name },
219
+ evidence: { details: check.details || [] },
220
+ supportedFixes: CHECK_FIXES[check.name] || [],
221
+ }));
222
+ }
223
+ return diagnostics.length ? diagnostics : [diagnostic({
224
+ code: 'artifact/check-failed',
225
+ message: 'Final artifact check failed without a classified diagnostic.',
226
+ subject: { check: 'unknown' },
227
+ evidence: {},
228
+ })];
229
+ }
230
+
231
+ function formatDiagnostics(error, diagnostics = []) {
232
+ if (!diagnostics.length) return error;
233
+ return [
234
+ error,
235
+ ...diagnostics.map((entry) => {
236
+ const fix = entry.supportedFixes?.length ? ` Fix: ${entry.supportedFixes.join('; ')}.` : '';
237
+ return `[${entry.code}] ${entry.message}${fix}`;
238
+ }),
239
+ ].join('\n');
240
+ }
241
+
242
+ function assertEvidenceType(type, repoRoot) {
243
+ if (repoRoot && type !== 'architecture') {
244
+ fail('--repo-root is currently supported for architecture diagrams only.');
245
+ }
246
+ }
247
+
248
+ function exitFrom(result) {
249
+ if (result.error) fail(result.error.message, 1);
250
+ process.exit(result.status ?? 1);
251
+ }
252
+
253
+ function reportCompareFailure({ json, stage, error, code = 'delta/internal', details = {}, status = 1 }) {
254
+ const receipt = {
255
+ schemaVersion: 1,
256
+ ok: false,
257
+ command: 'compare',
258
+ type: 'architecture',
259
+ stage,
260
+ error,
261
+ diagnostics: [{
262
+ code,
263
+ severity: 'error',
264
+ message: error,
265
+ subject: details.side ? { side: details.side, ...(details.path ? { path: details.path } : {}) } : {},
266
+ evidence: Object.fromEntries(Object.entries(details).filter(([key]) => !['side', 'path', 'supportedFixes'].includes(key))),
267
+ supportedFixes: details.supportedFixes || [],
268
+ }],
269
+ };
270
+ if (json) console.log(JSON.stringify(receipt, null, 2));
271
+ else console.error(formatDiagnostics(error, receipt.diagnostics));
272
+ process.exitCode = status;
273
+ }
274
+
275
+ function extractCompareOptions(args) {
276
+ const positional = [];
277
+ let receipt;
278
+ let json = false;
279
+ for (let index = 0; index < args.length; index += 1) {
280
+ const arg = args[index];
281
+ if (arg === '--json') {
282
+ json = true;
283
+ continue;
284
+ }
285
+ if (arg === '--receipt') {
286
+ receipt = args[index + 1];
287
+ if (!receipt || receipt.startsWith('--')) fail('--receipt requires a JSON output path.');
288
+ index += 1;
289
+ continue;
290
+ }
291
+ if (arg.startsWith('--receipt=')) {
292
+ receipt = arg.slice('--receipt='.length);
293
+ if (!receipt) fail('--receipt requires a JSON output path.');
294
+ continue;
295
+ }
296
+ if (arg.startsWith('--')) fail(`Unknown compare option "${arg}".`);
297
+ positional.push(arg);
298
+ }
299
+ return { positional, receipt, json };
300
+ }
301
+
302
+ function compareReceiptPath(outputPath) {
303
+ const extension = path.extname(outputPath);
304
+ return extension ? `${outputPath.slice(0, -extension.length)}.receipt.json` : `${outputPath}.receipt.json`;
305
+ }
306
+
307
+ function compareCommitError(message, code, details = {}) {
308
+ const error = new Error(message);
309
+ error.compareStage = 'commit';
310
+ error.compareCode = code;
311
+ error.compareDetails = details;
312
+ return error;
313
+ }
314
+
315
+ function commitComparePair({ htmlCandidate, receiptCandidate, outputPath, receiptPath, stagingDirectory }) {
316
+ const targets = [
317
+ { label: 'HTML artifact', target: outputPath, candidate: htmlCandidate, backup: path.join(stagingDirectory, '.previous-output') },
318
+ { label: 'receipt', target: receiptPath, candidate: receiptCandidate, backup: path.join(stagingDirectory, '.previous-receipt') },
319
+ ];
320
+
321
+ // Preflight the whole pair before moving either trusted target. This avoids
322
+ // replacing the HTML and only then discovering that its receipt destination
323
+ // cannot be committed (for example, because it is a directory).
324
+ for (const item of targets) {
325
+ if (!fs.existsSync(item.target)) continue;
326
+ const existing = fs.lstatSync(item.target);
327
+ if (!existing.isFile()) {
328
+ throw compareCommitError(
329
+ `Could not commit Architecture Delta: existing ${item.label} target is not a regular file.`,
330
+ 'delta/commit-target',
331
+ {
332
+ target: path.basename(item.target),
333
+ targetType: existing.isDirectory() ? 'directory' : 'non-file',
334
+ supportedFixes: [`choose a regular-file path for the ${item.label}`],
335
+ },
336
+ );
337
+ }
338
+ }
339
+
340
+ const backedUp = [];
341
+ const committed = [];
342
+ try {
343
+ for (const item of targets) {
344
+ if (!fs.existsSync(item.target)) continue;
345
+ fs.renameSync(item.target, item.backup);
346
+ backedUp.push(item);
347
+ }
348
+ for (const item of targets) {
349
+ fs.renameSync(item.candidate, item.target);
350
+ committed.push(item);
351
+ }
352
+ } catch (cause) {
353
+ const rollbackErrors = [];
354
+ for (const item of [...committed].reverse()) {
355
+ try {
356
+ fs.rmSync(item.target, { force: true });
357
+ } catch (error) {
358
+ rollbackErrors.push(`${item.label}: remove failed (${error.message})`);
359
+ }
360
+ }
361
+ for (const item of [...backedUp].reverse()) {
362
+ try {
363
+ if (fs.existsSync(item.target)) fs.rmSync(item.target, { force: true });
364
+ fs.renameSync(item.backup, item.target);
365
+ } catch (error) {
366
+ rollbackErrors.push(`${item.label}: restore failed (${error.message})`);
367
+ }
368
+ }
369
+ throw compareCommitError(
370
+ rollbackErrors.length
371
+ ? 'Architecture Delta pair commit failed and its previous files could not be fully restored.'
372
+ : 'Architecture Delta pair commit failed; the previous files were restored.',
373
+ rollbackErrors.length ? 'delta/commit-rollback-failed' : 'delta/commit-failed',
374
+ {
375
+ reason: cause.message,
376
+ ...(rollbackErrors.length ? { rollbackErrors } : {}),
377
+ supportedFixes: ['check that both output paths are writable regular files, then retry'],
378
+ },
379
+ );
380
+ }
381
+ }
382
+
383
+ function renderValidatedArchitecture(inputPath, outputPath, quality, repoRoot) {
384
+ const render = runNode([rendererPath('architecture'), inputPath, outputPath], {
385
+ stdio: 'pipe',
386
+ env: rendererEnv(quality, repoRoot, true),
387
+ });
388
+ if (render.status !== 0) {
389
+ const failure = rendererFailure(render);
390
+ const error = new Error(failure.error);
391
+ error.compareStage = 'input';
392
+ error.compareStatus = render.status ?? 1;
393
+ error.diagnostics = failure.diagnostics;
394
+ throw error;
395
+ }
396
+ const check = runNode([path.join(skillRoot, 'scripts/check-render-output.mjs'), outputPath], { stdio: 'pipe' });
397
+ if (check.status !== 0) {
398
+ const error = new Error('Validated snapshot failed final artifact checks.');
399
+ error.compareStage = 'check';
400
+ error.compareStatus = check.status ?? 1;
401
+ try {
402
+ error.checker = JSON.parse(check.stdout);
403
+ error.diagnostics = checkerDiagnostics(error.checker);
404
+ } catch {
405
+ error.diagnostics = [];
406
+ }
407
+ throw error;
408
+ }
409
+ const artifact = fs.readFileSync(outputPath);
410
+ return {
411
+ artifact,
412
+ html: artifact.toString('utf8'),
413
+ checks: JSON.parse(check.stdout),
414
+ sourceEvidence: sourceEvidenceFromArtifact(artifact),
415
+ };
416
+ }
417
+
418
+ async function commandCompare(args) {
419
+ const { resolveOutputPath } = await import('../renderers/shared/output-path.mjs');
420
+ const qualityArgs = extractQualityArgs(args);
421
+ const repoArgs = extractRepoRootArgs(qualityArgs.rest);
422
+ const options = extractCompareOptions(repoArgs.rest);
423
+ const [type, baseInput, headInput, requestedOutput] = options.positional;
424
+ if (type !== 'architecture' || !baseInput || !headInput || options.positional.length > 4) fail(usage());
425
+ let deltaRuntime;
426
+ try {
427
+ deltaRuntime = await import(pathToFileURL(path.join(skillRoot, 'delta/architecture-delta.mjs')).href);
428
+ } catch (error) {
429
+ reportCompareFailure({ json: options.json, stage: 'prepare', error: 'Architecture compare runtime is unavailable.', code: 'delta/runtime-missing', details: { reason: error.message, supportedFixes: ['install the complete Archify skill package'] } });
430
+ return;
431
+ }
432
+ const {
433
+ ArchitectureDeltaError,
434
+ annotateArchitectureSideSvg,
435
+ buildDeltaSvg,
436
+ canonicalArchitecture,
437
+ canonicalArchitectureJson,
438
+ compareArchitecture,
439
+ extractArchitectureSvg,
440
+ extractArtifactCss,
441
+ renderArchitectureDeltaHtml,
442
+ validateArchitectureDeltaHtml,
443
+ } = deltaRuntime;
444
+
445
+ const basePath = path.resolve(baseInput);
446
+ const headPath = path.resolve(headInput);
447
+ let outputPath;
448
+ try {
449
+ ({ outputPath } = resolveOutputPath({
450
+ requestedOutput,
451
+ defaultOutput: 'architecture-delta.html',
452
+ inputPaths: [basePath, headPath],
453
+ }));
454
+ } catch (error) {
455
+ const outputDiagnostic = error.archifyDiagnostics?.[0];
456
+ reportCompareFailure({
457
+ json: options.json,
458
+ stage: 'prepare',
459
+ error: error.message,
460
+ code: outputDiagnostic?.code || 'output/path-resolution',
461
+ details: {
462
+ ...(outputDiagnostic?.subject || {}),
463
+ ...(outputDiagnostic?.evidence || {}),
464
+ supportedFixes: outputDiagnostic?.supportedFixes || ['choose a safe output path and retry'],
465
+ },
466
+ });
467
+ return;
468
+ }
469
+ let receiptPath;
470
+ try {
471
+ ({ outputPath: receiptPath } = resolveOutputPath({
472
+ requestedOutput: options.receipt || compareReceiptPath(outputPath),
473
+ defaultOutput: compareReceiptPath(outputPath),
474
+ inputPaths: [basePath, headPath],
475
+ otherOutputPaths: [outputPath],
476
+ }));
477
+ } catch (error) {
478
+ const outputDiagnostic = error.archifyDiagnostics?.[0];
479
+ reportCompareFailure({
480
+ json: options.json,
481
+ stage: 'prepare',
482
+ error: error.message,
483
+ code: outputDiagnostic?.code || 'output/path-resolution',
484
+ details: {
485
+ ...(outputDiagnostic?.subject || {}),
486
+ ...(outputDiagnostic?.evidence || {}),
487
+ supportedFixes: outputDiagnostic?.supportedFixes || ['choose a safe receipt path and retry'],
488
+ },
489
+ });
490
+ return;
491
+ }
492
+ let baseBuffer;
493
+ let headBuffer;
494
+ let base;
495
+ let head;
496
+ try {
497
+ baseBuffer = fs.readFileSync(basePath);
498
+ base = JSON.parse(baseBuffer.toString('utf8'));
499
+ } catch (error) {
500
+ reportCompareFailure({ json: options.json, stage: 'input', error: `Could not read base input: ${error.message}`, code: 'delta/base-input', details: { side: 'base', reason: error.message } });
501
+ return;
502
+ }
503
+ try {
504
+ headBuffer = fs.readFileSync(headPath);
505
+ head = JSON.parse(headBuffer.toString('utf8'));
506
+ } catch (error) {
507
+ reportCompareFailure({ json: options.json, stage: 'input', error: `Could not read head input: ${error.message}`, code: 'delta/head-input', details: { side: 'head', reason: error.message } });
508
+ return;
509
+ }
510
+
511
+ const outputDirectory = path.dirname(outputPath);
512
+ if (path.dirname(receiptPath) !== outputDirectory) {
513
+ reportCompareFailure({ json: options.json, stage: 'prepare', error: 'The compare receipt must be written beside the HTML artifact.', code: 'delta/receipt-directory', details: { supportedFixes: ['choose a --receipt path in the same directory as output.html'] } });
514
+ return;
515
+ }
516
+ try {
517
+ fs.mkdirSync(outputDirectory, { recursive: true });
518
+ } catch (error) {
519
+ reportCompareFailure({ json: options.json, stage: 'prepare', error: `Could not create compare output directory: ${error.message}`, code: 'delta/output-directory', details: { reason: error.message } });
520
+ return;
521
+ }
522
+
523
+ let stagingDirectory;
524
+ try {
525
+ stagingDirectory = fs.mkdtempSync(path.join(outputDirectory, '.archify-compare-'));
526
+ } catch (error) {
527
+ reportCompareFailure({ json: options.json, stage: 'prepare', error: `Could not create compare candidate: ${error.message}`, code: 'delta/candidate-directory', details: { reason: error.message } });
528
+ return;
529
+ }
530
+
531
+ const baseCandidate = path.join(stagingDirectory, 'base.html');
532
+ const headCandidate = path.join(stagingDirectory, 'head.html');
533
+ const rawBaseCandidate = path.join(stagingDirectory, 'base.raw.html');
534
+ const rawHeadCandidate = path.join(stagingDirectory, 'head.raw.html');
535
+ const canonicalBaseInput = path.join(stagingDirectory, 'base.architecture.json');
536
+ const canonicalHeadInput = path.join(stagingDirectory, 'head.architecture.json');
537
+ const htmlCandidate = path.join(stagingDirectory, path.basename(outputPath));
538
+ const receiptCandidate = path.join(stagingDirectory, path.basename(receiptPath));
539
+
540
+ try {
541
+ let baseResult;
542
+ let headResult;
543
+ try {
544
+ renderValidatedArchitecture(basePath, rawBaseCandidate, qualityArgs.quality, repoArgs.repoRoot);
545
+ } catch (error) {
546
+ const diagnosticEntry = error.diagnostics?.[0];
547
+ reportCompareFailure({
548
+ json: options.json,
549
+ stage: error.compareStage || 'validate',
550
+ error: `Base snapshot failed validation: ${error.message}`,
551
+ code: diagnosticEntry?.code || 'delta/base-validation',
552
+ details: { side: 'base', ...(diagnosticEntry?.subject?.path ? { path: diagnosticEntry.subject.path } : {}), ...(diagnosticEntry?.evidence || {}), supportedFixes: diagnosticEntry?.supportedFixes || [] },
553
+ status: error.compareStatus || 1,
554
+ });
555
+ return;
556
+ }
557
+ try {
558
+ renderValidatedArchitecture(headPath, rawHeadCandidate, qualityArgs.quality, repoArgs.repoRoot);
559
+ } catch (error) {
560
+ const diagnosticEntry = error.diagnostics?.[0];
561
+ reportCompareFailure({
562
+ json: options.json,
563
+ stage: error.compareStage || 'validate',
564
+ error: `Head snapshot failed validation: ${error.message}`,
565
+ code: diagnosticEntry?.code || 'delta/head-validation',
566
+ details: { side: 'head', ...(diagnosticEntry?.subject?.path ? { path: diagnosticEntry.subject.path } : {}), ...(diagnosticEntry?.evidence || {}), supportedFixes: diagnosticEntry?.supportedFixes || [] },
567
+ status: error.compareStatus || 1,
568
+ });
569
+ return;
570
+ }
571
+
572
+ // Validation must see the exact authored inputs. Only after both sides
573
+ // pass do we canonicalize their collection order for deterministic SVG
574
+ // geometry and stable artifact bytes.
575
+ fs.writeFileSync(canonicalBaseInput, JSON.stringify(canonicalArchitecture(base)));
576
+ fs.writeFileSync(canonicalHeadInput, JSON.stringify(canonicalArchitecture(head)));
577
+ baseResult = renderValidatedArchitecture(canonicalBaseInput, baseCandidate, qualityArgs.quality, repoArgs.repoRoot);
578
+ headResult = renderValidatedArchitecture(canonicalHeadInput, headCandidate, qualityArgs.quality, repoArgs.repoRoot);
579
+
580
+ const semanticHash = (diagram) => createHash('sha256').update(canonicalArchitectureJson(diagram)).digest('hex');
581
+ let compareIr;
582
+ try {
583
+ compareIr = compareArchitecture(base, head, {
584
+ baseRawSha256: createHash('sha256').update(baseBuffer).digest('hex'),
585
+ headRawSha256: createHash('sha256').update(headBuffer).digest('hex'),
586
+ baseSemanticSha256: semanticHash(base),
587
+ headSemanticSha256: semanticHash(head),
588
+ baseBytes: baseBuffer.byteLength,
589
+ headBytes: headBuffer.byteLength,
590
+ baseVerified: Boolean(baseResult.sourceEvidence),
591
+ headVerified: Boolean(headResult.sourceEvidence),
592
+ });
593
+ } catch (error) {
594
+ if (!(error instanceof ArchitectureDeltaError)) throw error;
595
+ reportCompareFailure({ json: options.json, stage: 'compare', error: error.message, code: error.code, details: error.details });
596
+ return;
597
+ }
598
+
599
+ const baseSourceSvg = extractArchitectureSvg(baseResult.html);
600
+ const headSourceSvg = extractArchitectureSvg(headResult.html);
601
+ const baseSvg = annotateArchitectureSideSvg(baseSourceSvg, compareIr, 'base');
602
+ const headSvg = annotateArchitectureSideSvg(headSourceSvg, compareIr, 'head');
603
+ const deltaSvg = buildDeltaSvg(baseSourceSvg, headSourceSvg, compareIr);
604
+ // Raw input hashes and byte counts belong in the sidecar receipt, not the
605
+ // artifact. Keeping them out makes formatting-only input rewrites produce
606
+ // the exact same canonical review HTML and artifact hash.
607
+ const artifactIr = {
608
+ ...compareIr,
609
+ base: Object.fromEntries(Object.entries(compareIr.base).filter(([key]) => !['rawSha256', 'bytes'].includes(key))),
610
+ head: Object.fromEntries(Object.entries(compareIr.head).filter(([key]) => !['rawSha256', 'bytes'].includes(key))),
611
+ };
612
+ const html = renderArchitectureDeltaHtml({
613
+ receipt: artifactIr,
614
+ baseSvg,
615
+ deltaSvg,
616
+ headSvg,
617
+ baseHtml: baseResult.html,
618
+ headHtml: headResult.html,
619
+ artifactCss: extractArtifactCss(headResult.html),
620
+ });
621
+ const deltaValidation = validateArchitectureDeltaHtml(html, artifactIr);
622
+ fs.writeFileSync(htmlCandidate, html);
623
+ const artifact = fs.readFileSync(htmlCandidate);
624
+ const baseChecks = baseResult.checks.checks.filter((check) => check.ok).length;
625
+ const headChecks = headResult.checks.checks.filter((check) => check.ok).length;
626
+ const finalReceipt = {
627
+ ...compareIr,
628
+ artifact: { sha256: createHash('sha256').update(artifact).digest('hex'), bytes: artifact.byteLength },
629
+ validation: {
630
+ checksPassed: baseChecks + headChecks + deltaValidation.checksPassed,
631
+ checkCount: baseResult.checks.checks.length + headResult.checks.checks.length + deltaValidation.checkCount,
632
+ baseComposition: baseResult.checks.composition.status,
633
+ headComposition: headResult.checks.composition.status,
634
+ },
635
+ };
636
+ fs.writeFileSync(receiptCandidate, `${JSON.stringify(finalReceipt, null, 2)}\n`);
637
+
638
+ try {
639
+ const currentOutput = resolveOutputPath({
640
+ requestedOutput,
641
+ defaultOutput: 'architecture-delta.html',
642
+ inputPaths: [basePath, headPath],
643
+ }).outputPath;
644
+ resolveOutputPath({
645
+ requestedOutput: options.receipt || compareReceiptPath(currentOutput),
646
+ defaultOutput: compareReceiptPath(currentOutput),
647
+ inputPaths: [basePath, headPath],
648
+ otherOutputPaths: [currentOutput],
649
+ });
650
+ } catch (error) {
651
+ const outputDiagnostic = error.archifyDiagnostics?.[0];
652
+ reportCompareFailure({
653
+ json: options.json,
654
+ stage: 'commit',
655
+ error: error.message,
656
+ code: outputDiagnostic?.code || 'output/path-resolution',
657
+ details: {
658
+ ...(outputDiagnostic?.subject || {}),
659
+ ...(outputDiagnostic?.evidence || {}),
660
+ supportedFixes: outputDiagnostic?.supportedFixes || ['restore safe output paths and retry'],
661
+ },
662
+ });
663
+ return;
664
+ }
665
+
666
+ commitComparePair({ htmlCandidate, receiptCandidate, outputPath, receiptPath, stagingDirectory });
667
+ if (options.json) console.log(JSON.stringify(finalReceipt, null, 2));
668
+ else {
669
+ console.log(`compared architecture ${outputPath}`);
670
+ console.log(`${finalReceipt.validation.checksPassed}/${finalReceipt.validation.checkCount} checks; completeness ${finalReceipt.completeness}; ${finalReceipt.proofLevel}; sha256 ${finalReceipt.artifact.sha256.slice(0, 12)}`);
671
+ console.log(`receipt ${receiptPath}`);
672
+ }
673
+ } catch (error) {
674
+ if (error instanceof ArchitectureDeltaError) {
675
+ reportCompareFailure({ json: options.json, stage: 'artifact', error: error.message, code: error.code, details: error.details });
676
+ } else if (error.compareStage === 'commit') {
677
+ reportCompareFailure({
678
+ json: options.json,
679
+ stage: error.compareStage,
680
+ error: error.message,
681
+ code: error.compareCode,
682
+ details: error.compareDetails,
683
+ });
684
+ } else {
685
+ reportCompareFailure({ json: options.json, stage: 'internal', error: 'Architecture compare failed before commit.', code: 'delta/internal', details: { reason: error.message } });
686
+ }
687
+ } finally {
688
+ try {
689
+ fs.rmSync(stagingDirectory, { recursive: true, force: true });
690
+ } catch (error) {
691
+ console.error(`Warning: could not remove compare staging directory: ${error.message}`);
692
+ }
693
+ }
694
+ }
695
+
696
+ function commandRender(args) {
697
+ const qualityArgs = extractQualityArgs(args);
698
+ const repoArgs = extractRepoRootArgs(qualityArgs.rest);
699
+ const [type, input, output] = repoArgs.rest;
700
+ if (!type || !input) fail(usage());
701
+ assertEvidenceType(type, repoArgs.repoRoot);
702
+ const result = runNode([rendererPath(type), input, ...(output ? [output] : [])], {
703
+ env: rendererEnv(qualityArgs.quality, repoArgs.repoRoot),
704
+ });
705
+ if (result.status !== 0) exitFrom(result);
706
+ }
707
+
708
+ function reportArtifactFailure({ command, json, stage, type, input, output, error, diagnostics = [], status = 1, checker }) {
709
+ const receipt = {
710
+ schemaVersion: 1,
711
+ ok: false,
712
+ command,
713
+ stage,
714
+ type,
715
+ input,
716
+ ...(output === undefined ? {} : { output }),
717
+ error,
718
+ diagnostics,
719
+ ...(checker ? { checker } : {}),
720
+ };
721
+ if (json) console.log(JSON.stringify(receipt, null, 2));
722
+ else console.error(formatDiagnostics(error, diagnostics));
723
+ process.exitCode = status;
724
+ }
725
+
726
+ function reportDeliveryFailure(options) {
727
+ reportArtifactFailure({ ...options, command: 'deliver' });
728
+ }
729
+
730
+ function reportValidateFailure(options) {
731
+ reportArtifactFailure({ ...options, command: 'validate' });
732
+ }
733
+
734
+ function sourceEvidenceFromArtifact(artifact) {
735
+ const html = artifact.toString('utf8');
736
+ const match = html.match(/<script id="archify-source-evidence-data" type="application\/json">([\s\S]*?)<\/script>/);
737
+ if (!match) return null;
738
+ const evidence = JSON.parse(match[1]);
739
+ if (evidence?.verified !== true || !evidence.repository?.url || !evidence.repository?.revision || !Number.isInteger(evidence.referenceCount)) {
740
+ throw new Error('Rendered source evidence receipt is incomplete.');
741
+ }
742
+ return evidence;
743
+ }
744
+
745
+ function engineeringProfileFromArtifact(artifact) {
746
+ const match = artifact.toString('utf8').match(/<svg[^>]*\sdata-engineering-profile="([^"]+)"/);
747
+ return match ? match[1] : null;
748
+ }
749
+
750
+ async function commandDeliver(args) {
751
+ const { resolveOutputPath } = await import('../renderers/shared/output-path.mjs');
752
+ const qualityArgs = extractQualityArgs(args);
753
+ const repoArgs = extractRepoRootArgs(qualityArgs.rest);
754
+ const json = repoArgs.rest.includes('--json');
755
+ const open = repoArgs.rest.includes('--open');
756
+ const knownOptions = new Set(['--json', '--open']);
757
+ const unknown = repoArgs.rest.filter((arg) => arg.startsWith('--') && !knownOptions.has(arg));
758
+ if (unknown.length) fail(`Unknown deliver option "${unknown[0]}".`);
759
+ const positional = repoArgs.rest.filter((arg) => !knownOptions.has(arg));
760
+ const [type, input, requestedOutput] = positional;
761
+ if (!type || !input || positional.length > 3) fail(usage());
762
+ assertEvidenceType(type, repoArgs.repoRoot);
763
+
764
+ const renderer = rendererPath(type);
765
+ const inputPath = path.resolve(input);
766
+ let specification;
767
+ let diagram;
768
+ try {
769
+ specification = fs.readFileSync(inputPath);
770
+ diagram = JSON.parse(specification.toString('utf8'));
771
+ } catch (error) {
772
+ const repair = inputDiagnostic(error, inputPath);
773
+ reportDeliveryFailure({
774
+ json,
775
+ stage: 'input',
776
+ type,
777
+ input: inputPath,
778
+ output: path.resolve(requestedOutput || `${type}.html`),
779
+ error: `Could not read delivery input "${inputPath}": ${error.message}`,
780
+ diagnostics: [repair],
781
+ });
782
+ return;
783
+ }
784
+
785
+ const authoredOutput = typeof diagram?.meta?.output === 'string' && diagram.meta.output
786
+ ? diagram.meta.output
787
+ : undefined;
788
+ let outputPath;
789
+ try {
790
+ ({ outputPath } = resolveOutputPath({
791
+ requestedOutput,
792
+ authoredOutput,
793
+ defaultOutput: `${type}.html`,
794
+ inputPaths: [inputPath],
795
+ }));
796
+ } catch (error) {
797
+ const attemptedOutput = path.resolve(requestedOutput || authoredOutput || `${type}.html`);
798
+ reportDeliveryFailure({
799
+ json,
800
+ stage: 'prepare',
801
+ type,
802
+ input: inputPath,
803
+ output: attemptedOutput,
804
+ error: error.message,
805
+ diagnostics: error.archifyDiagnostics || [diagnostic({
806
+ code: 'output/path-resolution',
807
+ message: error.message,
808
+ subject: { output: attemptedOutput },
809
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}) },
810
+ supportedFixes: ['choose a safe output path and retry'],
811
+ })],
812
+ });
813
+ return;
814
+ }
815
+ const outputDirectory = path.dirname(outputPath);
816
+ try {
817
+ fs.mkdirSync(outputDirectory, { recursive: true });
818
+ } catch (error) {
819
+ const message = `Could not create delivery directory "${outputDirectory}": ${error.message}`;
820
+ reportDeliveryFailure({
821
+ json,
822
+ stage: 'prepare',
823
+ type,
824
+ input: inputPath,
825
+ output: outputPath,
826
+ error: message,
827
+ diagnostics: [diagnostic({
828
+ code: 'delivery/prepare-directory',
829
+ message,
830
+ subject: { outputDirectory },
831
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
832
+ supportedFixes: ['choose a writable output directory'],
833
+ })],
834
+ });
835
+ return;
836
+ }
837
+
838
+ // Keep the candidate beside the target so the final rename is one
839
+ // same-filesystem commit. A render or artifact-check failure never touches
840
+ // an existing trusted output.
841
+ let stagingDirectory;
842
+ try {
843
+ stagingDirectory = fs.mkdtempSync(path.join(outputDirectory, '.archify-delivery-'));
844
+ } catch (error) {
845
+ const message = `Could not create a delivery candidate beside "${outputPath}": ${error.message}`;
846
+ reportDeliveryFailure({
847
+ json,
848
+ stage: 'prepare',
849
+ type,
850
+ input: inputPath,
851
+ output: outputPath,
852
+ error: message,
853
+ diagnostics: [diagnostic({
854
+ code: 'delivery/prepare-candidate',
855
+ message,
856
+ subject: { output: outputPath },
857
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
858
+ supportedFixes: ['choose a writable output directory on the target filesystem'],
859
+ })],
860
+ });
861
+ return;
862
+ }
863
+ const candidatePath = path.join(stagingDirectory, path.basename(outputPath));
864
+ const specificationSnapshotPath = path.join(stagingDirectory, 'specification.snapshot.json');
865
+
866
+ try {
867
+ try {
868
+ fs.writeFileSync(specificationSnapshotPath, specification, { flag: 'wx' });
869
+ } catch (error) {
870
+ const message = `Could not freeze the delivery specification: ${error.message}`;
871
+ reportDeliveryFailure({
872
+ json,
873
+ stage: 'prepare',
874
+ type,
875
+ input: inputPath,
876
+ output: outputPath,
877
+ error: message,
878
+ diagnostics: [diagnostic({
879
+ code: 'delivery/freeze-specification',
880
+ message,
881
+ subject: { input: inputPath },
882
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
883
+ supportedFixes: ['choose a writable output directory on the target filesystem'],
884
+ })],
885
+ });
886
+ return;
887
+ }
888
+
889
+ const render = runNode([renderer, specificationSnapshotPath, candidatePath], {
890
+ stdio: 'pipe',
891
+ env: rendererEnv(qualityArgs.quality, repoArgs.repoRoot, true),
892
+ });
893
+ if (render.status !== 0) {
894
+ const failure = rendererFailure(render);
895
+ reportDeliveryFailure({
896
+ json,
897
+ stage: 'render',
898
+ type,
899
+ input: inputPath,
900
+ output: outputPath,
901
+ error: failure.error,
902
+ diagnostics: failure.diagnostics,
903
+ status: render.status ?? 1,
904
+ });
905
+ return;
906
+ }
907
+
908
+ const check = runNode([path.join(skillRoot, 'scripts/check-render-output.mjs'), candidatePath], {
909
+ stdio: 'pipe',
910
+ });
911
+ if (check.status !== 0) {
912
+ if (check.stderr) process.stderr.write(check.stderr);
913
+ let checker;
914
+ try {
915
+ checker = JSON.parse(check.stdout);
916
+ checker.file = outputPath;
917
+ } catch {
918
+ checker = { ok: false, file: outputPath, diagnostic: check.stdout.trim() };
919
+ }
920
+ reportDeliveryFailure({
921
+ json,
922
+ stage: 'check',
923
+ type,
924
+ input: inputPath,
925
+ output: outputPath,
926
+ error: 'Final artifact check failed; the previous artifact was preserved.',
927
+ diagnostics: checkerDiagnostics(checker),
928
+ status: check.status ?? 1,
929
+ checker,
930
+ });
931
+ return;
932
+ }
933
+
934
+ let result;
935
+ try {
936
+ result = JSON.parse(check.stdout);
937
+ } catch (error) {
938
+ const message = `Could not parse the successful artifact-check receipt: ${error.message}`;
939
+ reportDeliveryFailure({
940
+ json,
941
+ stage: 'receipt',
942
+ type,
943
+ input: inputPath,
944
+ output: outputPath,
945
+ error: message,
946
+ diagnostics: [diagnostic({
947
+ code: 'delivery/receipt-invalid',
948
+ message,
949
+ subject: { output: outputPath },
950
+ evidence: { reason: error.message },
951
+ })],
952
+ });
953
+ return;
954
+ }
955
+ let artifact;
956
+ try {
957
+ artifact = fs.readFileSync(candidatePath);
958
+ } catch (error) {
959
+ const message = `Could not read the verified delivery candidate: ${error.message}`;
960
+ reportDeliveryFailure({
961
+ json,
962
+ stage: 'receipt',
963
+ type,
964
+ input: inputPath,
965
+ output: outputPath,
966
+ error: message,
967
+ diagnostics: [diagnostic({
968
+ code: 'delivery/candidate-unreadable',
969
+ message,
970
+ subject: { output: outputPath },
971
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
972
+ })],
973
+ });
974
+ return;
975
+ }
976
+ let sourceEvidence;
977
+ try {
978
+ sourceEvidence = sourceEvidenceFromArtifact(artifact);
979
+ } catch (error) {
980
+ const message = `Could not read the repository evidence receipt: ${error.message}`;
981
+ reportDeliveryFailure({
982
+ json,
983
+ stage: 'receipt',
984
+ type,
985
+ input: inputPath,
986
+ output: outputPath,
987
+ error: message,
988
+ diagnostics: [diagnostic({
989
+ code: 'delivery/evidence-receipt-invalid',
990
+ message,
991
+ subject: { output: outputPath },
992
+ evidence: { reason: error.message },
993
+ })],
994
+ });
995
+ return;
996
+ }
997
+ const engineeringProfile = engineeringProfileFromArtifact(artifact);
998
+ const receipt = {
999
+ schemaVersion: 1,
1000
+ ok: true,
1001
+ command: 'deliver',
1002
+ type,
1003
+ input: inputPath,
1004
+ output: outputPath,
1005
+ specification: {
1006
+ sha256: createHash('sha256').update(specification).digest('hex'),
1007
+ bytes: specification.byteLength,
1008
+ },
1009
+ artifact: {
1010
+ sha256: createHash('sha256').update(artifact).digest('hex'),
1011
+ bytes: artifact.byteLength,
1012
+ },
1013
+ validation: {
1014
+ checksPassed: result.checks.filter((checkItem) => checkItem.ok).length,
1015
+ checkCount: result.checks.length,
1016
+ compositionProfile: result.composition.profile,
1017
+ compositionStatus: result.composition.status,
1018
+ ...(engineeringProfile ? { engineeringProfile } : {}),
1019
+ errors: result.composition.summary.errors,
1020
+ warnings: result.composition.summary.warnings,
1021
+ },
1022
+ ...(sourceEvidence ? {
1023
+ evidence: {
1024
+ verified: true,
1025
+ repository: sourceEvidence.repository.url,
1026
+ revision: sourceEvidence.repository.revision,
1027
+ references: sourceEvidence.referenceCount,
1028
+ },
1029
+ } : {}),
1030
+ };
1031
+
1032
+ try {
1033
+ resolveOutputPath({
1034
+ requestedOutput,
1035
+ authoredOutput,
1036
+ defaultOutput: `${type}.html`,
1037
+ inputPaths: [inputPath],
1038
+ });
1039
+ } catch (error) {
1040
+ reportDeliveryFailure({
1041
+ json,
1042
+ stage: 'commit',
1043
+ type,
1044
+ input: inputPath,
1045
+ output: outputPath,
1046
+ error: error.message,
1047
+ diagnostics: error.archifyDiagnostics || [diagnostic({
1048
+ code: 'output/path-resolution',
1049
+ message: error.message,
1050
+ subject: { output: outputPath },
1051
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}) },
1052
+ supportedFixes: ['restore a safe output path and retry'],
1053
+ })],
1054
+ });
1055
+ return;
1056
+ }
1057
+
1058
+ try {
1059
+ fs.renameSync(candidatePath, outputPath);
1060
+ } catch (error) {
1061
+ const message = `Could not commit verified delivery "${outputPath}": ${error.message}`;
1062
+ reportDeliveryFailure({
1063
+ json,
1064
+ stage: 'commit',
1065
+ type,
1066
+ input: inputPath,
1067
+ output: outputPath,
1068
+ error: message,
1069
+ diagnostics: [diagnostic({
1070
+ code: 'delivery/commit',
1071
+ message,
1072
+ subject: { output: outputPath },
1073
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
1074
+ supportedFixes: ['choose a replaceable file target on the same writable filesystem'],
1075
+ })],
1076
+ });
1077
+ return;
1078
+ }
1079
+
1080
+ if (open) {
1081
+ try {
1082
+ const { openArtifact } = await import('./open-artifact.mjs');
1083
+ receipt.open = openArtifact(outputPath);
1084
+ } catch {
1085
+ receipt.open = {
1086
+ requested: true,
1087
+ status: 'unsupported',
1088
+ target: outputPath,
1089
+ method: null,
1090
+ };
1091
+ }
1092
+ if (receipt.open.status !== 'opened') {
1093
+ console.error(`Could not open the verified artifact (${receipt.open.status}). Open it manually: ${outputPath}`);
1094
+ }
1095
+ }
1096
+
1097
+ if (json) {
1098
+ console.log(JSON.stringify(receipt, null, 2));
1099
+ } else {
1100
+ console.log(`delivered ${type} ${outputPath}`);
1101
+ const engineering = receipt.validation.engineeringProfile
1102
+ ? `; engineering ${receipt.validation.engineeringProfile}: pass`
1103
+ : '';
1104
+ console.log(`${receipt.validation.checksPassed}/${receipt.validation.checkCount} artifact checks; composition ${receipt.validation.compositionProfile}: ${receipt.validation.compositionStatus}${engineering}; sha256 ${receipt.artifact.sha256.slice(0, 12)}`);
1105
+ if (receipt.open?.status === 'opened') console.log(`opened ${outputPath}`);
1106
+ }
1107
+ } finally {
1108
+ try {
1109
+ fs.rmSync(stagingDirectory, { recursive: true, force: true });
1110
+ } catch (error) {
1111
+ console.error(`Warning: could not remove delivery staging directory "${stagingDirectory}": ${error.message}`);
1112
+ }
1113
+ }
1114
+ }
1115
+
1116
+ async function commandPreview(args) {
1117
+ const qualityArgs = extractQualityArgs(args);
1118
+ const repoArgs = extractRepoRootArgs(qualityArgs.rest);
1119
+ const noOpen = repoArgs.rest.includes('--no-open');
1120
+ const knownOptions = new Set(['--no-open']);
1121
+ const unknown = repoArgs.rest.filter((arg) => arg.startsWith('--') && !knownOptions.has(arg));
1122
+ if (unknown.length) fail(`Unknown preview option "${unknown[0]}".`);
1123
+ const positional = repoArgs.rest.filter((arg) => !knownOptions.has(arg));
1124
+ const [type, input, output] = positional;
1125
+ if (!type || !input || positional.length > 3) fail(usage());
1126
+ assertEvidenceType(type, repoArgs.repoRoot);
1127
+ rendererPath(type);
1128
+
1129
+ let runPreview;
1130
+ try {
1131
+ ({ runPreview } = await import('./preview.mjs'));
1132
+ } catch (error) {
1133
+ fail(`Could not load live preview: ${error.message}`, 1);
1134
+ }
1135
+ try {
1136
+ await runPreview({
1137
+ type,
1138
+ input,
1139
+ output,
1140
+ quality: qualityArgs.quality,
1141
+ repoRoot: repoArgs.repoRoot,
1142
+ open: !noOpen,
1143
+ });
1144
+ } catch (error) {
1145
+ fail(`Could not start live preview: ${error.message}`, 1);
1146
+ }
1147
+ }
1148
+
1149
+ function commandCheck(args) {
1150
+ const [html] = args;
1151
+ if (!html) fail(usage());
1152
+ const result = runNode([path.join(skillRoot, 'scripts/check-render-output.mjs'), html]);
1153
+ if (result.status !== 0) exitFrom(result);
1154
+ }
1155
+
1156
+ async function commandVisualCheck(args) {
1157
+ const json = args.includes('--json');
1158
+ const knownOptions = new Set(['--json']);
1159
+ const unknown = args.filter((arg) => arg.startsWith('--') && !knownOptions.has(arg));
1160
+ if (unknown.length) fail(`Unknown visual-check option "${unknown[0]}".`, 1);
1161
+ const positional = args.filter((arg) => !knownOptions.has(arg));
1162
+ if (positional.length !== 1) fail(usage(), 1);
1163
+
1164
+ let runVisualCheck;
1165
+ try {
1166
+ ({ runVisualCheck } = await import('./visual-check.mjs'));
1167
+ } catch (error) {
1168
+ fail(`Could not load visual-check: ${error.message}`, 1);
1169
+ }
1170
+
1171
+ let result;
1172
+ try {
1173
+ result = await runVisualCheck({ artifactPath: positional[0] });
1174
+ } catch (error) {
1175
+ if (json) {
1176
+ console.log(JSON.stringify({
1177
+ schemaVersion: 1,
1178
+ ok: false,
1179
+ command: 'visual-check',
1180
+ evidenceKind: 'automated-browser',
1181
+ status: 'fail',
1182
+ visualReview: 'pending',
1183
+ artifact: { path: path.resolve(positional[0]) },
1184
+ error: error.message,
1185
+ }, null, 2));
1186
+ } else {
1187
+ console.error(`automated browser evidence failed: ${error.message}`);
1188
+ console.error('perceptual visual review pending');
1189
+ }
1190
+ process.exitCode = 1;
1191
+ return;
1192
+ }
1193
+
1194
+ if (json) {
1195
+ console.log(JSON.stringify(result.receipt, null, 2));
1196
+ } else {
1197
+ console.log(`automated browser evidence ${result.receipt.status}: ${result.receipt.artifact.path}`);
1198
+ console.log(`visual-check containment ${result.receipt.containment.status}; captures ${result.receipt.captures.status}; perceptual visual review pending`);
1199
+ console.log(`receipt ${path.join(path.dirname(result.receipt.artifact.path), result.receipt.sidecars.receipt)}`);
1200
+ if (result.receipt.captures.contactSheet) {
1201
+ console.log(`contact sheet ${path.join(path.dirname(result.receipt.artifact.path), result.receipt.captures.contactSheet)}`);
1202
+ }
1203
+ if (result.receipt.error) console.error(result.receipt.error);
1204
+ }
1205
+ process.exitCode = result.exitCode;
1206
+ }
1207
+
1208
+ function commandExamples() {
1209
+ const result = runNode([path.join(skillRoot, 'scripts/render-examples.mjs')], { cwd: skillRoot });
1210
+ if (result.status !== 0) exitFrom(result);
1211
+ }
1212
+
1213
+ async function commandDoctor() {
1214
+ const checks = [];
1215
+ const nodeMajor = Number.parseInt(process.versions.node.split('.')[0], 10);
1216
+ checks.push({
1217
+ label: `Node.js v${process.versions.node} (requires >=18)`,
1218
+ ok: nodeMajor >= 18,
1219
+ missing: 0,
1220
+ failureLabel: 'unsupported',
1221
+ });
1222
+
1223
+ const template = path.join(skillRoot, 'assets/template.html');
1224
+ checks.push({
1225
+ label: 'Core template',
1226
+ ok: fs.existsSync(template),
1227
+ missing: fs.existsSync(template) ? 0 : 1,
1228
+ });
1229
+
1230
+ const examplesRenderer = path.join(skillRoot, 'scripts/render-examples.mjs');
1231
+ checks.push({
1232
+ label: 'Example renderer',
1233
+ ok: fs.existsSync(examplesRenderer),
1234
+ missing: fs.existsSync(examplesRenderer) ? 0 : 1,
1235
+ });
1236
+
1237
+ const previewRuntime = path.join(skillRoot, 'bin/preview.mjs');
1238
+ checks.push({
1239
+ label: 'Live preview runtime',
1240
+ ok: fs.existsSync(previewRuntime),
1241
+ missing: fs.existsSync(previewRuntime) ? 0 : 1,
1242
+ });
1243
+
1244
+ const visualCheckRuntime = path.join(skillRoot, 'bin/visual-check.mjs');
1245
+ checks.push({
1246
+ label: 'Visual-check runtime',
1247
+ ok: fs.existsSync(visualCheckRuntime),
1248
+ missing: fs.existsSync(visualCheckRuntime) ? 0 : 1,
1249
+ });
1250
+
1251
+ const outputPathRuntime = path.join(skillRoot, 'renderers/shared/output-path.mjs');
1252
+ checks.push({
1253
+ label: 'Output path safety runtime',
1254
+ ok: fs.existsSync(outputPathRuntime),
1255
+ missing: fs.existsSync(outputPathRuntime) ? 0 : 1,
1256
+ });
1257
+
1258
+ const scenarioGuide = path.join(skillRoot, 'recipes/scenarios.mjs');
1259
+ checks.push({
1260
+ label: 'Scenario recipe guide',
1261
+ ok: fs.existsSync(scenarioGuide),
1262
+ missing: fs.existsSync(scenarioGuide) ? 0 : 1,
1263
+ });
1264
+
1265
+ const authoringReferences = [
1266
+ path.join(skillRoot, 'references', 'authoring-contract.md'),
1267
+ path.join(skillRoot, 'references', 'viewer-runtime.md'),
1268
+ path.join(skillRoot, 'references', 'delivery-contract.md'),
1269
+ ];
1270
+ const authoringReferencesMissing = authoringReferences.filter((file) => !fs.existsSync(file)).length;
1271
+ checks.push({
1272
+ label: 'Progressive authoring references',
1273
+ ok: authoringReferencesMissing === 0,
1274
+ missing: authoringReferencesMissing,
1275
+ });
1276
+
1277
+ const compareRuntime = path.join(skillRoot, 'delta/architecture-delta.mjs');
1278
+ const compareFixtures = [
1279
+ path.join(skillRoot, 'examples/checkout-platform.base.architecture.json'),
1280
+ path.join(skillRoot, 'examples/checkout-platform.head.architecture.json'),
1281
+ ];
1282
+ const compareMissing = [compareRuntime, ...compareFixtures].filter((file) => !fs.existsSync(file)).length;
1283
+ checks.push({
1284
+ label: 'Architecture compare runtime and proof fixtures',
1285
+ ok: compareMissing === 0,
1286
+ missing: compareMissing,
1287
+ });
1288
+
1289
+ const validators = path.join(skillRoot, 'renderers/shared/generated-validators.mjs');
1290
+ const validatorsExist = fs.existsSync(validators);
1291
+ let validatorsValid = false;
1292
+ if (validatorsExist) {
1293
+ try {
1294
+ const module = await import(`${pathToFileURL(validators).href}?doctor=${Date.now()}`);
1295
+ validatorsValid = [...TYPES].every((type) => typeof module[type] === 'function');
1296
+ } catch {
1297
+ validatorsValid = false;
1298
+ }
1299
+ }
1300
+ checks.push({
1301
+ label: 'Standalone schema validators',
1302
+ ok: validatorsValid,
1303
+ missing: validatorsExist ? 0 : 1,
1304
+ invalid: validatorsExist && !validatorsValid ? 1 : 0,
1305
+ failureLabel: validatorsExist ? 'invalid' : 'missing',
1306
+ });
1307
+
1308
+ const examples = {
1309
+ architecture: 'web-app.architecture.json',
1310
+ workflow: 'agent-tool-call.workflow.json',
1311
+ sequence: 'cache-miss-request.sequence.json',
1312
+ dataflow: 'product-analytics.dataflow.json',
1313
+ lifecycle: 'agent-run.lifecycle.json',
1314
+ };
1315
+
1316
+ for (const type of TYPES) {
1317
+ const required = [
1318
+ path.join(skillRoot, 'renderers', type, `render-${type}.mjs`),
1319
+ path.join(skillRoot, 'schemas', `${type}.schema.json`),
1320
+ path.join(skillRoot, 'examples', examples[type]),
1321
+ ];
1322
+ const missing = required.filter((file) => !fs.existsSync(file)).length;
1323
+ checks.push({
1324
+ label: `${type} renderer, schema, and example`,
1325
+ ok: missing === 0,
1326
+ missing,
1327
+ });
1328
+ }
1329
+
1330
+ console.log('Archify doctor\n');
1331
+ for (const check of checks) {
1332
+ console.log(`[${check.ok ? 'ok' : (check.failureLabel || 'missing')}] ${check.label}`);
1333
+ }
1334
+
1335
+ const nodeFailed = checks[0].ok ? 0 : 1;
1336
+ const missingFiles = checks.reduce((count, check) => count + check.missing, 0);
1337
+ const invalidRuntime = checks.reduce((count, check) => count + (check.invalid || 0), 0);
1338
+ if (nodeFailed === 0 && missingFiles === 0 && invalidRuntime === 0) {
1339
+ console.log('\nArchify is ready.');
1340
+ return;
1341
+ }
1342
+
1343
+ const problems = [];
1344
+ if (nodeFailed) problems.push('Node.js 18 or newer is required');
1345
+ if (missingFiles) problems.push(`${missingFiles} required file${missingFiles === 1 ? '' : 's'} missing`);
1346
+ if (invalidRuntime) problems.push(`${invalidRuntime} runtime check${invalidRuntime === 1 ? '' : 's'} failed`);
1347
+ console.error(`\nArchify is not ready: ${problems.join('; ')}.`);
1348
+ process.exitCode = 1;
1349
+ }
1350
+
1351
+ async function commandGuide(args) {
1352
+ let lang;
1353
+ let json = false;
1354
+ const queryParts = [];
1355
+
1356
+ for (let index = 0; index < args.length; index += 1) {
1357
+ const arg = args[index];
1358
+ if (arg === '--json') {
1359
+ json = true;
1360
+ } else if (arg === '--lang') {
1361
+ const value = args[index + 1];
1362
+ if (value !== 'en' && value !== 'zh') fail('--lang must be "en" or "zh".');
1363
+ lang = value;
1364
+ index += 1;
1365
+ } else if (arg.startsWith('--lang=')) {
1366
+ const value = arg.slice('--lang='.length);
1367
+ if (value !== 'en' && value !== 'zh') fail('--lang must be "en" or "zh".');
1368
+ lang = value;
1369
+ } else if (arg.startsWith('--')) {
1370
+ fail(`Unknown guide option "${arg}".`);
1371
+ } else {
1372
+ queryParts.push(arg);
1373
+ }
1374
+ }
1375
+
1376
+ const guidePath = path.join(skillRoot, 'recipes/scenarios.mjs');
1377
+ let guide;
1378
+ try {
1379
+ guide = await import(pathToFileURL(guidePath).href);
1380
+ } catch (error) {
1381
+ fail(`Could not load the scenario recipe guide: ${error.message}`, 1);
1382
+ }
1383
+
1384
+ const query = queryParts.join(' ').trim();
1385
+ if (!query) {
1386
+ const selectedLang = lang || 'en';
1387
+ if (json) {
1388
+ console.log(JSON.stringify({
1389
+ ok: true,
1390
+ mode: 'list',
1391
+ lang: selectedLang,
1392
+ recipes: guide.listScenarioRecipes(selectedLang),
1393
+ }, null, 2));
1394
+ } else {
1395
+ console.log(guide.formatScenarioList(selectedLang));
1396
+ }
1397
+ return;
1398
+ }
1399
+
1400
+ const result = guide.recommendScenario(query, lang ? { lang } : {});
1401
+ console.log(json ? JSON.stringify(result, null, 2) : guide.formatScenarioRecommendation(result));
1402
+ }
1403
+
1404
+ async function commandBrands(args) {
1405
+ const json = args.includes('--json');
1406
+ const unknown = args.filter((arg) => arg.startsWith('--') && arg !== '--json');
1407
+ if (unknown.length) fail(`Unknown brands option "${unknown[0]}".`);
1408
+ const positional = args.filter((arg) => arg !== '--json');
1409
+ if (positional[0] === 'capture') {
1410
+ if (positional.length !== 2) fail('Usage: archify brands capture <url> [--json]');
1411
+ const { captureBrandReference } = await import('../renderers/shared/brand-marks.mjs');
1412
+ let capture;
1413
+ try {
1414
+ capture = await captureBrandReference(positional[1]);
1415
+ } catch (error) {
1416
+ fail(error.message);
1417
+ }
1418
+ const result = {
1419
+ schemaVersion: 1,
1420
+ ok: true,
1421
+ command: 'brands capture',
1422
+ brand: capture.brand,
1423
+ evidence: {
1424
+ status: capture.resolved.status,
1425
+ source: capture.resolved.sourceUrl,
1426
+ ...(capture.resolved.sha256 ? { sha256: capture.resolved.sha256 } : {}),
1427
+ ...(capture.resolved.contentType ? { contentType: capture.resolved.contentType } : {}),
1428
+ },
1429
+ };
1430
+ console.log(json ? JSON.stringify(result, null, 2) : JSON.stringify(result.brand));
1431
+ return;
1432
+ }
1433
+ const query = positional.join(' ').trim();
1434
+ const { listBrandMarks } = await import('../renderers/shared/brand-marks.mjs');
1435
+ const marks = listBrandMarks(query);
1436
+ if (json) {
1437
+ console.log(JSON.stringify({
1438
+ schemaVersion: 1,
1439
+ ok: true,
1440
+ command: 'brands',
1441
+ query,
1442
+ count: marks.length,
1443
+ marks,
1444
+ fallback: 'Run "archify brands capture <url> --json", then use the returned digest-pinned brand value.',
1445
+ }, null, 2));
1446
+ return;
1447
+ }
1448
+ if (!marks.length) {
1449
+ console.log(`No built-in brand matched "${query}". Run "archify brands capture <url> --json", then use the returned digest-pinned brand value.`);
1450
+ return;
1451
+ }
1452
+ const grouped = Map.groupBy
1453
+ ? Map.groupBy(marks, (mark) => mark.category)
1454
+ : marks.reduce((map, mark) => map.set(mark.category, [...(map.get(mark.category) || []), mark]), new Map());
1455
+ for (const [category, entries] of grouped) {
1456
+ console.log(`${category}: ${entries.map((mark) => mark.id).join(', ')}`);
1457
+ }
1458
+ }
1459
+
1460
+ function commandDemo(args) {
1461
+ if (args.length > 1) fail(usage());
1462
+
1463
+ const outputDirectory = path.resolve(args[0] || process.cwd());
1464
+ const output = path.join(outputDirectory, 'archify-demo.html');
1465
+ const input = path.join(skillRoot, 'examples/web-app.architecture.json');
1466
+
1467
+ try {
1468
+ fs.mkdirSync(outputDirectory, { recursive: true });
1469
+ } catch (error) {
1470
+ fail(`Could not create demo directory "${outputDirectory}": ${error.message}`, 1);
1471
+ }
1472
+
1473
+ const result = runNode([rendererPath('architecture'), input, output]);
1474
+ if (result.status !== 0) exitFrom(result);
1475
+
1476
+ console.log(`\nDemo ready: ${output}`);
1477
+ console.log('Next: open the HTML in your browser, then render your own diagram:');
1478
+ console.log(' archify render architecture <input.json> <output.html>');
1479
+ }
1480
+
1481
+ function migrationPathDiagnostics(error, sourcePath, destinationPath) {
1482
+ if (Array.isArray(error?.archifyDiagnostics) && error.archifyDiagnostics.length) {
1483
+ return error.archifyDiagnostics.map((entry) => ({
1484
+ ...entry,
1485
+ subject: { ...(entry.subject || {}) },
1486
+ evidence: { ...(entry.evidence || {}) },
1487
+ supportedFixes: [...(entry.supportedFixes || [])],
1488
+ }));
1489
+ }
1490
+ return [diagnostic({
1491
+ code: 'migration/path-preflight',
1492
+ message: 'Could not verify that the workflow migration paths are distinct.',
1493
+ subject: { source: sourcePath, destination: destinationPath },
1494
+ evidence: {
1495
+ ...(error?.code ? { systemCode: error.code } : {}),
1496
+ reason: error?.message || String(error),
1497
+ },
1498
+ supportedFixes: ['remove unsafe path aliases or choose a different destination path'],
1499
+ })];
1500
+ }
1501
+
1502
+ function migrationReport({
1503
+ ok,
1504
+ sourcePath,
1505
+ destinationPath,
1506
+ sourceBytes,
1507
+ destinationBytes,
1508
+ fromSchemaVersion,
1509
+ preExistingDiagnostics = [],
1510
+ migrationDiagnostics = [],
1511
+ newSchemaDiagnostics = [],
1512
+ changedCoordinates = [],
1513
+ oldRequiredViewBox = null,
1514
+ newRequiredViewBox = null,
1515
+ }) {
1516
+ const report = {
1517
+ ok,
1518
+ command: 'migrate',
1519
+ type: 'workflow',
1520
+ source: {
1521
+ path: sourcePath,
1522
+ ...(sourceBytes ? {
1523
+ sha256: createHash('sha256').update(sourceBytes).digest('hex'),
1524
+ bytes: sourceBytes.length,
1525
+ } : {}),
1526
+ },
1527
+ destination: {
1528
+ path: destinationPath,
1529
+ ...(destinationBytes ? {
1530
+ sha256: createHash('sha256').update(destinationBytes).digest('hex'),
1531
+ bytes: destinationBytes.length,
1532
+ } : {}),
1533
+ },
1534
+ fromSchemaVersion: fromSchemaVersion ?? null,
1535
+ toSchemaVersion: 2,
1536
+ preExistingDiagnostics,
1537
+ migrationDiagnostics,
1538
+ newSchemaDiagnostics,
1539
+ changedCoordinates,
1540
+ oldRequiredViewBox,
1541
+ newRequiredViewBox,
1542
+ };
1543
+ if (!ok) {
1544
+ report.diagnostics = [
1545
+ ...migrationDiagnostics,
1546
+ ...newSchemaDiagnostics,
1547
+ ...preExistingDiagnostics,
1548
+ ];
1549
+ if (!report.diagnostics.length) {
1550
+ report.diagnostics.push(diagnostic({
1551
+ code: 'migration/internal',
1552
+ message: 'Workflow migration failed without a classified diagnostic.',
1553
+ }));
1554
+ }
1555
+ report.error = report.diagnostics[0].message;
1556
+ }
1557
+ return report;
1558
+ }
1559
+
1560
+ function extractMigrationOptions(args) {
1561
+ const positional = [];
1562
+ let json = false;
1563
+ let toSchema;
1564
+ for (let index = 0; index < args.length; index += 1) {
1565
+ const arg = args[index];
1566
+ if (arg === '--json') {
1567
+ json = true;
1568
+ continue;
1569
+ }
1570
+ if (arg === '--to-schema') {
1571
+ toSchema = args[index + 1];
1572
+ if (!toSchema || toSchema.startsWith('--')) fail('--to-schema requires a schema version.');
1573
+ index += 1;
1574
+ continue;
1575
+ }
1576
+ if (arg.startsWith('--to-schema=')) {
1577
+ toSchema = arg.slice('--to-schema='.length);
1578
+ if (!toSchema) fail('--to-schema requires a schema version.');
1579
+ continue;
1580
+ }
1581
+ if (arg.startsWith('--')) fail(`Unknown migrate option "${arg}".`);
1582
+ positional.push(arg);
1583
+ }
1584
+ return { positional, json, toSchema };
1585
+ }
1586
+
1587
+ async function commandMigrate(args) {
1588
+ const options = extractMigrationOptions(args);
1589
+ const [type, sourceArgument, destinationArgument] = options.positional;
1590
+ if (
1591
+ type !== 'workflow'
1592
+ || !sourceArgument
1593
+ || !destinationArgument
1594
+ || options.positional.length !== 3
1595
+ || options.toSchema !== '2'
1596
+ ) {
1597
+ fail('Usage: archify migrate workflow <old.json> <new.json> --to-schema 2 [--json]');
1598
+ }
1599
+
1600
+ const sourcePath = path.resolve(sourceArgument);
1601
+ const destinationPath = path.resolve(destinationArgument);
1602
+ let sourceBytes;
1603
+ let sourceDocument;
1604
+ const reportMigrationFailure = ({ status = 1, ...details }) => {
1605
+ const report = migrationReport({
1606
+ ...details,
1607
+ ok: false,
1608
+ sourcePath,
1609
+ destinationPath,
1610
+ sourceBytes,
1611
+ fromSchemaVersion: sourceDocument?.schema_version,
1612
+ });
1613
+ if (options.json) console.log(JSON.stringify(report, null, 2));
1614
+ else console.error(formatDiagnostics(report.error, report.diagnostics));
1615
+ process.exitCode = status;
1616
+ };
1617
+ try {
1618
+ sourceBytes = fs.readFileSync(sourcePath);
1619
+ sourceDocument = JSON.parse(sourceBytes.toString('utf8'));
1620
+ } catch (error) {
1621
+ reportMigrationFailure({
1622
+ preExistingDiagnostics: [inputDiagnostic(error, sourcePath)],
1623
+ });
1624
+ return;
1625
+ }
1626
+ // Unlike render/validate, migrate has no --quality override. Pin every stage
1627
+ // to the document's durable policy and scrub any ambient profile from the
1628
+ // staged renderer by passing this value explicitly.
1629
+ const activeQualityProfile = sourceDocument?.meta?.quality_profile || 'standard';
1630
+
1631
+ const { pathsAlias } = await import('../renderers/shared/output-path.mjs');
1632
+ let sourceDestinationAlias;
1633
+ try {
1634
+ sourceDestinationAlias = pathsAlias(sourcePath, destinationPath);
1635
+ } catch (error) {
1636
+ reportMigrationFailure({
1637
+ migrationDiagnostics: migrationPathDiagnostics(error, sourcePath, destinationPath),
1638
+ });
1639
+ return;
1640
+ }
1641
+ if (sourceDestinationAlias) {
1642
+ reportMigrationFailure({
1643
+ migrationDiagnostics: [diagnostic({
1644
+ code: 'migration/source-destination',
1645
+ message: 'Workflow migration source and destination must be different files.',
1646
+ subject: { source: sourcePath, destination: destinationPath },
1647
+ supportedFixes: ['choose a different destination path and keep the source unchanged'],
1648
+ })],
1649
+ });
1650
+ return;
1651
+ }
1652
+
1653
+ const { migrateWorkflowDocument, serializeMigratedWorkflow } = await import('../migrations/workflow-v2.mjs');
1654
+ let migration;
1655
+ try {
1656
+ migration = migrateWorkflowDocument(sourceDocument);
1657
+ } catch (error) {
1658
+ migration = {
1659
+ ok: false,
1660
+ migrationDiagnostics: [diagnostic({
1661
+ code: 'migration/internal',
1662
+ message: 'Workflow migration failed unexpectedly.',
1663
+ evidence: { reason: error.message },
1664
+ supportedFixes: ['report the source workflow and this diagnostic to the Archify maintainers'],
1665
+ })],
1666
+ };
1667
+ }
1668
+
1669
+ if (!migration.ok) {
1670
+ reportMigrationFailure(migration);
1671
+ return;
1672
+ }
1673
+
1674
+ if (fs.existsSync(destinationPath) && !fs.lstatSync(destinationPath).isFile()) {
1675
+ reportMigrationFailure({
1676
+ ...migration,
1677
+ migrationDiagnostics: [...migration.migrationDiagnostics, diagnostic({
1678
+ code: 'migration/destination-type',
1679
+ message: 'Workflow migration destination must be a regular file path.',
1680
+ subject: { destination: destinationPath },
1681
+ supportedFixes: ['choose a destination path that is absent or names a regular file'],
1682
+ })],
1683
+ });
1684
+ return;
1685
+ }
1686
+
1687
+ const destinationDirectory = path.dirname(destinationPath);
1688
+ let stagingDirectory;
1689
+ try {
1690
+ fs.mkdirSync(destinationDirectory, { recursive: true });
1691
+ stagingDirectory = fs.mkdtempSync(path.join(destinationDirectory, '.archify-migration-'));
1692
+ } catch (error) {
1693
+ reportMigrationFailure({
1694
+ ...migration,
1695
+ migrationDiagnostics: [...migration.migrationDiagnostics, diagnostic({
1696
+ code: 'migration/prepare-destination',
1697
+ message: 'Could not prepare the workflow migration destination.',
1698
+ subject: { destination: destinationPath },
1699
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
1700
+ supportedFixes: ['choose a writable destination directory'],
1701
+ })],
1702
+ });
1703
+ return;
1704
+ }
1705
+
1706
+ const candidatePath = path.join(stagingDirectory, 'candidate.workflow.json');
1707
+ const artifactPath = path.join(stagingDirectory, 'migration-check.html');
1708
+ const destinationBytes = Buffer.from(serializeMigratedWorkflow(migration.document));
1709
+ try {
1710
+ fs.writeFileSync(candidatePath, destinationBytes, { flag: 'wx' });
1711
+ const render = runNode([rendererPath('workflow'), candidatePath, artifactPath], {
1712
+ stdio: 'pipe',
1713
+ env: rendererEnv(activeQualityProfile, undefined, true),
1714
+ });
1715
+ if (render.status !== 0) {
1716
+ const failure = rendererFailure(render);
1717
+ reportMigrationFailure({
1718
+ ...migration,
1719
+ newSchemaDiagnostics: [...migration.newSchemaDiagnostics, ...failure.diagnostics],
1720
+ status: render.status ?? 1,
1721
+ });
1722
+ return;
1723
+ }
1724
+
1725
+ const check = runNode([path.join(skillRoot, 'scripts/check-render-output.mjs'), artifactPath], {
1726
+ stdio: 'pipe',
1727
+ });
1728
+ if (check.status !== 0) {
1729
+ let checker;
1730
+ try {
1731
+ checker = JSON.parse(check.stdout);
1732
+ } catch {
1733
+ checker = null;
1734
+ }
1735
+ reportMigrationFailure({
1736
+ ...migration,
1737
+ newSchemaDiagnostics: [
1738
+ ...migration.newSchemaDiagnostics,
1739
+ ...checkerDiagnostics(checker),
1740
+ ],
1741
+ status: check.status ?? 1,
1742
+ });
1743
+ return;
1744
+ }
1745
+
1746
+ if (pathsAlias(sourcePath, destinationPath)) {
1747
+ reportMigrationFailure({
1748
+ ...migration,
1749
+ migrationDiagnostics: [...migration.migrationDiagnostics, diagnostic({
1750
+ code: 'migration/source-destination',
1751
+ message: 'Workflow migration source and destination resolved to the same file before commit.',
1752
+ subject: { source: sourcePath, destination: destinationPath },
1753
+ supportedFixes: ['choose a different destination path and retry'],
1754
+ })],
1755
+ });
1756
+ return;
1757
+ }
1758
+ const currentSourceBytes = fs.readFileSync(sourcePath);
1759
+ if (!currentSourceBytes.equals(sourceBytes)) {
1760
+ reportMigrationFailure({
1761
+ ...migration,
1762
+ migrationDiagnostics: [...migration.migrationDiagnostics, diagnostic({
1763
+ code: 'migration/source-changed',
1764
+ message: 'Workflow migration source changed while the destination was being verified.',
1765
+ subject: { source: sourcePath },
1766
+ supportedFixes: ['retry the migration from a stable workflow source file'],
1767
+ })],
1768
+ });
1769
+ return;
1770
+ }
1771
+
1772
+ fs.renameSync(candidatePath, destinationPath);
1773
+ const report = migrationReport({
1774
+ ...migration,
1775
+ sourcePath,
1776
+ destinationPath,
1777
+ sourceBytes,
1778
+ destinationBytes,
1779
+ fromSchemaVersion: sourceDocument.schema_version,
1780
+ });
1781
+ if (options.json) console.log(JSON.stringify(report, null, 2));
1782
+ else if (sourceDocument.schema_version === 1) {
1783
+ console.log(`migrated workflow schema v1→v2: ${sourcePath} → ${destinationPath}`);
1784
+ } else {
1785
+ console.log(`verified workflow schema v2 migration: ${sourcePath} → ${destinationPath}`);
1786
+ }
1787
+ } catch (error) {
1788
+ const migrationDiagnostics = Array.isArray(error?.archifyDiagnostics)
1789
+ ? migrationPathDiagnostics(error, sourcePath, destinationPath)
1790
+ : [diagnostic({
1791
+ code: 'migration/commit',
1792
+ message: 'Could not commit the verified workflow migration.',
1793
+ subject: { destination: destinationPath },
1794
+ evidence: { ...(error?.code ? { systemCode: error.code } : {}), reason: error.message },
1795
+ supportedFixes: ['choose a writable regular-file destination and retry'],
1796
+ })];
1797
+ reportMigrationFailure({
1798
+ ...migration,
1799
+ migrationDiagnostics: [...migration.migrationDiagnostics, ...migrationDiagnostics],
1800
+ });
1801
+ } finally {
1802
+ try {
1803
+ fs.rmSync(stagingDirectory, { recursive: true, force: true });
1804
+ } catch (error) {
1805
+ console.error(`Warning: could not remove workflow migration staging directory "${stagingDirectory}": ${error.message}`);
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+ function commandValidate(args) {
1811
+ const qualityArgs = extractQualityArgs(args);
1812
+ const repoArgs = extractRepoRootArgs(qualityArgs.rest);
1813
+ args = repoArgs.rest;
1814
+ const quality = qualityArgs.quality;
1815
+ const repoRoot = repoArgs.repoRoot;
1816
+ const knownOptions = new Set(['--json', '--layout-json']);
1817
+ const unknown = args.filter((arg) => arg.startsWith('--') && !knownOptions.has(arg));
1818
+ if (unknown.length) fail(`Unknown validate option "${unknown[0]}".`);
1819
+ const json = args.includes('--json');
1820
+ const layoutJson = args.includes('--layout-json');
1821
+ const rest = args.filter((arg) => !knownOptions.has(arg));
1822
+ const [type, input] = rest;
1823
+ if (!type || !input || rest.length !== 2) fail(usage());
1824
+ assertEvidenceType(type, repoRoot);
1825
+ const renderer = rendererPath(type);
1826
+
1827
+ if (layoutJson) {
1828
+ if (!['architecture', 'workflow'].includes(type)) {
1829
+ fail('--layout-json is currently supported for architecture and workflow diagrams only.');
1830
+ }
1831
+ const result = runNode([renderer, input, '/dev/null', '--layout-json'], {
1832
+ stdio: 'pipe',
1833
+ env: rendererEnv(quality, repoRoot, true),
1834
+ });
1835
+ if (result.status !== 0) {
1836
+ try {
1837
+ const receipt = JSON.parse(result.stdout);
1838
+ if (receipt?.contract && Array.isArray(receipt.diagnostics)) {
1839
+ process.stdout.write(`${JSON.stringify(receipt, null, 2)}\n`);
1840
+ process.exitCode = result.status ?? 1;
1841
+ return;
1842
+ }
1843
+ } catch {
1844
+ // Fall through to the renderer failure contract when no compiler
1845
+ // receipt was produced (for example, input JSON could not be read).
1846
+ }
1847
+ const failure = rendererFailure(result);
1848
+ reportValidateFailure({
1849
+ json,
1850
+ stage: failure.diagnostics.some((entry) => entry.code.startsWith('input/')) ? 'input' : 'render',
1851
+ type,
1852
+ input: path.resolve(input),
1853
+ error: failure.error,
1854
+ diagnostics: failure.diagnostics,
1855
+ status: result.status ?? 1,
1856
+ });
1857
+ return;
1858
+ }
1859
+ process.stdout.write(result.stdout);
1860
+ return;
1861
+ }
1862
+
1863
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'archify-validate-'));
1864
+ const out = path.join(tmp, `${type}.html`);
1865
+ let exitCode = 0;
1866
+
1867
+ try {
1868
+ const render = runNode([renderer, input, out], {
1869
+ stdio: 'pipe',
1870
+ env: rendererEnv(quality, repoRoot, true),
1871
+ });
1872
+ if (render.status !== 0) {
1873
+ const failure = rendererFailure(render);
1874
+ reportValidateFailure({
1875
+ json,
1876
+ stage: failure.diagnostics.some((entry) => entry.code.startsWith('input/')) ? 'input' : 'render',
1877
+ type,
1878
+ input: path.resolve(input),
1879
+ error: failure.error,
1880
+ diagnostics: failure.diagnostics,
1881
+ status: render.status ?? 1,
1882
+ });
1883
+ exitCode = render.status ?? 1;
1884
+ } else {
1885
+ const check = runNode([path.join(skillRoot, 'scripts/check-render-output.mjs'), out], { stdio: 'pipe' });
1886
+ if (check.status !== 0) {
1887
+ let checker;
1888
+ try {
1889
+ checker = JSON.parse(check.stdout);
1890
+ checker.file = path.resolve(input);
1891
+ } catch {
1892
+ checker = { ok: false, diagnostic: 'Artifact checker failed without a parseable receipt.' };
1893
+ }
1894
+ reportValidateFailure({
1895
+ json,
1896
+ stage: 'check',
1897
+ type,
1898
+ input: path.resolve(input),
1899
+ error: 'Final artifact check failed.',
1900
+ diagnostics: checkerDiagnostics(checker),
1901
+ checker,
1902
+ status: check.status ?? 1,
1903
+ });
1904
+ exitCode = check.status ?? 1;
1905
+ } else {
1906
+ const result = JSON.parse(check.stdout);
1907
+ const engineeringProfile = engineeringProfileFromArtifact(fs.readFileSync(out));
1908
+ if (json) {
1909
+ console.log(JSON.stringify({
1910
+ schemaVersion: 1,
1911
+ ok: true,
1912
+ command: 'validate',
1913
+ type,
1914
+ input: path.resolve(input),
1915
+ checks: result.checks,
1916
+ composition: result.composition,
1917
+ ...(engineeringProfile ? { engineeringProfile } : {}),
1918
+ }, null, 2));
1919
+ } else {
1920
+ const engineering = engineeringProfile
1921
+ ? `; engineering ${engineeringProfile}: pass`
1922
+ : '';
1923
+ console.log(`ok ${type} ${path.resolve(input)} (${result.checks.length} artifact checks; composition ${result.composition.profile}: ${result.composition.summary.errors} errors, ${result.composition.summary.warnings} warnings${engineering})`);
1924
+ }
1925
+ }
1926
+ }
1927
+ } finally {
1928
+ fs.rmSync(tmp, { recursive: true, force: true });
1929
+ }
1930
+
1931
+ if (exitCode !== 0) process.exitCode = exitCode;
1932
+ }
1933
+
1934
+ const [command, ...args] = process.argv.slice(2);
1935
+
1936
+ switch (command) {
1937
+ case undefined:
1938
+ case '-h':
1939
+ case '--help':
1940
+ case 'help':
1941
+ console.log(usage());
1942
+ break;
1943
+ case 'render':
1944
+ commandRender(args);
1945
+ break;
1946
+ case 'compare':
1947
+ await commandCompare(args);
1948
+ break;
1949
+ case 'deliver':
1950
+ await commandDeliver(args);
1951
+ break;
1952
+ case 'preview':
1953
+ await commandPreview(args);
1954
+ break;
1955
+ case 'validate':
1956
+ commandValidate(args);
1957
+ break;
1958
+ case 'migrate':
1959
+ await commandMigrate(args);
1960
+ break;
1961
+ case 'inspect':
1962
+ if (args[0] !== 'architecture') {
1963
+ fail('inspect is currently supported for architecture diagrams only.');
1964
+ }
1965
+ commandValidate([...args, '--layout-json']);
1966
+ break;
1967
+ case 'check':
1968
+ commandCheck(args);
1969
+ break;
1970
+ case 'visual-check':
1971
+ await commandVisualCheck(args);
1972
+ break;
1973
+ case 'guide':
1974
+ await commandGuide(args);
1975
+ break;
1976
+ case 'brands':
1977
+ await commandBrands(args);
1978
+ break;
1979
+ case 'examples':
1980
+ commandExamples();
1981
+ break;
1982
+ case 'doctor':
1983
+ await commandDoctor();
1984
+ break;
1985
+ case 'demo':
1986
+ commandDemo(args);
1987
+ break;
1988
+ default:
1989
+ fail(`Unknown command "${command}".\n\n${usage()}`);
1990
+ }