@ultrst-armada/krnl 1.0.1 → 1.0.3

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 (235) hide show
  1. package/README.md +67 -65
  2. package/package.json +13 -9
  3. package/packages/cli/dist/bin/krnl.cjs +1535 -9508
  4. package/packages/cli/dist/bin/krnl.js +55 -1915
  5. package/packages/cli/dist/chunk-6SHSECXR.js +1628 -0
  6. package/packages/cli/dist/index.cjs +1244 -7373
  7. package/packages/cli/dist/index.d.cts +45 -2
  8. package/packages/cli/dist/index.d.ts +45 -2
  9. package/packages/cli/dist/index.js +5 -20
  10. package/packages/cli/package.json +17 -10
  11. package/packages/core/dist/index.cjs +3039 -141
  12. package/packages/core/dist/index.d.cts +633 -27
  13. package/packages/core/dist/index.d.ts +633 -27
  14. package/packages/core/dist/index.js +3028 -139
  15. package/packages/core/package.json +15 -7
  16. package/packages/create-krnl/dist/index.cjs +322 -316
  17. package/packages/create-krnl/dist/index.js +322 -316
  18. package/packages/create-krnl/package.json +5 -3
  19. package/packages/eslint-plugin/dist/index.cjs +17 -55
  20. package/packages/eslint-plugin/dist/index.d.cts +8 -43
  21. package/packages/eslint-plugin/dist/index.d.ts +8 -43
  22. package/packages/eslint-plugin/dist/index.js +17 -55
  23. package/packages/eslint-plugin/package.json +5 -4
  24. package/packages/validate/dist/index.cjs +692 -361
  25. package/packages/validate/dist/index.d.cts +12 -14
  26. package/packages/validate/dist/index.d.ts +12 -14
  27. package/packages/validate/dist/index.js +692 -361
  28. package/packages/validate/package.json +14 -7
  29. package/packages/cli/dist/K_ENT_Entity-PQ5MURQY-ZG6FZXXX.js +0 -13
  30. package/packages/cli/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW-K4CRQYA5.js +0 -8
  31. package/packages/cli/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF-LNPXZYOE.js +0 -110
  32. package/packages/cli/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF-3ALZPNX4.js +0 -11
  33. package/packages/cli/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X-PJTICYSW.js +0 -11
  34. package/packages/cli/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW-M5TYU55O.js +0 -8
  35. package/packages/cli/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2-H6STOXRK.js +0 -20
  36. package/packages/cli/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK-XPJXSF7D.js +0 -19
  37. package/packages/cli/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7-CUYGTWOW.js +0 -7
  38. package/packages/cli/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU-VR6T4N6J.js +0 -17
  39. package/packages/cli/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5-RLJ4QWDP.js +0 -58
  40. package/packages/cli/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF-BOQGUASC.js +0 -22
  41. package/packages/cli/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG-XJI7KIT5.js +0 -8
  42. package/packages/cli/dist/K_LIB_Krnl_Telemetry-77FRZ3KV-K5VCWAFW.js +0 -9
  43. package/packages/cli/dist/chunk-3TRM6CYL.js +0 -152
  44. package/packages/cli/dist/chunk-5JDK35TG.js +0 -3872
  45. package/packages/cli/dist/chunk-63PTK33I.js +0 -997
  46. package/packages/cli/dist/chunk-6NIKAMUZ.js +0 -82
  47. package/packages/cli/dist/chunk-BOXWWXQG.js +0 -400
  48. package/packages/cli/dist/chunk-EEKLK7QJ.js +0 -565
  49. package/packages/cli/dist/chunk-EG7T2IAD.js +0 -107
  50. package/packages/cli/dist/chunk-F5EHXE2O.js +0 -1036
  51. package/packages/cli/dist/chunk-F65ANSQG.js +0 -269
  52. package/packages/cli/dist/chunk-FDNCADFE.js +0 -71
  53. package/packages/cli/dist/chunk-GDLRMDAN.js +0 -127
  54. package/packages/cli/dist/chunk-HWMTCMOS.js +0 -656
  55. package/packages/cli/dist/chunk-I74QIQOD.js +0 -5536
  56. package/packages/cli/dist/chunk-JTLSTO25.js +0 -71
  57. package/packages/cli/dist/chunk-JULBBJ27.js +0 -1033
  58. package/packages/cli/dist/chunk-OHVMVRBP.js +0 -117
  59. package/packages/cli/dist/chunk-P2PCLEKX.js +0 -666
  60. package/packages/cli/dist/chunk-PJQIUOX2.js +0 -7767
  61. package/packages/cli/dist/chunk-PPOF3DJW.js +0 -471
  62. package/packages/cli/dist/chunk-Q45257P6.js +0 -173
  63. package/packages/cli/dist/chunk-QNROWGBI.js +0 -1036
  64. package/packages/cli/dist/chunk-RJNYUXZD.js +0 -977
  65. package/packages/cli/dist/chunk-SRTOPJ5W.js +0 -104
  66. package/packages/cli/dist/chunk-TCEX3MPS.js +0 -702
  67. package/packages/cli/dist/chunk-TNOAJO2J.js +0 -675
  68. package/packages/cli/dist/chunk-UR2SUCSF.js +0 -701
  69. package/packages/cli/dist/chunk-X5LOIFM7.js +0 -68
  70. package/packages/cli/dist/chunk-XIRFOO3H.js +0 -589
  71. package/packages/cli/dist/chunk-ZAAV3JXQ.js +0 -809
  72. package/packages/core/dist/K_ENT_Entity-4MB7CU4A.js +0 -12
  73. package/packages/core/dist/K_ENT_Entity-DEJGIDGH.js +0 -12
  74. package/packages/core/dist/K_ENT_Entity-FXZO5UZ2.js +0 -12
  75. package/packages/core/dist/K_ENT_Entity-HDSCXC5F.js +0 -12
  76. package/packages/core/dist/K_ENT_Entity-JILABHLW.js +0 -12
  77. package/packages/core/dist/K_ENT_Entity-PQ5MURQY.js +0 -13
  78. package/packages/core/dist/K_ENT_Entity-ROAKDIHW.js +0 -12
  79. package/packages/core/dist/K_ENT_Entity-TBVFSKDV.js +0 -12
  80. package/packages/core/dist/K_ENT_Entity-ZFLKG3JO.js +0 -12
  81. package/packages/core/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW.js +0 -8
  82. package/packages/core/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF.js +0 -110
  83. package/packages/core/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF.js +0 -9
  84. package/packages/core/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X.js +0 -9
  85. package/packages/core/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW.js +0 -8
  86. package/packages/core/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2.js +0 -20
  87. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-4C6GBQAG.js +0 -18
  88. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-6V23A6F6.js +0 -18
  89. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK.js +0 -19
  90. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-DYLLC5G2.js +0 -18
  91. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-F4FOFAUP.js +0 -18
  92. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-FBOXXMI3.js +0 -18
  93. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-Q73BWLNP.js +0 -18
  94. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-QM2C4MVA.js +0 -18
  95. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-QUGI6SMP.js +0 -18
  96. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-RGMTBHNP.js +0 -18
  97. package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-RWR7UNDW.js +0 -18
  98. package/packages/core/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7.js +0 -7
  99. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-32MFJJ5Z.js +0 -17
  100. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-4J4CEWRY.js +0 -17
  101. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-A366YHF2.js +0 -17
  102. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-LK4LYJHI.js +0 -17
  103. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU.js +0 -17
  104. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-NW3K63II.js +0 -17
  105. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-QDHTI5ZV.js +0 -17
  106. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-VHCT6VIW.js +0 -17
  107. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-WBRKF24R.js +0 -17
  108. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-XKYQYT6Q.js +0 -17
  109. package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-Z2PWZYDZ.js +0 -17
  110. package/packages/core/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5.js +0 -58
  111. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-2EZU7QF4.js +0 -21
  112. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-6G3AQNAV.js +0 -21
  113. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-B2NZMQUG.js +0 -21
  114. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-C2RABMZP.js +0 -21
  115. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-HHE3NZ4F.js +0 -21
  116. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-LHFGR6WK.js +0 -21
  117. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-M74BLM3N.js +0 -21
  118. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-PT6ZA6EA.js +0 -21
  119. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-SP52V3CX.js +0 -21
  120. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF.js +0 -22
  121. package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-YNSEUHJJ.js +0 -21
  122. package/packages/core/dist/K_LIB_Krnl_System_Unified_Http_Adapter-M6SBHIVA.js +0 -8
  123. package/packages/core/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG.js +0 -8
  124. package/packages/core/dist/K_LIB_Krnl_Telemetry-77FRZ3KV.js +0 -9
  125. package/packages/core/dist/chunk-33L2J7V7.js +0 -82
  126. package/packages/core/dist/chunk-3ES4K2ZP.js +0 -817
  127. package/packages/core/dist/chunk-3SMHVVLL.js +0 -82
  128. package/packages/core/dist/chunk-3UEZ7JQA.js +0 -4877
  129. package/packages/core/dist/chunk-3XIE6KBD.js +0 -4877
  130. package/packages/core/dist/chunk-46ZLCML6.js +0 -107
  131. package/packages/core/dist/chunk-4UEL3DWJ.js +0 -107
  132. package/packages/core/dist/chunk-54GWZ5PC.js +0 -82
  133. package/packages/core/dist/chunk-6QCYRS5L.js +0 -127
  134. package/packages/core/dist/chunk-6ULMHNXR.js +0 -104
  135. package/packages/core/dist/chunk-7WUETJEV.js +0 -117
  136. package/packages/core/dist/chunk-A5KRAYDB.js +0 -107
  137. package/packages/core/dist/chunk-ANEAZ3PO.js +0 -107
  138. package/packages/core/dist/chunk-BE76RL6F.js +0 -82
  139. package/packages/core/dist/chunk-CIARVYDO.js +0 -107
  140. package/packages/core/dist/chunk-CR2ANE62.js +0 -107
  141. package/packages/core/dist/chunk-DI27MOR7.js +0 -173
  142. package/packages/core/dist/chunk-E6RLFHM5.js +0 -596
  143. package/packages/core/dist/chunk-EELAPMNV.js +0 -4877
  144. package/packages/core/dist/chunk-ENZ2RQVJ.js +0 -107
  145. package/packages/core/dist/chunk-F2U6CX4F.js +0 -4877
  146. package/packages/core/dist/chunk-FKG64OHL.js +0 -82
  147. package/packages/core/dist/chunk-FYAZJYM5.js +0 -772
  148. package/packages/core/dist/chunk-G4NP4RDQ.js +0 -82
  149. package/packages/core/dist/chunk-GADIRLRS.js +0 -473
  150. package/packages/core/dist/chunk-GR6CSLQJ.js +0 -772
  151. package/packages/core/dist/chunk-HDS7AT6O.js +0 -772
  152. package/packages/core/dist/chunk-HIMEZUU2.js +0 -71
  153. package/packages/core/dist/chunk-IB4UHG5I.js +0 -596
  154. package/packages/core/dist/chunk-J7ZYNVRS.js +0 -772
  155. package/packages/core/dist/chunk-JVLZU4K7.js +0 -604
  156. package/packages/core/dist/chunk-JYXXI7Q3.js +0 -82
  157. package/packages/core/dist/chunk-K54K2KZW.js +0 -192
  158. package/packages/core/dist/chunk-K6VHLBNH.js +0 -3316
  159. package/packages/core/dist/chunk-KCBP7ZYA.js +0 -596
  160. package/packages/core/dist/chunk-KFQGP6VL.js +0 -33
  161. package/packages/core/dist/chunk-KIUEUI7K.js +0 -82
  162. package/packages/core/dist/chunk-LB67NIZP.js +0 -949
  163. package/packages/core/dist/chunk-LDTYFUNW.js +0 -596
  164. package/packages/core/dist/chunk-MLVWARD4.js +0 -596
  165. package/packages/core/dist/chunk-MPYVXHKO.js +0 -2777
  166. package/packages/core/dist/chunk-MRQ3MITU.js +0 -772
  167. package/packages/core/dist/chunk-MVUN7I7O.js +0 -107
  168. package/packages/core/dist/chunk-NDDOIRW7.js +0 -596
  169. package/packages/core/dist/chunk-O3KDB5MH.js +0 -3330
  170. package/packages/core/dist/chunk-OEINUDSE.js +0 -400
  171. package/packages/core/dist/chunk-OPDENPT4.js +0 -4877
  172. package/packages/core/dist/chunk-P6XEM2LA.js +0 -429
  173. package/packages/core/dist/chunk-QKMRSQV4.js +0 -82
  174. package/packages/core/dist/chunk-R6CCWALL.js +0 -4877
  175. package/packages/core/dist/chunk-RAMMOO73.js +0 -774
  176. package/packages/core/dist/chunk-S3FTZFG6.js +0 -772
  177. package/packages/core/dist/chunk-T2ZVN434.js +0 -4877
  178. package/packages/core/dist/chunk-TFHLDMIA.js +0 -107
  179. package/packages/core/dist/chunk-TI3QUCIJ.js +0 -107
  180. package/packages/core/dist/chunk-TR2BAIGI.js +0 -107
  181. package/packages/core/dist/chunk-UGVVJKC6.js +0 -4877
  182. package/packages/core/dist/chunk-V2DX7YIU.js +0 -984
  183. package/packages/core/dist/chunk-W4IHYUYD.js +0 -772
  184. package/packages/core/dist/chunk-W6WBG5OY.js +0 -4877
  185. package/packages/core/dist/chunk-WN3M7O7H.js +0 -3312
  186. package/packages/core/dist/chunk-WR3NCU7U.js +0 -4877
  187. package/packages/core/dist/chunk-XC6B6L27.js +0 -82
  188. package/packages/core/dist/chunk-XNSE64ZY.js +0 -3316
  189. package/packages/core/dist/chunk-XROES2WN.js +0 -634
  190. package/packages/core/dist/chunk-XSCKNRCZ.js +0 -5020
  191. package/packages/core/dist/chunk-XVABPAUZ.js +0 -82
  192. package/packages/core/dist/chunk-YOBCB5C5.js +0 -596
  193. package/packages/core/dist/chunk-YUK6Q563.js +0 -666
  194. package/packages/core/dist/chunk-YXGL3ZEU.js +0 -1030
  195. package/packages/core/dist/chunk-ZINJ5OUX.js +0 -596
  196. package/packages/core/dist/chunk-ZPFD4BIQ.js +0 -604
  197. package/packages/core/dist/chunk-ZQZBFG6F.js +0 -4826
  198. package/packages/core/dist/chunk-ZZFRJGXM.js +0 -4877
  199. package/packages/create-krnl/dist/K_ENT_Entity-PQ5MURQY-R2OH4VXE.js +0 -14
  200. package/packages/create-krnl/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW-AZM5HF4M.js +0 -9
  201. package/packages/create-krnl/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF-X5N6SV2S.js +0 -111
  202. package/packages/create-krnl/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF-5PFHF4JU.js +0 -12
  203. package/packages/create-krnl/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X-ED33OQPH.js +0 -12
  204. package/packages/create-krnl/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW-YGQLVR4P.js +0 -9
  205. package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2-VM7CTU2L.js +0 -21
  206. package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK-Y2GQFJ7I.js +0 -21
  207. package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7-L3JQWO54.js +0 -8
  208. package/packages/create-krnl/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU-KQARASPR.js +0 -19
  209. package/packages/create-krnl/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5-OF3IGLVL.js +0 -59
  210. package/packages/create-krnl/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF-JOLHKOEX.js +0 -24
  211. package/packages/create-krnl/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG-L46LSHKQ.js +0 -10
  212. package/packages/create-krnl/dist/K_LIB_Krnl_Telemetry-77FRZ3KV-4JUPRR3X.js +0 -10
  213. package/packages/create-krnl/dist/chunk-3TRM6CYL.js +0 -152
  214. package/packages/create-krnl/dist/chunk-3URCB3QS.js +0 -127
  215. package/packages/create-krnl/dist/chunk-5JDK35TG.js +0 -3872
  216. package/packages/create-krnl/dist/chunk-A2XAXDOW.js +0 -812
  217. package/packages/create-krnl/dist/chunk-AN6TMQHG.js +0 -1033
  218. package/packages/create-krnl/dist/chunk-BOXWWXQG.js +0 -400
  219. package/packages/create-krnl/dist/chunk-BPTBREBG.js +0 -38
  220. package/packages/create-krnl/dist/chunk-FDNCADFE.js +0 -71
  221. package/packages/create-krnl/dist/chunk-JTLSTO25.js +0 -71
  222. package/packages/create-krnl/dist/chunk-M3NCUIPL.js +0 -107
  223. package/packages/create-krnl/dist/chunk-N2EONSOC.js +0 -7769
  224. package/packages/create-krnl/dist/chunk-OHVMVRBP.js +0 -117
  225. package/packages/create-krnl/dist/chunk-Q45257P6.js +0 -173
  226. package/packages/create-krnl/dist/chunk-QGM4M3NI.js +0 -37
  227. package/packages/create-krnl/dist/chunk-RJNYUXZD.js +0 -977
  228. package/packages/create-krnl/dist/chunk-SRTOPJ5W.js +0 -104
  229. package/packages/create-krnl/dist/chunk-UPBIGEC3.js +0 -666
  230. package/packages/create-krnl/dist/chunk-V2DB7UD7.js +0 -82
  231. package/packages/create-krnl/dist/chunk-WMHLIUI6.js +0 -3644
  232. package/packages/create-krnl/dist/chunk-XIRFOO3H.js +0 -589
  233. package/packages/create-krnl/dist/chunk-Y2CEEVZP.js +0 -5536
  234. package/packages/create-krnl/dist/main-DXUMPBND.js +0 -2217
  235. package/packages/create-krnl/dist/wrapper-SDF2VKX3.js +0 -31
@@ -1,1030 +0,0 @@
1
- import {
2
- __esm,
3
- __export,
4
- __require
5
- } from "./chunk-KFQGP6VL.js";
6
-
7
- // src/core/K_LIB_Krnl_Frontend_Generator.ts
8
- var K_LIB_Krnl_Frontend_Generator_exports = {};
9
- __export(K_LIB_Krnl_Frontend_Generator_exports, {
10
- KrnlFrontendGenerator: () => KrnlFrontendGenerator
11
- });
12
- import fs from "fs";
13
- import path from "path";
14
- import { fileURLToPath } from "url";
15
- var _metaUrl, _filename, _dirname, KrnlFrontendGenerator;
16
- var init_K_LIB_Krnl_Frontend_Generator = __esm({
17
- "src/core/K_LIB_Krnl_Frontend_Generator.ts"() {
18
- _metaUrl = typeof import.meta !== "undefined" && import.meta.url ? import.meta.url : null;
19
- _filename = _metaUrl ? fileURLToPath(_metaUrl) : "";
20
- _dirname = _metaUrl ? path.dirname(_filename) : "";
21
- KrnlFrontendGenerator = class {
22
- /**
23
- * Main entrypoint: ensures skeleton exists, generates React components & index.tsx
24
- */
25
- static async generate(entity, frontendDir) {
26
- this.ensureFrontendSkeleton(entity, frontendDir);
27
- const uiAllowlist = entity._frontend?.options?.uiEndpoints;
28
- const uiEndpointsMap = /* @__PURE__ */ new Map();
29
- const collectEndpoints = (ent) => {
30
- const funcs = [
31
- ...ent.localFunctionalities?.values() || [],
32
- ...ent.remoteFunctionalities?.values() || []
33
- ];
34
- for (const fn of funcs) {
35
- if (uiAllowlist && !uiAllowlist.includes(fn.id)) {
36
- continue;
37
- }
38
- const uiSpec = fn.uiSpec || fn.ui_spec;
39
- if (!uiSpec) {
40
- continue;
41
- }
42
- if (uiSpec && uiSpec.ui_component_enabled) {
43
- if (!uiEndpointsMap.has(fn.id)) {
44
- uiEndpointsMap.set(fn.id, { id: fn.id, uiSpec, schema: fn.schema });
45
- }
46
- }
47
- }
48
- const children = ent.hierarchyManager?.ownedComponents || ent.components;
49
- if (children && typeof children.values === "function") {
50
- for (const child of children.values()) {
51
- collectEndpoints(child);
52
- }
53
- }
54
- };
55
- collectEndpoints(entity);
56
- const uiEndpoints = Array.from(uiEndpointsMap.values());
57
- if (uiEndpoints.length > 0) {
58
- this.checkReactDependencies(frontendDir);
59
- const contractVal = this.validateExecutionContract(entity, uiEndpoints);
60
- if (!contractVal.valid) {
61
- console.error(`[KrnlFrontendGenerator] Execution Contract Validation Failed:
62
- ${contractVal.errors.map((e) => ` - ${e}`).join("\n")}`);
63
- throw new Error(`[KrnlExecutionContractError] ${contractVal.errors.join("; ")}`);
64
- }
65
- }
66
- this.generateAtoms(frontendDir);
67
- const componentsDir = path.join(frontendDir, "src", "components");
68
- fs.mkdirSync(componentsDir, { recursive: true });
69
- for (const ep of uiEndpoints) {
70
- const epDir = path.join(componentsDir, ep.id);
71
- fs.mkdirSync(epDir, { recursive: true });
72
- const compSource = this.generateComponentSource(ep.id, ep.uiSpec, ep.schema);
73
- fs.writeFileSync(path.join(epDir, "index.ts"), compSource, "utf-8");
74
- }
75
- const subAppPrefixesSet = new Set(entity._subAppRegistry?.keys() || []);
76
- if (entity.hierarchyManager?.ownedComponents) {
77
- for (const [childId, childEntity] of entity.hierarchyManager.ownedComponents.entries()) {
78
- if (childEntity && childEntity._frontend) {
79
- subAppPrefixesSet.add(childId.toLowerCase());
80
- }
81
- }
82
- }
83
- const subAppPrefixes = Array.from(subAppPrefixesSet);
84
- const indexSource = this.generateIndexSource(entity.entityName, uiEndpoints, subAppPrefixes);
85
- fs.writeFileSync(path.join(frontendDir, "src", "index.ts"), indexSource, "utf-8");
86
- }
87
- /**
88
- * Ensures essential files (package.json, index.html, index.css, atoms/) exist in frontendDir
89
- */
90
- static ensureFrontendSkeleton(entity, frontendDir) {
91
- const srcDir = path.join(frontendDir, "src");
92
- const atomsDir = path.join(srcDir, "atoms");
93
- fs.mkdirSync(atomsDir, { recursive: true });
94
- const candidates = [
95
- path.resolve(_dirname, "../src/krnl/frontend/atoms"),
96
- path.resolve(_dirname, "../../src/krnl/frontend/atoms"),
97
- path.resolve(_dirname, "../frontend/atoms"),
98
- path.resolve(process.cwd(), "node_modules/krnlts/src/krnl/frontend/atoms"),
99
- path.resolve(process.cwd(), "node_modules/krnlts/dist/frontend/atoms")
100
- ];
101
- const libAtomsDir = candidates.find((c) => fs.existsSync(c));
102
- if (libAtomsDir && fs.existsSync(libAtomsDir)) {
103
- const files = fs.readdirSync(libAtomsDir);
104
- for (const file of files) {
105
- const srcFile = path.join(libAtomsDir, file);
106
- const destFile = path.join(atomsDir, file);
107
- fs.copyFileSync(srcFile, destFile);
108
- }
109
- }
110
- const pkgPath = path.join(frontendDir, "package.json");
111
- if (!fs.existsSync(pkgPath)) {
112
- const pkgContent = {
113
- name: `${entity.entityName.toLowerCase()}-frontend`,
114
- version: "1.0.0",
115
- type: "module",
116
- dependencies: {
117
- react: "^18.2.0",
118
- "react-dom": "^18.2.0"
119
- },
120
- devDependencies: {
121
- "@types/react": "^18.2.0",
122
- "@types/react-dom": "^18.2.0"
123
- }
124
- };
125
- fs.writeFileSync(pkgPath, JSON.stringify(pkgContent, null, 2), "utf-8");
126
- }
127
- const htmlPath = path.join(frontendDir, "index.html");
128
- if (!fs.existsSync(htmlPath)) {
129
- const htmlContent = `<!DOCTYPE html>
130
- <html lang="en" data-theme="glass-brutalism">
131
- <head>
132
- <meta charset="UTF-8">
133
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
134
- <title>${entity.entityName} Frontend</title>
135
- <link rel="preconnect" href="https://fonts.googleapis.com">
136
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
137
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
138
- <link rel="stylesheet" href="styles.css">
139
- <link rel="stylesheet" href="/frontend/index.css">
140
- </head>
141
- <body>
142
- <div class="krnl-sphere krnl-sphere-accent"></div>
143
- <div class="krnl-sphere krnl-sphere-neutral"></div>
144
- <div id="root"></div>
145
- <script src="bundle.js"></script>
146
- </body>
147
- </html>`;
148
- fs.writeFileSync(htmlPath, htmlContent, "utf-8");
149
- }
150
- const cssPath = path.join(frontendDir, "index.css");
151
- if (!fs.existsSync(cssPath)) {
152
- const defaultCss = `/* =============================================================
153
- KRNL Glass-Brutalism Fallback Design System
154
- Apple precision + glassmorphism depth + neo-brutalist structure
155
- Override any --krnl-* token in your own index.css to restyle.
156
- ============================================================= */
157
-
158
- /* \u2500\u2500 Google Fonts fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
159
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
160
-
161
- /* \u2500\u2500 Design Tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
162
- :root {
163
- /* Typography */
164
- --krnl-font: 'Inter', -apple-system, 'SF Pro Display', 'Segoe UI', sans-serif;
165
- --krnl-font-mono: 'SF Mono', 'JetBrains Mono', 'Fira Code', monospace;
166
-
167
- /* Page base \u2014 Pastel Matte Black */
168
- --krnl-bg: #16181d;
169
- --krnl-text: #f1f5f9;
170
- --krnl-text-muted: #8e95a5;
171
-
172
- /* Matte glass \u2014 panels, cards, containers (recede back) */
173
- --krnl-matte-bg: rgba(26, 29, 36, 0.75);
174
- --krnl-matte-bg-hover: rgba(34, 38, 48, 0.88);
175
- --krnl-matte-blur: blur(24px);
176
-
177
- /* Gloss \u2014 buttons, focused inputs (float forward) */
178
- --krnl-gloss-bg: linear-gradient(160deg, rgba(255,255,255,0.12) 0%, rgba(255,255,255,0.03) 100%);
179
- --krnl-gloss-shine: inset 0 1px 0 rgba(255,255,255,0.20);
180
-
181
- /* Neo-brutalist borders & shadows */
182
- --krnl-border: 2px solid rgba(255, 255, 255, 0.85);
183
- --krnl-border-input: 2px solid rgba(255, 255, 255, 0.85);
184
- --krnl-radius: 14px;
185
- --krnl-radius-sm: 8px;
186
- --krnl-shadow: 5px 5px 0px rgba(0, 0, 0, 0.90);
187
- --krnl-shadow-hover: 8px 8px 0px rgba(0, 0, 0, 0.95);
188
- --krnl-shadow-btn: 4px 4px 0px rgba(0, 0, 0, 0.90);
189
- --krnl-shadow-btn-hover: 6px 6px 0px rgba(0, 0, 0, 0.95);
190
- --krnl-shadow-btn-active: 2px 2px 0px rgba(0, 0, 0, 0.90);
191
-
192
- /* Semantic accents \u2014 desaturated glow pastels for dark bg */
193
- --krnl-accent: #2b4c7e; /* Dark powder blue */
194
- --krnl-accent-fg: #f1f5f9;
195
- --krnl-success: #1f4d36; /* Dark mint */
196
- --krnl-success-fg: #f1f5f9;
197
- --krnl-danger: #5c2424; /* Dark blush red */
198
- --krnl-danger-fg: #f1f5f9;
199
- --krnl-warning: #5e4e19; /* Dark butter yellow */
200
- --krnl-warning-fg: #f1f5f9;
201
-
202
- /* Phantom / live-mode indicator */
203
- --krnl-phantom-glow: 0 0 24px rgba(48, 209, 88, 0.50);
204
- --krnl-phantom-border: 2px solid #30d158;
205
- }
206
-
207
- /* \u2500\u2500 Reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
208
- *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
209
-
210
- body {
211
- font-family: var(--krnl-font);
212
- background-color: var(--krnl-bg);
213
- color: var(--krnl-text);
214
- min-height: 100vh;
215
- overflow-x: hidden;
216
- position: relative;
217
- }
218
-
219
- /* \u2500\u2500 Ambient Sphere Orbs (hidden for solid pastel black theme) \u2500\u2500 */
220
- .krnl-sphere { display: none; }
221
-
222
- /* \u2500\u2500 App Shell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
223
- .krnl-app-shell {
224
- position: relative;
225
- z-index: 1;
226
- display: flex;
227
- flex-direction: column;
228
- min-height: 100vh;
229
- align-items: center;
230
- }
231
-
232
- /* \u2500\u2500 Header (matte glass) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
233
- .krnl-header {
234
- display: flex;
235
- align-items: center;
236
- justify-content: center;
237
- width: 100%;
238
- padding: 1rem 2rem;
239
- background: var(--krnl-matte-bg);
240
- backdrop-filter: var(--krnl-matte-blur);
241
- -webkit-backdrop-filter: var(--krnl-matte-blur);
242
- border-bottom: var(--krnl-border);
243
- box-shadow: 0 3px 0px rgba(0, 0, 0, 0.90);
244
- letter-spacing: -0.02em;
245
- position: sticky;
246
- top: 0;
247
- z-index: 100;
248
- }
249
- .krnl-header h1 {
250
- font-size: 1.15rem;
251
- font-weight: 800;
252
- letter-spacing: -0.04em;
253
- color: var(--krnl-text);
254
- text-align: center;
255
- }
256
-
257
- /* \u2500\u2500 Nav Tabs (matte glass bar, wrapping + icon-only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
258
- .krnl-nav-tabs {
259
- display: flex;
260
- flex-wrap: wrap;
261
- justify-content: center;
262
- width: 100%;
263
- gap: 0.5rem;
264
- padding: 0.75rem 2rem;
265
- background: var(--krnl-matte-bg);
266
- backdrop-filter: var(--krnl-matte-blur);
267
- -webkit-backdrop-filter: var(--krnl-matte-blur);
268
- border-bottom: var(--krnl-border);
269
- }
270
-
271
- /* Tab buttons \u2014 icon-only by default, reveal label on hover */
272
- .krnl-tab-btn {
273
- position: relative;
274
- display: inline-flex;
275
- align-items: center;
276
- justify-content: center;
277
- gap: 0;
278
- overflow: hidden;
279
- background: var(--krnl-gloss-bg);
280
- box-shadow: var(--krnl-gloss-shine);
281
- border: var(--krnl-border);
282
- color: var(--krnl-text);
283
- font-family: var(--krnl-font);
284
- font-size: 0.82rem;
285
- font-weight: 600;
286
- letter-spacing: -0.01em;
287
- /* Collapsed icon-only size */
288
- padding: 0.45rem 0.65rem;
289
- min-width: 2.4rem;
290
- max-width: 2.4rem;
291
- border-radius: var(--krnl-radius-sm);
292
- cursor: pointer;
293
- white-space: nowrap;
294
- transition: box-shadow 0.15s ease, transform 0.15s ease, max-width 0.25s ease, padding 0.25s ease, gap 0.25s ease;
295
- }
296
-
297
- /* Tab button label \u2014 hidden until hover */
298
- .krnl-tab-btn .krnl-tab-label {
299
- display: inline-block;
300
- max-width: 0;
301
- opacity: 0;
302
- overflow: hidden;
303
- transition: max-width 0.25s ease, opacity 0.2s ease;
304
- white-space: nowrap;
305
- pointer-events: none;
306
- }
307
-
308
- /* Expand on hover */
309
- .krnl-tab-btn:hover,
310
- .krnl-tab-btn:focus-visible {
311
- max-width: 14rem;
312
- padding: 0.45rem 1rem;
313
- gap: 0.4rem;
314
- transform: translateY(-1px);
315
- box-shadow: var(--krnl-gloss-shine), 4px 4px 0px rgba(0, 0, 0, 0.95);
316
- }
317
- .krnl-tab-btn:hover .krnl-tab-label,
318
- .krnl-tab-btn:focus-visible .krnl-tab-label {
319
- max-width: 10rem;
320
- opacity: 1;
321
- }
322
-
323
- /* Active tab \u2014 always show icon + label */
324
- .krnl-tab-btn.active {
325
- background: var(--krnl-accent);
326
- color: var(--krnl-accent-fg);
327
- box-shadow: var(--krnl-gloss-shine), var(--krnl-shadow-btn);
328
- transform: translateY(-1px);
329
- max-width: 14rem;
330
- padding: 0.45rem 1rem;
331
- gap: 0.4rem;
332
- }
333
- .krnl-tab-btn.active .krnl-tab-label {
334
- max-width: 10rem;
335
- opacity: 1;
336
- }
337
-
338
- /* \u2500\u2500 Main Content Area \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
339
- .krnl-main-body {
340
- flex: 1;
341
- width: 100%;
342
- max-width: 1100px;
343
- padding: 2.5rem 2rem;
344
- display: flex;
345
- flex-wrap: wrap;
346
- justify-content: center;
347
- align-items: flex-start;
348
- gap: 2rem;
349
- overflow-y: auto;
350
- }
351
-
352
- /* \u2500\u2500 Endpoint Card (matte glass panel) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
353
- .krnl-endpoint-card {
354
- background: var(--krnl-matte-bg);
355
- backdrop-filter: var(--krnl-matte-blur);
356
- -webkit-backdrop-filter: var(--krnl-matte-blur);
357
- border: var(--krnl-border);
358
- border-radius: var(--krnl-radius);
359
- box-shadow: var(--krnl-shadow);
360
- padding: 1.75rem;
361
- min-width: 320px;
362
- max-width: 480px;
363
- width: 100%;
364
- transition: box-shadow 0.15s ease, transform 0.15s ease;
365
- position: relative;
366
- margin: 0 auto;
367
- }
368
- .krnl-endpoint-card:hover {
369
- transform: translate(-2px, -2px);
370
- box-shadow: var(--krnl-shadow-hover);
371
- background: var(--krnl-matte-bg-hover);
372
- }
373
- .krnl-endpoint-card.krnl-phantom-active {
374
- border: var(--krnl-phantom-border);
375
- box-shadow: var(--krnl-phantom-glow);
376
- }
377
-
378
- .krnl-endpoint-title {
379
- font-size: 0.72rem;
380
- font-weight: 700;
381
- letter-spacing: 0.08em;
382
- text-transform: uppercase;
383
- color: var(--krnl-text-muted);
384
- margin-bottom: 1.25rem;
385
- }
386
-
387
- /* \u2500\u2500 Form Atoms (centered, icon-first, hover-reveal text) \u2500\u2500\u2500\u2500\u2500 */
388
- .krnl-form-group {
389
- display: flex;
390
- flex-direction: column;
391
- align-items: center;
392
- gap: 0.45rem;
393
- margin-bottom: 1.25rem;
394
- width: 100%;
395
- }
396
-
397
- .krnl-label {
398
- font-size: 0.72rem;
399
- font-weight: 700;
400
- letter-spacing: 0.06em;
401
- text-transform: uppercase;
402
- color: var(--krnl-text-muted);
403
- text-align: center;
404
- opacity: 0;
405
- max-height: 0px;
406
- overflow: hidden;
407
- transform: translateY(-4px);
408
- transition: opacity 0.2s ease, max-height 0.2s ease, transform 0.2s ease;
409
- }
410
-
411
- .krnl-form-group:hover .krnl-label,
412
- .krnl-form-group:focus-within .krnl-label {
413
- opacity: 1;
414
- max-height: 30px;
415
- transform: translateY(0);
416
- margin-bottom: 0.2rem;
417
- }
418
-
419
- /* Inputs \u2014 gloss surface (floats above matte panel) */
420
- .krnl-input,
421
- .krnl-select,
422
- .krnl-textarea {
423
- background: var(--krnl-gloss-bg);
424
- box-shadow: var(--krnl-gloss-shine);
425
- border: var(--krnl-border-input);
426
- border-radius: var(--krnl-radius-sm);
427
- color: var(--krnl-text);
428
- font-family: var(--krnl-font);
429
- font-size: 0.9rem;
430
- padding: 0.65rem 0.85rem;
431
- width: 100%;
432
- text-align: center;
433
- outline: none;
434
- transition: border-color 0.12s ease, box-shadow 0.12s ease;
435
- }
436
- .krnl-input:focus,
437
- .krnl-select:focus,
438
- .krnl-textarea:focus {
439
- border-color: #1d1d1f;
440
- box-shadow: var(--krnl-gloss-shine), 0 0 0 3px rgba(200, 223, 245, 0.50);
441
- }
442
- .krnl-textarea { resize: vertical; min-height: 90px; text-align: left; }
443
-
444
- .krnl-toggle-group {
445
- flex-direction: row;
446
- justify-content: center;
447
- align-items: center;
448
- gap: 0.75rem;
449
- }
450
-
451
- /* \u2500\u2500 Buttons (gloss, centered icon-first, hover-to-reveal text) \u2500\u2500 */
452
- .krnl-btn {
453
- display: inline-flex;
454
- align-items: center;
455
- justify-content: center;
456
- gap: 0.5rem;
457
- font-family: var(--krnl-font);
458
- font-size: 0.88rem;
459
- font-weight: 700;
460
- letter-spacing: -0.01em;
461
- padding: 0.65rem 1rem;
462
- border-radius: var(--krnl-radius-sm);
463
- border: var(--krnl-border);
464
- cursor: pointer;
465
- user-select: none;
466
- margin: 0 auto;
467
- transition: box-shadow 0.15s ease, transform 0.15s ease, padding 0.2s ease;
468
- background: var(--krnl-gloss-bg);
469
- box-shadow: var(--krnl-gloss-shine), var(--krnl-shadow-btn);
470
- color: var(--krnl-text);
471
- }
472
-
473
- .krnl-btn-icon {
474
- font-size: 1.1rem;
475
- filter: grayscale(100%);
476
- display: inline-block;
477
- line-height: 1;
478
- }
479
-
480
- .krnl-btn-label {
481
- display: inline-block;
482
- max-width: 0px;
483
- opacity: 0;
484
- overflow: hidden;
485
- white-space: nowrap;
486
- transition: max-width 0.25s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.2s ease;
487
- }
488
-
489
- .krnl-btn:hover .krnl-btn-label,
490
- .krnl-btn:focus .krnl-btn-label,
491
- .krnl-btn:disabled .krnl-btn-label {
492
- max-width: 200px;
493
- opacity: 1;
494
- margin-left: 0.25rem;
495
- }
496
-
497
- .krnl-btn:hover .krnl-btn-icon {
498
- filter: grayscale(0%);
499
- }
500
-
501
- .krnl-btn:hover:not(:disabled) {
502
- transform: translate(-1px, -1px);
503
- box-shadow: var(--krnl-gloss-shine), var(--krnl-shadow-btn-hover);
504
- padding: 0.65rem 1.35rem;
505
- }
506
- .krnl-btn:active:not(:disabled) {
507
- transform: translate(2px, 2px);
508
- box-shadow: var(--krnl-gloss-shine), var(--krnl-shadow-btn-active);
509
- }
510
- .krnl-btn:disabled {
511
- opacity: 0.45;
512
- cursor: not-allowed;
513
- }
514
-
515
- /* Semantic button variants */
516
- .krnl-btn-primary { background: var(--krnl-accent); color: var(--krnl-accent-fg); }
517
- .krnl-btn-success { background: var(--krnl-success); color: var(--krnl-success-fg); }
518
- .krnl-btn-danger { background: var(--krnl-danger); color: var(--krnl-danger-fg); }
519
- .krnl-btn-warning { background: var(--krnl-warning); color: var(--krnl-warning-fg); }
520
-
521
- /* \u2500\u2500 JSON Viewer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
522
- .krnl-json-viewer {
523
- background: rgba(245, 245, 247, 0.30);
524
- backdrop-filter: blur(8px);
525
- border: var(--krnl-border);
526
- border-radius: var(--krnl-radius-sm);
527
- padding: 1rem;
528
- margin-top: 0.5rem;
529
- }
530
- .krnl-json-code {
531
- font-family: var(--krnl-font-mono);
532
- font-size: 0.8rem;
533
- white-space: pre-wrap;
534
- word-break: break-all;
535
- color: var(--krnl-text);
536
- max-height: 320px;
537
- overflow-y: auto;
538
- }
539
-
540
- /* \u2500\u2500 Tile \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
541
- .krnl-tile {
542
- background: var(--krnl-matte-bg);
543
- backdrop-filter: var(--krnl-matte-blur);
544
- border: var(--krnl-border);
545
- border-radius: var(--krnl-radius);
546
- box-shadow: var(--krnl-shadow);
547
- padding: 1.25rem;
548
- display: flex;
549
- flex-direction: column;
550
- gap: 0.4rem;
551
- }
552
- .krnl-tile-title { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--krnl-text-muted); }
553
- .krnl-tile-value { font-size: 1.6rem; font-weight: 800; letter-spacing: -0.04em; color: var(--krnl-text); }
554
- .krnl-tile-subtitle { font-size: 0.75rem; color: var(--krnl-text-muted); }
555
-
556
- /* \u2500\u2500 Carousel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
557
- .krnl-carousel {
558
- display: flex;
559
- gap: 1rem;
560
- overflow-x: auto;
561
- scroll-snap-type: x mandatory;
562
- padding-bottom: 0.5rem;
563
- scrollbar-width: thin;
564
- }
565
- .krnl-carousel-item {
566
- scroll-snap-align: start;
567
- flex: 0 0 220px;
568
- background: var(--krnl-gloss-bg);
569
- box-shadow: var(--krnl-gloss-shine), var(--krnl-shadow);
570
- border: var(--krnl-border);
571
- border-radius: var(--krnl-radius-sm);
572
- padding: 1rem;
573
- font-size: 0.88rem;
574
- }
575
-
576
- /* \u2500\u2500 Phantom Badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
577
- .krnl-phantom-badge {
578
- position: absolute;
579
- top: -10px; right: -10px;
580
- background: #30d158;
581
- color: #fff;
582
- font-family: var(--krnl-font-mono);
583
- font-size: 0.65rem;
584
- font-weight: 700;
585
- letter-spacing: 0.04em;
586
- padding: 2px 8px;
587
- border-radius: 999px;
588
- border: 2px solid #1d1d1f;
589
- box-shadow: 2px 2px 0px #1d1d1f;
590
- }
591
-
592
- /* \u2500\u2500 JSON Builder Rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
593
- .krnl-json-rows { display: flex; flex-direction: column; gap: 0.5rem; }
594
- .krnl-json-row { display: flex; gap: 0.5rem; align-items: center; }
595
- .krnl-json-key { flex: 2; }
596
- .krnl-json-type { flex: 1; }
597
- .krnl-json-val { flex: 3; }
598
-
599
- /* \u2500\u2500 Empty State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
600
- .krnl-empty {
601
- color: var(--krnl-text-muted);
602
- font-size: 0.88rem;
603
- text-align: center;
604
- padding: 2rem;
605
- }
606
-
607
- /* \u2500\u2500 Responsive \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
608
- @media (max-width: 768px) {
609
- .krnl-header, .krnl-nav-tabs { padding-left: 1rem; padding-right: 1rem; }
610
- .krnl-main-body { padding: 1rem; }
611
- .krnl-endpoint-card { max-width: 100%; min-width: 0; }
612
- .krnl-sphere-accent { width: 320px; height: 320px; }
613
- .krnl-sphere-neutral { width: 260px; height: 260px; }
614
- }
615
- `;
616
- fs.writeFileSync(cssPath, defaultCss, "utf-8");
617
- }
618
- }
619
- /**
620
- * Verifies React dependencies are installed in frontend/
621
- */
622
- static checkReactDependencies(frontendDir) {
623
- const nodeModulesReact = path.join(frontendDir, "node_modules", "react");
624
- const rootNodeModulesReact = path.resolve(frontendDir, "../../node_modules/react");
625
- let hasReact = fs.existsSync(nodeModulesReact) || fs.existsSync(rootNodeModulesReact);
626
- if (!hasReact) {
627
- try {
628
- __require.resolve("react", { paths: [frontendDir, process.cwd()] });
629
- hasReact = true;
630
- } catch (_) {
631
- }
632
- }
633
- if (!hasReact) {
634
- console.error(`
635
- \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
636
- \u2502 [KrnlFrontend] WARNING: UI components are enabled but React is missing! \u2502
637
- \u2502 Please run inside your frontend/ directory: \u2502
638
- \u2502 npm install react react-dom \u2502
639
- \u2502 npm install -D @types/react @types/react-dom \u2502
640
- \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
641
- `);
642
- }
643
- }
644
- /**
645
- * Validates uiSpec definitions at build time to enforce protocol constraints and catch errors early
646
- */
647
- static validateUiSpec(fid, uiSpec) {
648
- const errors = [];
649
- const ALLOWED_INPUT_COMPONENTS = /* @__PURE__ */ new Set([
650
- "KrnlTextInput",
651
- "KrnlNumberInput",
652
- "KrnlToggle",
653
- "KrnlDropdown",
654
- "KrnlTextArea",
655
- "KrnlJsonInput"
656
- ]);
657
- const ALLOWED_OUTPUT_COMPONENTS = /* @__PURE__ */ new Set([
658
- "KrnlJsonViewer",
659
- "KrnlCarousel",
660
- "KrnlTile",
661
- "KrnlSSELog"
662
- ]);
663
- (uiSpec.inputs || []).forEach((spec) => {
664
- if (!spec.field || typeof spec.field !== "string") {
665
- errors.push(`[ERR_UISPEC_MISSING_FIELD] Endpoint '${fid}' input is missing required 'field' name.`);
666
- }
667
- if (spec.component && !ALLOWED_INPUT_COMPONENTS.has(spec.component)) {
668
- errors.push(`[ERR_UISPEC_INVALID_INPUT_COMPONENT] Endpoint '${fid}' input '${spec.field}' uses invalid component '${spec.component}'. Allowed input components: ${Array.from(ALLOWED_INPUT_COMPONENTS).join(", ")}`);
669
- }
670
- if (spec.sharedComponentId && typeof spec.sharedComponentId !== "string") {
671
- errors.push(`[ERR_UISPEC_INVALID_SLOT] Endpoint '${fid}' input '${spec.field}' sharedComponentId must be a string.`);
672
- }
673
- if (spec.sourceEndpointId && typeof spec.sourceEndpointId !== "string") {
674
- errors.push(`[ERR_UISPEC_INVALID_SOURCE_ENDPOINT] Endpoint '${fid}' input '${spec.field}' sourceEndpointId must be a string.`);
675
- }
676
- if (spec.sourceEndpointId && spec.component !== "KrnlDropdown") {
677
- errors.push(`[ERR_UISPEC_SOURCE_ENDPOINT_REQUIRES_DROPDOWN] Endpoint '${fid}' input '${spec.field}' sets sourceEndpointId='${spec.sourceEndpointId}' but uses component '${spec.component}'. Selection-source fields MUST use component 'KrnlDropdown'.`);
678
- }
679
- if (spec.component === "KrnlDropdown" && !spec.sharedComponentId && !spec.sourceEndpointId && (!spec.options || spec.options.length === 0)) {
680
- errors.push(`[ERR_UISPEC_DROPDOWN_MISSING_SOURCE] Endpoint '${fid}' input '${spec.field}' uses component 'KrnlDropdown' but provides no selection source. Must set 'sharedComponentId', 'sourceEndpointId', or static 'options'.`);
681
- }
682
- const SELECTION_FIELD_PATTERNS = ["provider", "model", "modelName", "model_name", "profile", "key_id", "keyId"];
683
- if (spec.component === "KrnlTextInput" && SELECTION_FIELD_PATTERNS.includes(spec.field)) {
684
- console.warn(`
685
- \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
686
- console.warn(`\u2502 [KrnlUiSpecValidator] SELECTION-SOURCE PATTERN WARNING: \u2502`);
687
- console.warn(`\u2502 Endpoint '${fid}' input '${spec.field}' uses KrnlTextInput. \u2502`);
688
- console.warn(`\u2502 Field '${spec.field}' is a finite-choice selection candidate. \u2502`);
689
- console.warn(`\u2502 KRNL ARCHITECTURE RULE: Users MUST NOT type finite selections manually. \u2502`);
690
- console.warn(`\u2502 FIX: Change component to 'KrnlDropdown' and specify 'sharedComponentId' \u2502`);
691
- console.warn(`\u2502 or 'sourceEndpointId' pointing to the options-providing endpoint. \u2502`);
692
- console.warn(`\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
693
- `);
694
- }
695
- if (spec.bindMode && spec.bindMode !== "selected" && spec.bindMode !== "all") {
696
- errors.push(`[ERR_UISPEC_INVALID_BINDMODE] Endpoint '${fid}' input '${spec.field}' bindMode '${spec.bindMode}' is invalid. Allowed: 'selected' | 'all'`);
697
- }
698
- if (spec.autoFetch) {
699
- errors.push(`[ERR_UISPEC_INVALID_AUTOFETCH] Endpoint '${fid}' input '${spec.field}' cannot use autoFetch. autoFetch is only allowed on output provider components.`);
700
- }
701
- });
702
- (uiSpec.outputs || []).forEach((spec) => {
703
- if (!spec.field || typeof spec.field !== "string") {
704
- errors.push(`[ERR_UISPEC_MISSING_FIELD] Endpoint '${fid}' output is missing required 'field' name.`);
705
- }
706
- if (spec.component && !ALLOWED_OUTPUT_COMPONENTS.has(spec.component)) {
707
- errors.push(`[ERR_UISPEC_INVALID_OUTPUT_COMPONENT] Endpoint '${fid}' output '${spec.field}' uses input component '${spec.component}'. Output fields must use display components: ${Array.from(ALLOWED_OUTPUT_COMPONENTS).join(", ")}.`);
708
- }
709
- if (spec.autoFetch && !spec.sharedComponentId) {
710
- errors.push(`[ERR_UISPEC_AUTOFETCH_MISSING_SLOT] Endpoint '${fid}' output '${spec.field}' sets autoFetch=true but lacks sharedComponentId.`);
711
- }
712
- });
713
- return {
714
- valid: errors.length === 0,
715
- errors
716
- };
717
- }
718
- /**
719
- * Validates that all UI components reference real registered endpoints on the entity.
720
- */
721
- static validateExecutionContract(entity, uiEndpoints) {
722
- const errors = [];
723
- const registeredFids = /* @__PURE__ */ new Set([
724
- ...entity.localFunctionalities?.keys() || [],
725
- ...entity.remoteFunctionalities?.keys() || []
726
- ]);
727
- for (const ep of uiEndpoints) {
728
- if (!registeredFids.has(ep.id)) {
729
- errors.push(`[ERR_UI_DEAD_FETCH] UI component generated for endpoint '${ep.id}', but no handler is registered on entity '${entity.entityName}'.`);
730
- }
731
- for (const input of ep.uiSpec.inputs || []) {
732
- if (input.sourceEndpointId && !registeredFids.has(input.sourceEndpointId)) {
733
- errors.push(`[ERR_UI_STALE_ENDPOINT] Endpoint '${ep.id}' input '${input.field}' references sourceEndpointId '${input.sourceEndpointId}', which is not a registered endpoint.`);
734
- }
735
- }
736
- }
737
- return { valid: errors.length === 0, errors };
738
- }
739
- /**
740
- * Generates TS source code for a single endpoint UI component using VanJS
741
- */
742
- static generateComponentSource(fid, uiSpec, schema) {
743
- const validation = this.validateUiSpec(fid, uiSpec);
744
- if (!validation.valid) {
745
- console.error(`
746
- \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
747
- \u2502 [KrnlUiSpecValidator] BUILD ERROR IN ENDPOINT '${fid}':
748
- ${validation.errors.map((e) => `\u2502 - ${e}`).join("\n")}
749
- \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
750
- `);
751
- throw new Error(`[KrnlUiSpecValidationError] Invalid uiSpec in endpoint '${fid}': ${validation.errors.join("; ")}`);
752
- }
753
- let inputs = uiSpec.inputs || [];
754
- const outputs = uiSpec.outputs || [];
755
- if (inputs.length === 0 && schema && schema.input) {
756
- try {
757
- let shape = {};
758
- if (typeof schema.input._def?.shape === "function") {
759
- shape = schema.input._def.shape();
760
- } else if (schema.input.shape) {
761
- shape = schema.input.shape;
762
- }
763
- inputs = Object.keys(shape).map((field) => ({
764
- field,
765
- label: field,
766
- component: "KrnlTextInput",
767
- placeholder: `Enter ${field}`
768
- }));
769
- } catch (e) {
770
- console.warn(`[KrnlFrontendGenerator] Could not infer input fields for '${fid}':`, e);
771
- }
772
- }
773
- const sharedInputIds = inputs.filter((i) => i.sharedComponentId).map((i) => i.sharedComponentId);
774
- const sharedOutputIds = outputs.filter((o) => o.sharedComponentId).map((o) => o.sharedComponentId);
775
- const allSharedIds = Array.from(/* @__PURE__ */ new Set([...sharedInputIds, ...sharedOutputIds]));
776
- const sourceEndpointInputs = inputs.filter((i) => i.sourceEndpointId);
777
- const autoFetchOutput = outputs.find((o) => o.autoFetch && o.sharedComponentId);
778
- return `import van from 'vanjs-core';
779
- import { KrnlButton, KrnlTextInput, KrnlDropdown, KrnlTextArea, KrnlJsonViewer, KrnlTile, getSharedSlot, KrnlAgentBridge } from '../../atoms/index.js';
780
-
781
- const { div, h3, h4, form } = van.tags;
782
-
783
- export default function Endpoint_${fid.replace(/[^a-zA-Z0-9]/g, "_")}() {
784
- const formData = van.state<Record<string, any>>({});
785
- const response = van.state<any>(null);
786
- const loading = van.state(false);
787
- const error = van.state<string | null>(null);
788
- const phantomActive = van.state(false);
789
-
790
- ${allSharedIds.map(
791
- (id) => `const slot_${id.replace(/[^a-zA-Z0-9]/g, "_")} = getSharedSlot('${id}');`
792
- ).join("\n ")}
793
-
794
- KrnlAgentBridge.register('${fid}', {
795
- trigger: async (overrideInput?: Record<string, any>, ticketId?: string) => {
796
- return await executeRequest(overrideInput, ticketId);
797
- }
798
- });
799
-
800
- const handleInputChange = (field: string, val: any) => {
801
- formData.val = { ...formData.val, [field]: val };
802
- KrnlAgentBridge.setState('${fid}', {
803
- fid: '${fid}',
804
- formData: formData.val,
805
- response: response.val,
806
- loading: false,
807
- error: null,
808
- lastUpdated: Date.now()
809
- });
810
- };
811
-
812
- const executeRequest = async (overrideData?: Record<string, any>, ticketId?: string) => {
813
- loading.val = true;
814
- error.val = null;
815
- if (ticketId || overrideData) {
816
- phantomActive.val = true;
817
- }
818
- const activeInput = overrideData || formData.val;
819
- if (overrideData) formData.val = { ...formData.val, ...overrideData };
820
-
821
- try {
822
- const res = await fetch('/frontend/api/${fid}', {
823
- method: 'POST',
824
- headers: { 'Content-Type': 'application/json' },
825
- body: JSON.stringify(activeInput),
826
- });
827
- const data = await res.json();
828
- const payload = data.payload !== undefined ? data.payload : data;
829
- response.val = payload;
830
-
831
- if (payload && (payload.status === 'error' || payload.message)) {
832
- if (payload.status === 'error') error.val = payload.message || 'Request failed';
833
- }
834
-
835
- ${outputs.filter((o) => o.sharedComponentId).map((o) => {
836
- const varName = `slot_${o.sharedComponentId.replace(/[^a-zA-Z0-9]/g, "_")}`;
837
- const fieldKey = o.field;
838
- const dataPath = o.dataPath;
839
- return `
840
- let extracted: any = null;
841
- if (payload && typeof payload === 'object') {
842
- ${dataPath ? `extracted = payload['${dataPath}'];` : `extracted = payload['${fieldKey}'] !== undefined ? payload['${fieldKey}'] : payload;`}
843
- }
844
- if (extracted && typeof extracted === 'object' && !Array.isArray(extracted)) {
845
- if (extracted.status === 'success' && extracted.data) extracted = extracted.data;
846
- else if (extracted.providers && Array.isArray(extracted.providers)) extracted = extracted.providers;
847
- else if (extracted.models && Array.isArray(extracted.models)) extracted = extracted.models;
848
- else if (extracted.agents && Array.isArray(extracted.agents)) extracted = extracted.agents;
849
- else if (extracted.keys && typeof extracted.keys === 'object') {
850
- extracted = Object.keys(extracted).map(k => ({ id: k, name: k, value: k }));
851
- }
852
- }
853
- if (Array.isArray(extracted)) {
854
- ${varName}.options.val = extracted;
855
- }`;
856
- }).join("\n ")}
857
-
858
- if (ticketId) KrnlAgentBridge.sendJobComplete(ticketId, '${fid}', payload, undefined);
859
- return payload;
860
- } catch (err: any) {
861
- const errMsg = err.message || 'Request failed';
862
- error.val = errMsg;
863
- if (ticketId) KrnlAgentBridge.sendJobComplete(ticketId, '${fid}', null, errMsg);
864
- } finally {
865
- loading.val = false;
866
- if (ticketId || overrideData) {
867
- setTimeout(() => { phantomActive.val = false; }, 2000);
868
- }
869
- }
870
- };
871
-
872
- ${autoFetchOutput ? `executeRequest({});` : ""}
873
- ${sourceEndpointInputs.map(
874
- (i) => `
875
- fetch('/frontend/api/${i.sourceEndpointId}', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
876
- .then((r) => r.json())
877
- .then((d) => {
878
- const payload = d.payload !== undefined ? d.payload : d;
879
- let list = payload.${i.dataPath || i.field} || payload.data || payload.items || payload.providers || payload.models || payload.agents || payload;
880
- if (list && typeof list === 'object' && !Array.isArray(list)) list = Object.keys(list).map(k => ({ id: k, name: k, value: k }));
881
- if (Array.isArray(list) && ${i.sharedComponentId ? `slot_${i.sharedComponentId.replace(/[^a-zA-Z0-9]/g, "_")}` : "null"}) {
882
- slot_${i.sharedComponentId.replace(/[^a-zA-Z0-9]/g, "_")}.options.val = list;
883
- }
884
- })
885
- .catch(() => {});`
886
- ).join("\n ")}
887
-
888
- const handleSubmit = async (e: Event) => {
889
- e.preventDefault();
890
- await executeRequest();
891
- };
892
-
893
- return div(
894
- {
895
- className: () => \`krnl-endpoint-card \${phantomActive.val ? 'krnl-phantom-active' : ''}\`,
896
- style: () => \`
897
- background: var(--krnl-bg-surface);
898
- padding: 1.5rem;
899
- border-radius: 12px;
900
- border: \${phantomActive.val ? '2px solid var(--krnl-accent)' : '1px solid var(--krnl-border-color)'};
901
- transition: all 0.3s ease;
902
- position: relative;
903
- \`
904
- },
905
- () => (phantomActive.val ? div({ className: 'krnl-phantom-badge' }, '\u{1F916} Phantom Execution Active') : null),
906
- h3({ style: 'margin-bottom: 1rem; color: var(--krnl-primary);' }, 'Endpoint: ${fid}'),
907
- form(
908
- { onsubmit: handleSubmit },
909
- ${inputs.map((inSpec) => this.renderVanInputAtom(inSpec)).join(",\n ")}${inputs.length > 0 ? "," : ""}
910
- KrnlButton({ type: 'submit', loading, disabled: loading, label: 'Execute ${fid}', icon: '\u26A1' })
911
- ),
912
- () => (error.val ? div({ style: 'color: var(--krnl-danger); margin-top: 1rem;' }, 'Error: ', error.val) : null),
913
- () =>
914
- response.val !== null
915
- ? div(
916
- { style: 'margin-top: 1.5rem; border-top: 1px solid var(--krnl-border-color); padding-top: 1rem;' },
917
- h4({ style: 'margin-bottom: 0.5rem; color: var(--krnl-accent);' }, 'Output Response'),
918
- ${outputs.length > 0 ? outputs.map((outSpec) => this.renderVanOutputAtom(outSpec)).join(",\n ") : `KrnlJsonViewer({ data: response })`}
919
- )
920
- : null
921
- );
922
- }
923
- `;
924
- }
925
- static renderVanInputAtom(spec) {
926
- const label = spec.label || spec.field;
927
- if (spec.sharedComponentId) {
928
- const varName = `slot_${spec.sharedComponentId.replace(/[^a-zA-Z0-9]/g, "_")}`;
929
- const bindMode = spec.bindMode || "selected";
930
- return `KrnlDropdown({
931
- label: "${label}",
932
- value: van.derive(() => formData.val['${spec.field}'] !== undefined ? formData.val['${spec.field}'] : (${varName}.value.val || '')),
933
- options: ${varName}.options,
934
- onChange: (v) => {
935
- ${varName}.value.val = v;
936
- handleInputChange('${spec.field}', ${bindMode === "all" ? `${varName}.options.val` : "v"});
937
- }
938
- })`;
939
- }
940
- switch (spec.component) {
941
- case "KrnlTextInput":
942
- return `KrnlTextInput({ label: "${label}", value: van.derive(() => formData.val['${spec.field}'] || ''), onChange: (v) => handleInputChange('${spec.field}', v), placeholder: "${spec.placeholder || ""}" })`;
943
- case "KrnlTextArea":
944
- return `KrnlTextArea({ label: "${label}", value: van.derive(() => formData.val['${spec.field}'] || ''), onChange: (v) => handleInputChange('${spec.field}', v), placeholder: "${spec.placeholder || ""}" })`;
945
- case "KrnlDropdown":
946
- const opts = JSON.stringify(spec.options || []);
947
- return `KrnlDropdown({ label: "${label}", value: van.derive(() => formData.val['${spec.field}'] || ''), options: ${opts}, onChange: (v) => handleInputChange('${spec.field}', v) })`;
948
- default:
949
- return `KrnlTextInput({ label: "${label}", value: van.derive(() => formData.val['${spec.field}'] || ''), onChange: (v) => handleInputChange('${spec.field}', v) })`;
950
- }
951
- }
952
- static renderVanOutputAtom(spec) {
953
- const label = spec.label || spec.field;
954
- if (spec.sharedComponentId) {
955
- const varName = `slot_${spec.sharedComponentId.replace(/[^a-zA-Z0-9]/g, "_")}`;
956
- return `KrnlJsonViewer({ label: "${label}", data: ${varName}.options })`;
957
- }
958
- switch (spec.component) {
959
- case "KrnlTile":
960
- return `KrnlTile({ label: "${label}", value: van.derive(() => response.val ? (response.val['${spec.field}'] !== undefined ? response.val['${spec.field}'] : response.val) : '') })`;
961
- default:
962
- return `KrnlJsonViewer({ label: "${label}", data: van.derive(() => response.val ? (response.val['${spec.field}'] !== undefined ? response.val['${spec.field}'] : response.val) : response.val) })`;
963
- }
964
- }
965
- /**
966
- * Generates root index.ts aggregator using VanJS
967
- */
968
- static generateIndexSource(appName, uiEndpoints, subAppPrefixes) {
969
- const imports = uiEndpoints.map(
970
- (ep) => `import Endpoint_${ep.id.replace(/[^a-zA-Z0-9]/g, "_")} from './components/${ep.id}/index.js';`
971
- ).join("\n");
972
- const initialTab = uiEndpoints.length > 0 ? uiEndpoints[0].id : subAppPrefixes.length > 0 ? subAppPrefixes[0] : "welcome";
973
- return `import van from 'vanjs-core';
974
- ${imports}
975
-
976
- const { div, header, span, h1, button, main, iframe, h2, p } = van.tags;
977
-
978
- function AppShell() {
979
- const activeTab = van.state<string>('${initialTab}');
980
-
981
- return div(
982
- { className: 'krnl-app-shell' },
983
- header(
984
- { className: 'krnl-header' },
985
- div(
986
- { style: 'display: flex; align-items: center; gap: 0.65rem;' },
987
- span({ style: 'font-size: 1.2rem; line-height: 1;' }, '\u2B21'),
988
- h1('${appName}')
989
- )
990
- ),
991
- div(
992
- { className: 'krnl-nav-tabs' },
993
- ${uiEndpoints.map(
994
- (ep) => `button({ className: () => \`krnl-tab-btn \${activeTab.val === '${ep.id}' ? 'active' : ''}\`, onclick: () => activeTab.val = '${ep.id}', title: '${ep.id}' }, span('\u2B21'), span({ className: 'krnl-tab-label' }, '${ep.id}'))`
995
- ).join(",\n ")}${uiEndpoints.length > 0 && subAppPrefixes.length > 0 ? "," : ""}
996
- ${subAppPrefixes.map(
997
- (sub) => `button({ className: () => \`krnl-tab-btn \${activeTab.val === '${sub}' ? 'active' : ''}\`, onclick: () => activeTab.val = '${sub}', title: '${sub}' }, span('\u{1F4E6}'), span({ className: 'krnl-tab-label' }, '${sub}'))`
998
- ).join(",\n ")}
999
- ),
1000
- main(
1001
- { className: 'krnl-main-body' },
1002
- ${uiEndpoints.map(
1003
- (ep) => `div({ style: () => \`display: \${activeTab.val === '${ep.id}' ? 'block' : 'none'}\` }, Endpoint_${ep.id.replace(/[^a-zA-Z0-9]/g, "_")}())`
1004
- ).join(",\n ")}${uiEndpoints.length > 0 && subAppPrefixes.length > 0 ? "," : ""}
1005
- ${subAppPrefixes.map(
1006
- (sub) => `() => activeTab.val === '${sub}' ? iframe({ src: '/${sub}/frontend/', title: '${sub}', style: 'width: 100%; height: calc(100vh - 160px); border: none; border-radius: 8px;' }) : null`
1007
- ).join(",\n ")}
1008
- )
1009
- );
1010
- }
1011
-
1012
- const rootElement = document.getElementById('root');
1013
- if (rootElement) {
1014
- van.add(rootElement, AppShell());
1015
- }
1016
- `;
1017
- }
1018
- static generateAtoms(frontendDir) {
1019
- const atomsDir = path.join(frontendDir, "src", "atoms");
1020
- fs.mkdirSync(atomsDir, { recursive: true });
1021
- }
1022
- };
1023
- }
1024
- });
1025
-
1026
- export {
1027
- KrnlFrontendGenerator,
1028
- K_LIB_Krnl_Frontend_Generator_exports,
1029
- init_K_LIB_Krnl_Frontend_Generator
1030
- };