@ultrst-armada/krnl 1.0.2 → 1.0.4
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 +15 -8
- package/packages/cli/dist/bin/krnl.cjs +808 -331
- package/packages/cli/dist/bin/krnl.js +50 -65
- package/packages/cli/dist/chunk-GHWYEAPD.js +1642 -0
- package/packages/cli/dist/index.cjs +761 -263
- 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 +2912 -140
- package/packages/core/dist/index.d.cts +614 -27
- package/packages/core/dist/index.d.ts +614 -27
- package/packages/core/dist/index.js +2903 -140
- package/packages/core/package.json +15 -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",
|
|
300
283
|
filePath,
|
|
301
284
|
line: step.node.getStartLineNumber(),
|
|
302
|
-
message: `
|
|
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",
|
|
291
|
+
filePath,
|
|
292
|
+
line: step.node.getStartLineNumber(),
|
|
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,112 @@ 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
|
+
|
|
923
|
+
// ../../node_modules/.pnpm/@dinilmusick+gutts@0.1.0/node_modules/@dinilmusick/gutts/dist/json/json-parse.js
|
|
924
|
+
function parseJson(text) {
|
|
925
|
+
return JSON.parse(text);
|
|
926
|
+
}
|
|
927
|
+
function tryParseJson(text) {
|
|
928
|
+
try {
|
|
929
|
+
return parseJson(text);
|
|
930
|
+
} catch {
|
|
931
|
+
return void 0;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// ../core/dist/index.js
|
|
936
|
+
var asyncHooks = globalThis.process?.getBuiltinModule?.("node:async_hooks");
|
|
660
937
|
var KrnlPackageReconciler = class {
|
|
661
938
|
/**
|
|
662
939
|
* Scans all manifest.json files across backend and frontend and reconciles root package.json.
|
|
@@ -668,7 +945,7 @@ var KrnlPackageReconciler = class {
|
|
|
668
945
|
for (const mPath of manifests) {
|
|
669
946
|
try {
|
|
670
947
|
const raw = fs5.readFileSync(mPath, "utf8");
|
|
671
|
-
const json =
|
|
948
|
+
const json = tryParseJson(raw) ?? {};
|
|
672
949
|
if (json.dependencies && typeof json.dependencies === "object") {
|
|
673
950
|
for (const [pkg, ver] of Object.entries(json.dependencies)) {
|
|
674
951
|
if (!aggregatedDeps[pkg]) aggregatedDeps[pkg] = [];
|
|
@@ -704,7 +981,7 @@ var KrnlPackageReconciler = class {
|
|
|
704
981
|
}
|
|
705
982
|
resolvedDevDeps[pkg] = versions[versions.length - 1];
|
|
706
983
|
}
|
|
707
|
-
const pkgJsonPath =
|
|
984
|
+
const pkgJsonPath = path6.join(projectRoot, "package.json");
|
|
708
985
|
let updated = false;
|
|
709
986
|
if (fs5.existsSync(pkgJsonPath)) {
|
|
710
987
|
const pkgContent = JSON.parse(fs5.readFileSync(pkgJsonPath, "utf8"));
|
|
@@ -742,12 +1019,15 @@ var KrnlPackageReconciler = class {
|
|
|
742
1019
|
*/
|
|
743
1020
|
static findManifests(projectRoot) {
|
|
744
1021
|
const searchDirs = [
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1022
|
+
path6.join(projectRoot, "krnl", "backend", "services"),
|
|
1023
|
+
path6.join(projectRoot, "krnl", "backend", "libraries"),
|
|
1024
|
+
path6.join(projectRoot, "krnl", "backend", "functionalities"),
|
|
1025
|
+
path6.join(projectRoot, "krnl", "frontend", "libraries"),
|
|
1026
|
+
path6.join(projectRoot, "krnl", "frontend", "functionalities"),
|
|
1027
|
+
path6.join(projectRoot, "src", "backend", "services"),
|
|
1028
|
+
path6.join(projectRoot, "src", "services"),
|
|
1029
|
+
path6.join(projectRoot, "src", "functionalities"),
|
|
1030
|
+
path6.join(projectRoot, "src", "libraries")
|
|
751
1031
|
];
|
|
752
1032
|
const found = [];
|
|
753
1033
|
for (const dir of searchDirs) {
|
|
@@ -762,7 +1042,7 @@ var KrnlPackageReconciler = class {
|
|
|
762
1042
|
const entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
763
1043
|
for (const entry of entries) {
|
|
764
1044
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
765
|
-
const full =
|
|
1045
|
+
const full = path6.join(dir, entry.name);
|
|
766
1046
|
if (entry.isDirectory()) {
|
|
767
1047
|
this.scanRecursive(full, found);
|
|
768
1048
|
} else if (entry.isFile() && entry.name === "manifest.json") {
|
|
@@ -775,16 +1055,40 @@ var KrnlPackageReconciler = class {
|
|
|
775
1055
|
};
|
|
776
1056
|
|
|
777
1057
|
// src/commands/generators/functionalityGenerator.ts
|
|
778
|
-
function generateFunctionality(name, projectRoot) {
|
|
1058
|
+
function generateFunctionality(name, projectRoot, parentServiceOrOptions) {
|
|
779
1059
|
const { backend, frontend } = getPlaneRoots(projectRoot);
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
1060
|
+
const options = typeof parentServiceOrOptions === "string" ? { parentService: parentServiceOrOptions } : parentServiceOrOptions || {};
|
|
1061
|
+
let targetService = options.parentService;
|
|
1062
|
+
if (!targetService) {
|
|
1063
|
+
const servicesDir = path7.join(backend, "services");
|
|
1064
|
+
if (fs6.existsSync(servicesDir)) {
|
|
1065
|
+
const existing = fs6.readdirSync(servicesDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1066
|
+
if (existing.length === 1) {
|
|
1067
|
+
targetService = existing[0].name;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
const bFuncDir = targetService ? path7.join(backend, "services", targetService, "functionalities", name) : path7.join(backend, "functionalities", name);
|
|
1072
|
+
fs6.mkdirSync(path7.join(bFuncDir, "main_function"), { recursive: true });
|
|
1073
|
+
fs6.mkdirSync(path7.join(bFuncDir, "helper_functions"), { recursive: true });
|
|
1074
|
+
fs6.mkdirSync(path7.join(bFuncDir, "events"), { recursive: true });
|
|
1075
|
+
fs6.mkdirSync(path7.join(bFuncDir, "tests"), { recursive: true });
|
|
1076
|
+
if (options.withState) {
|
|
1077
|
+
fs6.mkdirSync(path7.join(bFuncDir, "state_data"), { recursive: true });
|
|
1078
|
+
fs6.writeFileSync(
|
|
1079
|
+
path7.join(bFuncDir, "state_data", "state.ts"),
|
|
1080
|
+
`export interface ${name}State {
|
|
1081
|
+
executionCount: number;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
export const initialState: ${name}State = {
|
|
1085
|
+
executionCount: 0
|
|
1086
|
+
};
|
|
1087
|
+
`
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
786
1090
|
fs6.writeFileSync(
|
|
787
|
-
|
|
1091
|
+
path7.join(bFuncDir, `${name}Atom.ts`),
|
|
788
1092
|
`export interface ${name}Input {
|
|
789
1093
|
payload?: string;
|
|
790
1094
|
}
|
|
@@ -796,10 +1100,11 @@ export interface ${name}Output {
|
|
|
796
1100
|
`
|
|
797
1101
|
);
|
|
798
1102
|
fs6.writeFileSync(
|
|
799
|
-
|
|
1103
|
+
path7.join(bFuncDir, "manifest.json"),
|
|
800
1104
|
JSON.stringify(
|
|
801
1105
|
{
|
|
802
1106
|
name,
|
|
1107
|
+
service: targetService || void 0,
|
|
803
1108
|
description: `${name} quad-unit functionality`,
|
|
804
1109
|
dependencies: {}
|
|
805
1110
|
},
|
|
@@ -808,10 +1113,10 @@ export interface ${name}Output {
|
|
|
808
1113
|
)
|
|
809
1114
|
);
|
|
810
1115
|
fs6.writeFileSync(
|
|
811
|
-
|
|
1116
|
+
path7.join(bFuncDir, "main_function", "logic.ts"),
|
|
812
1117
|
`import type { ${name}Input, ${name}Output } from "../${name}Atom.js";
|
|
813
1118
|
|
|
814
|
-
export const main = async (input: ${name}Input,
|
|
1119
|
+
export const main = async (input: ${name}Input, context: any): Promise<${name}Output> => {
|
|
815
1120
|
return {
|
|
816
1121
|
success: true,
|
|
817
1122
|
timestamp: Date.now()
|
|
@@ -820,24 +1125,13 @@ export const main = async (input: ${name}Input, { state }: any): Promise<${name}
|
|
|
820
1125
|
`
|
|
821
1126
|
);
|
|
822
1127
|
fs6.writeFileSync(
|
|
823
|
-
|
|
1128
|
+
path7.join(bFuncDir, "main_function", "lifecycle.ts"),
|
|
824
1129
|
`export async function onMount() {}
|
|
825
1130
|
export async function onTeardown() {}
|
|
826
1131
|
`
|
|
827
1132
|
);
|
|
828
1133
|
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"),
|
|
1134
|
+
path7.join(bFuncDir, "helper_functions", "helper.ts"),
|
|
841
1135
|
`/**
|
|
842
1136
|
* @role component
|
|
843
1137
|
*/
|
|
@@ -847,7 +1141,7 @@ export function exampleHelper(): boolean {
|
|
|
847
1141
|
`
|
|
848
1142
|
);
|
|
849
1143
|
fs6.writeFileSync(
|
|
850
|
-
|
|
1144
|
+
path7.join(bFuncDir, "events", "events.ts"),
|
|
851
1145
|
`/**
|
|
852
1146
|
* @role component
|
|
853
1147
|
*/
|
|
@@ -857,7 +1151,7 @@ export interface ${name}CompletedEvent {
|
|
|
857
1151
|
`
|
|
858
1152
|
);
|
|
859
1153
|
fs6.writeFileSync(
|
|
860
|
-
|
|
1154
|
+
path7.join(bFuncDir, "tests", `${name}.test.ts`),
|
|
861
1155
|
`import { describe, it, expect } from "vitest";
|
|
862
1156
|
|
|
863
1157
|
describe("${name} functionality", () => {
|
|
@@ -867,10 +1161,10 @@ describe("${name} functionality", () => {
|
|
|
867
1161
|
});
|
|
868
1162
|
`
|
|
869
1163
|
);
|
|
870
|
-
const fFuncDir =
|
|
871
|
-
fs6.mkdirSync(
|
|
1164
|
+
const fFuncDir = path7.join(frontend, "functionalities", name);
|
|
1165
|
+
fs6.mkdirSync(path7.join(fFuncDir, "tests"), { recursive: true });
|
|
872
1166
|
fs6.writeFileSync(
|
|
873
|
-
|
|
1167
|
+
path7.join(fFuncDir, `${name}0.tsx`),
|
|
874
1168
|
`import React from "react";
|
|
875
1169
|
|
|
876
1170
|
export const ${name}0: React.FC = () => {
|
|
@@ -885,11 +1179,11 @@ export default ${name}0;
|
|
|
885
1179
|
`
|
|
886
1180
|
);
|
|
887
1181
|
fs6.writeFileSync(
|
|
888
|
-
|
|
1182
|
+
path7.join(fFuncDir, "manifest.json"),
|
|
889
1183
|
JSON.stringify({ name: `${name}UI`, dependencies: {} }, null, 2)
|
|
890
1184
|
);
|
|
891
1185
|
fs6.writeFileSync(
|
|
892
|
-
|
|
1186
|
+
path7.join(fFuncDir, "tests", `${name}0.test.tsx`),
|
|
893
1187
|
`import { describe, it, expect } from "vitest";
|
|
894
1188
|
|
|
895
1189
|
describe("${name}0 Component", () => {
|
|
@@ -900,20 +1194,33 @@ describe("${name}0 Component", () => {
|
|
|
900
1194
|
`
|
|
901
1195
|
);
|
|
902
1196
|
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
903
|
-
console.log(`\u2705 Created Backend Functionality
|
|
904
|
-
console.log(`\u2705 Created Frontend Functionality:
|
|
1197
|
+
console.log(`\u2705 Created Backend Functionality: ${path7.relative(projectRoot, bFuncDir)}/`);
|
|
1198
|
+
console.log(`\u2705 Created Frontend Functionality: ${path7.relative(projectRoot, fFuncDir)}/`);
|
|
905
1199
|
}
|
|
906
1200
|
|
|
907
1201
|
// src/commands/generators/libraryGenerator.ts
|
|
908
1202
|
var fs7 = __toESM(require("fs"), 1);
|
|
909
|
-
var
|
|
910
|
-
function generateLibrary(name, projectRoot) {
|
|
1203
|
+
var path8 = __toESM(require("path"), 1);
|
|
1204
|
+
function generateLibrary(name, projectRoot, parentService) {
|
|
911
1205
|
const { backend, frontend } = getPlaneRoots(projectRoot);
|
|
912
1206
|
const conceptName = name.endsWith("Concepts") ? name : `${name}Concepts`;
|
|
913
|
-
|
|
914
|
-
|
|
1207
|
+
let targetService = parentService;
|
|
1208
|
+
if (!targetService) {
|
|
1209
|
+
const servicesDir = path8.join(backend, "services");
|
|
1210
|
+
if (fs7.existsSync(servicesDir)) {
|
|
1211
|
+
const existing = fs7.readdirSync(servicesDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1212
|
+
if (existing.length === 1) {
|
|
1213
|
+
targetService = existing[0].name;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
if (!targetService) {
|
|
1218
|
+
targetService = "App";
|
|
1219
|
+
}
|
|
1220
|
+
const bLibDir = path8.join(backend, "services", targetService, "libraries", conceptName);
|
|
1221
|
+
fs7.mkdirSync(path8.join(bLibDir, "tests"), { recursive: true });
|
|
915
1222
|
fs7.writeFileSync(
|
|
916
|
-
|
|
1223
|
+
path8.join(bLibDir, "definitions.ts"),
|
|
917
1224
|
`/**
|
|
918
1225
|
* @file definitions.ts
|
|
919
1226
|
* @role component
|
|
@@ -924,7 +1231,7 @@ export interface ${conceptName}Options {
|
|
|
924
1231
|
`
|
|
925
1232
|
);
|
|
926
1233
|
fs7.writeFileSync(
|
|
927
|
-
|
|
1234
|
+
path8.join(bLibDir, "functions.ts"),
|
|
928
1235
|
`/**
|
|
929
1236
|
* @file functions.ts
|
|
930
1237
|
* @role component
|
|
@@ -937,31 +1244,38 @@ export function ${name.toLowerCase()}Transform<T>(data: T, _opts?: ${conceptName
|
|
|
937
1244
|
`
|
|
938
1245
|
);
|
|
939
1246
|
fs7.writeFileSync(
|
|
940
|
-
|
|
941
|
-
|
|
1247
|
+
path8.join(bLibDir, "index.ts"),
|
|
1248
|
+
`export * from "./definitions.js";
|
|
1249
|
+
export * from "./functions.js";
|
|
1250
|
+
`
|
|
1251
|
+
);
|
|
1252
|
+
fs7.writeFileSync(
|
|
1253
|
+
path8.join(bLibDir, "manifest.json"),
|
|
1254
|
+
JSON.stringify({ name: conceptName, service: targetService, dependencies: {} }, null, 2)
|
|
942
1255
|
);
|
|
943
1256
|
fs7.writeFileSync(
|
|
944
|
-
|
|
1257
|
+
path8.join(bLibDir, "tests", `${conceptName}.test.ts`),
|
|
945
1258
|
`import { describe, it, expect } from "vitest";
|
|
1259
|
+
import { ${name.toLowerCase()}Transform } from "../functions.js";
|
|
946
1260
|
|
|
947
1261
|
describe("${conceptName}", () => {
|
|
948
1262
|
it("runs correctly", () => {
|
|
949
|
-
expect(
|
|
1263
|
+
expect(${name.toLowerCase()}Transform(42)).toBe(42);
|
|
950
1264
|
});
|
|
951
1265
|
});
|
|
952
1266
|
`
|
|
953
1267
|
);
|
|
954
|
-
const fLibDir =
|
|
955
|
-
fs7.mkdirSync(
|
|
1268
|
+
const fLibDir = path8.join(frontend, "libraries", conceptName);
|
|
1269
|
+
fs7.mkdirSync(path8.join(fLibDir, "tests"), { recursive: true });
|
|
956
1270
|
fs7.writeFileSync(
|
|
957
|
-
|
|
1271
|
+
path8.join(fLibDir, "definitions.ts"),
|
|
958
1272
|
`export interface ${name}Props {
|
|
959
1273
|
label?: string;
|
|
960
1274
|
}
|
|
961
1275
|
`
|
|
962
1276
|
);
|
|
963
1277
|
fs7.writeFileSync(
|
|
964
|
-
|
|
1278
|
+
path8.join(fLibDir, "components.tsx"),
|
|
965
1279
|
`import React from "react";
|
|
966
1280
|
import type { ${name}Props } from "./definitions.js";
|
|
967
1281
|
import "./styles.css";
|
|
@@ -972,18 +1286,18 @@ export const ${name}: React.FC<${name}Props> = ({ label = "${name}" }) => {
|
|
|
972
1286
|
`
|
|
973
1287
|
);
|
|
974
1288
|
fs7.writeFileSync(
|
|
975
|
-
|
|
1289
|
+
path8.join(fLibDir, "styles.css"),
|
|
976
1290
|
`.krnl-${name.toLowerCase()} {
|
|
977
1291
|
font-family: inherit;
|
|
978
1292
|
}
|
|
979
1293
|
`
|
|
980
1294
|
);
|
|
981
1295
|
fs7.writeFileSync(
|
|
982
|
-
|
|
1296
|
+
path8.join(fLibDir, "manifest.json"),
|
|
983
1297
|
JSON.stringify({ name: `${conceptName}UI`, dependencies: {} }, null, 2)
|
|
984
1298
|
);
|
|
985
1299
|
fs7.writeFileSync(
|
|
986
|
-
|
|
1300
|
+
path8.join(fLibDir, "tests", `${name}.test.tsx`),
|
|
987
1301
|
`import { describe, it, expect } from "vitest";
|
|
988
1302
|
|
|
989
1303
|
describe("${name} UI Concept", () => {
|
|
@@ -994,82 +1308,165 @@ describe("${name} UI Concept", () => {
|
|
|
994
1308
|
`
|
|
995
1309
|
);
|
|
996
1310
|
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
997
|
-
console.log(`\u2705 Created
|
|
998
|
-
console.log(`\u2705 Created Frontend Concept Library:
|
|
1311
|
+
console.log(`\u2705 Created Service-Owned Library: ${path8.relative(projectRoot, bLibDir)}/ (Owner: ${targetService})`);
|
|
1312
|
+
console.log(`\u2705 Created Frontend Concept Library: ${path8.relative(projectRoot, fLibDir)}/`);
|
|
999
1313
|
}
|
|
1000
|
-
|
|
1314
|
+
|
|
1315
|
+
// src/commands/generators/serviceGenerator.ts
|
|
1316
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
1317
|
+
var path9 = __toESM(require("path"), 1);
|
|
1318
|
+
function generateService(name, projectRoot, defaultFrontend) {
|
|
1319
|
+
const frontendReference = defaultFrontend?.component ? {
|
|
1320
|
+
component: defaultFrontend.component,
|
|
1321
|
+
...defaultFrontend.package ? { package: defaultFrontend.package } : {},
|
|
1322
|
+
...defaultFrontend.export ? { export: defaultFrontend.export } : {},
|
|
1323
|
+
relationship: defaultFrontend.relationship ?? "recommended"
|
|
1324
|
+
} : void 0;
|
|
1325
|
+
const frontendConfig = frontendReference ? JSON.stringify(frontendReference, null, 2).replace(/\n/g, "\n ") : void 0;
|
|
1001
1326
|
const { backend } = getPlaneRoots(projectRoot);
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
)
|
|
1327
|
+
const serviceDir = path9.join(backend, "services", name);
|
|
1328
|
+
const funcsDir = path9.join(serviceDir, "functionalities");
|
|
1329
|
+
const orchsDir = path9.join(serviceDir, "orchestrations");
|
|
1330
|
+
const libsDir = path9.join(serviceDir, "libraries");
|
|
1331
|
+
const testsDir = path9.join(serviceDir, "tests");
|
|
1332
|
+
fs8.mkdirSync(funcsDir, { recursive: true });
|
|
1333
|
+
fs8.mkdirSync(orchsDir, { recursive: true });
|
|
1334
|
+
fs8.mkdirSync(libsDir, { recursive: true });
|
|
1335
|
+
fs8.mkdirSync(testsDir, { recursive: true });
|
|
1336
|
+
const conceptName = `${name}Concepts`;
|
|
1337
|
+
const defaultLibDir = path9.join(libsDir, conceptName);
|
|
1338
|
+
fs8.mkdirSync(path9.join(defaultLibDir, "tests"), { recursive: true });
|
|
1339
|
+
fs8.writeFileSync(
|
|
1340
|
+
path9.join(defaultLibDir, "definitions.ts"),
|
|
1341
|
+
`/**
|
|
1342
|
+
* @file definitions.ts
|
|
1343
|
+
* @role component
|
|
1344
|
+
*/
|
|
1345
|
+
export interface ${name}Options {
|
|
1346
|
+
enabled?: boolean;
|
|
1347
|
+
}
|
|
1348
|
+
`
|
|
1016
1349
|
);
|
|
1017
|
-
|
|
1018
|
-
path9.join(
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1350
|
+
fs8.writeFileSync(
|
|
1351
|
+
path9.join(defaultLibDir, "functions.ts"),
|
|
1352
|
+
`/**
|
|
1353
|
+
* @file functions.ts
|
|
1354
|
+
* @role component
|
|
1355
|
+
*/
|
|
1356
|
+
import type { ${name}Options } from "./definitions.js";
|
|
1357
|
+
|
|
1358
|
+
export function format${name}Name(input: string, _opts?: ${name}Options): string {
|
|
1359
|
+
return "${name}: " + input;
|
|
1025
1360
|
}
|
|
1026
|
-
export default register;
|
|
1027
1361
|
`
|
|
1028
1362
|
);
|
|
1029
|
-
|
|
1363
|
+
fs8.writeFileSync(
|
|
1364
|
+
path9.join(defaultLibDir, "index.ts"),
|
|
1365
|
+
`export * from "./definitions.js";
|
|
1366
|
+
export * from "./functions.js";
|
|
1367
|
+
`
|
|
1368
|
+
);
|
|
1369
|
+
fs8.writeFileSync(
|
|
1370
|
+
path9.join(defaultLibDir, "manifest.json"),
|
|
1371
|
+
JSON.stringify({ name: conceptName, description: `${name} service-owned library`, dependencies: {} }, null, 2)
|
|
1372
|
+
);
|
|
1373
|
+
fs8.writeFileSync(
|
|
1374
|
+
path9.join(defaultLibDir, "tests", `${conceptName}.test.ts`),
|
|
1375
|
+
`import { describe, it, expect } from "vitest";
|
|
1376
|
+
import { format${name}Name } from "../functions.js";
|
|
1377
|
+
|
|
1378
|
+
describe("${conceptName}", () => {
|
|
1379
|
+
it("formats name correctly", () => {
|
|
1380
|
+
expect(format${name}Name("test")).toContain("${name}");
|
|
1381
|
+
});
|
|
1382
|
+
});
|
|
1383
|
+
`
|
|
1384
|
+
);
|
|
1385
|
+
const frontendProperty = frontendConfig ? ` defaultFrontend: ${frontendConfig},
|
|
1386
|
+
` : "";
|
|
1387
|
+
fs8.writeFileSync(
|
|
1388
|
+
path9.join(serviceDir, `${name}ServiceFacade.ts`),
|
|
1389
|
+
`import { ServiceFacade } from "@ultrst-armada/krnl-core";
|
|
1390
|
+
import * as ${name.toLowerCase()}Concepts from "./libraries/${conceptName}/index.js";
|
|
1391
|
+
|
|
1392
|
+
export const ${name}ServiceFacade = new ServiceFacade({
|
|
1393
|
+
id: "${name.toLowerCase()}.service",
|
|
1394
|
+
name: "${name}Service",
|
|
1395
|
+
version: "1.0.0",
|
|
1396
|
+
description: "${name} service facade",
|
|
1397
|
+
${frontendProperty} libraries: {
|
|
1398
|
+
${conceptName}: ${name.toLowerCase()}Concepts,
|
|
1399
|
+
},
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
export default ${name}ServiceFacade;
|
|
1403
|
+
`
|
|
1404
|
+
);
|
|
1405
|
+
fs8.writeFileSync(
|
|
1406
|
+
path9.join(testsDir, `${name}ServiceFacade.test.ts`),
|
|
1407
|
+
`import { describe, it, expect } from "vitest";
|
|
1408
|
+
import { ${name}ServiceFacade } from "../${name}ServiceFacade.js";
|
|
1409
|
+
|
|
1410
|
+
describe("${name}ServiceFacade", () => {
|
|
1411
|
+
it("initializes and exposes service-owned library", () => {
|
|
1412
|
+
expect(${name}ServiceFacade.id).toBe("${name.toLowerCase()}.service");
|
|
1413
|
+
expect(${name}ServiceFacade.libraries.${conceptName}).toBeDefined();
|
|
1414
|
+
expect(typeof ${name}ServiceFacade.libraries.${conceptName}.format${name}Name).toBe("function");
|
|
1415
|
+
});
|
|
1416
|
+
});
|
|
1417
|
+
`
|
|
1418
|
+
);
|
|
1419
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1420
|
+
console.log(`\u2705 Created Service: ${path9.relative(projectRoot, serviceDir)}/`);
|
|
1030
1421
|
}
|
|
1031
1422
|
|
|
1032
1423
|
// src/commands/generate.ts
|
|
1033
|
-
async function runGenerate(type, name,
|
|
1424
|
+
async function runGenerate(type, name, parentService, projectRoot = process.cwd(), options = {}) {
|
|
1034
1425
|
if (!name) {
|
|
1035
|
-
console.error(
|
|
1426
|
+
console.error(
|
|
1427
|
+
"\u274C Error: Resource name is required. Usage: krnl generate <service|orchestration|functionality|library> <Name> [parentService]"
|
|
1428
|
+
);
|
|
1036
1429
|
process.exit(1);
|
|
1037
1430
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1431
|
+
const normalizedType = type.toLowerCase().replace(/[-_]/g, "");
|
|
1432
|
+
switch (normalizedType) {
|
|
1433
|
+
case "service":
|
|
1434
|
+
generateService(name, projectRoot, options.defaultFrontend);
|
|
1435
|
+
break;
|
|
1436
|
+
case "functionalityorchestration":
|
|
1437
|
+
case "orchestration":
|
|
1438
|
+
generateFunctionalityOrchestration(name, projectRoot);
|
|
1041
1439
|
break;
|
|
1042
1440
|
case "functionality":
|
|
1043
|
-
generateFunctionality(name, projectRoot);
|
|
1441
|
+
generateFunctionality(name, projectRoot, parentService);
|
|
1044
1442
|
break;
|
|
1045
1443
|
case "library":
|
|
1046
|
-
generateLibrary(name, projectRoot);
|
|
1047
|
-
break;
|
|
1048
|
-
case "subapp":
|
|
1049
|
-
generateSubApp(name, projectRoot);
|
|
1444
|
+
generateLibrary(name, projectRoot, parentService);
|
|
1050
1445
|
break;
|
|
1051
1446
|
default:
|
|
1052
|
-
console.error(
|
|
1447
|
+
console.error(
|
|
1448
|
+
`\u274C Unknown resource type "${type}". Valid types: service, orchestration, functionality, library`
|
|
1449
|
+
);
|
|
1053
1450
|
process.exit(1);
|
|
1054
1451
|
}
|
|
1055
1452
|
}
|
|
1056
1453
|
|
|
1057
1454
|
// src/commands/watch.ts
|
|
1058
|
-
var
|
|
1455
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
1059
1456
|
var path10 = __toESM(require("path"), 1);
|
|
1060
1457
|
function generateMagneticDeclarations(projectRoot = process.cwd()) {
|
|
1061
1458
|
const { results: functionalities, libDirs } = scanDirectory(projectRoot);
|
|
1062
1459
|
let dtsContent = `// Automatically generated by Krnl Magnetic Watcher. Do not edit manually.
|
|
1063
1460
|
|
|
1064
1461
|
`;
|
|
1065
|
-
dtsContent += `import {
|
|
1462
|
+
dtsContent += `import { Orchestration } from '@ultrst-armada/krnl-core';
|
|
1066
1463
|
|
|
1067
1464
|
`;
|
|
1068
1465
|
const globalDeclarations = [];
|
|
1069
1466
|
for (const func of functionalities) {
|
|
1070
1467
|
const helpersDir = path10.join(func.funcPath, "helper_functions");
|
|
1071
|
-
if (
|
|
1072
|
-
const files =
|
|
1468
|
+
if (fs9.existsSync(helpersDir)) {
|
|
1469
|
+
const files = fs9.readdirSync(helpersDir);
|
|
1073
1470
|
for (const file of files) {
|
|
1074
1471
|
if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
1075
1472
|
const filePath = path10.join(helpersDir, file);
|
|
@@ -1086,8 +1483,8 @@ function generateMagneticDeclarations(projectRoot = process.cwd()) {
|
|
|
1086
1483
|
}
|
|
1087
1484
|
}
|
|
1088
1485
|
const eventsDir = path10.join(func.funcPath, "events");
|
|
1089
|
-
if (
|
|
1090
|
-
const files =
|
|
1486
|
+
if (fs9.existsSync(eventsDir)) {
|
|
1487
|
+
const files = fs9.readdirSync(eventsDir);
|
|
1091
1488
|
for (const file of files) {
|
|
1092
1489
|
if (file.endsWith(".js") || file.endsWith(".ts")) {
|
|
1093
1490
|
const filePath = path10.join(eventsDir, file);
|
|
@@ -1114,12 +1511,12 @@ ${Array.from(new Set(globalDeclarations)).join("\n")}
|
|
|
1114
1511
|
`;
|
|
1115
1512
|
}
|
|
1116
1513
|
const outPath = path10.join(projectRoot, "krnl-magnetic.d.ts");
|
|
1117
|
-
|
|
1514
|
+
fs9.writeFileSync(outPath, dtsContent);
|
|
1118
1515
|
console.log(`[Krnl Watch] Updated ambient declarations: ${outPath}`);
|
|
1119
1516
|
}
|
|
1120
1517
|
function scanLibFiles(dir, projectRoot, decls) {
|
|
1121
|
-
if (!
|
|
1122
|
-
for (const entry of
|
|
1518
|
+
if (!fs9.existsSync(dir)) return;
|
|
1519
|
+
for (const entry of fs9.readdirSync(dir, { withFileTypes: true })) {
|
|
1123
1520
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
1124
1521
|
const full = path10.join(dir, entry.name);
|
|
1125
1522
|
if (entry.isDirectory()) {
|
|
@@ -1134,14 +1531,14 @@ function scanLibFiles(dir, projectRoot, decls) {
|
|
|
1134
1531
|
}
|
|
1135
1532
|
}
|
|
1136
1533
|
function scanDirectory(dir, results = [], libDirs = []) {
|
|
1137
|
-
if (!
|
|
1138
|
-
const list =
|
|
1534
|
+
if (!fs9.existsSync(dir)) return { results, libDirs };
|
|
1535
|
+
const list = fs9.readdirSync(dir, { withFileTypes: true });
|
|
1139
1536
|
for (const entry of list) {
|
|
1140
1537
|
if (entry.isDirectory()) {
|
|
1141
1538
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
1142
1539
|
const fullPath = path10.join(dir, entry.name);
|
|
1143
1540
|
if (entry.name === "functionalities") {
|
|
1144
|
-
const funcs =
|
|
1541
|
+
const funcs = fs9.readdirSync(fullPath, { withFileTypes: true });
|
|
1145
1542
|
for (const f of funcs) {
|
|
1146
1543
|
if (f.isDirectory()) results.push({ funcPath: path10.join(fullPath, f.name), funcName: f.name });
|
|
1147
1544
|
}
|
|
@@ -1155,7 +1552,7 @@ function scanDirectory(dir, results = [], libDirs = []) {
|
|
|
1155
1552
|
return { results, libDirs };
|
|
1156
1553
|
}
|
|
1157
1554
|
function parseExports(filePath, defaultName) {
|
|
1158
|
-
const content =
|
|
1555
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
1159
1556
|
const named = [];
|
|
1160
1557
|
let hasDefault = false;
|
|
1161
1558
|
const namedRegex = /export\s+(?:const|let|var|function|class|async\s+function)\s+([a-zA-Z0-9_$]+)/g;
|
|
@@ -1169,29 +1566,117 @@ function parseExports(filePath, defaultName) {
|
|
|
1169
1566
|
return { named, hasDefault };
|
|
1170
1567
|
}
|
|
1171
1568
|
|
|
1172
|
-
// src/
|
|
1173
|
-
var
|
|
1174
|
-
var
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1569
|
+
// src/commands/build.ts
|
|
1570
|
+
var path11 = __toESM(require("path"), 1);
|
|
1571
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
1572
|
+
var import_child_process = require("child_process");
|
|
1573
|
+
async function runBuild(projectRoot = process.cwd(), options = {}) {
|
|
1574
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1575
|
+
const target = options.service || options.orchestration;
|
|
1576
|
+
if (target) {
|
|
1577
|
+
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Target service/orchestration variant: "${target}"`);
|
|
1578
|
+
} else if (options.all) {
|
|
1579
|
+
console.log(`\u{1F3D7}\uFE0F [Krnl Build] Combined multi-service build`);
|
|
1580
|
+
}
|
|
1581
|
+
console.log("\u{1F50D} [Krnl Build] Running AST & layer purity validation...");
|
|
1582
|
+
const valid = await runValidate(projectRoot);
|
|
1583
|
+
if (!valid) {
|
|
1584
|
+
console.error("\u274C [Krnl Build] Build aborted due to validation errors.");
|
|
1585
|
+
return { success: false, error: "Validation failed" };
|
|
1586
|
+
}
|
|
1587
|
+
generateMagneticDeclarations(projectRoot);
|
|
1588
|
+
const tsConfigPath = path11.join(projectRoot, "tsconfig.json");
|
|
1589
|
+
if (fs10.existsSync(tsConfigPath)) {
|
|
1590
|
+
console.log("\u{1F3D7}\uFE0F [Krnl Build] Compiling TypeScript source files to dist/...");
|
|
1591
|
+
const localTsc = path11.join(projectRoot, "node_modules", ".bin", "tsc");
|
|
1592
|
+
const tscCmd = fs10.existsSync(localTsc) ? localTsc : "tsc";
|
|
1593
|
+
try {
|
|
1594
|
+
(0, import_child_process.execSync)(`${tscCmd} -p tsconfig.json`, { cwd: projectRoot, stdio: "inherit" });
|
|
1595
|
+
} catch (err) {
|
|
1596
|
+
console.error("\u274C [Krnl Build] TypeScript compilation failed.");
|
|
1597
|
+
return { success: false, error: "TypeScript compilation failed" };
|
|
1598
|
+
}
|
|
1599
|
+
} else {
|
|
1600
|
+
console.log("\u2139\uFE0F [Krnl Build] No tsconfig.json found; skipping TypeScript compiler invocation.");
|
|
1601
|
+
}
|
|
1602
|
+
console.log("\u2705 [Krnl Build] Project validation, declaration generation, and compilation completed successfully.");
|
|
1603
|
+
return { success: true };
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// src/commands/dev.ts
|
|
1607
|
+
var http = __toESM(require("http"), 1);
|
|
1608
|
+
var path12 = __toESM(require("path"), 1);
|
|
1609
|
+
var fs11 = __toESM(require("fs"), 1);
|
|
1610
|
+
async function runDev(projectRoot = process.cwd(), options = {}) {
|
|
1611
|
+
const port = options.port ?? 8080;
|
|
1612
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1613
|
+
generateMagneticDeclarations(projectRoot);
|
|
1614
|
+
if (options.dryRun) {
|
|
1615
|
+
console.log(`\u26A1 [Krnl Dev] Development environment verified on port ${port} (--dry-run).`);
|
|
1616
|
+
return {
|
|
1617
|
+
port,
|
|
1618
|
+
close: async () => {
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
const server = http.createServer((req, res) => {
|
|
1623
|
+
res.setHeader("Content-Type", "application/json");
|
|
1624
|
+
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
1625
|
+
if (url.pathname === "/" || url.pathname === "/health") {
|
|
1626
|
+
res.writeHead(200);
|
|
1627
|
+
res.end(JSON.stringify({ status: "ok", service: "krnl-dev", port, uptime: process.uptime() }));
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (url.pathname === "/manifest") {
|
|
1631
|
+
const pkgPath = path12.join(projectRoot, "package.json");
|
|
1632
|
+
const pkg = fs11.existsSync(pkgPath) ? JSON.parse(fs11.readFileSync(pkgPath, "utf8")) : {};
|
|
1633
|
+
res.writeHead(200);
|
|
1634
|
+
res.end(JSON.stringify({ name: pkg.name || "krnl-app", version: pkg.version || "1.0.0" }));
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
res.writeHead(404);
|
|
1638
|
+
res.end(JSON.stringify({ error: "Route not found" }));
|
|
1639
|
+
});
|
|
1640
|
+
await new Promise((resolve3, reject) => {
|
|
1641
|
+
server.listen(port, () => resolve3());
|
|
1642
|
+
server.on("error", reject);
|
|
1643
|
+
});
|
|
1644
|
+
console.log(`\u26A1 [Krnl Dev] Development server listening on http://localhost:${port}`);
|
|
1645
|
+
const watcher = fs11.watch(projectRoot, { recursive: true }, (_evt, filename) => {
|
|
1646
|
+
if (filename && (filename.endsWith(".ts") || filename.endsWith(".js")) && !filename.includes("krnl-magnetic.d.ts")) {
|
|
1180
1647
|
try {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
return f;
|
|
1184
|
-
}
|
|
1185
|
-
} catch (e) {
|
|
1648
|
+
generateMagneticDeclarations(projectRoot);
|
|
1649
|
+
} catch {
|
|
1186
1650
|
}
|
|
1187
1651
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1652
|
+
if (filename && filename.endsWith("manifest.json")) {
|
|
1653
|
+
try {
|
|
1654
|
+
KrnlPackageReconciler.reconcile(projectRoot, true);
|
|
1655
|
+
} catch {
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
});
|
|
1659
|
+
const close = async () => {
|
|
1660
|
+
watcher.close();
|
|
1661
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
1662
|
+
};
|
|
1663
|
+
return { server, close, port };
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
// src/bin/krnl.ts
|
|
1667
|
+
var args = process.argv.slice(2);
|
|
1668
|
+
var command = args[0] || "help";
|
|
1669
|
+
function optionValue(name) {
|
|
1670
|
+
const equalsPrefix = `${name}=`;
|
|
1671
|
+
const equalsArg = args.find((arg) => arg.startsWith(equalsPrefix));
|
|
1672
|
+
if (equalsArg) return equalsArg.slice(equalsPrefix.length);
|
|
1673
|
+
const index = args.indexOf(name);
|
|
1674
|
+
return index >= 0 && args[index + 1] && !args[index + 1].startsWith("--") ? args[index + 1] : void 0;
|
|
1190
1675
|
}
|
|
1191
1676
|
async function main() {
|
|
1192
1677
|
switch (command) {
|
|
1193
1678
|
case "sync": {
|
|
1194
|
-
const targetDir = args[1] && !args[1].startsWith("-") ?
|
|
1679
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1195
1680
|
console.log("\u{1F4E6} [Krnl Sync] Reconciling package.json from all manifest.json files...");
|
|
1196
1681
|
const res = KrnlPackageReconciler.reconcile(targetDir, true);
|
|
1197
1682
|
console.log(`\u2705 Reconciled dependencies from ${res.totalManifests} manifest.json file(s).`);
|
|
@@ -1201,7 +1686,7 @@ async function main() {
|
|
|
1201
1686
|
break;
|
|
1202
1687
|
}
|
|
1203
1688
|
case "validate": {
|
|
1204
|
-
const targetDir = args[1] && !args[1].startsWith("-") ?
|
|
1689
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1205
1690
|
const valid = await runValidate(targetDir);
|
|
1206
1691
|
process.exit(valid ? 0 : 1);
|
|
1207
1692
|
break;
|
|
@@ -1210,14 +1695,22 @@ async function main() {
|
|
|
1210
1695
|
const type = args[1];
|
|
1211
1696
|
const name = args[2];
|
|
1212
1697
|
const parent = args[3];
|
|
1213
|
-
|
|
1698
|
+
const component = optionValue("--default-frontend");
|
|
1699
|
+
const relationship = optionValue("--default-frontend-relationship") === "required" ? "required" : "recommended";
|
|
1700
|
+
const frontend = component ? {
|
|
1701
|
+
component,
|
|
1702
|
+
package: optionValue("--default-frontend-package"),
|
|
1703
|
+
export: optionValue("--default-frontend-export"),
|
|
1704
|
+
relationship
|
|
1705
|
+
} : void 0;
|
|
1706
|
+
await runGenerate(type, name, parent, process.cwd(), { defaultFrontend: frontend });
|
|
1214
1707
|
break;
|
|
1215
1708
|
}
|
|
1216
1709
|
case "watch": {
|
|
1217
1710
|
generateMagneticDeclarations(process.cwd());
|
|
1218
1711
|
if (args.includes("--watch") || args.includes("-w")) {
|
|
1219
1712
|
console.log("[Krnl Watch] Continuous watcher enabled.");
|
|
1220
|
-
|
|
1713
|
+
fs12.watch(process.cwd(), { recursive: true }, (_evt, filename) => {
|
|
1221
1714
|
if (filename && (filename.endsWith(".ts") || filename.endsWith(".js")) && !filename.includes("krnl-magnetic.d.ts")) {
|
|
1222
1715
|
try {
|
|
1223
1716
|
generateMagneticDeclarations(process.cwd());
|
|
@@ -1235,52 +1728,34 @@ async function main() {
|
|
|
1235
1728
|
break;
|
|
1236
1729
|
}
|
|
1237
1730
|
case "build": {
|
|
1238
|
-
const
|
|
1239
|
-
const
|
|
1240
|
-
const
|
|
1241
|
-
const targetEntity = entityArgIdx !== -1 ? args[entityArgIdx + 1] : void 0;
|
|
1731
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1732
|
+
const serviceArgIdx = args.indexOf("--service") !== -1 ? args.indexOf("--service") : args.indexOf("--orchestration");
|
|
1733
|
+
const targetService = serviceArgIdx !== -1 ? args[serviceArgIdx + 1] : void 0;
|
|
1242
1734
|
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.`);
|
|
1735
|
+
const res = await runBuild(targetDir, { service: targetService, orchestration: targetService, all: isAll });
|
|
1736
|
+
process.exit(res.success ? 0 : 1);
|
|
1261
1737
|
break;
|
|
1262
1738
|
}
|
|
1263
1739
|
case "dev": {
|
|
1264
|
-
const
|
|
1265
|
-
const appFile = detectAppEntrypoint(projectRoot);
|
|
1740
|
+
const targetDir = args[1] && !args[1].startsWith("-") ? path13.resolve(process.cwd(), args[1]) : process.cwd();
|
|
1266
1741
|
const portArgIdx = args.indexOf("--port");
|
|
1267
1742
|
const port = portArgIdx !== -1 ? parseInt(args[portArgIdx + 1], 10) : 8080;
|
|
1268
|
-
const
|
|
1269
|
-
const
|
|
1743
|
+
const serviceArgIdx = args.indexOf("--service") !== -1 ? args.indexOf("--service") : args.indexOf("--orchestration");
|
|
1744
|
+
const targetService = serviceArgIdx !== -1 ? args[serviceArgIdx + 1] : void 0;
|
|
1270
1745
|
const isAll = args.includes("--all");
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1746
|
+
const dryRun = args.includes("--dry-run") || args.includes("--once");
|
|
1747
|
+
const devInstance = await runDev(targetDir, { port, service: targetService, orchestration: targetService, all: isAll, dryRun });
|
|
1748
|
+
if (dryRun) {
|
|
1749
|
+
process.exit(0);
|
|
1274
1750
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
console.log(`\u26A1 [Krnl Dev] Development environment ready.`);
|
|
1751
|
+
process.on("SIGINT", async () => {
|
|
1752
|
+
await devInstance.close();
|
|
1753
|
+
process.exit(0);
|
|
1754
|
+
});
|
|
1755
|
+
process.on("SIGTERM", async () => {
|
|
1756
|
+
await devInstance.close();
|
|
1757
|
+
process.exit(0);
|
|
1758
|
+
});
|
|
1284
1759
|
break;
|
|
1285
1760
|
}
|
|
1286
1761
|
case "help":
|
|
@@ -1293,22 +1768,24 @@ async function main() {
|
|
|
1293
1768
|
Usage: krnl <command> [options]
|
|
1294
1769
|
|
|
1295
1770
|
Commands:
|
|
1296
|
-
dev Start Krnl service dev server
|
|
1297
|
-
build Validate and
|
|
1771
|
+
dev Start Krnl service dev server with hot declaration watcher
|
|
1772
|
+
build Validate, generate declarations, and compile project to dist/
|
|
1298
1773
|
validate Run deep AST & 4-layer function purity validation
|
|
1299
1774
|
sync Reconcile package.json from all co-located manifest.json files
|
|
1300
1775
|
watch Generate ambient TypeScript declarations (krnl-magnetic.d.ts)
|
|
1301
|
-
generate Scaffold
|
|
1776
|
+
generate Scaffold services, functionality-orchestrations, functionalities, libraries
|
|
1302
1777
|
Examples:
|
|
1303
|
-
krnl generate
|
|
1304
|
-
krnl generate
|
|
1305
|
-
krnl generate
|
|
1306
|
-
krnl generate
|
|
1778
|
+
krnl generate service Payment
|
|
1779
|
+
krnl generate service Payment --default-frontend=PaymentPage --default-frontend-package=@ultrst-armada/floks/ui --default-frontend-export=PaymentPage --default-frontend-relationship=required
|
|
1780
|
+
krnl generate functionality-orchestration Payment
|
|
1781
|
+
krnl generate functionality ProcessPayment Payment
|
|
1782
|
+
krnl generate library TaxCalculator Payment
|
|
1307
1783
|
|
|
1308
1784
|
Options:
|
|
1309
|
-
--
|
|
1310
|
-
--all Run or build all
|
|
1785
|
+
--service <name> Target a specific service variant to run or build
|
|
1786
|
+
--all Run or build all services as a combined build
|
|
1311
1787
|
--port <number> Specify port for Krnl service dev server (default: 8080)
|
|
1788
|
+
--dry-run, --once Verify environment without running persistent server
|
|
1312
1789
|
--watch, -w Enable continuous file watcher (for watch command)
|
|
1313
1790
|
--help, -h Show this help message
|
|
1314
1791
|
`);
|