@tuongaz/seeflow 0.1.64 → 0.1.68

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 (314) hide show
  1. package/README.md +4 -0
  2. package/dist/web/assets/abap-DsBKuouk.js +1 -0
  3. package/dist/web/assets/actionscript-3-D_z4Izcz.js +1 -0
  4. package/dist/web/assets/ada-727ZlQH0.js +1 -0
  5. package/dist/web/assets/andromeeda-C3khCPGq.js +1 -0
  6. package/dist/web/assets/angular-html-4alyEGLm.js +1 -0
  7. package/dist/web/assets/angular-ts-BixEUTMq.js +1 -0
  8. package/dist/web/assets/apache-Dn00JSTd.js +1 -0
  9. package/dist/web/assets/apex-COJ4H7py.js +1 -0
  10. package/dist/web/assets/apl-BBq3IX1j.js +1 -0
  11. package/dist/web/assets/applescript-Bu5BbsvL.js +1 -0
  12. package/dist/web/assets/ara-7O62HKoU.js +1 -0
  13. package/dist/web/assets/asciidoc-BPT9niGB.js +1 -0
  14. package/dist/web/assets/asm-Dhn9LcZ4.js +1 -0
  15. package/dist/web/assets/astro-CqkE3fuf.js +1 -0
  16. package/dist/web/assets/aurora-x-D-2ljcwZ.js +1 -0
  17. package/dist/web/assets/awk-eg146-Ew.js +1 -0
  18. package/dist/web/assets/ayu-dark-Cv9koXgw.js +1 -0
  19. package/dist/web/assets/ballerina-Du268qiB.js +1 -0
  20. package/dist/web/assets/bat-fje9CFhw.js +1 -0
  21. package/dist/web/assets/beancount-BwXTMy5W.js +1 -0
  22. package/dist/web/assets/berry-3xVqZejG.js +1 -0
  23. package/dist/web/assets/bibtex-xW4inM5L.js +1 -0
  24. package/dist/web/assets/bicep-DHo0CJ0O.js +1 -0
  25. package/dist/web/assets/blade-a8OxSdnT.js +1 -0
  26. package/dist/web/assets/bsl-Dgyn0ogV.js +1 -0
  27. package/dist/web/assets/c-C3t2pwGQ.js +1 -0
  28. package/dist/web/assets/cadence-DNquZEk8.js +1 -0
  29. package/dist/web/assets/cairo--RitsXJZ.js +1 -0
  30. package/dist/web/assets/catppuccin-frappe-CD_QflpE.js +1 -0
  31. package/dist/web/assets/catppuccin-latte-DRW-0cLl.js +1 -0
  32. package/dist/web/assets/catppuccin-macchiato-C-_shW-Y.js +1 -0
  33. package/dist/web/assets/catppuccin-mocha-LGGdnPYs.js +1 -0
  34. package/dist/web/assets/chart-8DxAnLoD.js +73 -0
  35. package/dist/web/assets/clarity-BHOwM8T6.js +1 -0
  36. package/dist/web/assets/clojure-DxSadP1t.js +1 -0
  37. package/dist/web/assets/cmake-DbXoA79R.js +1 -0
  38. package/dist/web/assets/cobol-PTqiYgYu.js +1 -0
  39. package/dist/web/assets/code-block-cx7LPXvE.js +13 -0
  40. package/dist/web/assets/codeowners-Bp6g37R7.js +1 -0
  41. package/dist/web/assets/codeql-sacFqUAJ.js +1 -0
  42. package/dist/web/assets/coffee-dyiR41kL.js +1 -0
  43. package/dist/web/assets/common-lisp-C7gG9l05.js +1 -0
  44. package/dist/web/assets/coq-Dsg_Bt_b.js +1 -0
  45. package/dist/web/assets/cpp-BksuvNSY.js +1 -0
  46. package/dist/web/assets/crystal-DtDmRg-F.js +1 -0
  47. package/dist/web/assets/csharp-D9R-vmeu.js +1 -0
  48. package/dist/web/assets/css-BPhBrDlE.js +1 -0
  49. package/dist/web/assets/csv-B0qRVHPH.js +1 -0
  50. package/dist/web/assets/cue-DtFQj3wx.js +1 -0
  51. package/dist/web/assets/cypher-m2LEI-9-.js +1 -0
  52. package/dist/web/assets/d-BoXegm-a.js +1 -0
  53. package/dist/web/assets/dark-plus-C3mMm8J8.js +1 -0
  54. package/dist/web/assets/dart-B9wLZaAG.js +1 -0
  55. package/dist/web/assets/dax-ClGRhx96.js +1 -0
  56. package/dist/web/assets/desktop-DEIpsLCJ.js +1 -0
  57. package/dist/web/assets/diff-BgYniUM_.js +1 -0
  58. package/dist/web/assets/docker-COcR7UxN.js +1 -0
  59. package/dist/web/assets/dotenv-BjQB5zDj.js +1 -0
  60. package/dist/web/assets/dracula-BzJJZx-M.js +1 -0
  61. package/dist/web/assets/dracula-soft-BXkSAIEj.js +1 -0
  62. package/dist/web/assets/dream-maker-C-nORZOA.js +1 -0
  63. package/dist/web/assets/edge-D5gP-w-T.js +1 -0
  64. package/dist/web/assets/elixir-CLiX3zqd.js +1 -0
  65. package/dist/web/assets/elm-CmHSxxaM.js +1 -0
  66. package/dist/web/assets/emacs-lisp-BX77sIaO.js +1 -0
  67. package/dist/web/assets/erb-BYTLMnw6.js +1 -0
  68. package/dist/web/assets/erlang-B-DoSBHF.js +1 -0
  69. package/dist/web/assets/everforest-dark-BgDCqdQA.js +1 -0
  70. package/dist/web/assets/everforest-light-C8M2exoo.js +1 -0
  71. package/dist/web/assets/fennel-bCA53EVm.js +1 -0
  72. package/dist/web/assets/fish-w-ucz2PV.js +1 -0
  73. package/dist/web/assets/fluent-Dayu4EKP.js +1 -0
  74. package/dist/web/assets/fortran-fixed-form-TqA4NnZg.js +1 -0
  75. package/dist/web/assets/fortran-free-form-DKXYxT9g.js +1 -0
  76. package/dist/web/assets/fsharp-XplgxFYe.js +1 -0
  77. package/dist/web/assets/gdresource-BHYsBjWJ.js +1 -0
  78. package/dist/web/assets/gdscript-DfxzS6Rs.js +1 -0
  79. package/dist/web/assets/gdshader-SKMF96pI.js +1 -0
  80. package/dist/web/assets/genie-ajMbGru0.js +1 -0
  81. package/dist/web/assets/gherkin--30QC5Em.js +1 -0
  82. package/dist/web/assets/git-commit-i4q6IMui.js +1 -0
  83. package/dist/web/assets/git-rebase-B-v9cOL2.js +1 -0
  84. package/dist/web/assets/github-dark-DHJKELXO.js +1 -0
  85. package/dist/web/assets/github-dark-default-Cuk6v7N8.js +1 -0
  86. package/dist/web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  87. package/dist/web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  88. package/dist/web/assets/github-light-DAi9KRSo.js +1 -0
  89. package/dist/web/assets/github-light-default-D7oLnXFd.js +1 -0
  90. package/dist/web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  91. package/dist/web/assets/gleam-B430Bg39.js +1 -0
  92. package/dist/web/assets/glimmer-js-D-cwc0-E.js +1 -0
  93. package/dist/web/assets/glimmer-ts-pgjy16dm.js +1 -0
  94. package/dist/web/assets/glsl-DBO2IWDn.js +1 -0
  95. package/dist/web/assets/gnuplot-CM8KxXT1.js +1 -0
  96. package/dist/web/assets/go-B1SYOhNW.js +1 -0
  97. package/dist/web/assets/graphql-cDcHW_If.js +1 -0
  98. package/dist/web/assets/groovy-DkBy-JyN.js +1 -0
  99. package/dist/web/assets/hack-D1yCygmZ.js +1 -0
  100. package/dist/web/assets/haml-B2EZWmdv.js +1 -0
  101. package/dist/web/assets/handlebars-BQGss363.js +1 -0
  102. package/dist/web/assets/haskell-BILxekzW.js +1 -0
  103. package/dist/web/assets/haxe-C5wWYbrZ.js +1 -0
  104. package/dist/web/assets/hcl-HzYwdGDm.js +1 -0
  105. package/dist/web/assets/hjson-T-Tgc4AT.js +1 -0
  106. package/dist/web/assets/hlsl-ifBTmRxC.js +1 -0
  107. package/dist/web/assets/houston-DnULxvSX.js +1 -0
  108. package/dist/web/assets/html-C2L_23MC.js +1 -0
  109. package/dist/web/assets/html-derivative-CSfWNPLT.js +1 -0
  110. package/dist/web/assets/http-FRrOvY1W.js +1 -0
  111. package/dist/web/assets/hxml-TIA70rKU.js +1 -0
  112. package/dist/web/assets/hy-BMj5Y0dO.js +1 -0
  113. package/dist/web/assets/imba-bv_oIlVt.js +1 -0
  114. package/dist/web/assets/index-CeLShda7.css +1 -0
  115. package/dist/web/assets/index-Dp4QwEl0.js +8608 -0
  116. package/dist/web/assets/{index.es-DZEdTXNJ.js → index.es-C-uXEdZB.js} +1 -1
  117. package/dist/web/assets/ini-BjABl1g7.js +1 -0
  118. package/dist/web/assets/java-xI-RfyKK.js +1 -0
  119. package/dist/web/assets/javascript-ySlJ1b_l.js +1 -0
  120. package/dist/web/assets/jinja-DGy0s7-h.js +1 -0
  121. package/dist/web/assets/jison-BqZprYcd.js +1 -0
  122. package/dist/web/assets/json-BQoSv7ci.js +1 -0
  123. package/dist/web/assets/json5-w8dY5SsB.js +1 -0
  124. package/dist/web/assets/jsonc-TU54ms6u.js +1 -0
  125. package/dist/web/assets/jsonl-DREVFZK8.js +1 -0
  126. package/dist/web/assets/jsonnet-BfivnA6A.js +1 -0
  127. package/dist/web/assets/{jspdf.es.min-DT1Li8zz.js → jspdf.es.min-BFQufOcQ.js} +3 -3
  128. package/dist/web/assets/jssm-P4WzXJd0.js +1 -0
  129. package/dist/web/assets/jsx-BAng5TT0.js +1 -0
  130. package/dist/web/assets/julia-BBuGR-5E.js +1 -0
  131. package/dist/web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  132. package/dist/web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  133. package/dist/web/assets/kanagawa-wave-DWedfzmr.js +1 -0
  134. package/dist/web/assets/kotlin-B5lbUyaz.js +1 -0
  135. package/dist/web/assets/kusto-mebxcVVE.js +1 -0
  136. package/dist/web/assets/laserwave-DUszq2jm.js +1 -0
  137. package/dist/web/assets/latex-C-cWTeAZ.js +1 -0
  138. package/dist/web/assets/lean-XBlWyCtg.js +1 -0
  139. package/dist/web/assets/less-BfCpw3nA.js +1 -0
  140. package/dist/web/assets/light-plus-B7mTdjB0.js +1 -0
  141. package/dist/web/assets/liquid-D3W5UaiH.js +1 -0
  142. package/dist/web/assets/log-Cc5clBb7.js +1 -0
  143. package/dist/web/assets/logo-IuBKFhSY.js +1 -0
  144. package/dist/web/assets/lua-CvWAzNxB.js +1 -0
  145. package/dist/web/assets/luau-Du5NY7AG.js +1 -0
  146. package/dist/web/assets/make-Bvotw-X0.js +1 -0
  147. package/dist/web/assets/markdown-DK_1WFMa.js +1 -0
  148. package/dist/web/assets/markdown-UIAJJxZW.js +1 -0
  149. package/dist/web/assets/marko-z0MBrx5-.js +1 -0
  150. package/dist/web/assets/material-theme-D5KoaKCx.js +1 -0
  151. package/dist/web/assets/material-theme-darker-BfHTSMKl.js +1 -0
  152. package/dist/web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  153. package/dist/web/assets/material-theme-ocean-CyktbL80.js +1 -0
  154. package/dist/web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  155. package/dist/web/assets/matlab-D9-PGadD.js +1 -0
  156. package/dist/web/assets/mdc-DB_EDNY_.js +1 -0
  157. package/dist/web/assets/mdx-sdHcTMYB.js +1 -0
  158. package/dist/web/assets/mermaid-Ci6OQyBP.js +1 -0
  159. package/dist/web/assets/min-dark-CafNBF8u.js +1 -0
  160. package/dist/web/assets/min-light-CTRr51gU.js +1 -0
  161. package/dist/web/assets/mipsasm-BC5c_5Pe.js +1 -0
  162. package/dist/web/assets/mojo-Tz6hzZYG.js +1 -0
  163. package/dist/web/assets/monokai-D4h5O-jR.js +1 -0
  164. package/dist/web/assets/move-DB_GagMm.js +1 -0
  165. package/dist/web/assets/narrat-DLbgOhZU.js +1 -0
  166. package/dist/web/assets/nextflow-B0XVJmRM.js +1 -0
  167. package/dist/web/assets/nginx-D_VnBJ67.js +1 -0
  168. package/dist/web/assets/night-owl-C39BiMTA.js +1 -0
  169. package/dist/web/assets/nim-ZlGxZxc3.js +1 -0
  170. package/dist/web/assets/nix-shcSOmrb.js +1 -0
  171. package/dist/web/assets/nord-Ddv68eIx.js +1 -0
  172. package/dist/web/assets/nushell-D4Tzg5kh.js +1 -0
  173. package/dist/web/assets/objective-c-Deuh7S70.js +1 -0
  174. package/dist/web/assets/objective-cpp-BUEGK8hf.js +1 -0
  175. package/dist/web/assets/ocaml-BNioltXt.js +1 -0
  176. package/dist/web/assets/one-dark-pro-GBQ2dnAY.js +1 -0
  177. package/dist/web/assets/one-light-PoHY5YXO.js +1 -0
  178. package/dist/web/assets/pascal-JqZropPD.js +1 -0
  179. package/dist/web/assets/perl-CHQXSrWU.js +1 -0
  180. package/dist/web/assets/php-B5ebYQev.js +1 -0
  181. package/dist/web/assets/plastic-3e1v2bzS.js +1 -0
  182. package/dist/web/assets/plsql-LKU2TuZ1.js +1 -0
  183. package/dist/web/assets/po-BFLt1xDp.js +1 -0
  184. package/dist/web/assets/poimandres-CS3Unz2-.js +1 -0
  185. package/dist/web/assets/polar-DKykz6zU.js +1 -0
  186. package/dist/web/assets/postcss-B3ZDOciz.js +1 -0
  187. package/dist/web/assets/powerquery-CSHBycmS.js +1 -0
  188. package/dist/web/assets/powershell-BIEUsx6d.js +1 -0
  189. package/dist/web/assets/prisma-B48N-Iqd.js +1 -0
  190. package/dist/web/assets/prolog-BY-TUvya.js +1 -0
  191. package/dist/web/assets/proto-zocC4JxJ.js +1 -0
  192. package/dist/web/assets/pug-CM9l7STV.js +1 -0
  193. package/dist/web/assets/puppet-Cza_XSSt.js +1 -0
  194. package/dist/web/assets/purescript-Bg-kzb6g.js +1 -0
  195. package/dist/web/assets/python-DhUJRlN_.js +1 -0
  196. package/dist/web/assets/qml-D8XfuvdV.js +1 -0
  197. package/dist/web/assets/qmldir-C8lEn-DE.js +1 -0
  198. package/dist/web/assets/qss-DhMKtDLN.js +1 -0
  199. package/dist/web/assets/r-CwjWoCRV.js +1 -0
  200. package/dist/web/assets/racket-CzouJOBO.js +1 -0
  201. package/dist/web/assets/raku-B1bQXN8T.js +1 -0
  202. package/dist/web/assets/razor-CNLDkMZG.js +1 -0
  203. package/dist/web/assets/red-bN70gL4F.js +1 -0
  204. package/dist/web/assets/reg-5LuOXUq_.js +1 -0
  205. package/dist/web/assets/regexp-DWJ3fJO_.js +1 -0
  206. package/dist/web/assets/rel-DJlmqQ1C.js +1 -0
  207. package/dist/web/assets/riscv-QhoSD0DR.js +1 -0
  208. package/dist/web/assets/rose-pine-CmCqftbK.js +1 -0
  209. package/dist/web/assets/rose-pine-dawn-Ds-gbosJ.js +1 -0
  210. package/dist/web/assets/rose-pine-moon-CjDtw9vr.js +1 -0
  211. package/dist/web/assets/rst-4NLicBqY.js +1 -0
  212. package/dist/web/assets/ruby-DeZ3UC14.js +1 -0
  213. package/dist/web/assets/rust-Be6lgOlo.js +1 -0
  214. package/dist/web/assets/sas-BmTFh92c.js +1 -0
  215. package/dist/web/assets/sass-BJ4Li9vH.js +1 -0
  216. package/dist/web/assets/scala-DQVVAn-B.js +1 -0
  217. package/dist/web/assets/scheme-BJGe-b2p.js +1 -0
  218. package/dist/web/assets/scss-C31hgJw-.js +1 -0
  219. package/dist/web/assets/sdbl-BLhTXw86.js +1 -0
  220. package/dist/web/assets/shaderlab-B7qAK45m.js +1 -0
  221. package/dist/web/assets/shellscript-atvbtKCR.js +1 -0
  222. package/dist/web/assets/shellsession-C_rIy8kc.js +1 -0
  223. package/dist/web/assets/slack-dark-BthQWCQV.js +1 -0
  224. package/dist/web/assets/slack-ochin-DqwNpetd.js +1 -0
  225. package/dist/web/assets/smalltalk-DkLiglaE.js +1 -0
  226. package/dist/web/assets/snazzy-light-Bw305WKR.js +1 -0
  227. package/dist/web/assets/solarized-dark-DXbdFlpD.js +1 -0
  228. package/dist/web/assets/solarized-light-L9t79GZl.js +1 -0
  229. package/dist/web/assets/solidity-C1w2a3ep.js +1 -0
  230. package/dist/web/assets/soy-C-lX7w71.js +1 -0
  231. package/dist/web/assets/sparql-bYkjHRlG.js +1 -0
  232. package/dist/web/assets/splunk-Cf8iN4DR.js +1 -0
  233. package/dist/web/assets/sql-COK4E0Yg.js +1 -0
  234. package/dist/web/assets/ssh-config-BknIz3MU.js +1 -0
  235. package/dist/web/assets/stata-DorPZHa4.js +1 -0
  236. package/dist/web/assets/stylus-BeQkCIfX.js +1 -0
  237. package/dist/web/assets/svelte-MSaWC3Je.js +1 -0
  238. package/dist/web/assets/swift-BSxZ-RaX.js +1 -0
  239. package/dist/web/assets/synthwave-84-CbfX1IO0.js +1 -0
  240. package/dist/web/assets/system-verilog-C7L56vO4.js +1 -0
  241. package/dist/web/assets/systemd-CUnW07Te.js +1 -0
  242. package/dist/web/assets/talonscript-C1XDQQGZ.js +1 -0
  243. package/dist/web/assets/tasl-CQjiPCtT.js +1 -0
  244. package/dist/web/assets/tcl-DQ1-QYvQ.js +1 -0
  245. package/dist/web/assets/templ-dwX3ZSMB.js +1 -0
  246. package/dist/web/assets/terraform-BbSNqyBO.js +1 -0
  247. package/dist/web/assets/tex-rYs2v40G.js +1 -0
  248. package/dist/web/assets/tokyo-night-DBQeEorK.js +1 -0
  249. package/dist/web/assets/toml-CB2ApiWb.js +1 -0
  250. package/dist/web/assets/ts-tags-CipyTH0X.js +1 -0
  251. package/dist/web/assets/tsv-B_m7g4N7.js +1 -0
  252. package/dist/web/assets/tsx-B6W0miNI.js +1 -0
  253. package/dist/web/assets/turtle-BMR_PYu6.js +1 -0
  254. package/dist/web/assets/twig-NC5TFiHP.js +1 -0
  255. package/dist/web/assets/typescript-Dj6nwHGl.js +1 -0
  256. package/dist/web/assets/typespec-BpWG_bgh.js +1 -0
  257. package/dist/web/assets/typst-BVUVsWT6.js +1 -0
  258. package/dist/web/assets/v-CAQ2eGtk.js +1 -0
  259. package/dist/web/assets/vala-BFOHcciG.js +1 -0
  260. package/dist/web/assets/vb-CdO5JTpU.js +1 -0
  261. package/dist/web/assets/verilog-CJaU5se_.js +1 -0
  262. package/dist/web/assets/vesper-BEBZ7ncR.js +1 -0
  263. package/dist/web/assets/vhdl-DYoNaHQp.js +1 -0
  264. package/dist/web/assets/viml-m4uW47V2.js +1 -0
  265. package/dist/web/assets/vitesse-black-Bkuqu6BP.js +1 -0
  266. package/dist/web/assets/vitesse-dark-D0r3Knsf.js +1 -0
  267. package/dist/web/assets/vitesse-light-CVO1_9PV.js +1 -0
  268. package/dist/web/assets/vue-BuYVFjOK.js +1 -0
  269. package/dist/web/assets/vue-html-xdeiXROB.js +1 -0
  270. package/dist/web/assets/vyper-nyqBNV6O.js +1 -0
  271. package/dist/web/assets/wasm-C6j12Q_x.js +1 -0
  272. package/dist/web/assets/wasm-CG6Dc4jp.js +1 -0
  273. package/dist/web/assets/wenyan-7A4Fjokl.js +1 -0
  274. package/dist/web/assets/wgsl-CB0Krxn9.js +1 -0
  275. package/dist/web/assets/wikitext-DCE3LsBG.js +1 -0
  276. package/dist/web/assets/wolfram-C3FkfJm5.js +1 -0
  277. package/dist/web/assets/xml-e3z08dGr.js +1 -0
  278. package/dist/web/assets/xsl-Dd0NUgwM.js +1 -0
  279. package/dist/web/assets/yaml-CVw76BM1.js +1 -0
  280. package/dist/web/assets/zenscript-HnGAYVZD.js +1 -0
  281. package/dist/web/assets/zig-BVz_zdnA.js +1 -0
  282. package/dist/web/index.html +2 -2
  283. package/examples/component-showcase/README.md +29 -0
  284. package/examples/component-showcase/flow.json +40 -0
  285. package/examples/component-showcase/nodes/chart/spec.json +66 -0
  286. package/examples/component-showcase/nodes/counter/spec.json +57 -0
  287. package/examples/component-showcase/nodes/fetcher/actions/refresh.ts +35 -0
  288. package/examples/component-showcase/nodes/fetcher/spec.json +68 -0
  289. package/examples/component-showcase/nodes/form/spec.json +87 -0
  290. package/examples/component-showcase/package.json +6 -0
  291. package/examples/component-showcase/style.json +28 -0
  292. package/examples/ecommerce-platform/flow.json +28 -30
  293. package/examples/order-pipeline/flow.json +16 -16
  294. package/package.json +2 -1
  295. package/src/api.ts +73 -23
  296. package/src/cli-e2e.ts +6 -7
  297. package/src/cli-manifest.ts +3 -5
  298. package/src/cli.ts +27 -0
  299. package/src/component-action-runner.ts +188 -0
  300. package/src/component-spec-resolver.ts +60 -0
  301. package/src/diagram.ts +8 -5
  302. package/src/layout.ts +23 -26
  303. package/src/mcp.ts +2 -2
  304. package/src/merge.ts +8 -3
  305. package/src/node-files.ts +1 -1
  306. package/src/operations.ts +109 -52
  307. package/src/runtime.ts +37 -0
  308. package/src/schema-catalog.ts +23 -11
  309. package/src/schema.ts +256 -262
  310. package/src/server.ts +1 -1
  311. package/src/status-runner.ts +2 -1
  312. package/src/watcher.ts +46 -10
  313. package/dist/web/assets/index-BAEA18IR.js +0 -7838
  314. package/dist/web/assets/index-CwfFCUzZ.css +0 -1
package/src/operations.ts CHANGED
@@ -11,6 +11,7 @@ import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSyn
11
11
  import { dirname, isAbsolute, join } from 'node:path';
12
12
  import { type ZodIssue, z } from 'zod';
13
13
  import { writeFileAtomic } from './atomic-write.ts';
14
+ import { inlineComponentSpecs } from './component-spec-resolver.ts';
14
15
  import { type LayoutOptions, computeLayout } from './layout.ts';
15
16
  import { mergeFlowAndStyle, splitFlow } from './merge.ts';
16
17
  import {
@@ -24,13 +25,14 @@ import {
24
25
  import type { Registry } from './registry.ts';
25
26
  import {
26
27
  ColorTokenSchema,
28
+ ComponentSpecSchema,
27
29
  EdgePinSchema,
28
30
  type Flow,
29
31
  FlowSchema,
32
+ NodeTypeSchema,
30
33
  PlayActionSchema,
31
34
  type ResolvedFlow,
32
35
  ResolvedFlowSchema,
33
- ShapeKindSchema,
34
36
  SourceHandleIdSchema,
35
37
  StateSourceSchema,
36
38
  StatusActionSchema,
@@ -82,25 +84,16 @@ export type ReorderBody = z.infer<typeof ReorderBodySchema>;
82
84
  // other key lands inside node.data. Final validity is enforced by re-parsing
83
85
  // the whole demo through ResolvedFlowSchema after the merge — this body schema just
84
86
  // rejects unknown top-level keys to catch typos.
85
- const NodeTypeSchema = z.enum([
86
- 'playNode',
87
- 'stateNode',
88
- 'shapeNode',
89
- 'imageNode',
90
- 'iconNode',
91
- 'htmlNode',
92
- ]);
93
-
94
87
  export const NodePatchBodySchema = z
95
88
  .object({
96
89
  // When supplied AND different from the node's current type, the merged
97
90
  // node is reclassified in place: data keys not allowed on the new type's
98
91
  // FlowDataSchema are stripped, visuals (which route to style.json) are
99
92
  // preserved, and the post-merge ResolvedFlowSchema reparse enforces the
100
- // new type's required fields (e.g. stateNode playNode without a
101
- // playAction in the same body surfaces as `badSchema`). The per-node
102
- // folder under `nodes/<id>/` is keyed by id, so retype keeps scripts,
103
- // detail.md, and view.html attached.
93
+ // new type's required fields (e.g. type:'image' without a `path` in the
94
+ // same body surfaces as `badSchema`). The per-node folder under
95
+ // `nodes/<id>/` is keyed by id, so retype keeps scripts, detail.md, and
96
+ // view.html attached.
104
97
  type: NodeTypeSchema.optional(),
105
98
  position: PositionBodySchema.optional(),
106
99
  name: z.string().optional(),
@@ -114,22 +107,22 @@ export const NodePatchBodySchema = z
114
107
  cornerRadius: z.number().min(0).optional(),
115
108
  width: z.number().positive().optional(),
116
109
  height: z.number().positive().optional(),
117
- // htmlNode-only: when true, the renderer measures content and React Flow
110
+ // type:'html'-only: when true, the renderer measures content and React Flow
118
111
  // sizes the wrapper around it. mergeNodeUpdates enforces the invariant
119
112
  // that autoSize:true never coexists with persisted width/height.
120
113
  autoSize: z.boolean().optional(),
121
- shape: ShapeKindSchema.optional(),
122
- // iconNode-only: stroke color token. Lands at data.color; ResolvedFlowSchema's
123
- // post-merge reparse gates that this is only valid on an iconNode.
114
+ // type:'icon'-only: stroke color token. Lands at data.color; the
115
+ // post-merge ResolvedFlowSchema reparse gates that this is only valid on
116
+ // type:'icon'.
124
117
  color: ColorTokenSchema.optional(),
125
- // iconNode-only: glyph stroke width. Lands at data.strokeWidth; the
118
+ // type:'icon'-only: glyph stroke width. Lands at data.strokeWidth; the
126
119
  // post-merge reparse gates the [0.5, 4] bound and arm validity.
127
120
  strokeWidth: z.number().min(0.5).max(4).optional(),
128
- // iconNode-only: accessible alt text for the icon. Lands at data.alt.
121
+ // type:'icon'/type:'image'-only: accessible alt text. Lands at data.alt.
129
122
  alt: z.string().optional(),
130
123
  // kebab-case Lucide icon name. Lands at data.icon. The post-merge reparse
131
124
  // enforces the schema's `.min(1)` non-empty rule for nodes that require
132
- // icon (iconNode), and gates which variants allow it. Explicit `null`
125
+ // icon (type:'icon'), and gates which variants allow it. Explicit `null`
133
126
  // clears the field (mergeNodeUpdates strips the key from disk) — mirrors
134
127
  // the empty-string clear convention used for description / detail.
135
128
  icon: z.string().min(1).nullable().optional(),
@@ -138,17 +131,24 @@ export const NodePatchBodySchema = z
138
131
  // serialize signal — `mergeNodeUpdates` strips the key from disk.
139
132
  description: z.string().optional(),
140
133
  detail: z.string().optional(),
141
- // htmlNode-only: inline HTML content. Externalized to
134
+ // type:'html'-only: inline HTML content. Externalized to
142
135
  // `<project>/nodes/<id>/view.html` by patchNodeImpl; the file:// ref on
143
136
  // the node persists. Empty string empties the file but keeps the ref.
144
137
  html: z.string().optional(),
145
- // P5 overlay attach: lets the skill (or any consumer) wire executable
146
- // behaviour onto a previously-created node without re-issuing it. Final
147
- // validity is enforced by the post-merge ResolvedFlowSchema reparse
148
- // e.g. statusAction is only valid on playNode / stateNode.
138
+ // Capability attach: lets the skill (or any consumer) wire executable
139
+ // behaviour onto a previously-created node without re-issuing it. All
140
+ // capabilities are valid on every node type presence drives renderer
141
+ // chrome. Final validity is enforced by the post-merge
142
+ // ResolvedFlowSchema reparse.
149
143
  playAction: PlayActionSchema.optional(),
150
144
  statusAction: StatusActionSchema.optional(),
151
145
  stateSource: StateSourceSchema.optional(),
146
+ // type:'component'-only: json-render spec describing the reactive UI.
147
+ // Externalized to `<project>/nodes/<id>/spec.json` by patchNodeImpl; the
148
+ // in-memory ResolvedFlow keeps `data.spec` populated for the post-merge
149
+ // reparse + SSE broadcast, but splitFlow strips it from flow.json so the
150
+ // sidecar is the source of truth on disk.
151
+ spec: ComponentSpecSchema.optional(),
152
152
  })
153
153
  .strict();
154
154
  export type NodePatchBody = z.infer<typeof NodePatchBodySchema>;
@@ -170,7 +170,6 @@ const NODE_DATA_PATCH_KEYS = [
170
170
  'width',
171
171
  'height',
172
172
  'autoSize',
173
- 'shape',
174
173
  'color',
175
174
  'strokeWidth',
176
175
  'alt',
@@ -181,6 +180,7 @@ const NODE_DATA_PATCH_KEYS = [
181
180
  'playAction',
182
181
  'statusAction',
183
182
  'stateSource',
183
+ 'spec',
184
184
  ] as const satisfies ReadonlyArray<keyof NodePatchBody>;
185
185
 
186
186
  const EXTERNALIZED_FIELD_NAMES = new Set<string>(EXTERNALIZED_NODE_FIELDS.map((e) => e.field));
@@ -190,35 +190,67 @@ const EXTERNALIZED_FIELD_NAMES = new Set<string>(EXTERNALIZED_NODE_FIELDS.map((e
190
190
  // they route to style.json on write. Everything else gets stripped from
191
191
  // `data` when a node changes type so the post-merge ResolvedFlowSchema reparse
192
192
  // doesn't reject lingering fields from the previous variant. Missing required
193
- // fields on the new type (e.g. stateNode playNode without playAction)
193
+ // fields on the new type (e.g. retype to type:'image' without a `path`)
194
194
  // surface as the normal `badSchema` outcome from the reparse.
195
+ const GEOMETRIC_SEMANTIC_KEYS: ReadonlySet<string> = new Set([
196
+ 'name',
197
+ 'description',
198
+ 'detail',
199
+ 'icon',
200
+ 'stateSource',
201
+ 'handlerModule',
202
+ 'playAction',
203
+ 'statusAction',
204
+ ]);
205
+
195
206
  const SEMANTIC_KEYS_BY_TYPE: Record<z.infer<typeof NodeTypeSchema>, ReadonlySet<string>> = {
196
- playNode: new Set([
207
+ rectangle: GEOMETRIC_SEMANTIC_KEYS,
208
+ ellipse: GEOMETRIC_SEMANTIC_KEYS,
209
+ sticky: GEOMETRIC_SEMANTIC_KEYS,
210
+ text: GEOMETRIC_SEMANTIC_KEYS,
211
+ database: GEOMETRIC_SEMANTIC_KEYS,
212
+ server: GEOMETRIC_SEMANTIC_KEYS,
213
+ user: GEOMETRIC_SEMANTIC_KEYS,
214
+ queue: GEOMETRIC_SEMANTIC_KEYS,
215
+ cloud: GEOMETRIC_SEMANTIC_KEYS,
216
+ image: new Set([
197
217
  'name',
198
- 'kind',
199
- 'stateSource',
200
- 'handlerModule',
201
- 'icon',
202
218
  'description',
203
219
  'detail',
220
+ 'icon',
221
+ 'stateSource',
222
+ 'handlerModule',
204
223
  'playAction',
205
224
  'statusAction',
225
+ 'path',
226
+ 'alt',
206
227
  ]),
207
- stateNode: new Set([
228
+ html: new Set([
208
229
  'name',
209
- 'kind',
230
+ 'description',
231
+ 'detail',
232
+ 'icon',
210
233
  'stateSource',
211
234
  'handlerModule',
212
- 'icon',
235
+ 'playAction',
236
+ 'statusAction',
237
+ 'html',
238
+ ]),
239
+ icon: new Set([
240
+ 'name',
213
241
  'description',
214
242
  'detail',
243
+ 'icon',
244
+ 'stateSource',
245
+ 'handlerModule',
215
246
  'playAction',
216
247
  'statusAction',
248
+ 'alt',
217
249
  ]),
218
- shapeNode: new Set(['shape', 'name', 'description', 'detail']),
219
- imageNode: new Set(['path', 'alt', 'description', 'detail']),
220
- iconNode: new Set(['icon', 'alt', 'name', 'description', 'detail']),
221
- htmlNode: new Set(['html', 'name', 'icon', 'description', 'detail']),
250
+ // Component nodes externalize `spec` to <project>/nodes/<id>/spec.json; the
251
+ // semantic-key set covers only the universal capability fields so retype
252
+ // never drags `spec` through `data`. (US-007 wires the sidecar writer.)
253
+ component: GEOMETRIC_SEMANTIC_KEYS,
222
254
  };
223
255
 
224
256
  // Visual data keys — routed to style.json on write by splitFlow. Kept here
@@ -288,7 +320,7 @@ export const mergeNodeUpdates = (node: Record<string, unknown>, updates: NodePat
288
320
  // doesn't reject lingering fields. The per-node folder under
289
321
  // `nodes/<id>/` is keyed by id (unchanged), so scripts and externalized
290
322
  // files stay attached. Missing required fields on the new type (e.g.
291
- // stateNode playNode without a playAction in the same patch) surface as
323
+ // retype to type:'image' without a `path` in the same patch) surface as
292
324
  // `badSchema` from the ResolvedFlowSchema reparse.
293
325
  if (updates.type !== undefined && updates.type !== node.type) {
294
326
  node.type = updates.type;
@@ -302,12 +334,13 @@ export const mergeNodeUpdates = (node: Record<string, unknown>, updates: NodePat
302
334
  }
303
335
  }
304
336
 
305
- // htmlNode-only invariant enforcement:
337
+ // type:'html' + type:'component' invariant enforcement:
306
338
  // autoSize === true ⊻ (width and height set).
307
339
  // autoSize: true is the dominant signal — it strips width/height even if
308
340
  // the same patch tried to write them. Writing width/height implicitly
309
- // flips autoSize to false.
310
- if (node.type === 'htmlNode') {
341
+ // flips autoSize to false. Both node types default to autoSize:true in the
342
+ // renderer and share the same shrink-wrap-to-content mechanism.
343
+ if (node.type === 'html' || node.type === 'component') {
311
344
  // The autoSize invariant requires `width`/`height` to be ABSENT from the
312
345
  // serialized JSON when autoSize is true — not present with value
313
346
  // `undefined` (which would serialize as a stray `"width": null` or get
@@ -389,7 +422,7 @@ export type GetFlowOutcome =
389
422
  | { kind: 'fileNotFound'; path: string };
390
423
 
391
424
  // Lightweight graph projection — flow + nodes + connectors with file-backed
392
- // fields (`detail` on every node, `html` on htmlNode) stripped so the
425
+ // fields (`detail` on every node, `html` on type:'html') stripped so the
393
426
  // caller can navigate the topology without paying for inlined bodies.
394
427
  export interface FlowGraphResponse {
395
428
  id: string;
@@ -738,7 +771,16 @@ export async function mutateMergedFlow<E extends { kind: string }>(
738
771
  const styleParse = StyleSchema.safeParse(read.rawStyle);
739
772
  if (!styleParse.success) return { kind: 'badSchema', issues: styleParse.error.issues };
740
773
 
741
- const merged = mergeFlowAndStyle(flowParse.data, styleParse.data) as unknown as {
774
+ // Inline component spec sidecars (<project>/nodes/<id>/spec.json) before the
775
+ // mutator runs so the post-mutation ResolvedFlowSchema parse sees `data.spec`
776
+ // on every existing component node. splitFlow strips `spec` back out before
777
+ // we write flow.json, keeping the sidecar as the on-disk source of truth.
778
+ const projectRoot = dirname(flowPath);
779
+ const { flow: inlinedFlow } = inlineComponentSpecs(
780
+ mergeFlowAndStyle(flowParse.data, styleParse.data),
781
+ projectRoot,
782
+ );
783
+ const merged = inlinedFlow as unknown as {
742
784
  version: number;
743
785
  name: string;
744
786
  resetAction?: unknown;
@@ -1141,6 +1183,9 @@ export async function createProjectImpl(
1141
1183
  try {
1142
1184
  mkdirSync(folderPath, { recursive: true });
1143
1185
  writeFileSync(demoFullPath, `${JSON.stringify(scaffold, null, 2)}\n`);
1186
+ const tmpDir = join(folderPath, '.tmp');
1187
+ mkdirSync(tmpDir, { recursive: true });
1188
+ writeFileSync(join(tmpDir, '.gitignore'), '*\n!.gitignore\n');
1144
1189
  } catch (err) {
1145
1190
  return { kind: 'scaffoldFailed', message: err instanceof Error ? err.message : String(err) };
1146
1191
  }
@@ -1378,7 +1423,7 @@ export async function addFlowBulkImpl(
1378
1423
  // schema violation surfaces honestly instead of being silently papered over.
1379
1424
  // After the flow.json write, `removeNodeDir` cascades the node's whole
1380
1425
  // `<project>/nodes/<id>/` folder — covering detail.md, view.html, and any
1381
- // imageNode upload that lived there.
1426
+ // type:'image' upload that lived there.
1382
1427
  export async function deleteNodeImpl(
1383
1428
  deps: OperationsDeps,
1384
1429
  flowId: string,
@@ -1510,6 +1555,22 @@ export async function patchNodeImpl(
1510
1555
  }
1511
1556
  node.data = data;
1512
1557
  }
1558
+ // Component spec sidecar — write the pretty-printed JSON to
1559
+ // `<project>/nodes/<id>/spec.json` so the on-disk source of truth stays
1560
+ // in sync. mergeNodeUpdates already put data.spec on the merged tree for
1561
+ // the post-mutation ResolvedFlowSchema parse; splitFlow strips it from
1562
+ // flow.json so we don't double-store the spec.
1563
+ if (node.type === 'component' && updates.spec !== undefined) {
1564
+ const specAbs = nodeFileAbsPath(entry.repoPath, nodeId, 'spec.json');
1565
+ try {
1566
+ writeNodeFile(specAbs, `${JSON.stringify(updates.spec, null, 2)}\n`);
1567
+ } catch (err) {
1568
+ return {
1569
+ kind: 'writeFailed',
1570
+ message: err instanceof Error ? err.message : String(err),
1571
+ };
1572
+ }
1573
+ }
1513
1574
  return { kind: 'ok' };
1514
1575
  });
1515
1576
  }
@@ -1765,11 +1826,7 @@ export async function applyLayoutImpl(
1765
1826
 
1766
1827
  const flow = flowParse.data;
1767
1828
  const result = await computeLayout(
1768
- flow.nodes.map((n) => ({
1769
- id: n.id,
1770
- type: n.type,
1771
- data: n.type === 'shapeNode' ? { shape: (n.data as { shape?: string }).shape } : undefined,
1772
- })),
1829
+ flow.nodes.map((n) => ({ id: n.id, type: n.type })),
1773
1830
  flow.connectors.map((c) => ({ id: c.id, source: c.source, target: c.target })),
1774
1831
  options,
1775
1832
  );
package/src/runtime.ts CHANGED
@@ -76,3 +76,40 @@ export function isPidAlive(pid: number): boolean {
76
76
  return false;
77
77
  }
78
78
  }
79
+
80
+ // `0.0.0.0` / `::` are wildcard bind addresses, not connectable destinations —
81
+ // probe loopback when the caller passes one. IPv6 unspecified `::` maps to
82
+ // `::1`; everything else is treated as IPv4 wildcard → `127.0.0.1`.
83
+ function probeHost(host: string): string {
84
+ if (host === '::' || host === '[::]') return '::1';
85
+ if (host === '0.0.0.0' || host === '') return '127.0.0.1';
86
+ return host;
87
+ }
88
+
89
+ /**
90
+ * Detects whether a TCP listener is responding on host:port. Uses a short
91
+ * connect probe (300 ms default) so we catch actively-listening servers
92
+ * without padding fast paths. Returns false on any connect error or timeout.
93
+ */
94
+ export async function portInUse(host: string, port: number, timeoutMs = 300): Promise<boolean> {
95
+ const hostname = probeHost(host);
96
+ let timer: ReturnType<typeof setTimeout> | undefined;
97
+ try {
98
+ const socket = await Promise.race([
99
+ Bun.connect({
100
+ hostname,
101
+ port,
102
+ socket: { data() {}, open() {}, close() {}, error() {} },
103
+ }),
104
+ new Promise<never>((_, reject) => {
105
+ timer = setTimeout(() => reject(new Error('timeout')), timeoutMs);
106
+ }),
107
+ ]);
108
+ socket.end();
109
+ return true;
110
+ } catch {
111
+ return false;
112
+ } finally {
113
+ if (timer) clearTimeout(timer);
114
+ }
115
+ }
@@ -8,14 +8,20 @@
8
8
  import type { ZodTypeAny } from 'zod';
9
9
  import { zodToJsonSchema } from 'zod-to-json-schema';
10
10
  import {
11
+ FlowCloudNodeSchema,
11
12
  FlowConnectorSchema,
13
+ FlowDatabaseNodeSchema,
14
+ FlowEllipseNodeSchema,
12
15
  FlowEnvelopeSchema,
13
16
  FlowHtmlNodeSchema,
14
17
  FlowIconNodeSchema,
15
18
  FlowImageNodeSchema,
16
- FlowPlayNodeSchema,
17
- FlowShapeNodeSchema,
18
- FlowStateNodeSchema,
19
+ FlowQueueNodeSchema,
20
+ FlowRectangleNodeSchema,
21
+ FlowServerNodeSchema,
22
+ FlowStickyNodeSchema,
23
+ FlowTextNodeSchema,
24
+ FlowUserNodeSchema,
19
25
  PlayActionSchema,
20
26
  ResetActionSchema,
21
27
  StatusActionSchema,
@@ -44,7 +50,7 @@ const CATEGORIES: SchemaCategory[] = [
44
50
  {
45
51
  name: 'node',
46
52
  description:
47
- 'All six node variants (playNode, stateNode, shapeNode, imageNode, iconNode, htmlNode).',
53
+ 'All 12 flat node variants (rectangle, ellipse, sticky, text, database, server, user, queue, cloud, image, html, icon). Visual kind is the type; capabilities (playAction / statusAction / stateSource) are independent optional fields on every variant.',
48
54
  },
49
55
  {
50
56
  name: 'connector',
@@ -64,15 +70,21 @@ const PAYLOADS: Record<string, SchemaPayload> = {
64
70
  },
65
71
  node: {
66
72
  schemas: {
67
- playNode: toJsonSchema(FlowPlayNodeSchema),
68
- stateNode: toJsonSchema(FlowStateNodeSchema),
69
- shapeNode: toJsonSchema(FlowShapeNodeSchema),
70
- imageNode: toJsonSchema(FlowImageNodeSchema),
71
- iconNode: toJsonSchema(FlowIconNodeSchema),
72
- htmlNode: toJsonSchema(FlowHtmlNodeSchema),
73
+ rectangle: toJsonSchema(FlowRectangleNodeSchema),
74
+ ellipse: toJsonSchema(FlowEllipseNodeSchema),
75
+ sticky: toJsonSchema(FlowStickyNodeSchema),
76
+ text: toJsonSchema(FlowTextNodeSchema),
77
+ database: toJsonSchema(FlowDatabaseNodeSchema),
78
+ server: toJsonSchema(FlowServerNodeSchema),
79
+ user: toJsonSchema(FlowUserNodeSchema),
80
+ queue: toJsonSchema(FlowQueueNodeSchema),
81
+ cloud: toJsonSchema(FlowCloudNodeSchema),
82
+ image: toJsonSchema(FlowImageNodeSchema),
83
+ html: toJsonSchema(FlowHtmlNodeSchema),
84
+ icon: toJsonSchema(FlowIconNodeSchema),
73
85
  },
74
86
  notes: [
75
- "imageNode.data.path must start with 'nodes/<id>/'.",
87
+ "type:'image' data.path must start with 'nodes/<id>/'.",
76
88
  "scriptPath in playAction/statusAction is relative to nodes/<nodeId>/ and may not contain '..' or absolute paths.",
77
89
  ],
78
90
  },