@metaobjectsdev/cli 1.0.9 → 1.0.11
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/src/commands/deps.d.ts.map +1 -1
- package/dist/src/commands/deps.js +9 -8
- package/dist/src/commands/deps.js.map +1 -1
- package/dist/src/commands/docs.d.ts.map +1 -1
- package/dist/src/commands/docs.js +19 -12
- package/dist/src/commands/docs.js.map +1 -1
- package/dist/src/commands/eject.d.ts.map +1 -1
- package/dist/src/commands/eject.js +8 -3
- package/dist/src/commands/eject.js.map +1 -1
- package/dist/src/commands/export.d.ts.map +1 -1
- package/dist/src/commands/export.js +3 -2
- package/dist/src/commands/export.js.map +1 -1
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +15 -7
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/generator.d.ts.map +1 -1
- package/dist/src/commands/generator.js +3 -2
- package/dist/src/commands/generator.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +5 -2
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +31 -23
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/prompt-snapshot.d.ts.map +1 -1
- package/dist/src/commands/prompt-snapshot.js +5 -4
- package/dist/src/commands/prompt-snapshot.js.map +1 -1
- package/dist/src/commands/types.d.ts.map +1 -1
- package/dist/src/commands/types.js +7 -1
- package/dist/src/commands/types.js.map +1 -1
- package/dist/src/commands/upgrade.d.ts.map +1 -1
- package/dist/src/commands/upgrade.js +4 -3
- package/dist/src/commands/upgrade.js.map +1 -1
- package/dist/src/commands/verify.d.ts.map +1 -1
- package/dist/src/commands/verify.js +73 -24
- package/dist/src/commands/verify.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/args.d.ts +11 -0
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +19 -6
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/catalog-listing.d.ts.map +1 -1
- package/dist/src/lib/catalog-listing.js +5 -1
- package/dist/src/lib/catalog-listing.js.map +1 -1
- package/dist/src/lib/dependency-sync.d.ts.map +1 -1
- package/dist/src/lib/dependency-sync.js +4 -3
- package/dist/src/lib/dependency-sync.js.map +1 -1
- package/dist/src/lib/error-text.d.ts +2 -0
- package/dist/src/lib/error-text.d.ts.map +1 -0
- package/dist/src/lib/error-text.js +15 -0
- package/dist/src/lib/error-text.js.map +1 -0
- package/dist/src/lib/fk-index-advisory.d.ts.map +1 -1
- package/dist/src/lib/fk-index-advisory.js +4 -1
- package/dist/src/lib/fk-index-advisory.js.map +1 -1
- package/dist/src/lib/gen-migrate-advice.d.ts +1 -1
- package/dist/src/lib/gen-migrate-advice.d.ts.map +1 -1
- package/dist/src/lib/gen-migrate-advice.js +24 -0
- package/dist/src/lib/gen-migrate-advice.js.map +1 -1
- package/dist/src/lib/git-ignore.d.ts.map +1 -1
- package/dist/src/lib/git-ignore.js +2 -1
- package/dist/src/lib/git-ignore.js.map +1 -1
- package/dist/src/lib/name-lint.d.ts +12 -0
- package/dist/src/lib/name-lint.d.ts.map +1 -0
- package/dist/src/lib/name-lint.js +95 -0
- package/dist/src/lib/name-lint.js.map +1 -0
- package/dist/src/lib/output.d.ts +3 -2
- package/dist/src/lib/output.d.ts.map +1 -1
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/requirement-check.d.ts.map +1 -1
- package/dist/src/lib/requirement-check.js +43 -2
- package/dist/src/lib/requirement-check.js.map +1 -1
- package/dist/src/lib/runtime-boundary-advisory.d.ts +24 -0
- package/dist/src/lib/runtime-boundary-advisory.d.ts.map +1 -0
- package/dist/src/lib/runtime-boundary-advisory.js +47 -0
- package/dist/src/lib/runtime-boundary-advisory.js.map +1 -0
- package/package.json +10 -10
- package/src/commands/deps.ts +9 -8
- package/src/commands/docs.ts +19 -12
- package/src/commands/eject.ts +9 -3
- package/src/commands/export.ts +3 -2
- package/src/commands/gen.ts +17 -7
- package/src/commands/generator.ts +3 -2
- package/src/commands/init.ts +5 -2
- package/src/commands/migrate.ts +33 -23
- package/src/commands/prompt-snapshot.ts +5 -4
- package/src/commands/types.ts +6 -1
- package/src/commands/upgrade.ts +4 -3
- package/src/commands/verify.ts +83 -24
- package/src/index.ts +14 -2
- package/src/lib/args.ts +28 -6
- package/src/lib/catalog-listing.ts +5 -1
- package/src/lib/dependency-sync.ts +4 -3
- package/src/lib/error-text.ts +13 -0
- package/src/lib/fk-index-advisory.ts +4 -1
- package/src/lib/gen-migrate-advice.ts +24 -1
- package/src/lib/git-ignore.ts +2 -1
- package/src/lib/name-lint.ts +106 -0
- package/src/lib/output.ts +3 -2
- package/src/lib/requirement-check.ts +46 -2
- package/src/lib/runtime-boundary-advisory.ts +74 -0
package/src/commands/docs.ts
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
} from "@metaobjectsdev/migrate-ts";
|
|
57
57
|
import type { AgentSchemaInput, SchemaColumnLike } from "@metaobjectsdev/codegen-ts";
|
|
58
58
|
import { reportLoadError } from "../lib/load-error.js";
|
|
59
|
+
import { describeError } from "../lib/error-text.js";
|
|
59
60
|
|
|
60
61
|
/**
|
|
61
62
|
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
@@ -286,6 +287,12 @@ function buildAgentSchemaInput(
|
|
|
286
287
|
);
|
|
287
288
|
return undefined;
|
|
288
289
|
}
|
|
290
|
+
// MySQL: MetaObjects does not own the schema, so there is no migrate-built schema to
|
|
291
|
+
// describe. The generated Drizzle tables are the description.
|
|
292
|
+
if (configured === "mysql") {
|
|
293
|
+
log.warn("docs: agent/schema.md skipped — MetaObjects does not own a MySQL schema (the generated Drizzle tables describe it).");
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
289
296
|
const dialect = configured ?? DEFAULT_DIALECT;
|
|
290
297
|
try {
|
|
291
298
|
const built = buildExpectedSchemaWithProvenance(root, {
|
|
@@ -313,7 +320,7 @@ function buildAgentSchemaInput(
|
|
|
313
320
|
// agent pages still emit.
|
|
314
321
|
log.warn(
|
|
315
322
|
`docs: agent/schema.md skipped — the expected schema could not be built ` +
|
|
316
|
-
`(${(err
|
|
323
|
+
`(${describeError(err)}). Run 'meta migrate' for the full diagnosis.`,
|
|
317
324
|
);
|
|
318
325
|
return undefined;
|
|
319
326
|
}
|
|
@@ -331,7 +338,7 @@ export async function docsCommand(
|
|
|
331
338
|
try {
|
|
332
339
|
flags = parseDocsArgs(args, cwd);
|
|
333
340
|
} catch (err) {
|
|
334
|
-
log.error(`docs: ${(err
|
|
341
|
+
log.error(`docs: ${describeError(err)}`);
|
|
335
342
|
return 2;
|
|
336
343
|
}
|
|
337
344
|
|
|
@@ -418,7 +425,7 @@ export async function docsCommand(
|
|
|
418
425
|
flags.projectRootProvided ? { explicitDir: metaRoot } : undefined,
|
|
419
426
|
);
|
|
420
427
|
} catch (err) {
|
|
421
|
-
log.error(`docs: ${(err
|
|
428
|
+
log.error(`docs: ${describeError(err)}`);
|
|
422
429
|
return 2;
|
|
423
430
|
}
|
|
424
431
|
|
|
@@ -468,7 +475,7 @@ export async function docsCommand(
|
|
|
468
475
|
configLoadOptions = loadMemoryOptionsFrom(loadedConfig);
|
|
469
476
|
} catch (err) {
|
|
470
477
|
log.warn(
|
|
471
|
-
`docs: metaobjects.config.ts failed to load (${(err
|
|
478
|
+
`docs: metaobjects.config.ts failed to load (${describeError(err)}); ` +
|
|
472
479
|
`generating docs without its providers`,
|
|
473
480
|
);
|
|
474
481
|
loadedConfig = undefined;
|
|
@@ -558,7 +565,7 @@ export async function docsCommand(
|
|
|
558
565
|
suite = resolveGenerators(loadedConfig?.generators ?? []);
|
|
559
566
|
} catch (err) {
|
|
560
567
|
log.warn(
|
|
561
|
-
`docs: could not resolve the generator suite (${(err
|
|
568
|
+
`docs: could not resolve the generator suite (${describeError(err)}) — the agent ` +
|
|
562
569
|
`pages fall back to the generators declared as values, so a tier wired by name may ` +
|
|
563
570
|
`be missing from them.`,
|
|
564
571
|
);
|
|
@@ -618,7 +625,7 @@ export async function docsCommand(
|
|
|
618
625
|
try {
|
|
619
626
|
modelFiles = await docsFile(modelOpts).generate(ctx);
|
|
620
627
|
} catch (err) {
|
|
621
|
-
const msg = (err
|
|
628
|
+
const msg = describeError(err);
|
|
622
629
|
// Duplicate output path (silent-overwrite backstop): the generator already
|
|
623
630
|
// names both colliding FQNs + the path and starts with "docs:". Surface it
|
|
624
631
|
// verbatim as a clean non-zero exit (no double prefix, no stack trace).
|
|
@@ -674,7 +681,7 @@ export async function docsCommand(
|
|
|
674
681
|
);
|
|
675
682
|
}
|
|
676
683
|
} catch (err) {
|
|
677
|
-
const msg = (err
|
|
684
|
+
const msg = describeError(err);
|
|
678
685
|
if (msg.startsWith("docs: duplicate output path")) {
|
|
679
686
|
log.error(msg);
|
|
680
687
|
return 1;
|
|
@@ -737,7 +744,7 @@ export async function docsCommand(
|
|
|
737
744
|
await writeFile(path, f.content, "utf8");
|
|
738
745
|
}
|
|
739
746
|
} catch (err) {
|
|
740
|
-
log.error(`docs: failed to write pages: ${(err
|
|
747
|
+
log.error(`docs: failed to write pages: ${describeError(err)}`);
|
|
741
748
|
return 1;
|
|
742
749
|
}
|
|
743
750
|
|
|
@@ -806,7 +813,7 @@ async function scaffoldSiteCommand(projectRoot: string): Promise<number> {
|
|
|
806
813
|
created.push(rel);
|
|
807
814
|
}
|
|
808
815
|
} catch (err) {
|
|
809
|
-
log.error(`docs: failed to scaffold site templates: ${(err
|
|
816
|
+
log.error(`docs: failed to scaffold site templates: ${describeError(err)}`);
|
|
810
817
|
return 1;
|
|
811
818
|
}
|
|
812
819
|
log.info(
|
|
@@ -913,7 +920,7 @@ async function emitSite(
|
|
|
913
920
|
log.info(`meta docs --site — wrote ${r.pages.length} page(s) → ${siteOutDir}`);
|
|
914
921
|
return 0;
|
|
915
922
|
} catch (err) {
|
|
916
|
-
log.error(`docs: failed to generate site: ${(err
|
|
923
|
+
log.error(`docs: failed to generate site: ${describeError(err)}`);
|
|
917
924
|
return 1;
|
|
918
925
|
}
|
|
919
926
|
}
|
|
@@ -931,7 +938,7 @@ async function metamodelDocsCommand(cwd: string, out: string): Promise<number> {
|
|
|
931
938
|
try {
|
|
932
939
|
docs = renderCoreMetamodelDocs(composeRegistry(coreProviders));
|
|
933
940
|
} catch (err) {
|
|
934
|
-
log.error(`docs: failed to render metamodel docs: ${(err
|
|
941
|
+
log.error(`docs: failed to render metamodel docs: ${describeError(err)}`);
|
|
935
942
|
return 1;
|
|
936
943
|
}
|
|
937
944
|
try {
|
|
@@ -942,7 +949,7 @@ async function metamodelDocsCommand(cwd: string, out: string): Promise<number> {
|
|
|
942
949
|
await writeFile(path, content, "utf8");
|
|
943
950
|
}
|
|
944
951
|
} catch (err) {
|
|
945
|
-
log.error(`docs: failed to write metamodel pages: ${(err
|
|
952
|
+
log.error(`docs: failed to write metamodel pages: ${describeError(err)}`);
|
|
946
953
|
return 1;
|
|
947
954
|
}
|
|
948
955
|
log.info(`meta docs --metamodel — wrote ${docs.size} page(s) → ${outDir}`);
|
package/src/commands/eject.ts
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
ejectLibrary, ejectableLibraryNames, isLibraryName, libraryStaleness,
|
|
37
37
|
type LibraryEjectResult,
|
|
38
38
|
} from "../lib/library-eject.js";
|
|
39
|
+
import { describeError } from "../lib/error-text.js";
|
|
39
40
|
|
|
40
41
|
// Mirrors `OWNED_GENERATORS_DIR` in init.ts's `writeOwnedGenerators` — same directory,
|
|
41
42
|
// same never-clobber-without-consent contract. Kept as its own local constant rather
|
|
@@ -255,7 +256,12 @@ export async function ejectGenerator(opts: EjectOptions): Promise<EjectResult> {
|
|
|
255
256
|
// The adapter source the OUTPUT imports is part of what is handed over — copied whether
|
|
256
257
|
// or not the generator file itself was already here, and under the same never-clobber
|
|
257
258
|
// rule, so re-running eject fills in a missing copy without touching a kept one.
|
|
258
|
-
|
|
259
|
+
// Except when the KEPT copy predates that hand-over (1.0.9): with no `runtimeImport`
|
|
260
|
+
// option its output imports the published package, so the copy would be dead code —
|
|
261
|
+
// a Drizzle adapter, and its dependencies, in a project that may have no database.
|
|
262
|
+
const keptCopyImportsPackage =
|
|
263
|
+
existing !== undefined && !opts.force && !existing.includes("runtimeImport");
|
|
264
|
+
const runtime = ejectsRuntime(opts.name) && !keptCopyImportsPackage
|
|
259
265
|
? await ejectRuntime(opts.cwd, [opts.name], opts.force === true)
|
|
260
266
|
: undefined;
|
|
261
267
|
|
|
@@ -613,7 +619,7 @@ export async function ejectCommand(
|
|
|
613
619
|
try {
|
|
614
620
|
flags = parseEjectArgs(args);
|
|
615
621
|
} catch (err) {
|
|
616
|
-
log.error((err
|
|
622
|
+
log.error(describeError(err));
|
|
617
623
|
return 2;
|
|
618
624
|
}
|
|
619
625
|
|
|
@@ -687,7 +693,7 @@ export async function ejectCommand(
|
|
|
687
693
|
if (fmt === "text") reportOne(result, name);
|
|
688
694
|
}
|
|
689
695
|
} catch (err) {
|
|
690
|
-
log.error((err
|
|
696
|
+
log.error(describeError(err));
|
|
691
697
|
return 1;
|
|
692
698
|
}
|
|
693
699
|
|
package/src/commands/export.ts
CHANGED
|
@@ -6,13 +6,14 @@ import { FileSource } from "@metaobjectsdev/metadata/core";
|
|
|
6
6
|
import { TypeRegistry, registerCoreTypes, MetaDataLoader, canonicalSerialize } from "@metaobjectsdev/metadata";
|
|
7
7
|
import { registerForgeTypes, resolveCollection } from "@metaobjectsdev/sdk";
|
|
8
8
|
import { collectionLoadOptions } from "../lib/collection-load-options.js";
|
|
9
|
+
import { describeError } from "../lib/error-text.js";
|
|
9
10
|
|
|
10
11
|
export async function exportCommand(args: string[], cwd: string): Promise<number> {
|
|
11
12
|
let flags;
|
|
12
13
|
try {
|
|
13
14
|
flags = parseExportArgs(args);
|
|
14
15
|
} catch (err) {
|
|
15
|
-
log.error((err
|
|
16
|
+
log.error(describeError(err));
|
|
16
17
|
return 2;
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -34,7 +35,7 @@ export async function exportCommand(args: string[], cwd: string): Promise<number
|
|
|
34
35
|
try {
|
|
35
36
|
collection = await resolveCollection(projectRoot);
|
|
36
37
|
} catch (err) {
|
|
37
|
-
log.error((err
|
|
38
|
+
log.error(describeError(err));
|
|
38
39
|
return 1;
|
|
39
40
|
}
|
|
40
41
|
|
package/src/commands/gen.ts
CHANGED
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
} from "../lib/catalog-listing.js";
|
|
30
30
|
import { emitStructured } from "../lib/format.js";
|
|
31
31
|
import { composeCatalog } from "../lib/catalog.js";
|
|
32
|
+
import { describeError } from "../lib/error-text.js";
|
|
33
|
+
import { findRuntimeBoundaryCrossings, runtimeBoundaryWarnings } from "../lib/runtime-boundary-advisory.js";
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
@@ -65,7 +67,7 @@ export function mapStatus(s: WriteStatus): GenFileStatus {
|
|
|
65
67
|
export async function genCommand(args: string[], cwd: string, fmt: OutputFormat = "text"): Promise<number> {
|
|
66
68
|
let flags;
|
|
67
69
|
try { flags = parseGenArgs(args); }
|
|
68
|
-
catch (err) { log.error((err
|
|
70
|
+
catch (err) { log.error(describeError(err)); return 2; }
|
|
69
71
|
|
|
70
72
|
// ADR-0021 D3 — `meta gen --list`: print the generator CATALOG and exit 0 WITHOUT
|
|
71
73
|
// running codegen. No project is required (like `meta types`): "what can this engine
|
|
@@ -97,7 +99,7 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
97
99
|
try {
|
|
98
100
|
collection = await resolveCollection(cwd);
|
|
99
101
|
} catch (err) {
|
|
100
|
-
log.error((err
|
|
102
|
+
log.error(describeError(err));
|
|
101
103
|
return 2;
|
|
102
104
|
}
|
|
103
105
|
// ...but `metaobjects.config.ts` is not named by the metadata: it is this
|
|
@@ -136,7 +138,7 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
136
138
|
try {
|
|
137
139
|
forgeConfig = await loadMetaobjectsConfig(projectRoot);
|
|
138
140
|
} catch (err) {
|
|
139
|
-
log.error((err
|
|
141
|
+
log.error(describeError(err));
|
|
140
142
|
return 2;
|
|
141
143
|
}
|
|
142
144
|
|
|
@@ -204,7 +206,7 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
204
206
|
...(cliConfig.entities.length > 0 ? { entityFilter: cliConfig.entities } : {}),
|
|
205
207
|
});
|
|
206
208
|
} catch (err) {
|
|
207
|
-
log.error(`gen failed: ${(err
|
|
209
|
+
log.error(`gen failed: ${describeError(err)}`);
|
|
208
210
|
return 1;
|
|
209
211
|
}
|
|
210
212
|
|
|
@@ -234,6 +236,14 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
234
236
|
info: "",
|
|
235
237
|
}));
|
|
236
238
|
|
|
239
|
+
// Advisory: generated code importing the owned adapter copy from outside its own
|
|
240
|
+
// workspace package (a monorepo) will not build. Warning only.
|
|
241
|
+
if (!cliConfig.dryRun) {
|
|
242
|
+
for (const w of runtimeBoundaryWarnings(
|
|
243
|
+
findRuntimeBoundaryCrossings(projectRoot, result.files.map((f) => f.path)),
|
|
244
|
+
)) log.warn(`warning: ${w}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
237
247
|
const targetDirs = Array.from(new Set(
|
|
238
248
|
(forgeConfig.targets ? Object.values(forgeConfig.targets).map((t) => t.outDir) : [])
|
|
239
249
|
.concat([forgeConfig.outDir]),
|
|
@@ -369,7 +379,7 @@ function runAntiPatternScan(
|
|
|
369
379
|
projectRoot, ignore !== undefined ? { ignore } : undefined)));
|
|
370
380
|
} catch (err) {
|
|
371
381
|
// Never let an advisory scan break gen — but never claim it found nothing either.
|
|
372
|
-
return skippedSection(`the scan failed: ${(err
|
|
382
|
+
return skippedSection(`the scan failed: ${describeError(err)}`);
|
|
373
383
|
}
|
|
374
384
|
}
|
|
375
385
|
|
|
@@ -402,7 +412,7 @@ async function listCatalogCommand(
|
|
|
402
412
|
collection = await resolveCollection(cwd);
|
|
403
413
|
} catch (err) {
|
|
404
414
|
log.error(
|
|
405
|
-
`meta gen --list --probe needs a project to probe: ${(err
|
|
415
|
+
`meta gen --list --probe needs a project to probe: ${describeError(err)}\n` +
|
|
406
416
|
"Run `meta gen --list` (no --probe) for the catalog on its own.",
|
|
407
417
|
);
|
|
408
418
|
return 2;
|
|
@@ -414,7 +424,7 @@ async function listCatalogCommand(
|
|
|
414
424
|
try {
|
|
415
425
|
forgeConfig = await loadMetaobjectsConfig(projectRoot);
|
|
416
426
|
} catch (err) {
|
|
417
|
-
log.error((err
|
|
427
|
+
log.error(describeError(err));
|
|
418
428
|
return 2;
|
|
419
429
|
}
|
|
420
430
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
OWNED_GENERATORS_DIR,
|
|
25
25
|
type GeneratorScope,
|
|
26
26
|
} from "./generator-help.js";
|
|
27
|
+
import { describeError } from "../lib/error-text.js";
|
|
27
28
|
|
|
28
29
|
export { GENERATOR_HELP, GENERATOR_OPTIONS, GENERATOR_SCOPES, OWNED_GENERATORS_DIR } from "./generator-help.js";
|
|
29
30
|
export type { GeneratorScope } from "./generator-help.js";
|
|
@@ -334,7 +335,7 @@ export async function generatorCommand(args: string[], cwd: string): Promise<num
|
|
|
334
335
|
try {
|
|
335
336
|
({ values, positionals } = parseArgs({ args, options: GENERATOR_OPTIONS, strict: true, allowPositionals: true }));
|
|
336
337
|
} catch (err) {
|
|
337
|
-
log.error((err
|
|
338
|
+
log.error(describeError(err));
|
|
338
339
|
return 2;
|
|
339
340
|
}
|
|
340
341
|
const [sub, name, ...extra] = positionals;
|
|
@@ -358,7 +359,7 @@ export async function generatorCommand(args: string[], cwd: string): Promise<num
|
|
|
358
359
|
wire: values["no-wire"] !== true,
|
|
359
360
|
});
|
|
360
361
|
} catch (err) {
|
|
361
|
-
log.error((err
|
|
362
|
+
log.error(describeError(err));
|
|
362
363
|
return 2;
|
|
363
364
|
}
|
|
364
365
|
|
package/src/commands/init.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { log } from "../lib/log.js";
|
|
|
14
14
|
import { cliVersion } from "../lib/version.js";
|
|
15
15
|
import { findWranglerConfig, parseWranglerConfig } from "@metaobjectsdev/migrate-ts";
|
|
16
16
|
import { DEFAULT_DOCS_DIR } from "@metaobjectsdev/codegen-ts";
|
|
17
|
+
import { describeError } from "../lib/error-text.js";
|
|
17
18
|
|
|
18
19
|
// ADR-0034 scaffold-and-own — `meta init` copies the codegen reference templates into
|
|
19
20
|
// the consumer's repo so they OWN them; metaobjects.config.ts imports them locally.
|
|
@@ -157,6 +158,8 @@ Next steps:
|
|
|
157
158
|
4. meta gen # generate from exactly what you wired
|
|
158
159
|
5. meta docs # neutral model + API docs (on by default)
|
|
159
160
|
6. Create your tables: meta migrate --from-db --db file:dev.sqlite --dialect sqlite --slug init --apply
|
|
161
|
+
A new database later (a fresh clone, CI, tests) replays the committed migrations:
|
|
162
|
+
meta migrate apply-pending --db file:other.sqlite
|
|
160
163
|
`;
|
|
161
164
|
|
|
162
165
|
export interface InitOptions {
|
|
@@ -861,7 +864,7 @@ export async function initCommand(args: string[], cwd: string): Promise<number>
|
|
|
861
864
|
// init failure gets. `init()` refuses it too, which is what covers every other door.
|
|
862
865
|
assertKnownStackValues({ servers: flags.servers ?? [], clients: flags.clients ?? [] });
|
|
863
866
|
} catch (err) {
|
|
864
|
-
log.error((err
|
|
867
|
+
log.error(describeError(err));
|
|
865
868
|
return 2;
|
|
866
869
|
}
|
|
867
870
|
|
|
@@ -923,7 +926,7 @@ export async function initCommand(args: string[], cwd: string): Promise<number>
|
|
|
923
926
|
}
|
|
924
927
|
return 0;
|
|
925
928
|
} catch (err) {
|
|
926
|
-
log.error((err
|
|
929
|
+
log.error(describeError(err));
|
|
927
930
|
return 1;
|
|
928
931
|
}
|
|
929
932
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -65,6 +65,7 @@ import { tokensToAllowOptions, blockedEntriesFor, blockedHintLines } from "../li
|
|
|
65
65
|
import { reportLoadError } from "../lib/load-error.js";
|
|
66
66
|
import { scanForReferentialActionConflicts } from "../lib/referential-action-advisory.js";
|
|
67
67
|
import type { MetaData } from "@metaobjectsdev/metadata";
|
|
68
|
+
import { describeError } from "../lib/error-text.js";
|
|
68
69
|
|
|
69
70
|
/**
|
|
70
71
|
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
@@ -498,7 +499,7 @@ export async function migrateCommand(
|
|
|
498
499
|
try {
|
|
499
500
|
flags = parseMigrateArgs(args);
|
|
500
501
|
} catch (err) {
|
|
501
|
-
const msg = (err
|
|
502
|
+
const msg = describeError(err);
|
|
502
503
|
log.error(`migrate: ${msg}`);
|
|
503
504
|
emitStructuredError(`migrate: ${msg}`, "run `meta migrate --help` for usage", fmt);
|
|
504
505
|
return 2;
|
|
@@ -692,7 +693,7 @@ export async function migrateCommand(
|
|
|
692
693
|
try {
|
|
693
694
|
collection = await resolveCollection(metaRoot);
|
|
694
695
|
} catch (err) {
|
|
695
|
-
log.error((err
|
|
696
|
+
log.error(describeError(err));
|
|
696
697
|
return 2;
|
|
697
698
|
}
|
|
698
699
|
|
|
@@ -712,7 +713,7 @@ export async function migrateCommand(
|
|
|
712
713
|
try {
|
|
713
714
|
kysely = await buildKyselyFromUrl(config.databaseUrl, config.dialect);
|
|
714
715
|
} catch (err) {
|
|
715
|
-
log.error(`migrate: ${(err
|
|
716
|
+
log.error(`migrate: ${describeError(err)}`);
|
|
716
717
|
return 2;
|
|
717
718
|
}
|
|
718
719
|
|
|
@@ -758,7 +759,7 @@ export async function migrateCommand(
|
|
|
758
759
|
try {
|
|
759
760
|
actual = await introspect(kysely.db, kysely.dialect);
|
|
760
761
|
} catch (err) {
|
|
761
|
-
log.error(`migrate: failed to connect to ${kysely.displayUrl}: ${(err
|
|
762
|
+
log.error(`migrate: failed to connect to ${kysely.displayUrl}: ${describeError(err)}`);
|
|
762
763
|
await kysely.close();
|
|
763
764
|
return 2;
|
|
764
765
|
}
|
|
@@ -801,7 +802,7 @@ export async function migrateCommand(
|
|
|
801
802
|
}
|
|
802
803
|
// diff() throws when onAmbiguous returns "abort" — surface as exit 1
|
|
803
804
|
// with the collected ambiguity list.
|
|
804
|
-
if ((err
|
|
805
|
+
if (describeError(err).includes("aborted by onAmbiguous")) {
|
|
805
806
|
ambiguous = ambiguousToEntries(collectedAmbiguous);
|
|
806
807
|
const migrateResult = {
|
|
807
808
|
dialect: kysely.dialect,
|
|
@@ -895,6 +896,14 @@ export async function migrateCommand(
|
|
|
895
896
|
if (exitCode === 0 && emitted) {
|
|
896
897
|
if (config.slug === undefined) {
|
|
897
898
|
log.error(`migrate: --slug <name> required when there are changes (e.g., --slug add-user-shipping)`);
|
|
899
|
+
// The common way to land here is a NEW database (a fresh clone, CI, another
|
|
900
|
+
// environment) whose migrations are already committed: the diff against an empty
|
|
901
|
+
// database is every table, so it asks to author a new migration. That database
|
|
902
|
+
// needs the committed chain replayed, not a new migration.
|
|
903
|
+
log.error(
|
|
904
|
+
` New database, migrations already committed? Apply them instead: ` +
|
|
905
|
+
`meta migrate apply-pending --db <url>`,
|
|
906
|
+
);
|
|
898
907
|
await kysely.close();
|
|
899
908
|
return 2;
|
|
900
909
|
}
|
|
@@ -936,7 +945,7 @@ export async function migrateCommand(
|
|
|
936
945
|
});
|
|
937
946
|
appliedNames = [...result.applied];
|
|
938
947
|
} catch (err) {
|
|
939
|
-
log.error(`migrate: apply failed: ${(err
|
|
948
|
+
log.error(`migrate: apply failed: ${describeError(err)}`);
|
|
940
949
|
exitCode = 1;
|
|
941
950
|
applyFailed = true;
|
|
942
951
|
}
|
|
@@ -992,7 +1001,7 @@ export async function migrateCommand(
|
|
|
992
1001
|
} catch (err) {
|
|
993
1002
|
// The migration itself is written (and possibly applied) — report the
|
|
994
1003
|
// bookkeeping failure for what it is rather than as an unexpected error.
|
|
995
|
-
log.error(`migrate: failed to write the schema snapshot: ${(err
|
|
1004
|
+
log.error(`migrate: failed to write the schema snapshot: ${describeError(err)}`);
|
|
996
1005
|
exitCode = 1;
|
|
997
1006
|
}
|
|
998
1007
|
}
|
|
@@ -1000,7 +1009,7 @@ export async function migrateCommand(
|
|
|
1000
1009
|
try {
|
|
1001
1010
|
await kysely.close();
|
|
1002
1011
|
} catch (err) {
|
|
1003
|
-
log.warn(`migrate: failed to close DB cleanly: ${(err
|
|
1012
|
+
log.warn(`migrate: failed to close DB cleanly: ${describeError(err)}`);
|
|
1004
1013
|
}
|
|
1005
1014
|
}
|
|
1006
1015
|
|
|
@@ -1038,7 +1047,7 @@ export async function migrateCommand(
|
|
|
1038
1047
|
// A metadata defect, not a tool failure: two declarations generate one database name.
|
|
1039
1048
|
if (isDuplicateSqlNameError(err)) return refuseEngineError(err, DUPLICATE_SQL_NAME_HINT, fmt);
|
|
1040
1049
|
// Unexpected error: emit structured error on stdout in the active format, then exit 1.
|
|
1041
|
-
const msg = (err
|
|
1050
|
+
const msg = describeError(err) ?? String(err);
|
|
1042
1051
|
log.error(`migrate: unexpected error: ${msg}`);
|
|
1043
1052
|
emitStructuredError(`migrate: unexpected error: ${msg}`, "run `meta migrate --help` for usage", fmt);
|
|
1044
1053
|
return 1;
|
|
@@ -1076,7 +1085,7 @@ export async function runBaseline(
|
|
|
1076
1085
|
try {
|
|
1077
1086
|
kysely = await buildKyselyFromUrl(config.databaseUrl, config.dialect);
|
|
1078
1087
|
} catch (err) {
|
|
1079
|
-
log.error(`migrate baseline: ${(err
|
|
1088
|
+
log.error(`migrate baseline: ${describeError(err)}`);
|
|
1080
1089
|
return 2;
|
|
1081
1090
|
}
|
|
1082
1091
|
try {
|
|
@@ -1183,7 +1192,7 @@ export async function runApplyPending(
|
|
|
1183
1192
|
try {
|
|
1184
1193
|
kysely = await buildKyselyFromUrl(config.databaseUrl, config.dialect);
|
|
1185
1194
|
} catch (err) {
|
|
1186
|
-
log.error(`migrate apply-pending: ${(err
|
|
1195
|
+
log.error(`migrate apply-pending: ${describeError(err)}`);
|
|
1187
1196
|
return 2;
|
|
1188
1197
|
}
|
|
1189
1198
|
|
|
@@ -1199,13 +1208,13 @@ export async function runApplyPending(
|
|
|
1199
1208
|
pendingNames = [...result.pending];
|
|
1200
1209
|
appliedNames = [...result.applied];
|
|
1201
1210
|
} catch (err) {
|
|
1202
|
-
log.error(`migrate apply-pending: apply failed: ${(err
|
|
1211
|
+
log.error(`migrate apply-pending: apply failed: ${describeError(err)}`);
|
|
1203
1212
|
exitCode = 1;
|
|
1204
1213
|
} finally {
|
|
1205
1214
|
try {
|
|
1206
1215
|
await kysely.close();
|
|
1207
1216
|
} catch (err) {
|
|
1208
|
-
log.warn(`migrate apply-pending: failed to close DB cleanly: ${(err
|
|
1217
|
+
log.warn(`migrate apply-pending: failed to close DB cleanly: ${describeError(err)}`);
|
|
1209
1218
|
}
|
|
1210
1219
|
}
|
|
1211
1220
|
if (exitCode !== 0) return exitCode;
|
|
@@ -1304,7 +1313,7 @@ export async function runOfflineGenerate(
|
|
|
1304
1313
|
try {
|
|
1305
1314
|
snapshot = await readSnapshot(path);
|
|
1306
1315
|
} catch (err) {
|
|
1307
|
-
log.error(`migrate: cannot read schema snapshot at ${path}: ${(err
|
|
1316
|
+
log.error(`migrate: cannot read schema snapshot at ${path}: ${describeError(err)}`);
|
|
1308
1317
|
return 2;
|
|
1309
1318
|
}
|
|
1310
1319
|
if (snapshot === null) {
|
|
@@ -1352,7 +1361,7 @@ export async function runOfflineGenerate(
|
|
|
1352
1361
|
// #258 — a primary-key move has no expressible migration; refuse loudly.
|
|
1353
1362
|
if (isPrimaryKeyChangeError(err)) return refuseEngineError(err, PK_CHANGE_HINT, fmt);
|
|
1354
1363
|
if (isDeclaredRenameError(err)) return refuseEngineError(err, DECLARED_RENAME_HINT, fmt);
|
|
1355
|
-
if ((err
|
|
1364
|
+
if (describeError(err).includes("aborted by onAmbiguous")) {
|
|
1356
1365
|
log.error(`migrate: ambiguous rename/drop detected; re-run with --on-ambiguous rename|drop-add`);
|
|
1357
1366
|
return 1;
|
|
1358
1367
|
}
|
|
@@ -1409,6 +1418,7 @@ export async function runOfflineGenerate(
|
|
|
1409
1418
|
);
|
|
1410
1419
|
await writeSnapshot(path, nextSnapshot);
|
|
1411
1420
|
log.info(`migrate: wrote ${res.upPath}`);
|
|
1421
|
+
log.info(`migrate: wrote ${res.downPath}`);
|
|
1412
1422
|
return 0;
|
|
1413
1423
|
}
|
|
1414
1424
|
|
|
@@ -1438,7 +1448,7 @@ async function runRollback(
|
|
|
1438
1448
|
try {
|
|
1439
1449
|
kysely = await buildKyselyFromUrl(databaseUrl, config.dialect);
|
|
1440
1450
|
} catch (err) {
|
|
1441
|
-
log.error(`migrate: ${(err
|
|
1451
|
+
log.error(`migrate: ${describeError(err)}`);
|
|
1442
1452
|
return 2;
|
|
1443
1453
|
}
|
|
1444
1454
|
// kysely.dialect is "sqlite" | "postgres" here — d1 is rejected upstream.
|
|
@@ -1456,13 +1466,13 @@ async function runRollback(
|
|
|
1456
1466
|
}
|
|
1457
1467
|
return 0;
|
|
1458
1468
|
} catch (err) {
|
|
1459
|
-
log.error(`migrate: rollback failed: ${(err
|
|
1469
|
+
log.error(`migrate: rollback failed: ${describeError(err)}`);
|
|
1460
1470
|
return 1;
|
|
1461
1471
|
} finally {
|
|
1462
1472
|
try {
|
|
1463
1473
|
await kysely.close();
|
|
1464
1474
|
} catch (err) {
|
|
1465
|
-
log.warn(`migrate: failed to close DB cleanly: ${(err
|
|
1475
|
+
log.warn(`migrate: failed to close DB cleanly: ${describeError(err)}`);
|
|
1466
1476
|
}
|
|
1467
1477
|
}
|
|
1468
1478
|
}
|
|
@@ -1496,7 +1506,7 @@ async function runD1Migrate(
|
|
|
1496
1506
|
try {
|
|
1497
1507
|
binding = resolveD1Binding(parsed.d1Bindings, config.d1.binding);
|
|
1498
1508
|
} catch (err) {
|
|
1499
|
-
log.error(`migrate: ${(err
|
|
1509
|
+
log.error(`migrate: ${describeError(err)}`);
|
|
1500
1510
|
return 2;
|
|
1501
1511
|
}
|
|
1502
1512
|
} else {
|
|
@@ -1538,7 +1548,7 @@ async function runD1Migrate(
|
|
|
1538
1548
|
try {
|
|
1539
1549
|
collection = await resolveCollection(metaRoot);
|
|
1540
1550
|
} catch (err) {
|
|
1541
|
-
log.error((err
|
|
1551
|
+
log.error(describeError(err));
|
|
1542
1552
|
return 2;
|
|
1543
1553
|
}
|
|
1544
1554
|
|
|
@@ -1579,7 +1589,7 @@ async function runD1Migrate(
|
|
|
1579
1589
|
configPath: wranglerConfigPath,
|
|
1580
1590
|
});
|
|
1581
1591
|
} catch (err) {
|
|
1582
|
-
log.error(`migrate: failed to introspect D1: ${(err
|
|
1592
|
+
log.error(`migrate: failed to introspect D1: ${describeError(err)}`);
|
|
1583
1593
|
return 2;
|
|
1584
1594
|
}
|
|
1585
1595
|
|
|
@@ -1612,7 +1622,7 @@ async function runD1Migrate(
|
|
|
1612
1622
|
// #258 — a primary-key move has no expressible migration; refuse loudly.
|
|
1613
1623
|
if (isPrimaryKeyChangeError(err)) return refuseEngineError(err, PK_CHANGE_HINT, fmt);
|
|
1614
1624
|
if (isDeclaredRenameError(err)) return refuseEngineError(err, DECLARED_RENAME_HINT, fmt);
|
|
1615
|
-
if ((err
|
|
1625
|
+
if (describeError(err).includes("aborted by onAmbiguous")) {
|
|
1616
1626
|
const entries = ambiguousToEntries(collectedAmbiguous);
|
|
1617
1627
|
for (const e of entries) {
|
|
1618
1628
|
log.error(` ambiguous ${e.kind}: ${e.description}${e.hint ? ` [${e.hint}]` : ""}`);
|
|
@@ -1708,7 +1718,7 @@ async function runWranglerApply(
|
|
|
1708
1718
|
return await new Promise<number>((resolve) => {
|
|
1709
1719
|
const child = spawn("wrangler", applyArgs, { stdio: "inherit" });
|
|
1710
1720
|
child.on("error", (err) => {
|
|
1711
|
-
log.error(`migrate: failed to run wrangler: ${(err
|
|
1721
|
+
log.error(`migrate: failed to run wrangler: ${describeError(err)}`);
|
|
1712
1722
|
resolve(2);
|
|
1713
1723
|
});
|
|
1714
1724
|
child.on("close", (code) => resolve(code ?? 1));
|
|
@@ -20,6 +20,7 @@ import { collectionLoadOptions } from "../lib/collection-load-options.js";
|
|
|
20
20
|
import { loadMemory, resolveCollection } from "@metaobjectsdev/sdk";
|
|
21
21
|
import { TYPE_TEMPLATE, TEMPLATE_ATTR_TEXT_REF, TEMPLATE_ATTR_FORMAT } from "@metaobjectsdev/metadata";
|
|
22
22
|
import { render, ESCAPERS, type RenderFormat } from "@metaobjectsdev/render";
|
|
23
|
+
import { describeError } from "../lib/error-text.js";
|
|
23
24
|
|
|
24
25
|
const DEFAULT_PROMPTS_DIR = "prompts";
|
|
25
26
|
|
|
@@ -28,7 +29,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
28
29
|
try {
|
|
29
30
|
flags = parsePromptSnapshotArgs(args);
|
|
30
31
|
} catch (err) {
|
|
31
|
-
log.error((err
|
|
32
|
+
log.error(describeError(err));
|
|
32
33
|
return 2;
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -44,7 +45,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
44
45
|
try {
|
|
45
46
|
collection = await resolveCollection(cwd);
|
|
46
47
|
} catch (err) {
|
|
47
|
-
log.error((err
|
|
48
|
+
log.error(describeError(err));
|
|
48
49
|
return 2;
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -117,7 +118,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
117
118
|
try {
|
|
118
119
|
payload = JSON.parse(readFileSync(payloadPath, "utf8"));
|
|
119
120
|
} catch (err) {
|
|
120
|
-
log.error(`[${tmpl.name}] invalid payload.json: ${(err
|
|
121
|
+
log.error(`[${tmpl.name}] invalid payload.json: ${describeError(err)}`);
|
|
121
122
|
errorCount++;
|
|
122
123
|
continue;
|
|
123
124
|
}
|
|
@@ -135,7 +136,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
135
136
|
try {
|
|
136
137
|
rendered = render({ ref: textRef, payload, provider, ...(format ? { format } : {}) });
|
|
137
138
|
} catch (err) {
|
|
138
|
-
log.error(`[${tmpl.name}] render failed: ${(err
|
|
139
|
+
log.error(`[${tmpl.name}] render failed: ${describeError(err)}`);
|
|
139
140
|
errorCount++;
|
|
140
141
|
continue;
|
|
141
142
|
}
|
package/src/commands/types.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { composeRegistry, buildVocabularyCatalog } from "@metaobjectsdev/metadat
|
|
|
24
24
|
import { defaultLoadMemoryProviders } from "@metaobjectsdev/sdk";
|
|
25
25
|
import { log } from "../lib/log.js";
|
|
26
26
|
import { emitStructured, type OutputFormat } from "../lib/format.js";
|
|
27
|
+
import { describeError } from "../lib/error-text.js";
|
|
27
28
|
|
|
28
29
|
interface TypesFlags {
|
|
29
30
|
query: string | null;
|
|
@@ -210,7 +211,7 @@ export async function typesCommand(args: string[], fmt: OutputFormat = "text"):
|
|
|
210
211
|
try {
|
|
211
212
|
f = parse(args);
|
|
212
213
|
} catch (err) {
|
|
213
|
-
const msg = (err
|
|
214
|
+
const msg = describeError(err);
|
|
214
215
|
log.error(msg);
|
|
215
216
|
// A structured caller gets a structured refusal — exiting 2 with an EMPTY stdout is
|
|
216
217
|
// the same silence a `| jq` cannot tell from "no results". Mirrors verify.ts.
|
|
@@ -317,7 +318,11 @@ export async function typesCommand(args: string[], fmt: OutputFormat = "text"):
|
|
|
317
318
|
const shown = capped ? matches.slice(0, f.limit) : matches;
|
|
318
319
|
|
|
319
320
|
if (f.detail) {
|
|
321
|
+
// A subtype's block lists its @attrs with their full descriptions, so an attr row
|
|
322
|
+
// whose owner subtype is also shown would print the same text a second time.
|
|
323
|
+
const shownSubtypes = new Set(shown.filter((e) => e.kind === "subtype").map((e) => e.owner));
|
|
320
324
|
for (const e of shown) {
|
|
325
|
+
if (e.kind === "attr" && shownSubtypes.has(e.owner)) continue;
|
|
321
326
|
log.info(`\n${e.name} (${e.kind})`);
|
|
322
327
|
if (e.description) log.info(` ${e.description}`);
|
|
323
328
|
if (e.sharedRoot)
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
retirementSuggestions,
|
|
30
30
|
} from "@metaobjectsdev/metadata";
|
|
31
31
|
import { log } from "../lib/log.js";
|
|
32
|
+
import { describeError } from "../lib/error-text.js";
|
|
32
33
|
|
|
33
34
|
/** YAML authoring (ADR-0006). Rewritten by the `yaml`-backed arm, loaded on demand below. */
|
|
34
35
|
const YAML_EXTENSIONS = new Set([".yaml", ".yml"]);
|
|
@@ -61,7 +62,7 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
61
62
|
try {
|
|
62
63
|
flags = parseArgs(args);
|
|
63
64
|
} catch (err) {
|
|
64
|
-
if ((err
|
|
65
|
+
if (describeError(err) === "__help__") {
|
|
65
66
|
log.info(
|
|
66
67
|
"meta upgrade [<project>] [--to <version>] [--apply]\n\n" +
|
|
67
68
|
" Rewrites metadata the current loader no longer accepts, in JSON and YAML alike:\n" +
|
|
@@ -72,7 +73,7 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
72
73
|
);
|
|
73
74
|
return 0;
|
|
74
75
|
}
|
|
75
|
-
log.error((err
|
|
76
|
+
log.error(describeError(err));
|
|
76
77
|
return 2;
|
|
77
78
|
}
|
|
78
79
|
|
|
@@ -82,7 +83,7 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
82
83
|
try {
|
|
83
84
|
files = (await resolveCollection(projectRoot)).files;
|
|
84
85
|
} catch (err) {
|
|
85
|
-
log.error((err
|
|
86
|
+
log.error(describeError(err));
|
|
86
87
|
return 1;
|
|
87
88
|
}
|
|
88
89
|
|