@kosdev-code/kos-ui-cli 2.0.33 → 2.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/lib/cli.mjs +355 -186
- package/src/lib/generators/component/index.mjs +3 -3
- package/src/lib/generators/i18n/namespace.mjs +3 -3
- package/src/lib/generators/model/companion.mjs +2 -2
- package/src/lib/generators/model/model.mjs +2 -2
- package/src/lib/generators/plugin/index.mjs +3 -3
- package/src/lib/utils/nx-context.mjs +294 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kosdev-code/kos-ui-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.34",
|
|
4
4
|
"bin": {
|
|
5
5
|
"kosui": "./src/lib/cli.mjs"
|
|
6
6
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"main": "./src/index.js",
|
|
21
21
|
"kos": {
|
|
22
22
|
"build": {
|
|
23
|
-
"gitHash": "
|
|
23
|
+
"gitHash": "abc125566178e7aa50012d17d649f46b4b511cc4"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
package/src/lib/cli.mjs
CHANGED
|
@@ -30,11 +30,11 @@ const showBanner =
|
|
|
30
30
|
async function launch() {
|
|
31
31
|
// Check for help modes before initializing plop to avoid expensive model parsing
|
|
32
32
|
const shouldShowHelp = parsedArgs.help;
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
if (!command || command === "help") {
|
|
35
35
|
// For general help, we still need plop to list generators
|
|
36
36
|
const plop = await nodePlop(configPath);
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
console.warn("--- KOS CLI Help ---");
|
|
39
39
|
console.log("\nAvailable Generators:");
|
|
40
40
|
plop.getGeneratorList().forEach((g) => {
|
|
@@ -58,128 +58,153 @@ async function launch() {
|
|
|
58
58
|
// For generator-specific help, check if we can show help without full plop initialization
|
|
59
59
|
if (shouldShowHelp) {
|
|
60
60
|
const earlyMeta = await getGeneratorMetadata(command);
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
if (earlyMeta && Object.keys(earlyMeta).length > 0) {
|
|
63
63
|
// Show help immediately for --help flag
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
console.log(`--- ${earlyMeta?.name || command} Help ---`);
|
|
65
|
+
console.log(earlyMeta.description || "No description available");
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
if (earlyMeta?.namedArguments) {
|
|
68
|
+
console.log("\nNamed Arguments:");
|
|
69
|
+
Object.entries(earlyMeta.namedArguments).forEach(
|
|
70
|
+
([cliArg, promptName]) => {
|
|
70
71
|
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
72
|
+
}
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log("\nExamples:");
|
|
77
|
+
|
|
78
|
+
// Generate examples dynamically from the generator's named arguments
|
|
79
|
+
if (earlyMeta?.namedArguments) {
|
|
80
|
+
const args = Object.keys(earlyMeta.namedArguments);
|
|
73
81
|
|
|
74
|
-
console.log("\nExamples:");
|
|
75
|
-
|
|
76
|
-
// Generate examples dynamically from the generator's named arguments
|
|
77
|
-
if (earlyMeta?.namedArguments) {
|
|
78
|
-
const args = Object.keys(earlyMeta.namedArguments);
|
|
79
|
-
|
|
80
82
|
// Generate example values based on argument names
|
|
81
83
|
const generateExampleValue = (argName) => {
|
|
82
84
|
switch (argName) {
|
|
83
|
-
case
|
|
84
|
-
case
|
|
85
|
-
return command.includes(
|
|
86
|
-
case
|
|
87
|
-
return
|
|
88
|
-
case
|
|
89
|
-
return
|
|
90
|
-
case
|
|
91
|
-
case
|
|
92
|
-
case
|
|
93
|
-
return
|
|
94
|
-
case
|
|
95
|
-
return
|
|
96
|
-
case
|
|
97
|
-
return
|
|
98
|
-
case
|
|
99
|
-
return
|
|
100
|
-
case
|
|
101
|
-
return
|
|
102
|
-
case
|
|
103
|
-
return
|
|
104
|
-
case
|
|
105
|
-
case
|
|
106
|
-
case
|
|
107
|
-
case
|
|
85
|
+
case "name":
|
|
86
|
+
case "componentName":
|
|
87
|
+
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
88
|
+
case "modelName":
|
|
89
|
+
return "my-model";
|
|
90
|
+
case "workspaceName":
|
|
91
|
+
return "my-workspace";
|
|
92
|
+
case "project":
|
|
93
|
+
case "componentProject":
|
|
94
|
+
case "modelProject":
|
|
95
|
+
return "my-ui-lib";
|
|
96
|
+
case "registrationProject":
|
|
97
|
+
return "my-lib";
|
|
98
|
+
case "companionParent":
|
|
99
|
+
return "parent-model";
|
|
100
|
+
case "extensionPoint":
|
|
101
|
+
return "utility";
|
|
102
|
+
case "group":
|
|
103
|
+
return "appearance";
|
|
104
|
+
case "locale":
|
|
105
|
+
return "en";
|
|
106
|
+
case "container":
|
|
107
|
+
case "singleton":
|
|
108
|
+
case "parentAware":
|
|
109
|
+
case "dataServices":
|
|
108
110
|
return true;
|
|
109
|
-
case
|
|
111
|
+
case "dryRun":
|
|
110
112
|
return true;
|
|
111
113
|
default:
|
|
112
114
|
return `my-${argName}`;
|
|
113
115
|
}
|
|
114
116
|
};
|
|
115
|
-
|
|
117
|
+
|
|
116
118
|
// Create basic example with most important arguments
|
|
117
119
|
const basicArgs = [];
|
|
118
|
-
const booleanArgs = [
|
|
119
|
-
|
|
120
|
+
const booleanArgs = [
|
|
121
|
+
"container",
|
|
122
|
+
"singleton",
|
|
123
|
+
"parentAware",
|
|
124
|
+
"dataServices",
|
|
125
|
+
"dryRun",
|
|
126
|
+
];
|
|
127
|
+
|
|
120
128
|
// Pick the most relevant arguments for each generator type
|
|
121
129
|
const getRelevantArgs = (args, command) => {
|
|
122
130
|
const relevantArgs = [];
|
|
123
|
-
|
|
131
|
+
|
|
124
132
|
// Always prefer name-type arguments first
|
|
125
|
-
const nameArgs = [
|
|
133
|
+
const nameArgs = [
|
|
134
|
+
"name",
|
|
135
|
+
"componentName",
|
|
136
|
+
"modelName",
|
|
137
|
+
"workspaceName",
|
|
138
|
+
].filter((arg) => args.includes(arg));
|
|
126
139
|
if (nameArgs.length > 0) {
|
|
127
140
|
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
128
141
|
}
|
|
129
|
-
|
|
142
|
+
|
|
130
143
|
// Then add project-type arguments
|
|
131
|
-
const projectArgs = [
|
|
144
|
+
const projectArgs = [
|
|
145
|
+
"project",
|
|
146
|
+
"componentProject",
|
|
147
|
+
"modelProject",
|
|
148
|
+
"registrationProject",
|
|
149
|
+
].filter((arg) => args.includes(arg));
|
|
132
150
|
if (projectArgs.length > 0) {
|
|
133
151
|
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
134
152
|
}
|
|
135
|
-
|
|
153
|
+
|
|
136
154
|
// Add other specific arguments
|
|
137
|
-
const otherArgs = args.filter(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
155
|
+
const otherArgs = args.filter(
|
|
156
|
+
(arg) =>
|
|
157
|
+
!nameArgs.includes(arg) &&
|
|
158
|
+
!projectArgs.includes(arg) &&
|
|
159
|
+
!booleanArgs.includes(arg) &&
|
|
160
|
+
arg !== "interactive"
|
|
142
161
|
);
|
|
143
|
-
|
|
162
|
+
|
|
144
163
|
// Add up to 2 more relevant arguments
|
|
145
164
|
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
146
|
-
|
|
165
|
+
|
|
147
166
|
return relevantArgs;
|
|
148
167
|
};
|
|
149
|
-
|
|
168
|
+
|
|
150
169
|
const relevantArgs = getRelevantArgs(args, command);
|
|
151
|
-
|
|
152
|
-
relevantArgs.forEach(argName => {
|
|
170
|
+
|
|
171
|
+
relevantArgs.forEach((argName) => {
|
|
153
172
|
const value = generateExampleValue(argName);
|
|
154
173
|
basicArgs.push(`--${argName} ${value}`);
|
|
155
174
|
});
|
|
156
|
-
|
|
175
|
+
|
|
157
176
|
// Create advanced example with boolean flags
|
|
158
177
|
const advancedBooleanArgs = [];
|
|
159
|
-
booleanArgs.forEach(argName => {
|
|
178
|
+
booleanArgs.forEach((argName) => {
|
|
160
179
|
if (args.includes(argName)) {
|
|
161
180
|
advancedBooleanArgs.push(`--${argName}`);
|
|
162
181
|
}
|
|
163
182
|
});
|
|
164
|
-
|
|
183
|
+
|
|
165
184
|
// Show basic example
|
|
166
185
|
if (basicArgs.length > 0) {
|
|
167
|
-
console.log(` kosui ${command} ${basicArgs.join(
|
|
186
|
+
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
168
187
|
}
|
|
169
|
-
|
|
188
|
+
|
|
170
189
|
// Show advanced example with boolean flags if any exist
|
|
171
190
|
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
172
|
-
console.log(
|
|
191
|
+
console.log(
|
|
192
|
+
` kosui ${command} ${basicArgs
|
|
193
|
+
.slice(0, 2)
|
|
194
|
+
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
195
|
+
);
|
|
173
196
|
}
|
|
174
|
-
|
|
197
|
+
|
|
175
198
|
// If no basic args, show a minimal example
|
|
176
199
|
if (basicArgs.length === 0) {
|
|
177
200
|
console.log(` kosui ${command} [options]`);
|
|
178
201
|
}
|
|
179
202
|
}
|
|
180
|
-
|
|
203
|
+
|
|
181
204
|
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
182
|
-
console.log(
|
|
205
|
+
console.log(
|
|
206
|
+
` kosui ${command} -i # Force interactive mode (short form)`
|
|
207
|
+
);
|
|
183
208
|
return;
|
|
184
209
|
}
|
|
185
210
|
}
|
|
@@ -203,7 +228,7 @@ async function launch() {
|
|
|
203
228
|
});
|
|
204
229
|
const hasAnyAnswers = Object.keys(providedAnswers).length > 0;
|
|
205
230
|
const forceInteractive = parsedArgs.interactive || parsedArgs.i;
|
|
206
|
-
|
|
231
|
+
|
|
207
232
|
// Show help for no-arguments case
|
|
208
233
|
if (!hasAnyAnswers && !forceInteractive) {
|
|
209
234
|
console.log(`--- ${earlyMeta?.name || command} Help ---`);
|
|
@@ -211,120 +236,145 @@ async function launch() {
|
|
|
211
236
|
|
|
212
237
|
if (earlyMeta?.namedArguments) {
|
|
213
238
|
console.log("\nNamed Arguments:");
|
|
214
|
-
Object.entries(earlyMeta.namedArguments).forEach(
|
|
215
|
-
|
|
216
|
-
|
|
239
|
+
Object.entries(earlyMeta.namedArguments).forEach(
|
|
240
|
+
([cliArg, promptName]) => {
|
|
241
|
+
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
242
|
+
}
|
|
243
|
+
);
|
|
217
244
|
}
|
|
218
245
|
|
|
219
246
|
console.log("\nExamples:");
|
|
220
|
-
|
|
247
|
+
|
|
221
248
|
// Generate examples dynamically from the generator's named arguments
|
|
222
249
|
if (earlyMeta?.namedArguments) {
|
|
223
250
|
const args = Object.keys(earlyMeta.namedArguments);
|
|
224
|
-
|
|
251
|
+
|
|
225
252
|
// Generate example values based on argument names
|
|
226
253
|
const generateExampleValue = (argName) => {
|
|
227
254
|
switch (argName) {
|
|
228
|
-
case
|
|
229
|
-
case
|
|
230
|
-
return command.includes(
|
|
231
|
-
case
|
|
232
|
-
return
|
|
233
|
-
case
|
|
234
|
-
return
|
|
235
|
-
case
|
|
236
|
-
case
|
|
237
|
-
case
|
|
238
|
-
return
|
|
239
|
-
case
|
|
240
|
-
return
|
|
241
|
-
case
|
|
242
|
-
return
|
|
243
|
-
case
|
|
244
|
-
return
|
|
245
|
-
case
|
|
246
|
-
return
|
|
247
|
-
case
|
|
248
|
-
return
|
|
249
|
-
case
|
|
250
|
-
case
|
|
251
|
-
case
|
|
252
|
-
case
|
|
255
|
+
case "name":
|
|
256
|
+
case "componentName":
|
|
257
|
+
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
258
|
+
case "modelName":
|
|
259
|
+
return "my-model";
|
|
260
|
+
case "workspaceName":
|
|
261
|
+
return "my-workspace";
|
|
262
|
+
case "project":
|
|
263
|
+
case "componentProject":
|
|
264
|
+
case "modelProject":
|
|
265
|
+
return "my-ui-lib";
|
|
266
|
+
case "registrationProject":
|
|
267
|
+
return "my-lib";
|
|
268
|
+
case "companionParent":
|
|
269
|
+
return "parent-model";
|
|
270
|
+
case "extensionPoint":
|
|
271
|
+
return "utility";
|
|
272
|
+
case "group":
|
|
273
|
+
return "appearance";
|
|
274
|
+
case "locale":
|
|
275
|
+
return "en";
|
|
276
|
+
case "container":
|
|
277
|
+
case "singleton":
|
|
278
|
+
case "parentAware":
|
|
279
|
+
case "dataServices":
|
|
253
280
|
return true;
|
|
254
|
-
case
|
|
281
|
+
case "dryRun":
|
|
255
282
|
return true;
|
|
256
283
|
default:
|
|
257
284
|
return `my-${argName}`;
|
|
258
285
|
}
|
|
259
286
|
};
|
|
260
|
-
|
|
287
|
+
|
|
261
288
|
// Create basic example with most important arguments
|
|
262
289
|
const basicArgs = [];
|
|
263
|
-
const booleanArgs = [
|
|
264
|
-
|
|
290
|
+
const booleanArgs = [
|
|
291
|
+
"container",
|
|
292
|
+
"singleton",
|
|
293
|
+
"parentAware",
|
|
294
|
+
"dataServices",
|
|
295
|
+
"dryRun",
|
|
296
|
+
];
|
|
297
|
+
|
|
265
298
|
// Pick the most relevant arguments for each generator type
|
|
266
299
|
const getRelevantArgs = (args, command) => {
|
|
267
300
|
const relevantArgs = [];
|
|
268
|
-
|
|
301
|
+
|
|
269
302
|
// Always prefer name-type arguments first
|
|
270
|
-
const nameArgs = [
|
|
303
|
+
const nameArgs = [
|
|
304
|
+
"name",
|
|
305
|
+
"componentName",
|
|
306
|
+
"modelName",
|
|
307
|
+
"workspaceName",
|
|
308
|
+
].filter((arg) => args.includes(arg));
|
|
271
309
|
if (nameArgs.length > 0) {
|
|
272
310
|
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
273
311
|
}
|
|
274
|
-
|
|
312
|
+
|
|
275
313
|
// Then add project-type arguments
|
|
276
|
-
const projectArgs = [
|
|
314
|
+
const projectArgs = [
|
|
315
|
+
"project",
|
|
316
|
+
"componentProject",
|
|
317
|
+
"modelProject",
|
|
318
|
+
"registrationProject",
|
|
319
|
+
].filter((arg) => args.includes(arg));
|
|
277
320
|
if (projectArgs.length > 0) {
|
|
278
321
|
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
279
322
|
}
|
|
280
|
-
|
|
323
|
+
|
|
281
324
|
// Add other specific arguments
|
|
282
|
-
const otherArgs = args.filter(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
325
|
+
const otherArgs = args.filter(
|
|
326
|
+
(arg) =>
|
|
327
|
+
!nameArgs.includes(arg) &&
|
|
328
|
+
!projectArgs.includes(arg) &&
|
|
329
|
+
!booleanArgs.includes(arg) &&
|
|
330
|
+
arg !== "interactive"
|
|
287
331
|
);
|
|
288
|
-
|
|
332
|
+
|
|
289
333
|
// Add up to 2 more relevant arguments
|
|
290
334
|
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
291
|
-
|
|
335
|
+
|
|
292
336
|
return relevantArgs;
|
|
293
337
|
};
|
|
294
|
-
|
|
338
|
+
|
|
295
339
|
const relevantArgs = getRelevantArgs(args, command);
|
|
296
|
-
|
|
297
|
-
relevantArgs.forEach(argName => {
|
|
340
|
+
|
|
341
|
+
relevantArgs.forEach((argName) => {
|
|
298
342
|
const value = generateExampleValue(argName);
|
|
299
343
|
basicArgs.push(`--${argName} ${value}`);
|
|
300
344
|
});
|
|
301
|
-
|
|
345
|
+
|
|
302
346
|
// Create advanced example with boolean flags
|
|
303
347
|
const advancedBooleanArgs = [];
|
|
304
|
-
booleanArgs.forEach(argName => {
|
|
348
|
+
booleanArgs.forEach((argName) => {
|
|
305
349
|
if (args.includes(argName)) {
|
|
306
350
|
advancedBooleanArgs.push(`--${argName}`);
|
|
307
351
|
}
|
|
308
352
|
});
|
|
309
|
-
|
|
353
|
+
|
|
310
354
|
// Show basic example
|
|
311
355
|
if (basicArgs.length > 0) {
|
|
312
|
-
console.log(` kosui ${command} ${basicArgs.join(
|
|
356
|
+
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
313
357
|
}
|
|
314
|
-
|
|
358
|
+
|
|
315
359
|
// Show advanced example with boolean flags if any exist
|
|
316
360
|
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
317
|
-
console.log(
|
|
361
|
+
console.log(
|
|
362
|
+
` kosui ${command} ${basicArgs
|
|
363
|
+
.slice(0, 2)
|
|
364
|
+
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
365
|
+
);
|
|
318
366
|
}
|
|
319
|
-
|
|
367
|
+
|
|
320
368
|
// If no basic args, show a minimal example
|
|
321
369
|
if (basicArgs.length === 0) {
|
|
322
370
|
console.log(` kosui ${command} [options]`);
|
|
323
371
|
}
|
|
324
372
|
}
|
|
325
|
-
|
|
373
|
+
|
|
326
374
|
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
327
|
-
console.log(
|
|
375
|
+
console.log(
|
|
376
|
+
` kosui ${command} -i # Force interactive mode (short form)`
|
|
377
|
+
);
|
|
328
378
|
return;
|
|
329
379
|
}
|
|
330
380
|
}
|
|
@@ -345,7 +395,6 @@ async function launch() {
|
|
|
345
395
|
|
|
346
396
|
const meta = await getGeneratorMetadata(command);
|
|
347
397
|
|
|
348
|
-
|
|
349
398
|
if (showBanner) {
|
|
350
399
|
console.log(`--- Running KOS Generator: ${meta?.name || command} ---`);
|
|
351
400
|
}
|
|
@@ -359,6 +408,14 @@ async function launch() {
|
|
|
359
408
|
|
|
360
409
|
// Convert CLI args to answer format using generator's mapping
|
|
361
410
|
const providedAnswers = {};
|
|
411
|
+
|
|
412
|
+
// Ensure we have the metadata with named arguments
|
|
413
|
+
if (!namedArgumentsMap || Object.keys(namedArgumentsMap).length === 0) {
|
|
414
|
+
console.warn(
|
|
415
|
+
`[kos-cli] Warning: No named arguments mapping found for generator '${command}'`
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
362
419
|
Object.entries(namedArgumentsMap).forEach(([cliArg, promptName]) => {
|
|
363
420
|
// Skip 'interactive' - it's handled as a special CLI flag, not a prompt argument
|
|
364
421
|
if (cliArg === "interactive") {
|
|
@@ -421,114 +478,137 @@ async function launch() {
|
|
|
421
478
|
}
|
|
422
479
|
|
|
423
480
|
console.log("\nExamples:");
|
|
424
|
-
|
|
481
|
+
|
|
425
482
|
// Generate examples dynamically from the generator's named arguments
|
|
426
483
|
if (meta?.namedArguments) {
|
|
427
484
|
const args = Object.keys(meta.namedArguments);
|
|
428
|
-
|
|
485
|
+
|
|
429
486
|
// Generate example values based on argument names
|
|
430
487
|
const generateExampleValue = (argName) => {
|
|
431
488
|
switch (argName) {
|
|
432
|
-
case
|
|
433
|
-
case
|
|
434
|
-
return command.includes(
|
|
435
|
-
case
|
|
436
|
-
return
|
|
437
|
-
case
|
|
438
|
-
return
|
|
439
|
-
case
|
|
440
|
-
case
|
|
441
|
-
case
|
|
442
|
-
return
|
|
443
|
-
case
|
|
444
|
-
return
|
|
445
|
-
case
|
|
446
|
-
return
|
|
447
|
-
case
|
|
448
|
-
return
|
|
449
|
-
case
|
|
450
|
-
return
|
|
451
|
-
case
|
|
452
|
-
return
|
|
453
|
-
case
|
|
454
|
-
case
|
|
455
|
-
case
|
|
456
|
-
case
|
|
489
|
+
case "name":
|
|
490
|
+
case "componentName":
|
|
491
|
+
return command.includes("plugin") ? "MyPlugin" : "MyComponent";
|
|
492
|
+
case "modelName":
|
|
493
|
+
return "my-model";
|
|
494
|
+
case "workspaceName":
|
|
495
|
+
return "my-workspace";
|
|
496
|
+
case "project":
|
|
497
|
+
case "componentProject":
|
|
498
|
+
case "modelProject":
|
|
499
|
+
return "my-ui-lib";
|
|
500
|
+
case "registrationProject":
|
|
501
|
+
return "my-lib";
|
|
502
|
+
case "companionParent":
|
|
503
|
+
return "parent-model";
|
|
504
|
+
case "extensionPoint":
|
|
505
|
+
return "utility";
|
|
506
|
+
case "group":
|
|
507
|
+
return "appearance";
|
|
508
|
+
case "locale":
|
|
509
|
+
return "en";
|
|
510
|
+
case "container":
|
|
511
|
+
case "singleton":
|
|
512
|
+
case "parentAware":
|
|
513
|
+
case "dataServices":
|
|
457
514
|
return true;
|
|
458
|
-
case
|
|
515
|
+
case "dryRun":
|
|
459
516
|
return true;
|
|
460
517
|
default:
|
|
461
518
|
return `my-${argName}`;
|
|
462
519
|
}
|
|
463
520
|
};
|
|
464
|
-
|
|
521
|
+
|
|
465
522
|
// Create basic example with most important arguments
|
|
466
523
|
const basicArgs = [];
|
|
467
|
-
const booleanArgs = [
|
|
468
|
-
|
|
524
|
+
const booleanArgs = [
|
|
525
|
+
"container",
|
|
526
|
+
"singleton",
|
|
527
|
+
"parentAware",
|
|
528
|
+
"dataServices",
|
|
529
|
+
"dryRun",
|
|
530
|
+
];
|
|
531
|
+
|
|
469
532
|
// Pick the most relevant arguments for each generator type
|
|
470
533
|
const getRelevantArgs = (args, command) => {
|
|
471
534
|
const relevantArgs = [];
|
|
472
|
-
|
|
535
|
+
|
|
473
536
|
// Always prefer name-type arguments first
|
|
474
|
-
const nameArgs = [
|
|
537
|
+
const nameArgs = [
|
|
538
|
+
"name",
|
|
539
|
+
"componentName",
|
|
540
|
+
"modelName",
|
|
541
|
+
"workspaceName",
|
|
542
|
+
].filter((arg) => args.includes(arg));
|
|
475
543
|
if (nameArgs.length > 0) {
|
|
476
544
|
relevantArgs.push(nameArgs[0]); // Take the first name argument
|
|
477
545
|
}
|
|
478
|
-
|
|
546
|
+
|
|
479
547
|
// Then add project-type arguments
|
|
480
|
-
const projectArgs = [
|
|
548
|
+
const projectArgs = [
|
|
549
|
+
"project",
|
|
550
|
+
"componentProject",
|
|
551
|
+
"modelProject",
|
|
552
|
+
"registrationProject",
|
|
553
|
+
].filter((arg) => args.includes(arg));
|
|
481
554
|
if (projectArgs.length > 0) {
|
|
482
555
|
relevantArgs.push(projectArgs[0]); // Take the first project argument
|
|
483
556
|
}
|
|
484
|
-
|
|
557
|
+
|
|
485
558
|
// Add other specific arguments
|
|
486
|
-
const otherArgs = args.filter(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
559
|
+
const otherArgs = args.filter(
|
|
560
|
+
(arg) =>
|
|
561
|
+
!nameArgs.includes(arg) &&
|
|
562
|
+
!projectArgs.includes(arg) &&
|
|
563
|
+
!booleanArgs.includes(arg) &&
|
|
564
|
+
arg !== "interactive"
|
|
491
565
|
);
|
|
492
|
-
|
|
566
|
+
|
|
493
567
|
// Add up to 2 more relevant arguments
|
|
494
568
|
relevantArgs.push(...otherArgs.slice(0, 2));
|
|
495
|
-
|
|
569
|
+
|
|
496
570
|
return relevantArgs;
|
|
497
571
|
};
|
|
498
|
-
|
|
572
|
+
|
|
499
573
|
const relevantArgs = getRelevantArgs(args, command);
|
|
500
|
-
|
|
501
|
-
relevantArgs.forEach(argName => {
|
|
574
|
+
|
|
575
|
+
relevantArgs.forEach((argName) => {
|
|
502
576
|
const value = generateExampleValue(argName);
|
|
503
577
|
basicArgs.push(`--${argName} ${value}`);
|
|
504
578
|
});
|
|
505
|
-
|
|
579
|
+
|
|
506
580
|
// Create advanced example with boolean flags
|
|
507
581
|
const advancedBooleanArgs = [];
|
|
508
|
-
booleanArgs.forEach(argName => {
|
|
582
|
+
booleanArgs.forEach((argName) => {
|
|
509
583
|
if (args.includes(argName)) {
|
|
510
584
|
advancedBooleanArgs.push(`--${argName}`);
|
|
511
585
|
}
|
|
512
586
|
});
|
|
513
|
-
|
|
587
|
+
|
|
514
588
|
// Show basic example
|
|
515
589
|
if (basicArgs.length > 0) {
|
|
516
|
-
console.log(` kosui ${command} ${basicArgs.join(
|
|
590
|
+
console.log(` kosui ${command} ${basicArgs.join(" ")}`);
|
|
517
591
|
}
|
|
518
|
-
|
|
592
|
+
|
|
519
593
|
// Show advanced example with boolean flags if any exist
|
|
520
594
|
if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
|
|
521
|
-
console.log(
|
|
595
|
+
console.log(
|
|
596
|
+
` kosui ${command} ${basicArgs
|
|
597
|
+
.slice(0, 2)
|
|
598
|
+
.join(" ")} ${advancedBooleanArgs.join(" ")}`
|
|
599
|
+
);
|
|
522
600
|
}
|
|
523
|
-
|
|
601
|
+
|
|
524
602
|
// If no basic args, show a minimal example
|
|
525
603
|
if (basicArgs.length === 0) {
|
|
526
604
|
console.log(` kosui ${command} [options]`);
|
|
527
605
|
}
|
|
528
606
|
}
|
|
529
|
-
|
|
607
|
+
|
|
530
608
|
console.log(` kosui ${command} --interactive # Force interactive mode`);
|
|
531
|
-
console.log(
|
|
609
|
+
console.log(
|
|
610
|
+
` kosui ${command} -i # Force interactive mode (short form)`
|
|
611
|
+
);
|
|
532
612
|
return;
|
|
533
613
|
}
|
|
534
614
|
|
|
@@ -547,14 +627,103 @@ async function launch() {
|
|
|
547
627
|
if (providedValue !== undefined) {
|
|
548
628
|
bypassArgs.push(providedValue);
|
|
549
629
|
} else {
|
|
630
|
+
// Check for workspace defaults for project-type prompts
|
|
631
|
+
let defaultValue = prompt.default;
|
|
632
|
+
|
|
633
|
+
// Use workspace defaults for project selection prompts
|
|
634
|
+
if (
|
|
635
|
+
prompt.name &&
|
|
636
|
+
(prompt.name.includes("Project") || prompt.name === "project")
|
|
637
|
+
) {
|
|
638
|
+
const { getDefaultProjectForType } = await import(
|
|
639
|
+
"./utils/nx-context.mjs"
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
// Determine project type based on command
|
|
643
|
+
let projectType = null;
|
|
644
|
+
if (command === "model" || command.startsWith("model:")) {
|
|
645
|
+
projectType = "model";
|
|
646
|
+
} else if (command === "component") {
|
|
647
|
+
projectType = "model-component";
|
|
648
|
+
} else if (command === "i18n:namespace") {
|
|
649
|
+
projectType = "i18n";
|
|
650
|
+
} else if (command.startsWith("plugin")) {
|
|
651
|
+
projectType = "plugin";
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (projectType) {
|
|
655
|
+
const workspaceDefault = await getDefaultProjectForType(
|
|
656
|
+
projectType
|
|
657
|
+
);
|
|
658
|
+
if (workspaceDefault) {
|
|
659
|
+
defaultValue = workspaceDefault;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// For required project prompts without a default value, we can't bypass - need to show help
|
|
665
|
+
if (
|
|
666
|
+
defaultValue === undefined &&
|
|
667
|
+
(prompt.name === "modelProject" ||
|
|
668
|
+
prompt.name === "project" ||
|
|
669
|
+
prompt.name === "componentProject" ||
|
|
670
|
+
prompt.name === "registrationProject")
|
|
671
|
+
) {
|
|
672
|
+
// Can't bypass required project prompts without a value - show help instead
|
|
673
|
+
console.log(
|
|
674
|
+
`\nError: Missing required argument '--project' (no default project configured)`
|
|
675
|
+
);
|
|
676
|
+
console.log(`\n--- ${meta?.name || command} Help ---`);
|
|
677
|
+
console.log(meta.description || "No description available");
|
|
678
|
+
|
|
679
|
+
if (meta?.namedArguments) {
|
|
680
|
+
console.log("\nNamed Arguments:");
|
|
681
|
+
Object.entries(meta.namedArguments).forEach(
|
|
682
|
+
([cliArg, promptName]) => {
|
|
683
|
+
console.log(` --${cliArg} Maps to prompt: ${promptName}`);
|
|
684
|
+
}
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
console.log("\nTo fix this, you can:");
|
|
689
|
+
console.log(
|
|
690
|
+
"1. Specify a project: kosui " +
|
|
691
|
+
command +
|
|
692
|
+
" --name MyModel --project my-model-lib"
|
|
693
|
+
);
|
|
694
|
+
console.log(
|
|
695
|
+
"2. Configure a default in .kos.json at the workspace root:"
|
|
696
|
+
);
|
|
697
|
+
console.log(
|
|
698
|
+
' { "type": "root", "generator": { "defaults": { "model": "my-default-project" } } }'
|
|
699
|
+
);
|
|
700
|
+
console.log(
|
|
701
|
+
"3. Run in interactive mode: kosui " + command + " --interactive"
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
|
|
550
707
|
// Use default value or skip with "_"
|
|
551
|
-
bypassArgs.push(
|
|
708
|
+
bypassArgs.push(defaultValue !== undefined ? defaultValue : "_");
|
|
552
709
|
}
|
|
553
710
|
}
|
|
554
711
|
|
|
555
712
|
// Only bypass if we have all non-conditional prompts
|
|
556
713
|
const nonConditionalPrompts = prompts.filter((p) => !p.when);
|
|
557
|
-
if
|
|
714
|
+
// Debug: Check if we're trying to bypass with "_" for required fields
|
|
715
|
+
const hasInvalidBypass = bypassArgs.includes("_");
|
|
716
|
+
if (hasInvalidBypass) {
|
|
717
|
+
console.log(
|
|
718
|
+
"[kos-cli] Cannot bypass prompts - missing required values"
|
|
719
|
+
);
|
|
720
|
+
// Fall back to interactive mode
|
|
721
|
+
console.log(
|
|
722
|
+
"Note: Running interactive mode. Your provided arguments will be applied automatically."
|
|
723
|
+
);
|
|
724
|
+
answers = await generator.runPrompts();
|
|
725
|
+
Object.assign(answers, providedAnswers);
|
|
726
|
+
} else if (bypassArgs.length === nonConditionalPrompts.length) {
|
|
558
727
|
// We can bypass all non-conditional prompts
|
|
559
728
|
answers = await generator.runPrompts(bypassArgs);
|
|
560
729
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// generators/component/index.mjs
|
|
2
2
|
import { actionFactory } from "../../utils/action-factory.mjs";
|
|
3
3
|
import { execute } from "../../utils/exec.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { getComponentCompatibleProjectsWithFallback } from "../../utils/nx-context.mjs";
|
|
5
5
|
import { required } from "../../utils/validators.mjs";
|
|
6
6
|
|
|
7
7
|
export const metadata = {
|
|
@@ -16,7 +16,7 @@ export const metadata = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export default async function (plop) {
|
|
19
|
-
const
|
|
19
|
+
const componentProjects = await getComponentCompatibleProjectsWithFallback();
|
|
20
20
|
|
|
21
21
|
plop.setActionType("createComponent", async function (answers) {
|
|
22
22
|
const command = `npx nx generate @kosdev-code/kos-nx-plugin:kos-component \
|
|
@@ -47,7 +47,7 @@ export default async function (plop) {
|
|
|
47
47
|
type: "list",
|
|
48
48
|
name: "componentProject",
|
|
49
49
|
message: "Which project should the component be created in?",
|
|
50
|
-
choices:
|
|
50
|
+
choices: componentProjects,
|
|
51
51
|
},
|
|
52
52
|
],
|
|
53
53
|
actions: actionFactory("createComponent", metadata),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { actionFactory } from "../../utils/action-factory.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { getI18nProjectsWithFallback, getProjectDetails } from "../../utils/nx-context.mjs";
|
|
6
6
|
import { required } from "../../utils/validators.mjs";
|
|
7
7
|
|
|
8
8
|
export const metadata = {
|
|
@@ -16,7 +16,7 @@ export const metadata = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export default async function (plop) {
|
|
19
|
-
const
|
|
19
|
+
const i18nProjects = await getI18nProjectsWithFallback();
|
|
20
20
|
|
|
21
21
|
plop.setActionType("addNamespace", async function (answers) {
|
|
22
22
|
const i18nProject = await getProjectDetails(answers.project);
|
|
@@ -53,7 +53,7 @@ export default async function (plop) {
|
|
|
53
53
|
type: "list",
|
|
54
54
|
name: "project",
|
|
55
55
|
message: "Which project should the namespace be created in?",
|
|
56
|
-
choices:
|
|
56
|
+
choices: i18nProjects,
|
|
57
57
|
},
|
|
58
58
|
],
|
|
59
59
|
actions: actionFactory("addNamespace", metadata),
|
|
@@ -3,7 +3,7 @@ import { actionFactory } from "../../utils/action-factory.mjs";
|
|
|
3
3
|
import { execute } from "../../utils/exec.mjs";
|
|
4
4
|
import {
|
|
5
5
|
getAllModels,
|
|
6
|
-
|
|
6
|
+
getModelProjectsWithFallback,
|
|
7
7
|
getProjectDetails,
|
|
8
8
|
} from "../../utils/nx-context.mjs";
|
|
9
9
|
import {
|
|
@@ -34,7 +34,7 @@ export const metadata = {
|
|
|
34
34
|
|
|
35
35
|
export default async function (plop) {
|
|
36
36
|
const allModels = await getAllModels();
|
|
37
|
-
const libraryProjects = await
|
|
37
|
+
const libraryProjects = await getModelProjectsWithFallback();
|
|
38
38
|
const modelChoices = allModels.map((m) => ({
|
|
39
39
|
name: `${m.model} (${m.project})`,
|
|
40
40
|
value: m.model,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { actionFactory } from "../../utils/action-factory.mjs";
|
|
3
3
|
import { execute } from "../../utils/exec.mjs";
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
getModelProjectsWithFallback,
|
|
6
6
|
getProjectDetails,
|
|
7
7
|
} from "../../utils/nx-context.mjs";
|
|
8
8
|
import { DEFAULT_PROMPTS, MODEL_PROMPTS } from "../../utils/prompts.mjs";
|
|
@@ -28,7 +28,7 @@ export const metadata = {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export default async function (plop) {
|
|
31
|
-
const libraryProjects = await
|
|
31
|
+
const libraryProjects = await getModelProjectsWithFallback();
|
|
32
32
|
|
|
33
33
|
plop.setActionType("createModel", async function (answers) {
|
|
34
34
|
const modelProject = await getProjectDetails(answers.modelProject);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// generators/plugin/plugin.mjs
|
|
2
2
|
|
|
3
3
|
import { execute } from "../../utils/exec.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { getPluginProjectsWithFallback } from "../../utils/nx-context.mjs";
|
|
5
5
|
import { required } from "../../utils/validators.mjs";
|
|
6
6
|
export const metadata = [
|
|
7
7
|
{
|
|
@@ -79,7 +79,7 @@ export const metadata = [
|
|
|
79
79
|
];
|
|
80
80
|
|
|
81
81
|
export default async function (plop) {
|
|
82
|
-
const
|
|
82
|
+
const pluginProjects = await getPluginProjectsWithFallback();
|
|
83
83
|
|
|
84
84
|
plop.setActionType("createPluginComponent", async function (answers) {
|
|
85
85
|
const pluginType = answers.extensionPoint;
|
|
@@ -105,7 +105,7 @@ export default async function (plop) {
|
|
|
105
105
|
type: "list",
|
|
106
106
|
name: "componentProject",
|
|
107
107
|
message: "Which project should the component be created in?",
|
|
108
|
-
choices:
|
|
108
|
+
choices: pluginProjects,
|
|
109
109
|
},
|
|
110
110
|
];
|
|
111
111
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// utils/nx-context.mjs
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { getCached, setCached } from "./cache.mjs";
|
|
@@ -12,6 +12,45 @@ function execJson(cmd) {
|
|
|
12
12
|
return JSON.parse(output);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function findKosJsonFiles(dir = process.cwd(), files = []) {
|
|
16
|
+
try {
|
|
17
|
+
const entries = readdirSync(dir);
|
|
18
|
+
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
// Skip common directories that won't have .kos.json files
|
|
21
|
+
// BUT don't skip .kos.json files themselves!
|
|
22
|
+
if (entry === 'node_modules' || entry === '.git' || entry === '.nx' ||
|
|
23
|
+
entry === 'dist' || entry === 'coverage' || entry === '.vscode' ||
|
|
24
|
+
entry === '.idea' || (entry.startsWith('.') && entry !== '.kos.json')) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const fullPath = path.join(dir, entry);
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const stat = statSync(fullPath);
|
|
32
|
+
|
|
33
|
+
if (stat.isFile() && entry === '.kos.json') {
|
|
34
|
+
files.push(fullPath);
|
|
35
|
+
} else if (stat.isDirectory()) {
|
|
36
|
+
// Only recurse into directories that might contain projects
|
|
37
|
+
// Skip common build/temp directories
|
|
38
|
+
if (entry !== 'tmp' && entry !== 'temp' && entry !== 'build') {
|
|
39
|
+
findKosJsonFiles(fullPath, files);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// Skip files/directories we can't access
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
// Skip directories we can't read
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return files;
|
|
52
|
+
}
|
|
53
|
+
|
|
15
54
|
let _workspaceDetected;
|
|
16
55
|
|
|
17
56
|
export async function detectWorkspace(startDir = process.cwd()) {
|
|
@@ -61,43 +100,270 @@ export async function getPluginProjects() {
|
|
|
61
100
|
return filtered;
|
|
62
101
|
}
|
|
63
102
|
|
|
64
|
-
export async function
|
|
65
|
-
const cached = getCached("
|
|
103
|
+
export async function getAllKosProjects() {
|
|
104
|
+
const cached = getCached("allKosProjects");
|
|
66
105
|
if (cached) return cached;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
return list;
|
|
81
|
-
}
|
|
82
|
-
const kosConfig = JSON.parse(readFileSync(kosConfigPath, "utf-8"));
|
|
83
|
-
if (kosConfig.models) {
|
|
84
|
-
Object.keys(kosConfig.models).forEach((model) => {
|
|
85
|
-
list.push({ model: model, project: project.name });
|
|
86
|
-
});
|
|
106
|
+
|
|
107
|
+
console.warn(`[kos-cli] Discovering KOS projects by scanning .kos.json files...`);
|
|
108
|
+
|
|
109
|
+
// In an NX workspace, focus on common project directories first
|
|
110
|
+
const projectDirs = ['apps', 'libs', 'packages'];
|
|
111
|
+
const kosJsonFiles = [];
|
|
112
|
+
const workspaceRoot = process.cwd();
|
|
113
|
+
|
|
114
|
+
// First scan common project directories
|
|
115
|
+
for (const dir of projectDirs) {
|
|
116
|
+
const dirPath = path.join(workspaceRoot, dir);
|
|
117
|
+
if (existsSync(dirPath)) {
|
|
118
|
+
findKosJsonFiles(dirPath, kosJsonFiles);
|
|
87
119
|
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Also check the workspace root for any .kos.json files
|
|
123
|
+
const rootKosJson = path.join(workspaceRoot, '.kos.json');
|
|
124
|
+
if (existsSync(rootKosJson)) {
|
|
125
|
+
kosJsonFiles.push(rootKosJson);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// If we didn't find any in the common directories, fall back to full scan
|
|
129
|
+
if (kosJsonFiles.length === 0) {
|
|
130
|
+
console.warn(`[kos-cli] No .kos.json files found in common directories, performing full workspace scan...`);
|
|
131
|
+
findKosJsonFiles(workspaceRoot, kosJsonFiles);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const kosProjects = [];
|
|
88
135
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
136
|
+
for (const kosJsonPath of kosJsonFiles) {
|
|
137
|
+
try {
|
|
138
|
+
const kosConfig = JSON.parse(readFileSync(kosJsonPath, "utf-8"));
|
|
139
|
+
const projectDir = path.dirname(kosJsonPath);
|
|
140
|
+
|
|
141
|
+
// Try to determine the project name by looking for project.json
|
|
142
|
+
let projectName = null;
|
|
143
|
+
const projectJsonPath = path.join(projectDir, 'project.json');
|
|
144
|
+
|
|
145
|
+
if (existsSync(projectJsonPath)) {
|
|
146
|
+
try {
|
|
147
|
+
const projectJson = JSON.parse(readFileSync(projectJsonPath, "utf-8"));
|
|
148
|
+
projectName = projectJson.name;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// If we can't read project.json, use directory name as fallback
|
|
151
|
+
projectName = path.basename(projectDir);
|
|
152
|
+
}
|
|
92
153
|
} else {
|
|
93
|
-
|
|
154
|
+
// Use directory name as fallback
|
|
155
|
+
projectName = path.basename(projectDir);
|
|
94
156
|
}
|
|
157
|
+
|
|
158
|
+
// Skip root-type configurations as they are not projects
|
|
159
|
+
if (kosConfig.type === 'root') {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
kosProjects.push({
|
|
164
|
+
name: projectName,
|
|
165
|
+
path: projectDir,
|
|
166
|
+
kosJsonPath,
|
|
167
|
+
config: kosConfig,
|
|
168
|
+
projectType: kosConfig.generator?.projectType
|
|
169
|
+
});
|
|
170
|
+
} catch (error) {
|
|
171
|
+
console.warn(`[kos-cli] Error reading ${kosJsonPath}: ${error.message}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setCached("allKosProjects", kosProjects);
|
|
176
|
+
return kosProjects;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function getProjectsByType(targetType) {
|
|
180
|
+
const cacheKey = `projectsByType:${targetType}`;
|
|
181
|
+
const cached = getCached(cacheKey);
|
|
182
|
+
if (cached) return cached;
|
|
183
|
+
|
|
184
|
+
console.warn(`[kos-cli] Filtering projects for ${targetType} projectType...`);
|
|
185
|
+
const allKosProjects = await getAllKosProjects();
|
|
186
|
+
const filteredProjects = [];
|
|
187
|
+
|
|
188
|
+
for (const kosProject of allKosProjects) {
|
|
189
|
+
const projectType = kosProject.projectType;
|
|
190
|
+
|
|
191
|
+
// Handle both string and array formats for projectType
|
|
192
|
+
const hasTargetType = Array.isArray(projectType)
|
|
193
|
+
? projectType.includes(targetType)
|
|
194
|
+
: projectType === targetType;
|
|
195
|
+
|
|
196
|
+
if (hasTargetType) {
|
|
197
|
+
filteredProjects.push(kosProject.name);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
setCached(cacheKey, filteredProjects);
|
|
202
|
+
return filteredProjects;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export async function getModelProjects() {
|
|
206
|
+
return await getProjectsByType("model");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function getUIProjects() {
|
|
210
|
+
return await getProjectsByType("ui");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export async function getModelComponentProjects() {
|
|
214
|
+
return await getProjectsByType("model-component");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export async function getI18nProjects() {
|
|
218
|
+
return await getProjectsByType("i18n");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
export async function getProjectsByTypeWithFallback(targetType, fallbackFunction = getLibraryProjects) {
|
|
223
|
+
const filteredProjects = await getProjectsByType(targetType);
|
|
224
|
+
|
|
225
|
+
if (filteredProjects.length > 0) {
|
|
226
|
+
console.warn(`[kos-cli] Found ${filteredProjects.length} ${targetType} projects`);
|
|
227
|
+
return filteredProjects;
|
|
228
|
+
} else {
|
|
229
|
+
console.warn(`[kos-cli] No ${targetType} projects found, showing fallback projects`);
|
|
230
|
+
return await fallbackFunction();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export async function getModelProjectsWithFallback() {
|
|
235
|
+
return await getProjectsByTypeWithFallback("model", getLibraryProjects);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export async function getModelComponentProjectsWithFallback() {
|
|
239
|
+
return await getProjectsByTypeWithFallback("model-component", getAllProjects);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function getProjectsByMultipleTypes(targetTypes) {
|
|
243
|
+
const cacheKey = `projectsByMultipleTypes:${targetTypes.join(',')}`;
|
|
244
|
+
const cached = getCached(cacheKey);
|
|
245
|
+
if (cached) return cached;
|
|
246
|
+
|
|
247
|
+
console.warn(`[kos-cli] Filtering projects for projectTypes: ${targetTypes.join(', ')}...`);
|
|
248
|
+
const allKosProjects = await getAllKosProjects();
|
|
249
|
+
const filteredProjects = [];
|
|
250
|
+
|
|
251
|
+
for (const kosProject of allKosProjects) {
|
|
252
|
+
const projectType = kosProject.projectType;
|
|
253
|
+
|
|
254
|
+
// Handle both string and array formats for projectType
|
|
255
|
+
const hasAnyTargetType = targetTypes.some(targetType => {
|
|
256
|
+
return Array.isArray(projectType)
|
|
257
|
+
? projectType.includes(targetType)
|
|
258
|
+
: projectType === targetType;
|
|
95
259
|
});
|
|
96
|
-
|
|
260
|
+
|
|
261
|
+
if (hasAnyTargetType) {
|
|
262
|
+
filteredProjects.push(kosProject.name);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
setCached(cacheKey, filteredProjects);
|
|
267
|
+
return filteredProjects;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export async function getComponentCompatibleProjects() {
|
|
271
|
+
return await getProjectsByMultipleTypes(["ui", "splash", "model-component"]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export async function getComponentCompatibleProjectsWithFallback() {
|
|
275
|
+
const componentProjects = await getComponentCompatibleProjects();
|
|
276
|
+
|
|
277
|
+
if (componentProjects.length > 0) {
|
|
278
|
+
console.warn(`[kos-cli] Found ${componentProjects.length} component-compatible projects`);
|
|
279
|
+
return componentProjects;
|
|
280
|
+
} else {
|
|
281
|
+
console.warn(`[kos-cli] No component-compatible projects found, showing all projects`);
|
|
282
|
+
return await getAllProjects();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export async function getI18nProjectsWithFallback() {
|
|
287
|
+
return await getProjectsByTypeWithFallback("i18n", getAllProjects);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export async function getPluginProjectsWithFallback() {
|
|
291
|
+
// First try type-based filtering
|
|
292
|
+
const pluginProjectsByType = await getProjectsByType("plugin");
|
|
293
|
+
if (pluginProjectsByType.length > 0) {
|
|
294
|
+
console.warn(`[kos-cli] Found ${pluginProjectsByType.length} plugin projects by type`);
|
|
295
|
+
return pluginProjectsByType;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Fall back to existing name-based filtering
|
|
299
|
+
const pluginProjectsByName = await getPluginProjects();
|
|
300
|
+
if (pluginProjectsByName.length > 0) {
|
|
301
|
+
console.warn(`[kos-cli] Found ${pluginProjectsByName.length} plugin projects by name`);
|
|
302
|
+
return pluginProjectsByName;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Final fallback to all projects
|
|
306
|
+
console.warn(`[kos-cli] No plugin projects found, showing all projects`);
|
|
307
|
+
return await getAllProjects();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export async function getAllModels() {
|
|
311
|
+
const cached = getCached("allModels");
|
|
312
|
+
if (cached) return cached;
|
|
313
|
+
|
|
314
|
+
console.warn(`[kos-cli] Scanning for models in KOS projects...`);
|
|
315
|
+
const allKosProjects = await getAllKosProjects();
|
|
316
|
+
const models = [];
|
|
317
|
+
|
|
318
|
+
for (const kosProject of allKosProjects) {
|
|
319
|
+
if (kosProject.config.models) {
|
|
320
|
+
Object.keys(kosProject.config.models).forEach((model) => {
|
|
321
|
+
models.push({ model: model, project: kosProject.name });
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Sort models by project name first, then by model name
|
|
327
|
+
models.sort((a, b) => {
|
|
328
|
+
if (a.project === b.project) {
|
|
329
|
+
return a.model.localeCompare(b.model);
|
|
330
|
+
} else {
|
|
331
|
+
return a.project.localeCompare(b.project);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
97
335
|
setCached("allModels", models);
|
|
98
336
|
return models;
|
|
99
337
|
}
|
|
100
338
|
|
|
339
|
+
export async function getWorkspaceDefaults() {
|
|
340
|
+
const cached = getCached("workspaceDefaults");
|
|
341
|
+
if (cached) return cached;
|
|
342
|
+
|
|
343
|
+
const workspaceRoot = process.cwd();
|
|
344
|
+
const rootKosJsonPath = path.join(workspaceRoot, '.kos.json');
|
|
345
|
+
|
|
346
|
+
if (existsSync(rootKosJsonPath)) {
|
|
347
|
+
try {
|
|
348
|
+
const rootConfig = JSON.parse(readFileSync(rootKosJsonPath, "utf-8"));
|
|
349
|
+
if (rootConfig.type === 'root' && rootConfig.generator?.defaults) {
|
|
350
|
+
setCached("workspaceDefaults", rootConfig.generator.defaults);
|
|
351
|
+
return rootConfig.generator.defaults;
|
|
352
|
+
}
|
|
353
|
+
} catch (error) {
|
|
354
|
+
console.warn(`[kos-cli] Error reading workspace defaults: ${error.message}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
setCached("workspaceDefaults", {});
|
|
359
|
+
return {};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export async function getDefaultProjectForType(projectType) {
|
|
363
|
+
const defaults = await getWorkspaceDefaults();
|
|
364
|
+
return defaults[projectType] || null;
|
|
365
|
+
}
|
|
366
|
+
|
|
101
367
|
export async function getProjectDetails(projectName) {
|
|
102
368
|
const cacheKey = `projectDetails:${projectName}`;
|
|
103
369
|
const cached = getCached(cacheKey);
|