@kosdev-code/kos-ui-cli 2.0.30 → 2.0.31

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kosdev-code/kos-ui-cli",
3
- "version": "2.0.30",
3
+ "version": "2.0.31",
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": "0f92875bc028bb7f4c46e8a12c3be28c1ca3c2ca"
23
+ "gitHash": "d7b8c63a9bfe61bb6177f4e7628bbb17e3696c2b"
24
24
  }
25
25
  },
26
26
  "publishConfig": {
package/src/lib/cli.mjs CHANGED
@@ -37,9 +37,22 @@ async function launch() {
37
37
 
38
38
  if (!command || command === "help") {
39
39
  console.warn("--- KOS CLI Help ---");
40
+ console.log("\nAvailable Generators:");
40
41
  plop.getGeneratorList().forEach((g) => {
41
42
  console.log(`- ${g.name}: ${g.description}`);
42
43
  });
44
+
45
+ console.log("\nUsage:");
46
+ console.log(" kosui <generator> [options]");
47
+ console.log(" kosui <generator> --help # Show generator-specific help");
48
+ console.log("\nGlobal Options:");
49
+ console.log(" --no-cache Disable cache");
50
+ console.log(" --refresh Clear cache and refresh");
51
+ console.log(
52
+ " --interactive, -i Force interactive mode (ignore provided arguments)"
53
+ );
54
+ console.log(" --help Show this help");
55
+
43
56
  return;
44
57
  }
45
58
 
@@ -49,13 +62,245 @@ async function launch() {
49
62
  console.error(`[kos-cli] Generator "${command}" not found.`);
50
63
  process.exit(1);
51
64
  }
65
+
52
66
  const meta = await getGeneratorMetadata(command);
67
+
68
+ // Show generator-specific help if requested
69
+ if (parsedArgs.help) {
70
+ console.log(`--- ${meta?.name || command} Help ---`);
71
+ console.log(generator.description || "No description available");
72
+
73
+ if (meta?.namedArguments) {
74
+ console.log("\nNamed Arguments:");
75
+ Object.entries(meta.namedArguments).forEach(([cliArg, promptName]) => {
76
+ console.log(` --${cliArg} Maps to prompt: ${promptName}`);
77
+ });
78
+ }
79
+
80
+ console.log("\nExamples:");
81
+
82
+ // Generate examples dynamically from the generator's named arguments
83
+ if (meta?.namedArguments) {
84
+ const args = Object.keys(meta.namedArguments);
85
+
86
+ // Generate example values based on argument names
87
+ const generateExampleValue = (argName) => {
88
+ switch (argName) {
89
+ case 'name':
90
+ case 'componentName':
91
+ return command.includes('plugin') ? 'MyPlugin' : 'MyComponent';
92
+ case 'modelName':
93
+ return 'my-model';
94
+ case 'workspaceName':
95
+ return 'my-workspace';
96
+ case 'project':
97
+ case 'componentProject':
98
+ case 'modelProject':
99
+ return 'my-ui-lib';
100
+ case 'registrationProject':
101
+ return 'my-lib';
102
+ case 'companionParent':
103
+ return 'parent-model';
104
+ case 'extensionPoint':
105
+ return 'utility';
106
+ case 'group':
107
+ return 'appearance';
108
+ case 'locale':
109
+ return 'en';
110
+ case 'container':
111
+ case 'singleton':
112
+ case 'parentAware':
113
+ case 'dataServices':
114
+ return true;
115
+ case 'dryRun':
116
+ return true;
117
+ default:
118
+ return `my-${argName}`;
119
+ }
120
+ };
121
+
122
+ // Create basic example with most important arguments
123
+ const basicArgs = [];
124
+ const booleanArgs = ['container', 'singleton', 'parentAware', 'dataServices', 'dryRun'];
125
+
126
+ // Pick the most relevant arguments for each generator type
127
+ const getRelevantArgs = (args, command) => {
128
+ const relevantArgs = [];
129
+
130
+ // Always prefer name-type arguments first
131
+ const nameArgs = ['name', 'componentName', 'modelName', 'workspaceName'].filter(arg => args.includes(arg));
132
+ if (nameArgs.length > 0) {
133
+ relevantArgs.push(nameArgs[0]); // Take the first name argument
134
+ }
135
+
136
+ // Then add project-type arguments
137
+ const projectArgs = ['project', 'componentProject', 'modelProject', 'registrationProject'].filter(arg => args.includes(arg));
138
+ if (projectArgs.length > 0) {
139
+ relevantArgs.push(projectArgs[0]); // Take the first project argument
140
+ }
141
+
142
+ // Add other specific arguments
143
+ const otherArgs = args.filter(arg =>
144
+ !nameArgs.includes(arg) &&
145
+ !projectArgs.includes(arg) &&
146
+ !booleanArgs.includes(arg) &&
147
+ arg !== 'interactive'
148
+ );
149
+
150
+ // Add up to 2 more relevant arguments
151
+ relevantArgs.push(...otherArgs.slice(0, 2));
152
+
153
+ return relevantArgs;
154
+ };
155
+
156
+ const relevantArgs = getRelevantArgs(args, command);
157
+
158
+ relevantArgs.forEach(argName => {
159
+ const value = generateExampleValue(argName);
160
+ basicArgs.push(`--${argName} ${value}`);
161
+ });
162
+
163
+ // Create advanced example with boolean flags
164
+ const advancedBooleanArgs = [];
165
+ booleanArgs.forEach(argName => {
166
+ if (args.includes(argName)) {
167
+ advancedBooleanArgs.push(`--${argName}`);
168
+ }
169
+ });
170
+
171
+ // Show basic example
172
+ if (basicArgs.length > 0) {
173
+ console.log(` kosui ${command} ${basicArgs.join(' ')}`);
174
+ }
175
+
176
+ // Show advanced example with boolean flags if any exist
177
+ if (basicArgs.length > 0 && advancedBooleanArgs.length > 0) {
178
+ console.log(` kosui ${command} ${basicArgs.slice(0, 2).join(' ')} ${advancedBooleanArgs.join(' ')}`);
179
+ }
180
+
181
+ // If no basic args, show a minimal example
182
+ if (basicArgs.length === 0) {
183
+ console.log(` kosui ${command} [options]`);
184
+ }
185
+ }
186
+
187
+ console.log(` kosui ${command} --interactive # Force interactive mode`);
188
+ console.log(` kosui ${command} -i # Force interactive mode (short form)`);
189
+ return;
190
+ }
191
+
53
192
  if (showBanner) {
54
193
  console.log(`--- Running KOS Generator: ${meta?.name || command} ---`);
55
194
  }
56
195
 
57
196
  try {
58
- const answers = await generator.runPrompts();
197
+ // Extract positional arguments for prompt bypass
198
+ const positionalArgs = parsedArgs._.slice(1); // Remove command from args
199
+
200
+ // Get named arguments mapping from generator metadata
201
+ const namedArgumentsMap = meta?.namedArguments || {};
202
+
203
+ // Convert CLI args to answer format using generator's mapping
204
+ const providedAnswers = {};
205
+ Object.entries(namedArgumentsMap).forEach(([cliArg, promptName]) => {
206
+ // Skip 'interactive' - it's handled as a special CLI flag, not a prompt argument
207
+ if (cliArg === "interactive") {
208
+ return;
209
+ }
210
+
211
+ if (parsedArgs[cliArg] !== undefined) {
212
+ let value = parsedArgs[cliArg];
213
+
214
+ // Convert string boolean values to actual booleans
215
+ if (value === "true" || value === "y" || value === "yes") {
216
+ value = true;
217
+ } else if (value === "false" || value === "n" || value === "no") {
218
+ value = false;
219
+ }
220
+
221
+ providedAnswers[promptName] = value;
222
+ }
223
+ });
224
+
225
+ // Also handle positional arguments
226
+ const prompts = generator.prompts || [];
227
+ positionalArgs.forEach((arg, index) => {
228
+ if (prompts[index] && !prompts[index].when) {
229
+ // Only non-conditional prompts
230
+ const promptName = prompts[index].name;
231
+ if (providedAnswers[promptName] === undefined) {
232
+ let value = arg;
233
+
234
+ // Convert string boolean values to actual booleans
235
+ if (value === "true" || value === "y" || value === "yes") {
236
+ value = true;
237
+ } else if (value === "false" || value === "n" || value === "no") {
238
+ value = false;
239
+ }
240
+
241
+ providedAnswers[promptName] = value;
242
+ }
243
+ }
244
+ });
245
+
246
+ // Check if we have ANY provided answers
247
+ const hasAnyAnswers = Object.keys(providedAnswers).length > 0;
248
+
249
+ let answers;
250
+
251
+ // Check if user wants to force interactive mode
252
+ const forceInteractive = parsedArgs.interactive || parsedArgs.i;
253
+
254
+ if (hasAnyAnswers && !forceInteractive) {
255
+ // Create bypass array for all prompts
256
+ const bypassArgs = [];
257
+
258
+ // Fill bypass array with provided values or defaults
259
+ for (const prompt of prompts) {
260
+ if (prompt.when) {
261
+ // Skip conditional prompts - they can't be bypassed
262
+ continue;
263
+ }
264
+
265
+ const providedValue = providedAnswers[prompt.name];
266
+ if (providedValue !== undefined) {
267
+ bypassArgs.push(providedValue);
268
+ } else {
269
+ // Use default value or skip with "_"
270
+ bypassArgs.push(prompt.default !== undefined ? prompt.default : "_");
271
+ }
272
+ }
273
+
274
+ // Only bypass if we have all non-conditional prompts
275
+ const nonConditionalPrompts = prompts.filter((p) => !p.when);
276
+ if (bypassArgs.length === nonConditionalPrompts.length) {
277
+ // We can bypass all non-conditional prompts
278
+ answers = await generator.runPrompts(bypassArgs);
279
+
280
+ // Add any conditional prompt values that were provided
281
+ Object.assign(answers, providedAnswers);
282
+ } else {
283
+ // Fall back to interactive mode
284
+ console.log(
285
+ "Note: Running interactive mode. Your provided arguments will be applied automatically."
286
+ );
287
+ answers = await generator.runPrompts();
288
+ Object.assign(answers, providedAnswers);
289
+ }
290
+ } else {
291
+ // Run prompts interactively
292
+ if (forceInteractive) {
293
+ console.log(
294
+ "Note: Running in interactive mode. All prompts will be shown."
295
+ );
296
+
297
+ // In interactive mode, ignore provided arguments and run all prompts
298
+ answers = await generator.runPrompts();
299
+ } else {
300
+ answers = await generator.runPrompts();
301
+ }
302
+ }
303
+
59
304
  const results = await generator.runActions(answers);
60
305
 
61
306
  console.log("[kos-cli] Generator completed successfully!");
@@ -7,6 +7,12 @@ import { required } from "../../utils/validators.mjs";
7
7
  export const metadata = {
8
8
  key: "component",
9
9
  name: "KOS React Component",
10
+ namedArguments: {
11
+ name: "componentName",
12
+ componentName: "componentName",
13
+ project: "componentProject",
14
+ componentProject: "componentProject"
15
+ }
10
16
  };
11
17
 
12
18
  export default async function (plop) {
@@ -8,6 +8,11 @@ import { required } from "../../utils/validators.mjs";
8
8
  export const metadata = {
9
9
  key: "i18n:namespace",
10
10
  name: "KOS i18n Project Namespace",
11
+ namedArguments: {
12
+ name: "name",
13
+ locale: "locale",
14
+ project: "project",
15
+ },
11
16
  };
12
17
 
13
18
  export default async function (plop) {
@@ -12,6 +12,19 @@ import { required } from "../../utils/validators.mjs";
12
12
  export const metadata = {
13
13
  key: "model:companion",
14
14
  name: "KOS Companion Model",
15
+ namedArguments: {
16
+ name: "modelName",
17
+ modelName: "modelName",
18
+ project: "modelProject",
19
+ modelProject: "modelProject",
20
+ companionParent: "companionParent",
21
+ container: "container",
22
+ parentAware: "parentAware",
23
+ singleton: "singleton",
24
+ dataServices: "dataServices",
25
+ dryRun: "dryRun",
26
+ interactive: "interactive"
27
+ }
15
28
  };
16
29
 
17
30
  export default async function (plop) {
@@ -11,6 +11,16 @@ import { DEFAULT_PROMPTS, MODEL_PROMPTS } from "../../utils/prompts.mjs";
11
11
  export const metadata = {
12
12
  key: "container",
13
13
  name: "KOS Container Model",
14
+ namedArguments: {
15
+ modelName: "modelName",
16
+ registrationProject: "registrationProject",
17
+ container: "container",
18
+ parentAware: "parentAware",
19
+ singleton: "singleton",
20
+ dataServices: "dataServices",
21
+ dryRun: "dryRun",
22
+ interactive: "interactive",
23
+ },
14
24
  };
15
25
 
16
26
  export default async function (plop) {
@@ -5,6 +5,11 @@ import { getAllModels, getAllProjects } from "../../utils/nx-context.mjs";
5
5
  export const metadata = {
6
6
  key: "context",
7
7
  name: "KOS Model React Context",
8
+ namedArguments: {
9
+ modelName: "modelName",
10
+ componentProject: "componentProject",
11
+ project: "componentProject",
12
+ },
8
13
  };
9
14
 
10
15
  export default async function (plop) {
@@ -5,6 +5,11 @@ import { getAllModels, getAllProjects } from "../../utils/nx-context.mjs";
5
5
  export const metadata = {
6
6
  key: "hook",
7
7
  name: "KOS Model React Hook",
8
+ namedArguments: {
9
+ modelName: "modelName",
10
+ componentProject: "componentProject",
11
+ project: "componentProject"
12
+ }
8
13
  };
9
14
 
10
15
  export default async function (plop) {
@@ -13,6 +13,18 @@ export const metadata = {
13
13
  key: "model",
14
14
  name: "KOS Model",
15
15
  invalidateCache: true,
16
+ namedArguments: {
17
+ name: "modelName",
18
+ modelName: "modelName",
19
+ project: "modelProject",
20
+ modelProject: "modelProject",
21
+ container: "container",
22
+ parentAware: "parentAware",
23
+ singleton: "singleton",
24
+ dataServices: "dataServices",
25
+ dryRun: "dryRun",
26
+ interactive: "interactive"
27
+ }
16
28
  };
17
29
 
18
30
  export default async function (plop) {
@@ -4,13 +4,78 @@ import { execute } from "../../utils/exec.mjs";
4
4
  import { getAllProjects } from "../../utils/nx-context.mjs";
5
5
  import { required } from "../../utils/validators.mjs";
6
6
  export const metadata = [
7
- { key: "pluginComponent", name: "KOS UI Plugin Component" },
8
- { key: "plugin:cui", name: "KOS UI Plugin CUI Configuration" },
9
- { key: "plugin:setup", name: "KOS UI Plugin Setup Step" },
10
- { key: "plugin:utility", name: "KOS UI Plugin Utility" },
11
- { key: "plugin:setting", name: "KOS UI Plugin Setting" },
12
- { key: "plugin:nav", name: "KOS UI Plugin Navigation View" },
13
- { key: "plugin:cp", name: "KOS UI Plugin Control Pour" },
7
+ {
8
+ key: "pluginComponent",
9
+ name: "KOS UI Plugin Component",
10
+ namedArguments: {
11
+ name: "componentName",
12
+ componentName: "componentName",
13
+ project: "componentProject",
14
+ componentProject: "componentProject",
15
+ extensionPoint: "extensionPoint"
16
+ }
17
+ },
18
+ {
19
+ key: "plugin:cui",
20
+ name: "KOS UI Plugin CUI Configuration",
21
+ namedArguments: {
22
+ name: "componentName",
23
+ componentName: "componentName",
24
+ project: "componentProject",
25
+ componentProject: "componentProject"
26
+ }
27
+ },
28
+ {
29
+ key: "plugin:setup",
30
+ name: "KOS UI Plugin Setup Step",
31
+ namedArguments: {
32
+ name: "componentName",
33
+ componentName: "componentName",
34
+ project: "componentProject",
35
+ componentProject: "componentProject"
36
+ }
37
+ },
38
+ {
39
+ key: "plugin:utility",
40
+ name: "KOS UI Plugin Utility",
41
+ namedArguments: {
42
+ name: "componentName",
43
+ componentName: "componentName",
44
+ project: "componentProject",
45
+ componentProject: "componentProject"
46
+ }
47
+ },
48
+ {
49
+ key: "plugin:setting",
50
+ name: "KOS UI Plugin Setting",
51
+ namedArguments: {
52
+ name: "componentName",
53
+ componentName: "componentName",
54
+ project: "componentProject",
55
+ componentProject: "componentProject",
56
+ group: "group"
57
+ }
58
+ },
59
+ {
60
+ key: "plugin:nav",
61
+ name: "KOS UI Plugin Navigation View",
62
+ namedArguments: {
63
+ name: "componentName",
64
+ componentName: "componentName",
65
+ project: "componentProject",
66
+ componentProject: "componentProject"
67
+ }
68
+ },
69
+ {
70
+ key: "plugin:cp",
71
+ name: "KOS UI Plugin Control Pour",
72
+ namedArguments: {
73
+ name: "componentName",
74
+ componentName: "componentName",
75
+ project: "componentProject",
76
+ componentProject: "componentProject"
77
+ }
78
+ },
14
79
  ];
15
80
 
16
81
  export default async function (plop) {
@@ -7,6 +7,7 @@ export const metadata = {
7
7
  key: "project",
8
8
  name: "KOS UI App Project",
9
9
  invalidateCache: true,
10
+ namedArguments: { name: "name" },
10
11
  };
11
12
  export default async function (plop) {
12
13
  plop.setActionType("createUiProject", async function (answers) {
@@ -6,6 +6,7 @@ export const metadata = {
6
6
  key: "i18n",
7
7
  name: "KOS Localization Project",
8
8
  invalidateCache: true,
9
+ namedArguments: { name: "name" },
9
10
  };
10
11
  export default async function (plop) {
11
12
  plop.setActionType("createI18nProject", async function (answers) {
@@ -6,6 +6,7 @@ export const metadata = {
6
6
  key: "plugin",
7
7
  name: "KOS Plugin Project",
8
8
  invalidateCache: true,
9
+ namedArguments: { name: "name" },
9
10
  };
10
11
  export default async function (plop) {
11
12
  plop.setActionType("createPluginProject", async function (answers) {
@@ -7,6 +7,7 @@ export const metadata = {
7
7
  key: "project:splash",
8
8
  name: "KOS Splash Screen Project",
9
9
  invalidateCache: true,
10
+ namedArguments: { name: "name" },
10
11
  };
11
12
  export default async function (plop) {
12
13
  plop.setActionType("createSplashProject", async function (answers) {
@@ -6,6 +6,7 @@ export const metadata = {
6
6
  key: "theme",
7
7
  name: "KOS Theme Project",
8
8
  invalidateCache: true,
9
+ namedArguments: { name: "name" },
9
10
  };
10
11
  export default async function (plop) {
11
12
  plop.setActionType("createThemeProject", async function (answers) {
@@ -5,6 +5,10 @@ import { required } from "../../utils/validators.mjs";
5
5
  export const metadata = {
6
6
  key: "workspace",
7
7
  name: "Create a new KOS UI Workspace",
8
+ namedArguments: {
9
+ name: "workspaceName",
10
+ workspaceName: "workspaceName"
11
+ }
8
12
  };
9
13
  export default async function (plop) {
10
14
  plop.setActionType("createWorkspace", async function (answers) {
@@ -29,7 +29,6 @@ export const MODEL_PROMPTS = [
29
29
  name: "parentAware",
30
30
  message: "Aware of parent container?",
31
31
  default: false,
32
- when: (answers) => !!answers.container,
33
32
  },
34
33
  {
35
34
  type: "confirm",