@ultrst-armada/krnl 1.0.2 → 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.
- package/README.md +67 -65
- package/package.json +12 -8
- package/packages/cli/dist/bin/krnl.cjs +793 -330
- package/packages/cli/dist/bin/krnl.js +50 -65
- package/packages/cli/dist/chunk-6SHSECXR.js +1628 -0
- package/packages/cli/dist/index.cjs +746 -262
- package/packages/cli/dist/index.d.cts +45 -2
- package/packages/cli/dist/index.d.ts +45 -2
- package/packages/cli/dist/index.js +5 -1
- package/packages/cli/package.json +17 -10
- package/packages/core/dist/index.cjs +2905 -139
- package/packages/core/dist/index.d.cts +611 -27
- package/packages/core/dist/index.d.ts +611 -27
- package/packages/core/dist/index.js +2897 -139
- package/packages/core/package.json +14 -6
- package/packages/create-krnl/dist/index.cjs +102 -65
- package/packages/create-krnl/dist/index.js +102 -65
- package/packages/create-krnl/package.json +5 -3
- package/packages/eslint-plugin/dist/index.cjs +17 -55
- package/packages/eslint-plugin/dist/index.d.cts +8 -43
- package/packages/eslint-plugin/dist/index.d.ts +8 -43
- package/packages/eslint-plugin/dist/index.js +17 -55
- package/packages/eslint-plugin/package.json +5 -4
- package/packages/validate/dist/index.cjs +378 -85
- package/packages/validate/dist/index.d.cts +11 -1
- package/packages/validate/dist/index.d.ts +11 -1
- package/packages/validate/dist/index.js +375 -82
- package/packages/validate/package.json +14 -7
- package/packages/cli/dist/K_ENT_Entity-PQ5MURQY-ZG6FZXXX.js +0 -13
- package/packages/cli/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW-K4CRQYA5.js +0 -8
- package/packages/cli/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF-LNPXZYOE.js +0 -110
- package/packages/cli/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF-3ALZPNX4.js +0 -11
- package/packages/cli/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X-PJTICYSW.js +0 -11
- package/packages/cli/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW-M5TYU55O.js +0 -8
- package/packages/cli/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2-H6STOXRK.js +0 -20
- package/packages/cli/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK-XPJXSF7D.js +0 -19
- package/packages/cli/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7-CUYGTWOW.js +0 -7
- package/packages/cli/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU-VR6T4N6J.js +0 -17
- package/packages/cli/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5-RLJ4QWDP.js +0 -58
- package/packages/cli/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF-BOQGUASC.js +0 -22
- package/packages/cli/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG-XJI7KIT5.js +0 -8
- package/packages/cli/dist/K_LIB_Krnl_Telemetry-77FRZ3KV-K5VCWAFW.js +0 -9
- package/packages/cli/dist/chunk-3TRM6CYL.js +0 -152
- package/packages/cli/dist/chunk-5JDK35TG.js +0 -3872
- package/packages/cli/dist/chunk-63PTK33I.js +0 -997
- package/packages/cli/dist/chunk-6NIKAMUZ.js +0 -82
- package/packages/cli/dist/chunk-BOXWWXQG.js +0 -400
- package/packages/cli/dist/chunk-EEKLK7QJ.js +0 -565
- package/packages/cli/dist/chunk-EG7T2IAD.js +0 -107
- package/packages/cli/dist/chunk-ESTKOQ7T.js +0 -1146
- package/packages/cli/dist/chunk-F5EHXE2O.js +0 -1036
- package/packages/cli/dist/chunk-F65ANSQG.js +0 -269
- package/packages/cli/dist/chunk-FDNCADFE.js +0 -71
- package/packages/cli/dist/chunk-FZ6X7PHR.js +0 -1146
- package/packages/cli/dist/chunk-GDLRMDAN.js +0 -127
- package/packages/cli/dist/chunk-HWMTCMOS.js +0 -656
- package/packages/cli/dist/chunk-I74QIQOD.js +0 -5536
- package/packages/cli/dist/chunk-JTLSTO25.js +0 -71
- package/packages/cli/dist/chunk-JULBBJ27.js +0 -1033
- package/packages/cli/dist/chunk-OHVMVRBP.js +0 -117
- package/packages/cli/dist/chunk-P2PCLEKX.js +0 -666
- package/packages/cli/dist/chunk-PJQIUOX2.js +0 -7767
- package/packages/cli/dist/chunk-PPOF3DJW.js +0 -471
- package/packages/cli/dist/chunk-Q45257P6.js +0 -173
- package/packages/cli/dist/chunk-QNROWGBI.js +0 -1036
- package/packages/cli/dist/chunk-RJNYUXZD.js +0 -977
- package/packages/cli/dist/chunk-SRTOPJ5W.js +0 -104
- package/packages/cli/dist/chunk-TCEX3MPS.js +0 -702
- package/packages/cli/dist/chunk-TNOAJO2J.js +0 -675
- package/packages/cli/dist/chunk-UR2SUCSF.js +0 -701
- package/packages/cli/dist/chunk-X5LOIFM7.js +0 -68
- package/packages/cli/dist/chunk-XIRFOO3H.js +0 -589
- package/packages/cli/dist/chunk-ZAAV3JXQ.js +0 -809
- package/packages/core/dist/K_ENT_Entity-4MB7CU4A.js +0 -12
- package/packages/core/dist/K_ENT_Entity-DEJGIDGH.js +0 -12
- package/packages/core/dist/K_ENT_Entity-FXZO5UZ2.js +0 -12
- package/packages/core/dist/K_ENT_Entity-HDSCXC5F.js +0 -12
- package/packages/core/dist/K_ENT_Entity-JILABHLW.js +0 -12
- package/packages/core/dist/K_ENT_Entity-PQ5MURQY.js +0 -13
- package/packages/core/dist/K_ENT_Entity-ROAKDIHW.js +0 -12
- package/packages/core/dist/K_ENT_Entity-TBVFSKDV.js +0 -12
- package/packages/core/dist/K_ENT_Entity-ZFLKG3JO.js +0 -12
- package/packages/core/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW.js +0 -8
- package/packages/core/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF.js +0 -110
- package/packages/core/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF.js +0 -9
- package/packages/core/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X.js +0 -9
- package/packages/core/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW.js +0 -8
- package/packages/core/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2.js +0 -20
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-4C6GBQAG.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-6V23A6F6.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK.js +0 -19
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-DYLLC5G2.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-F4FOFAUP.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-FBOXXMI3.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-Q73BWLNP.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-QM2C4MVA.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-QUGI6SMP.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-RGMTBHNP.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Registry-RWR7UNDW.js +0 -18
- package/packages/core/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7.js +0 -7
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-32MFJJ5Z.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-4J4CEWRY.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-A366YHF2.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-LK4LYJHI.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-NW3K63II.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-QDHTI5ZV.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-VHCT6VIW.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-WBRKF24R.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-XKYQYT6Q.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_App_Adapter-Z2PWZYDZ.js +0 -17
- package/packages/core/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5.js +0 -58
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-2EZU7QF4.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-6G3AQNAV.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-B2NZMQUG.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-C2RABMZP.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-HHE3NZ4F.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-LHFGR6WK.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-M74BLM3N.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-PT6ZA6EA.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-SP52V3CX.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF.js +0 -22
- package/packages/core/dist/K_LIB_Krnl_System_Magnetic_Loader-YNSEUHJJ.js +0 -21
- package/packages/core/dist/K_LIB_Krnl_System_Unified_Http_Adapter-M6SBHIVA.js +0 -8
- package/packages/core/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG.js +0 -8
- package/packages/core/dist/K_LIB_Krnl_Telemetry-77FRZ3KV.js +0 -9
- package/packages/core/dist/chunk-33L2J7V7.js +0 -82
- package/packages/core/dist/chunk-3ES4K2ZP.js +0 -817
- package/packages/core/dist/chunk-3SMHVVLL.js +0 -82
- package/packages/core/dist/chunk-3UEZ7JQA.js +0 -4877
- package/packages/core/dist/chunk-3XIE6KBD.js +0 -4877
- package/packages/core/dist/chunk-46ZLCML6.js +0 -107
- package/packages/core/dist/chunk-4UEL3DWJ.js +0 -107
- package/packages/core/dist/chunk-54GWZ5PC.js +0 -82
- package/packages/core/dist/chunk-6QCYRS5L.js +0 -127
- package/packages/core/dist/chunk-6ULMHNXR.js +0 -104
- package/packages/core/dist/chunk-7WUETJEV.js +0 -117
- package/packages/core/dist/chunk-A5KRAYDB.js +0 -107
- package/packages/core/dist/chunk-ANEAZ3PO.js +0 -107
- package/packages/core/dist/chunk-BE76RL6F.js +0 -82
- package/packages/core/dist/chunk-CIARVYDO.js +0 -107
- package/packages/core/dist/chunk-CR2ANE62.js +0 -107
- package/packages/core/dist/chunk-DI27MOR7.js +0 -173
- package/packages/core/dist/chunk-E6RLFHM5.js +0 -596
- package/packages/core/dist/chunk-EELAPMNV.js +0 -4877
- package/packages/core/dist/chunk-ENZ2RQVJ.js +0 -107
- package/packages/core/dist/chunk-F2U6CX4F.js +0 -4877
- package/packages/core/dist/chunk-FKG64OHL.js +0 -82
- package/packages/core/dist/chunk-FYAZJYM5.js +0 -772
- package/packages/core/dist/chunk-G4NP4RDQ.js +0 -82
- package/packages/core/dist/chunk-GADIRLRS.js +0 -473
- package/packages/core/dist/chunk-GR6CSLQJ.js +0 -772
- package/packages/core/dist/chunk-HDS7AT6O.js +0 -772
- package/packages/core/dist/chunk-HIMEZUU2.js +0 -71
- package/packages/core/dist/chunk-IB4UHG5I.js +0 -596
- package/packages/core/dist/chunk-J7ZYNVRS.js +0 -772
- package/packages/core/dist/chunk-JVLZU4K7.js +0 -604
- package/packages/core/dist/chunk-JYXXI7Q3.js +0 -82
- package/packages/core/dist/chunk-K54K2KZW.js +0 -192
- package/packages/core/dist/chunk-K6VHLBNH.js +0 -3316
- package/packages/core/dist/chunk-KCBP7ZYA.js +0 -596
- package/packages/core/dist/chunk-KFQGP6VL.js +0 -33
- package/packages/core/dist/chunk-KIUEUI7K.js +0 -82
- package/packages/core/dist/chunk-LB67NIZP.js +0 -949
- package/packages/core/dist/chunk-LDTYFUNW.js +0 -596
- package/packages/core/dist/chunk-MLVWARD4.js +0 -596
- package/packages/core/dist/chunk-MPYVXHKO.js +0 -2777
- package/packages/core/dist/chunk-MRQ3MITU.js +0 -772
- package/packages/core/dist/chunk-MVUN7I7O.js +0 -107
- package/packages/core/dist/chunk-NDDOIRW7.js +0 -596
- package/packages/core/dist/chunk-O3KDB5MH.js +0 -3330
- package/packages/core/dist/chunk-OEINUDSE.js +0 -400
- package/packages/core/dist/chunk-OPDENPT4.js +0 -4877
- package/packages/core/dist/chunk-P6XEM2LA.js +0 -429
- package/packages/core/dist/chunk-QKMRSQV4.js +0 -82
- package/packages/core/dist/chunk-R6CCWALL.js +0 -4877
- package/packages/core/dist/chunk-RAMMOO73.js +0 -774
- package/packages/core/dist/chunk-S3FTZFG6.js +0 -772
- package/packages/core/dist/chunk-T2ZVN434.js +0 -4877
- package/packages/core/dist/chunk-TFHLDMIA.js +0 -107
- package/packages/core/dist/chunk-TI3QUCIJ.js +0 -107
- package/packages/core/dist/chunk-TR2BAIGI.js +0 -107
- package/packages/core/dist/chunk-UGVVJKC6.js +0 -4877
- package/packages/core/dist/chunk-V2DX7YIU.js +0 -984
- package/packages/core/dist/chunk-W4IHYUYD.js +0 -772
- package/packages/core/dist/chunk-W6WBG5OY.js +0 -4877
- package/packages/core/dist/chunk-WN3M7O7H.js +0 -3312
- package/packages/core/dist/chunk-WR3NCU7U.js +0 -4877
- package/packages/core/dist/chunk-XC6B6L27.js +0 -82
- package/packages/core/dist/chunk-XNSE64ZY.js +0 -3316
- package/packages/core/dist/chunk-XROES2WN.js +0 -634
- package/packages/core/dist/chunk-XSCKNRCZ.js +0 -5020
- package/packages/core/dist/chunk-XVABPAUZ.js +0 -82
- package/packages/core/dist/chunk-YOBCB5C5.js +0 -596
- package/packages/core/dist/chunk-YUK6Q563.js +0 -666
- package/packages/core/dist/chunk-YXGL3ZEU.js +0 -1030
- package/packages/core/dist/chunk-ZINJ5OUX.js +0 -596
- package/packages/core/dist/chunk-ZPFD4BIQ.js +0 -604
- package/packages/core/dist/chunk-ZQZBFG6F.js +0 -4826
- package/packages/core/dist/chunk-ZZFRJGXM.js +0 -4877
- package/packages/create-krnl/dist/K_ENT_Entity-PQ5MURQY-R2OH4VXE.js +0 -14
- package/packages/create-krnl/dist/K_LIB_Krnl_Aiko_Client-OPZAVZCW-AZM5HF4M.js +0 -9
- package/packages/create-krnl/dist/K_LIB_Krnl_Ep_Tools-ROOE2TQF-X5N6SV2S.js +0 -111
- package/packages/create-krnl/dist/K_LIB_Krnl_Frontend_Builder-2ZDUH6PF-5PFHF4JU.js +0 -12
- package/packages/create-krnl/dist/K_LIB_Krnl_Frontend_Generator-UYNRNX2X-ED33OQPH.js +0 -12
- package/packages/create-krnl/dist/K_LIB_Krnl_Registry_Client-NXV6D2QW-YGQLVR4P.js +0 -9
- package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Engine-7HR5HWW2-VM7CTU2L.js +0 -21
- package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Registry-7XYGDKJK-Y2GQFJ7I.js +0 -21
- package/packages/create-krnl/dist/K_LIB_Krnl_SubApp_Worker_Host-CQVTGGG7-L3JQWO54.js +0 -8
- package/packages/create-krnl/dist/K_LIB_Krnl_System_App_Adapter-M6FJKLGU-KQARASPR.js +0 -19
- package/packages/create-krnl/dist/K_LIB_Krnl_System_Base_Functionality_APIs-ZZUZ6ZG5-OF3IGLVL.js +0 -59
- package/packages/create-krnl/dist/K_LIB_Krnl_System_Magnetic_Loader-XBQO2KXF-JOLHKOEX.js +0 -24
- package/packages/create-krnl/dist/K_LIB_Krnl_System_Unified_Http_Adapter-RCEGP3OG-L46LSHKQ.js +0 -10
- package/packages/create-krnl/dist/K_LIB_Krnl_Telemetry-77FRZ3KV-4JUPRR3X.js +0 -10
- package/packages/create-krnl/dist/chunk-3TRM6CYL.js +0 -152
- package/packages/create-krnl/dist/chunk-3URCB3QS.js +0 -127
- package/packages/create-krnl/dist/chunk-5JDK35TG.js +0 -3872
- package/packages/create-krnl/dist/chunk-A2XAXDOW.js +0 -812
- package/packages/create-krnl/dist/chunk-AN6TMQHG.js +0 -1033
- package/packages/create-krnl/dist/chunk-BOXWWXQG.js +0 -400
- package/packages/create-krnl/dist/chunk-BPTBREBG.js +0 -38
- package/packages/create-krnl/dist/chunk-FDNCADFE.js +0 -71
- package/packages/create-krnl/dist/chunk-JTLSTO25.js +0 -71
- package/packages/create-krnl/dist/chunk-M3NCUIPL.js +0 -107
- package/packages/create-krnl/dist/chunk-N2EONSOC.js +0 -7769
- package/packages/create-krnl/dist/chunk-OHVMVRBP.js +0 -117
- package/packages/create-krnl/dist/chunk-Q45257P6.js +0 -173
- package/packages/create-krnl/dist/chunk-QGM4M3NI.js +0 -37
- package/packages/create-krnl/dist/chunk-RJNYUXZD.js +0 -977
- package/packages/create-krnl/dist/chunk-SRTOPJ5W.js +0 -104
- package/packages/create-krnl/dist/chunk-UPBIGEC3.js +0 -666
- package/packages/create-krnl/dist/chunk-V2DB7UD7.js +0 -82
- package/packages/create-krnl/dist/chunk-WMHLIUI6.js +0 -3644
- package/packages/create-krnl/dist/chunk-XIRFOO3H.js +0 -589
- package/packages/create-krnl/dist/chunk-Y2CEEVZP.js +0 -5536
- package/packages/create-krnl/dist/main-DXUMPBND.js +0 -2217
- package/packages/create-krnl/dist/wrapper-SDF2VKX3.js +0 -31
|
@@ -24,25 +24,25 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/bin/krnl.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
27
|
+
var path13 = __toESM(require("path"), 1);
|
|
28
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
29
29
|
|
|
30
30
|
// ../validate/dist/index.js
|
|
31
31
|
var fs2 = __toESM(require("fs"), 1);
|
|
32
|
-
var
|
|
32
|
+
var path3 = __toESM(require("path"), 1);
|
|
33
33
|
var import_ts_morph = require("ts-morph");
|
|
34
34
|
var path = __toESM(require("path"), 1);
|
|
35
35
|
var import_ts_morph2 = require("ts-morph");
|
|
36
|
-
var path2 = __toESM(require("path"), 1);
|
|
37
36
|
var import_ts_morph3 = require("ts-morph");
|
|
38
37
|
var fs = __toESM(require("fs"), 1);
|
|
39
|
-
var
|
|
38
|
+
var path2 = __toESM(require("path"), 1);
|
|
40
39
|
var import_ts_morph4 = require("ts-morph");
|
|
40
|
+
var import_ts_morph5 = require("ts-morph");
|
|
41
41
|
function checkFileLimits(sf, options) {
|
|
42
42
|
const errors = [];
|
|
43
43
|
const warnings = [];
|
|
44
44
|
const filePath = sf.getFilePath();
|
|
45
|
-
const sourceText = sf.
|
|
45
|
+
const sourceText = sf.getFullText();
|
|
46
46
|
const lines = sourceText.split("\n");
|
|
47
47
|
if (lines.length > options.maxFileLineLimit) {
|
|
48
48
|
errors.push({
|
|
@@ -153,7 +153,7 @@ function checkComponentRules(sf) {
|
|
|
153
153
|
ruleId: "krnl/helper-purity",
|
|
154
154
|
filePath,
|
|
155
155
|
line: decl.getStartLineNumber(),
|
|
156
|
-
message: `Helper functions (Layer 1) cannot directly import I/O modules ('${spec}'). Delegate to Layer 0 libraries or
|
|
156
|
+
message: `Helper functions (Layer 1) cannot directly import I/O modules ('${spec}'). Delegate to Layer 0 libraries or ServiceFacade context.`,
|
|
157
157
|
severity: "error"
|
|
158
158
|
});
|
|
159
159
|
}
|
|
@@ -161,12 +161,11 @@ function checkComponentRules(sf) {
|
|
|
161
161
|
}
|
|
162
162
|
return { errors, warnings };
|
|
163
163
|
}
|
|
164
|
-
function
|
|
164
|
+
function checkOrchestrationRules(sf) {
|
|
165
165
|
const errors = [];
|
|
166
166
|
const warnings = [];
|
|
167
167
|
const filePath = sf.getFilePath();
|
|
168
168
|
const sourceText = sf.getText();
|
|
169
|
-
const baseName = path2.basename(filePath);
|
|
170
169
|
const calls = sf.getDescendantsOfKind(import_ts_morph3.SyntaxKind.CallExpression);
|
|
171
170
|
for (const call of calls) {
|
|
172
171
|
const exprText = call.getExpression().getText();
|
|
@@ -175,7 +174,7 @@ function checkEntityRules(sf) {
|
|
|
175
174
|
ruleId: "krnl/no-polling",
|
|
176
175
|
filePath,
|
|
177
176
|
line: call.getStartLineNumber(),
|
|
178
|
-
message: `Prohibited use of 'setInterval'. Krnl applications must use reactive event streams
|
|
177
|
+
message: `Prohibited use of 'setInterval'. Krnl applications must use reactive event streams or triggers.`,
|
|
179
178
|
severity: "error"
|
|
180
179
|
});
|
|
181
180
|
}
|
|
@@ -184,65 +183,36 @@ function checkEntityRules(sf) {
|
|
|
184
183
|
const match = sourceText.match(/main\s*=\s*async\s*\([^,]+,\s*\{([^}]*)\}\s*\)/);
|
|
185
184
|
if (match) {
|
|
186
185
|
const destructured = match[1];
|
|
187
|
-
if (/\bsystem\b/.test(destructured)
|
|
186
|
+
if (/\bsystem\b/.test(destructured)) {
|
|
188
187
|
errors.push({
|
|
189
188
|
ruleId: "krnl/context-destructuring",
|
|
190
189
|
filePath,
|
|
191
|
-
message: `Functionality context parameter destructures 'system'. Functionality passes { state,
|
|
190
|
+
message: `Functionality context parameter destructures 'system'. Functionality passes { state, orchestration } or service context.`,
|
|
192
191
|
severity: "error"
|
|
193
192
|
});
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
195
|
}
|
|
197
|
-
const
|
|
196
|
+
const isOrchestrationClass = sf.getClasses().some((c) => {
|
|
198
197
|
const ext = c.getExtends();
|
|
199
|
-
return ext && (ext.getText().includes("
|
|
198
|
+
return ext && (ext.getText().includes("FunctionalityOrchestration") || ext.getText().includes("Orchestration") || ext.getText().includes("krnlOrchestrationBase"));
|
|
200
199
|
});
|
|
201
|
-
if (
|
|
200
|
+
if (isOrchestrationClass) {
|
|
202
201
|
for (const decl of sf.getImportDeclarations()) {
|
|
203
202
|
const spec = decl.getModuleSpecifierValue();
|
|
204
203
|
if (spec.includes("libraries/") || spec.includes("Concepts")) {
|
|
205
204
|
errors.push({
|
|
206
|
-
ruleId: "krnl/
|
|
205
|
+
ruleId: "krnl/orchestration-no-libraries",
|
|
207
206
|
filePath,
|
|
208
207
|
line: decl.getStartLineNumber(),
|
|
209
|
-
message: `
|
|
208
|
+
message: `FunctionalityOrchestration class violates Library Calling Invariant. FunctionalityOrchestrations must not call or import libraries directly ('${spec}'). Only functionalities are permitted to call shared libraries.`,
|
|
210
209
|
severity: "error"
|
|
211
210
|
});
|
|
212
211
|
}
|
|
213
212
|
}
|
|
214
|
-
let loadAllLine = -1;
|
|
215
|
-
const addLocalLines = [];
|
|
216
|
-
for (const call of calls) {
|
|
217
|
-
const txt = call.getText();
|
|
218
|
-
if (txt.includes("MagneticLoader.loadAll") || txt.includes("KrnlMagneticLoader.loadAll")) {
|
|
219
|
-
loadAllLine = call.getStartLineNumber();
|
|
220
|
-
} else if (txt.startsWith("this.addLocal(")) {
|
|
221
|
-
const hasUiSpec = txt.includes("uiSpec");
|
|
222
|
-
const idMatch = txt.match(/id\s*:\s*["']([^"']+)["']/);
|
|
223
|
-
addLocalLines.push({
|
|
224
|
-
line: call.getStartLineNumber(),
|
|
225
|
-
hasUiSpec,
|
|
226
|
-
id: idMatch ? idMatch[1] : "unknown"
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (loadAllLine !== -1) {
|
|
231
|
-
for (const al of addLocalLines) {
|
|
232
|
-
if (al.hasUiSpec && al.line > loadAllLine) {
|
|
233
|
-
errors.push({
|
|
234
|
-
ruleId: "krnl/boot-order",
|
|
235
|
-
filePath,
|
|
236
|
-
line: al.line,
|
|
237
|
-
message: `addLocal('${al.id}') with uiSpec at line ${al.line} appears AFTER loadAll() at line ${loadAllLine}. All addLocal() with UI must precede loadAll().`,
|
|
238
|
-
severity: "error"
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
213
|
for (const cls of sf.getClasses()) {
|
|
244
214
|
const ext = cls.getExtends();
|
|
245
|
-
if (ext && (ext.getText().includes("
|
|
215
|
+
if (ext && (ext.getText().includes("FunctionalityOrchestration") || ext.getText().includes("Orchestration") || ext.getText().includes("krnlOrchestrationBase"))) {
|
|
246
216
|
const loops = [
|
|
247
217
|
...cls.getDescendantsOfKind(import_ts_morph3.SyntaxKind.ForStatement),
|
|
248
218
|
...cls.getDescendantsOfKind(import_ts_morph3.SyntaxKind.ForOfStatement),
|
|
@@ -252,21 +222,34 @@ function checkEntityRules(sf) {
|
|
|
252
222
|
];
|
|
253
223
|
for (const loop of loops) {
|
|
254
224
|
errors.push({
|
|
255
|
-
ruleId: "krnl/
|
|
225
|
+
ruleId: "krnl/orchestration-purity",
|
|
256
226
|
filePath,
|
|
257
227
|
line: loop.getStartLineNumber(),
|
|
258
|
-
message: `
|
|
228
|
+
message: `FunctionalityOrchestration '${cls.getName() || "Anonymous"}' violates Orchestration Purity Law. Loops and procedural algorithms are prohibited inside orchestrations. Move logic to a functionality or a global library function.`,
|
|
259
229
|
severity: "error"
|
|
260
230
|
});
|
|
261
231
|
}
|
|
232
|
+
const allowedMethods = /* @__PURE__ */ new Set([
|
|
233
|
+
"flow",
|
|
234
|
+
"getFlow",
|
|
235
|
+
"listFlows",
|
|
236
|
+
"clearFlows",
|
|
237
|
+
"thenFunctionality",
|
|
238
|
+
"parallel",
|
|
239
|
+
"branch",
|
|
240
|
+
"fanOut",
|
|
241
|
+
"thenFunctionalityOrchestration",
|
|
242
|
+
"getSteps",
|
|
243
|
+
"assertServiceBoundary"
|
|
244
|
+
]);
|
|
262
245
|
for (const method of cls.getMethods()) {
|
|
263
246
|
const methodName = method.getName();
|
|
264
|
-
if (!
|
|
247
|
+
if (!allowedMethods.has(methodName)) {
|
|
265
248
|
errors.push({
|
|
266
|
-
ruleId: "krnl/
|
|
249
|
+
ruleId: "krnl/orchestration-purity",
|
|
267
250
|
filePath,
|
|
268
251
|
line: method.getStartLineNumber(),
|
|
269
|
-
message: `
|
|
252
|
+
message: `FunctionalityOrchestration '${cls.getName() || "Anonymous"}' defines custom method '${methodName}'. FunctionalityOrchestrations are purely declarative compositors. Define capabilities as functionalities or global library functions.`,
|
|
270
253
|
severity: "error"
|
|
271
254
|
});
|
|
272
255
|
}
|
|
@@ -275,7 +258,7 @@ function checkEntityRules(sf) {
|
|
|
275
258
|
}
|
|
276
259
|
for (const call of calls) {
|
|
277
260
|
const callText = call.getText();
|
|
278
|
-
if (callText.startsWith("this.
|
|
261
|
+
if (callText.startsWith("this.flow(") || callText.startsWith("orchestration.flow(")) {
|
|
279
262
|
let currentExpr = call;
|
|
280
263
|
const chainCalls = [];
|
|
281
264
|
while (currentExpr && import_ts_morph3.Node.isCallExpression(currentExpr)) {
|
|
@@ -292,14 +275,22 @@ function checkEntityRules(sf) {
|
|
|
292
275
|
}
|
|
293
276
|
let chainId = "orchestration";
|
|
294
277
|
for (const step of chainCalls) {
|
|
295
|
-
if (step.name === "
|
|
278
|
+
if (step.name === "flow") {
|
|
296
279
|
chainId = step.argText ? step.argText.replace(/['"]/g, "") : "orchestration";
|
|
297
280
|
} else if (step.name === "thenFunction") {
|
|
298
281
|
errors.push({
|
|
299
|
-
ruleId: "krnl/
|
|
282
|
+
ruleId: "krnl/orchestration-no-direct-library-calls",
|
|
283
|
+
filePath,
|
|
284
|
+
line: step.node.getStartLineNumber(),
|
|
285
|
+
message: `FunctionalityOrchestration flow '${chainId}' violates Orchestration Purity Law. Orchestrations cannot chain direct library functions via thenFunction(). Orchestrations must only sequence functionalities (thenFunctionality) and peer functionality orchestrations (thenFunctionalityOrchestration).`,
|
|
286
|
+
severity: "error"
|
|
287
|
+
});
|
|
288
|
+
} else if (step.name === "thenService") {
|
|
289
|
+
errors.push({
|
|
290
|
+
ruleId: "krnl/orchestration-no-external-services",
|
|
300
291
|
filePath,
|
|
301
292
|
line: step.node.getStartLineNumber(),
|
|
302
|
-
message: `
|
|
293
|
+
message: `FunctionalityOrchestration flow '${chainId}' violates Plane Isolation Law L1. A service-level FunctionalityOrchestration cannot compose external services. Use Skipo ServiceOrchestration at the application layer instead.`,
|
|
303
294
|
severity: "error"
|
|
304
295
|
});
|
|
305
296
|
}
|
|
@@ -313,9 +304,9 @@ function checkTopLevelPurity(sf) {
|
|
|
313
304
|
const errors = [];
|
|
314
305
|
const warnings = [];
|
|
315
306
|
const filePath = sf.getFilePath();
|
|
316
|
-
const baseName =
|
|
307
|
+
const baseName = path2.basename(filePath);
|
|
317
308
|
const isUiTopLevel = /^(App|main|index|_app|root)\.(tsx|jsx)$/i.test(baseName);
|
|
318
|
-
const isBackendTopLevel = /^(server|app)\.(ts|js)$/i.test(baseName) && !filePath.includes("/components/") && !filePath.includes("/
|
|
309
|
+
const isBackendTopLevel = /^(server|app|index)\.(ts|js)$/i.test(baseName) && !filePath.includes("/components/") && !filePath.includes("/orchestrations/") && !filePath.includes("/services/") && !filePath.includes("/libraries/");
|
|
319
310
|
if (isUiTopLevel) {
|
|
320
311
|
const jsxElements = sf.getDescendantsOfKind(import_ts_morph4.SyntaxKind.JsxOpeningElement);
|
|
321
312
|
const jsxSelfClosing = sf.getDescendantsOfKind(import_ts_morph4.SyntaxKind.JsxSelfClosingElement);
|
|
@@ -373,19 +364,56 @@ function checkTopLevelPurity(sf) {
|
|
|
373
364
|
return { errors, warnings };
|
|
374
365
|
}
|
|
375
366
|
function checkWorkspaceLayout(projectRoot, errors) {
|
|
376
|
-
const krnlDir =
|
|
377
|
-
const srcDir =
|
|
367
|
+
const krnlDir = path2.join(projectRoot, "krnl");
|
|
368
|
+
const srcDir = path2.join(projectRoot, "src");
|
|
378
369
|
const targetDir = fs.existsSync(krnlDir) ? krnlDir : fs.existsSync(srcDir) ? srcDir : null;
|
|
379
370
|
if (!targetDir) return;
|
|
380
|
-
const backendDir =
|
|
381
|
-
const frontendDir =
|
|
371
|
+
const backendDir = path2.join(targetDir, "backend");
|
|
372
|
+
const frontendDir = path2.join(targetDir, "frontend");
|
|
382
373
|
if (fs.existsSync(backendDir)) {
|
|
383
|
-
const
|
|
374
|
+
const bServices = path2.join(backendDir, "services");
|
|
375
|
+
if (fs.existsSync(bServices)) {
|
|
376
|
+
for (const sEntry of fs.readdirSync(bServices, { withFileTypes: true })) {
|
|
377
|
+
if (!sEntry.isDirectory()) continue;
|
|
378
|
+
const sDir = path2.join(bServices, sEntry.name);
|
|
379
|
+
const sLibs = path2.join(sDir, "libraries");
|
|
380
|
+
if (fs.existsSync(sLibs)) {
|
|
381
|
+
for (const entry of fs.readdirSync(sLibs, { withFileTypes: true })) {
|
|
382
|
+
if (!entry.isDirectory()) continue;
|
|
383
|
+
const libPath = path2.join(sLibs, entry.name);
|
|
384
|
+
if (!fs.existsSync(path2.join(libPath, "manifest.json"))) {
|
|
385
|
+
errors.push({
|
|
386
|
+
ruleId: "krnl/concept-manifest-required",
|
|
387
|
+
filePath: libPath,
|
|
388
|
+
message: `Service-owned concept library "${sEntry.name}/${entry.name}" is missing a manifest.json file.`,
|
|
389
|
+
severity: "error"
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const sFuncs = path2.join(sDir, "functionalities");
|
|
395
|
+
if (fs.existsSync(sFuncs)) {
|
|
396
|
+
for (const entry of fs.readdirSync(sFuncs, { withFileTypes: true })) {
|
|
397
|
+
if (!entry.isDirectory()) continue;
|
|
398
|
+
const funcPath = path2.join(sFuncs, entry.name);
|
|
399
|
+
if (!fs.existsSync(path2.join(funcPath, "manifest.json"))) {
|
|
400
|
+
errors.push({
|
|
401
|
+
ruleId: "krnl/functionality-manifest-required",
|
|
402
|
+
filePath: funcPath,
|
|
403
|
+
message: `Service-owned functionality "${sEntry.name}/${entry.name}" is missing a manifest.json file.`,
|
|
404
|
+
severity: "error"
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const bLibs = path2.join(backendDir, "libraries");
|
|
384
412
|
if (fs.existsSync(bLibs)) {
|
|
385
413
|
for (const entry of fs.readdirSync(bLibs, { withFileTypes: true })) {
|
|
386
414
|
if (!entry.isDirectory()) continue;
|
|
387
|
-
const libPath =
|
|
388
|
-
if (!fs.existsSync(
|
|
415
|
+
const libPath = path2.join(bLibs, entry.name);
|
|
416
|
+
if (!fs.existsSync(path2.join(libPath, "manifest.json"))) {
|
|
389
417
|
errors.push({
|
|
390
418
|
ruleId: "krnl/concept-manifest-required",
|
|
391
419
|
filePath: libPath,
|
|
@@ -395,12 +423,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
395
423
|
}
|
|
396
424
|
}
|
|
397
425
|
}
|
|
398
|
-
const bFuncs =
|
|
426
|
+
const bFuncs = path2.join(backendDir, "functionalities");
|
|
399
427
|
if (fs.existsSync(bFuncs)) {
|
|
400
428
|
for (const entry of fs.readdirSync(bFuncs, { withFileTypes: true })) {
|
|
401
429
|
if (!entry.isDirectory()) continue;
|
|
402
|
-
const funcPath =
|
|
403
|
-
if (!fs.existsSync(
|
|
430
|
+
const funcPath = path2.join(bFuncs, entry.name);
|
|
431
|
+
if (!fs.existsSync(path2.join(funcPath, "manifest.json"))) {
|
|
404
432
|
errors.push({
|
|
405
433
|
ruleId: "krnl/functionality-manifest-required",
|
|
406
434
|
filePath: funcPath,
|
|
@@ -412,12 +440,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
412
440
|
}
|
|
413
441
|
}
|
|
414
442
|
if (fs.existsSync(frontendDir)) {
|
|
415
|
-
const fLibs =
|
|
443
|
+
const fLibs = path2.join(frontendDir, "libraries");
|
|
416
444
|
if (fs.existsSync(fLibs)) {
|
|
417
445
|
for (const entry of fs.readdirSync(fLibs, { withFileTypes: true })) {
|
|
418
446
|
if (!entry.isDirectory()) continue;
|
|
419
|
-
const libPath =
|
|
420
|
-
if (!fs.existsSync(
|
|
447
|
+
const libPath = path2.join(fLibs, entry.name);
|
|
448
|
+
if (!fs.existsSync(path2.join(libPath, "manifest.json"))) {
|
|
421
449
|
errors.push({
|
|
422
450
|
ruleId: "krnl/frontend-concept-manifest-required",
|
|
423
451
|
filePath: libPath,
|
|
@@ -427,12 +455,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
427
455
|
}
|
|
428
456
|
}
|
|
429
457
|
}
|
|
430
|
-
const fFuncs =
|
|
458
|
+
const fFuncs = path2.join(frontendDir, "functionalities");
|
|
431
459
|
if (fs.existsSync(fFuncs)) {
|
|
432
460
|
for (const entry of fs.readdirSync(fFuncs, { withFileTypes: true })) {
|
|
433
461
|
if (!entry.isDirectory()) continue;
|
|
434
|
-
const funcPath =
|
|
435
|
-
if (!fs.existsSync(
|
|
462
|
+
const funcPath = path2.join(fFuncs, entry.name);
|
|
463
|
+
if (!fs.existsSync(path2.join(funcPath, "manifest.json"))) {
|
|
436
464
|
errors.push({
|
|
437
465
|
ruleId: "krnl/frontend-functionality-manifest-required",
|
|
438
466
|
filePath: funcPath,
|
|
@@ -444,19 +472,258 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
444
472
|
}
|
|
445
473
|
}
|
|
446
474
|
}
|
|
475
|
+
function checkServiceBoundaries(sf) {
|
|
476
|
+
const errors = [];
|
|
477
|
+
const warnings = [];
|
|
478
|
+
const filePath = sf.getFilePath().replace(/\\/g, "/");
|
|
479
|
+
const serviceMatch = filePath.match(/\/services\/([^/]+)\//);
|
|
480
|
+
if (!serviceMatch) {
|
|
481
|
+
return { errors, warnings };
|
|
482
|
+
}
|
|
483
|
+
const currentService = serviceMatch[1];
|
|
484
|
+
const imports = sf.getImportDeclarations();
|
|
485
|
+
for (const imp of imports) {
|
|
486
|
+
const spec = imp.getModuleSpecifierValue();
|
|
487
|
+
const crossServiceLibMatch = spec.match(/(?:^|\/|\.\.\/)services\/([^/]+)\/libraries\//) || spec.match(/\.\.\/(?:(?:\.\.\/)+)?([^/]+)\/libraries\//);
|
|
488
|
+
if (crossServiceLibMatch) {
|
|
489
|
+
const targetService = crossServiceLibMatch[1];
|
|
490
|
+
if (targetService !== currentService && targetService !== "." && targetService !== "..") {
|
|
491
|
+
errors.push({
|
|
492
|
+
ruleId: "krnl/no-cross-service-library-imports",
|
|
493
|
+
filePath,
|
|
494
|
+
line: imp.getStartLineNumber(),
|
|
495
|
+
message: `Cross-service library import forbidden: '${spec}'. Service '${currentService}' cannot import '${targetService}' libraries directly via filesystem. Access libraries through the '${targetService}' ServiceFacade (e.g. ${targetService}Facade.libraries).`,
|
|
496
|
+
severity: "error"
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return { errors, warnings };
|
|
502
|
+
}
|
|
503
|
+
var PRIMITIVE_AND_BUILTIN_TYPES = /* @__PURE__ */ new Set([
|
|
504
|
+
"string",
|
|
505
|
+
"number",
|
|
506
|
+
"boolean",
|
|
507
|
+
"symbol",
|
|
508
|
+
"bigint",
|
|
509
|
+
"void",
|
|
510
|
+
"undefined",
|
|
511
|
+
"null",
|
|
512
|
+
"never",
|
|
513
|
+
"unknown",
|
|
514
|
+
"any",
|
|
515
|
+
"object",
|
|
516
|
+
"Record",
|
|
517
|
+
"Array",
|
|
518
|
+
"ReadonlyArray",
|
|
519
|
+
"Map",
|
|
520
|
+
"Set",
|
|
521
|
+
"WeakMap",
|
|
522
|
+
"WeakSet",
|
|
523
|
+
"Promise",
|
|
524
|
+
"Date",
|
|
525
|
+
"RegExp",
|
|
526
|
+
"Error",
|
|
527
|
+
"Uint8Array",
|
|
528
|
+
"Int8Array",
|
|
529
|
+
"Uint16Array",
|
|
530
|
+
"Int16Array",
|
|
531
|
+
"Uint32Array",
|
|
532
|
+
"Int32Array",
|
|
533
|
+
"Float32Array",
|
|
534
|
+
"Float64Array",
|
|
535
|
+
"ArrayBuffer",
|
|
536
|
+
"Buffer",
|
|
537
|
+
"Iterable",
|
|
538
|
+
"AsyncIterable",
|
|
539
|
+
"Iterator",
|
|
540
|
+
"AsyncIterator",
|
|
541
|
+
"Partial",
|
|
542
|
+
"Required",
|
|
543
|
+
"Readonly",
|
|
544
|
+
"Pick",
|
|
545
|
+
"Omit",
|
|
546
|
+
"Exclude",
|
|
547
|
+
"Extract",
|
|
548
|
+
"NonNullable",
|
|
549
|
+
"Parameters",
|
|
550
|
+
"ConstructorParameters",
|
|
551
|
+
"ReturnType",
|
|
552
|
+
"InstanceType"
|
|
553
|
+
]);
|
|
554
|
+
function detectServiceContext(filePath) {
|
|
555
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
556
|
+
const match = normalized.match(/(?:^|\/)services\/([^/]+)\/libraries\/([^/]+)/);
|
|
557
|
+
if (match) {
|
|
558
|
+
return { serviceName: match[1], libraryName: match[2] };
|
|
559
|
+
}
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
function containsIdentifier(name, target) {
|
|
563
|
+
return name.toLowerCase().includes(target.toLowerCase());
|
|
564
|
+
}
|
|
565
|
+
function isCustomContextualType(typeName, serviceName, localTypes) {
|
|
566
|
+
if (PRIMITIVE_AND_BUILTIN_TYPES.has(typeName)) return false;
|
|
567
|
+
if (localTypes.has(typeName)) return true;
|
|
568
|
+
if (containsIdentifier(typeName, serviceName)) return true;
|
|
569
|
+
if (/^[A-Z][a-zA-Z0-9]+$/.test(typeName)) return true;
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
function hasContextualTypeReference(node, serviceName, localTypes) {
|
|
573
|
+
const typeRefs = node.getDescendantsOfKind(import_ts_morph5.SyntaxKind.TypeReference);
|
|
574
|
+
for (const ref of typeRefs) {
|
|
575
|
+
const text = ref.getTypeName().getText().trim();
|
|
576
|
+
if (isCustomContextualType(text, serviceName, localTypes)) {
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
function checkScopedLibraryRules(sf) {
|
|
583
|
+
const errors = [];
|
|
584
|
+
const warnings = [];
|
|
585
|
+
const promotableAssets = [];
|
|
586
|
+
const filePath = sf.getFilePath().replace(/\\/g, "/");
|
|
587
|
+
const context = detectServiceContext(filePath);
|
|
588
|
+
if (!context) {
|
|
589
|
+
return { errors, warnings, promotableAssets };
|
|
590
|
+
}
|
|
591
|
+
const { serviceName, libraryName } = context;
|
|
592
|
+
const localTypes = /* @__PURE__ */ new Set();
|
|
593
|
+
sf.getInterfaces().forEach((i) => localTypes.add(i.getName()));
|
|
594
|
+
sf.getTypeAliases().forEach((t) => localTypes.add(t.getName()));
|
|
595
|
+
sf.getClasses().forEach((c) => {
|
|
596
|
+
const n = c.getName();
|
|
597
|
+
if (n) localTypes.add(n);
|
|
598
|
+
});
|
|
599
|
+
sf.getEnums().forEach((e) => localTypes.add(e.getName()));
|
|
600
|
+
const functions = sf.getFunctions();
|
|
601
|
+
for (const fn of functions) {
|
|
602
|
+
const fnName = fn.getName();
|
|
603
|
+
if (!fnName) continue;
|
|
604
|
+
const isContextual = hasContextualTypeReference(fn, serviceName, localTypes);
|
|
605
|
+
const hasServiceName = containsIdentifier(fnName, serviceName);
|
|
606
|
+
if (isContextual) {
|
|
607
|
+
if (!hasServiceName) {
|
|
608
|
+
errors.push({
|
|
609
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
610
|
+
filePath,
|
|
611
|
+
line: fn.getStartLineNumber(),
|
|
612
|
+
message: `Service library asset '${fnName}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}'). Expected name containing '${serviceName}' (e.g. '${serviceName.toLowerCase()}${fnName[0].toUpperCase()}${fnName.slice(1)}'), or eliminate contextual custom type dependencies to make it a generic promotable utility.`,
|
|
613
|
+
severity: "error"
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
} else {
|
|
617
|
+
promotableAssets.push({
|
|
618
|
+
name: fnName,
|
|
619
|
+
kind: "function",
|
|
620
|
+
filePath,
|
|
621
|
+
scope: "service",
|
|
622
|
+
scopeName: serviceName,
|
|
623
|
+
target: "GutTS"
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
for (const stmt of sf.getVariableStatements()) {
|
|
628
|
+
for (const decl of stmt.getDeclarations()) {
|
|
629
|
+
const varName = decl.getName();
|
|
630
|
+
const init = decl.getInitializer();
|
|
631
|
+
const isFunction = init && (init.getKind() === import_ts_morph5.SyntaxKind.ArrowFunction || init.getKind() === import_ts_morph5.SyntaxKind.FunctionExpression);
|
|
632
|
+
if (isFunction) {
|
|
633
|
+
const isContextual = hasContextualTypeReference(decl, serviceName, localTypes);
|
|
634
|
+
const hasServiceName = containsIdentifier(varName, serviceName);
|
|
635
|
+
if (isContextual) {
|
|
636
|
+
if (!hasServiceName) {
|
|
637
|
+
errors.push({
|
|
638
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
639
|
+
filePath,
|
|
640
|
+
line: decl.getStartLineNumber(),
|
|
641
|
+
message: `Service library asset '${varName}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}'). Expected name containing '${serviceName}', or eliminate contextual custom type dependencies to make it a generic promotable utility.`,
|
|
642
|
+
severity: "error"
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
} else {
|
|
646
|
+
promotableAssets.push({
|
|
647
|
+
name: varName,
|
|
648
|
+
kind: "function",
|
|
649
|
+
filePath,
|
|
650
|
+
scope: "service",
|
|
651
|
+
scopeName: serviceName,
|
|
652
|
+
target: "GutTS"
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
const isContextual = hasContextualTypeReference(decl, serviceName, localTypes);
|
|
657
|
+
const hasServiceName = containsIdentifier(varName, serviceName);
|
|
658
|
+
if (isContextual && !hasServiceName) {
|
|
659
|
+
errors.push({
|
|
660
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
661
|
+
filePath,
|
|
662
|
+
line: decl.getStartLineNumber(),
|
|
663
|
+
message: `Service library asset '${varName}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}').`,
|
|
664
|
+
severity: "error"
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
for (const iface of sf.getInterfaces()) {
|
|
671
|
+
const name = iface.getName();
|
|
672
|
+
const hasServiceName = containsIdentifier(name, serviceName);
|
|
673
|
+
const hasProps = iface.getProperties().length > 0;
|
|
674
|
+
if (hasProps && !hasServiceName) {
|
|
675
|
+
errors.push({
|
|
676
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
677
|
+
filePath,
|
|
678
|
+
line: iface.getStartLineNumber(),
|
|
679
|
+
message: `Service library interface '${name}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}'). Expected name like '${serviceName}${name}'.`,
|
|
680
|
+
severity: "error"
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
for (const t of sf.getTypeAliases()) {
|
|
685
|
+
const name = t.getName();
|
|
686
|
+
const hasServiceName = containsIdentifier(name, serviceName);
|
|
687
|
+
const isContextual = hasContextualTypeReference(t, serviceName, localTypes);
|
|
688
|
+
if (isContextual && !hasServiceName) {
|
|
689
|
+
errors.push({
|
|
690
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
691
|
+
filePath,
|
|
692
|
+
line: t.getStartLineNumber(),
|
|
693
|
+
message: `Service library type alias '${name}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}'). Expected name like '${serviceName}${name}'.`,
|
|
694
|
+
severity: "error"
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
for (const cls of sf.getClasses()) {
|
|
699
|
+
const name = cls.getName();
|
|
700
|
+
if (!name) continue;
|
|
701
|
+
const hasServiceName = containsIdentifier(name, serviceName);
|
|
702
|
+
if (!hasServiceName) {
|
|
703
|
+
errors.push({
|
|
704
|
+
ruleId: "krnl/service-library-asset-naming",
|
|
705
|
+
filePath,
|
|
706
|
+
line: cls.getStartLineNumber(),
|
|
707
|
+
message: `Service library class '${name}' in service '${serviceName}' violates scoped library naming convention. Custom library asset identifiers must contain the owning service name ('${serviceName}'). Expected name like '${serviceName}${name}'.`,
|
|
708
|
+
severity: "error"
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return { errors, warnings, promotableAssets };
|
|
713
|
+
}
|
|
447
714
|
var KrnlValidatorEngine = class {
|
|
448
715
|
project;
|
|
449
716
|
projectRoot;
|
|
450
717
|
limitOptions;
|
|
451
718
|
constructor(optionsOrRoot) {
|
|
452
719
|
const options = typeof optionsOrRoot === "string" ? { projectRoot: optionsOrRoot } : optionsOrRoot;
|
|
453
|
-
this.projectRoot =
|
|
720
|
+
this.projectRoot = path3.resolve(options.projectRoot || process.cwd());
|
|
454
721
|
this.limitOptions = {
|
|
455
722
|
maxFileLineLimit: options.maxFileLineLimit ?? 200,
|
|
456
723
|
maxMainLogicLimit: options.maxMainLogicLimit ?? 20,
|
|
457
724
|
maxHelperLineLimit: options.maxHelperLineLimit ?? 30
|
|
458
725
|
};
|
|
459
|
-
const tsConfigPath =
|
|
726
|
+
const tsConfigPath = path3.join(this.projectRoot, "tsconfig.json");
|
|
460
727
|
if (fs2.existsSync(tsConfigPath)) {
|
|
461
728
|
this.project = new import_ts_morph.Project({ tsConfigFilePath: tsConfigPath, skipAddingFilesFromTsConfig: true });
|
|
462
729
|
} else {
|
|
@@ -470,33 +737,55 @@ var KrnlValidatorEngine = class {
|
|
|
470
737
|
const files = this.collectSourceFiles(this.projectRoot);
|
|
471
738
|
const errors = [];
|
|
472
739
|
const warnings = [];
|
|
740
|
+
const promotableAssets = [];
|
|
473
741
|
checkWorkspaceLayout(this.projectRoot, errors);
|
|
474
742
|
for (const f of files) {
|
|
475
743
|
const sf = this.project.addSourceFileAtPath(f);
|
|
476
744
|
const fileReport = this.validateSourceFile(sf);
|
|
477
745
|
errors.push(...fileReport.errors);
|
|
478
746
|
warnings.push(...fileReport.warnings);
|
|
747
|
+
if (fileReport.promotableAssets) {
|
|
748
|
+
promotableAssets.push(...fileReport.promotableAssets);
|
|
749
|
+
}
|
|
479
750
|
}
|
|
480
751
|
return {
|
|
481
752
|
valid: errors.length === 0,
|
|
482
753
|
totalFiles: files.length,
|
|
483
754
|
errors,
|
|
484
|
-
warnings
|
|
755
|
+
warnings,
|
|
756
|
+
promotableAssets
|
|
485
757
|
};
|
|
486
758
|
}
|
|
487
759
|
validateSourceFile(sf) {
|
|
488
760
|
const filePath = sf.getFilePath();
|
|
489
|
-
const baseName =
|
|
761
|
+
const baseName = path3.basename(filePath);
|
|
490
762
|
if (baseName.includes("_pb.") || baseName.endsWith(".d.ts")) {
|
|
491
|
-
return { errors: [], warnings: [] };
|
|
763
|
+
return { errors: [], warnings: [], promotableAssets: [] };
|
|
492
764
|
}
|
|
493
765
|
const limits = checkFileLimits(sf, this.limitOptions);
|
|
494
766
|
const purity = checkTopLevelPurity(sf);
|
|
495
767
|
const components = checkComponentRules(sf);
|
|
496
|
-
const
|
|
768
|
+
const orchestration = checkOrchestrationRules(sf);
|
|
769
|
+
const boundaries = checkServiceBoundaries(sf);
|
|
770
|
+
const scopedLibraries = checkScopedLibraryRules(sf);
|
|
497
771
|
return {
|
|
498
|
-
errors: [
|
|
499
|
-
|
|
772
|
+
errors: [
|
|
773
|
+
...limits.errors,
|
|
774
|
+
...purity.errors,
|
|
775
|
+
...components.errors,
|
|
776
|
+
...orchestration.errors,
|
|
777
|
+
...boundaries.errors,
|
|
778
|
+
...scopedLibraries.errors
|
|
779
|
+
],
|
|
780
|
+
warnings: [
|
|
781
|
+
...limits.warnings,
|
|
782
|
+
...purity.warnings,
|
|
783
|
+
...components.warnings,
|
|
784
|
+
...orchestration.warnings,
|
|
785
|
+
...boundaries.warnings,
|
|
786
|
+
...scopedLibraries.warnings
|
|
787
|
+
],
|
|
788
|
+
promotableAssets: scopedLibraries.promotableAssets
|
|
500
789
|
};
|
|
501
790
|
}
|
|
502
791
|
collectSourceFiles(dir, collected = []) {
|
|
@@ -504,7 +793,7 @@ var KrnlValidatorEngine = class {
|
|
|
504
793
|
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
505
794
|
for (const entry of entries) {
|
|
506
795
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
507
|
-
const full =
|
|
796
|
+
const full = path3.join(dir, entry.name);
|
|
508
797
|
if (entry.isDirectory()) {
|
|
509
798
|
this.collectSourceFiles(full, collected);
|
|
510
799
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js") || entry.name.endsWith(".tsx") || entry.name.endsWith(".jsx"))) {
|
|
@@ -539,124 +828,98 @@ async function runValidate(projectRoot = process.cwd()) {
|
|
|
539
828
|
}
|
|
540
829
|
return false;
|
|
541
830
|
}
|
|
831
|
+
if (report.promotableAssets && report.promotableAssets.length > 0) {
|
|
832
|
+
console.log(`\u{1F4E6} [PROMOTABLE ASSETS] Detected ${report.promotableAssets.length} generic library asset(s) eligible for GutTS promotion:`);
|
|
833
|
+
for (const asset of report.promotableAssets) {
|
|
834
|
+
console.log(` \u2726 [${asset.scope}:${asset.scopeName}] ${asset.name} (${asset.kind}) -> ${asset.target}`);
|
|
835
|
+
}
|
|
836
|
+
console.log("");
|
|
837
|
+
}
|
|
542
838
|
console.log(`\u2705 [VALIDATION PASSED] ${report.totalFiles} source files verified clean against Krnl paradigms.
|
|
543
839
|
`);
|
|
544
840
|
return true;
|
|
545
841
|
}
|
|
546
842
|
|
|
547
|
-
// src/commands/generators/
|
|
843
|
+
// src/commands/generators/functionalityOrchestrationGenerator.ts
|
|
844
|
+
var path5 = __toESM(require("path"), 1);
|
|
548
845
|
var fs4 = __toESM(require("fs"), 1);
|
|
549
|
-
var path6 = __toESM(require("path"), 1);
|
|
550
846
|
|
|
551
847
|
// src/commands/generators/common.ts
|
|
552
848
|
var fs3 = __toESM(require("fs"), 1);
|
|
553
|
-
var
|
|
849
|
+
var path4 = __toESM(require("path"), 1);
|
|
554
850
|
function getPlaneRoots(projectRoot) {
|
|
555
|
-
const krnlRoot =
|
|
851
|
+
const krnlRoot = path4.join(projectRoot, "krnl");
|
|
556
852
|
if (fs3.existsSync(krnlRoot)) {
|
|
557
853
|
return {
|
|
558
|
-
backend:
|
|
559
|
-
frontend:
|
|
854
|
+
backend: path4.join(krnlRoot, "backend"),
|
|
855
|
+
frontend: path4.join(krnlRoot, "frontend"),
|
|
560
856
|
isKrnlDir: true
|
|
561
857
|
};
|
|
562
858
|
}
|
|
563
859
|
return {
|
|
564
|
-
backend:
|
|
565
|
-
frontend:
|
|
860
|
+
backend: path4.join(projectRoot, "src"),
|
|
861
|
+
frontend: path4.join(projectRoot, "src"),
|
|
566
862
|
isKrnlDir: false
|
|
567
863
|
};
|
|
568
864
|
}
|
|
569
865
|
|
|
570
|
-
// src/commands/generators/
|
|
571
|
-
function
|
|
572
|
-
const { backend
|
|
573
|
-
const
|
|
574
|
-
fs4.mkdirSync(
|
|
575
|
-
fs4.mkdirSync(path6.join(bEntityDir, "tests"), { recursive: true });
|
|
866
|
+
// src/commands/generators/functionalityOrchestrationGenerator.ts
|
|
867
|
+
function generateFunctionalityOrchestration(name, projectRoot) {
|
|
868
|
+
const { backend } = getPlaneRoots(projectRoot);
|
|
869
|
+
const orchDir = path5.join(backend, "orchestrations", name);
|
|
870
|
+
fs4.mkdirSync(path5.join(orchDir, "tests"), { recursive: true });
|
|
576
871
|
fs4.writeFileSync(
|
|
577
|
-
|
|
578
|
-
`import {
|
|
872
|
+
path5.join(orchDir, `${name}FunctionalityOrchestration.ts`),
|
|
873
|
+
`import { FunctionalityOrchestration } from '@ultrst-armada/krnl-core';
|
|
579
874
|
|
|
580
875
|
/**
|
|
581
|
-
* @role
|
|
876
|
+
* @role functionality-orchestration
|
|
877
|
+
* Declaratively composes functionalities within this service into named flows.
|
|
582
878
|
*/
|
|
583
|
-
export class ${name} extends
|
|
879
|
+
export class ${name}FunctionalityOrchestration extends FunctionalityOrchestration {
|
|
584
880
|
constructor() {
|
|
585
881
|
super({
|
|
586
|
-
id:
|
|
587
|
-
|
|
588
|
-
|
|
882
|
+
id: '${name}FunctionalityOrchestration',
|
|
883
|
+
name: '${name}',
|
|
884
|
+
version: '1.0.0',
|
|
885
|
+
description: '${name} declarative functionality orchestration flow',
|
|
589
886
|
});
|
|
590
|
-
}
|
|
591
887
|
|
|
592
|
-
|
|
593
|
-
|
|
888
|
+
this.flow('default')
|
|
889
|
+
.thenFunctionality('Execute${name}')
|
|
890
|
+
.register({ visibility: 'public' });
|
|
594
891
|
}
|
|
595
892
|
}
|
|
596
893
|
|
|
597
|
-
export default ${name};
|
|
598
|
-
`
|
|
599
|
-
);
|
|
600
|
-
fs4.writeFileSync(
|
|
601
|
-
path6.join(bEntityDir, "orchestrations", "DefaultFlow.ts"),
|
|
602
|
-
`export function configureDefaultFlow(entity: any) {
|
|
603
|
-
return entity.flow("defaultFlow")
|
|
604
|
-
.register({ visibility: "public" });
|
|
605
|
-
}
|
|
606
|
-
`
|
|
607
|
-
);
|
|
608
|
-
fs4.writeFileSync(
|
|
609
|
-
path6.join(bEntityDir, "tests", `${name}.test.ts`),
|
|
610
|
-
`import { describe, it, expect } from "vitest";
|
|
611
|
-
import { ${name} } from "../${name}.js";
|
|
612
|
-
|
|
613
|
-
describe("${name} Entity", () => {
|
|
614
|
-
it("instantiates correctly", () => {
|
|
615
|
-
const instance = new ${name}();
|
|
616
|
-
expect(instance.id).toBe("${name}");
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
`
|
|
620
|
-
);
|
|
621
|
-
const fEntityDir = path6.join(frontend, "entities", name);
|
|
622
|
-
fs4.mkdirSync(path6.join(fEntityDir, "tests"), { recursive: true });
|
|
623
|
-
fs4.writeFileSync(
|
|
624
|
-
path6.join(fEntityDir, `${name}0.tsx`),
|
|
625
|
-
`import React from "react";
|
|
626
|
-
|
|
627
|
-
export const ${name}0: React.FC = () => {
|
|
628
|
-
return (
|
|
629
|
-
<div className="krnl-entity-${name.toLowerCase()}">
|
|
630
|
-
<h2>${name} (Variant 0)</h2>
|
|
631
|
-
</div>
|
|
632
|
-
);
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
export default ${name}0;
|
|
894
|
+
export default ${name}FunctionalityOrchestration;
|
|
636
895
|
`
|
|
637
896
|
);
|
|
638
897
|
fs4.writeFileSync(
|
|
639
|
-
|
|
640
|
-
`import { describe, it, expect } from
|
|
898
|
+
path5.join(orchDir, "tests", `${name}FunctionalityOrchestration.test.ts`),
|
|
899
|
+
`import { describe, it, expect } from 'vitest';
|
|
900
|
+
import { ${name}FunctionalityOrchestration } from '../${name}FunctionalityOrchestration.js';
|
|
641
901
|
|
|
642
|
-
describe(
|
|
643
|
-
it(
|
|
644
|
-
|
|
902
|
+
describe('${name}FunctionalityOrchestration', () => {
|
|
903
|
+
it('instantiates and configures declarative functionality flow correctly', () => {
|
|
904
|
+
const orchestration = new ${name}FunctionalityOrchestration();
|
|
905
|
+
expect(orchestration.id).toBe('${name}FunctionalityOrchestration');
|
|
906
|
+
expect(orchestration.getFlow('default')).toBeDefined();
|
|
907
|
+
expect(orchestration.getFlow('default')?.steps).toHaveLength(1);
|
|
645
908
|
});
|
|
646
909
|
});
|
|
647
910
|
`
|
|
648
911
|
);
|
|
649
|
-
console.log(`\u2705 Created
|
|
650
|
-
console.log(`\u2705 Created Frontend Entity Folder: krnl/frontend/entities/${name}/`);
|
|
912
|
+
console.log(`\u2705 Created FunctionalityOrchestration: krnl/backend/orchestrations/${name}/`);
|
|
651
913
|
}
|
|
652
914
|
|
|
653
915
|
// src/commands/generators/functionalityGenerator.ts
|
|
654
916
|
var fs6 = __toESM(require("fs"), 1);
|
|
655
|
-
var
|
|
917
|
+
var path7 = __toESM(require("path"), 1);
|
|
656
918
|
|
|
657
919
|
// ../core/dist/index.js
|
|
658
920
|
var fs5 = __toESM(require("fs"), 1);
|
|
659
|
-
var
|
|
921
|
+
var path6 = __toESM(require("path"), 1);
|
|
922
|
+
var asyncHooks = globalThis.process?.getBuiltinModule?.("node:async_hooks");
|
|
660
923
|
var KrnlPackageReconciler = class {
|
|
661
924
|
/**
|
|
662
925
|
* Scans all manifest.json files across backend and frontend and reconciles root package.json.
|
|
@@ -704,7 +967,7 @@ var KrnlPackageReconciler = class {
|
|
|
704
967
|
}
|
|
705
968
|
resolvedDevDeps[pkg] = versions[versions.length - 1];
|
|
706
969
|
}
|
|
707
|
-
const pkgJsonPath =
|
|
970
|
+
const pkgJsonPath = path6.join(projectRoot, "package.json");
|
|
708
971
|
let updated = false;
|
|
709
972
|
if (fs5.existsSync(pkgJsonPath)) {
|
|
710
973
|
const pkgContent = JSON.parse(fs5.readFileSync(pkgJsonPath, "utf8"));
|
|
@@ -742,12 +1005,15 @@ var KrnlPackageReconciler = class {
|
|
|
742
1005
|
*/
|
|
743
1006
|
static findManifests(projectRoot) {
|
|
744
1007
|
const searchDirs = [
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1008
|
+
path6.join(projectRoot, "krnl", "backend", "services"),
|
|
1009
|
+
path6.join(projectRoot, "krnl", "backend", "libraries"),
|
|
1010
|
+
path6.join(projectRoot, "krnl", "backend", "functionalities"),
|
|
1011
|
+
path6.join(projectRoot, "krnl", "frontend", "libraries"),
|
|
1012
|
+
path6.join(projectRoot, "krnl", "frontend", "functionalities"),
|
|
1013
|
+
path6.join(projectRoot, "src", "backend", "services"),
|
|
1014
|
+
path6.join(projectRoot, "src", "services"),
|
|
1015
|
+
path6.join(projectRoot, "src", "functionalities"),
|
|
1016
|
+
path6.join(projectRoot, "src", "libraries")
|
|
751
1017
|
];
|
|
752
1018
|
const found = [];
|
|
753
1019
|
for (const dir of searchDirs) {
|
|
@@ -762,7 +1028,7 @@ var KrnlPackageReconciler = class {
|
|
|
762
1028
|
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
763
1029
|
for (const entry of entries) {
|
|
764
1030
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
765
|
-
const full =
|
|
1031
|
+
const full = path6.join(dir, entry.name);
|
|
766
1032
|
if (entry.isDirectory()) {
|
|
767
1033
|
this.scanRecursive(full, found);
|
|
768
1034
|
} else if (entry.isFile() && entry.name === "manifest.json") {
|
|
@@ -775,16 +1041,40 @@ var KrnlPackageReconciler = class {
|
|
|
775
1041
|
};
|
|
776
1042
|
|
|
777
1043
|
// src/commands/generators/functionalityGenerator.ts
|
|
778
|
-
function generateFunctionality(name, projectRoot) {
|
|
1044
|
+
function generateFunctionality(name, projectRoot, parentServiceOrOptions) {
|
|
779
1045
|
const { backend, frontend } = getPlaneRoots(projectRoot);
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
1046
|
+
const options = typeof parentServiceOrOptions === "string" ? { parentService: parentServiceOrOptions } : parentServiceOrOptions || {};
|
|
1047
|
+
let targetService = options.parentService;
|
|
1048
|
+
if (!targetService) {
|
|
1049
|
+
const servicesDir = path7.join(backend, "services");
|
|
1050
|
+
if (fs6.existsSync(servicesDir)) {
|
|
1051
|
+
const existing = fs6.readdirSync(servicesDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1052
|
+
if (existing.length === 1) {
|
|
1053
|
+
targetService = existing[0].name;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
const bFuncDir = targetService ? path7.join(backend, "services", targetService, "functionalities", name) : path7.join(backend, "functionalities", name);
|
|
1058
|
+
fs6.mkdirSync(path7.join(bFuncDir, "main_function"), { recursive: true });
|
|
1059
|
+
fs6.mkdirSync(path7.join(bFuncDir, "helper_functions"), { recursive: true });
|
|
1060
|
+
fs6.mkdirSync(path7.join(bFuncDir, "events"), { recursive: true });
|
|
1061
|
+
fs6.mkdirSync(path7.join(bFuncDir, "tests"), { recursive: true });
|
|
1062
|
+
if (options.withState) {
|
|
1063
|
+
fs6.mkdirSync(path7.join(bFuncDir, "state_data"), { recursive: true });
|
|
1064
|
+
fs6.writeFileSync(
|
|
1065
|
+
path7.join(bFuncDir, "state_data", "state.ts"),
|
|
1066
|
+
`export interface ${name}State {
|
|
1067
|
+
executionCount: number;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
export const initialState: ${name}State = {
|
|
1071
|
+
executionCount: 0
|
|
1072
|
+
};
|
|
1073
|
+
`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
786
1076
|
fs6.writeFileSync(
|
|
787
|
-
|
|
1077
|
+
path7.join(bFuncDir, `${name}Atom.ts`),
|
|
788
1078
|
`export interface ${name}Input {
|
|
789
1079
|
payload?: string;
|
|
790
1080
|
}
|
|
@@ -796,10 +1086,11 @@ export interface ${name}Output {
|
|
|
796
1086
|
`
|
|
797
1087
|
);
|
|
798
1088
|
fs6.writeFileSync(
|
|
799
|
-
|
|
1089
|
+
path7.join(bFuncDir, "manifest.json"),
|
|
800
1090
|
JSON.stringify(
|
|
801
1091
|
{
|
|
802
1092
|
name,
|
|
1093
|
+
service: targetService || void 0,
|
|
803
1094
|
description: `${name} quad-unit functionality`,
|
|
804
1095
|
dependencies: {}
|
|
805
1096
|
},
|
|
@@ -808,10 +1099,10 @@ export interface ${name}Output {
|
|
|
808
1099
|
)
|
|
809
1100
|
);
|
|
810
1101
|
fs6.writeFileSync(
|
|
811
|
-
|
|
1102
|
+
path7.join(bFuncDir, "main_function", "logic.ts"),
|
|
812
1103
|
`import type { ${name}Input, ${name}Output } from "../${name}Atom.js";
|
|
813
1104
|
|
|
814
|
-
export const main = async (input: ${name}Input,
|
|
1105
|
+
export const main = async (input: ${name}Input, context: any): Promise<${name}Output> => {
|
|
815
1106
|
return {
|
|
816
1107
|
success: true,
|
|
817
1108
|
timestamp: Date.now()
|
|
@@ -820,24 +1111,13 @@ export const main = async (input: ${name}Input, { state }: any): Promise<${name}
|
|
|
820
1111
|
`
|
|
821
1112
|
);
|
|
822
1113
|
fs6.writeFileSync(
|
|
823
|
-
|
|
1114
|
+
path7.join(bFuncDir, "main_function", "lifecycle.ts"),
|
|
824
1115
|
`export async function onMount() {}
|
|
825
1116
|
export async function onTeardown() {}
|
|
826
1117
|
`
|
|
827
1118
|
);
|
|
828
1119
|
fs6.writeFileSync(
|
|
829
|
-
|
|
830
|
-
`export interface ${name}State {
|
|
831
|
-
executionCount: number;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
export const initialState: ${name}State = {
|
|
835
|
-
executionCount: 0
|
|
836
|
-
};
|
|
837
|
-
`
|
|
838
|
-
);
|
|
839
|
-
fs6.writeFileSync(
|
|
840
|
-
path8.join(bFuncDir, "helper_functions", "helper.ts"),
|
|
1120
|
+
path7.join(bFuncDir, "helper_functions", "helper.ts"),
|
|
841
1121
|
`/**
|
|
842
1122
|
* @role component
|
|
843
1123
|
*/
|
|
@@ -847,7 +1127,7 @@ export function exampleHelper(): boolean {
|
|
|
847
1127
|
`
|
|
848
1128
|
);
|
|
849
1129
|
fs6.writeFileSync(
|
|
850
|
-
|
|
1130
|
+
path7.join(bFuncDir, "events", "events.ts"),
|
|
851
1131
|
`/**
|
|
852
1132
|
* @role component
|
|
853
1133
|
*/
|
|
@@ -857,7 +1137,7 @@ export interface ${name}CompletedEvent {
|
|
|
857
1137
|
`
|
|
858
1138
|
);
|
|
859
1139
|
fs6.writeFileSync(
|
|
860
|
-
|
|
1140
|
+
path7.join(bFuncDir, "tests", `${name}.test.ts`),
|
|
861
1141
|
`import { describe, it, expect } from "vitest";
|
|
862
1142
|
|
|
863
1143
|
describe("${name} functionality", () => {
|
|
@@ -867,10 +1147,10 @@ describe("${name} functionality", () => {
|
|
|
867
1147
|
});
|
|
868
1148
|
`
|
|
869
1149
|
);
|
|
870
|
-
const fFuncDir =
|
|
871
|
-
fs6.mkdirSync(
|
|
1150
|
+
const fFuncDir = path7.join(frontend, "functionalities", name);
|
|
1151
|
+
fs6.mkdirSync(path7.join(fFuncDir, "tests"), { recursive: true });
|
|
872
1152
|
fs6.writeFileSync(
|
|
873
|
-
|
|
1153
|
+
path7.join(fFuncDir, `${name}0.tsx`),
|
|
874
1154
|
`import React from "react";
|
|
875
1155
|
|
|
876
1156
|
export const ${name}0: React.FC = () => {
|
|
@@ -885,11 +1165,11 @@ export default ${name}0;
|
|
|
885
1165
|
`
|
|
886
1166
|
);
|
|
887
1167
|
fs6.writeFileSync(
|
|
888
|
-
|
|
1168
|
+
path7.join(fFuncDir, "manifest.json"),
|
|
889
1169
|
JSON.stringify({ name: `${name}UI`, dependencies: {} }, null, 2)
|
|
890
1170
|
);
|
|
891
1171
|
fs6.writeFileSync(
|
|
892
|
-
|
|
1172
|
+
path7.join(fFuncDir, "tests", `${name}0.test.tsx`),
|
|
893
1173
|
`import { describe, it, expect } from "vitest";
|
|
894
1174
|
|
|
895
1175
|
describe("${name}0 Component", () => {
|
|
@@ -900,20 +1180,33 @@ describe("${name}0 Component", () => {
|
|
|
900
1180
|
`
|
|
901
1181
|
);
|
|
902
1182
|
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
903
|
-
console.log(`\u2705 Created Backend Functionality
|
|
904
|
-
console.log(`\u2705 Created Frontend Functionality:
|
|
1183
|
+
console.log(`\u2705 Created Backend Functionality: ${path7.relative(projectRoot, bFuncDir)}/`);
|
|
1184
|
+
console.log(`\u2705 Created Frontend Functionality: ${path7.relative(projectRoot, fFuncDir)}/`);
|
|
905
1185
|
}
|
|
906
1186
|
|
|
907
1187
|
// src/commands/generators/libraryGenerator.ts
|
|
908
1188
|
var fs7 = __toESM(require("fs"), 1);
|
|
909
|
-
var
|
|
910
|
-
function generateLibrary(name, projectRoot) {
|
|
1189
|
+
var path8 = __toESM(require("path"), 1);
|
|
1190
|
+
function generateLibrary(name, projectRoot, parentService) {
|
|
911
1191
|
const { backend, frontend } = getPlaneRoots(projectRoot);
|
|
912
1192
|
const conceptName = name.endsWith("Concepts") ? name : `${name}Concepts`;
|
|
913
|
-
|
|
914
|
-
|
|
1193
|
+
let targetService = parentService;
|
|
1194
|
+
if (!targetService) {
|
|
1195
|
+
const servicesDir = path8.join(backend, "services");
|
|
1196
|
+
if (fs7.existsSync(servicesDir)) {
|
|
1197
|
+
const existing = fs7.readdirSync(servicesDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1198
|
+
if (existing.length === 1) {
|
|
1199
|
+
targetService = existing[0].name;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (!targetService) {
|
|
1204
|
+
targetService = "App";
|
|
1205
|
+
}
|
|
1206
|
+
const bLibDir = path8.join(backend, "services", targetService, "libraries", conceptName);
|
|
1207
|
+
fs7.mkdirSync(path8.join(bLibDir, "tests"), { recursive: true });
|
|
915
1208
|
fs7.writeFileSync(
|
|
916
|
-
|
|
1209
|
+
path8.join(bLibDir, "definitions.ts"),
|
|
917
1210
|
`/**
|
|
918
1211
|
* @file definitions.ts
|
|
919
1212
|
* @role component
|
|
@@ -924,7 +1217,7 @@ export interface ${conceptName}Options {
|
|
|
924
1217
|
`
|
|
925
1218
|
);
|
|
926
1219
|
fs7.writeFileSync(
|
|
927
|
-
|
|
1220
|
+
path8.join(bLibDir, "functions.ts"),
|
|
928
1221
|
`/**
|
|
929
1222
|
* @file functions.ts
|
|
930
1223
|
* @role component
|
|
@@ -937,31 +1230,38 @@ export function ${name.toLowerCase()}Transform<T>(data: T, _opts?: ${conceptName
|
|
|
937
1230
|
`
|
|
938
1231
|
);
|
|
939
1232
|
fs7.writeFileSync(
|
|
940
|
-
|
|
941
|
-
|
|
1233
|
+
path8.join(bLibDir, "index.ts"),
|
|
1234
|
+
`export * from "./definitions.js";
|
|
1235
|
+
export * from "./functions.js";
|
|
1236
|
+
`
|
|
942
1237
|
);
|
|
943
1238
|
fs7.writeFileSync(
|
|
944
|
-
|
|
1239
|
+
path8.join(bLibDir, "manifest.json"),
|
|
1240
|
+
JSON.stringify({ name: conceptName, service: targetService, dependencies: {} }, null, 2)
|
|
1241
|
+
);
|
|
1242
|
+
fs7.writeFileSync(
|
|
1243
|
+
path8.join(bLibDir, "tests", `${conceptName}.test.ts`),
|
|
945
1244
|
`import { describe, it, expect } from "vitest";
|
|
1245
|
+
import { ${name.toLowerCase()}Transform } from "../functions.js";
|
|
946
1246
|
|
|
947
1247
|
describe("${conceptName}", () => {
|
|
948
1248
|
it("runs correctly", () => {
|
|
949
|
-
expect(
|
|
1249
|
+
expect(${name.toLowerCase()}Transform(42)).toBe(42);
|
|
950
1250
|
});
|
|
951
1251
|
});
|
|
952
1252
|
`
|
|
953
1253
|
);
|
|
954
|
-
const fLibDir =
|
|
955
|
-
fs7.mkdirSync(
|
|
1254
|
+
const fLibDir = path8.join(frontend, "libraries", conceptName);
|
|
1255
|
+
fs7.mkdirSync(path8.join(fLibDir, "tests"), { recursive: true });
|
|
956
1256
|
fs7.writeFileSync(
|
|
957
|
-
|
|
1257
|
+
path8.join(fLibDir, "definitions.ts"),
|
|
958
1258
|
`export interface ${name}Props {
|
|
959
1259
|
label?: string;
|
|
960
1260
|
}
|
|
961
1261
|
`
|
|
962
1262
|
);
|
|
963
1263
|
fs7.writeFileSync(
|
|
964
|
-
|
|
1264
|
+
path8.join(fLibDir, "components.tsx"),
|
|
965
1265
|
`import React from "react";
|
|
966
1266
|
import type { ${name}Props } from "./definitions.js";
|
|
967
1267
|
import "./styles.css";
|
|
@@ -972,18 +1272,18 @@ export const ${name}: React.FC<${name}Props> = ({ label = "${name}" }) => {
|
|
|
972
1272
|
`
|
|
973
1273
|
);
|
|
974
1274
|
fs7.writeFileSync(
|
|
975
|
-
|
|
1275
|
+
path8.join(fLibDir, "styles.css"),
|
|
976
1276
|
`.krnl-${name.toLowerCase()} {
|
|
977
1277
|
font-family: inherit;
|
|
978
1278
|
}
|
|
979
1279
|
`
|
|
980
1280
|
);
|
|
981
1281
|
fs7.writeFileSync(
|
|
982
|
-
|
|
1282
|
+
path8.join(fLibDir, "manifest.json"),
|
|
983
1283
|
JSON.stringify({ name: `${conceptName}UI`, dependencies: {} }, null, 2)
|
|
984
1284
|
);
|
|
985
1285
|
fs7.writeFileSync(
|
|
986
|
-
|
|
1286
|
+
path8.join(fLibDir, "tests", `${name}.test.tsx`),
|
|
987
1287
|
`import { describe, it, expect } from "vitest";
|
|
988
1288
|
|
|
989
1289
|
describe("${name} UI Concept", () => {
|
|
@@ -994,82 +1294,165 @@ describe("${name} UI Concept", () => {
|
|
|
994
1294
|
`
|
|
995
1295
|
);
|
|
996
1296
|
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
997
|
-
console.log(`\u2705 Created
|
|
998
|
-
console.log(`\u2705 Created Frontend Concept Library:
|
|
1297
|
+
console.log(`\u2705 Created Service-Owned Library: ${path8.relative(projectRoot, bLibDir)}/ (Owner: ${targetService})`);
|
|
1298
|
+
console.log(`\u2705 Created Frontend Concept Library: ${path8.relative(projectRoot, fLibDir)}/`);
|
|
999
1299
|
}
|
|
1000
|
-
|
|
1300
|
+
|
|
1301
|
+
// src/commands/generators/serviceGenerator.ts
|
|
1302
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
1303
|
+
var path9 = __toESM(require("path"), 1);
|
|
1304
|
+
function generateService(name, projectRoot, defaultFrontend) {
|
|
1305
|
+
const frontendReference = defaultFrontend?.component ? {
|
|
1306
|
+
component: defaultFrontend.component,
|
|
1307
|
+
...defaultFrontend.package ? { package: defaultFrontend.package } : {},
|
|
1308
|
+
...defaultFrontend.export ? { export: defaultFrontend.export } : {},
|
|
1309
|
+
relationship: defaultFrontend.relationship ?? "recommended"
|
|
1310
|
+
} : void 0;
|
|
1311
|
+
const frontendConfig = frontendReference ? JSON.stringify(frontendReference, null, 2).replace(/\n/g, "\n ") : void 0;
|
|
1001
1312
|
const { backend } = getPlaneRoots(projectRoot);
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
)
|
|
1313
|
+
const serviceDir = path9.join(backend, "services", name);
|
|
1314
|
+
const funcsDir = path9.join(serviceDir, "functionalities");
|
|
1315
|
+
const orchsDir = path9.join(serviceDir, "orchestrations");
|
|
1316
|
+
const libsDir = path9.join(serviceDir, "libraries");
|
|
1317
|
+
const testsDir = path9.join(serviceDir, "tests");
|
|
1318
|
+
fs8.mkdirSync(funcsDir, { recursive: true });
|
|
1319
|
+
fs8.mkdirSync(orchsDir, { recursive: true });
|
|
1320
|
+
fs8.mkdirSync(libsDir, { recursive: true });
|
|
1321
|
+
fs8.mkdirSync(testsDir, { recursive: true });
|
|
1322
|
+
const conceptName = `${name}Concepts`;
|
|
1323
|
+
const defaultLibDir = path9.join(libsDir, conceptName);
|
|
1324
|
+
fs8.mkdirSync(path9.join(defaultLibDir, "tests"), { recursive: true });
|
|
1325
|
+
fs8.writeFileSync(
|
|
1326
|
+
path9.join(defaultLibDir, "definitions.ts"),
|
|
1327
|
+
`/**
|
|
1328
|
+
* @file definitions.ts
|
|
1329
|
+
* @role component
|
|
1330
|
+
*/
|
|
1331
|
+
export interface ${name}Options {
|
|
1332
|
+
enabled?: boolean;
|
|
1333
|
+
}
|
|
1334
|
+
`
|
|
1016
1335
|
);
|
|
1017
|
-
|
|
1018
|
-
path9.join(
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1336
|
+
fs8.writeFileSync(
|
|
1337
|
+
path9.join(defaultLibDir, "functions.ts"),
|
|
1338
|
+
`/**
|
|
1339
|
+
* @file functions.ts
|
|
1340
|
+
* @role component
|
|
1341
|
+
*/
|
|
1342
|
+
import type { ${name}Options } from "./definitions.js";
|
|
1343
|
+
|
|
1344
|
+
export function format${name}Name(input: string, _opts?: ${name}Options): string {
|
|
1345
|
+
return "${name}: " + input;
|
|
1025
1346
|
}
|
|
1026
|
-
export default register;
|
|
1027
1347
|
`
|
|
1028
1348
|
);
|
|
1029
|
-
|
|
1349
|
+
fs8.writeFileSync(
|
|
1350
|
+
path9.join(defaultLibDir, "index.ts"),
|
|
1351
|
+
`export * from "./definitions.js";
|
|
1352
|
+
export * from "./functions.js";
|
|
1353
|
+
`
|
|
1354
|
+
);
|
|
1355
|
+
fs8.writeFileSync(
|
|
1356
|
+
path9.join(defaultLibDir, "manifest.json"),
|
|
1357
|
+
JSON.stringify({ name: conceptName, description: `${name} service-owned library`, dependencies: {} }, null, 2)
|
|
1358
|
+
);
|
|
1359
|
+
fs8.writeFileSync(
|
|
1360
|
+
path9.join(defaultLibDir, "tests", `${conceptName}.test.ts`),
|
|
1361
|
+
`import { describe, it, expect } from "vitest";
|
|
1362
|
+
import { format${name}Name } from "../functions.js";
|
|
1363
|
+
|
|
1364
|
+
describe("${conceptName}", () => {
|
|
1365
|
+
it("formats name correctly", () => {
|
|
1366
|
+
expect(format${name}Name("test")).toContain("${name}");
|
|
1367
|
+
});
|
|
1368
|
+
});
|
|
1369
|
+
`
|
|
1370
|
+
);
|
|
1371
|
+
const frontendProperty = frontendConfig ? ` defaultFrontend: ${frontendConfig},
|
|
1372
|
+
` : "";
|
|
1373
|
+
fs8.writeFileSync(
|
|
1374
|
+
path9.join(serviceDir, `${name}ServiceFacade.ts`),
|
|
1375
|
+
`import { ServiceFacade } from "@ultrst-armada/krnl-core";
|
|
1376
|
+
import * as ${name.toLowerCase()}Concepts from "./libraries/${conceptName}/index.js";
|
|
1377
|
+
|
|
1378
|
+
export const ${name}ServiceFacade = new ServiceFacade({
|
|
1379
|
+
id: "${name.toLowerCase()}.service",
|
|
1380
|
+
name: "${name}Service",
|
|
1381
|
+
version: "1.0.0",
|
|
1382
|
+
description: "${name} service facade",
|
|
1383
|
+
${frontendProperty} libraries: {
|
|
1384
|
+
${conceptName}: ${name.toLowerCase()}Concepts,
|
|
1385
|
+
},
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
export default ${name}ServiceFacade;
|
|
1389
|
+
`
|
|
1390
|
+
);
|
|
1391
|
+
fs8.writeFileSync(
|
|
1392
|
+
path9.join(testsDir, `${name}ServiceFacade.test.ts`),
|
|
1393
|
+
`import { describe, it, expect } from "vitest";
|
|
1394
|
+
import { ${name}ServiceFacade } from "../${name}ServiceFacade.js";
|
|
1395
|
+
|
|
1396
|
+
describe("${name}ServiceFacade", () => {
|
|
1397
|
+
it("initializes and exposes service-owned library", () => {
|
|
1398
|
+
expect(${name}ServiceFacade.id).toBe("${name.toLowerCase()}.service");
|
|
1399
|
+
expect(${name}ServiceFacade.libraries.${conceptName}).toBeDefined();
|
|
1400
|
+
expect(typeof ${name}ServiceFacade.libraries.${conceptName}.format${name}Name).toBe("function");
|
|
1401
|
+
});
|
|
1402
|
+
});
|
|
1403
|
+
`
|
|
1404
|
+
);
|
|
1405
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1406
|
+
console.log(`\u2705 Created Service: ${path9.relative(projectRoot, serviceDir)}/`);
|
|
1030
1407
|
}
|
|
1031
1408
|
|
|
1032
1409
|
// src/commands/generate.ts
|
|
1033
|
-
async function runGenerate(type, name,
|
|
1410
|
+
async function runGenerate(type, name, parentService, projectRoot = process.cwd(), options = {}) {
|
|
1034
1411
|
if (!name) {
|
|
1035
|
-
console.error(
|
|
1412
|
+
console.error(
|
|
1413
|
+
"\u274C Error: Resource name is required. Usage: krnl generate <service|orchestration|functionality|library> <Name> [parentService]"
|
|
1414
|
+
);
|
|
1036
1415
|
process.exit(1);
|
|
1037
1416
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1417
|
+
const normalizedType = type.toLowerCase().replace(/[-_]/g, "");
|
|
1418
|
+
switch (normalizedType) {
|
|
1419
|
+
case "service":
|
|
1420
|
+
generateService(name, projectRoot, options.defaultFrontend);
|
|
1421
|
+
break;
|
|
1422
|
+
case "functionalityorchestration":
|
|
1423
|
+
case "orchestration":
|
|
1424
|
+
generateFunctionalityOrchestration(name, projectRoot);
|
|
1041
1425
|
break;
|
|
1042
1426
|
case "functionality":
|
|
1043
|
-
generateFunctionality(name, projectRoot);
|
|
1427
|
+
generateFunctionality(name, projectRoot, parentService);
|
|
1044
1428
|
break;
|
|
1045
1429
|
case "library":
|
|
1046
|
-
generateLibrary(name, projectRoot);
|
|
1047
|
-
break;
|
|
1048
|
-
case "subapp":
|
|
1049
|
-
generateSubApp(name, projectRoot);
|
|
1430
|
+
generateLibrary(name, projectRoot, parentService);
|
|
1050
1431
|
break;
|
|
1051
1432
|
default:
|
|
1052
|
-
console.error(
|
|
1433
|
+
console.error(
|
|
1434
|
+
`\u274C Unknown resource type "${type}". Valid types: service, orchestration, functionality, library`
|
|
1435
|
+
);
|
|
1053
1436
|
process.exit(1);
|
|
1054
1437
|
}
|
|
1055
1438
|
}
|
|
1056
1439
|
|
|
1057
1440
|
// src/commands/watch.ts
|
|
1058
|
-
var
|
|
1441
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
1059
1442
|
var path10 = __toESM(require("path"), 1);
|
|
1060
1443
|
function generateMagneticDeclarations(projectRoot = process.cwd()) {
|
|
1061
1444
|
const { results: functionalities, libDirs } = scanDirectory(projectRoot);
|
|
1062
1445
|
let dtsContent = `// Automatically generated by Krnl Magnetic Watcher. Do not edit manually.
|
|
1063
1446
|
|
|
1064
1447
|
`;
|
|
1065
|
-
dtsContent += `import {
|
|
1448
|
+
dtsContent += `import { Orchestration } from '@ultrst-armada/krnl-core';
|
|
1066
1449
|
|
|
1067
1450
|
`;
|
|
1068
1451
|
const globalDeclarations = [];
|
|
1069
1452
|
for (const func of functionalities) {
|
|
1070
1453
|
const helpersDir = path10.join(func.funcPath, "helper_functions");
|
|
1071
|
-
if (
|
|
1072
|
-
const files =
|
|
1454
|
+
if (fs9.existsSync(helpersDir)) {
|
|
1455
|
+
const files = fs9.readdirSync(helpersDir);
|
|
1073
1456
|
for (const file of files) {
|
|
1074
1457
|
if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
1075
1458
|
const filePath = path10.join(helpersDir, file);
|
|
@@ -1086,8 +1469,8 @@ function generateMagneticDeclarations(projectRoot = process.cwd()) {
|
|
|
1086
1469
|
}
|
|
1087
1470
|
}
|
|
1088
1471
|
const eventsDir = path10.join(func.funcPath, "events");
|
|
1089
|
-
if (
|
|
1090
|
-
const files =
|
|
1472
|
+
if (fs9.existsSync(eventsDir)) {
|
|
1473
|
+
const files = fs9.readdirSync(eventsDir);
|
|
1091
1474
|
for (const file of files) {
|
|
1092
1475
|
if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
1093
1476
|
const filePath = path10.join(eventsDir, file);
|
|
@@ -1114,12 +1497,12 @@ ${Array.from(new Set(globalDeclarations)).join("\n")}
|
|
|
1114
1497
|
`;
|
|
1115
1498
|
}
|
|
1116
1499
|
const outPath = path10.join(projectRoot, "krnl-magnetic.d.ts");
|
|
1117
|
-
|
|
1500
|
+
fs9.writeFileSync(outPath, dtsContent);
|
|
1118
1501
|
console.log(`[Krnl Watch] Updated ambient declarations: ${outPath}`);
|
|
1119
1502
|
}
|
|
1120
1503
|
function scanLibFiles(dir, projectRoot, decls) {
|
|
1121
|
-
if (!
|
|
1122
|
-
for (const entry of
|
|
1504
|
+
if (!fs9.existsSync(dir)) return;
|
|
1505
|
+
for (const entry of fs9.readdirSync(dir, { withFileTypes: true })) {
|
|
1123
1506
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
1124
1507
|
const full = path10.join(dir, entry.name);
|
|
1125
1508
|
if (entry.isDirectory()) {
|
|
@@ -1134,14 +1517,14 @@ function scanLibFiles(dir, projectRoot, decls) {
|
|
|
1134
1517
|
}
|
|
1135
1518
|
}
|
|
1136
1519
|
function scanDirectory(dir, results = [], libDirs = []) {
|
|
1137
|
-
if (!
|
|
1138
|
-
const list =
|
|
1520
|
+
if (!fs9.existsSync(dir)) return { results, libDirs };
|
|
1521
|
+
const list = fs9.readdirSync(dir, { withFileTypes: true });
|
|
1139
1522
|
for (const entry of list) {
|
|
1140
1523
|
if (entry.isDirectory()) {
|
|
1141
1524
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
1142
1525
|
const fullPath = path10.join(dir, entry.name);
|
|
1143
1526
|
if (entry.name === "functionalities") {
|
|
1144
|
-
const funcs =
|
|
1527
|
+
const funcs = fs9.readdirSync(fullPath, { withFileTypes: true });
|
|
1145
1528
|
for (const f of funcs) {
|
|
1146
1529
|
if (f.isDirectory()) results.push({ funcPath: path10.join(fullPath, f.name), funcName: f.name });
|
|
1147
1530
|
}
|
|
@@ -1155,7 +1538,7 @@ function scanDirectory(dir, results = [], libDirs = []) {
|
|
|
1155
1538
|
return { results, libDirs };
|
|
1156
1539
|
}
|
|
1157
1540
|
function parseExports(filePath, defaultName) {
|
|
1158
|
-
const content =
|
|
1541
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
1159
1542
|
const named = [];
|
|
1160
1543
|
let hasDefault = false;
|
|
1161
1544
|
const namedRegex = /export\s+(?:const|let|var|function|class|async\s+function)\s+([a-zA-Z0-9_$]+)/g;
|
|
@@ -1169,29 +1552,117 @@ function parseExports(filePath, defaultName) {
|
|
|
1169
1552
|
return { named, hasDefault };
|
|
1170
1553
|
}
|
|
1171
1554
|
|
|
1172
|
-
// src/
|
|
1173
|
-
var
|
|
1174
|
-
var
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1555
|
+
// src/commands/build.ts
|
|
1556
|
+
var path11 = __toESM(require("path"), 1);
|
|
1557
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
1558
|
+
var import_child_process = require("child_process");
|
|
1559
|
+
async function runBuild(projectRoot = process.cwd(), options = {}) {
|
|
1560
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1561
|
+
const target = options.service || options.orchestration;
|
|
1562
|
+
if (target) {
|
|
1563
|
+
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Target service/orchestration variant: "${target}"`);
|
|
1564
|
+
} else if (options.all) {
|
|
1565
|
+
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Combined multi-service build`);
|
|
1566
|
+
}
|
|
1567
|
+
console.log("\u{1F50D} [Krnl Build] Running AST & layer purity validation...");
|
|
1568
|
+
const valid = await runValidate(projectRoot);
|
|
1569
|
+
if (!valid) {
|
|
1570
|
+
console.error("\u274C [Krnl Build] Build aborted due to validation errors.");
|
|
1571
|
+
return { success: false, error: "Validation failed" };
|
|
1572
|
+
}
|
|
1573
|
+
generateMagneticDeclarations(projectRoot);
|
|
1574
|
+
const tsConfigPath = path11.join(projectRoot, "tsconfig.json");
|
|
1575
|
+
if (fs10.existsSync(tsConfigPath)) {
|
|
1576
|
+
console.log("\u{1F3D7}\uFE0F [Krnl Build] Compiling TypeScript source files to dist/...");
|
|
1577
|
+
const localTsc = path11.join(projectRoot, "node_modules", ".bin", "tsc");
|
|
1578
|
+
const tscCmd = fs10.existsSync(localTsc) ? localTsc : "tsc";
|
|
1579
|
+
try {
|
|
1580
|
+
(0, import_child_process.execSync)(`${tscCmd} -p tsconfig.json`, { cwd: projectRoot, stdio: "inherit" });
|
|
1581
|
+
} catch (err) {
|
|
1582
|
+
console.error("\u274C [Krnl Build] TypeScript compilation failed.");
|
|
1583
|
+
return { success: false, error: "TypeScript compilation failed" };
|
|
1584
|
+
}
|
|
1585
|
+
} else {
|
|
1586
|
+
console.log("\u2139\uFE0F [Krnl Build] No tsconfig.json found; skipping TypeScript compiler invocation.");
|
|
1587
|
+
}
|
|
1588
|
+
console.log("\u2705 [Krnl Build] Project validation, declaration generation, and compilation completed successfully.");
|
|
1589
|
+
return { success: true };
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// src/commands/dev.ts
|
|
1593
|
+
var http = __toESM(require("http"), 1);
|
|
1594
|
+
var path12 = __toESM(require("path"), 1);
|
|
1595
|
+
var fs11 = __toESM(require("fs"), 1);
|
|
1596
|
+
async function runDev(projectRoot = process.cwd(), options = {}) {
|
|
1597
|
+
const port = options.port ?? 8080;
|
|
1598
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1599
|
+
generateMagneticDeclarations(projectRoot);
|
|
1600
|
+
if (options.dryRun) {
|
|
1601
|
+
console.log(`\u26A1 [Krnl Dev] Development environment verified on port ${port} (--dry-run).`);
|
|
1602
|
+
return {
|
|
1603
|
+
port,
|
|
1604
|
+
close: async () => {
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
const server = http.createServer((req, res) => {
|
|
1609
|
+
res.setHeader("Content-Type", "application/json");
|
|
1610
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
1611
|
+
if (url.pathname === "/" || url.pathname === "/health") {
|
|
1612
|
+
res.writeHead(200);
|
|
1613
|
+
res.end(JSON.stringify({ status: "ok", service: "krnl-dev", port, uptime: process.uptime() }));
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
if (url.pathname === "/manifest") {
|
|
1617
|
+
const pkgPath = path12.join(projectRoot, "package.json");
|
|
1618
|
+
const pkg = fs11.existsSync(pkgPath) ? JSON.parse(fs11.readFileSync(pkgPath, "utf8")) : {};
|
|
1619
|
+
res.writeHead(200);
|
|
1620
|
+
res.end(JSON.stringify({ name: pkg.name || "krnl-app", version: pkg.version || "1.0.0" }));
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
res.writeHead(404);
|
|
1624
|
+
res.end(JSON.stringify({ error: "Route not found" }));
|
|
1625
|
+
});
|
|
1626
|
+
await new Promise((resolve3, reject) => {
|
|
1627
|
+
server.listen(port, () => resolve3());
|
|
1628
|
+
server.on("error", reject);
|
|
1629
|
+
});
|
|
1630
|
+
console.log(`\u26A1 [Krnl Dev] Development server listening on http://localhost:${port}`);
|
|
1631
|
+
const watcher = fs11.watch(projectRoot, { recursive: true }, (_evt, filename) => {
|
|
1632
|
+
if (filename && (filename.endsWith(".ts") || filename.endsWith(".js")) && !filename.includes("krnl-magnetic.d.ts")) {
|
|
1180
1633
|
try {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
return f;
|
|
1184
|
-
}
|
|
1185
|
-
} catch (e) {
|
|
1634
|
+
generateMagneticDeclarations(projectRoot);
|
|
1635
|
+
} catch {
|
|
1186
1636
|
}
|
|
1187
1637
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1638
|
+
if (filename && filename.endsWith("manifest.json")) {
|
|
1639
|
+
try {
|
|
1640
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1641
|
+
} catch {
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
const close = async () => {
|
|
1646
|
+
watcher.close();
|
|
1647
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
1648
|
+
};
|
|
1649
|
+
return { server, close, port };
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// src/bin/krnl.ts
|
|
1653
|
+
var args = process.argv.slice(2);
|
|
1654
|
+
var command = args[0] || "help";
|
|
1655
|
+
function optionValue(name) {
|
|
1656
|
+
const equalsPrefix = `${name}=`;
|
|
1657
|
+
const equalsArg = args.find((arg) => arg.startsWith(equalsPrefix));
|
|
1658
|
+
if (equalsArg) return equalsArg.slice(equalsPrefix.length);
|
|
1659
|
+
const index = args.indexOf(name);
|
|
1660
|
+
return index >= 0 && args[index + 1] && !args[index + 1].startsWith("--") ? args[index + 1] : void 0;
|
|
1190
1661
|
}
|
|
1191
1662
|
async function main() {
|
|
1192
1663
|
switch (command) {
|
|
1193
1664
|
case "sync": {
|
|
1194
|
-
const targetDir = args[1] && !args[1].startsWith("-") ?
|
|
1665
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1195
1666
|
console.log("\u{1F4E6} [Krnl Sync] Reconciling package.json from all manifest.json files...");
|
|
1196
1667
|
const res = KrnlPackageReconciler.reconcile(targetDir, true);
|
|
1197
1668
|
console.log(`\u2705 Reconciled dependencies from ${res.totalManifests} manifest.json file(s).`);
|
|
@@ -1201,7 +1672,7 @@ async function main() {
|
|
|
1201
1672
|
break;
|
|
1202
1673
|
}
|
|
1203
1674
|
case "validate": {
|
|
1204
|
-
const targetDir = args[1] && !args[1].startsWith("-") ?
|
|
1675
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1205
1676
|
const valid = await runValidate(targetDir);
|
|
1206
1677
|
process.exit(valid ? 0 : 1);
|
|
1207
1678
|
break;
|
|
@@ -1210,14 +1681,22 @@ async function main() {
|
|
|
1210
1681
|
const type = args[1];
|
|
1211
1682
|
const name = args[2];
|
|
1212
1683
|
const parent = args[3];
|
|
1213
|
-
|
|
1684
|
+
const component = optionValue("--default-frontend");
|
|
1685
|
+
const relationship = optionValue("--default-frontend-relationship") === "required" ? "required" : "recommended";
|
|
1686
|
+
const frontend = component ? {
|
|
1687
|
+
component,
|
|
1688
|
+
package: optionValue("--default-frontend-package"),
|
|
1689
|
+
export: optionValue("--default-frontend-export"),
|
|
1690
|
+
relationship
|
|
1691
|
+
} : void 0;
|
|
1692
|
+
await runGenerate(type, name, parent, process.cwd(), { defaultFrontend: frontend });
|
|
1214
1693
|
break;
|
|
1215
1694
|
}
|
|
1216
1695
|
case "watch": {
|
|
1217
1696
|
generateMagneticDeclarations(process.cwd());
|
|
1218
1697
|
if (args.includes("--watch") || args.includes("-w")) {
|
|
1219
1698
|
console.log("[Krnl Watch] Continuous watcher enabled.");
|
|
1220
|
-
|
|
1699
|
+
fs12.watch(process.cwd(), { recursive: true }, (_evt, filename) => {
|
|
1221
1700
|
if (filename && (filename.endsWith(".ts") || filename.endsWith(".js")) && !filename.includes("krnl-magnetic.d.ts")) {
|
|
1222
1701
|
try {
|
|
1223
1702
|
generateMagneticDeclarations(process.cwd());
|
|
@@ -1235,52 +1714,34 @@ async function main() {
|
|
|
1235
1714
|
break;
|
|
1236
1715
|
}
|
|
1237
1716
|
case "build": {
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1241
|
-
const targetEntity = entityArgIdx !== -1 ? args[entityArgIdx + 1] : void 0;
|
|
1717
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1718
|
+
const serviceArgIdx = args.indexOf("--service") !== -1 ? args.indexOf("--service") : args.indexOf("--orchestration");
|
|
1719
|
+
const targetService = serviceArgIdx !== -1 ? args[serviceArgIdx + 1] : void 0;
|
|
1242
1720
|
const isAll = args.includes("--all");
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Found application entrypoint: ${appFile}`);
|
|
1246
|
-
}
|
|
1247
|
-
if (targetEntity) {
|
|
1248
|
-
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Validating and building app variant for entity "${targetEntity}"...`);
|
|
1249
|
-
} else if (isAll) {
|
|
1250
|
-
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Validating and building combined multi-entity application...`);
|
|
1251
|
-
} else {
|
|
1252
|
-
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Validating and building project...`);
|
|
1253
|
-
}
|
|
1254
|
-
const valid = await runValidate(projectRoot);
|
|
1255
|
-
if (!valid) {
|
|
1256
|
-
console.error("\u274C Build aborted due to validation errors.");
|
|
1257
|
-
process.exit(1);
|
|
1258
|
-
}
|
|
1259
|
-
generateMagneticDeclarations(projectRoot);
|
|
1260
|
-
console.log(`\u2705 [Krnl Build] Compilation completed successfully.`);
|
|
1721
|
+
const res = await runBuild(targetDir, { service: targetService, orchestration: targetService, all: isAll });
|
|
1722
|
+
process.exit(res.success ? 0 : 1);
|
|
1261
1723
|
break;
|
|
1262
1724
|
}
|
|
1263
1725
|
case "dev": {
|
|
1264
|
-
const
|
|
1265
|
-
const appFile = detectAppEntrypoint(projectRoot);
|
|
1726
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1266
1727
|
const portArgIdx = args.indexOf("--port");
|
|
1267
1728
|
const port = portArgIdx !== -1 ? parseInt(args[portArgIdx + 1], 10) : 8080;
|
|
1268
|
-
const
|
|
1269
|
-
const
|
|
1729
|
+
const serviceArgIdx = args.indexOf("--service") !== -1 ? args.indexOf("--service") : args.indexOf("--orchestration");
|
|
1730
|
+
const targetService = serviceArgIdx !== -1 ? args[serviceArgIdx + 1] : void 0;
|
|
1270
1731
|
const isAll = args.includes("--all");
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1732
|
+
const dryRun = args.includes("--dry-run") || args.includes("--once");
|
|
1733
|
+
const devInstance = await runDev(targetDir, { port, service: targetService, orchestration: targetService, all: isAll, dryRun });
|
|
1734
|
+
if (dryRun) {
|
|
1735
|
+
process.exit(0);
|
|
1274
1736
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
console.log(`\u26A1 [Krnl Dev] Development environment ready.`);
|
|
1737
|
+
process.on("SIGINT", async () => {
|
|
1738
|
+
await devInstance.close();
|
|
1739
|
+
process.exit(0);
|
|
1740
|
+
});
|
|
1741
|
+
process.on("SIGTERM", async () => {
|
|
1742
|
+
await devInstance.close();
|
|
1743
|
+
process.exit(0);
|
|
1744
|
+
});
|
|
1284
1745
|
break;
|
|
1285
1746
|
}
|
|
1286
1747
|
case "help":
|
|
@@ -1293,22 +1754,24 @@ async function main() {
|
|
|
1293
1754
|
Usage: krnl <command> [options]
|
|
1294
1755
|
|
|
1295
1756
|
Commands:
|
|
1296
|
-
dev Start Krnl service dev server
|
|
1297
|
-
build Validate and
|
|
1757
|
+
dev Start Krnl service dev server with hot declaration watcher
|
|
1758
|
+
build Validate, generate declarations, and compile project to dist/
|
|
1298
1759
|
validate Run deep AST & 4-layer function purity validation
|
|
1299
1760
|
sync Reconcile package.json from all co-located manifest.json files
|
|
1300
1761
|
watch Generate ambient TypeScript declarations (krnl-magnetic.d.ts)
|
|
1301
|
-
generate Scaffold
|
|
1762
|
+
generate Scaffold services, functionality-orchestrations, functionalities, libraries
|
|
1302
1763
|
Examples:
|
|
1303
|
-
krnl generate
|
|
1304
|
-
krnl generate
|
|
1305
|
-
krnl generate
|
|
1306
|
-
krnl generate
|
|
1764
|
+
krnl generate service Payment
|
|
1765
|
+
krnl generate service Payment --default-frontend=PaymentPage --default-frontend-package=@ultrst-armada/floks/ui --default-frontend-export=PaymentPage --default-frontend-relationship=required
|
|
1766
|
+
krnl generate functionality-orchestration Payment
|
|
1767
|
+
krnl generate functionality ProcessPayment Payment
|
|
1768
|
+
krnl generate library TaxCalculator Payment
|
|
1307
1769
|
|
|
1308
1770
|
Options:
|
|
1309
|
-
--
|
|
1310
|
-
--all Run or build all
|
|
1771
|
+
--service <name> Target a specific service variant to run or build
|
|
1772
|
+
--all Run or build all services as a combined build
|
|
1311
1773
|
--port <number> Specify port for Krnl service dev server (default: 8080)
|
|
1774
|
+
--dry-run, --once Verify environment without running persistent server
|
|
1312
1775
|
--watch, -w Enable continuous file watcher (for watch command)
|
|
1313
1776
|
--help, -h Show this help message
|
|
1314
1777
|
`);
|