@cosmicdrift/kumiko-cli 0.364.0 → 0.365.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/package.json +8 -8
- package/src/changes.json +6 -0
- package/src/commands/handbuch.ts +23 -2
- package/src/missing-peer.ts +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.365.0",
|
|
4
4
|
"description": "CLI for Kumiko apps. `bunx @cosmicdrift/kumiko-cli new app <name>` scaffolds a runnable workspace; `add feature <name>` mounts a feature; `check` runs boot validation plus the guard suites with the step list derived from kumiko.json; `agent lint`, `project` and `consumer` operate on an existing app; `handbuch build` renders the HTML handbuch.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@cosmicdrift/kumiko-dev-server": "0.
|
|
40
|
-
"@cosmicdrift/kumiko-guards": "0.
|
|
41
|
-
"@cosmicdrift/kumiko-repo-manifest": "0.
|
|
42
|
-
"@cosmicdrift/kumiko-testing": "0.
|
|
39
|
+
"@cosmicdrift/kumiko-dev-server": "0.365.0",
|
|
40
|
+
"@cosmicdrift/kumiko-guards": "0.365.0",
|
|
41
|
+
"@cosmicdrift/kumiko-repo-manifest": "0.365.0",
|
|
42
|
+
"@cosmicdrift/kumiko-testing": "0.365.0",
|
|
43
43
|
"marked": "^18.0.3",
|
|
44
44
|
"zod": "^4.4.3"
|
|
45
45
|
},
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
68
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
69
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
67
|
+
"@cosmicdrift/kumiko-bundled-features": "0.365.0",
|
|
68
|
+
"@cosmicdrift/kumiko-framework": "0.365.0",
|
|
69
|
+
"@cosmicdrift/kumiko-headless": "0.365.0",
|
|
70
70
|
"sharp": "^0.35.5"
|
|
71
71
|
},
|
|
72
72
|
"publishConfig": {
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.365.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "kumiko handbuch build refuses a dangerous --out; missing-peer message tells an outdated install from a missing one",
|
|
6
|
+
"detail": "handbuch build deletes the output directory before building, so `--out .` or `--out <root>` removed the checkout. The command now exits 2 when --out is, or contains, the working directory, --root or a configured source repo. When an installed @cosmicdrift package lacks a requested subpath, the error asks for an upgrade instead of recommending bun add."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.357.0",
|
|
4
10
|
"type": "improvement",
|
package/src/commands/handbuch.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { basename, join, resolve } from "node:path";
|
|
1
|
+
import { basename, isAbsolute, join, relative, resolve } from "node:path";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
import { ZodError } from "zod";
|
|
4
4
|
import type { HandbuchConfig } from "../handbuch/config";
|
|
@@ -41,6 +41,11 @@ function appSlug(configPath: string): string {
|
|
|
41
41
|
return basename(configPath).replace(/\.json$/, "") || "handbuch";
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function containsPath(parentDir: string, candidate: string): boolean {
|
|
45
|
+
const rel = relative(parentDir, candidate);
|
|
46
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
async function runBuild(ctx: CliCommandContext, args: ReadonlyArray<string>): Promise<number> {
|
|
45
50
|
let parsed: ReturnType<
|
|
46
51
|
typeof parseArgs<{ options: typeof BUILD_OPTIONS; allowPositionals: true }>
|
|
@@ -82,11 +87,27 @@ async function runBuild(ctx: CliCommandContext, args: ReadonlyArray<string>): Pr
|
|
|
82
87
|
return 2;
|
|
83
88
|
}
|
|
84
89
|
|
|
90
|
+
// buildHandbuch wipes outDir recursively, so a mistyped --out must never be
|
|
91
|
+
// (or contain) a directory the build reads from or the user works in.
|
|
92
|
+
const outDir = resolve(ctx.cwd, values.out ?? join(rootDir, ".handbuch", appSlug(configPath)));
|
|
93
|
+
const protectedDirs = [
|
|
94
|
+
ctx.cwd,
|
|
95
|
+
rootDir,
|
|
96
|
+
resolve(rootDir, config.repo),
|
|
97
|
+
...(config.flowSources ?? []).map((source) => resolve(rootDir, source.repo)),
|
|
98
|
+
];
|
|
99
|
+
if (protectedDirs.some((dir) => containsPath(outDir, dir))) {
|
|
100
|
+
return usageError(
|
|
101
|
+
ctx,
|
|
102
|
+
`Refusing to build into ${outDir}: it is or contains the working directory, --root or a source repo, and is deleted before the build.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
85
106
|
const optionalDir = (value: string | undefined) => (value ? resolve(ctx.cwd, value) : undefined);
|
|
86
107
|
try {
|
|
87
108
|
const result = await buildHandbuch(config, {
|
|
88
109
|
rootDir,
|
|
89
|
-
outDir
|
|
110
|
+
outDir,
|
|
90
111
|
shotsDir: optionalDir(values.shots),
|
|
91
112
|
textsDir: optionalDir(values.texts),
|
|
92
113
|
flowShotsDir: optionalDir(values["web-shots"]),
|
package/src/missing-peer.ts
CHANGED
|
@@ -6,12 +6,18 @@ const APP_PEER_PACKAGES = [
|
|
|
6
6
|
|
|
7
7
|
// The runtime packages are optional peers (so `new app` runs without them); a
|
|
8
8
|
// command that needs one must report the missing install, not a resolver stacktrace.
|
|
9
|
+
// A subpath miss means the package is installed but too old for the requested export.
|
|
9
10
|
export function missingPeerMessage(error: unknown): string | undefined {
|
|
10
11
|
if (!(error instanceof Error)) return undefined;
|
|
12
|
+
if (!/cannot find (package|module)/i.test(error.message)) return undefined;
|
|
11
13
|
for (const peer of APP_PEER_PACKAGES) {
|
|
12
|
-
if (error.message.includes(`'${peer}`)
|
|
14
|
+
if (error.message.includes(`'${peer}'`)) {
|
|
13
15
|
return `${peer} is not installed. Install ${peer} in your app (bun add ${peer}).`;
|
|
14
16
|
}
|
|
17
|
+
const subpath = error.message.match(new RegExp(`'${peer}(/[^']*)'`))?.[1];
|
|
18
|
+
if (subpath !== undefined) {
|
|
19
|
+
return `Installed ${peer} lacks ${subpath.slice(1)}. Upgrade ${peer} in your app.`;
|
|
20
|
+
}
|
|
15
21
|
}
|
|
16
22
|
return undefined;
|
|
17
23
|
}
|