@kidd-cli/cli 0.2.0 → 0.3.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/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/commands.mjs +2 -2
- package/dist/commands/doctor.mjs +2 -2
- package/dist/commands/init.mjs +121 -35
- package/dist/index.mjs +14 -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/pnpm-workspace.yaml +15 -0
- package/dist/validate-D3mbQfJT.mjs +16 -0
- package/dist/{write-CdoqLFeH.mjs → write-BF8u0sRy.mjs} +1 -16
- package/package.json +8 -8
- /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
|
/**
|
|
@@ -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
|
/**
|
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,31 +1,98 @@
|
|
|
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";
|
|
5
6
|
import { readManifest } from "@kidd-cli/utils/manifest";
|
|
6
7
|
import { z } from "zod";
|
|
7
|
-
import {
|
|
8
|
-
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { attempt, err, match, ok } from "@kidd-cli/utils/fp";
|
|
10
|
+
import { parse } from "yaml";
|
|
11
|
+
//#region src/lib/template-versions.ts
|
|
9
12
|
/**
|
|
10
|
-
* Zod
|
|
13
|
+
* Zod schema for the `catalog` field in `pnpm-workspace.yaml`.
|
|
14
|
+
*
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
const catalogSchema = z.object({ catalog: z.object({
|
|
18
|
+
tsdown: z.string(),
|
|
19
|
+
typescript: z.string(),
|
|
20
|
+
vitest: z.string(),
|
|
21
|
+
zod: z.string()
|
|
22
|
+
}) });
|
|
23
|
+
/**
|
|
24
|
+
* Known locations for `pnpm-workspace.yaml` relative to this module.
|
|
25
|
+
*
|
|
26
|
+
* - First path covers the built `dist/` layout (yaml copied to `dist/`).
|
|
27
|
+
* - Second path covers running from source `src/lib/` during development.
|
|
28
|
+
*
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
31
|
+
const CANDIDATE_PATHS = [join(import.meta.dirname, "..", "pnpm-workspace.yaml"), join(import.meta.dirname, "..", "..", "..", "..", "pnpm-workspace.yaml")];
|
|
32
|
+
/**
|
|
33
|
+
* Locate `pnpm-workspace.yaml` by checking known candidate paths.
|
|
34
|
+
*
|
|
35
|
+
* @returns The resolved path, or `null` when no candidate exists.
|
|
36
|
+
* @private
|
|
11
37
|
*/
|
|
12
|
-
|
|
38
|
+
function findWorkspaceYaml() {
|
|
39
|
+
return CANDIDATE_PATHS.find(existsSync) ?? null;
|
|
40
|
+
}
|
|
13
41
|
/**
|
|
14
|
-
*
|
|
42
|
+
* Range operator prefixes recognized in version strings.
|
|
43
|
+
*
|
|
44
|
+
* @private
|
|
15
45
|
*/
|
|
16
|
-
const
|
|
46
|
+
const RANGE_PREFIXES = [
|
|
47
|
+
"^",
|
|
48
|
+
"~",
|
|
49
|
+
">",
|
|
50
|
+
"<",
|
|
51
|
+
"="
|
|
52
|
+
];
|
|
17
53
|
/**
|
|
18
|
-
*
|
|
54
|
+
* Normalize a version string to always include a caret range prefix.
|
|
55
|
+
*
|
|
56
|
+
* If the version already starts with a range operator (`^`, `~`, `>`, `<`, `=`)
|
|
57
|
+
* it is returned as-is. Otherwise a `^` prefix is added.
|
|
58
|
+
*
|
|
59
|
+
* @param version - The raw version string from the catalog.
|
|
60
|
+
* @returns The version prefixed with `^` when no range operator is present.
|
|
19
61
|
*/
|
|
20
|
-
|
|
62
|
+
function normalizeVersion(version) {
|
|
63
|
+
return match(RANGE_PREFIXES.some((prefix) => version.startsWith(prefix))).with(true, () => version).with(false, () => `^${version}`).exhaustive();
|
|
64
|
+
}
|
|
21
65
|
/**
|
|
22
|
-
*
|
|
66
|
+
* Read template dependency versions from the workspace catalog (`pnpm-workspace.yaml`).
|
|
67
|
+
*
|
|
68
|
+
* Resolves the workspace file from known relative locations, parses the YAML,
|
|
69
|
+
* validates the structure with Zod, and returns normalized version strings
|
|
70
|
+
* suitable for scaffolding `package.json` files in new projects.
|
|
71
|
+
*
|
|
72
|
+
* @returns A `Result` tuple with the resolved versions or an error.
|
|
23
73
|
*/
|
|
24
|
-
|
|
74
|
+
function readTemplateVersions() {
|
|
75
|
+
const yamlPath = findWorkspaceYaml();
|
|
76
|
+
if (yamlPath === null) return err(/* @__PURE__ */ new Error("Could not locate pnpm-workspace.yaml"));
|
|
77
|
+
const [readError, content] = attempt(() => readFileSync(yamlPath, "utf8"));
|
|
78
|
+
if (readError) return err(readError);
|
|
79
|
+
const [parseError, rawParsed] = attempt(() => parse(content));
|
|
80
|
+
if (parseError) return err(parseError);
|
|
81
|
+
const validation = catalogSchema.safeParse(rawParsed);
|
|
82
|
+
if (!validation.success) return err(/* @__PURE__ */ new Error(`Invalid pnpm-workspace.yaml catalog: ${validation.error.message}`));
|
|
83
|
+
const { catalog } = validation.data;
|
|
84
|
+
return ok(Object.freeze({
|
|
85
|
+
tsdownVersion: normalizeVersion(catalog.tsdown),
|
|
86
|
+
typescriptVersion: normalizeVersion(catalog.typescript),
|
|
87
|
+
vitestVersion: normalizeVersion(catalog.vitest),
|
|
88
|
+
zodVersion: normalizeVersion(catalog.zod)
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
25
91
|
//#endregion
|
|
26
92
|
//#region src/commands/init.ts
|
|
27
93
|
const initCommand = command({
|
|
28
94
|
args: z.object({
|
|
95
|
+
config: z.boolean().describe("Include config schema setup").optional(),
|
|
29
96
|
description: z.string().describe("Project description").optional(),
|
|
30
97
|
example: z.boolean().describe("Include example command").optional(),
|
|
31
98
|
name: z.string().describe("Project name (kebab-case)").optional(),
|
|
@@ -41,7 +108,13 @@ const initCommand = command({
|
|
|
41
108
|
const projectDescription = await resolveDescription(ctx);
|
|
42
109
|
const packageManager = await resolvePackageManager(ctx);
|
|
43
110
|
const includeExample = await resolveIncludeExample(ctx);
|
|
111
|
+
const includeConfig = await resolveIncludeConfig(ctx);
|
|
44
112
|
ctx.spinner.start("Scaffolding project...");
|
|
113
|
+
const [versionsError, templateVersions] = readTemplateVersions();
|
|
114
|
+
if (versionsError) {
|
|
115
|
+
ctx.spinner.stop("Failed");
|
|
116
|
+
return ctx.fail(versionsError.message);
|
|
117
|
+
}
|
|
45
118
|
const coreVersion = await resolveDependencyVersion("@kidd-cli/core");
|
|
46
119
|
const cliVersion = await resolveSelfVersion();
|
|
47
120
|
const [renderError, rendered] = await renderTemplate({
|
|
@@ -50,12 +123,10 @@ const initCommand = command({
|
|
|
50
123
|
cliVersion,
|
|
51
124
|
coreVersion,
|
|
52
125
|
description: projectDescription,
|
|
126
|
+
includeConfig,
|
|
53
127
|
name: projectName,
|
|
54
128
|
packageManager,
|
|
55
|
-
|
|
56
|
-
typescriptVersion: TYPESCRIPT_VERSION,
|
|
57
|
-
vitestVersion: VITEST_VERSION,
|
|
58
|
-
zodVersion: ZOD_VERSION
|
|
129
|
+
...templateVersions
|
|
59
130
|
}
|
|
60
131
|
});
|
|
61
132
|
if (renderError) {
|
|
@@ -63,7 +134,10 @@ const initCommand = command({
|
|
|
63
134
|
return ctx.fail(renderError.message);
|
|
64
135
|
}
|
|
65
136
|
const [writeError] = await writeFiles({
|
|
66
|
-
files: selectFiles(
|
|
137
|
+
files: selectFiles({
|
|
138
|
+
includeConfig,
|
|
139
|
+
includeExample
|
|
140
|
+
}, rendered),
|
|
67
141
|
outputDir: join(process.cwd(), projectName),
|
|
68
142
|
overwrite: false
|
|
69
143
|
});
|
|
@@ -72,10 +146,10 @@ const initCommand = command({
|
|
|
72
146
|
return ctx.fail(writeError.message);
|
|
73
147
|
}
|
|
74
148
|
ctx.spinner.stop("Project created!");
|
|
75
|
-
ctx.
|
|
76
|
-
ctx.
|
|
77
|
-
ctx.
|
|
78
|
-
ctx.
|
|
149
|
+
ctx.logger.newline();
|
|
150
|
+
ctx.logger.print("Next steps:");
|
|
151
|
+
ctx.logger.print(` cd ${projectName}`);
|
|
152
|
+
ctx.logger.print(` ${packageManager} install`);
|
|
79
153
|
}
|
|
80
154
|
});
|
|
81
155
|
/**
|
|
@@ -155,26 +229,29 @@ async function resolveIncludeExample(ctx) {
|
|
|
155
229
|
});
|
|
156
230
|
}
|
|
157
231
|
/**
|
|
158
|
-
*
|
|
232
|
+
* Resolve whether to include config schema setup from args or prompt.
|
|
159
233
|
*
|
|
160
|
-
* @param
|
|
161
|
-
* @
|
|
162
|
-
* @returns The filtered file list.
|
|
234
|
+
* @param ctx - Command context.
|
|
235
|
+
* @returns True when the config schema file should be included.
|
|
163
236
|
* @private
|
|
164
237
|
*/
|
|
165
|
-
function
|
|
166
|
-
if (
|
|
167
|
-
return
|
|
238
|
+
async function resolveIncludeConfig(ctx) {
|
|
239
|
+
if (ctx.args.config !== void 0) return ctx.args.config;
|
|
240
|
+
return ctx.prompts.confirm({
|
|
241
|
+
initialValue: false,
|
|
242
|
+
message: "Include config schema?"
|
|
243
|
+
});
|
|
168
244
|
}
|
|
169
245
|
/**
|
|
170
|
-
*
|
|
246
|
+
* Select the rendered files to write, optionally excluding the example command and config.
|
|
171
247
|
*
|
|
172
|
-
* @param
|
|
173
|
-
* @
|
|
248
|
+
* @param options - Flags controlling which optional files to include.
|
|
249
|
+
* @param rendered - The full set of rendered files.
|
|
250
|
+
* @returns The filtered file list.
|
|
174
251
|
* @private
|
|
175
252
|
*/
|
|
176
|
-
function
|
|
177
|
-
return !file.relativePath.includes("commands/hello.ts");
|
|
253
|
+
function selectFiles(options, rendered) {
|
|
254
|
+
return rendered.filter((file) => options.includeExample || !file.relativePath.includes("commands/hello.ts")).filter((file) => options.includeConfig || !file.relativePath.includes("config.ts"));
|
|
178
255
|
}
|
|
179
256
|
const DEFAULT_VERSION = "0.0.0";
|
|
180
257
|
/**
|
|
@@ -189,7 +266,10 @@ const DEFAULT_VERSION = "0.0.0";
|
|
|
189
266
|
*/
|
|
190
267
|
async function resolveSelfVersion() {
|
|
191
268
|
const [error, manifest] = await readManifest(join(import.meta.dirname, "..", ".."));
|
|
192
|
-
if (error || !manifest.version)
|
|
269
|
+
if (error || !manifest.version) {
|
|
270
|
+
console.warn("Warning: Could not resolve CLI version, using fallback 0.0.0");
|
|
271
|
+
return DEFAULT_VERSION;
|
|
272
|
+
}
|
|
193
273
|
return manifest.version;
|
|
194
274
|
}
|
|
195
275
|
/**
|
|
@@ -206,9 +286,15 @@ async function resolveSelfVersion() {
|
|
|
206
286
|
async function resolveDependencyVersion(packageName) {
|
|
207
287
|
const require = createRequire(import.meta.url);
|
|
208
288
|
const [resolveError, entryPath] = attempt(() => require.resolve(packageName));
|
|
209
|
-
if (resolveError || entryPath === null)
|
|
289
|
+
if (resolveError || entryPath === null) {
|
|
290
|
+
console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
|
|
291
|
+
return DEFAULT_VERSION;
|
|
292
|
+
}
|
|
210
293
|
const [manifestError, manifest] = await readManifest(join(dirname(entryPath), ".."));
|
|
211
|
-
if (manifestError || !manifest.version)
|
|
294
|
+
if (manifestError || !manifest.version) {
|
|
295
|
+
console.warn(`Warning: Could not resolve version for ${packageName}, using fallback 0.0.0`);
|
|
296
|
+
return DEFAULT_VERSION;
|
|
297
|
+
}
|
|
212
298
|
return manifest.version;
|
|
213
299
|
}
|
|
214
300
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -7,27 +7,31 @@ 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,
|
|
@@ -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,15 @@
|
|
|
1
|
+
packages:
|
|
2
|
+
- packages/*
|
|
3
|
+
- examples/*
|
|
4
|
+
|
|
5
|
+
catalog:
|
|
6
|
+
'@types/node': ^25.5.0
|
|
7
|
+
'@vitest/coverage-v8': ^4.1.0
|
|
8
|
+
es-toolkit: ^1.45.1
|
|
9
|
+
liquidjs: ^10.25.0
|
|
10
|
+
ts-pattern: ^5.9.0
|
|
11
|
+
tsdown: 0.21.3
|
|
12
|
+
tsx: ^4.21.0
|
|
13
|
+
typescript: ^5.9.3
|
|
14
|
+
vitest: ^4.1.0
|
|
15
|
+
zod: ^4.3.6
|
|
@@ -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.1",
|
|
4
4
|
"description": "DX companion CLI for the kidd framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -25,21 +25,21 @@
|
|
|
25
25
|
"fs-extra": "^11.3.4",
|
|
26
26
|
"liquidjs": "^10.25.0",
|
|
27
27
|
"picocolors": "^1.1.1",
|
|
28
|
+
"yaml": "^2.8.2",
|
|
28
29
|
"zod": "^4.3.6",
|
|
29
|
-
"@kidd-cli/bundler": "0.2.
|
|
30
|
-
"@kidd-cli/config": "0.1.
|
|
31
|
-
"@kidd-cli/core": "0.
|
|
30
|
+
"@kidd-cli/bundler": "0.2.1",
|
|
31
|
+
"@kidd-cli/config": "0.1.5",
|
|
32
|
+
"@kidd-cli/core": "0.5.1",
|
|
32
33
|
"@kidd-cli/utils": "0.1.4"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/fs-extra": "^11.0.4",
|
|
36
|
-
"tsdown": "0.21.
|
|
37
|
+
"tsdown": "0.21.3",
|
|
37
38
|
"typescript": "^5.9.3",
|
|
38
|
-
"vitest": "^4.0
|
|
39
|
-
"yaml": "^2.8.0"
|
|
39
|
+
"vitest": "^4.1.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"build": "tsdown && mkdir -p dist/lib && cp -r src/lib/templates dist/lib/templates",
|
|
42
|
+
"build": "tsdown && mkdir -p dist/lib && cp -r src/lib/templates dist/lib/templates && cp ../../pnpm-workspace.yaml dist/pnpm-workspace.yaml",
|
|
43
43
|
"typecheck": "tsgo --noEmit",
|
|
44
44
|
"lint": "oxlint --ignore-pattern node_modules",
|
|
45
45
|
"lint:fix": "oxlint --fix --ignore-pattern node_modules",
|
|
File without changes
|