@kidd-cli/cli 0.1.4 → 0.3.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.
- package/dist/commands/add/command.mjs +4 -3
- package/dist/commands/add/config.d.mts +6 -0
- package/dist/commands/add/config.mjs +55 -0
- package/dist/commands/add/index.mjs +1 -1
- package/dist/commands/add/middleware.mjs +4 -3
- package/dist/commands/build.mjs +20 -3
- package/dist/commands/commands.mjs +63 -5
- package/dist/commands/doctor.mjs +2 -2
- package/dist/commands/init.mjs +40 -21
- package/dist/index.mjs +15 -10
- package/dist/lib/templates/config/config.ts.liquid +16 -0
- package/dist/lib/templates/project/src/commands/hello.ts.liquid +1 -1
- package/dist/lib/templates/project/src/config.ts.liquid +16 -0
- package/dist/lib/templates/project/src/index.ts.liquid +7 -2
- package/dist/validate-D3mbQfJT.mjs +16 -0
- package/dist/{write-CdoqLFeH.mjs → write-BF8u0sRy.mjs} +1 -16
- package/package.json +5 -5
- /package/dist/{detect-DcO0_CWy.mjs → detect-Cxj1jrYq.mjs} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { t as
|
|
1
|
+
import { n as renderTemplate, t as writeFiles } from "../../write-BF8u0sRy.mjs";
|
|
2
|
+
import { t as isKebabCase } from "../../validate-D3mbQfJT.mjs";
|
|
3
|
+
import { t as detectProject } from "../../detect-Cxj1jrYq.mjs";
|
|
3
4
|
import { command } from "@kidd-cli/core";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { loadConfig } from "@kidd-cli/config/loader";
|
|
@@ -48,7 +49,7 @@ const addCommandCommand = command({
|
|
|
48
49
|
}
|
|
49
50
|
ctx.spinner.stop("Command created!");
|
|
50
51
|
const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
|
|
51
|
-
if (summary.length > 0) ctx.
|
|
52
|
+
if (summary.length > 0) ctx.logger.print(summary);
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
/**
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { n as renderTemplate, t as writeFiles } from "../../write-BF8u0sRy.mjs";
|
|
2
|
+
import { t as detectProject } from "../../detect-Cxj1jrYq.mjs";
|
|
3
|
+
import { command } from "@kidd-cli/core";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { readManifest } from "@kidd-cli/utils/manifest";
|
|
6
|
+
//#region src/commands/add/config.ts
|
|
7
|
+
const addConfigCommand = command({
|
|
8
|
+
description: "Add a config schema to your project",
|
|
9
|
+
handler: async (ctx) => {
|
|
10
|
+
const [detectError, project] = await detectProject(process.cwd());
|
|
11
|
+
if (detectError) return ctx.fail(detectError.message);
|
|
12
|
+
if (!project) return ctx.fail("Not in a kidd project. Run `kidd init` first.");
|
|
13
|
+
const projectName = await resolveProjectName(project.rootDir);
|
|
14
|
+
ctx.spinner.start("Generating config...");
|
|
15
|
+
const [renderError, rendered] = await renderTemplate({
|
|
16
|
+
templateDir: join(import.meta.dirname, "..", "..", "lib", "templates", "config"),
|
|
17
|
+
variables: { name: projectName }
|
|
18
|
+
});
|
|
19
|
+
if (renderError) {
|
|
20
|
+
ctx.spinner.stop("Failed");
|
|
21
|
+
return ctx.fail(renderError.message);
|
|
22
|
+
}
|
|
23
|
+
const [writeError, result] = await writeFiles({
|
|
24
|
+
files: rendered,
|
|
25
|
+
outputDir: join(project.rootDir, "src"),
|
|
26
|
+
overwrite: false
|
|
27
|
+
});
|
|
28
|
+
if (writeError) {
|
|
29
|
+
ctx.spinner.stop("Failed");
|
|
30
|
+
return ctx.fail(writeError.message);
|
|
31
|
+
}
|
|
32
|
+
ctx.spinner.stop("Config created!");
|
|
33
|
+
const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
|
|
34
|
+
if (summary.length > 0) ctx.logger.print(summary);
|
|
35
|
+
ctx.logger.newline();
|
|
36
|
+
ctx.logger.print("Next steps:");
|
|
37
|
+
ctx.logger.print(" 1. Add fields to the config schema in src/config.ts");
|
|
38
|
+
ctx.logger.print(" 2. Import and pass the schema to cli({ config: { schema: configSchema } })");
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const DEFAULT_NAME = "my-app";
|
|
42
|
+
/**
|
|
43
|
+
* Resolve the project name from the project's package.json.
|
|
44
|
+
*
|
|
45
|
+
* @param rootDir - The project root directory.
|
|
46
|
+
* @returns The project name from package.json, or a default fallback.
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
async function resolveProjectName(rootDir) {
|
|
50
|
+
const [error, manifest] = await readManifest(rootDir);
|
|
51
|
+
if (error || !manifest.name) return DEFAULT_NAME;
|
|
52
|
+
return manifest.name;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { addConfigCommand as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { command } from "@kidd-cli/core";
|
|
2
2
|
//#region src/commands/add/index.ts
|
|
3
|
-
const addCommand = command({ description: "Add a command or
|
|
3
|
+
const addCommand = command({ description: "Add a command, middleware, or config to your project" });
|
|
4
4
|
//#endregion
|
|
5
5
|
export { addCommand as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { t as
|
|
1
|
+
import { n as renderTemplate, t as writeFiles } from "../../write-BF8u0sRy.mjs";
|
|
2
|
+
import { t as isKebabCase } from "../../validate-D3mbQfJT.mjs";
|
|
3
|
+
import { t as detectProject } from "../../detect-Cxj1jrYq.mjs";
|
|
3
4
|
import { command } from "@kidd-cli/core";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { z } from "zod";
|
|
@@ -43,7 +44,7 @@ const addMiddlewareCommand = command({
|
|
|
43
44
|
}
|
|
44
45
|
ctx.spinner.stop("Middleware created!");
|
|
45
46
|
const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
|
|
46
|
-
if (summary.length > 0) ctx.
|
|
47
|
+
if (summary.length > 0) ctx.logger.print(summary);
|
|
47
48
|
}
|
|
48
49
|
});
|
|
49
50
|
/**
|
package/dist/commands/build.mjs
CHANGED
|
@@ -41,7 +41,8 @@ const buildCommand = command({
|
|
|
41
41
|
ctx.logger.note(formatBuildNote({
|
|
42
42
|
cwd,
|
|
43
43
|
entryFile: buildOutput.entryFile,
|
|
44
|
-
outDir: buildOutput.outDir
|
|
44
|
+
outDir: buildOutput.outDir,
|
|
45
|
+
version: buildOutput.version
|
|
45
46
|
}), "Bundle");
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
@@ -63,7 +64,8 @@ const buildCommand = command({
|
|
|
63
64
|
ctx.logger.note(formatBuildNote({
|
|
64
65
|
cwd,
|
|
65
66
|
entryFile: buildOutput.entryFile,
|
|
66
|
-
outDir: buildOutput.outDir
|
|
67
|
+
outDir: buildOutput.outDir,
|
|
68
|
+
version: buildOutput.version
|
|
67
69
|
}), "Bundle");
|
|
68
70
|
ctx.logger.note(formatBinariesNote({
|
|
69
71
|
binaries: compileOutput.binaries,
|
|
@@ -133,7 +135,22 @@ function resolveExistingCompile(value) {
|
|
|
133
135
|
* @returns A formatted string with entry and output directory.
|
|
134
136
|
*/
|
|
135
137
|
function formatBuildNote(params) {
|
|
136
|
-
return [
|
|
138
|
+
return [
|
|
139
|
+
`entry ${relative(params.cwd, params.entryFile)}`,
|
|
140
|
+
`output ${relative(params.cwd, params.outDir)}`,
|
|
141
|
+
...formatVersionLine(params.version)
|
|
142
|
+
].join("\n");
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Format a version line for the build note, if a version is available.
|
|
146
|
+
*
|
|
147
|
+
* @private
|
|
148
|
+
* @param version - The version string, or undefined.
|
|
149
|
+
* @returns A single-element array with the formatted line, or an empty array.
|
|
150
|
+
*/
|
|
151
|
+
function formatVersionLine(version) {
|
|
152
|
+
if (!version) return [];
|
|
153
|
+
return [`version ${version}`];
|
|
137
154
|
}
|
|
138
155
|
/**
|
|
139
156
|
* Format compiled binaries into an aligned, multi-line string for display.
|
|
@@ -22,10 +22,10 @@ const commandsCommand = command({
|
|
|
22
22
|
const tree = await buildTree(await autoload({ dir: commandsDir }));
|
|
23
23
|
ctx.spinner.stop("Commands");
|
|
24
24
|
if (tree.length === 0) {
|
|
25
|
-
ctx.
|
|
25
|
+
ctx.logger.print("No commands found");
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
ctx.
|
|
28
|
+
ctx.logger.print(renderTree(tree));
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
/**
|
|
@@ -43,21 +43,79 @@ async function resolveSubcommands(commands) {
|
|
|
43
43
|
/**
|
|
44
44
|
* Recursively build a sorted tree of entries from a CommandMap.
|
|
45
45
|
*
|
|
46
|
+
* Commands listed in the order array appear first in the specified order;
|
|
47
|
+
* omitted commands fall back to alphabetical sort.
|
|
48
|
+
*
|
|
46
49
|
* @private
|
|
47
50
|
* @param commandMap - The map of command names to Command objects.
|
|
51
|
+
* @param order - Optional array of command names defining display order.
|
|
48
52
|
* @returns A sorted array of TreeEntry nodes.
|
|
49
53
|
*/
|
|
50
|
-
async function buildTree(commandMap) {
|
|
51
|
-
const entries =
|
|
54
|
+
async function buildTree(commandMap, order) {
|
|
55
|
+
const entries = sortEntries({
|
|
56
|
+
entries: Object.entries(commandMap),
|
|
57
|
+
order
|
|
58
|
+
});
|
|
52
59
|
return Promise.all(entries.map(async ([name, cmd]) => {
|
|
53
60
|
return {
|
|
54
|
-
children: await buildTree(await resolveSubcommands(cmd.commands)),
|
|
61
|
+
children: await buildTree(await resolveSubcommands(cmd.commands), cmd.order),
|
|
55
62
|
description: cmd.description ?? "",
|
|
56
63
|
name
|
|
57
64
|
};
|
|
58
65
|
}));
|
|
59
66
|
}
|
|
60
67
|
/**
|
|
68
|
+
* Sort command entries with ordered names first (in specified order),
|
|
69
|
+
* remaining names alphabetically.
|
|
70
|
+
*
|
|
71
|
+
* Validates the order array against available command names and logs a
|
|
72
|
+
* warning for unknown or duplicate entries rather than failing silently.
|
|
73
|
+
*
|
|
74
|
+
* @private
|
|
75
|
+
* @param params - The command entries and optional order array.
|
|
76
|
+
* @returns Sorted array of entries.
|
|
77
|
+
*/
|
|
78
|
+
function sortEntries(params) {
|
|
79
|
+
const { entries, order } = params;
|
|
80
|
+
if (!order || order.length === 0) return entries.toSorted(([a], [b]) => a.localeCompare(b));
|
|
81
|
+
const validOrder = validateOrder({
|
|
82
|
+
commandNames: entries.map(([name]) => name),
|
|
83
|
+
order
|
|
84
|
+
});
|
|
85
|
+
const entryMap = new Map(entries);
|
|
86
|
+
const orderedSet = new Set(validOrder);
|
|
87
|
+
const ordered = validOrder.filter((name) => entryMap.has(name)).map((name) => [name, entryMap.get(name)]);
|
|
88
|
+
const remaining = entries.filter(([name]) => !orderedSet.has(name)).toSorted(([a], [b]) => a.localeCompare(b));
|
|
89
|
+
return [...ordered, ...remaining];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate the order array by filtering out unknown and duplicate names.
|
|
93
|
+
*
|
|
94
|
+
* Logs warnings for invalid entries so developers see the mismatch
|
|
95
|
+
* during `kidd commands` introspection, matching the runtime behaviour.
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
* @param params - The order array and available command names.
|
|
99
|
+
* @returns A deduplicated array of valid order names.
|
|
100
|
+
*/
|
|
101
|
+
function validateOrder(params) {
|
|
102
|
+
const { commandNames, order } = params;
|
|
103
|
+
const nameSet = new Set(commandNames);
|
|
104
|
+
const seen = /* @__PURE__ */ new Set();
|
|
105
|
+
return order.filter((name) => {
|
|
106
|
+
if (seen.has(name)) {
|
|
107
|
+
console.warn(`Warning: duplicate command name "${name}" in order array`);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
seen.add(name);
|
|
111
|
+
if (!nameSet.has(name)) {
|
|
112
|
+
console.warn(`Warning: unknown command "${name}" in order array`);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
61
119
|
* Render a tree of entries into an ASCII tree string.
|
|
62
120
|
*
|
|
63
121
|
* @private
|
package/dist/commands/doctor.mjs
CHANGED
|
@@ -538,7 +538,7 @@ const doctorCommand = command({
|
|
|
538
538
|
total: results.length,
|
|
539
539
|
warnings
|
|
540
540
|
});
|
|
541
|
-
ctx.
|
|
541
|
+
ctx.logger.print(summary);
|
|
542
542
|
if (failed > 0) ctx.fail(`${failed} ${pluralizeCheck(failed)} failed`);
|
|
543
543
|
}
|
|
544
544
|
});
|
|
@@ -607,7 +607,7 @@ async function applyFixes(results, context) {
|
|
|
607
607
|
*/
|
|
608
608
|
function displayResults(ctx, results, fixResults) {
|
|
609
609
|
const output = results.map((result) => formatResultLine(result, fixResults)).join("");
|
|
610
|
-
if (output.length > 0) ctx.
|
|
610
|
+
if (output.length > 0) ctx.logger.print(output);
|
|
611
611
|
}
|
|
612
612
|
/**
|
|
613
613
|
* Format a single check result line with optional hint.
|
package/dist/commands/init.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as renderTemplate, t as writeFiles } from "../write-BF8u0sRy.mjs";
|
|
2
|
+
import { t as isKebabCase } from "../validate-D3mbQfJT.mjs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { command } from "@kidd-cli/core";
|
|
4
5
|
import { dirname, join } from "node:path";
|
|
@@ -26,6 +27,7 @@ const TSDOWN_VERSION = "^0.21.1";
|
|
|
26
27
|
//#region src/commands/init.ts
|
|
27
28
|
const initCommand = command({
|
|
28
29
|
args: z.object({
|
|
30
|
+
config: z.boolean().describe("Include config schema setup").optional(),
|
|
29
31
|
description: z.string().describe("Project description").optional(),
|
|
30
32
|
example: z.boolean().describe("Include example command").optional(),
|
|
31
33
|
name: z.string().describe("Project name (kebab-case)").optional(),
|
|
@@ -41,6 +43,7 @@ const initCommand = command({
|
|
|
41
43
|
const projectDescription = await resolveDescription(ctx);
|
|
42
44
|
const packageManager = await resolvePackageManager(ctx);
|
|
43
45
|
const includeExample = await resolveIncludeExample(ctx);
|
|
46
|
+
const includeConfig = await resolveIncludeConfig(ctx);
|
|
44
47
|
ctx.spinner.start("Scaffolding project...");
|
|
45
48
|
const coreVersion = await resolveDependencyVersion("@kidd-cli/core");
|
|
46
49
|
const cliVersion = await resolveSelfVersion();
|
|
@@ -50,6 +53,7 @@ const initCommand = command({
|
|
|
50
53
|
cliVersion,
|
|
51
54
|
coreVersion,
|
|
52
55
|
description: projectDescription,
|
|
56
|
+
includeConfig,
|
|
53
57
|
name: projectName,
|
|
54
58
|
packageManager,
|
|
55
59
|
tsdownVersion: TSDOWN_VERSION,
|
|
@@ -63,7 +67,10 @@ const initCommand = command({
|
|
|
63
67
|
return ctx.fail(renderError.message);
|
|
64
68
|
}
|
|
65
69
|
const [writeError] = await writeFiles({
|
|
66
|
-
files: selectFiles(
|
|
70
|
+
files: selectFiles({
|
|
71
|
+
includeConfig,
|
|
72
|
+
includeExample
|
|
73
|
+
}, rendered),
|
|
67
74
|
outputDir: join(process.cwd(), projectName),
|
|
68
75
|
overwrite: false
|
|
69
76
|
});
|
|
@@ -72,10 +79,10 @@ const initCommand = command({
|
|
|
72
79
|
return ctx.fail(writeError.message);
|
|
73
80
|
}
|
|
74
81
|
ctx.spinner.stop("Project created!");
|
|
75
|
-
ctx.
|
|
76
|
-
ctx.
|
|
77
|
-
ctx.
|
|
78
|
-
ctx.
|
|
82
|
+
ctx.logger.newline();
|
|
83
|
+
ctx.logger.print("Next steps:");
|
|
84
|
+
ctx.logger.print(` cd ${projectName}`);
|
|
85
|
+
ctx.logger.print(` ${packageManager} install`);
|
|
79
86
|
}
|
|
80
87
|
});
|
|
81
88
|
/**
|
|
@@ -155,26 +162,29 @@ async function resolveIncludeExample(ctx) {
|
|
|
155
162
|
});
|
|
156
163
|
}
|
|
157
164
|
/**
|
|
158
|
-
*
|
|
165
|
+
* Resolve whether to include config schema setup from args or prompt.
|
|
159
166
|
*
|
|
160
|
-
* @param
|
|
161
|
-
* @
|
|
162
|
-
* @returns The filtered file list.
|
|
167
|
+
* @param ctx - Command context.
|
|
168
|
+
* @returns True when the config schema file should be included.
|
|
163
169
|
* @private
|
|
164
170
|
*/
|
|
165
|
-
function
|
|
166
|
-
if (
|
|
167
|
-
return
|
|
171
|
+
async function resolveIncludeConfig(ctx) {
|
|
172
|
+
if (ctx.args.config !== void 0) return ctx.args.config;
|
|
173
|
+
return ctx.prompts.confirm({
|
|
174
|
+
initialValue: false,
|
|
175
|
+
message: "Include config schema?"
|
|
176
|
+
});
|
|
168
177
|
}
|
|
169
178
|
/**
|
|
170
|
-
*
|
|
179
|
+
* Select the rendered files to write, optionally excluding the example command and config.
|
|
171
180
|
*
|
|
172
|
-
* @param
|
|
173
|
-
* @
|
|
181
|
+
* @param options - Flags controlling which optional files to include.
|
|
182
|
+
* @param rendered - The full set of rendered files.
|
|
183
|
+
* @returns The filtered file list.
|
|
174
184
|
* @private
|
|
175
185
|
*/
|
|
176
|
-
function
|
|
177
|
-
return !file.relativePath.includes("commands/hello.ts");
|
|
186
|
+
function selectFiles(options, rendered) {
|
|
187
|
+
return rendered.filter((file) => options.includeExample || !file.relativePath.includes("commands/hello.ts")).filter((file) => options.includeConfig || !file.relativePath.includes("config.ts"));
|
|
178
188
|
}
|
|
179
189
|
const DEFAULT_VERSION = "0.0.0";
|
|
180
190
|
/**
|
|
@@ -189,7 +199,10 @@ const DEFAULT_VERSION = "0.0.0";
|
|
|
189
199
|
*/
|
|
190
200
|
async function resolveSelfVersion() {
|
|
191
201
|
const [error, manifest] = await readManifest(join(import.meta.dirname, "..", ".."));
|
|
192
|
-
if (error || !manifest.version)
|
|
202
|
+
if (error || !manifest.version) {
|
|
203
|
+
console.warn("Warning: Could not resolve CLI version, using fallback 0.0.0");
|
|
204
|
+
return DEFAULT_VERSION;
|
|
205
|
+
}
|
|
193
206
|
return manifest.version;
|
|
194
207
|
}
|
|
195
208
|
/**
|
|
@@ -206,9 +219,15 @@ async function resolveSelfVersion() {
|
|
|
206
219
|
async function resolveDependencyVersion(packageName) {
|
|
207
220
|
const require = createRequire(import.meta.url);
|
|
208
221
|
const [resolveError, entryPath] = attempt(() => require.resolve(packageName));
|
|
209
|
-
if (resolveError || entryPath === null)
|
|
222
|
+
if (resolveError || entryPath === null) {
|
|
223
|
+
console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
|
|
224
|
+
return DEFAULT_VERSION;
|
|
225
|
+
}
|
|
210
226
|
const [manifestError, manifest] = await readManifest(join(dirname(entryPath), ".."));
|
|
211
|
-
if (manifestError || !manifest.version)
|
|
227
|
+
if (manifestError || !manifest.version) {
|
|
228
|
+
console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
|
|
229
|
+
return DEFAULT_VERSION;
|
|
230
|
+
}
|
|
212
231
|
return manifest.version;
|
|
213
232
|
}
|
|
214
233
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -7,30 +7,35 @@ import { readManifest } from "@kidd-cli/utils/manifest";
|
|
|
7
7
|
*
|
|
8
8
|
* Reads package.json one directory above `baseDir` (the dist output sits
|
|
9
9
|
* one level below the package root) and ensures all required fields are
|
|
10
|
-
* present.
|
|
11
|
-
* required field is missing
|
|
10
|
+
* present. Returns an error Result if the manifest cannot be read or any
|
|
11
|
+
* required field is missing.
|
|
12
12
|
*
|
|
13
13
|
* @param baseDir - The directory the CLI entry file lives in (typically `import.meta.dirname`).
|
|
14
|
-
* @returns A validated {@link CLIManifest}
|
|
14
|
+
* @returns A Result tuple: error on failure, validated {@link CLIManifest} on success.
|
|
15
15
|
*/
|
|
16
16
|
async function loadCLIManifest(baseDir) {
|
|
17
17
|
const [manifestError, manifest] = await readManifest(join(baseDir, ".."));
|
|
18
|
-
if (manifestError)
|
|
19
|
-
if (!manifest.name)
|
|
20
|
-
if (!manifest.version)
|
|
21
|
-
if (!manifest.description)
|
|
22
|
-
return {
|
|
18
|
+
if (manifestError) return [/* @__PURE__ */ new Error(`Failed to read CLI manifest: ${manifestError.message}`), null];
|
|
19
|
+
if (!manifest.name) return [/* @__PURE__ */ new Error("CLI manifest is missing required field: name"), null];
|
|
20
|
+
if (!manifest.version) return [/* @__PURE__ */ new Error("CLI manifest is missing required field: version"), null];
|
|
21
|
+
if (!manifest.description) return [/* @__PURE__ */ new Error("CLI manifest is missing required field: description"), null];
|
|
22
|
+
return [null, {
|
|
23
23
|
description: manifest.description,
|
|
24
24
|
name: manifest.name,
|
|
25
25
|
version: manifest.version
|
|
26
|
-
};
|
|
26
|
+
}];
|
|
27
27
|
}
|
|
28
28
|
//#endregion
|
|
29
29
|
//#region src/index.ts
|
|
30
|
-
const manifest = await loadCLIManifest(import.meta.dirname);
|
|
30
|
+
const [manifestError, manifest] = await loadCLIManifest(import.meta.dirname);
|
|
31
|
+
if (manifestError) {
|
|
32
|
+
console.error(manifestError.message);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
31
35
|
await cli({
|
|
32
36
|
commands: `${import.meta.dirname}/commands`,
|
|
33
37
|
description: manifest.description,
|
|
38
|
+
help: { header: `${manifest.name} v${manifest.version}` },
|
|
34
39
|
name: manifest.name,
|
|
35
40
|
version: manifest.version
|
|
36
41
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ConfigType } from '@kidd-cli/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runtime config schema for the {{ name }} CLI.
|
|
6
|
+
*
|
|
7
|
+
* This schema validates config files loaded at startup (e.g. `.{{ name }}.jsonc`).
|
|
8
|
+
* The inferred type is merged into `ctx.config` via module augmentation below.
|
|
9
|
+
*/
|
|
10
|
+
export const configSchema = z.object({
|
|
11
|
+
// Add your config fields here
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
declare module '@kidd-cli/core' {
|
|
15
|
+
interface CliConfig extends ConfigType<typeof configSchema> {}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ConfigType } from '@kidd-cli/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Runtime config schema for the {{ name }} CLI.
|
|
6
|
+
*
|
|
7
|
+
* This schema validates config files loaded at startup (e.g. `.{{ name }}.jsonc`).
|
|
8
|
+
* The inferred type is merged into `ctx.config` via module augmentation below.
|
|
9
|
+
*/
|
|
10
|
+
export const configSchema = z.object({
|
|
11
|
+
// Add your config fields here
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
declare module '@kidd-cli/core' {
|
|
15
|
+
interface CliConfig extends ConfigType<typeof configSchema> {}
|
|
16
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { cli } from '@kidd-cli/core'
|
|
2
|
-
|
|
2
|
+
{% if includeConfig %}
|
|
3
|
+
import { configSchema } from './config.js'
|
|
4
|
+
{% endif %}
|
|
3
5
|
void cli({
|
|
4
6
|
name: '{{ name }}',
|
|
5
7
|
version: '0.0.0',
|
|
6
8
|
description: '{{ description }}',
|
|
7
9
|
commands: import.meta.dirname + '/commands',
|
|
8
|
-
}
|
|
10
|
+
{% if includeConfig %} config: {
|
|
11
|
+
schema: configSchema,
|
|
12
|
+
},
|
|
13
|
+
{% endif %}})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/lib/validate.ts
|
|
2
|
+
const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
|
|
3
|
+
/**
|
|
4
|
+
* Check whether a string is valid kebab-case.
|
|
5
|
+
*
|
|
6
|
+
* @param value - The string to validate.
|
|
7
|
+
* @returns True when the string is kebab-case.
|
|
8
|
+
*/
|
|
9
|
+
function isKebabCase(value) {
|
|
10
|
+
if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
|
|
11
|
+
if (value.endsWith("-")) return false;
|
|
12
|
+
if (value.includes("--")) return false;
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { isKebabCase as t };
|
|
@@ -92,21 +92,6 @@ function isGenerateError(value) {
|
|
|
92
92
|
return "type" in value && "message" in value;
|
|
93
93
|
}
|
|
94
94
|
//#endregion
|
|
95
|
-
//#region src/lib/validate.ts
|
|
96
|
-
const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
|
|
97
|
-
/**
|
|
98
|
-
* Check whether a string is valid kebab-case.
|
|
99
|
-
*
|
|
100
|
-
* @param value - The string to validate.
|
|
101
|
-
* @returns True when the string is kebab-case.
|
|
102
|
-
*/
|
|
103
|
-
function isKebabCase(value) {
|
|
104
|
-
if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
|
|
105
|
-
if (value.endsWith("-")) return false;
|
|
106
|
-
if (value.includes("--")) return false;
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
110
95
|
//#region src/lib/write.ts
|
|
111
96
|
/**
|
|
112
97
|
* Write rendered files to disk with optional conflict detection.
|
|
@@ -160,4 +145,4 @@ async function writeSingleFile(file, outputDir, overwrite) {
|
|
|
160
145
|
}
|
|
161
146
|
}
|
|
162
147
|
//#endregion
|
|
163
|
-
export {
|
|
148
|
+
export { renderTemplate as n, writeFiles as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kidd-cli/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "DX companion CLI for the kidd framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"liquidjs": "^10.25.0",
|
|
27
27
|
"picocolors": "^1.1.1",
|
|
28
28
|
"zod": "^4.3.6",
|
|
29
|
-
"@kidd-cli/bundler": "0.
|
|
30
|
-
"@kidd-cli/config": "0.1.
|
|
31
|
-
"@kidd-cli/
|
|
32
|
-
"@kidd-cli/
|
|
29
|
+
"@kidd-cli/bundler": "0.2.0",
|
|
30
|
+
"@kidd-cli/config": "0.1.4",
|
|
31
|
+
"@kidd-cli/utils": "0.1.4",
|
|
32
|
+
"@kidd-cli/core": "0.5.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/fs-extra": "^11.0.4",
|
|
File without changes
|