@cosmicdrift/kumiko-cli 0.386.0 → 0.388.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 CHANGED
@@ -1,57 +1,21 @@
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marc Frost
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-cli",
3
- "version": "0.386.0",
3
+ "version": "0.388.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
- "license": "BUSL-1.1",
5
+ "license": "MIT",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
7
7
  "repository": {
8
8
  "type": "git",
@@ -36,18 +36,18 @@
36
36
  }
37
37
  },
38
38
  "dependencies": {
39
- "@cosmicdrift/kumiko-dev-server": "0.386.0",
40
- "@cosmicdrift/kumiko-guards": "0.386.0",
41
- "@cosmicdrift/kumiko-server-runtime": "0.386.0",
42
- "@cosmicdrift/kumiko-testing": "0.386.0",
39
+ "@cosmicdrift/kumiko-dev-server": "0.388.0",
40
+ "@cosmicdrift/kumiko-guards": "0.388.0",
41
+ "@cosmicdrift/kumiko-server-runtime": "0.388.0",
42
+ "@cosmicdrift/kumiko-testing": "0.388.0",
43
43
  "marked": "^18.0.3",
44
44
  "zod": "^4.4.3"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "sharp": "^0.35.5",
48
- "@cosmicdrift/kumiko-bundled-features": "0.386.0",
49
- "@cosmicdrift/kumiko-framework": "0.386.0",
50
- "@cosmicdrift/kumiko-renderer": "0.386.0"
48
+ "@cosmicdrift/kumiko-bundled-features": "0.388.0",
49
+ "@cosmicdrift/kumiko-framework": "0.388.0",
50
+ "@cosmicdrift/kumiko-renderer": "0.388.0"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "sharp": {
@@ -64,9 +64,9 @@
64
64
  }
65
65
  },
66
66
  "devDependencies": {
67
- "@cosmicdrift/kumiko-bundled-features": "0.386.0",
68
- "@cosmicdrift/kumiko-framework": "0.386.0",
69
- "@cosmicdrift/kumiko-renderer": "0.386.0",
67
+ "@cosmicdrift/kumiko-bundled-features": "0.388.0",
68
+ "@cosmicdrift/kumiko-framework": "0.388.0",
69
+ "@cosmicdrift/kumiko-renderer": "0.388.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.388.0",
4
+ "type": "fix",
5
+ "title": "check, sync-managed and backfill-pii handle failure and subdirectories correctly",
6
+ "detail": "kumiko check only warns about unresolvable managed files or package.json scripts until kumiko.config.ts calls defineAppConfig. sync-managed resolves the repo root like check instead of using cwd. ops backfill-pii closes the KMS wiring when registry creation fails. The agent command reuses allAppFeatures from the framework config."
7
+ },
2
8
  {
3
9
  "version": "0.379.0",
4
10
  "type": "improvement",
@@ -1,5 +1,6 @@
1
1
  import { join } from "node:path";
2
- import { allConfiguredFeatures, loadAppConfig } from "./load-app-config";
2
+ import { allAppFeatures } from "@cosmicdrift/kumiko-framework/config";
3
+ import { loadAppConfig } from "./load-app-config";
3
4
  import type { CliCommand } from "./types";
4
5
 
5
6
  const LINT_SUBCOMMAND = "lint";
@@ -26,7 +27,9 @@ export const agentCommand: CliCommand = {
26
27
  ctx.out.err(" // kumiko.config.ts");
27
28
  ctx.out.err(' import { defineAppConfig } from "@cosmicdrift/kumiko-framework/config";');
28
29
  ctx.out.err(' import { myFeature } from "./src/features/my-feature";');
29
- ctx.out.err(" export default defineAppConfig({ features: [myFeature], client, ports });");
30
+ ctx.out.err(
31
+ ' export default defineAppConfig({ features: [myFeature], client: { entries: ["src/client.tsx"] }, ports: { dev: 4173, e2e: 4174 } });',
32
+ );
30
33
  ctx.out.err("");
31
34
  return 1;
32
35
  }
@@ -37,7 +40,7 @@ export const agentCommand: CliCommand = {
37
40
  "@cosmicdrift/kumiko-bundled-features/agent-tools"
38
41
  );
39
42
 
40
- const features = allConfiguredFeatures(config);
43
+ const features = allAppFeatures(config);
41
44
  const gaps = findAgentDocGaps(features);
42
45
  const translationGaps = findHandlerTranslationGaps(features);
43
46
 
@@ -35,8 +35,26 @@ export async function runManagedCheckStep(
35
35
  uiRoots: readonly string[],
36
36
  ): Promise<number> {
37
37
  const managed: ManagedFilesModule = await import("@cosmicdrift/kumiko-dev-server/managed-files");
38
- const facts = managed.resolveManagedAppFacts({ appRoot: repoRoot, uiRoots });
39
- const result = managed.checkManagedFiles(facts);
38
+ let result: ReturnType<ManagedFilesModule["checkManagedFiles"]>;
39
+ try {
40
+ result = managed.checkManagedFiles(
41
+ managed.resolveManagedAppFacts({ appRoot: repoRoot, uiRoots }),
42
+ );
43
+ } catch (error) {
44
+ // Before defineAppConfig is adopted the managed step only warns, also when the facts cannot be resolved.
45
+ if (managed.readStaticAppConfig(repoRoot).kind === "defined") throw error;
46
+ out.log(` ! ${error instanceof Error ? error.message : String(error)}`);
47
+ out.log(` ${NOT_ADOPTED_NOTE}`);
48
+ return 0;
49
+ }
50
+ return reportManagedCheck(out, managed, result);
51
+ }
52
+
53
+ function reportManagedCheck(
54
+ out: Output,
55
+ managed: ManagedFilesModule,
56
+ result: ReturnType<ManagedFilesModule["checkManagedFiles"]>,
57
+ ): number {
40
58
  const drift = result.files.filter(managed.isManagedDrift);
41
59
  const local = result.files.filter((report) => report.state === "local");
42
60
  const okCount = result.files.length - drift.length - local.length;
@@ -28,8 +28,16 @@ export async function runScriptsCheckStep(
28
28
  uiRoots: readonly string[],
29
29
  ): Promise<number> {
30
30
  const managed: ManagedFilesModule = await import("@cosmicdrift/kumiko-dev-server/managed-files");
31
- const report = managed.checkAppScripts(readScripts(repoRoot), { hasUi: uiRoots.length > 0 });
32
31
  const adopted = managed.readStaticAppConfig(repoRoot).kind === "defined";
32
+ let scripts: Record<string, string>;
33
+ try {
34
+ scripts = readScripts(repoRoot);
35
+ } catch (error) {
36
+ if (adopted) throw error;
37
+ out.log(` ! ${error instanceof Error ? error.message : String(error)}`);
38
+ return 0;
39
+ }
40
+ const report = managed.checkAppScripts(scripts, { hasUi: uiRoots.length > 0 });
33
41
  if (report.knownExtras.length > 0)
34
42
  out.log(` extras (standard): ${report.knownExtras.join(", ")}`);
35
43
  if (report.appExtras.length > 0) out.log(` extras (app): ${report.appExtras.join(", ")}`);
@@ -9,7 +9,7 @@ export const CLI_KMS_SLOTS = [
9
9
 
10
10
  // A rebuild replays applyEntityEvent, which computes bidx columns from the
11
11
  // boot-injected blind-index key and subject KMS. This standalone CLI never
12
- // boots the app, so without wiring them a rebuild nulls the bidx columns (fw#3091).
12
+ // boots the app, so without wiring them a rebuild nulls the bidx columns.
13
13
  // Plaintext is refused for apps with PII carriers, like the prod boot does, unless
14
14
  // the operator names a reason.
15
15
  export async function wireKmsFromEnv(options: {
@@ -20,11 +20,6 @@ function isAppConfig(value: unknown): value is AppConfig {
20
20
  );
21
21
  }
22
22
 
23
- /** Everything prod mounts: lint and docs checks must see the prod-only features too. */
24
- export function allConfiguredFeatures(config: AppConfig): readonly FeatureDefinition[] {
25
- return [...config.features, ...(config.prodFeatures ?? [])];
26
- }
27
-
28
23
  // kumiko.config.ts is user-authored: a missing default export or `features`
29
24
  // array must produce a readable message, not a TypeError further down.
30
25
  export async function loadAppConfig(
@@ -38,7 +33,9 @@ export async function loadAppConfig(
38
33
  ctx.out.err("");
39
34
  ctx.out.err(` ${configPath} must default-export an object with a "features" array:`);
40
35
  ctx.out.err(' import { defineAppConfig } from "@cosmicdrift/kumiko-framework/config";');
41
- ctx.out.err(" export default defineAppConfig({ features: [myFeature], client, ports });");
36
+ ctx.out.err(
37
+ ' export default defineAppConfig({ features: [myFeature], client: { entries: ["src/client.tsx"] }, ports: { dev: 4173, e2e: 4174 } });',
38
+ );
42
39
  ctx.out.err("");
43
40
  return null;
44
41
  }
@@ -219,20 +219,22 @@ export async function runBackfillPii(ctx: CliCommandContext): Promise<number> {
219
219
  ctx.out.err(errorMessage(e));
220
220
  return 1;
221
221
  }
222
- crypto.configurePiiSubjectKms(wiring.kms);
223
- crypto.configureBlindIndexKey(wiring.blindIndexKey);
224
-
225
- const registry = createRegistry(config.features);
226
- const { db, close } = createDbConnection({ url: databaseUrl, maxConnections: 4 });
227
222
  try {
228
- return args.mode === "rebuild"
229
- ? await rebuildPiiProjections(ctx, db, registry, crypto)
230
- : await backfillPii(ctx, db, registry, args);
223
+ crypto.configurePiiSubjectKms(wiring.kms);
224
+ crypto.configureBlindIndexKey(wiring.blindIndexKey);
225
+ const registry = createRegistry(config.features);
226
+ const { db, close } = createDbConnection({ url: databaseUrl, maxConnections: 4 });
227
+ try {
228
+ return args.mode === "rebuild"
229
+ ? await rebuildPiiProjections(ctx, db, registry, crypto)
230
+ : await backfillPii(ctx, db, registry, args);
231
+ } finally {
232
+ await close();
233
+ }
231
234
  } catch (e) {
232
235
  ctx.out.err(`${LOG_PREFIX} ${errorMessage(e)}`);
233
236
  return 1;
234
237
  } finally {
235
- await close();
236
238
  // The KMS pool keeps the process alive otherwise.
237
239
  await wiring.close();
238
240
  }
@@ -57,7 +57,7 @@ export const waitlistMigrateOp = {
57
57
  });
58
58
  ctx.out.log("");
59
59
  ctx.out.log(
60
- ` ${dryRun ? "[dry-run] " : ""}waitlist-migrate --from ${from}: read ${report.read}, ${dryRun ? "would create" : "created"} ${report.created}, already present ${report.skipped}, unreadable ${report.unreadable}, legacy streams archived ${report.archivedStreams}`,
60
+ ` ${dryRun ? "[dry-run] " : ""}waitlist-migrate --from ${from}: read ${report.read}, ${dryRun ? "would create" : "created"} ${report.created}, already present ${report.skipped}, unreadable ${report.unreadable}, legacy streams ${dryRun ? "would archive" : "archived"} ${report.archivedStreams}`,
61
61
  );
62
62
  ctx.out.log("");
63
63
  return report.unreadable > 0 ? 1 : 0;
@@ -1,4 +1,4 @@
1
- import { loadRepoManifest, REPO_MANIFEST_FILE } from "../repo-manifest";
1
+ import { REPO_MANIFEST_FILE } from "../repo-manifest";
2
2
  import type { CliCommand, CliCommandContext } from "./types";
3
3
 
4
4
  const SYNC_FLAGS = ["--write", "--adopt"] as const;
@@ -11,9 +11,13 @@ export async function runSyncManaged(ctx: CliCommandContext): Promise<number> {
11
11
  );
12
12
  return 1;
13
13
  }
14
- const { manifest } = loadRepoManifest(ctx.cwd, {
15
- warn: (message) => ctx.out.err(` ${message}`),
16
- });
14
+ const { findLocalRepo } = await import("@cosmicdrift/kumiko-guards");
15
+ const repo = findLocalRepo(ctx.cwd);
16
+ if (repo === undefined) {
17
+ ctx.out.err(` No Kumiko repo above ${ctx.cwd}. Add a ${REPO_MANIFEST_FILE} at the repo root.`);
18
+ return 1;
19
+ }
20
+ const { manifest } = repo;
17
21
  if (manifest.kind !== "app") {
18
22
  ctx.out.err(
19
23
  ` sync-managed needs kind "app" in ${REPO_MANIFEST_FILE}, got "${manifest.kind}".`,
@@ -23,7 +27,7 @@ export async function runSyncManaged(ctx: CliCommandContext): Promise<number> {
23
27
  const write = ctx.argv.includes("--write");
24
28
  const managed = await import("@cosmicdrift/kumiko-dev-server/managed-files");
25
29
  const facts = managed.resolveManagedAppFacts({
26
- appRoot: ctx.cwd,
30
+ appRoot: repo.absPath,
27
31
  uiRoots: manifest.uiRoots ?? [],
28
32
  });
29
33
  for (const error of managed.listManagedErrors(facts)) ctx.out.err(` ✗ ${error}`);
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- // biome-ignore-all lint/suspicious/noConsole: CLI-Script, console ist Feature.
1
+ // biome-ignore-all lint/suspicious/noConsole: CLI script; console is an intentional feature.
2
2
  //
3
3
  // runCli — programmatic entry-point for the kumiko CLI. The bin-shim
4
4
  // (../bin/cli.ts) is a 3-line wrapper that forwards process.argv. Tests