@metaobjectsdev/cli 1.0.0-rc.5 → 1.0.0-rc.7
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/docs.d.ts.map +1 -1
- package/dist/src/commands/docs.js +41 -9
- package/dist/src/commands/docs.js.map +1 -1
- package/dist/src/commands/gen.d.ts +5 -0
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +12 -1
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +27 -3
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +5 -0
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +10 -4
- 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 +2 -1
- 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 +12 -3
- 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 +62 -4
- 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 +69 -21
- package/dist/src/commands/verify.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +37 -18
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/advisory.d.ts +6 -0
- package/dist/src/lib/advisory.d.ts.map +1 -1
- package/dist/src/lib/advisory.js +13 -0
- package/dist/src/lib/advisory.js.map +1 -1
- package/dist/src/lib/anti-patterns.d.ts.map +1 -1
- package/dist/src/lib/anti-patterns.js +8 -4
- package/dist/src/lib/anti-patterns.js.map +1 -1
- package/dist/src/lib/args.d.ts +23 -12
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +33 -22
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/authored-source.d.ts +22 -0
- package/dist/src/lib/authored-source.d.ts.map +1 -0
- package/dist/src/lib/authored-source.js +46 -0
- package/dist/src/lib/authored-source.js.map +1 -0
- package/dist/src/lib/base-url-advisory.d.ts +37 -0
- package/dist/src/lib/base-url-advisory.d.ts.map +1 -0
- package/dist/src/lib/base-url-advisory.js +168 -0
- package/dist/src/lib/base-url-advisory.js.map +1 -0
- package/dist/src/lib/codegen-drift.d.ts +8 -0
- package/dist/src/lib/codegen-drift.d.ts.map +1 -1
- package/dist/src/lib/codegen-drift.js +43 -10
- package/dist/src/lib/codegen-drift.js.map +1 -1
- package/dist/src/lib/detect-stack.d.ts +17 -0
- package/dist/src/lib/detect-stack.d.ts.map +1 -1
- package/dist/src/lib/detect-stack.js +64 -2
- package/dist/src/lib/detect-stack.js.map +1 -1
- package/dist/src/lib/docs-drift.d.ts.map +1 -1
- package/dist/src/lib/docs-drift.js +16 -7
- package/dist/src/lib/docs-drift.js.map +1 -1
- package/dist/src/lib/git-ignore.d.ts +19 -0
- package/dist/src/lib/git-ignore.d.ts.map +1 -1
- package/dist/src/lib/git-ignore.js +46 -3
- package/dist/src/lib/git-ignore.js.map +1 -1
- package/dist/src/lib/ignored-scaffold-check.d.ts +12 -0
- package/dist/src/lib/ignored-scaffold-check.d.ts.map +1 -0
- package/dist/src/lib/ignored-scaffold-check.js +75 -0
- package/dist/src/lib/ignored-scaffold-check.js.map +1 -0
- package/dist/src/lib/load-error.d.ts +46 -0
- package/dist/src/lib/load-error.d.ts.map +1 -0
- package/dist/src/lib/load-error.js +51 -0
- package/dist/src/lib/load-error.js.map +1 -0
- package/dist/src/lib/load-metaobjects-config.d.ts +13 -0
- package/dist/src/lib/load-metaobjects-config.d.ts.map +1 -1
- package/dist/src/lib/load-metaobjects-config.js +54 -5
- package/dist/src/lib/load-metaobjects-config.js.map +1 -1
- package/dist/src/lib/manifest-ignored-check.d.ts.map +1 -1
- package/dist/src/lib/manifest-ignored-check.js +19 -6
- package/dist/src/lib/manifest-ignored-check.js.map +1 -1
- package/dist/src/lib/output.d.ts +13 -1
- package/dist/src/lib/output.d.ts.map +1 -1
- package/dist/src/lib/output.js +26 -8
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/rel-posix.d.ts +5 -0
- package/dist/src/lib/rel-posix.d.ts.map +1 -0
- package/dist/src/lib/rel-posix.js +23 -0
- package/dist/src/lib/rel-posix.js.map +1 -0
- package/dist/src/lib/replay-remedy.d.ts +2 -0
- package/dist/src/lib/replay-remedy.d.ts.map +1 -0
- package/dist/src/lib/replay-remedy.js +69 -0
- package/dist/src/lib/replay-remedy.js.map +1 -0
- package/dist/src/lib/wrangler.d.ts +17 -2
- package/dist/src/lib/wrangler.d.ts.map +1 -1
- package/dist/src/lib/wrangler.js +51 -2
- package/dist/src/lib/wrangler.js.map +1 -1
- package/package.json +10 -10
- package/src/commands/docs.ts +51 -12
- package/src/commands/gen.ts +14 -1
- package/src/commands/init.ts +27 -3
- package/src/commands/migrate.ts +12 -4
- package/src/commands/prompt-snapshot.ts +2 -1
- package/src/commands/types.ts +12 -3
- package/src/commands/upgrade.ts +69 -4
- package/src/commands/verify.ts +74 -23
- package/src/index.ts +37 -18
- package/src/lib/advisory.ts +15 -0
- package/src/lib/anti-patterns.ts +7 -5
- package/src/lib/args.ts +60 -39
- package/src/lib/authored-source.ts +45 -0
- package/src/lib/base-url-advisory.ts +178 -0
- package/src/lib/codegen-drift.ts +52 -9
- package/src/lib/detect-stack.ts +73 -2
- package/src/lib/docs-drift.ts +17 -7
- package/src/lib/git-ignore.ts +47 -3
- package/src/lib/ignored-scaffold-check.ts +78 -0
- package/src/lib/load-error.ts +89 -0
- package/src/lib/load-metaobjects-config.ts +53 -5
- package/src/lib/manifest-ignored-check.ts +21 -6
- package/src/lib/output.ts +36 -8
- package/src/lib/rel-posix.ts +25 -0
- package/src/lib/replay-remedy.ts +78 -0
- package/src/lib/wrangler.ts +52 -4
package/dist/src/lib/wrangler.js
CHANGED
|
@@ -13,6 +13,55 @@ export function buildWranglerExecuteArgs(opts) {
|
|
|
13
13
|
}
|
|
14
14
|
return args;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The reason to report when wrangler exits non-zero.
|
|
18
|
+
*
|
|
19
|
+
* **`--json` puts wrangler's error on STDOUT, and warnings on stderr.** This function
|
|
20
|
+
* exists because the runner used to report stderr alone, so a live D1 gate failing for
|
|
21
|
+
* want of a `CLOUDFLARE_API_TOKEN` told the adopter its cause was
|
|
22
|
+
* `▲ [WARNING] … "unsafe" fields are experimental` — a warning, named as the reason a
|
|
23
|
+
* schema gate failed, with the real cause discarded. Found by running an estate's own
|
|
24
|
+
* `verify:prod-schema` against production for the first time.
|
|
25
|
+
*
|
|
26
|
+
* Order: the structured error wrangler wrote, then stderr, then raw stdout, then the
|
|
27
|
+
* process's own message. Stderr is still consulted — a genuine wrangler failure that
|
|
28
|
+
* never reaches stdout must not be swallowed to fix the opposite mistake.
|
|
29
|
+
*/
|
|
30
|
+
export function wranglerFailureReason(stdout, stderr, fallback) {
|
|
31
|
+
const structured = structuredWranglerError(stdout);
|
|
32
|
+
if (structured !== undefined)
|
|
33
|
+
return structured;
|
|
34
|
+
const err = stderr.trim();
|
|
35
|
+
if (err.length > 0)
|
|
36
|
+
return err;
|
|
37
|
+
const out = stdout.trim();
|
|
38
|
+
if (out.length > 0)
|
|
39
|
+
return out;
|
|
40
|
+
return fallback;
|
|
41
|
+
}
|
|
42
|
+
/** wrangler's two `--json` error shapes: `{error:{text}}` / `{error}` and the
|
|
43
|
+
* `[{success:false,error}]` execute envelope. Anything else reads as absent. */
|
|
44
|
+
function structuredWranglerError(stdout) {
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = JSON.parse(stdout);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const node = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
53
|
+
if (node === null || typeof node !== "object")
|
|
54
|
+
return undefined;
|
|
55
|
+
const { error } = node;
|
|
56
|
+
if (typeof error === "string" && error.trim().length > 0)
|
|
57
|
+
return error.trim();
|
|
58
|
+
if (error !== null && typeof error === "object") {
|
|
59
|
+
const { text } = error;
|
|
60
|
+
if (typeof text === "string" && text.trim().length > 0)
|
|
61
|
+
return text.trim();
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
16
65
|
export const defaultWranglerRunner = async (args, cwd) => {
|
|
17
66
|
try {
|
|
18
67
|
const { stdout, stderr } = await execFile("wrangler", args, { cwd, maxBuffer: 16 * 1024 * 1024 });
|
|
@@ -23,8 +72,8 @@ export const defaultWranglerRunner = async (args, cwd) => {
|
|
|
23
72
|
if (e.code === "ENOENT") {
|
|
24
73
|
throw new Error(`wrangler not found on PATH; install it: 'npm i -D wrangler'`);
|
|
25
74
|
}
|
|
26
|
-
const
|
|
27
|
-
throw new Error(`wrangler ${args.join(" ")} failed: ${
|
|
75
|
+
const reason = wranglerFailureReason(e.stdout ?? "", e.stderr ?? "", e.message);
|
|
76
|
+
throw new Error(`wrangler ${args.join(" ")} failed: ${reason}`);
|
|
28
77
|
}
|
|
29
78
|
};
|
|
30
79
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrangler.js","sourceRoot":"","sources":["../../../src/lib/wrangler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;AASvC,MAAM,UAAU,wBAAwB,CAAC,IAA4B;IACnE,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO;QAC7B,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;QACpC,QAAQ;QACR,WAAW,EAAE,IAAI,CAAC,OAAO;KAC1B,CAAC;IACF,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AASD,MAAM,CAAC,MAAM,qBAAqB,GAAmB,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IACvE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,CAAC;QAClG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAAmE,CAAC;QAC9E,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"wrangler.js","sourceRoot":"","sources":["../../../src/lib/wrangler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/cli",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.7",
|
|
4
4
|
"description": "CLI for MetaObjects: scaffold, codegen, migrate, and drift-detection commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
"@biomejs/js-api": "^0.7.0",
|
|
52
52
|
"@biomejs/wasm-nodejs": "^1.9.4",
|
|
53
53
|
"@libsql/kysely-libsql": "^0.4.0",
|
|
54
|
-
"@metaobjectsdev/codegen-ts": "1.0.0-rc.
|
|
55
|
-
"@metaobjectsdev/codegen-ts-react": "1.0.0-rc.
|
|
56
|
-
"@metaobjectsdev/codegen-ts-tanstack": "1.0.0-rc.
|
|
57
|
-
"@metaobjectsdev/docs-site": "1.0.0-rc.
|
|
58
|
-
"@metaobjectsdev/metadata": "1.0.0-rc.
|
|
59
|
-
"@metaobjectsdev/migrate-ts": "1.0.0-rc.
|
|
60
|
-
"@metaobjectsdev/render": "1.0.0-rc.
|
|
61
|
-
"@metaobjectsdev/runtime-ts": "1.0.0-rc.
|
|
62
|
-
"@metaobjectsdev/sdk": "1.0.0-rc.
|
|
54
|
+
"@metaobjectsdev/codegen-ts": "1.0.0-rc.7",
|
|
55
|
+
"@metaobjectsdev/codegen-ts-react": "1.0.0-rc.7",
|
|
56
|
+
"@metaobjectsdev/codegen-ts-tanstack": "1.0.0-rc.7",
|
|
57
|
+
"@metaobjectsdev/docs-site": "1.0.0-rc.7",
|
|
58
|
+
"@metaobjectsdev/metadata": "1.0.0-rc.7",
|
|
59
|
+
"@metaobjectsdev/migrate-ts": "1.0.0-rc.7",
|
|
60
|
+
"@metaobjectsdev/render": "1.0.0-rc.7",
|
|
61
|
+
"@metaobjectsdev/runtime-ts": "1.0.0-rc.7",
|
|
62
|
+
"@metaobjectsdev/sdk": "1.0.0-rc.7",
|
|
63
63
|
"@toon-format/toon": "^2.3.0",
|
|
64
64
|
"jiti": "^2.4.0"
|
|
65
65
|
},
|
package/src/commands/docs.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import type {
|
|
30
30
|
GenContext,
|
|
31
31
|
EmittedFile,
|
|
32
|
+
Generator,
|
|
32
33
|
ResolvedDocsConfig,
|
|
33
34
|
DocsSurface,
|
|
34
35
|
Dialect,
|
|
@@ -41,7 +42,7 @@ import {
|
|
|
41
42
|
DEFAULT_COLUMN_NAMING_STRATEGY,
|
|
42
43
|
renderCoreMetamodelDocs,
|
|
43
44
|
} from "@metaobjectsdev/metadata";
|
|
44
|
-
import { dbEmittingObjects, DEFAULT_DIALECT, missingDialectMessage } from "@metaobjectsdev/codegen-ts";
|
|
45
|
+
import { dbEmittingObjects, DEFAULT_DIALECT, DEFAULT_DOCS_DIR, missingDialectMessage, resolveGenerators, runEmitsHonoRoutes, runEmitsUiTier } from "@metaobjectsdev/codegen-ts";
|
|
45
46
|
import type { MetaDataTypeProvider, MetaRoot } from "@metaobjectsdev/metadata";
|
|
46
47
|
import { generateSite, SITE_TEMPLATE_NAMES, SITE_ASSET_NAMES, readSiteFile } from "@metaobjectsdev/docs-site";
|
|
47
48
|
// The `agent` schema surface takes the physical schema as an ARGUMENT with its resolvers
|
|
@@ -53,6 +54,14 @@ import {
|
|
|
53
54
|
qualifiedDbName,
|
|
54
55
|
} from "@metaobjectsdev/migrate-ts";
|
|
55
56
|
import type { AgentSchemaInput, SchemaColumnLike } from "@metaobjectsdev/codegen-ts";
|
|
57
|
+
import { reportLoadError } from "../lib/load-error.js";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
61
|
+
* code, the file, the json path, and the loader's own next steps — instead of the bare
|
|
62
|
+
* `err.message` five commands used to print. See `lib/load-error.ts`.
|
|
63
|
+
*/
|
|
64
|
+
|
|
56
65
|
|
|
57
66
|
type DocsLayout = "flat" | "package";
|
|
58
67
|
|
|
@@ -202,9 +211,14 @@ function parseDocsArgs(argv: string[], cwd: string): DocsFlags {
|
|
|
202
211
|
// cwd (mirrors how migrate/gen treat the working directory as the root).
|
|
203
212
|
projectRoot: projectRoot ?? cwd,
|
|
204
213
|
projectRootProvided: projectRoot !== undefined,
|
|
205
|
-
// Default out dir, resolved against the project root below.
|
|
206
|
-
//
|
|
207
|
-
|
|
214
|
+
// Default out dir, resolved against the project root below. ONE spelling of the
|
|
215
|
+
// default, shared with resolveDocsConfig — two spellings is how a flag default and
|
|
216
|
+
// a config default come to disagree about where the pages are.
|
|
217
|
+
//
|
|
218
|
+
// --metamodel keeps its own sub-path: the renderer writes under <out>/metamodel/,
|
|
219
|
+
// and it is a different artifact (the metamodel reference, not this project's
|
|
220
|
+
// pages), so it is not swept into the generated-docs directory.
|
|
221
|
+
out: out ?? (wantMetamodel ? "./docs/metamodel" : DEFAULT_DOCS_DIR),
|
|
208
222
|
// Default flat preserves today's single-package output (+ existing goldens).
|
|
209
223
|
layout: layout ?? "flat",
|
|
210
224
|
metamodel: wantMetamodel,
|
|
@@ -464,7 +478,7 @@ export async function docsCommand(
|
|
|
464
478
|
|
|
465
479
|
// Merge the config `docs:` block with CLI overrides over documented defaults.
|
|
466
480
|
// CLI --out/--layout only override when explicitly passed; surfaces/baseUrl
|
|
467
|
-
// override whenever present. The resolver supplies defaults (outDir ./docs,
|
|
481
|
+
// override whenever present. The resolver supplies defaults (outDir ./docs/generated,
|
|
468
482
|
// layout = fallback, surfaces = both) so config-less + flag-less runs are
|
|
469
483
|
// unchanged.
|
|
470
484
|
const cliOverrides: Partial<ResolvedDocsConfig> = {
|
|
@@ -505,7 +519,7 @@ export async function docsCommand(
|
|
|
505
519
|
...configLoadOptions,
|
|
506
520
|
});
|
|
507
521
|
} catch (err) {
|
|
508
|
-
log
|
|
522
|
+
reportLoadError(log, "docs: failed to load metadata", err);
|
|
509
523
|
return 2;
|
|
510
524
|
}
|
|
511
525
|
|
|
@@ -527,6 +541,29 @@ export async function docsCommand(
|
|
|
527
541
|
pkMap: buildPkMap(root),
|
|
528
542
|
relationMap: buildRelationMap(root),
|
|
529
543
|
});
|
|
544
|
+
// The generator suite, with stable-name STRINGS resolved to the generators they name
|
|
545
|
+
// (ADR-0021 #1 allows `generators: ["routes-hono"]`). Both aggregations below read a
|
|
546
|
+
// generator MARKER, and a string carries none — so reading the raw array answered
|
|
547
|
+
// "no Hono routes / no UI tier" for a project that wires them by name, which is the
|
|
548
|
+
// same two-doors-one-question defect these flags exist to close. `meta gen` resolves
|
|
549
|
+
// the identical array through `normalizeConfig`.
|
|
550
|
+
//
|
|
551
|
+
// An unknown name throws (the message names it and lists the valid ones). `meta gen`
|
|
552
|
+
// fails on it; `meta docs` has never had to load the suite at all, so it degrades to
|
|
553
|
+
// the already-typed entries rather than becoming a new failure — and SAYS it did,
|
|
554
|
+
// because a page quietly losing a section is exactly what this whole fix is about.
|
|
555
|
+
let suite: Generator[];
|
|
556
|
+
try {
|
|
557
|
+
suite = resolveGenerators(loadedConfig?.generators ?? []);
|
|
558
|
+
} catch (err) {
|
|
559
|
+
log.warn(
|
|
560
|
+
`docs: could not resolve the generator suite (${(err as Error).message}) — the agent ` +
|
|
561
|
+
`pages fall back to the generators declared as values, so a tier wired by name may ` +
|
|
562
|
+
`be missing from them.`,
|
|
563
|
+
);
|
|
564
|
+
suite = (loadedConfig?.generators ?? []).filter((g): g is Generator => typeof g !== "string");
|
|
565
|
+
}
|
|
566
|
+
|
|
530
567
|
const ctx: GenContext = {
|
|
531
568
|
entities: root.objects(),
|
|
532
569
|
loadedRoot: root,
|
|
@@ -541,12 +578,14 @@ export async function docsCommand(
|
|
|
541
578
|
// surface. Aggregate it from the generator set exactly as the gen runner
|
|
542
579
|
// does (a generator opts in via emitsHonoRoutes), so `meta docs` auto-detects
|
|
543
580
|
// routesFileHono() rather than relying on a field users don't normally set.
|
|
544
|
-
includeHonoRoutes:
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
581
|
+
includeHonoRoutes: loadedConfig?.includeHonoRoutes ?? runEmitsHonoRoutes(suite),
|
|
582
|
+
// `agent/ui.md` describes forms, grids and the endpoints their hooks call. Whether
|
|
583
|
+
// any of that is emitted is a GENERATOR fact — the page's own predicate is
|
|
584
|
+
// metadata-only and answered "could a UI be generated?", so a project with
|
|
585
|
+
// `generators: []` got a confident page naming endpoints nothing serves. Aggregate
|
|
586
|
+
// it through the same helper the gen runner uses, so `meta docs` and `meta gen` —
|
|
587
|
+
// the two doors onto this page — cannot answer it differently.
|
|
588
|
+
includeUiTier: loadedConfig?.includeUiTier ?? runEmitsUiTier(suite),
|
|
550
589
|
} as never,
|
|
551
590
|
renderContext,
|
|
552
591
|
projectRoot,
|
package/src/commands/gen.ts
CHANGED
|
@@ -16,6 +16,14 @@ import {
|
|
|
16
16
|
import { loadMemory, resolveCollection } from "@metaobjectsdev/sdk";
|
|
17
17
|
import { runGen, listGenerators } from "@metaobjectsdev/codegen-ts";
|
|
18
18
|
import type { WriteStatus } from "@metaobjectsdev/codegen-ts";
|
|
19
|
+
import { reportLoadError } from "../lib/load-error.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
23
|
+
* code, the file, the json path, and the loader's own next steps — instead of the bare
|
|
24
|
+
* `err.message` five commands used to print. See `lib/load-error.ts`.
|
|
25
|
+
*/
|
|
26
|
+
|
|
19
27
|
|
|
20
28
|
export function mapStatus(s: WriteStatus): GenFileStatus {
|
|
21
29
|
switch (s) {
|
|
@@ -28,6 +36,10 @@ export function mapStatus(s: WriteStatus): GenFileStatus {
|
|
|
28
36
|
case "unchanged":
|
|
29
37
|
case "skipped": return "unchanged";
|
|
30
38
|
case "refused": return "refused";
|
|
39
|
+
// --baseline=adopt — recorded as the merge base, nothing written. Its own word,
|
|
40
|
+
// for the same reason "overwrite" is not "new": the adopter has to know a manifest
|
|
41
|
+
// now exists to commit.
|
|
42
|
+
case "adopted": return "adopted";
|
|
31
43
|
// FR-038 §8 — a generated file deleted because it is no longer generated.
|
|
32
44
|
// Shown as its own outcome, not folded into "unchanged": a run summary that
|
|
33
45
|
// lists writes but hides deletions is how a silent deletion happens.
|
|
@@ -114,7 +126,7 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
114
126
|
...loadMemoryOptionsFrom(forgeConfig),
|
|
115
127
|
});
|
|
116
128
|
} catch (err) {
|
|
117
|
-
log
|
|
129
|
+
reportLoadError(log, "failed to load metadata", err);
|
|
118
130
|
return 2;
|
|
119
131
|
}
|
|
120
132
|
|
|
@@ -172,6 +184,7 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
172
184
|
dryRun: cliConfig.dryRun,
|
|
173
185
|
warnings: [],
|
|
174
186
|
antiPatterns,
|
|
187
|
+
generatorCount: forgeConfig.generators?.length ?? 0,
|
|
175
188
|
};
|
|
176
189
|
const output =
|
|
177
190
|
fmt === "toon" ? formatGenResultToon(genResult)
|
package/src/commands/init.ts
CHANGED
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
assemble, resolveAgentContextRoot, planScaffold,
|
|
9
9
|
AGENT_CONTEXT_MANIFEST_PATH, type Manifest, type Stack,
|
|
10
10
|
} from "@metaobjectsdev/sdk/agent-context";
|
|
11
|
-
import { resolveStack } from "../lib/detect-stack.js";
|
|
11
|
+
import { assertKnownStackValues, resolveStack } from "../lib/detect-stack.js";
|
|
12
|
+
import { reportIgnoredScaffold } from "../lib/ignored-scaffold-check.js";
|
|
12
13
|
import { parseInitArgs } from "../lib/args.js";
|
|
13
14
|
import { log } from "../lib/log.js";
|
|
14
15
|
import { cliVersion } from "../lib/version.js";
|
|
15
16
|
import { declaredDependencyNames, type PackageManifest } from "../lib/package-manifest.js";
|
|
16
17
|
import { findWranglerConfig, parseWranglerConfig } from "@metaobjectsdev/migrate-ts";
|
|
17
|
-
import { readReferenceTemplate, type ReferenceGeneratorName } from "@metaobjectsdev/codegen-ts";
|
|
18
|
+
import { DEFAULT_DOCS_DIR, readReferenceTemplate, type ReferenceGeneratorName } from "@metaobjectsdev/codegen-ts";
|
|
18
19
|
|
|
19
20
|
// ADR-0034 scaffold-and-own — `meta init` copies the codegen reference templates into
|
|
20
21
|
// the consumer's repo so they OWN them; metaobjects.config.ts imports them locally.
|
|
@@ -138,7 +139,9 @@ export default defineConfig({
|
|
|
138
139
|
barrel(),
|
|
139
140
|
],
|
|
140
141
|
docs: {
|
|
141
|
-
outDir: "
|
|
142
|
+
outDir: "${DEFAULT_DOCS_DIR}", // every surface lands here (run: meta docs).
|
|
143
|
+
// A SUB-directory on purpose: these pages are regenerated
|
|
144
|
+
// and overwritten, and docs/ itself is usually yours.
|
|
142
145
|
layout: "flat", // or "package" for multi-package models
|
|
143
146
|
// surfaces defaults to ["model", "api", "requirements", "agent"] — all four.
|
|
144
147
|
// Deliberately NOT narrowed here: the requirements and agent surfaces emit ZERO
|
|
@@ -600,6 +603,16 @@ async function writeConfigFile(opts: InitOptions, result: InitResult, agentDir:
|
|
|
600
603
|
}
|
|
601
604
|
|
|
602
605
|
export async function init(opts: InitOptions): Promise<InitResult> {
|
|
606
|
+
// Refused HERE, in the shared function, before anything is written — NOT at one CLI
|
|
607
|
+
// entry point. It was at `initCommand`'s arg parse only, and `meta agent-docs` calls
|
|
608
|
+
// this directly: `meta init --docs-only --server klingon` exited 2 with the message
|
|
609
|
+
// while `meta agent-docs --server klingon` exited 0, reported "11 files", and recorded
|
|
610
|
+
// `"servers": []`. That is the worse of the two doors to miss — `agent-docs` is the
|
|
611
|
+
// canonical redirect target for every language port, so the ports used the unguarded
|
|
612
|
+
// one. A non-empty override array suppresses both the prior manifest's stack AND
|
|
613
|
+
// detection, so a dropped value does not degrade, it inverts three statements in the
|
|
614
|
+
// generated context.
|
|
615
|
+
assertKnownStackValues({ servers: opts.servers ?? [], clients: opts.clients ?? [] });
|
|
603
616
|
const result: InitResult = { created: [], preserved: [], removed: [], warnings: [] };
|
|
604
617
|
const agentDir = join(opts.cwd, DEFAULT_METAOBJECTS_DIR);
|
|
605
618
|
const metaobjectsDir = join(opts.cwd, DEFAULT_METADATA_DIR);
|
|
@@ -1135,6 +1148,9 @@ export async function initCommand(args: string[], cwd: string): Promise<number>
|
|
|
1135
1148
|
let flags;
|
|
1136
1149
|
try {
|
|
1137
1150
|
flags = parseInitArgs(args);
|
|
1151
|
+
// Also here, so a bad value is a USAGE error (exit 2) rather than the exit 1 an
|
|
1152
|
+
// init failure gets. `init()` refuses it too, which is what covers every other door.
|
|
1153
|
+
assertKnownStackValues({ servers: flags.servers ?? [], clients: flags.clients ?? [] });
|
|
1138
1154
|
} catch (err) {
|
|
1139
1155
|
log.error((err as Error).message);
|
|
1140
1156
|
return 2;
|
|
@@ -1163,6 +1179,14 @@ export async function initCommand(args: string[], cwd: string): Promise<number>
|
|
|
1163
1179
|
}
|
|
1164
1180
|
|
|
1165
1181
|
if (!flags.quiet) {
|
|
1182
|
+
// A count is not a guarantee that the files reached the repository. Many projects
|
|
1183
|
+
// git-ignore `.claude/` under a comment about credentials — a common and defensible
|
|
1184
|
+
// convention — and eight of the eleven files land there. Ignored, they exist only on
|
|
1185
|
+
// the machine that ran this: not committed, absent from CI and from a fresh clone,
|
|
1186
|
+
// invisible to a teammate, while `.agent-context.json` (which IS committed) tracks
|
|
1187
|
+
// them. That silently voids the whole downstream agent-context design, and the answer
|
|
1188
|
+
// was available from the outputs this command had just written.
|
|
1189
|
+
reportIgnoredScaffold(cwd, result.created);
|
|
1166
1190
|
if (flags.docsOnly) {
|
|
1167
1191
|
log.info(`Scaffolded the MetaObjects agent context (${result.created.length} files): .metaobjects/AGENTS.md + .claude/skills/metaobjects-*.`);
|
|
1168
1192
|
for (const w of result.warnings) log.info(` ${w}`);
|
package/src/commands/migrate.ts
CHANGED
|
@@ -58,6 +58,14 @@ import {
|
|
|
58
58
|
} from "../lib/wrangler.js";
|
|
59
59
|
import { buildProjectionViews } from "@metaobjectsdev/codegen-ts";
|
|
60
60
|
import { tokensToAllowOptions, describeChange } from "../lib/allow.js";
|
|
61
|
+
import { reportLoadError } from "../lib/load-error.js";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
65
|
+
* code, the file, the json path, and the loader's own next steps — instead of the bare
|
|
66
|
+
* `err.message` five commands used to print. See `lib/load-error.ts`.
|
|
67
|
+
*/
|
|
68
|
+
|
|
61
69
|
|
|
62
70
|
export const MIGRATE_HELP_TEXT = `meta migrate — diff metadata vs live DB; emit migration SQL files
|
|
63
71
|
|
|
@@ -628,7 +636,7 @@ export async function migrateCommand(
|
|
|
628
636
|
...postgresLoadOptions,
|
|
629
637
|
});
|
|
630
638
|
} catch (err) {
|
|
631
|
-
log
|
|
639
|
+
reportLoadError(log, "failed to load metadata", err);
|
|
632
640
|
return 2;
|
|
633
641
|
}
|
|
634
642
|
|
|
@@ -1056,7 +1064,7 @@ export async function runBaseline(
|
|
|
1056
1064
|
...baselineLoadOptions,
|
|
1057
1065
|
});
|
|
1058
1066
|
} catch (err) {
|
|
1059
|
-
log
|
|
1067
|
+
reportLoadError(log, "migrate baseline: failed to load metadata", err);
|
|
1060
1068
|
return 2;
|
|
1061
1069
|
}
|
|
1062
1070
|
const baselineViews = buildProjectionViews(metadata, { dialect: config.dialect, columnNamingStrategy: baselineStrategy });
|
|
@@ -1195,7 +1203,7 @@ export async function runOfflineGenerate(
|
|
|
1195
1203
|
...offlineLoadOptions,
|
|
1196
1204
|
});
|
|
1197
1205
|
} catch (err) {
|
|
1198
|
-
log
|
|
1206
|
+
reportLoadError(log, "migrate: failed to load metadata", err);
|
|
1199
1207
|
return 2;
|
|
1200
1208
|
}
|
|
1201
1209
|
|
|
@@ -1460,7 +1468,7 @@ async function runD1Migrate(
|
|
|
1460
1468
|
...d1LoadOptions,
|
|
1461
1469
|
});
|
|
1462
1470
|
} catch (err) {
|
|
1463
|
-
log
|
|
1471
|
+
reportLoadError(log, "migrate: failed to load metadata", err);
|
|
1464
1472
|
return 2;
|
|
1465
1473
|
}
|
|
1466
1474
|
|
|
@@ -14,6 +14,7 @@ import { parsePromptSnapshotArgs } from "../lib/args.js";
|
|
|
14
14
|
import { log } from "../lib/log.js";
|
|
15
15
|
import { FileProvider } from "../lib/file-provider.js";
|
|
16
16
|
import { snapshotPaths, unifiedDiff } from "../lib/snapshot.js";
|
|
17
|
+
import { reportLoadError } from "../lib/load-error.js";
|
|
17
18
|
import { loadMemoryOptionsFrom, loadMetaobjectsConfig, resolveGenConfigDir } from "../lib/load-metaobjects-config.js";
|
|
18
19
|
import { loadMemory, resolveCollection } from "@metaobjectsdev/sdk";
|
|
19
20
|
import { TYPE_TEMPLATE, TEMPLATE_ATTR_TEXT_REF, TEMPLATE_ATTR_FORMAT } from "@metaobjectsdev/metadata";
|
|
@@ -78,7 +79,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
78
79
|
...configLoadOptions,
|
|
79
80
|
});
|
|
80
81
|
} catch (err) {
|
|
81
|
-
log
|
|
82
|
+
reportLoadError(log, "failed to load metadata", err);
|
|
82
83
|
return 1;
|
|
83
84
|
}
|
|
84
85
|
|
package/src/commands/types.ts
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
// The `--json` flag this once advertised in its own --help, twice, is not coming back: the
|
|
21
21
|
// CLI rejects a bare `--json` before a command ever sees its args (index.ts, `formatAlias`),
|
|
22
22
|
// on purpose — one global spelling for all three formats.
|
|
23
|
-
import { composeRegistry,
|
|
24
|
-
import {
|
|
23
|
+
import { composeRegistry, buildVocabularyCatalog } from "@metaobjectsdev/metadata";
|
|
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
27
|
|
|
@@ -226,7 +226,16 @@ export async function typesCommand(args: string[], fmt: OutputFormat = "text"):
|
|
|
226
226
|
// @sortable, @dbColumnType), `view.textarea` with none (no @rows), and the eight
|
|
227
227
|
// documentation commonAttrs — @title among them — were absent entirely. This is the same
|
|
228
228
|
// provider set the loader composes, so what this prints is what the loader accepts.
|
|
229
|
-
|
|
229
|
+
// `defaultLoadMemoryProviders` — THE composition, not a second spelling of it. This read
|
|
230
|
+
// `[...coreProviders]`, which is what that constant happens to equal today, so the claim
|
|
231
|
+
// above ("the same provider set the loader composes") was true by coincidence and the gate
|
|
232
|
+
// that pins the default composition against the canonical manifest had no jurisdiction
|
|
233
|
+
// here: add or drop a provider in the default set and `meta types` would silently print a
|
|
234
|
+
// vocabulary the loader does not accept, with nothing failing. `forgeTypesProvider` was
|
|
235
|
+
// once in this list, and printing it as registered vocabulary was part of how a TS-only
|
|
236
|
+
// registration read as cross-port: `meta types forge --all` listed 20 attrs no other port
|
|
237
|
+
// has. One composition, one door.
|
|
238
|
+
const registry = composeRegistry([...defaultLoadMemoryProviders], { validate: true });
|
|
230
239
|
const catalog = buildVocabularyCatalog(registry);
|
|
231
240
|
|
|
232
241
|
// Flatten the catalog into searchable entries.
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
import { readFile, writeFile } from "node:fs/promises";
|
|
22
22
|
import { extname, relative } from "node:path";
|
|
23
23
|
import { resolveCollection } from "@metaobjectsdev/sdk";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
rewriteDocument,
|
|
26
|
+
composeRegistry,
|
|
27
|
+
coreProviders,
|
|
28
|
+
SUBTYPE_BASE,
|
|
29
|
+
retirementSuggestions,
|
|
30
|
+
} from "@metaobjectsdev/metadata";
|
|
25
31
|
import { log } from "../lib/log.js";
|
|
26
32
|
|
|
27
33
|
/** YAML authoring (ADR-0006). Rewritten by the `yaml`-backed arm, loaded on demand below. */
|
|
@@ -96,7 +102,37 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
96
102
|
? (await import("@metaobjectsdev/metadata/vocabulary-rewrite-yaml")).rewriteYamlDocument
|
|
97
103
|
: undefined;
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
// Which types have an ABSTRACT ANCHOR at `<type>.base`, derived from the core registry
|
|
106
|
+
// rather than listed here: `base` is an anchor exactly when the type registers some OTHER
|
|
107
|
+
// subtype for it to anchor. The rewriter is registry-free on purpose, so the caller — this
|
|
108
|
+
// command, which can build a registry — supplies the fact.
|
|
109
|
+
//
|
|
110
|
+
// Without it, `meta upgrade` answered "nothing to rewrite" on an estate whose
|
|
111
|
+
// `{"object.base": …}` the loader refuses (ERR_ABSTRACT_SUBTYPE_AUTHORED) — the change
|
|
112
|
+
// §10A of the 1.0 guide LEADS WITH. The one command whose job is "what does the new
|
|
113
|
+
// version need me to change?" said "nothing", and the adopter then hit the load failure.
|
|
114
|
+
const registry = composeRegistry(coreProviders);
|
|
115
|
+
// `allTypes()` yields one TypeId per registered type.subType pair, so take the distinct
|
|
116
|
+
// TYPE names off it.
|
|
117
|
+
const abstractAnchorTypes = [...new Set(registry.allTypes().map((id) => id.type))]
|
|
118
|
+
.filter((t) => {
|
|
119
|
+
const subs = registry.allSubTypesOf(t);
|
|
120
|
+
return subs.includes(SUBTYPE_BASE) && subs.some((sub) => sub !== SUBTYPE_BASE);
|
|
121
|
+
})
|
|
122
|
+
.sort();
|
|
123
|
+
|
|
124
|
+
const opts = {
|
|
125
|
+
abstractAnchorTypes,
|
|
126
|
+
...(flags.maxVersion !== undefined ? { maxVersion: flags.maxVersion } : {}),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// One retirement RULE, however many occurrences it has. An estate hit this with 24
|
|
130
|
+
// `@forge*` attributes, and the per-occurrence rationale turned the output into ~96
|
|
131
|
+
// lines saying one thing four times over — the wall that buries the instruction it is
|
|
132
|
+
// made of, which is the exact failure `runGen`'s no-manifest refusal aggregates to
|
|
133
|
+
// avoid. Keyed by the rendered text, so two rules that happen to read identically
|
|
134
|
+
// collapse and two that differ anywhere do not.
|
|
135
|
+
const rules = new Map<string, { why: string; suggestions: string[]; subjects: Set<string> }>();
|
|
100
136
|
|
|
101
137
|
for (const file of files) {
|
|
102
138
|
const rel = relative(projectRoot, file);
|
|
@@ -120,10 +156,24 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
120
156
|
log.info(`\n${rel}`);
|
|
121
157
|
for (const c of r.changes) log.info(` ${c.line}: @${c.from} → ${c.to}`);
|
|
122
158
|
for (const f of r.refusals) {
|
|
159
|
+
// The occurrence line is per-line information: file, line, subject, the value found.
|
|
160
|
+
// The RATIONALE that goes with it is per RULE and prints once, after the listing —
|
|
161
|
+
// see `rules` below.
|
|
123
162
|
log.warn(
|
|
124
|
-
` ${f.line}: ${f.subject}${f.value !== undefined ? `: ${f.value}` : ""} — needs a decision
|
|
125
|
-
`
|
|
163
|
+
` ${f.line}: ${f.subject}${f.value !== undefined ? `: ${f.value}` : ""} — needs a decision ` +
|
|
164
|
+
`(no longer accepted as of ${f.since}).`,
|
|
126
165
|
);
|
|
166
|
+
const key = `${f.why}\u0000${retirementSuggestions(f).join("\u0000")}`;
|
|
167
|
+
const rule = rules.get(key);
|
|
168
|
+
if (rule === undefined) {
|
|
169
|
+
rules.set(key, {
|
|
170
|
+
why: f.why,
|
|
171
|
+
suggestions: retirementSuggestions(f),
|
|
172
|
+
subjects: new Set([f.subject]),
|
|
173
|
+
});
|
|
174
|
+
} else {
|
|
175
|
+
rule.subjects.add(f.subject);
|
|
176
|
+
}
|
|
127
177
|
}
|
|
128
178
|
|
|
129
179
|
totalChanges += r.changes.length;
|
|
@@ -135,6 +185,21 @@ export async function upgradeCommand(args: string[], cwd: string): Promise<numbe
|
|
|
135
185
|
}
|
|
136
186
|
|
|
137
187
|
log.info("");
|
|
188
|
+
|
|
189
|
+
// The WHY and the options, once per rule. Both print, and the guide is not an
|
|
190
|
+
// alternative to them: this used to read `Retired in <since>. See <guide>`, dropping
|
|
191
|
+
// `why` whenever a guide existed — which is almost always — and dropping `replacedBy`
|
|
192
|
+
// unconditionally. For the `@forge*` entries that removed the only actionable sentence
|
|
193
|
+
// there is ("opt the provider in explicitly"). The subject list is what lets a reader
|
|
194
|
+
// connect the paragraph back to the lines above it now that it prints away from them.
|
|
195
|
+
for (const rule of rules.values()) {
|
|
196
|
+
const subjects = [...rule.subjects].sort().join(", ");
|
|
197
|
+
log.warn(`\n ${subjects} — why, and what to do:`);
|
|
198
|
+
log.warn(` ${rule.why}`);
|
|
199
|
+
for (const line of rule.suggestions) log.warn(` ${line}`);
|
|
200
|
+
}
|
|
201
|
+
if (rules.size > 0) log.info("");
|
|
202
|
+
|
|
138
203
|
if (notChecked.length > 0) {
|
|
139
204
|
log.warn(
|
|
140
205
|
`${notChecked.length} file(s) could not be parsed and were NOT checked — fix these ` +
|