@ultrst-armada/krnl 1.0.17 → 1.0.19
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/package.json +1 -1
- package/packages/cli/dist/bin/krnl.cjs +145 -143
- package/packages/cli/dist/bin/krnl.js +1 -1
- package/packages/cli/dist/{chunk-OOVZPIMX.js → chunk-FKQ5QRQF.js} +140 -138
- package/packages/cli/dist/index.cjs +140 -138
- package/packages/cli/dist/index.js +1 -1
- package/packages/core/dist/index.cjs +94 -79
- package/packages/core/dist/index.d.cts +7 -15
- package/packages/core/dist/index.d.ts +7 -15
- package/packages/core/dist/index.js +94 -79
- package/packages/validate/dist/index.cjs +51 -41
- package/packages/validate/dist/index.js +48 -38
|
@@ -62,8 +62,60 @@ var LifecycleManager = class {
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
// src/telemetry/
|
|
65
|
+
// src/telemetry/TelemetryInternals.ts
|
|
66
66
|
import { randomUUID } from "crypto";
|
|
67
|
+
var createTelemetryId = (prefix) => `${prefix}_${randomUUID()}`;
|
|
68
|
+
|
|
69
|
+
// src/telemetry/TelemetrySnapshotBuilder.ts
|
|
70
|
+
function percentiles(values) {
|
|
71
|
+
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
72
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
73
|
+
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
74
|
+
return {
|
|
75
|
+
min: sorted[0],
|
|
76
|
+
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
77
|
+
p50: pick(0.5),
|
|
78
|
+
p90: pick(0.9),
|
|
79
|
+
p95: pick(0.95),
|
|
80
|
+
p99: pick(0.99),
|
|
81
|
+
max: sorted[sorted.length - 1]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function buildTelemetrySnapshot(input) {
|
|
85
|
+
const invocations = input.invocations.slice();
|
|
86
|
+
const durations = invocations.map((item) => item.durationMs);
|
|
87
|
+
const targetMap = /* @__PURE__ */ new Map();
|
|
88
|
+
for (const invocation of invocations) {
|
|
89
|
+
const key = `${invocation.kind}:${invocation.target}`;
|
|
90
|
+
const group = targetMap.get(key) ?? [];
|
|
91
|
+
group.push(invocation);
|
|
92
|
+
targetMap.set(key, group);
|
|
93
|
+
}
|
|
94
|
+
const targets = [...targetMap.values()].map((group) => ({
|
|
95
|
+
target: group[0].target,
|
|
96
|
+
kind: group[0].kind,
|
|
97
|
+
count: group.length,
|
|
98
|
+
successCount: group.filter((item) => item.status === "completed").length,
|
|
99
|
+
errorCount: group.filter((item) => item.status === "failed").length,
|
|
100
|
+
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
101
|
+
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
102
|
+
}));
|
|
103
|
+
return {
|
|
104
|
+
serviceId: input.serviceId,
|
|
105
|
+
mode: input.mode,
|
|
106
|
+
capturedAt: Date.now(),
|
|
107
|
+
status: input.status,
|
|
108
|
+
totals: {
|
|
109
|
+
invocationCount: input.totalInvocationCount,
|
|
110
|
+
successCount: input.totalSuccessCount,
|
|
111
|
+
errorCount: input.totalErrorCount,
|
|
112
|
+
durationMs: percentiles(durations)
|
|
113
|
+
},
|
|
114
|
+
targets,
|
|
115
|
+
activeInvocations: input.activeInvocations,
|
|
116
|
+
recentInvocations: invocations.slice(-input.maxRecentInvocations)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
67
119
|
|
|
68
120
|
// src/telemetry/TelemetryResources.ts
|
|
69
121
|
var runtimeProcess = typeof globalThis !== "undefined" ? globalThis.process : void 0;
|
|
@@ -103,21 +155,6 @@ function deltaResources(start, end) {
|
|
|
103
155
|
}
|
|
104
156
|
|
|
105
157
|
// src/telemetry/TelemetryController.ts
|
|
106
|
-
var id = (prefix) => `${prefix}_${randomUUID()}`;
|
|
107
|
-
function percentiles(values) {
|
|
108
|
-
if (!values.length) return { min: 0, mean: 0, p50: 0, p90: 0, p95: 0, p99: 0, max: 0 };
|
|
109
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
110
|
-
const pick = (p) => sorted[Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * p))];
|
|
111
|
-
return {
|
|
112
|
-
min: sorted[0],
|
|
113
|
-
mean: sorted.reduce((sum, value) => sum + value, 0) / sorted.length,
|
|
114
|
-
p50: pick(0.5),
|
|
115
|
-
p90: pick(0.9),
|
|
116
|
-
p95: pick(0.95),
|
|
117
|
-
p99: pick(0.99),
|
|
118
|
-
max: sorted[sorted.length - 1]
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
158
|
var TelemetryController = class {
|
|
122
159
|
constructor(serviceId, options = {}) {
|
|
123
160
|
this.serviceId = serviceId;
|
|
@@ -169,9 +206,9 @@ var TelemetryController = class {
|
|
|
169
206
|
end: () => void 0
|
|
170
207
|
};
|
|
171
208
|
}
|
|
172
|
-
const invocationId =
|
|
173
|
-
const spanId =
|
|
174
|
-
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ??
|
|
209
|
+
const invocationId = createTelemetryId("inv");
|
|
210
|
+
const spanId = createTelemetryId("span");
|
|
211
|
+
const traceId = parentSpanId ? this.findTraceId(parentSpanId) ?? createTelemetryId("trace") : createTelemetryId("trace");
|
|
175
212
|
const active = {
|
|
176
213
|
invocationId,
|
|
177
214
|
traceId,
|
|
@@ -202,39 +239,17 @@ var TelemetryController = class {
|
|
|
202
239
|
this.lastInvocationAt = void 0;
|
|
203
240
|
}
|
|
204
241
|
snapshot() {
|
|
205
|
-
|
|
206
|
-
const durations = invocations.map((item) => item.durationMs);
|
|
207
|
-
const targetMap = /* @__PURE__ */ new Map();
|
|
208
|
-
for (const invocation of invocations) {
|
|
209
|
-
const key = `${invocation.kind}:${invocation.target}`;
|
|
210
|
-
const group = targetMap.get(key) ?? [];
|
|
211
|
-
group.push(invocation);
|
|
212
|
-
targetMap.set(key, group);
|
|
213
|
-
}
|
|
214
|
-
const targets = [...targetMap.values()].map((group) => ({
|
|
215
|
-
target: group[0].target,
|
|
216
|
-
kind: group[0].kind,
|
|
217
|
-
count: group.length,
|
|
218
|
-
successCount: group.filter((item) => item.status === "completed").length,
|
|
219
|
-
errorCount: group.filter((item) => item.status === "failed").length,
|
|
220
|
-
durationMs: percentiles(group.map((item) => item.durationMs)),
|
|
221
|
-
lastInvocationAt: group[group.length - 1]?.completedAt
|
|
222
|
-
}));
|
|
223
|
-
return {
|
|
242
|
+
return buildTelemetrySnapshot({
|
|
224
243
|
serviceId: this.serviceId,
|
|
225
244
|
mode: this.mode,
|
|
226
|
-
|
|
245
|
+
invocations: this.samples,
|
|
227
246
|
status: this.status(),
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
errorCount: this.totalErrorCount,
|
|
232
|
-
durationMs: percentiles(durations)
|
|
233
|
-
},
|
|
234
|
-
targets,
|
|
247
|
+
totalInvocationCount: this.totalInvocationCount,
|
|
248
|
+
totalSuccessCount: this.totalSuccessCount,
|
|
249
|
+
totalErrorCount: this.totalErrorCount,
|
|
235
250
|
activeInvocations: this.active.size,
|
|
236
|
-
|
|
237
|
-
};
|
|
251
|
+
maxRecentInvocations: this.maxRecentInvocations
|
|
252
|
+
});
|
|
238
253
|
}
|
|
239
254
|
functionality(name) {
|
|
240
255
|
return this.snapshot().targets.find((target) => target.kind === "functionality" && target.target === name);
|
|
@@ -638,22 +653,22 @@ var FunctionalityFacade = class {
|
|
|
638
653
|
definition;
|
|
639
654
|
eventBus;
|
|
640
655
|
events;
|
|
641
|
-
constructor(
|
|
642
|
-
if (!
|
|
656
|
+
constructor(id, definition, options = {}) {
|
|
657
|
+
if (!id || typeof id !== "string") {
|
|
643
658
|
throw new Error("[FunctionalityFacade] Functionality id must be a non-empty string.");
|
|
644
659
|
}
|
|
645
660
|
if (!definition || typeof definition.execute !== "function") {
|
|
646
|
-
throw new Error(`[FunctionalityFacade:${
|
|
661
|
+
throw new Error(`[FunctionalityFacade:${id}] Functionality must define execute().`);
|
|
647
662
|
}
|
|
648
|
-
this.id =
|
|
649
|
-
this.name = definition.name ||
|
|
663
|
+
this.id = id;
|
|
664
|
+
this.name = definition.name || id;
|
|
650
665
|
this.description = definition.description || "";
|
|
651
666
|
this.bubbleEvents = options.bubbleEvents ?? definition.bubbleEvents ?? true;
|
|
652
667
|
this.definition = definition;
|
|
653
668
|
this.eventBus = new EventBus();
|
|
654
669
|
for (const reserved of ["triggered", "completed", "failed"]) {
|
|
655
670
|
if (definition.events && reserved in definition.events) {
|
|
656
|
-
throw new Error(`[FunctionalityFacade:${
|
|
671
|
+
throw new Error(`[FunctionalityFacade:${id}] Event '${reserved}' is reserved for functionality lifecycle.`);
|
|
657
672
|
}
|
|
658
673
|
}
|
|
659
674
|
const eventNames = [
|
|
@@ -767,11 +782,11 @@ var PriorityQueue = class {
|
|
|
767
782
|
return item.run;
|
|
768
783
|
}
|
|
769
784
|
enqueue(run, options) {
|
|
770
|
-
const { priority = 0, id
|
|
785
|
+
const { priority = 0, id } = options ?? {};
|
|
771
786
|
const { size } = this;
|
|
772
787
|
const element = {
|
|
773
788
|
priority,
|
|
774
|
-
id
|
|
789
|
+
id,
|
|
775
790
|
run
|
|
776
791
|
};
|
|
777
792
|
if (size === 0) {
|
|
@@ -788,16 +803,16 @@ var PriorityQueue = class {
|
|
|
788
803
|
const index = lowerBound(this.#queue, element, (a, b) => a.priority === b.priority ? 0 : b.priority - a.priority);
|
|
789
804
|
this.#queue.splice(index, 0, element);
|
|
790
805
|
}
|
|
791
|
-
setPriority(
|
|
792
|
-
const index = this.#findIndex((element) => element.id ===
|
|
806
|
+
setPriority(id, priority) {
|
|
807
|
+
const index = this.#findIndex((element) => element.id === id);
|
|
793
808
|
if (index === -1) {
|
|
794
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
809
|
+
throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
|
|
795
810
|
}
|
|
796
811
|
if (this.#queue[index].priority === priority) {
|
|
797
812
|
return;
|
|
798
813
|
}
|
|
799
814
|
const [item] = this.#queue.splice(index, 1);
|
|
800
|
-
this.enqueue(item.run, { priority, id
|
|
815
|
+
this.enqueue(item.run, { priority, id });
|
|
801
816
|
}
|
|
802
817
|
remove(idOrRun) {
|
|
803
818
|
const index = this.#findIndex((element) => (typeof idOrRun === "string" ? element.id : element.run) === idOrRun);
|
|
@@ -1213,17 +1228,17 @@ var PQueue = class extends EventTarget {
|
|
|
1213
1228
|
}
|
|
1214
1229
|
}
|
|
1215
1230
|
async #add(function_, options, waitingTask) {
|
|
1216
|
-
const
|
|
1231
|
+
const id = options.id ?? (this.#idAssigner++).toString();
|
|
1217
1232
|
options = {
|
|
1218
1233
|
timeout: this.#timeout,
|
|
1219
1234
|
...options,
|
|
1220
|
-
id
|
|
1235
|
+
id
|
|
1221
1236
|
};
|
|
1222
1237
|
validateTimeout(options.timeout);
|
|
1223
1238
|
if (options.priority !== void 0 && (typeof options.priority !== "number" || Number.isNaN(options.priority))) {
|
|
1224
1239
|
throw new TypeError(`Expected \`priority\` to be a number, got \`${String(options.priority)}\` (${typeof options.priority})`);
|
|
1225
1240
|
}
|
|
1226
|
-
waitingTask.id =
|
|
1241
|
+
waitingTask.id = id;
|
|
1227
1242
|
waitingTask.priority = options.priority ?? 0;
|
|
1228
1243
|
return new Promise((resolve, reject) => {
|
|
1229
1244
|
if (options.signal?.aborted) {
|
|
@@ -1240,7 +1255,7 @@ var PQueue = class extends EventTarget {
|
|
|
1240
1255
|
}
|
|
1241
1256
|
this.#pending++;
|
|
1242
1257
|
const runningTask = {
|
|
1243
|
-
id
|
|
1258
|
+
id,
|
|
1244
1259
|
priority: waitingTask.priority,
|
|
1245
1260
|
startTime: Date.now(),
|
|
1246
1261
|
timeout: options.timeout
|
|
@@ -1307,7 +1322,7 @@ var PQueue = class extends EventTarget {
|
|
|
1307
1322
|
if (this.#queue instanceof PriorityQueue) {
|
|
1308
1323
|
this.#queue.remove(run);
|
|
1309
1324
|
} else {
|
|
1310
|
-
this.#queue.remove(
|
|
1325
|
+
this.#queue.remove(id);
|
|
1311
1326
|
}
|
|
1312
1327
|
reject(signal.reason);
|
|
1313
1328
|
this.#processQueue();
|
|
@@ -1383,18 +1398,18 @@ var PQueue = class extends EventTarget {
|
|
|
1383
1398
|
// '🦀' runs last
|
|
1384
1399
|
```
|
|
1385
1400
|
*/
|
|
1386
|
-
setPriority(
|
|
1401
|
+
setPriority(id, priority) {
|
|
1387
1402
|
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1388
1403
|
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
1389
1404
|
}
|
|
1390
1405
|
for (const waitingTask of this.#waitingTasks) {
|
|
1391
|
-
if (waitingTask.id ===
|
|
1392
|
-
this.#queue.setPriority(
|
|
1406
|
+
if (waitingTask.id === id) {
|
|
1407
|
+
this.#queue.setPriority(id, priority);
|
|
1393
1408
|
waitingTask.priority = priority;
|
|
1394
1409
|
return;
|
|
1395
1410
|
}
|
|
1396
1411
|
}
|
|
1397
|
-
throw new ReferenceError(`No promise function with the id "${
|
|
1412
|
+
throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
|
|
1398
1413
|
}
|
|
1399
1414
|
/**
|
|
1400
1415
|
Adds a sync or async task to the queue.
|
|
@@ -1739,7 +1754,7 @@ var TimeoutError = class extends DOMException {
|
|
|
1739
1754
|
// src/orchestration/canonical/KrnlQ.ts
|
|
1740
1755
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1741
1756
|
|
|
1742
|
-
// src/orchestration/canonical/
|
|
1757
|
+
// src/orchestration/canonical/dagValidation.ts
|
|
1743
1758
|
function validateOrchestrationDAG(steps) {
|
|
1744
1759
|
const errors = [];
|
|
1745
1760
|
const stepMap = /* @__PURE__ */ new Map();
|
|
@@ -1804,8 +1819,8 @@ function validateOrchestrationDAG(steps) {
|
|
|
1804
1819
|
}
|
|
1805
1820
|
}
|
|
1806
1821
|
const queue = [];
|
|
1807
|
-
for (const [
|
|
1808
|
-
if (deg === 0) queue.push(
|
|
1822
|
+
for (const [id, deg] of inDegree.entries()) {
|
|
1823
|
+
if (deg === 0) queue.push(id);
|
|
1809
1824
|
}
|
|
1810
1825
|
const order = [];
|
|
1811
1826
|
while (queue.length > 0) {
|
|
@@ -2009,9 +2024,9 @@ var KrnlQueue = class {
|
|
|
2009
2024
|
if (this.jobs.size <= this.maxRetainedJobs) return;
|
|
2010
2025
|
const excess = this.jobs.size - this.maxRetainedJobs;
|
|
2011
2026
|
let pruned = 0;
|
|
2012
|
-
for (const [
|
|
2027
|
+
for (const [id, record] of this.jobs.entries()) {
|
|
2013
2028
|
if (record.status === "completed" || record.status === "failed" || record.status === "cancelled") {
|
|
2014
|
-
this.jobs.delete(
|
|
2029
|
+
this.jobs.delete(id);
|
|
2015
2030
|
pruned++;
|
|
2016
2031
|
if (pruned >= excess) break;
|
|
2017
2032
|
}
|
|
@@ -3576,9 +3591,9 @@ var ServiceRuntime = class {
|
|
|
3576
3591
|
// src/discovery/ServiceDiscovery.ts
|
|
3577
3592
|
var ServiceDiscovery = class {
|
|
3578
3593
|
peers = /* @__PURE__ */ new Map();
|
|
3579
|
-
registerPeer(
|
|
3580
|
-
this.peers.set(
|
|
3581
|
-
id
|
|
3594
|
+
registerPeer(id, name, endpoints) {
|
|
3595
|
+
this.peers.set(id, {
|
|
3596
|
+
id,
|
|
3582
3597
|
name,
|
|
3583
3598
|
endpoints,
|
|
3584
3599
|
lastSeen: Date.now()
|
|
@@ -3587,8 +3602,8 @@ var ServiceDiscovery = class {
|
|
|
3587
3602
|
getPeers() {
|
|
3588
3603
|
return Array.from(this.peers.values());
|
|
3589
3604
|
}
|
|
3590
|
-
findPeer(
|
|
3591
|
-
return this.peers.get(
|
|
3605
|
+
findPeer(id) {
|
|
3606
|
+
return this.peers.get(id);
|
|
3592
3607
|
}
|
|
3593
3608
|
};
|
|
3594
3609
|
|
|
@@ -36,8 +36,8 @@ module.exports = __toCommonJS(index_exports);
|
|
|
36
36
|
|
|
37
37
|
// src/KrnlValidatorEngine.ts
|
|
38
38
|
var fs2 = __toESM(require("fs"), 1);
|
|
39
|
-
var
|
|
40
|
-
var
|
|
39
|
+
var path4 = __toESM(require("path"), 1);
|
|
40
|
+
var import_ts_morph6 = require("ts-morph");
|
|
41
41
|
|
|
42
42
|
// src/rules/fileLimits.ts
|
|
43
43
|
function checkFileLimits(sf, options) {
|
|
@@ -312,6 +312,9 @@ function checkOrchestrationRules(sf) {
|
|
|
312
312
|
|
|
313
313
|
// src/rules/workspaceRules.ts
|
|
314
314
|
var fs = __toESM(require("fs"), 1);
|
|
315
|
+
var path3 = __toESM(require("path"), 1);
|
|
316
|
+
|
|
317
|
+
// src/rules/topLevelPurityRules.ts
|
|
315
318
|
var path2 = __toESM(require("path"), 1);
|
|
316
319
|
var import_ts_morph3 = require("ts-morph");
|
|
317
320
|
function checkTopLevelPurity(sf) {
|
|
@@ -377,25 +380,27 @@ function checkTopLevelPurity(sf) {
|
|
|
377
380
|
}
|
|
378
381
|
return { errors, warnings };
|
|
379
382
|
}
|
|
383
|
+
|
|
384
|
+
// src/rules/workspaceRules.ts
|
|
380
385
|
function checkWorkspaceLayout(projectRoot, errors) {
|
|
381
|
-
const krnlDir =
|
|
382
|
-
const srcDir =
|
|
386
|
+
const krnlDir = path3.join(projectRoot, "krnl");
|
|
387
|
+
const srcDir = path3.join(projectRoot, "src");
|
|
383
388
|
const targetDir = fs.existsSync(krnlDir) ? krnlDir : fs.existsSync(srcDir) ? srcDir : null;
|
|
384
389
|
if (!targetDir) return;
|
|
385
|
-
const backendDir =
|
|
386
|
-
const frontendDir =
|
|
390
|
+
const backendDir = path3.join(targetDir, "backend");
|
|
391
|
+
const frontendDir = path3.join(targetDir, "frontend");
|
|
387
392
|
if (fs.existsSync(backendDir)) {
|
|
388
|
-
const bServices =
|
|
393
|
+
const bServices = path3.join(backendDir, "services");
|
|
389
394
|
if (fs.existsSync(bServices)) {
|
|
390
395
|
for (const sEntry of fs.readdirSync(bServices, { withFileTypes: true })) {
|
|
391
396
|
if (!sEntry.isDirectory()) continue;
|
|
392
|
-
const sDir =
|
|
393
|
-
const sLibs =
|
|
397
|
+
const sDir = path3.join(bServices, sEntry.name);
|
|
398
|
+
const sLibs = path3.join(sDir, "libraries");
|
|
394
399
|
if (fs.existsSync(sLibs)) {
|
|
395
400
|
for (const entry of fs.readdirSync(sLibs, { withFileTypes: true })) {
|
|
396
401
|
if (!entry.isDirectory()) continue;
|
|
397
|
-
const libPath =
|
|
398
|
-
if (!fs.existsSync(
|
|
402
|
+
const libPath = path3.join(sLibs, entry.name);
|
|
403
|
+
if (!fs.existsSync(path3.join(libPath, "manifest.json"))) {
|
|
399
404
|
errors.push({
|
|
400
405
|
ruleId: "krnl/concept-manifest-required",
|
|
401
406
|
filePath: libPath,
|
|
@@ -405,12 +410,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
405
410
|
}
|
|
406
411
|
}
|
|
407
412
|
}
|
|
408
|
-
const sFuncs =
|
|
413
|
+
const sFuncs = path3.join(sDir, "functionalities");
|
|
409
414
|
if (fs.existsSync(sFuncs)) {
|
|
410
415
|
for (const entry of fs.readdirSync(sFuncs, { withFileTypes: true })) {
|
|
411
416
|
if (!entry.isDirectory()) continue;
|
|
412
|
-
const funcPath =
|
|
413
|
-
if (!fs.existsSync(
|
|
417
|
+
const funcPath = path3.join(sFuncs, entry.name);
|
|
418
|
+
if (!fs.existsSync(path3.join(funcPath, "manifest.json"))) {
|
|
414
419
|
errors.push({
|
|
415
420
|
ruleId: "krnl/functionality-manifest-required",
|
|
416
421
|
filePath: funcPath,
|
|
@@ -422,12 +427,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
422
427
|
}
|
|
423
428
|
}
|
|
424
429
|
}
|
|
425
|
-
const bLibs =
|
|
430
|
+
const bLibs = path3.join(backendDir, "libraries");
|
|
426
431
|
if (fs.existsSync(bLibs)) {
|
|
427
432
|
for (const entry of fs.readdirSync(bLibs, { withFileTypes: true })) {
|
|
428
433
|
if (!entry.isDirectory()) continue;
|
|
429
|
-
const libPath =
|
|
430
|
-
if (!fs.existsSync(
|
|
434
|
+
const libPath = path3.join(bLibs, entry.name);
|
|
435
|
+
if (!fs.existsSync(path3.join(libPath, "manifest.json"))) {
|
|
431
436
|
errors.push({
|
|
432
437
|
ruleId: "krnl/concept-manifest-required",
|
|
433
438
|
filePath: libPath,
|
|
@@ -437,12 +442,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
437
442
|
}
|
|
438
443
|
}
|
|
439
444
|
}
|
|
440
|
-
const bFuncs =
|
|
445
|
+
const bFuncs = path3.join(backendDir, "functionalities");
|
|
441
446
|
if (fs.existsSync(bFuncs)) {
|
|
442
447
|
for (const entry of fs.readdirSync(bFuncs, { withFileTypes: true })) {
|
|
443
448
|
if (!entry.isDirectory()) continue;
|
|
444
|
-
const funcPath =
|
|
445
|
-
if (!fs.existsSync(
|
|
449
|
+
const funcPath = path3.join(bFuncs, entry.name);
|
|
450
|
+
if (!fs.existsSync(path3.join(funcPath, "manifest.json"))) {
|
|
446
451
|
errors.push({
|
|
447
452
|
ruleId: "krnl/functionality-manifest-required",
|
|
448
453
|
filePath: funcPath,
|
|
@@ -454,12 +459,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
454
459
|
}
|
|
455
460
|
}
|
|
456
461
|
if (fs.existsSync(frontendDir)) {
|
|
457
|
-
const fLibs =
|
|
462
|
+
const fLibs = path3.join(frontendDir, "libraries");
|
|
458
463
|
if (fs.existsSync(fLibs)) {
|
|
459
464
|
for (const entry of fs.readdirSync(fLibs, { withFileTypes: true })) {
|
|
460
465
|
if (!entry.isDirectory()) continue;
|
|
461
|
-
const libPath =
|
|
462
|
-
if (!fs.existsSync(
|
|
466
|
+
const libPath = path3.join(fLibs, entry.name);
|
|
467
|
+
if (!fs.existsSync(path3.join(libPath, "manifest.json"))) {
|
|
463
468
|
errors.push({
|
|
464
469
|
ruleId: "krnl/frontend-concept-manifest-required",
|
|
465
470
|
filePath: libPath,
|
|
@@ -469,12 +474,12 @@ function checkWorkspaceLayout(projectRoot, errors) {
|
|
|
469
474
|
}
|
|
470
475
|
}
|
|
471
476
|
}
|
|
472
|
-
const fFuncs =
|
|
477
|
+
const fFuncs = path3.join(frontendDir, "functionalities");
|
|
473
478
|
if (fs.existsSync(fFuncs)) {
|
|
474
479
|
for (const entry of fs.readdirSync(fFuncs, { withFileTypes: true })) {
|
|
475
480
|
if (!entry.isDirectory()) continue;
|
|
476
|
-
const funcPath =
|
|
477
|
-
if (!fs.existsSync(
|
|
481
|
+
const funcPath = path3.join(fFuncs, entry.name);
|
|
482
|
+
if (!fs.existsSync(path3.join(funcPath, "manifest.json"))) {
|
|
478
483
|
errors.push({
|
|
479
484
|
ruleId: "krnl/frontend-functionality-manifest-required",
|
|
480
485
|
filePath: funcPath,
|
|
@@ -518,6 +523,9 @@ function checkServiceBoundaries(sf) {
|
|
|
518
523
|
}
|
|
519
524
|
|
|
520
525
|
// src/rules/scopedLibraryRules.ts
|
|
526
|
+
var import_ts_morph5 = require("ts-morph");
|
|
527
|
+
|
|
528
|
+
// src/rules/scopedLibraryTypeHelpers.ts
|
|
521
529
|
var import_ts_morph4 = require("ts-morph");
|
|
522
530
|
var PRIMITIVE_AND_BUILTIN_TYPES = /* @__PURE__ */ new Set([
|
|
523
531
|
"string",
|
|
@@ -570,14 +578,6 @@ var PRIMITIVE_AND_BUILTIN_TYPES = /* @__PURE__ */ new Set([
|
|
|
570
578
|
"ReturnType",
|
|
571
579
|
"InstanceType"
|
|
572
580
|
]);
|
|
573
|
-
function detectServiceContext(filePath) {
|
|
574
|
-
const normalized = filePath.replace(/\\/g, "/");
|
|
575
|
-
const match = normalized.match(/(?:^|\/)services\/([^/]+)\/libraries\/([^/]+)/);
|
|
576
|
-
if (match) {
|
|
577
|
-
return { serviceName: match[1], libraryName: match[2] };
|
|
578
|
-
}
|
|
579
|
-
return null;
|
|
580
|
-
}
|
|
581
581
|
function containsIdentifier(name, target) {
|
|
582
582
|
return name.toLowerCase().includes(target.toLowerCase());
|
|
583
583
|
}
|
|
@@ -598,6 +598,16 @@ function hasContextualTypeReference(node, serviceName, localTypes) {
|
|
|
598
598
|
}
|
|
599
599
|
return false;
|
|
600
600
|
}
|
|
601
|
+
|
|
602
|
+
// src/rules/scopedLibraryRules.ts
|
|
603
|
+
function detectServiceContext(filePath) {
|
|
604
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
605
|
+
const match = normalized.match(/(?:^|\/)services\/([^/]+)\/libraries\/([^/]+)/);
|
|
606
|
+
if (match) {
|
|
607
|
+
return { serviceName: match[1], libraryName: match[2] };
|
|
608
|
+
}
|
|
609
|
+
return null;
|
|
610
|
+
}
|
|
601
611
|
function checkScopedLibraryRules(sf) {
|
|
602
612
|
const errors = [];
|
|
603
613
|
const warnings = [];
|
|
@@ -647,7 +657,7 @@ function checkScopedLibraryRules(sf) {
|
|
|
647
657
|
for (const decl of stmt.getDeclarations()) {
|
|
648
658
|
const varName = decl.getName();
|
|
649
659
|
const init = decl.getInitializer();
|
|
650
|
-
const isFunction = init && (init.getKind() ===
|
|
660
|
+
const isFunction = init && (init.getKind() === import_ts_morph5.SyntaxKind.ArrowFunction || init.getKind() === import_ts_morph5.SyntaxKind.FunctionExpression);
|
|
651
661
|
if (isFunction) {
|
|
652
662
|
const isContextual = hasContextualTypeReference(decl, serviceName, localTypes);
|
|
653
663
|
const hasServiceName = containsIdentifier(varName, serviceName);
|
|
@@ -738,17 +748,17 @@ var KrnlValidatorEngine = class {
|
|
|
738
748
|
limitOptions;
|
|
739
749
|
constructor(optionsOrRoot) {
|
|
740
750
|
const options = typeof optionsOrRoot === "string" ? { projectRoot: optionsOrRoot } : optionsOrRoot;
|
|
741
|
-
this.projectRoot =
|
|
751
|
+
this.projectRoot = path4.resolve(options.projectRoot || process.cwd());
|
|
742
752
|
this.limitOptions = {
|
|
743
753
|
maxFileLineLimit: options.maxFileLineLimit ?? 200,
|
|
744
754
|
maxMainLogicLimit: options.maxMainLogicLimit ?? 20,
|
|
745
755
|
maxHelperLineLimit: options.maxHelperLineLimit ?? 30
|
|
746
756
|
};
|
|
747
|
-
const tsConfigPath =
|
|
757
|
+
const tsConfigPath = path4.join(this.projectRoot, "tsconfig.json");
|
|
748
758
|
if (fs2.existsSync(tsConfigPath)) {
|
|
749
|
-
this.project = new
|
|
759
|
+
this.project = new import_ts_morph6.Project({ tsConfigFilePath: tsConfigPath, skipAddingFilesFromTsConfig: true });
|
|
750
760
|
} else {
|
|
751
|
-
this.project = new
|
|
761
|
+
this.project = new import_ts_morph6.Project({ compilerOptions: {
|
|
752
762
|
target: 99
|
|
753
763
|
/* ESNext */
|
|
754
764
|
} });
|
|
@@ -779,7 +789,7 @@ var KrnlValidatorEngine = class {
|
|
|
779
789
|
}
|
|
780
790
|
validateSourceFile(sf) {
|
|
781
791
|
const filePath = sf.getFilePath();
|
|
782
|
-
const baseName =
|
|
792
|
+
const baseName = path4.basename(filePath);
|
|
783
793
|
if (baseName.includes("_pb.") || baseName.endsWith(".d.ts")) {
|
|
784
794
|
return { errors: [], warnings: [], promotableAssets: [] };
|
|
785
795
|
}
|
|
@@ -814,7 +824,7 @@ var KrnlValidatorEngine = class {
|
|
|
814
824
|
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
815
825
|
for (const entry of entries) {
|
|
816
826
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git") continue;
|
|
817
|
-
const full =
|
|
827
|
+
const full = path4.join(dir, entry.name);
|
|
818
828
|
if (entry.isDirectory()) {
|
|
819
829
|
this.collectSourceFiles(full, collected);
|
|
820
830
|
} else if (entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js") || entry.name.endsWith(".tsx") || entry.name.endsWith(".jsx"))) {
|