@cosmicdrift/kumiko-cli 0.363.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/LICENSE ADDED
@@ -0,0 +1,57 @@
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: Marc Frost
6
+
7
+ Licensed Work: @cosmicdrift/kumiko-framework
8
+ The Licensed Work is © 2026 Marc Frost.
9
+
10
+ Additional Use Grant:
11
+ You may use the Licensed Work in production for any purpose, including
12
+ commercially, EXCEPT for the Restricted Use.
13
+
14
+ "Restricted Use" is defined as using the Licensed Work to provide a platform
15
+ or service to third parties that allows them to host, deploy, or run their
16
+ own applications built with the Licensed Work. This includes, but is not
17
+ limited to: managed hosting services, software-as-a-service (SaaS) platforms,
18
+ platform-as-a-service (PaaS), developer platforms, or any multi-tenant
19
+ managed offering of the Licensed Work.
20
+
21
+ This restriction does not apply to the Licensor, any entity controlled by,
22
+ controlling, or under common control with the Licensor ("Affiliates"), or
23
+ contractors acting on their behalf. The Licensor remains free to use the
24
+ Licensed Work for any purpose, including for the operation of kumiko.rocks.
25
+
26
+ Change Date: 2030-05-05
27
+ Change License: Apache License, Version 2.0
28
+
29
+
30
+ Terms
31
+
32
+ The Licensor hereby grants you the right to copy, modify, create derivative works,
33
+ redistribute, and make non-production use of the Licensed Work. The Licensor may
34
+ make an Additional Use Grant, above, permitting limited production use.
35
+
36
+ Effective on the Change Date, or the fourth anniversary of the first publicly
37
+ available distribution of the Licensed Work under this License, whichever comes
38
+ first, this License will convert to the Change License.
39
+
40
+ This Business Source License governs use of the Licensed Work in all cases, except
41
+ as to any use that is explicitly granted in the Additional Use Grant above or
42
+ under the Change License after the Change Date.
43
+
44
+ If your use of the Licensed Work does not comply with the requirements of this
45
+ License, you must cease use of the Licensed Work immediately.
46
+
47
+ All copies of the Licensed Work, and all derivative works thereof, must include
48
+ this License.
49
+
50
+ This License does not grant you any right, title, or interest in any trademark,
51
+ logo, or branding of the Licensor, except as required to comply with this License.
52
+
53
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
54
+ “AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
55
+ WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
56
+ TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
57
+ ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-cli",
3
- "version": "0.363.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.363.0",
40
- "@cosmicdrift/kumiko-guards": "0.363.0",
41
- "@cosmicdrift/kumiko-repo-manifest": "0.363.0",
42
- "@cosmicdrift/kumiko-testing": "0.363.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.363.0",
68
- "@cosmicdrift/kumiko-framework": "0.363.0",
69
- "@cosmicdrift/kumiko-headless": "0.363.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",
@@ -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: resolve(ctx.cwd, values.out ?? join(rootDir, ".handbuch", appSlug(configPath))),
110
+ outDir,
90
111
  shotsDir: optionalDir(values.shots),
91
112
  textsDir: optionalDir(values.texts),
92
113
  flowShotsDir: optionalDir(values["web-shots"]),
@@ -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}`) && /cannot find (package|module)/i.test(error.message)) {
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
  }