@kosdev-code/kos-ui-cli 2.1.0 → 2.1.1
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 +3 -2
- package/src/lib/cli.mjs +11 -0
- package/src/lib/utils/command-builder.mjs +94 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kosdev-code/kos-ui-cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"bin": {
|
|
5
5
|
"kosui": "./src/lib/cli.mjs"
|
|
6
6
|
},
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
],
|
|
10
10
|
"type": "module",
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"chalk": "^5.3.0",
|
|
12
13
|
"prettier": "^2.6.2",
|
|
13
14
|
"rimraf": "^5.0.1",
|
|
14
15
|
"plop": "^3.1.2",
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
"main": "./src/index.js",
|
|
21
22
|
"kos": {
|
|
22
23
|
"build": {
|
|
23
|
-
"gitHash": "
|
|
24
|
+
"gitHash": "8f34a7c5827b814dc09dd2bcbf41c9195d8b3437"
|
|
24
25
|
}
|
|
25
26
|
},
|
|
26
27
|
"publishConfig": {
|
package/src/lib/cli.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import chalk from "chalk";
|
|
2
3
|
import figlet from "figlet";
|
|
3
4
|
import minimist from "minimist";
|
|
4
5
|
import nodePlop from "node-plop";
|
|
5
6
|
import path, { dirname } from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
7
8
|
import { clearCache } from "./utils/cache.mjs";
|
|
9
|
+
import { buildNonInteractiveCommand, isRunningInteractively } from "./utils/command-builder.mjs";
|
|
8
10
|
import { getGeneratorMetadata } from "./utils/generator-loader.mjs";
|
|
9
11
|
|
|
10
12
|
const originalArgs = process.argv.slice(2);
|
|
@@ -772,6 +774,15 @@ async function launch() {
|
|
|
772
774
|
results.failures.forEach((fail) => {
|
|
773
775
|
console.error(fail.error || fail.message);
|
|
774
776
|
});
|
|
777
|
+
|
|
778
|
+
// Output equivalent non-interactive command when running interactively
|
|
779
|
+
if (isRunningInteractively(parsedArgs, hasAnyAnswers) && results.failures.length === 0 && !hasQuiet) {
|
|
780
|
+
const commandString = buildNonInteractiveCommand(command, answers, meta);
|
|
781
|
+
if (commandString) {
|
|
782
|
+
console.log(chalk.cyan("\n[kos-cli] Equivalent non-interactive command:"));
|
|
783
|
+
console.log(chalk.green(` ${commandString}`));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
775
786
|
} catch (err) {
|
|
776
787
|
console.error("[kos-cli] Generator run failed:", err.message);
|
|
777
788
|
process.exit(1);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a non-interactive command string from interactive session answers
|
|
3
|
+
* This helps users understand how to run the same command without prompts
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Converts interactive prompt answers back to CLI command arguments
|
|
8
|
+
* @param {string} command - The generator command name
|
|
9
|
+
* @param {Object} answers - The answers collected from prompts
|
|
10
|
+
* @param {Object} meta - Generator metadata including namedArguments mapping
|
|
11
|
+
* @returns {string|null} The equivalent CLI command string, or null if cannot be built
|
|
12
|
+
*/
|
|
13
|
+
export function buildNonInteractiveCommand(command, answers, meta) {
|
|
14
|
+
if (!meta?.namedArguments) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const args = [`kosui ${command}`];
|
|
19
|
+
const reverseMap = {};
|
|
20
|
+
|
|
21
|
+
// Create reverse mapping from prompt names to CLI arguments
|
|
22
|
+
Object.entries(meta.namedArguments).forEach(([cliArg, promptName]) => {
|
|
23
|
+
// Skip special flags that don't map to prompts
|
|
24
|
+
if (cliArg !== "interactive" && cliArg !== "dryRun") {
|
|
25
|
+
reverseMap[promptName] = cliArg;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Build command arguments from answers
|
|
30
|
+
Object.entries(answers).forEach(([promptName, value]) => {
|
|
31
|
+
const cliArg = reverseMap[promptName];
|
|
32
|
+
if (cliArg && value !== undefined && value !== null && value !== "") {
|
|
33
|
+
args.push(formatArgument(cliArg, value));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Add dryRun if it was provided
|
|
38
|
+
if (answers.dryRun) {
|
|
39
|
+
args.push("--dryRun");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return args.join(" ");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Formats a single CLI argument based on its value type
|
|
47
|
+
* @param {string} argName - The CLI argument name
|
|
48
|
+
* @param {any} value - The value for the argument
|
|
49
|
+
* @returns {string} The formatted CLI argument string
|
|
50
|
+
*/
|
|
51
|
+
function formatArgument(argName, value) {
|
|
52
|
+
// Handle boolean values
|
|
53
|
+
if (typeof value === "boolean") {
|
|
54
|
+
if (value) {
|
|
55
|
+
return `--${argName}`;
|
|
56
|
+
} else {
|
|
57
|
+
// For false booleans, explicitly set to false
|
|
58
|
+
// This ensures the command can be replicated exactly
|
|
59
|
+
return `--${argName}=false`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handle string/number values
|
|
64
|
+
const stringValue = String(value);
|
|
65
|
+
|
|
66
|
+
// Check if value needs escaping
|
|
67
|
+
if (needsEscaping(stringValue)) {
|
|
68
|
+
// Use double quotes and escape internal quotes
|
|
69
|
+
return `--${argName}="${stringValue.replace(/"/g, '\\"')}"`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return `--${argName}=${stringValue}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Determines if a string value needs shell escaping
|
|
77
|
+
* @param {string} value - The value to check
|
|
78
|
+
* @returns {boolean} True if the value needs escaping
|
|
79
|
+
*/
|
|
80
|
+
function needsEscaping(value) {
|
|
81
|
+
// Check for characters that need escaping in shell
|
|
82
|
+
return /[\s'"$`\\!]/.test(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Determines if the CLI is running in interactive mode
|
|
87
|
+
* @param {Object} parsedArgs - Parsed command line arguments
|
|
88
|
+
* @param {boolean} hasAnyAnswers - Whether any answers were provided via CLI
|
|
89
|
+
* @returns {boolean} True if running in interactive mode
|
|
90
|
+
*/
|
|
91
|
+
export function isRunningInteractively(parsedArgs, hasAnyAnswers) {
|
|
92
|
+
const forceInteractive = parsedArgs.interactive || parsedArgs.i;
|
|
93
|
+
return forceInteractive || (!hasAnyAnswers && !parsedArgs.help);
|
|
94
|
+
}
|