@metaobjectsdev/cli 1.0.3 → 1.0.4

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.
Files changed (79) hide show
  1. package/README.md +13 -5
  2. package/dist/src/commands/eject.d.ts +2 -1
  3. package/dist/src/commands/eject.d.ts.map +1 -1
  4. package/dist/src/commands/eject.js +235 -75
  5. package/dist/src/commands/eject.js.map +1 -1
  6. package/dist/src/commands/gen.d.ts.map +1 -1
  7. package/dist/src/commands/gen.js +119 -29
  8. package/dist/src/commands/gen.js.map +1 -1
  9. package/dist/src/commands/init.d.ts +5 -9
  10. package/dist/src/commands/init.d.ts.map +1 -1
  11. package/dist/src/commands/init.js +80 -384
  12. package/dist/src/commands/init.js.map +1 -1
  13. package/dist/src/commands/verify.d.ts.map +1 -1
  14. package/dist/src/commands/verify.js +40 -14
  15. package/dist/src/commands/verify.js.map +1 -1
  16. package/dist/src/index.d.ts.map +1 -1
  17. package/dist/src/index.js +36 -14
  18. package/dist/src/index.js.map +1 -1
  19. package/dist/src/lib/advisory.d.ts +6 -0
  20. package/dist/src/lib/advisory.d.ts.map +1 -1
  21. package/dist/src/lib/advisory.js +10 -0
  22. package/dist/src/lib/advisory.js.map +1 -1
  23. package/dist/src/lib/args.d.ts +18 -2
  24. package/dist/src/lib/args.d.ts.map +1 -1
  25. package/dist/src/lib/args.js +15 -3
  26. package/dist/src/lib/args.js.map +1 -1
  27. package/dist/src/lib/catalog-listing.d.ts +92 -0
  28. package/dist/src/lib/catalog-listing.d.ts.map +1 -0
  29. package/dist/src/lib/catalog-listing.js +268 -0
  30. package/dist/src/lib/catalog-listing.js.map +1 -0
  31. package/dist/src/lib/catalog.d.ts +41 -0
  32. package/dist/src/lib/catalog.d.ts.map +1 -0
  33. package/dist/src/lib/catalog.js +89 -0
  34. package/dist/src/lib/catalog.js.map +1 -0
  35. package/dist/src/lib/collection-load-options.d.ts +1 -1
  36. package/dist/src/lib/collection-load-options.d.ts.map +1 -1
  37. package/dist/src/lib/collection-load-options.js +6 -0
  38. package/dist/src/lib/collection-load-options.js.map +1 -1
  39. package/dist/src/lib/install-set.d.ts +31 -0
  40. package/dist/src/lib/install-set.d.ts.map +1 -0
  41. package/dist/src/lib/install-set.js +103 -0
  42. package/dist/src/lib/install-set.js.map +1 -0
  43. package/dist/src/lib/library-eject.d.ts +79 -0
  44. package/dist/src/lib/library-eject.d.ts.map +1 -0
  45. package/dist/src/lib/library-eject.js +241 -0
  46. package/dist/src/lib/library-eject.js.map +1 -0
  47. package/dist/src/lib/library-listing.d.ts +63 -0
  48. package/dist/src/lib/library-listing.d.ts.map +1 -0
  49. package/dist/src/lib/library-listing.js +178 -0
  50. package/dist/src/lib/library-listing.js.map +1 -0
  51. package/dist/src/lib/library-prefix-advisory.d.ts +17 -0
  52. package/dist/src/lib/library-prefix-advisory.d.ts.map +1 -0
  53. package/dist/src/lib/library-prefix-advisory.js +67 -0
  54. package/dist/src/lib/library-prefix-advisory.js.map +1 -0
  55. package/dist/src/lib/load-metaobjects-config.d.ts +1 -2
  56. package/dist/src/lib/load-metaobjects-config.d.ts.map +1 -1
  57. package/dist/src/lib/load-metaobjects-config.js +11 -17
  58. package/dist/src/lib/load-metaobjects-config.js.map +1 -1
  59. package/dist/src/lib/requirement-check.d.ts +17 -2
  60. package/dist/src/lib/requirement-check.d.ts.map +1 -1
  61. package/dist/src/lib/requirement-check.js +51 -9
  62. package/dist/src/lib/requirement-check.js.map +1 -1
  63. package/package.json +10 -10
  64. package/src/commands/eject.ts +304 -90
  65. package/src/commands/gen.ts +128 -28
  66. package/src/commands/init.ts +82 -390
  67. package/src/commands/verify.ts +47 -15
  68. package/src/index.ts +36 -14
  69. package/src/lib/advisory.ts +13 -0
  70. package/src/lib/args.ts +29 -5
  71. package/src/lib/catalog-listing.ts +369 -0
  72. package/src/lib/catalog.ts +107 -0
  73. package/src/lib/collection-load-options.ts +7 -1
  74. package/src/lib/install-set.ts +116 -0
  75. package/src/lib/library-eject.ts +298 -0
  76. package/src/lib/library-listing.ts +258 -0
  77. package/src/lib/library-prefix-advisory.ts +78 -0
  78. package/src/lib/load-metaobjects-config.ts +15 -21
  79. package/src/lib/requirement-check.ts +71 -11
@@ -15,12 +15,18 @@ import {
15
15
  type AdvisoryFindingRow, type AdvisorySection,
16
16
  } from "../lib/advisory.js";
17
17
  import { loadMemory, resolveCollection } from "@metaobjectsdev/sdk";
18
- import { runGen, listGenerators } from "@metaobjectsdev/codegen-ts";
18
+ import { runGen } from "@metaobjectsdev/codegen-ts";
19
19
  import type { WriteStatus } from "@metaobjectsdev/codegen-ts";
20
20
  import { packageOfResolutionKey } from "@metaobjectsdev/metadata";
21
21
  import type { MetaRoot } from "@metaobjectsdev/metadata";
22
22
  import type { Collection } from "@metaobjectsdev/sdk";
23
23
  import { reportLoadError } from "../lib/load-error.js";
24
+ import {
25
+ buildCatalogListing, renderCatalogText, wiredGeneratorNames, ownedGeneratorNames,
26
+ declaredDepsOf,
27
+ } from "../lib/catalog-listing.js";
28
+ import { emitStructured } from "../lib/format.js";
29
+ import { composeCatalog } from "../lib/catalog.js";
24
30
 
25
31
  /**
26
32
  * Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
@@ -56,10 +62,16 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
56
62
  try { flags = parseGenArgs(args); }
57
63
  catch (err) { log.error((err as Error).message); return 2; }
58
64
 
59
- // ADR-0021 D3 — `meta gen --list`: print the stable-name generator registry
60
- // and exit 0 WITHOUT running codegen (no config/metadata required).
65
+ // ADR-0021 D3 — `meta gen --list`: print the generator CATALOG and exit 0 WITHOUT
66
+ // running codegen. No project is required (like `meta types`): "what can this engine
67
+ // do" is a question about the installed engine. `--probe` adds "...and what would
68
+ // each emit for MY model", which does need one.
61
69
  if (flags.list) {
62
- return listGeneratorsCommand();
70
+ return listCatalogCommand(cwd, fmt, flags.probe);
71
+ }
72
+ if (flags.probe) {
73
+ log.error("--probe is only meaningful with --list. Run: meta gen --list --probe");
74
+ return 2;
63
75
  }
64
76
 
65
77
  const cliConfig = resolveGenConfig(flags);
@@ -153,6 +165,9 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
153
165
  config: forgeConfig,
154
166
  metadata,
155
167
  projectRoot,
168
+ // The COMPOSED catalog, so the requires / api-framework gates can see the react
169
+ // and tanstack entries too. codegen-ts only knows its own slice.
170
+ catalog: composeCatalog(),
156
171
  baseline: flags.baseline,
157
172
  // --dry-run must actually preview. This was previously passed only to the
158
173
  // display object below, so a "preview" run wrote every file.
@@ -166,6 +181,10 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
166
181
  // snapshot artifact), so sharedModelFile() defaults its `files` selection
167
182
  // to exactly what this project itself declares.
168
183
  sourceFiles: genCollection.ownFiles,
184
+ // FR-043 §6 — the shipped-library selection. Always passed, including as `[]`:
185
+ // that is what tells the post-selection audit "this project opted into none",
186
+ // which is a different statement from a programmatic caller that never said.
187
+ libraries: genCollection.libraries,
169
188
  ...(cliConfig.entities.length > 0 ? { entityFilter: cliConfig.entities } : {}),
170
189
  });
171
190
  } catch (err) {
@@ -175,6 +194,21 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
175
194
 
176
195
  for (const w of result.warnings) { log.warn(w); }
177
196
 
197
+ // A first-run POINTER, not a warning: an empty selection is the designed state of a
198
+ // fresh `meta init`, so calling it a problem would make every new project start with
199
+ // one. It says what to do next and disappears the moment anything is wired.
200
+ if ((forgeConfig.generators?.length ?? 0) === 0) {
201
+ log.info(
202
+ "\nNothing is generated until you choose it — `generators: []` is what `meta init` " +
203
+ "scaffolds, by design.\n" +
204
+ " meta gen --list --probe the catalog, with how many files each generator " +
205
+ "would emit for YOUR model\n" +
206
+ " meta eject <name>... take the ones you want; it prints the import, the " +
207
+ "entry to wire, and what to install\n" +
208
+ "(`meta docs` needs none of this — documentation is on by default.)",
209
+ );
210
+ }
211
+
178
212
  // result.files[].path is the absolute full path from decideAndWrite. With
179
213
  // per-target output, show each path relative to the project root so files in
180
214
  // different targets are distinguishable.
@@ -311,34 +345,100 @@ function runAntiPatternScan(
311
345
  }
312
346
 
313
347
  /**
314
- * `meta gen --list` — print the stable-name generator registry (ADR-0021 D3).
348
+ * `meta gen --list` — the generator catalog (ADR-0021 D3; opt-in-codegen design §D3).
315
349
  *
316
- * Generators are grouped by tier: the recommended native `meta gen` suite
317
- * first, then neutral artifacts (owned by `meta docs` per D1). Each line is
318
- * `<stable-name> — <description>` plus an options summary and, for neutral
319
- * entries, a note pointing at the canonical door. Exits 0; no codegen runs.
350
+ * Codegen is opt-in, so this is the door: the tool describes what it can do and the
351
+ * builder decides what the app needs. Rows are grouped by `layer`, the axis you select
352
+ * by; `--format json|toon` emits the same catalog as ONE document (nothing else on
353
+ * stdout, per `meta types`' purity rule).
354
+ *
355
+ * With `--probe`, every catalog generator is constructed and dry-run against this
356
+ * project's real model, so the `capability` layer stops being a list of labels and
357
+ * becomes `output-parser: 3, callable: 0, requirement-tests: 7` — information that
358
+ * cannot go stale, because it does not describe the generators, it runs them.
320
359
  */
321
- function listGeneratorsCommand(): number {
322
- const entries = listGenerators();
323
- const native = entries.filter((e) => e.tier === "native");
324
- const neutral = entries.filter((e) => e.tier === "neutral");
325
- const width = Math.max(...entries.map((e) => e.name.length));
360
+ async function listCatalogCommand(
361
+ cwd: string,
362
+ fmt: OutputFormat,
363
+ probe: boolean,
364
+ ): Promise<number> {
365
+ let opts: Parameters<typeof buildCatalogListing>[0] = {};
326
366
 
327
- const lines: string[] = [];
328
- lines.push("Available generators (select by stable name):");
329
- lines.push("");
330
- lines.push("Native (recommended `meta gen` suite):");
331
- for (const e of native) {
332
- lines.push(` ${e.name.padEnd(width)} — ${e.description}`);
333
- if (e.options) lines.push(` ${" ".repeat(width)} options: ${e.options}`);
334
- }
335
- lines.push("");
336
- lines.push("Neutral (owned by `meta docs`; not part of the native suite):");
337
- for (const e of neutral) {
338
- lines.push(` ${e.name.padEnd(width)} — ${e.description}`);
339
- if (e.note) lines.push(` ${" ".repeat(width)} ${e.note}`);
367
+ if (probe) {
368
+ // A probe reports what YOUR model would produce, so a project is mandatory here
369
+ // even though it is optional for a bare --list. Failing loudly beats a listing of
370
+ // zeros that reads like "none of these apply to you".
371
+ let collection;
372
+ try {
373
+ collection = await resolveCollection(cwd);
374
+ } catch (err) {
375
+ log.error(
376
+ `meta gen --list --probe needs a project to probe: ${(err as Error).message}\n` +
377
+ "Run `meta gen --list` (no --probe) for the catalog on its own.",
378
+ );
379
+ return 2;
380
+ }
381
+ const projectRoot = resolveGenConfigDir(cwd, collection.configDir);
382
+ const genCollection = await resolveGenCollection(collection, projectRoot);
383
+
384
+ let forgeConfig;
385
+ try {
386
+ forgeConfig = await loadMetaobjectsConfig(projectRoot);
387
+ } catch (err) {
388
+ log.error((err as Error).message);
389
+ return 2;
390
+ }
391
+
392
+ let metadata;
393
+ try {
394
+ metadata = await loadMemory(genCollection.configDir, {
395
+ ...collectionLoadOptions(genCollection),
396
+ ...loadMemoryOptionsFrom(forgeConfig),
397
+ });
398
+ } catch (err) {
399
+ reportLoadError(log, "failed to load metadata", err);
400
+ return 2;
401
+ }
402
+
403
+ opts = {
404
+ project: {
405
+ projectRoot,
406
+ config: forgeConfig,
407
+ wiredNames: wiredGeneratorNames(forgeConfig),
408
+ ownedNames: ownedGeneratorNames(projectRoot),
409
+ declaredDeps: declaredDepsOf(projectRoot),
410
+ // FR-043 — the library rows read the selection from the COLLECTION, which is
411
+ // where `libraries` lives now (`.metaobjects/config.json`), not from the
412
+ // codegen config it was moved out of.
413
+ libraries: genCollection.libraries,
414
+ },
415
+ probe: { metadata, scope: genCollection.inScope },
416
+ };
417
+ } else {
418
+ // No probe: still report `wired` / `owned` when a project happens to be here, since
419
+ // both are free. A directory with no config is not an error — the catalog is a fact
420
+ // about the installed engine.
421
+ try {
422
+ const collection = await resolveCollection(cwd);
423
+ const projectRoot = resolveGenConfigDir(cwd, collection.configDir);
424
+ const forgeConfig = await loadMetaobjectsConfig(projectRoot);
425
+ opts = {
426
+ project: {
427
+ projectRoot,
428
+ config: forgeConfig,
429
+ wiredNames: wiredGeneratorNames(forgeConfig),
430
+ ownedNames: ownedGeneratorNames(projectRoot),
431
+ declaredDeps: declaredDepsOf(projectRoot),
432
+ libraries: collection.libraries,
433
+ },
434
+ };
435
+ } catch {
436
+ // No project here — the catalog stands on its own.
437
+ }
340
438
  }
341
439
 
342
- log.info(lines.join("\n"));
440
+ const rows = await buildCatalogListing(opts);
441
+ if (fmt === "text") log.info(renderCatalogText(rows, probe));
442
+ else emitStructured(rows, fmt);
343
443
  return 0;
344
444
  }