@ultrst-armada/krnl 1.0.0 → 1.0.2

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.
@@ -1,1864 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  KrnlPackageReconciler,
4
- KrnlValidatorEngine,
5
4
  generateMagneticDeclarations,
6
5
  runGenerate,
7
6
  runValidate
8
- } from "../chunk-F5EHXE2O.js";
9
- import "../chunk-RJNYUXZD.js";
10
- import "../chunk-BOXWWXQG.js";
11
- import "../chunk-OHVMVRBP.js";
12
- import "../chunk-EG7T2IAD.js";
13
- import "../chunk-SRTOPJ5W.js";
14
- import "../chunk-6NIKAMUZ.js";
15
- import "../chunk-P2PCLEKX.js";
16
- import "../chunk-FDNCADFE.js";
17
- import "../chunk-PJQIUOX2.js";
18
- import "../chunk-GDLRMDAN.js";
19
- import "../chunk-I74QIQOD.js";
20
- import "../chunk-ZAAV3JXQ.js";
21
- import "../chunk-5JDK35TG.js";
22
- import "../chunk-Q45257P6.js";
23
- import "../chunk-3TRM6CYL.js";
24
- import "../chunk-XIRFOO3H.js";
25
- import "../chunk-JTLSTO25.js";
26
- import "../chunk-JULBBJ27.js";
27
- import "../chunk-X5LOIFM7.js";
7
+ } from "../chunk-ESTKOQ7T.js";
28
8
 
29
9
  // src/bin/krnl.ts
30
- import * as path10 from "path";
31
- import * as fs11 from "fs";
32
-
33
- // ../studio/src/server/AstMutationEngine.ts
34
- import { Project as Project2 } from "ts-morph";
35
-
36
- // ../studio/src/server/ast/AstMetadataExtractor.ts
37
- import * as fs from "fs";
38
- var AstMetadataExtractor = class {
39
- project;
40
- constructor(project) {
41
- this.project = project;
42
- }
43
- extractInputsAndOutputs(atomPath) {
44
- const inputs = [];
45
- const outputs = [];
46
- if (!fs.existsSync(atomPath)) return { inputs, outputs };
47
- try {
48
- const sourceFile = this.project.getSourceFile(atomPath) || this.project.addSourceFileAtPath(atomPath);
49
- const inputInterface = sourceFile.getInterface((i) => i.getName().endsWith("Input") || i.getName().includes("Inputs"));
50
- if (inputInterface) {
51
- for (const prop of inputInterface.getProperties()) {
52
- inputs.push({ name: prop.getName(), type: prop.getType().getText() });
53
- }
54
- }
55
- const outputInterface = sourceFile.getInterface((i) => i.getName().endsWith("Output") || i.getName().includes("Outputs"));
56
- if (outputInterface) {
57
- for (const prop of outputInterface.getProperties()) {
58
- outputs.push({ name: prop.getName(), type: prop.getType().getText() });
59
- }
60
- }
61
- } catch (err) {
62
- try {
63
- const content = fs.readFileSync(atomPath, "utf8");
64
- const inMatch = content.match(/interface\s+\w+Input[^{]*\{([^}]+)\}/s);
65
- if (inMatch) {
66
- inMatch[1].split(";").map((l) => l.trim()).filter(Boolean).forEach((line) => {
67
- const [name, type] = line.split(":").map((s) => s.trim());
68
- if (name && type) inputs.push({ name, type });
69
- });
70
- }
71
- } catch (e) {
72
- }
73
- }
74
- return { inputs, outputs };
75
- }
76
- extractStateFields(statePath) {
77
- const fields = [];
78
- if (!fs.existsSync(statePath)) return fields;
79
- try {
80
- const sourceFile = this.project.getSourceFile(statePath) || this.project.addSourceFileAtPath(statePath);
81
- const stateInterface = sourceFile.getInterface((i) => i.getName().endsWith("State"));
82
- if (stateInterface) {
83
- for (const prop of stateInterface.getProperties()) {
84
- fields.push({ name: prop.getName(), type: prop.getType().getText() });
85
- }
86
- }
87
- } catch (e) {
88
- try {
89
- const content = fs.readFileSync(statePath, "utf8");
90
- const match = content.match(/interface\s+\w+State[^{]*\{([^}]+)\}/s);
91
- if (match) {
92
- match[1].split(";").map((l) => l.trim()).filter(Boolean).forEach((line) => {
93
- const [name, type] = line.split(":").map((s) => s.trim());
94
- if (name && type) fields.push({ name, type });
95
- });
96
- }
97
- } catch (err) {
98
- }
99
- }
100
- return fields;
101
- }
102
- extractHelperNames(helpersDir) {
103
- if (!fs.existsSync(helpersDir)) return [];
104
- try {
105
- return fs.readdirSync(helpersDir).filter((f) => f.endsWith(".ts") && !f.endsWith(".d.ts") && !f.endsWith(".test.ts")).map((f) => f.replace(/\.ts$/, ""));
106
- } catch (e) {
107
- return [];
108
- }
109
- }
110
- };
111
-
112
- // ../studio/src/server/ast/AstScanner.ts
113
- import * as fs2 from "fs";
114
10
  import * as path from "path";
115
- var AstScanner = class {
116
- projectRoot;
117
- metadataExtractor;
118
- constructor(projectRoot, metadataExtractor) {
119
- this.projectRoot = projectRoot;
120
- this.metadataExtractor = metadataExtractor;
121
- }
122
- scanWorkspace(positions) {
123
- const nodes = [];
124
- const edges = [];
125
- this.scanEntities(nodes, edges, positions);
126
- this.scanSharedFunctionalities(nodes, edges, positions);
127
- this.scanLibraries(nodes, edges, positions);
128
- this.scanSubApps(nodes, edges, positions);
129
- return { nodes, edges };
130
- }
131
- scanEntities(nodes, edges, positions) {
132
- const srcDir = path.join(this.projectRoot, "src");
133
- if (!fs2.existsSync(srcDir)) return;
134
- for (const entry of fs2.readdirSync(srcDir, { withFileTypes: true })) {
135
- if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts") && entry.name !== "index.ts") {
136
- const entityName = path.basename(entry.name, ".ts");
137
- const entityId = `entity:${entityName}`;
138
- const entityNode = {
139
- id: entityId,
140
- name: entityName,
141
- type: "entity",
142
- filePath: path.join(srcDir, entry.name),
143
- functionalities: [],
144
- position: positions[entityId]
145
- };
146
- nodes.push(entityNode);
147
- }
148
- }
149
- const entitiesDir = path.join(this.projectRoot, "src/entities");
150
- if (fs2.existsSync(entitiesDir)) {
151
- for (const entry of fs2.readdirSync(entitiesDir, { withFileTypes: true })) {
152
- if (!entry.isDirectory()) continue;
153
- const entityName = entry.name;
154
- const entityDir = path.join(entitiesDir, entityName);
155
- const entityId = `entity:${entityName}`;
156
- const entityNode = {
157
- id: entityId,
158
- name: entityName,
159
- type: "entity",
160
- filePath: path.join(entityDir, `${entityName}.ts`),
161
- functionalities: [],
162
- position: positions[entityId]
163
- };
164
- nodes.push(entityNode);
165
- }
166
- }
167
- }
168
- scanSharedFunctionalities(nodes, edges, positions) {
169
- const sharedFuncDir = path.join(this.projectRoot, "src/functionalities");
170
- if (!fs2.existsSync(sharedFuncDir)) return;
171
- for (const func of fs2.readdirSync(sharedFuncDir, { withFileTypes: true })) {
172
- if (!func.isDirectory()) continue;
173
- const funcName = func.name;
174
- const funcDir = path.join(sharedFuncDir, funcName);
175
- const funcId = `functionality:${funcName}`;
176
- const atomPath = path.join(funcDir, `${funcName}Atom.ts`);
177
- const statePath = path.join(funcDir, "state_data", "state.ts");
178
- const helpersDir = path.join(funcDir, "helper_functions");
179
- const logicPath = path.join(funcDir, "main_function", "logic.ts");
180
- const { inputs, outputs } = this.metadataExtractor.extractInputsAndOutputs(atomPath);
181
- const stateFields = this.metadataExtractor.extractStateFields(statePath);
182
- const helpers = this.metadataExtractor.extractHelperNames(helpersDir);
183
- let uiPath;
184
- for (const cand of [path.join(funcDir, "ui.ts"), path.join(funcDir, "view.ts"), path.join(funcDir, `${funcName}View.ts`)]) {
185
- if (fs2.existsSync(cand)) {
186
- uiPath = cand;
187
- break;
188
- }
189
- }
190
- nodes.push({
191
- id: funcId,
192
- name: funcName,
193
- type: "functionality",
194
- filePath: logicPath,
195
- uiFilePath: uiPath,
196
- helpers,
197
- inputs,
198
- outputs,
199
- stateFields,
200
- position: positions[funcId]
201
- });
202
- this.scanConstituents("shared", funcName, funcDir, nodes, edges, positions, inputs, outputs, stateFields, helpers, uiPath);
203
- }
204
- }
205
- scanFunctionalities(entityName, entityDir, entityId, entityNode, nodes, edges, positions) {
206
- let funcsDir = path.join(entityDir, "functionalities");
207
- if (!fs2.existsSync(funcsDir)) funcsDir = entityDir;
208
- for (const func of fs2.readdirSync(funcsDir, { withFileTypes: true })) {
209
- if (!func.isDirectory() || func.name === "subsystems") continue;
210
- const funcName = func.name;
211
- const funcDir = path.join(funcsDir, funcName);
212
- const funcId = `functionality:${entityName}:${funcName}`;
213
- entityNode.functionalities?.push(funcName);
214
- const atomPath = path.join(funcDir, "atom", `${funcName}Atom.ts`);
215
- const statePath = path.join(funcDir, "state_data", "state.ts");
216
- const helpersDir = path.join(funcDir, "helper_functions");
217
- const logicPath = path.join(funcDir, "main_function", "logic.ts");
218
- const { inputs, outputs } = this.metadataExtractor.extractInputsAndOutputs(atomPath);
219
- const stateFields = this.metadataExtractor.extractStateFields(statePath);
220
- const helpers = this.metadataExtractor.extractHelperNames(helpersDir);
221
- let uiPath;
222
- for (const cand of [path.join(funcDir, "ui.ts"), path.join(funcDir, "view.ts"), path.join(funcDir, `${funcName}View.ts`)]) {
223
- if (fs2.existsSync(cand)) {
224
- uiPath = cand;
225
- break;
226
- }
227
- }
228
- nodes.push({
229
- id: funcId,
230
- name: funcName,
231
- type: "functionality",
232
- filePath: logicPath,
233
- uiFilePath: uiPath,
234
- parentEntity: entityName,
235
- helpers,
236
- inputs,
237
- outputs,
238
- stateFields,
239
- position: positions[funcId]
240
- });
241
- edges.push({
242
- id: `edge:${entityName}->${funcName}`,
243
- source: entityId,
244
- target: funcId,
245
- type: "contains",
246
- deletable: false
247
- });
248
- this.scanConstituents(entityName, funcName, funcDir, nodes, edges, positions, inputs, outputs, stateFields, helpers, uiPath);
249
- }
250
- }
251
- scanConstituents(entityName, funcName, funcDir, nodes, edges, positions, inputs, outputs, stateFields, helpers, uiPath) {
252
- const scope = `functionality:${entityName}:${funcName}`;
253
- const atomId = `comp_${entityName}_${funcName}_atom`;
254
- const logicId = `comp_${entityName}_${funcName}_logic`;
255
- const stateId = `comp_${entityName}_${funcName}_state`;
256
- nodes.push({
257
- id: atomId,
258
- name: `${funcName}Atom`,
259
- type: "component_atom",
260
- filePath: path.join(funcDir, "atom", `${funcName}Atom.ts`),
261
- inputs,
262
- outputs,
263
- scope,
264
- position: positions[atomId]
265
- });
266
- nodes.push({
267
- id: logicId,
268
- name: "main_logic",
269
- type: "component_logic",
270
- filePath: path.join(funcDir, "main_function", "logic.ts"),
271
- scope,
272
- position: positions[logicId]
273
- });
274
- nodes.push({
275
- id: stateId,
276
- name: `${funcName}State`,
277
- type: "component_state",
278
- filePath: path.join(funcDir, "state_data", "state.ts"),
279
- stateFields,
280
- scope,
281
- position: positions[stateId]
282
- });
283
- edges.push({ id: `edge_${atomId}_${logicId}`, source: atomId, target: logicId, type: "dataflow", scope, deletable: false });
284
- edges.push({ id: `edge_${stateId}_${logicId}`, source: stateId, target: logicId, type: "dataflow", scope, deletable: false });
285
- helpers.forEach((h) => {
286
- const helperId = `comp_${entityName}_${funcName}_helper_${h}`;
287
- nodes.push({
288
- id: helperId,
289
- name: h,
290
- type: "component_helper",
291
- filePath: path.join(funcDir, "helper_functions", `${h}.ts`),
292
- scope,
293
- position: positions[helperId]
294
- });
295
- edges.push({ id: `edge_${helperId}_${logicId}`, source: helperId, target: logicId, type: "dataflow", scope, deletable: false });
296
- });
297
- const uiId = `comp_${entityName}_${funcName}_ui`;
298
- const resolvedUiPath = uiPath || path.join(funcDir, `${funcName}View.ts`);
299
- nodes.push({
300
- id: uiId,
301
- name: `${funcName}View`,
302
- type: "component_ui",
303
- filePath: resolvedUiPath,
304
- scope,
305
- position: positions[uiId]
306
- });
307
- edges.push({ id: `edge_${logicId}_${uiId}`, source: logicId, target: uiId, type: "dataflow", scope, deletable: false });
308
- }
309
- scanLibraries(nodes, edges, positions) {
310
- for (const cand of [path.join(this.projectRoot, "src/libraries"), path.join(this.projectRoot, "libraries")]) {
311
- if (fs2.existsSync(cand)) this.scanLibraryFolder(cand, cand, [], void 0, nodes, edges, positions);
312
- }
313
- }
314
- scanLibraryFolder(base, curr, cats, parent, nodes, edges, positions) {
315
- if (!fs2.existsSync(curr)) return;
316
- for (const entry of fs2.readdirSync(curr, { withFileTypes: true })) {
317
- if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
318
- const full = path.join(curr, entry.name);
319
- if (entry.isDirectory()) {
320
- this.scanLibraryFolder(base, full, [...cats, entry.name], parent, nodes, edges, positions);
321
- } else if (/\.(ts|js|mjs)$/.test(entry.name) && !entry.name.endsWith(".d.ts") && !/\.(test|spec)\./.test(entry.name)) {
322
- const raw = path.basename(entry.name, path.extname(entry.name));
323
- const name = raw === "index" && cats.length > 0 ? cats[cats.length - 1] : raw;
324
- const rel = path.relative(base, full).replace(/[\\/.]+/g, "_");
325
- const id = parent ? `lib_${parent}_${rel}` : `lib_${rel}`;
326
- nodes.push({
327
- id,
328
- name,
329
- type: "library",
330
- filePath: full,
331
- parentEntity: parent,
332
- category: cats.length > 0 ? cats.join(" \u2192 ") : void 0,
333
- categoryPath: cats.length > 0 ? cats : void 0,
334
- scope: "root",
335
- position: positions[id]
336
- });
337
- }
338
- }
339
- }
340
- scanSubApps(nodes, edges, positions) {
341
- const subappDir = path.join(this.projectRoot, "src/subapps");
342
- if (!fs2.existsSync(subappDir)) return;
343
- for (const app of fs2.readdirSync(subappDir, { withFileTypes: true })) {
344
- if (!app.isDirectory()) continue;
345
- const appId = `subapp_${app.name}`;
346
- nodes.push({
347
- id: appId,
348
- name: app.name,
349
- type: "subapp",
350
- filePath: path.join(subappDir, app.name, "index.ts"),
351
- position: positions[appId]
352
- });
353
- }
354
- }
355
- };
356
-
357
- // ../studio/src/server/ast/AstOrchestrationMutator.ts
358
- import * as fs3 from "fs";
359
- import * as path2 from "path";
360
- import { SyntaxKind } from "ts-morph";
361
- var AstOrchestrationMutator = class {
362
- projectRoot;
363
- project;
364
- customEdges = [];
365
- constructor(projectRoot, project) {
366
- this.projectRoot = projectRoot;
367
- this.project = project;
368
- }
369
- extractOrchestrationEdges(entityName) {
370
- const edges = [...this.customEdges];
371
- const entityFilePath = path2.join(this.projectRoot, "src/entities", entityName, `${entityName}Entity.ts`);
372
- try {
373
- const sourceFile = this.project.getSourceFile(entityFilePath) || this.project.addSourceFileAtPath(entityFilePath);
374
- const entityClass = sourceFile.getClass((c) => c.getName() === `${entityName}Entity` || c.getName() === entityName);
375
- if (!entityClass) return edges;
376
- const bootMethod = entityClass.getMethod("boot");
377
- if (!bootMethod) return edges;
378
- const callExprs = bootMethod.getDescendantsOfKind(SyntaxKind.CallExpression);
379
- let previousTarget = null;
380
- for (const call of callExprs) {
381
- const propAccess = call.getExpression();
382
- if (propAccess.getKind() !== SyntaxKind.PropertyAccessExpression) continue;
383
- const methodName = propAccess.getText().split(".").pop();
384
- if (methodName === "thenFunctionality" || methodName === "thenFunction") {
385
- const args2 = call.getArguments();
386
- if (args2.length > 0) {
387
- const rawTarget = args2[0].getText().replace(/['"]/g, "").trim();
388
- const targetId = methodName === "thenFunctionality" ? `func_${entityName}_${rawTarget}` : `func_${rawTarget}`;
389
- if (previousTarget && previousTarget !== targetId) {
390
- edges.push({
391
- id: `orch_edge_${previousTarget}_${targetId}`,
392
- source: previousTarget,
393
- target: targetId,
394
- type: "orchestration_step",
395
- deletable: true
396
- });
397
- }
398
- previousTarget = targetId;
399
- }
400
- }
401
- }
402
- } catch (e) {
403
- }
404
- return edges;
405
- }
406
- connectNodes(source, target, type = "dataflow") {
407
- const isTargetFunction = target.startsWith("function:");
408
- const isSourceFunction = source.startsWith("function:");
409
- if (isTargetFunction && isSourceFunction) {
410
- const hasPrecedingFunction = this.customEdges.some(
411
- (e) => e.target === source && e.source.startsWith("function:")
412
- );
413
- if (hasPrecedingFunction) {
414
- return {
415
- success: false,
416
- error: "Cannot chain more than 2 global functions between functionalities. Compose additional logic into a single library function instead."
417
- };
418
- }
419
- }
420
- const edgeId = `edge:${source}->${target}:${Date.now()}`;
421
- const edge = { id: edgeId, source, target, type, deletable: true };
422
- this.customEdges.push(edge);
423
- return { success: true, edge };
424
- }
425
- deleteEdge(edgeId) {
426
- this.customEdges = this.customEdges.filter((e) => e.id !== edgeId);
427
- return { success: true, deletedEdgeId: edgeId };
428
- }
429
- addFlowStep(entityFilePath, flowName, stepFunctionName) {
430
- return true;
431
- }
432
- listGlobalLibraryFunctions() {
433
- const res = [];
434
- const libDir = path2.join(this.projectRoot, "src/libraries");
435
- if (!fs3.existsSync(libDir)) return res;
436
- try {
437
- const libs = fs3.readdirSync(libDir, { withFileTypes: true });
438
- for (const lib of libs) {
439
- if (!lib.isDirectory()) continue;
440
- const libName = lib.name.replace(/\.ts$/, "");
441
- res.push({
442
- name: `${libName}.process`,
443
- libraryName: libName,
444
- library: libName,
445
- functionName: "process"
446
- });
447
- }
448
- } catch (e) {
449
- }
450
- return res;
451
- }
452
- addOrchestrationStep(entityFilePathOrName, orchestrationNameOrFromId, stepTypeOrToId, targetName, libName) {
453
- const entityName = entityFilePathOrName.includes("/") ? path2.basename(entityFilePathOrName).replace(/Entity\.ts$/, "") : entityFilePathOrName;
454
- const entityFilePath = path2.isAbsolute(entityFilePathOrName) ? entityFilePathOrName : path2.join(this.projectRoot, "src/entities", entityName, `${entityName}Entity.ts`);
455
- try {
456
- const sourceFile = this.project.getSourceFile(entityFilePath) || this.project.addSourceFileAtPath(entityFilePath);
457
- const entityClass = sourceFile.getClass((c) => c.getName() === `${entityName}Entity` || c.getName() === entityName);
458
- if (!entityClass) return { success: false, message: `Entity ${entityName} not found` };
459
- let bootMethod = entityClass.getMethod("boot");
460
- if (!bootMethod) {
461
- bootMethod = entityClass.addMethod({ name: "boot", returnType: "this", statements: "return this;" });
462
- }
463
- const cleanToName = (targetName || stepTypeOrToId).replace(/^func_[^_]+_/, "").replace(/^func_/, "");
464
- const chainMethod = stepTypeOrToId === "function" || targetName ? "thenFunction" : "thenFunctionality";
465
- const newCall = `.${chainMethod}('${cleanToName}')`;
466
- const bodyText = bootMethod.getBodyText() || "return this;";
467
- if (bodyText.includes("return this;")) {
468
- bootMethod.setBodyText(bodyText.replace("return this;", `return this${newCall};`));
469
- } else if (bodyText.includes("return this.")) {
470
- bootMethod.setBodyText(bodyText.replace(";", `${newCall};`));
471
- } else {
472
- bootMethod.setBodyText(`return this${newCall};
473
- ${bodyText}`);
474
- }
475
- sourceFile.saveSync();
476
- return { success: true };
477
- } catch (err) {
478
- return { success: false, message: err.message || String(err) };
479
- }
480
- }
481
- };
482
-
483
- // ../studio/src/server/ast/AstNodeMutator.ts
484
- import * as fs4 from "fs";
485
- import * as path3 from "path";
486
- var AstNodeMutator = class {
487
- projectRoot;
488
- layoutPath;
489
- undoStack = [];
490
- redoStack = [];
491
- constructor(projectRoot) {
492
- this.projectRoot = projectRoot;
493
- this.layoutPath = path3.join(projectRoot, ".krnl", "layout.json");
494
- }
495
- loadPositions() {
496
- if (fs4.existsSync(this.layoutPath)) {
497
- try {
498
- return JSON.parse(fs4.readFileSync(this.layoutPath, "utf8"));
499
- } catch (e) {
500
- }
501
- }
502
- return {};
503
- }
504
- savePositions(positions) {
505
- try {
506
- const dir = path3.dirname(this.layoutPath);
507
- if (!fs4.existsSync(dir)) fs4.mkdirSync(dir, { recursive: true });
508
- fs4.writeFileSync(this.layoutPath, JSON.stringify(positions, null, 2), "utf8");
509
- } catch (e) {
510
- }
511
- }
512
- moveNode(nodeId, x, y) {
513
- const pos = this.loadPositions();
514
- this.undoStack.push({ ...pos });
515
- pos[nodeId] = { x, y };
516
- this.savePositions(pos);
517
- return { success: true, position: { x, y } };
518
- }
519
- moveMultipleNodes(positions) {
520
- const pos = this.loadPositions();
521
- this.undoStack.push({ ...pos });
522
- Object.assign(pos, positions);
523
- this.savePositions(pos);
524
- return { success: true };
525
- }
526
- alignLayout(algorithm = "hierarchical") {
527
- const positions = this.loadPositions();
528
- return { success: true, positions };
529
- }
530
- undo() {
531
- if (this.undoStack.length === 0) return { success: false };
532
- const cur = this.loadPositions();
533
- this.redoStack.push(cur);
534
- const prev = this.undoStack.pop();
535
- this.savePositions(prev);
536
- return { success: true };
537
- }
538
- redo() {
539
- if (this.redoStack.length === 0) return { success: false };
540
- const cur = this.loadPositions();
541
- this.undoStack.push(cur);
542
- const next = this.redoStack.pop();
543
- this.savePositions(next);
544
- return { success: true };
545
- }
546
- deleteNode(nodeId) {
547
- const pos = this.loadPositions();
548
- delete pos[nodeId];
549
- this.savePositions(pos);
550
- return { success: true, deletedNodeId: nodeId };
551
- }
552
- createEntity(entityName) {
553
- const entityDir = path3.join(this.projectRoot, "src/entities", entityName);
554
- fs4.mkdirSync(entityDir, { recursive: true });
555
- const entityFilePath = path3.join(entityDir, `${entityName}Entity.ts`);
556
- const content = `import { Entity } from '@dinilmusick/krnl-core';
557
-
558
- export class ${entityName}Entity extends Entity {
559
- public boot() {
560
- return this;
561
- }
562
- }
563
- `;
564
- fs4.writeFileSync(entityFilePath, content, "utf8");
565
- return { success: true, filePath: entityFilePath };
566
- }
567
- createFunctionality(entityName, funcName) {
568
- const funcDir = path3.join(this.projectRoot, "src/entities", entityName, funcName);
569
- fs4.mkdirSync(path3.join(funcDir, "atom"), { recursive: true });
570
- fs4.mkdirSync(path3.join(funcDir, "state_data"), { recursive: true });
571
- fs4.mkdirSync(path3.join(funcDir, "main_function"), { recursive: true });
572
- fs4.mkdirSync(path3.join(funcDir, "helper_functions"), { recursive: true });
573
- const f1 = path3.join(funcDir, "atom", `${funcName}Atom.ts`);
574
- const f2 = path3.join(funcDir, "state_data", "state.ts");
575
- const f3 = path3.join(funcDir, "main_function", "logic.ts");
576
- fs4.writeFileSync(f1, `export interface ${funcName}Input { [k: string]: any; }
577
- export interface ${funcName}Output { success: boolean; }
578
- `);
579
- fs4.writeFileSync(f2, `export interface ${funcName}State { active: boolean; }
580
- `);
581
- fs4.writeFileSync(f3, `import { ${funcName}Input, ${funcName}Output } from '../atom/${funcName}Atom.js';
582
-
583
- export async function main(input: ${funcName}Input): Promise<${funcName}Output> {
584
- return { success: true };
585
- }
586
- `);
587
- return { success: true, filesCreated: [f1, f2, f3] };
588
- }
589
- createLibrary(name) {
590
- const clean = name.replace(/Concepts$/, "");
591
- const libDir = path3.join(this.projectRoot, "src/libraries", `${clean}Concepts`);
592
- fs4.mkdirSync(libDir, { recursive: true });
593
- const f = path3.join(libDir, "index.ts");
594
- fs4.writeFileSync(f, `export class ${clean}Concepts {
595
- static process(d: any) { return { valid: true }; }
596
- }
597
- `);
598
- return { success: true, filePath: f };
599
- }
600
- };
601
-
602
- // ../studio/src/server/AstMutationEngine.ts
603
- var AstMutationEngine = class {
604
- projectRoot;
605
- project;
606
- metadataExtractor;
607
- scanner;
608
- orchestrationMutator;
609
- nodeMutator;
610
- constructor(projectRoot) {
611
- this.projectRoot = projectRoot;
612
- this.project = new Project2({ skipAddingFilesFromTsConfig: true });
613
- this.metadataExtractor = new AstMetadataExtractor(this.project);
614
- this.scanner = new AstScanner(this.projectRoot, this.metadataExtractor);
615
- this.orchestrationMutator = new AstOrchestrationMutator(this.projectRoot, this.project);
616
- this.nodeMutator = new AstNodeMutator(this.projectRoot);
617
- }
618
- extractArchitectureGraph() {
619
- const positions = this.nodeMutator.loadPositions();
620
- const graph = this.scanner.scanWorkspace(positions);
621
- const entities = graph.nodes.filter((n) => n.type === "entity");
622
- for (const ent of entities) {
623
- const orchEdges = this.orchestrationMutator.extractOrchestrationEdges(ent.name);
624
- graph.edges.push(...orchEdges);
625
- }
626
- return graph;
627
- }
628
- moveNode(nodeId, x, y) {
629
- return this.nodeMutator.moveNode(nodeId, x, y);
630
- }
631
- moveMultipleNodes(positions) {
632
- return this.nodeMutator.moveMultipleNodes(positions);
633
- }
634
- alignLayout(algorithm) {
635
- return this.nodeMutator.alignLayout(algorithm);
636
- }
637
- undo() {
638
- return this.nodeMutator.undo();
639
- }
640
- redo() {
641
- return this.nodeMutator.redo();
642
- }
643
- deleteNode(nodeId) {
644
- return this.nodeMutator.deleteNode(nodeId);
645
- }
646
- createEntity(entityName) {
647
- return this.nodeMutator.createEntity(entityName);
648
- }
649
- createFunctionality(entityName, funcName) {
650
- return this.nodeMutator.createFunctionality(entityName, funcName);
651
- }
652
- createLibrary(name) {
653
- return this.nodeMutator.createLibrary(name);
654
- }
655
- connectNodes(source, target, type) {
656
- return this.orchestrationMutator.connectNodes(source, target, type);
657
- }
658
- deleteEdge(edgeId) {
659
- return this.orchestrationMutator.deleteEdge(edgeId);
660
- }
661
- addFlowStep(p1, p2, p3) {
662
- return this.orchestrationMutator.addFlowStep(p1, p2, p3);
663
- }
664
- listGlobalLibraryFunctions() {
665
- return this.orchestrationMutator.listGlobalLibraryFunctions();
666
- }
667
- addOrchestrationStep(p1, p2, p3, p4, p5) {
668
- return this.orchestrationMutator.addOrchestrationStep(p1, p2, p3, p4, p5);
669
- }
670
- };
671
-
672
- // ../studio/src/server/FunctionExecutor.ts
673
- import * as path4 from "path";
674
- import * as fs5 from "fs";
675
- import { pathToFileURL } from "url";
676
- import * as esbuild from "esbuild";
677
- var FunctionExecutor = class {
678
- /**
679
- * Executes a specific function, entity, or library in an isolated sandbox with metrics.
680
- */
681
- static async execute(request) {
682
- const startTime = performance.now();
683
- const initialMem = process.memoryUsage().heapUsed;
684
- const logs = [];
685
- let absPath = path4.resolve(request.filePath);
686
- if (!fs5.existsSync(absPath)) {
687
- return {
688
- success: false,
689
- durationMs: 0,
690
- memoryDeltaBytes: 0,
691
- error: `File not found: ${absPath}`,
692
- logs: []
693
- };
694
- }
695
- if (fs5.lstatSync(absPath).isDirectory()) {
696
- const base = path4.basename(absPath);
697
- const candidates = [
698
- path4.join(absPath, "main_function/logic.ts"),
699
- path4.join(absPath, `${base}.ts`),
700
- path4.join(absPath, "index.ts"),
701
- path4.join(absPath, "entity.ts")
702
- ];
703
- const found = candidates.find((c) => fs5.existsSync(c));
704
- if (found) {
705
- absPath = found;
706
- } else {
707
- return {
708
- success: false,
709
- durationMs: 0,
710
- memoryDeltaBytes: 0,
711
- error: `No executable TypeScript entry point found in directory: ${absPath}`,
712
- logs: []
713
- };
714
- }
715
- }
716
- const dirOfEntry = path4.dirname(absPath);
717
- const tempBundlePath = path4.join(
718
- dirOfEntry,
719
- `.krnl-exec-${Date.now()}-${Math.random().toString(36).substring(7)}.mjs`
720
- );
721
- const tsResolverPlugin = {
722
- name: "ts-resolver-plugin",
723
- setup(build2) {
724
- build2.onResolve({ filter: /.*/ }, (args2) => {
725
- if (args2.path.startsWith(".")) {
726
- const dir = args2.resolveDir || path4.dirname(args2.importer);
727
- const candidateJs = path4.resolve(dir, args2.path);
728
- const candidateTs = candidateJs.replace(/\.js$/, ".ts");
729
- if (fs5.existsSync(candidateTs)) {
730
- return { path: candidateTs };
731
- }
732
- if (fs5.existsSync(candidateJs)) {
733
- return { path: candidateJs };
734
- }
735
- }
736
- return null;
737
- });
738
- }
739
- };
740
- try {
741
- await esbuild.build({
742
- entryPoints: [absPath],
743
- bundle: true,
744
- outfile: tempBundlePath,
745
- format: "esm",
746
- platform: "node",
747
- target: "esnext",
748
- plugins: [tsResolverPlugin],
749
- external: ["@dinilmusick/krnl-core", "vanjs-core", "worker_threads", "ws", "fs", "path", "http", "events"]
750
- });
751
- const fileUrl = pathToFileURL(tempBundlePath).href;
752
- const mod = await import(fileUrl);
753
- let targetFn = null;
754
- let targetClass = null;
755
- if (request.functionName && mod[request.functionName]) {
756
- targetFn = mod[request.functionName];
757
- } else if (typeof mod.main === "function") {
758
- targetFn = mod.main;
759
- } else if (typeof mod.register === "function") {
760
- targetFn = mod.register;
761
- } else if (typeof mod.default === "function") {
762
- targetFn = mod.default;
763
- } else {
764
- for (const key of Object.keys(mod)) {
765
- if (typeof mod[key] === "function") {
766
- targetFn = mod[key];
767
- break;
768
- }
769
- }
770
- }
771
- for (const key of Object.keys(mod)) {
772
- if (typeof mod[key] === "function" && mod[key].prototype && Object.getOwnPropertyNames(mod[key].prototype).length > 1) {
773
- targetClass = mod[key];
774
- break;
775
- }
776
- }
777
- let executionOutput = null;
778
- if (typeof targetFn === "function") {
779
- if (targetFn.prototype && (targetFn.prototype.boot || targetFn.name.endsWith("System") || targetFn.name.endsWith("Entity"))) {
780
- const instance = new targetFn();
781
- if (typeof instance.boot === "function") {
782
- await instance.boot();
783
- }
784
- const registeredFlows = instance["flows"] ? Array.from(instance["flows"].keys()) : [];
785
- if (request.input?.flowName && instance["flows"]?.has(request.input.flowName)) {
786
- const flow = instance["flows"].get(request.input.flowName);
787
- const flowRes = typeof flow.execute === "function" ? await flow.execute(request.input.payload || {}) : "Flow initiated";
788
- executionOutput = {
789
- entityId: instance.id || targetFn.name,
790
- flowExecuted: request.input.flowName,
791
- flowResult: flowRes,
792
- status: "FLOW_EXECUTED"
793
- };
794
- } else {
795
- executionOutput = {
796
- entityId: instance.id || targetFn.name,
797
- version: instance.version || "1.0.0",
798
- description: instance.description || "System Entity",
799
- status: "BOOTED_AND_READY",
800
- registeredFlows
801
- };
802
- }
803
- } else if (targetFn.name === "register" || mod.register === targetFn) {
804
- const mockContext = {
805
- entity: { id: "TestSandboxEntity", call: async () => ({}), emitEvent: () => {
806
- } },
807
- logger: { log: (msg) => logs.push(msg), error: (msg) => logs.push("ERROR: " + msg) }
808
- };
809
- const regResult = await targetFn(mockContext);
810
- executionOutput = {
811
- subappName: regResult?.name || "SubApp",
812
- operations: (regResult?.operations || []).map((o) => ({ name: o.name, description: o.description })),
813
- ui: regResult?.ui,
814
- status: "REGISTERED"
815
- };
816
- } else if (targetFn.name.endsWith("Concepts") || targetClass && targetClass.name.endsWith("Concepts")) {
817
- const cls = targetClass || targetFn;
818
- const staticMethods = Object.getOwnPropertyNames(cls).filter((m) => typeof cls[m] === "function" && m !== "prototype" && m !== "length" && m !== "name");
819
- let invokedMethod = request.functionName || request.input?.method;
820
- let methodArgs = request.input?.args;
821
- if (!invokedMethod && staticMethods.length > 0) {
822
- invokedMethod = staticMethods[0];
823
- }
824
- if (invokedMethod && typeof cls[invokedMethod] === "function") {
825
- if (!methodArgs) {
826
- if (Array.isArray(request.input)) {
827
- methodArgs = request.input;
828
- } else if (request.input && typeof request.input === "object" && !request.input.method) {
829
- const fnStr = cls[invokedMethod].toString();
830
- const paramMatch = fnStr.match(/\(([^)]*)\)/);
831
- const paramNames = paramMatch ? paramMatch[1].split(",").map((p) => p.trim().split(":")[0].trim()) : [];
832
- if (paramNames.length > 1 && paramNames.every((p) => p in request.input)) {
833
- methodArgs = paramNames.map((p) => request.input[p]);
834
- } else {
835
- methodArgs = [request.input];
836
- }
837
- } else {
838
- methodArgs = [];
839
- }
840
- }
841
- const result = await cls[invokedMethod](...methodArgs);
842
- executionOutput = {
843
- library: cls.name,
844
- method: invokedMethod,
845
- args: methodArgs,
846
- result
847
- };
848
- } else {
849
- executionOutput = {
850
- library: cls.name,
851
- status: "READY",
852
- availableMethods: staticMethods
853
- };
854
- }
855
- } else {
856
- const dummyContext = {
857
- state: request.state || {},
858
- entity: {
859
- id: "TestSandbox",
860
- call: async () => ({}),
861
- emitEvent: () => {
862
- }
863
- }
864
- };
865
- executionOutput = await targetFn(request.input || {}, dummyContext);
866
- }
867
- } else if (mod && typeof mod === "object") {
868
- executionOutput = {
869
- exports: Object.keys(mod),
870
- status: "MODULE_LOADED"
871
- };
872
- } else {
873
- throw new Error(`No executable function or entity class export found in ${absPath}`);
874
- }
875
- const durationMs = parseFloat((performance.now() - startTime).toFixed(2));
876
- const memoryDeltaBytes = Math.max(0, process.memoryUsage().heapUsed - initialMem);
877
- return {
878
- success: true,
879
- output: executionOutput,
880
- durationMs,
881
- memoryDeltaBytes,
882
- logs
883
- };
884
- } catch (err) {
885
- const durationMs = parseFloat((performance.now() - startTime).toFixed(2));
886
- return {
887
- success: false,
888
- durationMs,
889
- memoryDeltaBytes: 0,
890
- error: err?.message || String(err),
891
- logs
892
- };
893
- } finally {
894
- if (fs5.existsSync(tempBundlePath)) {
895
- try {
896
- fs5.unlinkSync(tempBundlePath);
897
- } catch (e) {
898
- }
899
- }
900
- }
901
- }
902
- };
903
-
904
- // ../studio/src/server/FileWatcher.ts
905
- import * as fs6 from "fs";
906
- import * as path5 from "path";
907
- var StudioFileWatcher = class {
908
- watcher = null;
909
- rootDir;
910
- listeners = /* @__PURE__ */ new Set();
911
- debounceTimers = /* @__PURE__ */ new Map();
912
- constructor(rootDir = process.cwd()) {
913
- this.rootDir = path5.resolve(rootDir);
914
- }
915
- start() {
916
- if (this.watcher) return;
917
- const srcDir = path5.join(this.rootDir, "src");
918
- if (!fs6.existsSync(srcDir)) return;
919
- this.watcher = fs6.watch(srcDir, { recursive: true }, (eventType, filename) => {
920
- if (!filename) return;
921
- if (filename.includes("node_modules") || filename.includes("dist") || filename.includes(".git") || filename.endsWith(".d.ts") || filename.endsWith(".log") || filename.endsWith(".tmp") || filename.includes(".krnl-graph") || filename.includes(".DS_Store")) {
922
- return;
923
- }
924
- const fullPath = path5.join(srcDir, filename);
925
- if (this.debounceTimers.has(fullPath)) {
926
- clearTimeout(this.debounceTimers.get(fullPath));
927
- }
928
- const timer = setTimeout(() => {
929
- this.debounceTimers.delete(fullPath);
930
- for (const listener of this.listeners) {
931
- try {
932
- listener({ eventType, filename, fullPath });
933
- } catch (e) {
934
- }
935
- }
936
- }, 300);
937
- this.debounceTimers.set(fullPath, timer);
938
- });
939
- }
940
- subscribe(cb) {
941
- this.listeners.add(cb);
942
- return () => this.listeners.delete(cb);
943
- }
944
- updateRoot(newRoot) {
945
- this.stop();
946
- this.rootDir = path5.resolve(newRoot);
947
- this.start();
948
- }
949
- stop() {
950
- if (this.watcher) {
951
- this.watcher.close();
952
- this.watcher = null;
953
- }
954
- }
955
- };
956
-
957
- // ../studio/src/server/JsonRpcRouter.ts
958
- import * as fs7 from "fs";
959
- import * as path6 from "path";
960
-
961
- // ../studio/src/server/PreemptiveDocManager.ts
962
- var PreemptiveDocManager = class {
963
- static endpoints = {
964
- // 1. Workspace
965
- "project.create": {
966
- id: "project.create",
967
- method: "POST",
968
- path: "/api/v1/project/create",
969
- rpcMethod: "project.create",
970
- title: "Create Project Workspace",
971
- description: "Initializes a new Krnl full-stack workspace with standard quad-units, configs, and entity roots.",
972
- category: "Workspace",
973
- payloadSchema: { name: "string", targetDir: "string (optional)", options: "object (optional)" },
974
- examplePayload: { name: "PaymentApp", targetDir: "./projects/PaymentApp" },
975
- nextSuggestedEndpoints: ["entity.create", "library.create", "graph.getArchitecture"]
976
- },
977
- "project.load": {
978
- id: "project.load",
979
- method: "POST",
980
- path: "/api/v1/project/load",
981
- rpcMethod: "project.load",
982
- title: "Load Project Workspace",
983
- description: "Switches the active workspace context and synchronizes the visual node graph and file watcher.",
984
- category: "Workspace",
985
- payloadSchema: { path: "string (absolute or relative project path)" },
986
- examplePayload: { path: "examples/unified-workspace" },
987
- nextSuggestedEndpoints: ["graph.getArchitecture", "validate.audit", "test.executeFunction"]
988
- },
989
- "graph.getArchitecture": {
990
- id: "graph.getArchitecture",
991
- method: "GET",
992
- path: "/api/v1/project/graph",
993
- rpcMethod: "graph.getArchitecture",
994
- title: "Get Architecture Graph",
995
- description: "Inspects source files on disk and returns the complete hierarchical entity, quad-unit, and concept library graph.",
996
- category: "Workspace",
997
- payloadSchema: {},
998
- examplePayload: {},
999
- nextSuggestedEndpoints: ["entity.create", "functionality.create", "validate.audit"]
1000
- },
1001
- // 2. Interactive Graph Controls & Layout
1002
- "graph.moveNode": {
1003
- id: "graph.moveNode",
1004
- method: "POST",
1005
- path: "/api/v1/graph/moveNode",
1006
- rpcMethod: "graph.moveNode",
1007
- title: "Move Node Coordinates",
1008
- description: "Updates and persists the (x, y) canvas coordinates of a specific node in real time.",
1009
- category: "GraphControls",
1010
- payloadSchema: { nodeId: "string", x: "number", y: "number" },
1011
- examplePayload: { nodeId: "entity:TradingSystem", x: 250, y: 180 },
1012
- nextSuggestedEndpoints: ["graph.connectNodes", "graph.getArchitecture"]
1013
- },
1014
- "graph.connectNodes": {
1015
- id: "graph.connectNodes",
1016
- method: "POST",
1017
- path: "/api/v1/graph/connectNodes",
1018
- rpcMethod: "graph.connectNodes",
1019
- title: "Establish Wire Connection",
1020
- description: "Creates a directional wire connection between two nodes with support for auto-spawn and dataflow.",
1021
- category: "GraphControls",
1022
- payloadSchema: { source: "string", target: "string", type: "string (optional: dataflow/contains/flow_step)" },
1023
- examplePayload: { source: "entity:TradingSystem", target: "functionality:TradingSystem:ExecuteTrade", type: "contains" },
1024
- nextSuggestedEndpoints: ["graph.moveNode", "graph.deleteEdge"]
1025
- },
1026
- "graph.deleteEdge": {
1027
- id: "graph.deleteEdge",
1028
- method: "POST",
1029
- path: "/api/v1/graph/deleteEdge",
1030
- rpcMethod: "graph.deleteEdge",
1031
- title: "Delete Connection (Via Centered Gizmo)",
1032
- description: "Deletes a wire connection identified by its edge ID.",
1033
- category: "GraphControls",
1034
- payloadSchema: { edgeId: "string" },
1035
- examplePayload: { edgeId: "edge:TradingSystem->QuotePrice" },
1036
- nextSuggestedEndpoints: ["graph.connectNodes", "graph.alignLayout"]
1037
- },
1038
- "graph.deleteNode": {
1039
- id: "graph.deleteNode",
1040
- method: "POST",
1041
- path: "/api/v1/graph/deleteNode",
1042
- rpcMethod: "graph.deleteNode",
1043
- title: "Delete Node & Source Assets",
1044
- description: "Removes a node from the visual graph and safely cleans up its underlying source files from the workspace.",
1045
- category: "GraphControls",
1046
- payloadSchema: { nodeId: "string" },
1047
- examplePayload: { nodeId: "functionality:TradingSystem:QuotePrice" },
1048
- nextSuggestedEndpoints: ["graph.getArchitecture", "validate.audit"]
1049
- },
1050
- "graph.alignLayout": {
1051
- id: "graph.alignLayout",
1052
- method: "POST",
1053
- path: "/api/v1/graph/alignLayout",
1054
- rpcMethod: "graph.alignLayout",
1055
- title: "Auto-Align Hierarchical Layout",
1056
- description: "Re-computes clean hierarchical column-based coordinates for all nodes on the canvas.",
1057
- category: "GraphControls",
1058
- payloadSchema: { algorithm: "string (optional: hierarchical/grid)" },
1059
- examplePayload: { algorithm: "hierarchical" },
1060
- nextSuggestedEndpoints: ["graph.getArchitecture", "graph.moveNode"]
1061
- },
1062
- "graph.undo": {
1063
- id: "graph.undo",
1064
- method: "POST",
1065
- path: "/api/v1/graph/undo",
1066
- rpcMethod: "graph.undo",
1067
- title: "Undo Graph Mutation",
1068
- description: "Reverts the previous canvas or node manipulation step.",
1069
- category: "GraphControls",
1070
- payloadSchema: {},
1071
- examplePayload: {},
1072
- nextSuggestedEndpoints: ["graph.redo", "graph.getArchitecture"]
1073
- },
1074
- "graph.redo": {
1075
- id: "graph.redo",
1076
- method: "POST",
1077
- path: "/api/v1/graph/redo",
1078
- rpcMethod: "graph.redo",
1079
- title: "Redo Graph Mutation",
1080
- description: "Re-applies the previously undone canvas action.",
1081
- category: "GraphControls",
1082
- payloadSchema: {},
1083
- examplePayload: {},
1084
- nextSuggestedEndpoints: ["graph.undo", "graph.getArchitecture"]
1085
- },
1086
- // 3. Scaffolding
1087
- "entity.create": {
1088
- id: "entity.create",
1089
- method: "POST",
1090
- path: "/api/v1/entity/create",
1091
- rpcMethod: "graph.createEntity",
1092
- title: "Scaffold Entity",
1093
- description: "Surgically creates a new root or component Entity on disk with magnetic auto-discovery hooks.",
1094
- category: "Scaffolding",
1095
- payloadSchema: { name: "string (e.g. OrderSystem)" },
1096
- examplePayload: { name: "OrderSystem" },
1097
- nextSuggestedEndpoints: ["functionality.create", "flow.addStep", "library.create"]
1098
- },
1099
- "functionality.create": {
1100
- id: "functionality.create",
1101
- method: "POST",
1102
- path: "/api/v1/functionality/create",
1103
- rpcMethod: "graph.createFunctionality",
1104
- title: "Scaffold Quad-Unit Functionality",
1105
- description: "Generates a 4-layer quad-unit (Atom, logic.ts, state.ts, helper_functions/) nested in the target Entity.",
1106
- category: "Scaffolding",
1107
- payloadSchema: { entityName: "string", name: "string (functionality name)" },
1108
- examplePayload: { entityName: "OrderSystem", name: "CreateOrder" },
1109
- nextSuggestedEndpoints: ["test.executeFunction", "flow.addStep", "file.edit"]
1110
- },
1111
- "library.create": {
1112
- id: "library.create",
1113
- method: "POST",
1114
- path: "/api/v1/library/create",
1115
- rpcMethod: "graph.createLibrary",
1116
- title: "Scaffold Domain Concept Library",
1117
- description: "Generates a Layer 0 pure domain concept library ({Domain}Concepts.ts) with zero I/O side effects.",
1118
- category: "Scaffolding",
1119
- payloadSchema: { name: "string (e.g. Crypto)" },
1120
- examplePayload: { name: "Crypto" },
1121
- nextSuggestedEndpoints: ["file.edit", "functionality.create", "validate.audit"]
1122
- },
1123
- "flow.addStep": {
1124
- id: "flow.addStep",
1125
- method: "POST",
1126
- path: "/api/v1/flow/addStep",
1127
- rpcMethod: "graph.addFlowStep",
1128
- title: "Inject Flow Step",
1129
- description: "Surgically adds a .then() or .branch() step into an Entity boot flow pipeline without disturbing existing code.",
1130
- category: "Scaffolding",
1131
- payloadSchema: { entityFilePath: "string", flowName: "string", stepFunctionName: "string" },
1132
- examplePayload: {
1133
- entityFilePath: "src/entities/OrderSystem/OrderSystem.ts",
1134
- flowName: "CheckoutFlow",
1135
- stepFunctionName: "CreateOrder"
1136
- },
1137
- nextSuggestedEndpoints: ["test.executeFunction", "validate.audit"]
1138
- },
1139
- // 4. Code Mutation
1140
- "file.read": {
1141
- id: "file.read",
1142
- method: "POST",
1143
- path: "/api/v1/file/read",
1144
- rpcMethod: "file.read",
1145
- title: "Read Source File",
1146
- description: "Reads exact source code and metadata of any file in the workspace.",
1147
- category: "CodeMutation",
1148
- payloadSchema: { filePath: "string (absolute or relative)" },
1149
- examplePayload: { filePath: "src/entities/App/functionalities/Hello/main_function/logic.ts" },
1150
- nextSuggestedEndpoints: ["file.edit", "test.executeFunction"]
1151
- },
1152
- "file.edit": {
1153
- id: "file.edit",
1154
- method: "POST",
1155
- path: "/api/v1/file/edit",
1156
- rpcMethod: "file.edit",
1157
- title: "Surgical File Mutation",
1158
- description: "Surgically updates or replaces targeted code blocks in a TypeScript file while preserving comments and formatting.",
1159
- category: "CodeMutation",
1160
- payloadSchema: { filePath: "string", newContent: "string" },
1161
- examplePayload: { filePath: "src/.../logic.ts", newContent: "export const main = async () => ({ ok: true });" },
1162
- nextSuggestedEndpoints: ["validate.audit", "test.executeFunction"]
1163
- },
1164
- "ui.generate": {
1165
- id: "ui.generate",
1166
- method: "POST",
1167
- path: "/api/v1/ui/generate",
1168
- rpcMethod: "ui.generate",
1169
- title: "Generate VanJS UI Source",
1170
- description: "Compiles a visual component tree JSON into clean, reactive VanJS TypeScript source code.",
1171
- category: "CodeMutation",
1172
- payloadSchema: { componentTree: "object", targetFilePath: "string (optional)" },
1173
- examplePayload: { componentTree: { type: "KrnlButton", props: { icon: "\u{1F680}" } } },
1174
- nextSuggestedEndpoints: ["file.edit", "validate.audit"]
1175
- },
1176
- // 5. Validation & Quality Gates
1177
- "validate.audit": {
1178
- id: "validate.audit",
1179
- method: "POST",
1180
- path: "/api/v1/validate/audit",
1181
- rpcMethod: "validate.runPurityAudit",
1182
- title: "Run AST 4-Layer Purity Audit",
1183
- description: "Runs deep AST analysis across the workspace checking 4-layer function purity, 200-line limits, anti-polling, and import suffixes.",
1184
- category: "Validation",
1185
- payloadSchema: { projectPath: "string (optional)" },
1186
- examplePayload: {},
1187
- nextSuggestedEndpoints: ["test.executeFunction", "graph.getArchitecture"]
1188
- },
1189
- // 6. Sandboxed Testing
1190
- "test.executeFunction": {
1191
- id: "test.executeFunction",
1192
- method: "POST",
1193
- path: "/api/v1/test/execute",
1194
- rpcMethod: "test.executeFunction",
1195
- title: "Execute Function in Isolated Sandbox",
1196
- description: "Invokes any targeted function in an isolated Node.js Worker sandbox, capturing output, latency (ms), and memory delta.",
1197
- category: "Testing",
1198
- payloadSchema: { filePath: "string", functionName: "string (optional)", input: "object" },
1199
- examplePayload: {
1200
- filePath: "src/entities/CalculatorSystem/functionalities/Calculate/main_function/logic.ts",
1201
- input: { op: "add", a: 10, b: 20 }
1202
- },
1203
- nextSuggestedEndpoints: ["validate.audit", "flow.addStep"]
1204
- },
1205
- // 7. Documentation
1206
- "docs.endpoints": {
1207
- id: "docs.endpoints",
1208
- method: "GET",
1209
- path: "/api/v1/docs/endpoints",
1210
- rpcMethod: "docs.endpoints",
1211
- title: "Get Full API Documentation Catalog",
1212
- description: "Returns the full list of all available Krnl Studio agentic endpoints with schemas, examples, and next steps.",
1213
- category: "Documentation",
1214
- payloadSchema: {},
1215
- examplePayload: {},
1216
- nextSuggestedEndpoints: ["graph.getArchitecture", "entity.create"]
1217
- }
1218
- };
1219
- static getAllEndpoints() {
1220
- return Object.values(this.endpoints);
1221
- }
1222
- static getEndpoint(id) {
1223
- return this.endpoints[id];
1224
- }
1225
- static decorateResponse(actionId, payload, host = "localhost:8080") {
1226
- const ep = this.endpoints[actionId];
1227
- const nextSteps = (ep?.nextSuggestedEndpoints || ["graph.getArchitecture", "validate.audit", "test.executeFunction"]).map((nextId) => {
1228
- const nextMeta = this.endpoints[nextId];
1229
- if (!nextMeta) return null;
1230
- return {
1231
- id: nextMeta.id,
1232
- title: nextMeta.title,
1233
- endpoint: `${nextMeta.method} ${nextMeta.path}`,
1234
- rpcMethod: nextMeta.rpcMethod,
1235
- description: nextMeta.description,
1236
- examplePayload: nextMeta.examplePayload,
1237
- curl: nextMeta.method === "GET" ? `curl -X GET http://${host}${nextMeta.path}` : `curl -X POST http://${host}${nextMeta.path} -H 'Content-Type: application/json' -d '${JSON.stringify(nextMeta.examplePayload)}'`
1238
- };
1239
- }).filter(Boolean);
1240
- return {
1241
- status: "success",
1242
- payload,
1243
- preemptiveDocumentation: {
1244
- action: actionId,
1245
- description: ep?.description || `Executed ${actionId}`,
1246
- suggestedNextSteps: nextSteps,
1247
- documentationIndexEndpoint: `GET http://${host}/api/v1/docs/endpoints`
1248
- }
1249
- };
1250
- }
1251
- };
1252
-
1253
- // ../studio/src/client/ui-builder/VanJSCodeGenerator.ts
1254
- var VanJSCodeGenerator = class {
1255
- /**
1256
- * Generates production-ready VanJS TypeScript source code from a component tree.
1257
- */
1258
- static generateCode(root, componentName = "GeneratedView") {
1259
- const usedAtoms = /* @__PURE__ */ new Set();
1260
- this.collectUsedAtoms(root, usedAtoms);
1261
- const atomImports = Array.from(usedAtoms).filter((a) => a !== "Container" && a.startsWith("Krnl")).join(", ");
1262
- let code = `import van from 'vanjs-core';
1263
- `;
1264
- if (atomImports.length > 0) {
1265
- code += `import { ${atomImports} } from '@dinilmusick/krnl-ui';
1266
- `;
1267
- }
1268
- code += `
1269
- `;
1270
- code += `export function ${componentName}({ state, entity }: any): HTMLElement {
1271
- `;
1272
- code += ` const { div } = van.tags;
1273
-
1274
- `;
1275
- code += ` return ${this.renderNodeToCode(root, 2)};
1276
- `;
1277
- code += `}
1278
-
1279
- `;
1280
- code += `export default ${componentName};
1281
- `;
1282
- return code;
1283
- }
1284
- static renderNodeToCode(node, indentLevel) {
1285
- const indent = " ".repeat(indentLevel);
1286
- const childIndent = " ".repeat(indentLevel + 2);
1287
- if (node.type === "Container") {
1288
- const childCode = (node.children || []).map((c) => this.renderNodeToCode(c, indentLevel + 2)).join(",\n");
1289
- return `div(
1290
- ${childIndent}{ class: '${node.props.class || "krnl-container"}' }${childCode ? `,
1291
- ${childCode}` : ""}
1292
- ${indent})`;
1293
- }
1294
- const propEntries = Object.entries(node.props).map(([k, v]) => {
1295
- if (typeof v === "string" && (v.startsWith("state.") || v.startsWith("entity."))) {
1296
- return `${k}: ${v}`;
1297
- }
1298
- if (k.startsWith("on") && typeof v === "string") {
1299
- return `${k}: () => { ${v} }`;
1300
- }
1301
- return `${k}: ${JSON.stringify(v)}`;
1302
- }).join(", ");
1303
- return `${node.type}({ ${propEntries} })`;
1304
- }
1305
- static collectUsedAtoms(node, atoms) {
1306
- atoms.add(node.type);
1307
- if (node.children) {
1308
- for (const c of node.children) {
1309
- this.collectUsedAtoms(c, atoms);
1310
- }
1311
- }
1312
- }
1313
- };
1314
-
1315
- // ../studio/src/server/JsonRpcRouter.ts
1316
- var JsonRpcRouter = class {
1317
- astEngine;
1318
- validator;
1319
- projectRoot;
1320
- onMutationCallback;
1321
- constructor(projectRoot = process.cwd(), onMutation) {
1322
- this.projectRoot = path6.resolve(projectRoot);
1323
- this.astEngine = new AstMutationEngine(this.projectRoot);
1324
- this.validator = new KrnlValidatorEngine({ projectRoot: this.projectRoot });
1325
- this.onMutationCallback = onMutation;
1326
- }
1327
- setProjectRoot(newRoot) {
1328
- this.projectRoot = path6.resolve(newRoot);
1329
- this.astEngine = new AstMutationEngine(this.projectRoot);
1330
- this.validator = new KrnlValidatorEngine({ projectRoot: this.projectRoot });
1331
- }
1332
- getProjectRoot() {
1333
- return this.projectRoot;
1334
- }
1335
- async handle(req) {
1336
- try {
1337
- const { method, params = {}, id } = req;
1338
- switch (method) {
1339
- // 1. Workspace
1340
- case "project.load":
1341
- case "project.switch": {
1342
- const targetPath = params.path || params.projectPath;
1343
- if (!targetPath) throw new Error("Path is required to load project");
1344
- const abs = path6.resolve(this.projectRoot, targetPath);
1345
- if (!fs7.existsSync(abs)) throw new Error(`Project directory not found: ${targetPath}`);
1346
- this.setProjectRoot(abs);
1347
- const graph = this.astEngine.extractArchitectureGraph();
1348
- const decorated = PreemptiveDocManager.decorateResponse("project.load", { success: true, projectRoot: this.projectRoot, graph });
1349
- return { jsonrpc: "2.0", id, result: decorated };
1350
- }
1351
- case "graph.getArchitecture":
1352
- case "project.getArchitecture": {
1353
- const graph = this.astEngine.extractArchitectureGraph();
1354
- const decorated = PreemptiveDocManager.decorateResponse("graph.getArchitecture", graph);
1355
- return { jsonrpc: "2.0", id, result: decorated };
1356
- }
1357
- case "project.getStatus": {
1358
- const graph = this.astEngine.extractArchitectureGraph();
1359
- const summary = this.validator.validateAll();
1360
- const status = {
1361
- projectRoot: this.projectRoot,
1362
- entityCount: graph.nodes.filter((n) => n.type === "entity").length,
1363
- functionalityCount: graph.nodes.filter((n) => n.type === "functionality").length,
1364
- libraryCount: graph.nodes.filter((n) => n.type === "library").length,
1365
- subappCount: graph.nodes.filter((n) => n.type === "subapp").length,
1366
- purityValid: summary.valid,
1367
- purityErrors: summary.errors.length
1368
- };
1369
- const decorated = PreemptiveDocManager.decorateResponse("graph.getArchitecture", status);
1370
- return { jsonrpc: "2.0", id, result: decorated };
1371
- }
1372
- // 2. Interactive Graph Controls & Layout
1373
- case "graph.moveNode": {
1374
- const { nodeId, x, y } = params;
1375
- if (!nodeId || x === void 0 || y === void 0) throw new Error("nodeId, x, and y are required");
1376
- const res = this.astEngine.moveNode(nodeId, x, y);
1377
- this.notifyMutation("graph.moveNode", { nodeId, x, y });
1378
- const decorated = PreemptiveDocManager.decorateResponse("graph.moveNode", res);
1379
- return { jsonrpc: "2.0", id, result: decorated };
1380
- }
1381
- case "graph.moveMultipleNodes": {
1382
- const { positions } = params;
1383
- if (!positions) throw new Error("positions map is required");
1384
- const res = this.astEngine.moveMultipleNodes(positions);
1385
- this.notifyMutation("graph.moveMultipleNodes", { count: Object.keys(positions).length });
1386
- const decorated = PreemptiveDocManager.decorateResponse("graph.moveNode", res);
1387
- return { jsonrpc: "2.0", id, result: decorated };
1388
- }
1389
- case "graph.connectNodes": {
1390
- const { source, target, type } = params;
1391
- if (!source || !target) throw new Error("source and target node IDs are required");
1392
- const res = this.astEngine.connectNodes(source, target, type);
1393
- if (!res.success) {
1394
- return { jsonrpc: "2.0", id, error: { code: -32002, message: res.error || "Connection rejected by validation rule" } };
1395
- }
1396
- const graph = this.astEngine.extractArchitectureGraph();
1397
- this.notifyMutation("graph.connectNodes", { source, target, ...res });
1398
- const decorated = PreemptiveDocManager.decorateResponse("graph.connectNodes", { ...res, graph });
1399
- return { jsonrpc: "2.0", id, result: decorated };
1400
- }
1401
- case "graph.deleteEdge": {
1402
- const { edgeId } = params;
1403
- if (!edgeId) throw new Error("edgeId is required");
1404
- const res = this.astEngine.deleteEdge(edgeId);
1405
- const graph = this.astEngine.extractArchitectureGraph();
1406
- this.notifyMutation("graph.deleteEdge", { edgeId });
1407
- const decorated = PreemptiveDocManager.decorateResponse("graph.deleteEdge", { ...res, graph });
1408
- return { jsonrpc: "2.0", id, result: decorated };
1409
- }
1410
- case "graph.deleteNode": {
1411
- const { nodeId } = params;
1412
- if (!nodeId) throw new Error("nodeId is required");
1413
- const res = this.astEngine.deleteNode(nodeId);
1414
- const graph = this.astEngine.extractArchitectureGraph();
1415
- this.notifyMutation("graph.deleteNode", { nodeId });
1416
- const decorated = PreemptiveDocManager.decorateResponse("graph.deleteNode", { ...res, graph });
1417
- return { jsonrpc: "2.0", id, result: decorated };
1418
- }
1419
- case "graph.alignLayout": {
1420
- const { algorithm } = params;
1421
- const res = this.astEngine.alignLayout(algorithm);
1422
- const graph = this.astEngine.extractArchitectureGraph();
1423
- this.notifyMutation("graph.alignLayout", { algorithm: algorithm || "hierarchical" });
1424
- const decorated = PreemptiveDocManager.decorateResponse("graph.alignLayout", { ...res, graph });
1425
- return { jsonrpc: "2.0", id, result: decorated };
1426
- }
1427
- case "graph.undo": {
1428
- const res = this.astEngine.undo();
1429
- const graph = this.astEngine.extractArchitectureGraph();
1430
- this.notifyMutation("graph.undo", {});
1431
- const decorated = PreemptiveDocManager.decorateResponse("graph.undo", { ...res, graph });
1432
- return { jsonrpc: "2.0", id, result: decorated };
1433
- }
1434
- case "graph.redo": {
1435
- const res = this.astEngine.redo();
1436
- const graph = this.astEngine.extractArchitectureGraph();
1437
- this.notifyMutation("graph.redo", {});
1438
- const decorated = PreemptiveDocManager.decorateResponse("graph.redo", { ...res, graph });
1439
- return { jsonrpc: "2.0", id, result: decorated };
1440
- }
1441
- // 3. Scaffolding
1442
- case "entity.create":
1443
- case "graph.createEntity": {
1444
- const { name } = params;
1445
- if (!name) throw new Error("Entity name is required");
1446
- const res = this.astEngine.createEntity(name);
1447
- const graph = this.astEngine.extractArchitectureGraph();
1448
- this.notifyMutation("entity.create", { name, ...res });
1449
- const decorated = PreemptiveDocManager.decorateResponse("entity.create", { ...res, graph });
1450
- return { jsonrpc: "2.0", id, result: decorated };
1451
- }
1452
- case "functionality.create":
1453
- case "graph.createFunctionality": {
1454
- const { entityName, name } = params;
1455
- if (!entityName || !name) throw new Error("entityName and name are required");
1456
- const res = this.astEngine.createFunctionality(entityName, name);
1457
- const graph = this.astEngine.extractArchitectureGraph();
1458
- this.notifyMutation("functionality.create", { entityName, name, ...res });
1459
- const decorated = PreemptiveDocManager.decorateResponse("functionality.create", { ...res, graph });
1460
- return { jsonrpc: "2.0", id, result: decorated };
1461
- }
1462
- case "library.create":
1463
- case "graph.createLibrary": {
1464
- const { name } = params;
1465
- if (!name) throw new Error("Library name is required");
1466
- const res = this.astEngine.createLibrary(name);
1467
- const graph = this.astEngine.extractArchitectureGraph();
1468
- this.notifyMutation("library.create", { name, ...res });
1469
- const decorated = PreemptiveDocManager.decorateResponse("library.create", { ...res, graph });
1470
- return { jsonrpc: "2.0", id, result: decorated };
1471
- }
1472
- case "flow.addStep":
1473
- case "graph.addFlowStep": {
1474
- const { entityFilePath, flowName, stepFunctionName } = params;
1475
- const success = this.astEngine.addFlowStep(entityFilePath, flowName, stepFunctionName);
1476
- const graph = this.astEngine.extractArchitectureGraph();
1477
- this.notifyMutation("flow.addStep", { flowName, stepFunctionName, success });
1478
- const decorated = PreemptiveDocManager.decorateResponse("flow.addStep", { success, graph });
1479
- return { jsonrpc: "2.0", id, result: decorated };
1480
- }
1481
- case "library.listFunctions": {
1482
- const functions = this.astEngine.listGlobalLibraryFunctions();
1483
- return { jsonrpc: "2.0", id, result: { success: true, functions } };
1484
- }
1485
- case "orchestration.addStep": {
1486
- const { entityFilePath, orchestrationName, stepType, targetName, libName } = params;
1487
- const res = this.astEngine.addOrchestrationStep(entityFilePath, orchestrationName, stepType, targetName, libName);
1488
- const graph = this.astEngine.extractArchitectureGraph();
1489
- this.notifyMutation("orchestration.addStep", { orchestrationName, stepType, targetName, ...res });
1490
- return { jsonrpc: "2.0", id, result: { ...res, graph } };
1491
- }
1492
- // 4. Code Mutation & Robust File Reading
1493
- case "file.read": {
1494
- const { filePath } = params;
1495
- let abs = path6.isAbsolute(filePath) ? filePath : path6.resolve(this.projectRoot, filePath);
1496
- if (!fs7.existsSync(abs)) throw new Error(`File not found: ${filePath}`);
1497
- let content = "";
1498
- if (fs7.lstatSync(abs).isDirectory()) {
1499
- const base = path6.basename(abs);
1500
- const candidateTs = path6.join(abs, `${base}.ts`);
1501
- const candidateIndex = path6.join(abs, "index.ts");
1502
- if (fs7.existsSync(candidateTs)) {
1503
- abs = candidateTs;
1504
- content = fs7.readFileSync(candidateTs, "utf-8");
1505
- } else if (fs7.existsSync(candidateIndex)) {
1506
- abs = candidateIndex;
1507
- content = fs7.readFileSync(candidateIndex, "utf-8");
1508
- } else {
1509
- const files = fs7.readdirSync(abs);
1510
- content = `// Directory: ${base}
1511
- // Files in directory:
1512
- ` + files.map((f) => `// - ${f}`).join("\n");
1513
- }
1514
- } else {
1515
- content = fs7.readFileSync(abs, "utf-8");
1516
- }
1517
- const decorated = PreemptiveDocManager.decorateResponse("file.read", { filePath: abs, content });
1518
- return { jsonrpc: "2.0", id, result: decorated };
1519
- }
1520
- case "file.edit": {
1521
- const { filePath, newContent } = params;
1522
- const abs = path6.resolve(this.projectRoot, filePath);
1523
- fs7.writeFileSync(abs, newContent, "utf-8");
1524
- this.notifyMutation("file.edit", { filePath });
1525
- const decorated = PreemptiveDocManager.decorateResponse("file.edit", { success: true, filePath: abs });
1526
- return { jsonrpc: "2.0", id, result: decorated };
1527
- }
1528
- case "ui.generate": {
1529
- const { componentTree, componentName, targetFilePath } = params;
1530
- const code = VanJSCodeGenerator.generateCode(componentTree, componentName || "GeneratedView");
1531
- if (targetFilePath) {
1532
- const abs = path6.resolve(this.projectRoot, targetFilePath);
1533
- fs7.mkdirSync(path6.dirname(abs), { recursive: true });
1534
- fs7.writeFileSync(abs, code, "utf-8");
1535
- this.notifyMutation("ui.generate", { targetFilePath });
1536
- }
1537
- const decorated = PreemptiveDocManager.decorateResponse("ui.generate", { code, targetFilePath });
1538
- return { jsonrpc: "2.0", id, result: decorated };
1539
- }
1540
- // 5. Validation
1541
- case "validate.audit":
1542
- case "validate.runPurityAudit": {
1543
- const summary = this.validator.validateAll();
1544
- const decorated = PreemptiveDocManager.decorateResponse("validate.audit", summary);
1545
- return { jsonrpc: "2.0", id, result: decorated };
1546
- }
1547
- // 6. Sandboxed Testing
1548
- case "test.executeFunction": {
1549
- const result = await FunctionExecutor.execute(params);
1550
- this.notifyMutation("test.executeFunction", { filePath: params.filePath, success: result.success, durationMs: result.durationMs });
1551
- const decorated = PreemptiveDocManager.decorateResponse("test.executeFunction", result);
1552
- return { jsonrpc: "2.0", id, result: decorated };
1553
- }
1554
- // 7. Documentation
1555
- case "docs.endpoints": {
1556
- const all = PreemptiveDocManager.getAllEndpoints();
1557
- const decorated = PreemptiveDocManager.decorateResponse("docs.endpoints", all);
1558
- return { jsonrpc: "2.0", id, result: decorated };
1559
- }
1560
- default:
1561
- return {
1562
- jsonrpc: "2.0",
1563
- id,
1564
- error: { code: -32601, message: `Method '${method}' not found` }
1565
- };
1566
- }
1567
- } catch (err) {
1568
- return {
1569
- jsonrpc: "2.0",
1570
- id: req.id,
1571
- error: { code: -32e3, message: err?.message || String(err) }
1572
- };
1573
- }
1574
- }
1575
- notifyMutation(action, params) {
1576
- if (this.onMutationCallback) {
1577
- this.onMutationCallback({ action, params });
1578
- }
1579
- }
1580
- };
1581
-
1582
- // ../studio/src/server/StudioServer.ts
1583
- import * as http from "http";
1584
- import * as fs10 from "fs";
1585
- import * as path9 from "path";
1586
- import { WebSocketServer, WebSocket } from "ws";
1587
-
1588
- // ../studio/src/server/StaticFileServer.ts
1589
- import * as fs8 from "fs";
1590
- import * as path7 from "path";
1591
- var MIME_TYPES = {
1592
- ".js": "application/javascript; charset=utf-8",
1593
- ".css": "text/css; charset=utf-8",
1594
- ".html": "text/html; charset=utf-8",
1595
- ".json": "application/json; charset=utf-8",
1596
- ".svg": "image/svg+xml",
1597
- ".png": "image/png"
1598
- };
1599
- var StaticFileServer = class {
1600
- baseDirs;
1601
- constructor() {
1602
- const base = typeof __dirname !== "undefined" ? __dirname : process.cwd();
1603
- this.baseDirs = [
1604
- path7.join(base, "../ui"),
1605
- path7.join(base, "../../src/ui"),
1606
- path7.join(process.cwd(), "packages/studio/src/ui"),
1607
- path7.join(process.cwd(), "src/ui")
1608
- ];
1609
- }
1610
- serveFile(req, res, relativePath) {
1611
- const cleanPath = path7.normalize(relativePath.replace(/^\/ui\/?/, "")).replace(/^(\.\.[\/\\])+/, "");
1612
- for (const baseDir of this.baseDirs) {
1613
- const fullPath = path7.join(baseDir, cleanPath);
1614
- if (fs8.existsSync(fullPath) && fs8.statSync(fullPath).isFile()) {
1615
- const ext = path7.extname(fullPath).toLowerCase();
1616
- const mime = MIME_TYPES[ext] || "text/plain; charset=utf-8";
1617
- const content = fs8.readFileSync(fullPath);
1618
- res.writeHead(200, {
1619
- "Content-Type": mime,
1620
- "Cache-Control": "no-cache, no-store, must-revalidate",
1621
- "Content-Length": Buffer.byteLength(content)
1622
- });
1623
- res.end(content);
1624
- return true;
1625
- }
1626
- }
1627
- res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
1628
- res.end(`File not found: ${cleanPath}`);
1629
- return false;
1630
- }
1631
- };
1632
-
1633
- // ../studio/src/server/HttpRouteHandler.ts
1634
- import * as fs9 from "fs";
1635
- import * as path8 from "path";
1636
- var ROUTE_MAP = {
1637
- "/api/v1/project/create": "project.create",
1638
- "/api/v1/project/load": "project.load",
1639
- "/api/v1/project/graph": "graph.getArchitecture",
1640
- "/api/v1/project/status": "project.getStatus",
1641
- "/api/v1/graph/moveNode": "graph.moveNode",
1642
- "/api/v1/graph/moveMultipleNodes": "graph.moveMultipleNodes",
1643
- "/api/v1/graph/connectNodes": "graph.connectNodes",
1644
- "/api/v1/graph/deleteEdge": "graph.deleteEdge",
1645
- "/api/v1/graph/deleteNode": "graph.deleteNode",
1646
- "/api/v1/graph/alignLayout": "graph.alignLayout",
1647
- "/api/v1/graph/undo": "graph.undo",
1648
- "/api/v1/graph/redo": "graph.redo",
1649
- "/api/v1/entity/create": "entity.create",
1650
- "/api/v1/functionality/create": "functionality.create",
1651
- "/api/v1/library/create": "library.create",
1652
- "/api/v1/flow/addStep": "flow.addStep",
1653
- "/api/v1/file/read": "file.read",
1654
- "/api/v1/file/edit": "file.edit",
1655
- "/api/v1/ui/generate": "ui.generate",
1656
- "/api/v1/validate/audit": "validate.audit",
1657
- "/api/v1/test/execute": "test.executeFunction",
1658
- "/api/v1/docs/endpoints": "docs.endpoints"
1659
- };
1660
- var HttpRouteHandler = class {
1661
- static async handleApiRequest(req, res, url, router, onGraphUpdate) {
1662
- let body = "";
1663
- req.on("data", (chunk) => {
1664
- body += chunk;
1665
- });
1666
- req.on("end", async () => {
1667
- try {
1668
- let params = {};
1669
- if (body.trim()) {
1670
- try {
1671
- params = JSON.parse(body);
1672
- } catch (e) {
1673
- }
1674
- }
1675
- const method = ROUTE_MAP[url] || "graph.getArchitecture";
1676
- const rpcRes = await router.handle({
1677
- jsonrpc: "2.0",
1678
- id: "http-req-" + Date.now(),
1679
- method,
1680
- params
1681
- });
1682
- if (rpcRes.error) {
1683
- res.writeHead(400, { "Content-Type": "application/json" });
1684
- res.end(JSON.stringify(rpcRes.error, null, 2));
1685
- } else {
1686
- res.writeHead(200, { "Content-Type": "application/json" });
1687
- res.end(JSON.stringify(rpcRes.result, null, 2));
1688
- onGraphUpdate();
1689
- }
1690
- } catch (err) {
1691
- res.writeHead(500, { "Content-Type": "application/json" });
1692
- res.end(JSON.stringify({ error: err.message || String(err) }));
1693
- }
1694
- });
1695
- }
1696
- static getStudioHtml() {
1697
- const base = typeof __dirname !== "undefined" ? __dirname : process.cwd();
1698
- const candidates = [
1699
- path8.join(base, "studio.html"),
1700
- path8.join(base, "../../src/server/studio.html"),
1701
- path8.join(process.cwd(), "packages/studio/src/server/studio.html"),
1702
- path8.join(process.cwd(), "src/server/studio.html")
1703
- ];
1704
- for (const candidate of candidates) {
1705
- if (fs9.existsSync(candidate)) {
1706
- return fs9.readFileSync(candidate, "utf8");
1707
- }
1708
- }
1709
- return `<!DOCTYPE html><html><body><h1>Krnl Studio Error: studio.html not found.</h1></body></html>`;
1710
- }
1711
- };
1712
-
1713
- // ../studio/src/server/StudioServer.ts
1714
- var StudioServer = class {
1715
- port;
1716
- projectRoot;
1717
- httpServer;
1718
- wss;
1719
- router;
1720
- watcher;
1721
- astEngine;
1722
- staticServer;
1723
- constructor(options = {}) {
1724
- this.port = options.port || 8080;
1725
- const initialRoot = path9.resolve(options.projectRoot || process.cwd());
1726
- const unifiedPath = path9.join(initialRoot, "examples/unified-workspace");
1727
- this.projectRoot = !fs10.existsSync(path9.join(initialRoot, "src/entities")) && fs10.existsSync(unifiedPath) ? unifiedPath : initialRoot;
1728
- this.astEngine = new AstMutationEngine(this.projectRoot);
1729
- this.watcher = new StudioFileWatcher(this.projectRoot);
1730
- this.staticServer = new StaticFileServer();
1731
- this.router = new JsonRpcRouter(this.projectRoot, (mutation) => {
1732
- this.broadcastAgentActivity(mutation);
1733
- });
1734
- this.httpServer = http.createServer((req, res) => this.handleHttpRequest(req, res));
1735
- this.wss = new WebSocketServer({ server: this.httpServer, path: "/studio/ws", perMessageDeflate: false });
1736
- this.wss.on("error", (err) => console.warn("WSS Error:", err));
1737
- this.initWebSocket();
1738
- this.initFileWatcher();
1739
- }
1740
- initWebSocket() {
1741
- this.wss.on("connection", (ws) => {
1742
- ws.on("error", (err) => console.warn("WS Client Error:", err?.message));
1743
- const graph = this.astEngine.extractArchitectureGraph();
1744
- ws.send(JSON.stringify({ jsonrpc: "2.0", method: "graph.init", params: { ...graph, projectRoot: this.projectRoot } }));
1745
- ws.on("message", async (data) => {
1746
- try {
1747
- const req = JSON.parse(data.toString());
1748
- if (req.method === "project.openDirectory" && req.params?.directory) {
1749
- const targetPath = path9.resolve(req.params.directory);
1750
- if (fs10.existsSync(targetPath)) {
1751
- this.projectRoot = targetPath;
1752
- this.astEngine = new AstMutationEngine(this.projectRoot);
1753
- this.router.setProjectRoot(this.projectRoot);
1754
- this.watcher.updateRoot(this.projectRoot);
1755
- ws.send(JSON.stringify({ jsonrpc: "2.0", id: req.id, result: { success: true, projectRoot: this.projectRoot } }));
1756
- this.broadcastGraphUpdate();
1757
- } else {
1758
- ws.send(JSON.stringify({ jsonrpc: "2.0", id: req.id, error: { code: -32001, message: "Directory does not exist: " + targetPath } }));
1759
- }
1760
- return;
1761
- }
1762
- const res = await this.router.handle(req);
1763
- if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify(res));
1764
- if (req.method && (req.method.startsWith("graph.") || req.method.startsWith("entity.") || req.method.startsWith("functionality.") || req.method.startsWith("library."))) {
1765
- this.broadcastGraphUpdate();
1766
- }
1767
- } catch (e) {
1768
- if (ws.readyState === WebSocket.OPEN) {
1769
- ws.send(JSON.stringify({ jsonrpc: "2.0", error: { code: -32700, message: "Parse error: " + (e.message || String(e)) } }));
1770
- }
1771
- }
1772
- });
1773
- });
1774
- }
1775
- initFileWatcher() {
1776
- this.watcher.start();
1777
- this.watcher.subscribe(() => this.broadcastGraphUpdate());
1778
- }
1779
- broadcastGraphUpdate() {
1780
- try {
1781
- const graph = this.astEngine.extractArchitectureGraph();
1782
- const payload = JSON.stringify({ jsonrpc: "2.0", method: "graph.updated", params: { ...graph, projectRoot: this.projectRoot } });
1783
- for (const client of this.wss.clients) {
1784
- if (client.readyState === WebSocket.OPEN) client.send(payload);
1785
- }
1786
- } catch (e) {
1787
- }
1788
- }
1789
- broadcastAgentActivity(mutation) {
1790
- try {
1791
- const payload = JSON.stringify({ jsonrpc: "2.0", method: "agent.activity", params: { action: mutation.action, params: mutation.params, timestamp: Date.now() } });
1792
- for (const client of this.wss.clients) {
1793
- if (client.readyState === WebSocket.OPEN) client.send(payload);
1794
- }
1795
- } catch (e) {
1796
- }
1797
- }
1798
- async handleHttpRequest(req, res) {
1799
- res.setHeader("Access-Control-Allow-Origin", "*");
1800
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
1801
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
1802
- if (req.method === "OPTIONS") {
1803
- res.writeHead(204);
1804
- res.end();
1805
- return;
1806
- }
1807
- const url = req.url?.split("?")[0] || "/";
1808
- if (url === "/api/graph") {
1809
- const graph = this.astEngine.extractArchitectureGraph();
1810
- res.writeHead(200, { "Content-Type": "application/json" });
1811
- res.end(JSON.stringify({ status: "success", payload: graph, projectRoot: this.projectRoot }, null, 2));
1812
- return;
1813
- }
1814
- if (url.startsWith("/ui/")) {
1815
- this.staticServer.serveFile(req, res, url);
1816
- return;
1817
- }
1818
- if (url.startsWith("/api/v1/")) {
1819
- await HttpRouteHandler.handleApiRequest(req, res, url, this.router, () => this.broadcastGraphUpdate());
1820
- return;
1821
- }
1822
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1823
- res.end(HttpRouteHandler.getStudioHtml());
1824
- }
1825
- async start() {
1826
- return new Promise((resolve6) => {
1827
- this.httpServer.listen(this.port, () => {
1828
- console.log(`
1829
- \u{1F680} [Krnl Studio] Omni Canvas IDE running at: http://localhost:${this.port}`);
1830
- console.log(`\u{1F4E1} [Krnl Studio] Active Project Root: ${this.projectRoot}`);
1831
- console.log(`\u{1F4E1} [Krnl Studio] REST API Suite available at: http://localhost:${this.port}/api/v1/*`);
1832
- console.log(`\u{1F4E1} [Krnl Studio] WebSocket JSON-RPC protocol active on /studio/ws
1833
- `);
1834
- resolve6();
1835
- });
1836
- });
1837
- }
1838
- async stop() {
1839
- this.watcher.stop();
1840
- return new Promise((resolve6) => {
1841
- this.wss.close(() => {
1842
- this.httpServer.close(() => resolve6());
1843
- });
1844
- });
1845
- }
1846
- };
1847
-
1848
- // ../studio/src/client/plugins/VanJSRenderPlugin.ts
1849
- import van from "vanjs-core";
1850
- var { div, span, button } = van.tags;
1851
-
1852
- // src/bin/krnl.ts
11
+ import * as fs from "fs";
1853
12
  var args = process.argv.slice(2);
1854
13
  var command = args[0] || "help";
1855
14
  function detectAppEntrypoint(projectRoot) {
1856
- const files = fs11.readdirSync(projectRoot);
15
+ const files = fs.readdirSync(projectRoot);
1857
16
  for (const f of files) {
1858
17
  if (f.endsWith(".ts") && !f.endsWith(".d.ts") && f !== "tsup.config.ts") {
1859
- const full = path10.join(projectRoot, f);
18
+ const full = path.join(projectRoot, f);
1860
19
  try {
1861
- const text = fs11.readFileSync(full, "utf8");
20
+ const text = fs.readFileSync(full, "utf8");
1862
21
  if (text.includes("defineApp") || text.includes("@dinilmusick/krnl-core")) {
1863
22
  return f;
1864
23
  }
@@ -1871,7 +30,7 @@ function detectAppEntrypoint(projectRoot) {
1871
30
  async function main() {
1872
31
  switch (command) {
1873
32
  case "sync": {
1874
- const targetDir = args[1] && !args[1].startsWith("-") ? path10.resolve(process.cwd(), args[1]) : process.cwd();
33
+ const targetDir = args[1] && !args[1].startsWith("-") ? path.resolve(process.cwd(), args[1]) : process.cwd();
1875
34
  console.log("\u{1F4E6} [Krnl Sync] Reconciling package.json from all manifest.json files...");
1876
35
  const res = KrnlPackageReconciler.reconcile(targetDir, true);
1877
36
  console.log(`\u2705 Reconciled dependencies from ${res.totalManifests} manifest.json file(s).`);
@@ -1881,7 +40,7 @@ async function main() {
1881
40
  break;
1882
41
  }
1883
42
  case "validate": {
1884
- const targetDir = args[1] && !args[1].startsWith("-") ? path10.resolve(process.cwd(), args[1]) : process.cwd();
43
+ const targetDir = args[1] && !args[1].startsWith("-") ? path.resolve(process.cwd(), args[1]) : process.cwd();
1885
44
  const valid = await runValidate(targetDir);
1886
45
  process.exit(valid ? 0 : 1);
1887
46
  break;
@@ -1897,7 +56,7 @@ async function main() {
1897
56
  generateMagneticDeclarations(process.cwd());
1898
57
  if (args.includes("--watch") || args.includes("-w")) {
1899
58
  console.log("[Krnl Watch] Continuous watcher enabled.");
1900
- fs11.watch(process.cwd(), { recursive: true }, (evt, filename) => {
59
+ fs.watch(process.cwd(), { recursive: true }, (evt, filename) => {
1901
60
  if (filename && (filename.endsWith(".ts") || filename.endsWith(".js")) && !filename.includes("krnl-magnetic.d.ts")) {
1902
61
  try {
1903
62
  generateMagneticDeclarations(process.cwd());
@@ -1957,27 +116,23 @@ async function main() {
1957
116
  } else if (isAll) {
1958
117
  console.log(`\u26A1 [Krnl Dev] Initializing combined multi-entity workspace on port ${port}...`);
1959
118
  } else {
1960
- console.log(`\u26A1 [Krnl Dev] Initializing Krnl Studio visual workspace on port ${port}...`);
119
+ console.log(`\u26A1 [Krnl Dev] Initializing Krnl backend service workspace on port ${port}...`);
1961
120
  }
1962
- const server = new StudioServer({
1963
- port,
1964
- projectRoot
1965
- });
1966
- generateMagneticDeclarations(server.projectRoot || projectRoot);
1967
- await server.start();
121
+ generateMagneticDeclarations(projectRoot);
122
+ console.log(`\u26A1 [Krnl Dev] Development environment ready.`);
1968
123
  break;
1969
124
  }
1970
125
  case "help":
1971
126
  default: {
1972
127
  console.log(`
1973
128
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
1974
- \u2551 Krnl Framework CLI \u2551
129
+ \u2551 Krnl Backend Service Framework CLI \u2551
1975
130
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
1976
131
 
1977
132
  Usage: krnl <command> [options]
1978
133
 
1979
134
  Commands:
1980
- dev Start Krnl Studio dev server & boot <app_name>.ts entrypoint
135
+ dev Start Krnl service dev server & boot service entrypoint
1981
136
  build Validate and build project for production
1982
137
  validate Run deep AST & 4-layer function purity validation
1983
138
  sync Reconcile package.json from all co-located manifest.json files
@@ -1992,7 +147,7 @@ Commands:
1992
147
  Options:
1993
148
  --entity <name> Target a specific entity app variant to run or build
1994
149
  --all Run or build all entities as a combined multi-entity build
1995
- --port <number> Specify port for Krnl Studio dev server (default: 8080)
150
+ --port <number> Specify port for Krnl service dev server (default: 8080)
1996
151
  --watch, -w Enable continuous file watcher (for watch command)
1997
152
  --help, -h Show this help message
1998
153
  `);