@kosdev-code/kos-ui-cli 2.1.38 → 3.0.0

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,19 +1,1425 @@
1
- // generators/model/companion.mjs
2
- import { actionFactory } from "../../utils/action-factory.mjs";
3
- import { execute } from "../../utils/exec.mjs";
4
- import {
5
- getAllModels,
6
- getModelProjectsWithFallback,
7
- getProjectDetails,
8
- } from "../../utils/nx-context.mjs";
9
- import {
10
- COMPANION_PROMPTS,
11
- DEFAULT_PROMPTS,
12
- MODEL_PROMPTS,
13
- } from "../../utils/prompts.mjs";
14
- import { required } from "../../utils/validators.mjs";
15
-
16
- export const metadata = {
1
+ // ../kos-codegen-core/src/lib/codegen-filesystem.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ var TrackingFileSystem = class {
5
+ inner;
6
+ _writtenPaths = [];
7
+ constructor(inner) {
8
+ this.inner = inner;
9
+ }
10
+ get root() {
11
+ return this.inner.root;
12
+ }
13
+ get writtenPaths() {
14
+ return [...this._writtenPaths];
15
+ }
16
+ read(filePath) {
17
+ return this.inner.read(filePath);
18
+ }
19
+ write(filePath, content) {
20
+ this.inner.write(filePath, content);
21
+ this._writtenPaths.push(
22
+ path.isAbsolute(filePath) ? filePath : path.join(this.inner.root, filePath)
23
+ );
24
+ }
25
+ exists(filePath) {
26
+ return this.inner.exists(filePath);
27
+ }
28
+ delete(filePath) {
29
+ this.inner.delete(filePath);
30
+ }
31
+ listFiles(dirPath) {
32
+ return this.inner.listFiles(dirPath);
33
+ }
34
+ };
35
+ var DirectFileSystem = class {
36
+ root;
37
+ constructor(workspaceRoot) {
38
+ this.root = path.resolve(workspaceRoot);
39
+ }
40
+ read(filePath) {
41
+ const abs = this.resolve(filePath);
42
+ try {
43
+ return fs.readFileSync(abs, "utf-8");
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+ write(filePath, content) {
49
+ const abs = this.resolve(filePath);
50
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
51
+ fs.writeFileSync(abs, content, "utf-8");
52
+ }
53
+ exists(filePath) {
54
+ return fs.existsSync(this.resolve(filePath));
55
+ }
56
+ delete(filePath) {
57
+ const abs = this.resolve(filePath);
58
+ try {
59
+ fs.unlinkSync(abs);
60
+ } catch {
61
+ }
62
+ }
63
+ listFiles(dirPath) {
64
+ const abs = this.resolve(dirPath);
65
+ if (!fs.existsSync(abs)) {
66
+ return [];
67
+ }
68
+ return this.walkDir(abs).map((file) => path.relative(this.root, file));
69
+ }
70
+ resolve(filePath) {
71
+ if (path.isAbsolute(filePath)) {
72
+ return filePath;
73
+ }
74
+ return path.join(this.root, filePath);
75
+ }
76
+ walkDir(dir) {
77
+ const results = [];
78
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
79
+ for (const entry of entries) {
80
+ const full = path.join(dir, entry.name);
81
+ if (entry.isDirectory()) {
82
+ results.push(...this.walkDir(full));
83
+ } else {
84
+ results.push(full);
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+ };
90
+
91
+ // ../kos-codegen-core/src/lib/generate-files.ts
92
+ import * as fs2 from "fs";
93
+ import * as path2 from "path";
94
+ import * as ejs from "ejs";
95
+
96
+ // ../kos-codegen-core/src/lib/logger.ts
97
+ var noopLogger = {
98
+ debug: () => {
99
+ },
100
+ info: () => {
101
+ },
102
+ warn: () => {
103
+ },
104
+ error: () => {
105
+ }
106
+ };
107
+ var activeLogger = noopLogger;
108
+ function getCodegenLogger() {
109
+ return activeLogger;
110
+ }
111
+
112
+ // ../kos-codegen-core/src/lib/generate-files.ts
113
+ function generateFilesFromTemplates(codegenFs, srcFolder, destFolder, substitutions) {
114
+ const logger = getCodegenLogger();
115
+ const templateFiles = walkTemplateDir(srcFolder);
116
+ for (const templateFile of templateFiles) {
117
+ const relPath = path2.relative(srcFolder, templateFile);
118
+ let destRelPath = interpolateFilename(relPath, substitutions);
119
+ if (destRelPath.endsWith(".template")) {
120
+ destRelPath = destRelPath.slice(0, -".template".length);
121
+ }
122
+ const destPath = path2.join(destFolder, destRelPath);
123
+ const rawContent = fs2.readFileSync(templateFile, "utf-8");
124
+ const rendered = ejs.render(rawContent, substitutions, {
125
+ filename: templateFile
126
+ // for EJS error messages and includes
127
+ });
128
+ logger.debug(`Generating ${destPath}`);
129
+ codegenFs.write(destPath, rendered);
130
+ }
131
+ }
132
+ function interpolateFilename(filePath, substitutions) {
133
+ return filePath.replace(/__([^_]+)__/g, (match, key) => {
134
+ if (key in substitutions) {
135
+ return String(substitutions[key]);
136
+ }
137
+ return match;
138
+ });
139
+ }
140
+ function walkTemplateDir(dir) {
141
+ const results = [];
142
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
143
+ for (const entry of entries) {
144
+ const full = path2.join(dir, entry.name);
145
+ if (entry.isDirectory()) {
146
+ results.push(...walkTemplateDir(full));
147
+ } else {
148
+ results.push(full);
149
+ }
150
+ }
151
+ return results;
152
+ }
153
+
154
+ // ../kos-codegen-core/src/lib/project-discovery.ts
155
+ import * as fs3 from "fs";
156
+ import * as path3 from "path";
157
+ import fg from "fast-glob";
158
+ function discoverProjects(workspaceRoot) {
159
+ const logger = getCodegenLogger();
160
+ const projects = /* @__PURE__ */ new Map();
161
+ const projectJsonPaths = fg.sync("**/project.json", {
162
+ cwd: workspaceRoot,
163
+ ignore: ["**/node_modules/**", "**/dist/**", "**/.git/**"],
164
+ absolute: false
165
+ });
166
+ for (const relPath of projectJsonPaths) {
167
+ const absPath = path3.join(workspaceRoot, relPath);
168
+ try {
169
+ const raw = fs3.readFileSync(absPath, "utf-8");
170
+ const json = JSON.parse(raw);
171
+ const projectRoot = path3.dirname(relPath);
172
+ const name = json.name ?? path3.basename(projectRoot);
173
+ const config = {
174
+ name,
175
+ root: projectRoot,
176
+ sourceRoot: json.sourceRoot ?? path3.join(projectRoot, "src"),
177
+ projectType: json.projectType,
178
+ targets: json.targets,
179
+ tags: json.tags
180
+ };
181
+ projects.set(name, config);
182
+ logger.debug(`Discovered project: ${name} at ${projectRoot}`);
183
+ } catch (err) {
184
+ logger.warn(`Failed to parse ${absPath}: ${err}`);
185
+ }
186
+ }
187
+ logger.info(`Discovered ${projects.size} projects`);
188
+ return projects;
189
+ }
190
+ function findProjectByName(workspaceRoot, projectName, projects) {
191
+ const map = projects ?? discoverProjects(workspaceRoot);
192
+ return map.get(projectName);
193
+ }
194
+ function findProjectForPath(workspaceRoot, filePath) {
195
+ const resolved = path3.resolve(workspaceRoot);
196
+ let dir = path3.dirname(path3.resolve(filePath));
197
+ while (dir.startsWith(resolved) && dir !== resolved) {
198
+ const projectJsonPath = path3.join(dir, "project.json");
199
+ if (fs3.existsSync(projectJsonPath)) {
200
+ try {
201
+ const raw = fs3.readFileSync(projectJsonPath, "utf-8");
202
+ const json = JSON.parse(raw);
203
+ const projectRoot = path3.relative(resolved, dir);
204
+ const name = json.name ?? path3.basename(dir);
205
+ return {
206
+ name,
207
+ root: projectRoot,
208
+ sourceRoot: json.sourceRoot ?? path3.join(projectRoot, "src"),
209
+ projectType: json.projectType,
210
+ targets: json.targets,
211
+ tags: json.tags
212
+ };
213
+ } catch {
214
+ return void 0;
215
+ }
216
+ }
217
+ dir = path3.dirname(dir);
218
+ }
219
+ return void 0;
220
+ }
221
+
222
+ // ../kos-codegen-core/src/lib/json-utils.ts
223
+ function readJson(codegenFs, filePath) {
224
+ const content = codegenFs.read(filePath);
225
+ if (content === null) {
226
+ throw new Error(`File not found: ${filePath}`);
227
+ }
228
+ return JSON.parse(content);
229
+ }
230
+ function writeJson(codegenFs, filePath, value) {
231
+ codegenFs.write(filePath, JSON.stringify(value, null, 2) + "\n");
232
+ }
233
+ function updateJson(codegenFs, filePath, updater) {
234
+ const current = readJson(codegenFs, filePath);
235
+ const updated = updater(current);
236
+ writeJson(codegenFs, filePath, updated);
237
+ }
238
+
239
+ // ../kos-codegen-core/src/lib/format-files.ts
240
+ import * as fs4 from "fs";
241
+ import * as path4 from "path";
242
+ import prettier from "prettier";
243
+ var FORMATTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
244
+ ".ts",
245
+ ".tsx",
246
+ ".js",
247
+ ".jsx",
248
+ ".json",
249
+ ".css",
250
+ ".scss",
251
+ ".md",
252
+ ".yaml",
253
+ ".yml",
254
+ ".html"
255
+ ]);
256
+ async function formatFiles(workspaceRoot, filePaths) {
257
+ const logger = getCodegenLogger();
258
+ for (const filePath of filePaths) {
259
+ const ext = path4.extname(filePath);
260
+ if (!FORMATTABLE_EXTENSIONS.has(ext)) {
261
+ continue;
262
+ }
263
+ try {
264
+ const content = fs4.readFileSync(filePath, "utf-8");
265
+ const options = await prettier.resolveConfig(filePath, {
266
+ editorconfig: true
267
+ });
268
+ const formatted = await prettier.format(content, {
269
+ ...options,
270
+ filepath: filePath
271
+ });
272
+ fs4.writeFileSync(filePath, formatted, "utf-8");
273
+ logger.debug(`Formatted ${path4.relative(workspaceRoot, filePath)}`);
274
+ } catch (err) {
275
+ logger.warn(`Failed to format ${filePath}: ${err}`);
276
+ }
277
+ }
278
+ }
279
+
280
+ // ../kos-codegen-core/src/lib/name-utils.ts
281
+ function dashCase(input) {
282
+ return input.replace(/\s+/g, "-").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
283
+ }
284
+ function camelCase(input) {
285
+ if (input.length === 0)
286
+ return "";
287
+ const words = input.split(/-|\s+/);
288
+ if (words.length > 0 && words[0].length > 0) {
289
+ words[0] = words[0].charAt(0).toLowerCase() + words[0].slice(1);
290
+ }
291
+ for (let i = 1; i < words.length; i++) {
292
+ words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
293
+ }
294
+ return words.join("");
295
+ }
296
+ function pascalCase(input) {
297
+ if (input.length === 0)
298
+ return "";
299
+ const cc = camelCase(input);
300
+ return cc[0].toUpperCase() + cc.slice(1);
301
+ }
302
+ function properCase(input) {
303
+ const words = input.toLowerCase().replaceAll("-", " ").split(" ").filter(Boolean);
304
+ for (let i = 0; i < words.length; i++) {
305
+ words[i] = words[i][0].toUpperCase() + words[i].slice(1);
306
+ }
307
+ return words.join("");
308
+ }
309
+ function constantCase(input) {
310
+ if (input.length === 0)
311
+ return "";
312
+ return input.toUpperCase().split(/[\s-]+/).filter(Boolean).join("_");
313
+ }
314
+
315
+ // ../kos-codegen-core/src/lib/normalize-values.ts
316
+ var normalizeValue = (optionsName, value) => ({
317
+ [`${camelCase(optionsName)}CamelCase`]: camelCase(value),
318
+ [`${camelCase(optionsName)}ConstantCase`]: constantCase(value),
319
+ [`${camelCase(optionsName)}DashCase`]: dashCase(value),
320
+ [`${camelCase(optionsName)}PascalCase`]: pascalCase(value),
321
+ [`${camelCase(optionsName)}ProperCase`]: properCase(value),
322
+ [`${camelCase(optionsName)}LowerCase`]: value.toLowerCase(),
323
+ [`${optionsName}`]: value
324
+ });
325
+ var normalizeAllValues = (options) => {
326
+ let normalizedValues = {};
327
+ for (const key in options) {
328
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
329
+ const element = options[key];
330
+ const newOptions = typeof element !== "string" || element === "" ? { [key]: element } : normalizeValue(key, element);
331
+ normalizedValues = {
332
+ ...normalizedValues,
333
+ ...newOptions
334
+ };
335
+ }
336
+ }
337
+ return normalizedValues;
338
+ };
339
+
340
+ // ../kos-codegen-core/src/lib/kos-config.ts
341
+ import * as path5 from "path";
342
+ function getCurrentDirectoryName(cwd) {
343
+ return cwd.split("/").pop();
344
+ }
345
+ function getProject(codegenFs, cwd) {
346
+ return findProjectForPath(codegenFs.root, cwd);
347
+ }
348
+ function getKosProjectConfiguration(codegenFs, projectName, projects) {
349
+ const project = findProjectByName(codegenFs.root, projectName, projects);
350
+ if (!project)
351
+ return void 0;
352
+ const configPath = path5.join(project.root, ".kos.json");
353
+ if (!codegenFs.exists(configPath)) {
354
+ const defaultConfig = {
355
+ name: `${dashCase(projectName)}-model`,
356
+ type: "kos.model",
357
+ version: "0.1.0",
358
+ models: {},
359
+ generator: { defaults: { model: { folder: "" } } }
360
+ };
361
+ codegenFs.write(configPath, JSON.stringify(defaultConfig, null, 2));
362
+ }
363
+ const content = codegenFs.read(configPath);
364
+ return content ? JSON.parse(content) : void 0;
365
+ }
366
+ function addKosModelConfiguration(params) {
367
+ const logger = getCodegenLogger();
368
+ const kosConfigPath = path5.join(params.projectRoot, ".kos.json");
369
+ if (!params.codegenFs.exists(kosConfigPath)) {
370
+ logger.info(`Creating .kos.json in ${params.projectRoot}`);
371
+ const defaultConfig = {
372
+ name: params.projectName,
373
+ type: "kos.model",
374
+ version: "0.1.0",
375
+ models: {},
376
+ generator: { defaults: { model: { folder: "" } } }
377
+ };
378
+ params.codegenFs.write(
379
+ kosConfigPath,
380
+ JSON.stringify(defaultConfig, null, 2) + "\n"
381
+ );
382
+ }
383
+ updateJson(params.codegenFs, kosConfigPath, (json) => {
384
+ json.models = {
385
+ ...json.models,
386
+ [params.modelName]: {
387
+ name: params.modelName,
388
+ type: `${params.modelName}-model`,
389
+ singleton: !!params.singleton,
390
+ container: !!params.container
391
+ }
392
+ };
393
+ return json;
394
+ });
395
+ }
396
+
397
+ // ../kos-codegen-core/src/lib/template-resolver.ts
398
+ import * as path6 from "path";
399
+ import * as fs5 from "fs";
400
+ function findPackageRoot() {
401
+ if (process.env.KOS_TEMPLATE_BASE_DIR) {
402
+ return process.env.KOS_TEMPLATE_BASE_DIR;
403
+ }
404
+ let dir = __dirname;
405
+ while (dir !== path6.dirname(dir)) {
406
+ const pkgPath = path6.join(dir, "package.json");
407
+ if (fs5.existsSync(pkgPath)) {
408
+ try {
409
+ const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
410
+ if (pkg.name === "@kosdev-code/kos-codegen-core") {
411
+ return dir;
412
+ }
413
+ } catch {
414
+ }
415
+ }
416
+ dir = path6.dirname(dir);
417
+ }
418
+ return path6.resolve(__dirname, "..", "..");
419
+ }
420
+ function getTemplateDir(generatorName) {
421
+ return path6.join(findPackageRoot(), "templates", generatorName);
422
+ }
423
+
424
+ // ../kos-codegen-core/src/lib/generators/normalize-options.ts
425
+ import * as path7 from "path";
426
+ function normalizeOptions(codegenFs, options, projects) {
427
+ const toNormalize = {
428
+ name: options.name
429
+ };
430
+ if (options.modelName) {
431
+ toNormalize.modelName = options.modelName;
432
+ }
433
+ if (options.companionModel) {
434
+ toNormalize.companionModel = options.companionModel;
435
+ }
436
+ const normalizedValues = normalizeAllValues(toNormalize);
437
+ const modelProject = options.modelProject;
438
+ const registrationProject = options.registrationProject || "";
439
+ const useModelProject = modelProject !== "__NONE__";
440
+ let importPath = "";
441
+ if (useModelProject) {
442
+ const modelProjectConfig = findProjectByName(
443
+ codegenFs.root,
444
+ modelProject,
445
+ projects
446
+ );
447
+ if (modelProjectConfig) {
448
+ const pkgJsonPath = path7.join(modelProjectConfig.root, "package.json");
449
+ try {
450
+ const pkgJson = readJson(codegenFs, pkgJsonPath);
451
+ importPath = pkgJson.name || "";
452
+ } catch {
453
+ importPath = "";
454
+ }
455
+ }
456
+ }
457
+ const booleanDefaults = {
458
+ companion: false,
459
+ skipRegistration: false
460
+ };
461
+ return {
462
+ ...booleanDefaults,
463
+ ...options,
464
+ ...normalizedValues,
465
+ modelProject,
466
+ importPath,
467
+ registrationProject,
468
+ template: ""
469
+ };
470
+ }
471
+
472
+ // ../kos-codegen-core/src/lib/generators/update-model-index.ts
473
+ import * as ts from "typescript";
474
+ function updateModelIndex(codegenFs, indexPath, modelPath) {
475
+ const logger = getCodegenLogger();
476
+ if (!indexPath)
477
+ return;
478
+ const content = codegenFs.read(indexPath);
479
+ if (content === null) {
480
+ logger.warn(`Index file not found: ${indexPath}`);
481
+ return;
482
+ }
483
+ logger.info(`Updating ${indexPath} \u2014 adding export for ${modelPath}`);
484
+ const sourceFile = ts.createSourceFile(
485
+ indexPath,
486
+ content,
487
+ ts.ScriptTarget.Latest,
488
+ true
489
+ );
490
+ const exportDeclaration = ts.factory.createExportDeclaration(
491
+ void 0,
492
+ false,
493
+ void 0,
494
+ ts.factory.createStringLiteral(`./${modelPath}`)
495
+ );
496
+ const updatedSourceFile = ts.factory.updateSourceFile(sourceFile, [
497
+ ...sourceFile.statements,
498
+ exportDeclaration
499
+ ]);
500
+ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
501
+ const newContents = printer.printFile(updatedSourceFile);
502
+ codegenFs.write(indexPath, newContents);
503
+ }
504
+
505
+ // ../kos-codegen-core/src/lib/generators/generate-container-model.ts
506
+ import * as path8 from "path";
507
+ function generateContainerModel(codegenFs, templateDir, options, cwd, projects) {
508
+ const logger = getCodegenLogger();
509
+ const currentProject = getProject(codegenFs, cwd);
510
+ const modelProjectName = options.modelProject || currentProject?.name;
511
+ if (!modelProjectName) {
512
+ throw new Error(
513
+ "No model project found. Please specify a model project with --modelProject."
514
+ );
515
+ }
516
+ const modelName = options.modelName || getCurrentDirectoryName(cwd);
517
+ if (!modelName) {
518
+ throw new Error(
519
+ "No model name found. Please specify a model name with --name."
520
+ );
521
+ }
522
+ options.modelName = modelName;
523
+ options.name = `${modelName}-container`;
524
+ const normalized = normalizeOptions(codegenFs, options, projects);
525
+ const projectConfig = findProjectByName(
526
+ codegenFs.root,
527
+ normalized.modelProject,
528
+ projects
529
+ );
530
+ if (!projectConfig) {
531
+ throw new Error(`Model project '${normalized.modelProject}' not found`);
532
+ }
533
+ addKosModelConfiguration({
534
+ codegenFs,
535
+ modelName: normalized.nameDashCase,
536
+ projectName: projectConfig.name,
537
+ projectRoot: projectConfig.root,
538
+ singleton: !!options.singleton,
539
+ container: true
540
+ });
541
+ const kosConfig = getKosProjectConfiguration(
542
+ codegenFs,
543
+ projectConfig.name,
544
+ projects
545
+ );
546
+ const modelLocation = kosConfig?.generator?.defaults?.model?.folder || "";
547
+ const internal = !!kosConfig?.generator?.internal;
548
+ options.modelDirectory = options.modelDirectory || modelLocation;
549
+ const projectRoot = projectConfig.sourceRoot;
550
+ if (projectRoot) {
551
+ logger.info(
552
+ `Generating container model ${normalized.nameDashCase} in ${projectRoot}`
553
+ );
554
+ const modelNameDashCase = normalized.modelNameDashCase || normalized.nameDashCase;
555
+ generateFilesFromTemplates(
556
+ codegenFs,
557
+ path8.join(templateDir, "model"),
558
+ path8.join(projectRoot, options.modelDirectory || "", modelNameDashCase),
559
+ { ...normalized, internal }
560
+ );
561
+ if (options.dataServices) {
562
+ logger.info(
563
+ `Generating data services for ${modelNameDashCase}`
564
+ );
565
+ generateFilesFromTemplates(
566
+ codegenFs,
567
+ path8.join(templateDir, "services"),
568
+ path8.join(
569
+ projectRoot,
570
+ options.modelDirectory,
571
+ modelNameDashCase,
572
+ "services"
573
+ ),
574
+ { ...normalized, internal }
575
+ );
576
+ }
577
+ const modelIndex = path8.join(projectRoot, "index.ts");
578
+ const modelPath = normalized.modelDirectory ? `${normalized.modelDirectory}/${modelNameDashCase}` : modelNameDashCase;
579
+ updateModelIndex(codegenFs, modelIndex, modelPath);
580
+ }
581
+ }
582
+
583
+ // ../kos-codegen-core/src/lib/generators/generate-companion-model.ts
584
+ import * as path9 from "path";
585
+ function generateCompanionModel(codegenFs, templateDir, options, projects) {
586
+ const logger = getCodegenLogger();
587
+ const normalized = normalizeAllValues({
588
+ companionModelName: options.companionModelName,
589
+ modelName: options.modelName
590
+ });
591
+ const companionChildKosConfig = getKosProjectConfiguration(
592
+ codegenFs,
593
+ options.companionModelProject,
594
+ projects
595
+ );
596
+ const parentProject = findProjectByName(
597
+ codegenFs.root,
598
+ options.modelProject,
599
+ projects
600
+ );
601
+ const childProject = findProjectByName(
602
+ codegenFs.root,
603
+ options.companionModelProject,
604
+ projects
605
+ );
606
+ const projectRoot = childProject?.sourceRoot;
607
+ if (!projectRoot) {
608
+ logger.warn(`Companion child project source root not found`);
609
+ return;
610
+ }
611
+ let importPath = "";
612
+ if (parentProject) {
613
+ const pkgJsonPath = path9.join(parentProject.root, "package.json");
614
+ try {
615
+ const pkgJson = readJson(codegenFs, pkgJsonPath);
616
+ importPath = pkgJson.name || "";
617
+ } catch {
618
+ importPath = "";
619
+ }
620
+ }
621
+ const modelLocation = companionChildKosConfig?.generator?.defaults?.model?.folder || "";
622
+ const filePath = path9.join(
623
+ projectRoot,
624
+ modelLocation,
625
+ normalized.companionModelNameDashCase
626
+ );
627
+ logger.info(`Generating companion model in ${filePath}`);
628
+ generateFilesFromTemplates(codegenFs, templateDir, filePath, {
629
+ ...options,
630
+ ...normalized,
631
+ importPath
632
+ });
633
+ }
634
+
635
+ // ../kos-codegen-core/src/lib/generators/generate-model.ts
636
+ import * as path10 from "path";
637
+ function generateModel(params) {
638
+ const {
639
+ codegenFs,
640
+ modelTemplateDir,
641
+ containerTemplateDir,
642
+ companionTemplateDir,
643
+ options,
644
+ cwd,
645
+ projects
646
+ } = params;
647
+ const logger = getCodegenLogger();
648
+ const currentProject = getProject(codegenFs, cwd);
649
+ const modelProjectName = options.modelProject || currentProject?.name;
650
+ if (!modelProjectName) {
651
+ throw new Error(
652
+ "No model project found. Please specify a model project with --modelProject."
653
+ );
654
+ }
655
+ options.modelProject = modelProjectName;
656
+ const normalized = normalizeOptions(codegenFs, options, projects);
657
+ const projectConfig = findProjectByName(
658
+ codegenFs.root,
659
+ normalized.modelProject,
660
+ projects
661
+ );
662
+ if (!projectConfig) {
663
+ throw new Error(`Model project '${normalized.modelProject}' not found`);
664
+ }
665
+ const projectRoot = projectConfig.sourceRoot;
666
+ if (!projectRoot)
667
+ return;
668
+ const kosConfigPath = path10.join(projectConfig.root, ".kos.json");
669
+ const kosConfig = getKosProjectConfiguration(
670
+ codegenFs,
671
+ projectConfig.name,
672
+ projects
673
+ );
674
+ const modelLocation = kosConfig?.generator?.defaults?.model?.folder || "";
675
+ const internal = !!kosConfig?.generator?.internal;
676
+ options.modelDirectory = options.modelDirectory || modelLocation;
677
+ logger.info(
678
+ `Generating model ${normalized.nameDashCase} in ${projectRoot}`
679
+ );
680
+ generateFilesFromTemplates(
681
+ codegenFs,
682
+ path10.join(modelTemplateDir, "model"),
683
+ path10.join(projectRoot, options.modelDirectory, normalized.nameDashCase),
684
+ { ...normalized, internal }
685
+ );
686
+ if (normalized.dataServices) {
687
+ generateFilesFromTemplates(
688
+ codegenFs,
689
+ path10.join(modelTemplateDir, "services"),
690
+ path10.join(
691
+ projectRoot,
692
+ options.modelDirectory,
693
+ normalized.nameDashCase,
694
+ "services"
695
+ ),
696
+ { ...normalized, internal }
697
+ );
698
+ }
699
+ const modelIndex = path10.join(projectRoot, "index.ts");
700
+ const modelPath = options.modelDirectory ? `${options.modelDirectory}/${normalized.nameDashCase}` : normalized.nameDashCase;
701
+ updateModelIndex(codegenFs, modelIndex, modelPath);
702
+ updateJson(codegenFs, kosConfigPath, (json) => {
703
+ json.models = {
704
+ ...json.models,
705
+ [normalized.name]: {
706
+ name: normalized.name,
707
+ type: `${normalized.nameDashCase}-model`,
708
+ singleton: !!normalized.singleton
709
+ }
710
+ };
711
+ return json;
712
+ });
713
+ if (normalized.container && containerTemplateDir) {
714
+ logger.info(`Generating container for ${normalized.name}`);
715
+ generateContainerModel(
716
+ codegenFs,
717
+ containerTemplateDir,
718
+ {
719
+ ...options,
720
+ name: `${normalized.name}-container`,
721
+ modelName: normalized.name,
722
+ singleton: normalized.isContainerSingleton,
723
+ dataServices: normalized.dataServices
724
+ },
725
+ cwd,
726
+ projects
727
+ );
728
+ }
729
+ if (normalized.companion && normalized.companionModel && normalized.companionModelProject && companionTemplateDir) {
730
+ generateCompanionModel(
731
+ codegenFs,
732
+ companionTemplateDir,
733
+ {
734
+ companionModelName: normalized.name,
735
+ companionModelProject: normalized.modelProject,
736
+ modelName: normalized.companionModel,
737
+ modelProject: normalized.companionModelProject,
738
+ companionPattern: normalized.companionPattern
739
+ },
740
+ projects
741
+ );
742
+ }
743
+ }
744
+
745
+ // ../kos-codegen-core/src/lib/generators/component/types.ts
746
+ var PLUGIN_TYPES = {
747
+ CUI: "cui",
748
+ UTILITY: "utility",
749
+ TROUBLE_ACTION: "troubleAction",
750
+ SETUP: "setup",
751
+ SETTING: "setting",
752
+ NAV: "nav",
753
+ CONTROL_POUR: "controlPour",
754
+ CUSTOM: "custom"
755
+ };
756
+ var CONTRIBUTION_TYPE_MAP = {
757
+ [PLUGIN_TYPES.SETUP]: "setup",
758
+ [PLUGIN_TYPES.CUI]: "cui",
759
+ [PLUGIN_TYPES.UTILITY]: "utility",
760
+ [PLUGIN_TYPES.SETTING]: "setting",
761
+ [PLUGIN_TYPES.NAV]: "nav",
762
+ [PLUGIN_TYPES.TROUBLE_ACTION]: "trouble-action",
763
+ [PLUGIN_TYPES.CONTROL_POUR]: "control-pour",
764
+ [PLUGIN_TYPES.CUSTOM]: "custom"
765
+ };
766
+ var LOCALIZED_PLUGIN_TYPES = /* @__PURE__ */ new Set([
767
+ PLUGIN_TYPES.CUI,
768
+ PLUGIN_TYPES.UTILITY,
769
+ PLUGIN_TYPES.SETUP,
770
+ PLUGIN_TYPES.SETTING,
771
+ PLUGIN_TYPES.NAV,
772
+ PLUGIN_TYPES.CONTROL_POUR,
773
+ PLUGIN_TYPES.TROUBLE_ACTION,
774
+ PLUGIN_TYPES.CUSTOM
775
+ ]);
776
+
777
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/base.ts
778
+ var BasePluginHandler = class {
779
+ getContributionKey() {
780
+ return this.contributionKey;
781
+ }
782
+ requiresLocalization() {
783
+ return this.requiresI18n;
784
+ }
785
+ getTemplatePath() {
786
+ return this.contributionKey;
787
+ }
788
+ /**
789
+ * Helper to create experience configuration
790
+ */
791
+ createExperience(options, experienceId) {
792
+ const compPath = this.getComponentPath(options);
793
+ return {
794
+ id: experienceId,
795
+ component: options.namePascalCase,
796
+ location: `./src/${compPath}`
797
+ };
798
+ }
799
+ /**
800
+ * Helper to get component path
801
+ */
802
+ getComponentPath(options) {
803
+ return `${options.appDirectory}/${this.contributionKey}/${options.nameDashCase}/${options.nameDashCase}.tsx`;
804
+ }
805
+ /**
806
+ * Helper to create config prefix
807
+ */
808
+ getConfigPrefix(options) {
809
+ return `${options.appProject}.${options.nameCamelCase}`;
810
+ }
811
+ };
812
+
813
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/control-pour-handler.ts
814
+ var ControlPourPluginHandler = class extends BasePluginHandler {
815
+ pluginType = PLUGIN_TYPES.CONTROL_POUR;
816
+ contributionKey = "control-pour";
817
+ requiresI18n = true;
818
+ createConfiguration(options) {
819
+ const configPrefix = this.getConfigPrefix(options);
820
+ const experienceId = `${configPrefix}.controlPour.experience`;
821
+ const contribution = {
822
+ id: `${configPrefix}.controlPour`,
823
+ title: `${configPrefix}.controlPour.title`,
824
+ namespace: options.appProject,
825
+ experienceId
826
+ };
827
+ const experience = this.createExperience(options, experienceId);
828
+ return {
829
+ contributions: {
830
+ controlPour: [contribution]
831
+ },
832
+ experiences: {
833
+ [experienceId]: experience
834
+ }
835
+ };
836
+ }
837
+ };
838
+
839
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/cui-handler.ts
840
+ var CuiPluginHandler = class extends BasePluginHandler {
841
+ pluginType = PLUGIN_TYPES.CUI;
842
+ contributionKey = "cui";
843
+ requiresI18n = true;
844
+ createConfiguration(options) {
845
+ const configPrefix = this.getConfigPrefix(options);
846
+ const experienceId = `${configPrefix}.cui.experience`;
847
+ const contribution = {
848
+ id: configPrefix,
849
+ title: `${configPrefix}.cui.title`,
850
+ namespace: options.appProject,
851
+ experienceId
852
+ };
853
+ const experience = this.createExperience(options, experienceId);
854
+ return {
855
+ contributions: {
856
+ cui: [contribution]
857
+ },
858
+ experiences: {
859
+ [experienceId]: experience
860
+ }
861
+ };
862
+ }
863
+ };
864
+
865
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/custom-handler.ts
866
+ var CustomPluginHandler = class extends BasePluginHandler {
867
+ pluginType = PLUGIN_TYPES.CUSTOM;
868
+ contributionKey = "custom";
869
+ requiresI18n = true;
870
+ createConfiguration(options) {
871
+ const configPrefix = this.getConfigPrefix(options);
872
+ const experienceId = `${configPrefix}.${options.contributionKey || "custom"}.experience`;
873
+ const userContributionKey = options.contributionKey || "custom";
874
+ const contribution = {
875
+ id: configPrefix,
876
+ title: `${configPrefix}.${userContributionKey}.title`,
877
+ namespace: options.appProject,
878
+ experienceId
879
+ // TODO: Add additional fields as required by the plugin-explorer specification
880
+ // Refer to the plugin-explorer documentation for your specific contribution type
881
+ };
882
+ const experience = this.createExperience(options, experienceId);
883
+ return {
884
+ contributions: {
885
+ [userContributionKey]: [contribution]
886
+ },
887
+ experiences: {
888
+ [experienceId]: experience
889
+ }
890
+ };
891
+ }
892
+ getTemplatePath() {
893
+ return this.contributionKey || "custom";
894
+ }
895
+ getComponentPath(options) {
896
+ const pathKey = options.contributionKey || "custom";
897
+ return `${options.appDirectory}/${pathKey}/${options.nameDashCase}/${options.nameDashCase}.tsx`;
898
+ }
899
+ };
900
+
901
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/default-handler.ts
902
+ var DefaultComponentHandler = class extends BasePluginHandler {
903
+ pluginType = "component";
904
+ contributionKey = "components";
905
+ requiresI18n = false;
906
+ createConfiguration(options) {
907
+ const compPath = this.getComponentPath(options);
908
+ const viewConfig = {
909
+ id: `${options.appProject}.${options.nameCamelCase}`,
910
+ title: "ddk.ncui.config.title",
911
+ namespace: options.appProject,
912
+ component: options.namePascalCase,
913
+ location: `./src/${compPath}`
914
+ };
915
+ return {
916
+ contributions: {},
917
+ experiences: {},
918
+ views: {
919
+ [this.getTabViewKey()]: [viewConfig]
920
+ }
921
+ };
922
+ }
923
+ getTabViewKey() {
924
+ return "ddk.ncui.settings.tabView";
925
+ }
926
+ getTemplatePath() {
927
+ return "files";
928
+ }
929
+ };
930
+
931
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/nav-handler.ts
932
+ var NavPluginHandler = class extends BasePluginHandler {
933
+ pluginType = PLUGIN_TYPES.NAV;
934
+ contributionKey = "nav";
935
+ requiresI18n = true;
936
+ createConfiguration(options) {
937
+ const configPrefix = this.getConfigPrefix(options);
938
+ const experienceId = `${configPrefix}.nav.experience`;
939
+ const contribution = {
940
+ id: `${configPrefix}.nav`,
941
+ title: `${configPrefix}.nav.title`,
942
+ namespace: options.appProject,
943
+ navDescriptor: options.nameLowerCase,
944
+ experienceId
945
+ };
946
+ const experience = this.createExperience(options, experienceId);
947
+ return {
948
+ contributions: {
949
+ navViews: [contribution]
950
+ },
951
+ experiences: {
952
+ [experienceId]: experience
953
+ }
954
+ };
955
+ }
956
+ };
957
+
958
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/setting-handler.ts
959
+ var SettingPluginHandler = class extends BasePluginHandler {
960
+ pluginType = PLUGIN_TYPES.SETTING;
961
+ contributionKey = "setting";
962
+ requiresI18n = true;
963
+ createConfiguration(options) {
964
+ const configPrefix = this.getConfigPrefix(options);
965
+ const experienceId = `${configPrefix}.settings.experience`;
966
+ const contribution = {
967
+ id: `${configPrefix}.setting`,
968
+ title: `${configPrefix}.setting.title`,
969
+ namespace: options.appProject,
970
+ settingsGroup: options.group || "general",
971
+ experienceId
972
+ };
973
+ const experience = this.createExperience(options, experienceId);
974
+ return {
975
+ contributions: {
976
+ settings: [contribution]
977
+ },
978
+ experiences: {
979
+ [experienceId]: experience
980
+ }
981
+ };
982
+ }
983
+ };
984
+
985
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/setup-handler.ts
986
+ var SetupPluginHandler = class extends BasePluginHandler {
987
+ pluginType = PLUGIN_TYPES.SETUP;
988
+ contributionKey = "setup";
989
+ requiresI18n = true;
990
+ createConfiguration(options) {
991
+ const configPrefix = this.getConfigPrefix(options);
992
+ const experienceId = `${configPrefix}.setup.experience`;
993
+ const contribution = {
994
+ id: `${configPrefix}.setup`,
995
+ title: `${configPrefix}.setup.title`,
996
+ namespace: options.appProject,
997
+ setupDescriptor: options.nameCamelCase,
998
+ experienceId
999
+ };
1000
+ const experience = this.createExperience(options, experienceId);
1001
+ return {
1002
+ contributions: {
1003
+ setupStep: [contribution]
1004
+ },
1005
+ experiences: {
1006
+ [experienceId]: experience
1007
+ }
1008
+ };
1009
+ }
1010
+ };
1011
+
1012
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/trouble-action-handler.ts
1013
+ var TroubleActionPluginHandler = class extends BasePluginHandler {
1014
+ pluginType = PLUGIN_TYPES.TROUBLE_ACTION;
1015
+ contributionKey = "trouble-action";
1016
+ requiresI18n = true;
1017
+ createConfiguration(options) {
1018
+ const configPrefix = this.getConfigPrefix(options);
1019
+ const experienceId = `${configPrefix}.troubleAction.experience`;
1020
+ const contribution = {
1021
+ id: `${configPrefix}.troubleAction`,
1022
+ title: `${configPrefix}.troubleAction.title`,
1023
+ namespace: options.appProject,
1024
+ troubleType: options.nameCamelCase,
1025
+ experienceId
1026
+ };
1027
+ const experience = this.createExperience(options, experienceId);
1028
+ return {
1029
+ contributions: {
1030
+ troubleActions: [contribution]
1031
+ },
1032
+ experiences: {
1033
+ [experienceId]: experience
1034
+ }
1035
+ };
1036
+ }
1037
+ };
1038
+
1039
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/utility-handler.ts
1040
+ var UtilityPluginHandler = class extends BasePluginHandler {
1041
+ pluginType = PLUGIN_TYPES.UTILITY;
1042
+ contributionKey = "utility";
1043
+ requiresI18n = true;
1044
+ createConfiguration(options) {
1045
+ const configPrefix = this.getConfigPrefix(options);
1046
+ const experienceId = `${configPrefix}.util.experience`;
1047
+ const contribution = {
1048
+ id: `${configPrefix}.util`,
1049
+ title: `${configPrefix}.utility.title`,
1050
+ namespace: options.appProject,
1051
+ utilDescriptor: options.nameCamelCase,
1052
+ experienceId
1053
+ };
1054
+ const experience = this.createExperience(options, experienceId);
1055
+ return {
1056
+ contributions: {
1057
+ utilities: [contribution]
1058
+ },
1059
+ experiences: {
1060
+ [experienceId]: experience
1061
+ }
1062
+ };
1063
+ }
1064
+ };
1065
+
1066
+ // ../kos-codegen-core/src/lib/generators/component/plugin-handlers/factory.ts
1067
+ var PluginHandlerFactory = class {
1068
+ static handlers = /* @__PURE__ */ new Map([
1069
+ [PLUGIN_TYPES.CUI, CuiPluginHandler],
1070
+ [PLUGIN_TYPES.UTILITY, UtilityPluginHandler],
1071
+ [PLUGIN_TYPES.SETTING, SettingPluginHandler],
1072
+ [PLUGIN_TYPES.SETUP, SetupPluginHandler],
1073
+ [PLUGIN_TYPES.NAV, NavPluginHandler],
1074
+ [PLUGIN_TYPES.CONTROL_POUR, ControlPourPluginHandler],
1075
+ [PLUGIN_TYPES.TROUBLE_ACTION, TroubleActionPluginHandler],
1076
+ [PLUGIN_TYPES.CUSTOM, CustomPluginHandler]
1077
+ ]);
1078
+ static createHandler(pluginType) {
1079
+ if (!pluginType) {
1080
+ return new DefaultComponentHandler();
1081
+ }
1082
+ const HandlerClass = this.handlers.get(pluginType);
1083
+ if (!HandlerClass) {
1084
+ console.warn(
1085
+ `No handler found for plugin type: ${pluginType}. Using default handler.`
1086
+ );
1087
+ return new DefaultComponentHandler();
1088
+ }
1089
+ return new HandlerClass();
1090
+ }
1091
+ static isValidPluginType(type) {
1092
+ return this.handlers.has(type);
1093
+ }
1094
+ };
1095
+
1096
+ // src/lib/utils/action-factory.mjs
1097
+ var actionFactory = (action, metadata2) => {
1098
+ return () => {
1099
+ const _actions = [{ type: action }];
1100
+ if (metadata2.invalidateCache) {
1101
+ _actions.push({ type: "clearCache" });
1102
+ }
1103
+ return _actions;
1104
+ };
1105
+ };
1106
+
1107
+ // src/lib/utils/nx-context.mjs
1108
+ import { existsSync as existsSync4, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync } from "fs";
1109
+ import path12 from "path";
1110
+ import { fileURLToPath } from "url";
1111
+
1112
+ // src/lib/utils/cache.mjs
1113
+ import fs6 from "fs";
1114
+ import path11 from "path";
1115
+ var CACHE_PATH = path11.resolve(".nx/cli-cache.json");
1116
+ var CACHE_TTL = 600 * 1e3;
1117
+ var ARGS = process.argv;
1118
+ var DISABLE_CACHE = process.env.DISABLE_CACHE === "true" || process.env.REFRESH === "true";
1119
+ var _cache = {};
1120
+ var _loaded = false;
1121
+ function ensureCacheDir() {
1122
+ const dir = path11.dirname(CACHE_PATH);
1123
+ if (!fs6.existsSync(dir))
1124
+ fs6.mkdirSync(dir, { recursive: true });
1125
+ }
1126
+ function loadCacheFromDisk() {
1127
+ if (_loaded)
1128
+ return;
1129
+ _loaded = true;
1130
+ try {
1131
+ if (fs6.existsSync(CACHE_PATH)) {
1132
+ const data = fs6.readFileSync(CACHE_PATH, "utf-8");
1133
+ _cache = JSON.parse(data);
1134
+ }
1135
+ } catch (err) {
1136
+ console.warn("Failed to load CLI cache:", err);
1137
+ _cache = {};
1138
+ }
1139
+ }
1140
+ function saveCacheToDisk() {
1141
+ try {
1142
+ ensureCacheDir();
1143
+ fs6.writeFileSync(CACHE_PATH, JSON.stringify(_cache, null, 2));
1144
+ } catch (err) {
1145
+ console.warn("Failed to save CLI cache:", err);
1146
+ }
1147
+ }
1148
+ function isFresh(entry, ttl = CACHE_TTL) {
1149
+ if (!entry || !entry.timestamp)
1150
+ return false;
1151
+ return Date.now() - entry.timestamp < ttl;
1152
+ }
1153
+ function getCached(key, ttl = CACHE_TTL) {
1154
+ if (DISABLE_CACHE)
1155
+ return null;
1156
+ loadCacheFromDisk();
1157
+ const entry = _cache[key];
1158
+ if (isFresh(entry, ttl))
1159
+ return entry.data;
1160
+ return null;
1161
+ }
1162
+ function setCached(key, data) {
1163
+ loadCacheFromDisk();
1164
+ _cache[key] = {
1165
+ data,
1166
+ timestamp: Date.now()
1167
+ };
1168
+ saveCacheToDisk();
1169
+ }
1170
+
1171
+ // src/lib/utils/nx-context.mjs
1172
+ var __dirname2 = path12.dirname(fileURLToPath(import.meta.url));
1173
+ function findKosJsonFiles(dir = process.cwd(), files = []) {
1174
+ try {
1175
+ const entries = readdirSync3(dir);
1176
+ for (const entry of entries) {
1177
+ if (entry === "node_modules" || entry === ".git" || entry === ".nx" || entry === "dist" || entry === "coverage" || entry === ".vscode" || entry === ".idea" || entry.startsWith(".") && entry !== ".kos.json") {
1178
+ continue;
1179
+ }
1180
+ const fullPath = path12.join(dir, entry);
1181
+ try {
1182
+ const stat = statSync(fullPath);
1183
+ if (stat.isFile() && entry === ".kos.json") {
1184
+ files.push(fullPath);
1185
+ } else if (stat.isDirectory()) {
1186
+ if (entry !== "tmp" && entry !== "temp" && entry !== "build") {
1187
+ findKosJsonFiles(fullPath, files);
1188
+ }
1189
+ }
1190
+ } catch (error) {
1191
+ continue;
1192
+ }
1193
+ }
1194
+ } catch (error) {
1195
+ }
1196
+ return files;
1197
+ }
1198
+ async function getLibraryProjects() {
1199
+ const cached = getCached("libraryProjects");
1200
+ if (cached)
1201
+ return cached;
1202
+ const projectMap = discoverProjects(process.cwd());
1203
+ const projects = Array.from(projectMap.values()).filter((p) => p.projectType === "library").map((p) => p.name);
1204
+ setCached("libraryProjects", projects);
1205
+ return projects;
1206
+ }
1207
+ async function getAllKosProjects() {
1208
+ const cached = getCached("allKosProjects");
1209
+ if (cached)
1210
+ return cached;
1211
+ if (process.env.KOS_CLI_QUIET !== "true") {
1212
+ console.warn(`[kos-cli] Discovering KOS projects by scanning .kos.json files...`);
1213
+ }
1214
+ const projectDirs = ["apps", "libs", "packages"];
1215
+ const kosJsonFiles = [];
1216
+ const workspaceRoot = process.cwd();
1217
+ for (const dir of projectDirs) {
1218
+ const dirPath = path12.join(workspaceRoot, dir);
1219
+ if (existsSync4(dirPath)) {
1220
+ findKosJsonFiles(dirPath, kosJsonFiles);
1221
+ }
1222
+ }
1223
+ const rootKosJson = path12.join(workspaceRoot, ".kos.json");
1224
+ if (existsSync4(rootKosJson)) {
1225
+ kosJsonFiles.push(rootKosJson);
1226
+ }
1227
+ if (kosJsonFiles.length === 0) {
1228
+ if (process.env.KOS_CLI_QUIET !== "true") {
1229
+ console.warn(`[kos-cli] No .kos.json files found in common directories, performing full workspace scan...`);
1230
+ }
1231
+ findKosJsonFiles(workspaceRoot, kosJsonFiles);
1232
+ }
1233
+ const kosProjects = [];
1234
+ for (const kosJsonPath of kosJsonFiles) {
1235
+ try {
1236
+ const kosConfig = JSON.parse(readFileSync6(kosJsonPath, "utf-8"));
1237
+ const projectDir = path12.dirname(kosJsonPath);
1238
+ let projectName = null;
1239
+ const projectJsonPath = path12.join(projectDir, "project.json");
1240
+ if (existsSync4(projectJsonPath)) {
1241
+ try {
1242
+ const projectJson = JSON.parse(readFileSync6(projectJsonPath, "utf-8"));
1243
+ projectName = projectJson.name;
1244
+ } catch (error) {
1245
+ projectName = path12.basename(projectDir);
1246
+ }
1247
+ } else {
1248
+ projectName = path12.basename(projectDir);
1249
+ }
1250
+ if (kosConfig.type === "root") {
1251
+ continue;
1252
+ }
1253
+ kosProjects.push({
1254
+ name: projectName,
1255
+ path: projectDir,
1256
+ kosJsonPath,
1257
+ config: kosConfig,
1258
+ projectType: kosConfig.generator?.projectType
1259
+ });
1260
+ } catch (error) {
1261
+ console.warn(`[kos-cli] Error reading ${kosJsonPath}: ${error.message}`);
1262
+ }
1263
+ }
1264
+ setCached("allKosProjects", kosProjects);
1265
+ return kosProjects;
1266
+ }
1267
+ async function getProjectsByType(targetType) {
1268
+ const cacheKey = `projectsByType:${targetType}`;
1269
+ const cached = getCached(cacheKey);
1270
+ if (cached)
1271
+ return cached;
1272
+ if (process.env.KOS_CLI_QUIET !== "true") {
1273
+ console.warn(`[kos-cli] Filtering projects for ${targetType} projectType...`);
1274
+ }
1275
+ const allKosProjects = await getAllKosProjects();
1276
+ const filteredProjects = [];
1277
+ for (const kosProject of allKosProjects) {
1278
+ const projectType = kosProject.projectType;
1279
+ const hasTargetType = Array.isArray(projectType) ? projectType.includes(targetType) : projectType === targetType;
1280
+ if (hasTargetType) {
1281
+ filteredProjects.push(kosProject.name);
1282
+ }
1283
+ }
1284
+ setCached(cacheKey, filteredProjects);
1285
+ return filteredProjects;
1286
+ }
1287
+ async function getProjectsByTypeWithFallback(targetType, fallbackFunction = getLibraryProjects) {
1288
+ const filteredProjects = await getProjectsByType(targetType);
1289
+ if (filteredProjects.length > 0) {
1290
+ if (process.env.KOS_CLI_QUIET !== "true") {
1291
+ console.warn(`[kos-cli] Found ${filteredProjects.length} ${targetType} projects`);
1292
+ }
1293
+ return filteredProjects;
1294
+ } else {
1295
+ if (process.env.KOS_CLI_QUIET !== "true") {
1296
+ console.warn(`[kos-cli] No ${targetType} projects found, showing fallback projects`);
1297
+ }
1298
+ return await fallbackFunction();
1299
+ }
1300
+ }
1301
+ async function getModelProjectsWithFallback() {
1302
+ return await getProjectsByTypeWithFallback("model", getLibraryProjects);
1303
+ }
1304
+ async function getAllModels() {
1305
+ const cached = getCached("allModels");
1306
+ if (cached)
1307
+ return cached;
1308
+ if (process.env.KOS_CLI_QUIET !== "true") {
1309
+ console.warn(`[kos-cli] Scanning for models in KOS projects...`);
1310
+ }
1311
+ const allKosProjects = await getAllKosProjects();
1312
+ const models = [];
1313
+ for (const kosProject of allKosProjects) {
1314
+ if (kosProject.config.models) {
1315
+ Object.keys(kosProject.config.models).forEach((model) => {
1316
+ models.push({ model, project: kosProject.name });
1317
+ });
1318
+ }
1319
+ }
1320
+ models.sort((a, b) => {
1321
+ if (a.project === b.project) {
1322
+ return a.model.localeCompare(b.model);
1323
+ } else {
1324
+ return a.project.localeCompare(b.project);
1325
+ }
1326
+ });
1327
+ setCached("allModels", models);
1328
+ return models;
1329
+ }
1330
+ async function getProjectDetails(projectName) {
1331
+ const cacheKey = `projectDetails:${projectName}`;
1332
+ const cached = getCached(cacheKey);
1333
+ if (cached)
1334
+ return cached;
1335
+ const details = findProjectByName(process.cwd(), projectName);
1336
+ if (!details) {
1337
+ throw new Error(`Project "${projectName}" not found in workspace`);
1338
+ }
1339
+ setCached(cacheKey, details);
1340
+ return details;
1341
+ }
1342
+
1343
+ // src/lib/utils/prompts.mjs
1344
+ var DEFAULT_PROMPTS = [
1345
+ {
1346
+ type: "confirm",
1347
+ name: "interactive",
1348
+ message: "Use interactive mode?",
1349
+ default: false,
1350
+ when: false
1351
+ },
1352
+ {
1353
+ type: "confirm",
1354
+ name: "dryRun",
1355
+ message: "Dry run the command?",
1356
+ default: false,
1357
+ when: false
1358
+ }
1359
+ ];
1360
+ var MODEL_PROMPTS = [
1361
+ {
1362
+ type: "confirm",
1363
+ name: "container",
1364
+ message: "Requires container model?",
1365
+ default: false
1366
+ },
1367
+ {
1368
+ type: "confirm",
1369
+ name: "parentAware",
1370
+ message: "Aware of parent container?",
1371
+ default: false
1372
+ },
1373
+ {
1374
+ type: "confirm",
1375
+ name: "singleton",
1376
+ message: "Is singleton?",
1377
+ default: false
1378
+ },
1379
+ {
1380
+ type: "confirm",
1381
+ name: "dataServices",
1382
+ message: "Create data services?",
1383
+ default: true
1384
+ },
1385
+ {
1386
+ type: "list",
1387
+ name: "futureAware",
1388
+ message: "Include Future-aware capabilities?",
1389
+ choices: [
1390
+ { name: "No Future support", value: "none" },
1391
+ { name: "Minimal (external access only)", value: "minimal" },
1392
+ { name: "Complete (internal + external access)", value: "complete" }
1393
+ ],
1394
+ default: "none"
1395
+ }
1396
+ ];
1397
+ var COMPANION_PROMPTS = [
1398
+ {
1399
+ type: "list",
1400
+ name: "companionPattern",
1401
+ message: "Which companion pattern to use?",
1402
+ choices: [
1403
+ {
1404
+ name: "Composition (recommended) - explicit parent access via this.parent",
1405
+ value: "composition"
1406
+ },
1407
+ {
1408
+ name: "Decorator - transparent parent access, drop-in replacement",
1409
+ value: "decorator"
1410
+ }
1411
+ ],
1412
+ default: "composition"
1413
+ }
1414
+ ];
1415
+
1416
+ // src/lib/utils/validators.mjs
1417
+ function required(value) {
1418
+ return value && value.trim() !== "" ? true : "This field is required.";
1419
+ }
1420
+
1421
+ // src/lib/generators/model/companion.mjs
1422
+ var metadata = {
17
1423
  key: "model:companion",
18
1424
  name: "KOS Companion Model",
19
1425
  namedArguments: {
@@ -29,63 +1435,61 @@ export const metadata = {
29
1435
  dataServices: "dataServices",
30
1436
  autoRegister: "autoRegister",
31
1437
  dryRun: "dryRun",
32
- interactive: "interactive",
33
- },
1438
+ interactive: "interactive"
1439
+ }
34
1440
  };
35
-
36
- export default async function (plop) {
1441
+ async function companion_default(plop) {
37
1442
  const libraryProjects = await getModelProjectsWithFallback();
38
-
39
- // Check if we're in interactive mode by looking at process args
40
- const isInteractive = process.argv.includes('-i') || process.argv.includes('--interactive');
41
-
42
- // For interactive mode, use lazy loading. For non-interactive, load immediately.
1443
+ const isInteractive = process.argv.includes("-i") || process.argv.includes("--interactive");
43
1444
  let modelChoices;
44
1445
  if (isInteractive) {
45
1446
  modelChoices = async () => {
46
1447
  const allModels = await getAllModels();
47
1448
  return allModels.map((m) => ({
48
1449
  name: `${m.model} (${m.project})`,
49
- value: m.model,
1450
+ value: m.model
50
1451
  }));
51
1452
  };
52
1453
  } else {
53
1454
  const allModels = await getAllModels();
54
1455
  modelChoices = allModels.map((m) => ({
55
1456
  name: `${m.model} (${m.project})`,
56
- value: m.model,
1457
+ value: m.model
57
1458
  }));
58
1459
  }
59
-
60
- plop.setActionType("createCompanionModel", async function (answers) {
1460
+ plop.setActionType("createCompanionModel", async function(answers) {
1461
+ const cwd = process.cwd();
1462
+ const codegenFs = new TrackingFileSystem(new DirectFileSystem(cwd));
61
1463
  const modelProject = await getProjectDetails(answers.modelProject);
62
1464
  const allModels = await getAllModels();
63
1465
  const companionProject = allModels.find(
64
1466
  (m) => m.model === answers.companionParent
65
1467
  )?.project;
66
-
67
- const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-model \
68
- --name=${answers.modelName} \
69
- --modelProject=${modelProject.name} \
70
- --skipRegistration=true \
71
- --container=${!!answers.container} \
72
- --dataServices=${!!answers.dataServices} \
73
- --singleton=${!!answers.singleton} \
74
- --parentAware=${!!answers.parentAware} \
75
- --autoRegister=${!!answers.autoRegister} \
76
- --companion=true \
77
- --companionModel=${answers.companionParent} \
78
- --companionModelProject=${companionProject} \
79
- --companionPattern=${answers.companionPattern} \
80
- --no-interactive ${answers.dryRun ? "--dryRun" : ""} --verbose`;
81
-
82
- try {
83
- await execute(command);
84
- } catch (error) {
85
- throw new Error(error);
86
- }
1468
+ generateModel({
1469
+ codegenFs,
1470
+ modelTemplateDir: getTemplateDir("kos-model"),
1471
+ containerTemplateDir: getTemplateDir("kos-container-model"),
1472
+ companionTemplateDir: getTemplateDir("kos-companion-model"),
1473
+ options: {
1474
+ name: answers.modelName,
1475
+ modelProject: modelProject.name,
1476
+ modelDirectory: "",
1477
+ skipRegistration: true,
1478
+ container: !!answers.container,
1479
+ dataServices: !!answers.dataServices,
1480
+ singleton: !!answers.singleton,
1481
+ parentAware: !!answers.parentAware,
1482
+ autoRegister: !!answers.autoRegister,
1483
+ companion: true,
1484
+ companionModel: answers.companionParent,
1485
+ companionModelProject: companionProject,
1486
+ companionPattern: answers.companionPattern
1487
+ },
1488
+ cwd
1489
+ });
1490
+ await formatFiles(codegenFs.root, codegenFs.writtenPaths);
1491
+ return `Companion model ${answers.modelName} created in ${answers.modelProject}`;
87
1492
  });
88
-
89
1493
  plop.setGenerator("model:companion", {
90
1494
  description: "Create a new KOS Companion Model",
91
1495
  prompts: [
@@ -94,24 +1498,29 @@ export default async function (plop) {
94
1498
  type: "input",
95
1499
  name: "modelName",
96
1500
  message: "Enter the name of the model",
97
- validate: required,
1501
+ validate: required
98
1502
  },
99
1503
  {
100
1504
  type: "list",
101
1505
  name: "modelProject",
102
1506
  message: "Which model project to use?",
103
1507
  validate: required,
104
- choices: libraryProjects,
1508
+ choices: libraryProjects
105
1509
  },
106
1510
  {
107
1511
  type: "list",
108
1512
  name: "companionParent",
109
1513
  message: "Select the companion parent model",
110
- choices: modelChoices,
1514
+ choices: modelChoices
111
1515
  },
112
1516
  ...COMPANION_PROMPTS,
113
- ...MODEL_PROMPTS,
1517
+ ...MODEL_PROMPTS
114
1518
  ],
115
- actions: actionFactory("createCompanionModel", metadata),
1519
+ actions: actionFactory("createCompanionModel", metadata)
116
1520
  });
117
1521
  }
1522
+ export {
1523
+ companion_default as default,
1524
+ metadata
1525
+ };
1526
+ //# sourceMappingURL=companion.mjs.map