@drzl/cli 4.17.0 → 4.19.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/dist/cli.js CHANGED
@@ -5,12 +5,12 @@ import {
5
5
  filterTables,
6
6
  loadConfig,
7
7
  trpcOutDir
8
- } from "./chunk-I4KMDCQR.js";
8
+ } from "./chunk-V2IXXAC2.js";
9
9
 
10
10
  // src/cli.ts
11
11
  import { SchemaAnalyzer } from "@drzl/analyzer";
12
12
  import { ORPCGenerator } from "@drzl/generator-orpc";
13
- import chalk2 from "chalk";
13
+ import chalk3 from "chalk";
14
14
  import chokidar from "chokidar";
15
15
  import cliProgress from "cli-progress";
16
16
  import { Command } from "commander";
@@ -76,6 +76,264 @@ function trpcOptions(g, cfg, servicesDir) {
76
76
  };
77
77
  }
78
78
 
79
+ // src/doctor.ts
80
+ import { parseCheck } from "@drzl/validation-core";
81
+ import chalk from "chalk";
82
+ var HANDLED_CODES = /* @__PURE__ */ new Set(["DRZL_ANL_UNKNOWN_COLUMN"]);
83
+ function splitPath(path5) {
84
+ if (!path5) return {};
85
+ const dot = path5.lastIndexOf(".");
86
+ if (dot <= 0) return { table: path5 };
87
+ return { table: path5.slice(0, dot), column: path5.slice(dot + 1) };
88
+ }
89
+ function namedColumns(parsed) {
90
+ const out = [];
91
+ for (const c of parsed.checks) out.push({ column: c.column, scalar: true });
92
+ for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });
93
+ for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });
94
+ for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });
95
+ for (const r of parsed.rows ?? []) {
96
+ out.push({ column: r.left, scalar: false });
97
+ out.push({ column: r.right, scalar: false });
98
+ }
99
+ return out;
100
+ }
101
+ function describeShape(c) {
102
+ if (c.arrayDimensions) return "an array";
103
+ switch (c.shape?.kind) {
104
+ case "json":
105
+ return "a JSON";
106
+ case "buffer":
107
+ return "a binary";
108
+ case "tuple":
109
+ case "numberObject":
110
+ return "a structured";
111
+ case "numberVector":
112
+ return "a vector";
113
+ case "bitstring":
114
+ return "a bit-string";
115
+ case "byteString":
116
+ return "a byte-string";
117
+ case "custom":
118
+ return "a customType";
119
+ default:
120
+ return "a structured";
121
+ }
122
+ }
123
+ function checkFindings(table) {
124
+ const out = [];
125
+ const byName = new Map(table.columns.map((c) => [c.name, c]));
126
+ for (const k of table.checks ?? []) {
127
+ const label = k.name ? `"${k.name}"` : "an unnamed constraint";
128
+ const raw = k.expression ?? "";
129
+ const expr = raw.trim() ? raw : "(empty)";
130
+ const parsed = parseCheck(raw, k.name);
131
+ if (!parsed.ok) {
132
+ out.push({
133
+ kind: "check-declined",
134
+ level: "warn",
135
+ table: table.tsName,
136
+ constraint: k.name,
137
+ message: `CHECK ${label} on "${table.tsName}" is not translated: ${parsed.reason}. Expression: ${expr}`,
138
+ hint: "Only constraints whose meaning is unambiguous are translated, because a validator enforcing a guess rejects rows the database accepts. Your database still enforces this one; nothing DRZL emits does."
139
+ });
140
+ continue;
141
+ }
142
+ const seen = /* @__PURE__ */ new Set();
143
+ for (const { column, scalar } of namedColumns(parsed)) {
144
+ if (seen.has(column)) continue;
145
+ seen.add(column);
146
+ const col = byName.get(column);
147
+ if (!col) {
148
+ out.push({
149
+ kind: "check-unknown-column",
150
+ level: "warn",
151
+ table: table.tsName,
152
+ column,
153
+ constraint: k.name,
154
+ message: `CHECK ${label} on "${table.tsName}" names "${column}", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,
155
+ hint: "A constraint is attached to the field it names. Check the spelling, or move a constraint spanning two tables out of the schema."
156
+ });
157
+ continue;
158
+ }
159
+ if (scalar && (col.arrayDimensions || col.shape)) {
160
+ out.push({
161
+ kind: "check-not-scalar",
162
+ level: "warn",
163
+ table: table.tsName,
164
+ column,
165
+ constraint: k.name,
166
+ message: `CHECK ${label} on "${table.tsName}" compares ${describeShape(col)} column "${column}" against a scalar literal, which does not describe it, so it is not translated. Expression: ${expr}`,
167
+ hint: "On an array column only cardinality(col) is read, since it is the one comparison that is about the array rather than about an element."
168
+ });
169
+ }
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+ function primaryKeyFindings(table) {
175
+ if (table.readOnly) return [];
176
+ const pk = table.primaryKey?.columns ?? [];
177
+ if (!pk.length) {
178
+ const hasId = table.columns.some((c) => c.name === "id");
179
+ return [
180
+ {
181
+ kind: "no-primary-key",
182
+ level: "warn",
183
+ table: table.tsName,
184
+ message: hasId ? `Table "${table.tsName}" declares no primary key. The service and router generators fall back to a column named "id", which this table happens to have, so they work by coincidence.` : `Table "${table.tsName}" declares no primary key. The service and router generators fall back to a column named "id", which this table does not have, so the generated service will not compile.`,
185
+ hint: "Declare a primary key, or leave this table out with the config table filter."
186
+ }
187
+ ];
188
+ }
189
+ if (pk.length > 1) {
190
+ return [
191
+ {
192
+ kind: "partial-primary-key",
193
+ level: "warn",
194
+ table: table.tsName,
195
+ message: `Table "${table.tsName}" has a composite primary key (${pk.join(", ")}). The service and router generators key getById, update and delete on "${pk[0]}" alone, so those operations match on part of the key.`,
196
+ hint: "Treat the generated service as a starting point for this table and widen the key by hand."
197
+ }
198
+ ];
199
+ }
200
+ return [];
201
+ }
202
+ function buildDoctorReport(analysis, schemaPath) {
203
+ const findings = [];
204
+ const errors = analysis.issues.filter((i) => i.level === "error");
205
+ for (const i of errors) {
206
+ findings.push({
207
+ kind: "analyzer",
208
+ level: "error",
209
+ ...splitPath(i.path),
210
+ message: i.message,
211
+ hint: i.hint
212
+ });
213
+ }
214
+ for (const i of analysis.issues) {
215
+ if (i.code !== "DRZL_ANL_UNKNOWN_COLUMN") continue;
216
+ findings.push({
217
+ kind: "unknown-column",
218
+ level: "warn",
219
+ ...splitPath(i.path),
220
+ message: i.message,
221
+ hint: i.hint
222
+ });
223
+ }
224
+ for (const t of analysis.tables) findings.push(...checkFindings(t));
225
+ for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));
226
+ for (const i of analysis.issues) {
227
+ if (i.level === "error" || HANDLED_CODES.has(i.code)) continue;
228
+ findings.push({
229
+ kind: "analyzer",
230
+ level: "warn",
231
+ ...splitPath(i.path),
232
+ message: i.message,
233
+ hint: i.hint
234
+ });
235
+ }
236
+ const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);
237
+ const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);
238
+ return {
239
+ schema: schemaPath,
240
+ dialect: analysis.dialect,
241
+ ok: findings.length === 0,
242
+ counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },
243
+ findings
244
+ };
245
+ }
246
+ var SECTIONS = [
247
+ {
248
+ kinds: ["unknown-column"],
249
+ title: "Columns DRZL cannot type",
250
+ why: "These get a validator that accepts any value."
251
+ },
252
+ {
253
+ kinds: ["check-declined", "check-unknown-column", "check-not-scalar"],
254
+ title: "CHECK constraints DRZL does not enforce",
255
+ why: "Your database still enforces these. Nothing DRZL generates does."
256
+ },
257
+ {
258
+ kinds: ["no-primary-key", "partial-primary-key"],
259
+ title: "Primary keys the generators cannot use",
260
+ why: "The generated getById, update and delete are keyed on one column."
261
+ },
262
+ {
263
+ kinds: ["analyzer"],
264
+ title: "Other findings",
265
+ why: "Reported by the analyzer while reading the schema."
266
+ }
267
+ ];
268
+ function wrap(text, indent, first = indent, width = 96) {
269
+ const lines = [];
270
+ let line = "";
271
+ for (const word of text.split(/\s+/)) {
272
+ if (line && `${line} ${word}`.length + indent.length > width) {
273
+ lines.push(line);
274
+ line = word;
275
+ } else {
276
+ line = line ? `${line} ${word}` : word;
277
+ }
278
+ }
279
+ if (line) lines.push(line);
280
+ return lines.map((l, i) => (i === 0 ? first : indent) + l).join("\n");
281
+ }
282
+ function renderDoctorReport(report) {
283
+ const out = [];
284
+ const plural = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
285
+ out.push(chalk.bold(`DRZL doctor ${report.schema}`));
286
+ out.push(
287
+ chalk.dim(
288
+ `${report.dialect}, ${plural(report.counts.tables, "table")}, ${plural(report.counts.columns, "column")}, ${plural(report.counts.checks, "CHECK constraint")}`
289
+ )
290
+ );
291
+ out.push("");
292
+ if (report.ok) {
293
+ out.push(chalk.green("Nothing to report."));
294
+ out.push(chalk.dim(" Every column has a type DRZL can describe."));
295
+ out.push(chalk.dim(" Every CHECK constraint is translated into the generated validators."));
296
+ out.push(chalk.dim(" Every table has a primary key the generators can use."));
297
+ return out.join("\n");
298
+ }
299
+ const fatal = report.findings.filter((f) => f.level === "error");
300
+ if (fatal.length) {
301
+ out.push(chalk.red("DRZL could not read this schema"));
302
+ out.push(chalk.dim(" Nothing else could be checked."));
303
+ out.push("");
304
+ for (const f of fatal) {
305
+ out.push(wrap(f.message, " ", ` ${chalk.dim("-")} `));
306
+ if (f.hint) out.push(chalk.dim(wrap(f.hint, " ")));
307
+ }
308
+ out.push("");
309
+ }
310
+ for (const section of SECTIONS) {
311
+ const mine = report.findings.filter(
312
+ (f) => f.level !== "error" && section.kinds.includes(f.kind)
313
+ );
314
+ if (!mine.length) continue;
315
+ out.push(chalk.yellow(`${section.title} (${mine.length})`));
316
+ out.push(chalk.dim(` ${section.why}`));
317
+ out.push("");
318
+ const groups = /* @__PURE__ */ new Map();
319
+ for (const f of mine) {
320
+ const key = f.hint ?? "";
321
+ groups.set(key, [...groups.get(key) ?? [], f]);
322
+ }
323
+ for (const [hint, items] of groups) {
324
+ for (const f of items) out.push(wrap(f.message, " ", ` ${chalk.dim("-")} `));
325
+ if (hint) out.push(chalk.dim(wrap(hint, " ")));
326
+ out.push("");
327
+ }
328
+ }
329
+ out.push(
330
+ chalk.bold(`${plural(report.counts.findings, "finding")} in ${report.schema}.`) + chalk.dim(
331
+ fatal.length ? " Fix the error above and run this again." : " None of these stop DRZL generating; they are what it will not check for you."
332
+ )
333
+ );
334
+ return out.join("\n");
335
+ }
336
+
79
337
  // src/drift.ts
80
338
  import { promises as fs } from "fs";
81
339
  import path from "path";
@@ -152,7 +410,7 @@ async function loadGenerator(specifier, load) {
152
410
  }
153
411
 
154
412
  // src/sponsor.ts
155
- import chalk from "chalk";
413
+ import chalk2 from "chalk";
156
414
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
157
415
  import path2 from "path";
158
416
  var CACHE_DIR = path2.join(process.cwd(), "node_modules", ".cache", "@drzl");
@@ -162,13 +420,13 @@ var shownThisProcess = false;
162
420
  var tips = [
163
421
  "Pair DRZL watch mode with drizzle-kit to keep schema & API synced.",
164
422
  "Templatize your ORPC routers to roll out new endpoints safely.",
165
- "Need typed validators? Enable the zod, valibot, arktype, or typebox generators.",
423
+ "Need typed validators? Enable the zod, valibot, arktype, typebox, or effect generators.",
166
424
  "Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.",
167
425
  "Use output headers to track generated files and trim noisy diffs."
168
426
  ];
169
- var green = (msg) => chalk.hex("#6ee7b7")(msg);
170
- var cyan = (msg) => chalk.cyan(msg);
171
- var gray = (msg) => chalk.gray(msg);
427
+ var green = (msg) => chalk2.hex("#6ee7b7")(msg);
428
+ var cyan = (msg) => chalk2.cyan(msg);
429
+ var gray = (msg) => chalk2.gray(msg);
172
430
  function maybeShowSponsorMessage({
173
431
  reason = "generate",
174
432
  minIntervalMs = DEFAULT_INTERVAL_MS,
@@ -257,13 +515,13 @@ var CLI_VERSION = readCliVersion();
257
515
  function reportGeneratorFailure(kind, e) {
258
516
  if (e instanceof GeneratorNotInstalledError) {
259
517
  console.error(
260
- chalk2.red(`The ${kind} generator is not installed.`),
261
- chalk2.yellow(`
518
+ chalk3.red(`The ${kind} generator is not installed.`),
519
+ chalk3.yellow(`
262
520
  Install with: npm install ${e.specifier}`)
263
521
  );
264
522
  return;
265
523
  }
266
- console.error(chalk2.red(`The ${kind} generator failed:`), e?.message ?? e);
524
+ console.error(chalk3.red(`The ${kind} generator failed:`), e?.message ?? e);
267
525
  }
268
526
  var program = new Command();
269
527
  program.name("drzl").description("DRZL - Drizzle Developer Toolkit").version(CLI_VERSION);
@@ -290,9 +548,9 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
290
548
  } else if (opts.out) {
291
549
  const fs2 = await import("fs/promises");
292
550
  await fs2.writeFile(opts.out, json, "utf8");
293
- spinner?.succeed(chalk2.green(`Analysis written to ${opts.out} in ${ms}ms`));
551
+ spinner?.succeed(chalk3.green(`Analysis written to ${opts.out} in ${ms}ms`));
294
552
  } else {
295
- spinner?.succeed(chalk2.green(`Analyzed in ${ms}ms`));
553
+ spinner?.succeed(chalk3.green(`Analyzed in ${ms}ms`));
296
554
  console.log(json);
297
555
  }
298
556
  process.exit(res.issues.some((i) => i.level === "error") ? 2 : 0);
@@ -302,7 +560,48 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
302
560
  console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_ANALYZE", message: msg }));
303
561
  else
304
562
  console.error(
305
- chalk2.red("Analyze failed (DRZL_CLI_ANALYZE):"),
563
+ chalk3.red("Analyze failed (DRZL_CLI_ANALYZE):"),
564
+ msg,
565
+ "\nTip: run with --json for structured output."
566
+ );
567
+ process.exit(1);
568
+ }
569
+ });
570
+ program.command("doctor").description("Report what DRZL cannot type or enforce in your schema, and why").argument("[schema]", "path to drizzle schema (TS); defaults to the schema in drzl.config").option("-c, --config <path>", "path to drzl.config, read when no schema argument is given").option("--json", "print the report as JSON instead of prose", false).option("--strict", "exit 2 when anything is reported", false).action(async (schema, opts) => {
571
+ try {
572
+ let target = schema;
573
+ if (!target) {
574
+ const cfg = await loadConfig(opts.config);
575
+ target = cfg?.schema;
576
+ }
577
+ if (!target) {
578
+ const msg = "No schema given. Pass a path, or run from a directory with a drzl.config.";
579
+ if (opts.json)
580
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
581
+ else console.error(chalk3.red("Doctor failed (DRZL_CLI_DOCTOR):"), msg);
582
+ process.exit(1);
583
+ return;
584
+ }
585
+ const analyzer = new SchemaAnalyzer(target);
586
+ const analysis = await analyzer.analyze({
587
+ includeRelations: true,
588
+ validateConstraints: true
589
+ });
590
+ const report = buildDoctorReport(analysis, target);
591
+ if (opts.json) console.log(JSON.stringify(report, null, 2));
592
+ else console.log(renderDoctorReport(report));
593
+ if (report.findings.some((f) => f.level === "error")) {
594
+ process.exit(1);
595
+ return;
596
+ }
597
+ process.exit(opts.strict && report.findings.length ? 2 : 0);
598
+ } catch (e) {
599
+ const msg = e?.message ?? String(e);
600
+ if (opts.json)
601
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
602
+ else
603
+ console.error(
604
+ chalk3.red("Doctor failed (DRZL_CLI_DOCTOR):"),
306
605
  msg,
307
606
  "\nTip: run with --json for structured output."
308
607
  );
@@ -317,7 +616,7 @@ program.command("generate").description("Run configured generators (drzl.config.
317
616
  const cfg = await loadConfig(opts.config);
318
617
  if (!cfg) {
319
618
  console.error(
320
- chalk2.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
619
+ chalk3.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
321
620
  );
322
621
  process.exit(2);
323
622
  return;
@@ -362,8 +661,8 @@ program.command("generate").description("Run configured generators (drzl.config.
362
661
  onProgress: ({ index }) => progress.update(index)
363
662
  });
364
663
  progress.stop();
365
- ora().succeed(chalk2.green(`Generated (${g.kind}): ${files.length} files`));
366
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
664
+ ora().succeed(chalk3.green(`Generated (${g.kind}): ${files.length} files`));
665
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
367
666
  } else if (g.kind === "trpc") {
368
667
  try {
369
668
  const { TRPCGenerator } = await loadGenerator(
@@ -376,8 +675,8 @@ program.command("generate").description("Run configured generators (drzl.config.
376
675
  onProgress: ({ index }) => progress.update(index)
377
676
  });
378
677
  progress.stop();
379
- ora().succeed(chalk2.green(`Generated (trpc): ${files.length} files`));
380
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
678
+ ora().succeed(chalk3.green(`Generated (trpc): ${files.length} files`));
679
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
381
680
  } catch (e) {
382
681
  progress.stop();
383
682
  reportGeneratorFailure(g.kind, e);
@@ -406,8 +705,8 @@ program.command("generate").description("Run configured generators (drzl.config.
406
705
  databaseInjection: g.databaseInjection
407
706
  });
408
707
  progress.stop();
409
- ora().succeed(chalk2.green(`Generated (service): ${files.length} files`));
410
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
708
+ ora().succeed(chalk3.green(`Generated (service): ${files.length} files`));
709
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
411
710
  } catch (e) {
412
711
  progress.stop();
413
712
  reportGeneratorFailure(g.kind, e);
@@ -425,8 +724,8 @@ program.command("generate").description("Run configured generators (drzl.config.
425
724
  validationOptions(g, cfg, target, { schemaTypes: true })
426
725
  );
427
726
  progress.stop();
428
- ora().succeed(chalk2.green(`Generated (zod): ${files.length} files`));
429
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
727
+ ora().succeed(chalk3.green(`Generated (zod): ${files.length} files`));
728
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
430
729
  } catch (e) {
431
730
  progress.stop();
432
731
  reportGeneratorFailure(g.kind, e);
@@ -444,8 +743,8 @@ program.command("generate").description("Run configured generators (drzl.config.
444
743
  validationOptions(g, cfg, target, { schemaTypes: true })
445
744
  );
446
745
  progress.stop();
447
- ora().succeed(chalk2.green(`Generated (valibot): ${files.length} files`));
448
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
746
+ ora().succeed(chalk3.green(`Generated (valibot): ${files.length} files`));
747
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
449
748
  } catch (e) {
450
749
  progress.stop();
451
750
  reportGeneratorFailure(g.kind, e);
@@ -463,8 +762,8 @@ program.command("generate").description("Run configured generators (drzl.config.
463
762
  validationOptions(g, cfg, target, { schemaTypes: false })
464
763
  );
465
764
  progress.stop();
466
- ora().succeed(chalk2.green(`Generated (arktype): ${files.length} files`));
467
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
765
+ ora().succeed(chalk3.green(`Generated (arktype): ${files.length} files`));
766
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
468
767
  } catch (e) {
469
768
  progress.stop();
470
769
  reportGeneratorFailure(g.kind, e);
@@ -480,8 +779,8 @@ program.command("generate").description("Run configured generators (drzl.config.
480
779
  const target = g.path ?? "src/validators/json-schema";
481
780
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
482
781
  progress.stop();
483
- ora().succeed(chalk2.green(`Generated (json-schema): ${files.length} files`));
484
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
782
+ ora().succeed(chalk3.green(`Generated (json-schema): ${files.length} files`));
783
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
485
784
  } catch (e) {
486
785
  progress.stop();
487
786
  reportGeneratorFailure(g.kind, e);
@@ -499,8 +798,27 @@ program.command("generate").description("Run configured generators (drzl.config.
499
798
  validationOptions(g, cfg, target, { schemaTypes: true })
500
799
  );
501
800
  progress.stop();
502
- ora().succeed(chalk2.green(`Generated (typebox): ${files.length} files`));
503
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
801
+ ora().succeed(chalk3.green(`Generated (typebox): ${files.length} files`));
802
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
803
+ } catch (e) {
804
+ progress.stop();
805
+ reportGeneratorFailure(g.kind, e);
806
+ process.exit(1);
807
+ }
808
+ } else if (g.kind === "effect") {
809
+ try {
810
+ const { EffectGenerator } = await loadGenerator(
811
+ "@drzl/generator-effect",
812
+ () => import("./dist-CZDVFYFW.js")
813
+ );
814
+ const gen = new EffectGenerator(analysis);
815
+ const target = g.path ?? "src/validators/effect";
816
+ const files = await gen.generate(
817
+ validationOptions(g, cfg, target, { schemaTypes: true })
818
+ );
819
+ progress.stop();
820
+ ora().succeed(chalk3.green(`Generated (effect): ${files.length} files`));
821
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
504
822
  } catch (e) {
505
823
  progress.stop();
506
824
  reportGeneratorFailure(g.kind, e);
@@ -513,22 +831,22 @@ program.command("generate").description("Run configured generators (drzl.config.
513
831
  const drift = diffSnapshots(driftBefore, after);
514
832
  await restoreSnapshot(driftBefore, after);
515
833
  if (drift.length) {
516
- console.error(chalk2.red(`
834
+ console.error(chalk3.red(`
517
835
  Generated output is out of date (${drift.length} file(s)):`));
518
836
  for (const d of drift) {
519
837
  const mark = d.status === "added" ? "+" : d.status === "removed" ? "-" : "~";
520
838
  console.error(
521
- ` ${mark} ${chalk2.yellow(d.status.padEnd(8))} ${path4.relative(process.cwd(), d.file)}`
839
+ ` ${mark} ${chalk3.yellow(d.status.padEnd(8))} ${path4.relative(process.cwd(), d.file)}`
522
840
  );
523
841
  }
524
842
  console.error(
525
- chalk2.dim(
843
+ chalk3.dim(
526
844
  "\nRun `drzl generate` and commit the result. Nothing was written by this check."
527
845
  )
528
846
  );
529
847
  process.exit(1);
530
848
  }
531
- console.log(chalk2.green("Generated output is up to date."));
849
+ console.log(chalk3.green("Generated output is up to date."));
532
850
  return;
533
851
  }
534
852
  if (cfg.generators.length) {
@@ -536,7 +854,7 @@ Generated output is out of date (${drift.length} file(s)):`));
536
854
  }
537
855
  } catch (e) {
538
856
  console.error(
539
- chalk2.red("Generate failed (DRZL_GEN_001):"),
857
+ chalk3.red("Generate failed (DRZL_GEN_001):"),
540
858
  e?.message ?? e,
541
859
  "\nTip: check your drzl.config.ts and template path."
542
860
  );
@@ -556,10 +874,10 @@ program.command("generate:orpc").argument("<schema>", "path to drizzle schema (T
556
874
  template: opts.template,
557
875
  includeRelations: !!opts.includeRelations
558
876
  });
559
- console.log(chalk2.green(`Generated:`), files.map((f) => chalk2.cyan(f)).join(", "));
877
+ console.log(chalk3.green(`Generated:`), files.map((f) => chalk3.cyan(f)).join(", "));
560
878
  maybeShowSponsorMessage({ reason: "generate:orpc" });
561
879
  } catch (e) {
562
- console.error(chalk2.red("Generate orpc failed:"), e?.message ?? e);
880
+ console.error(chalk3.red("Generate orpc failed:"), e?.message ?? e);
563
881
  process.exit(1);
564
882
  }
565
883
  });
@@ -583,7 +901,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
583
901
  // cannot become the branch that forgets it.
584
902
  servicesDir: opts.servicesDir
585
903
  });
586
- console.log(chalk2.green(`Generated:`), files.map((f) => chalk2.cyan(f)).join(", "));
904
+ console.log(chalk3.green(`Generated:`), files.map((f) => chalk3.cyan(f)).join(", "));
587
905
  maybeShowSponsorMessage({ reason: "generate:trpc" });
588
906
  } catch (e) {
589
907
  reportGeneratorFailure("trpc", e);
@@ -593,7 +911,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
593
911
  program.command("watch").description("Watch schema and regenerate on changes").option("-c, --config <path>", "path to drzl.config").option("--pipeline <name>", "all | analyze | generate-orpc | generate-trpc", "all").option("--debounce <ms>", "debounce ms", "200").option("--json", "emit JSON logs", false).option("--poll", "force polling (helps WSL/Docker/remote FS)", false).action(async (opts) => {
594
912
  let cfg = await loadConfig(opts.config);
595
913
  if (!cfg) {
596
- console.error(chalk2.red("No config found. Create drzl.config.ts or pass --config."));
914
+ console.error(chalk3.red("No config found. Create drzl.config.ts or pass --config."));
597
915
  process.exit(2);
598
916
  return;
599
917
  }
@@ -685,7 +1003,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
685
1003
  })
686
1004
  );
687
1005
  } else {
688
- console.log(chalk2.green("Analyze complete."));
1006
+ console.log(chalk3.green("Analyze complete."));
689
1007
  }
690
1008
  return;
691
1009
  }
@@ -715,8 +1033,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
715
1033
  servicesDir
716
1034
  });
717
1035
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
718
- chalk2.green(`Generated (${g.kind}):`),
719
- files.map((f) => chalk2.cyan(f)).join(", ")
1036
+ chalk3.green(`Generated (${g.kind}):`),
1037
+ files.map((f) => chalk3.cyan(f)).join(", ")
720
1038
  );
721
1039
  newFiles.push(...files);
722
1040
  } else if (g.kind === "trpc") {
@@ -728,8 +1046,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
728
1046
  const gen = new TRPCGenerator(analysis);
729
1047
  const { files } = await gen.generate(trpcOptions(g, cfg, servicesDir));
730
1048
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
731
- chalk2.green(`Generated (trpc): ${files.length} files`),
732
- files.map((f) => chalk2.cyan(f)).join(", ")
1049
+ chalk3.green(`Generated (trpc): ${files.length} files`),
1050
+ files.map((f) => chalk3.cyan(f)).join(", ")
733
1051
  );
734
1052
  newFiles.push(...files);
735
1053
  } catch (e) {
@@ -755,8 +1073,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
755
1073
  databaseInjection: g.databaseInjection
756
1074
  });
757
1075
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
758
- chalk2.green(`Generated (service): ${files.length} files`),
759
- files.map((f) => chalk2.cyan(f)).join(", ")
1076
+ chalk3.green(`Generated (service): ${files.length} files`),
1077
+ files.map((f) => chalk3.cyan(f)).join(", ")
760
1078
  );
761
1079
  newFiles.push(...files);
762
1080
  } catch (e) {
@@ -775,8 +1093,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
775
1093
  validationOptions(g, cfg, target, { schemaTypes: true })
776
1094
  );
777
1095
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
778
- chalk2.green(`Generated (zod): ${files.length} files`),
779
- files.map((f) => chalk2.cyan(f)).join(", ")
1096
+ chalk3.green(`Generated (zod): ${files.length} files`),
1097
+ files.map((f) => chalk3.cyan(f)).join(", ")
780
1098
  );
781
1099
  newFiles.push(...files);
782
1100
  } catch (e) {
@@ -795,8 +1113,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
795
1113
  validationOptions(g, cfg, target, { schemaTypes: true })
796
1114
  );
797
1115
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
798
- chalk2.green(`Generated (valibot): ${files.length} files`),
799
- files.map((f) => chalk2.cyan(f)).join(", ")
1116
+ chalk3.green(`Generated (valibot): ${files.length} files`),
1117
+ files.map((f) => chalk3.cyan(f)).join(", ")
800
1118
  );
801
1119
  newFiles.push(...files);
802
1120
  } catch (e) {
@@ -815,8 +1133,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
815
1133
  validationOptions(g, cfg, target, { schemaTypes: false })
816
1134
  );
817
1135
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
818
- chalk2.green(`Generated (arktype): ${files.length} files`),
819
- files.map((f) => chalk2.cyan(f)).join(", ")
1136
+ chalk3.green(`Generated (arktype): ${files.length} files`),
1137
+ files.map((f) => chalk3.cyan(f)).join(", ")
820
1138
  );
821
1139
  newFiles.push(...files);
822
1140
  } catch (e) {
@@ -835,8 +1153,28 @@ program.command("watch").description("Watch schema and regenerate on changes").o
835
1153
  validationOptions(g, cfg, target, { schemaTypes: true })
836
1154
  );
837
1155
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
838
- chalk2.green(`Generated (typebox): ${files.length} files`),
839
- files.map((f) => chalk2.cyan(f)).join(", ")
1156
+ chalk3.green(`Generated (typebox): ${files.length} files`),
1157
+ files.map((f) => chalk3.cyan(f)).join(", ")
1158
+ );
1159
+ newFiles.push(...files);
1160
+ } catch (e) {
1161
+ reportGeneratorFailure(g.kind, e);
1162
+ return;
1163
+ }
1164
+ } else if (g.kind === "effect") {
1165
+ try {
1166
+ const { EffectGenerator } = await loadGenerator(
1167
+ "@drzl/generator-effect",
1168
+ () => import("./dist-CZDVFYFW.js")
1169
+ );
1170
+ const gen = new EffectGenerator(analysis);
1171
+ const target = g.path ?? "src/validators/effect";
1172
+ const files = await gen.generate(
1173
+ validationOptions(g, cfg, target, { schemaTypes: true })
1174
+ );
1175
+ opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
1176
+ chalk3.green(`Generated (effect): ${files.length} files`),
1177
+ files.map((f) => chalk3.cyan(f)).join(", ")
840
1178
  );
841
1179
  newFiles.push(...files);
842
1180
  } catch (e) {
@@ -853,8 +1191,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
853
1191
  const target = g.path ?? "src/validators/json-schema";
854
1192
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
855
1193
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
856
- chalk2.green(`Generated (json-schema): ${files.length} files`),
857
- files.map((f) => chalk2.cyan(f)).join(", ")
1194
+ chalk3.green(`Generated (json-schema): ${files.length} files`),
1195
+ files.map((f) => chalk3.cyan(f)).join(", ")
858
1196
  );
859
1197
  newFiles.push(...files);
860
1198
  } catch (e) {
@@ -866,8 +1204,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
866
1204
  const added = newFiles.filter((f) => !lastFiles.includes(f));
867
1205
  const removed = lastFiles.filter((f) => !newFiles.includes(f));
868
1206
  opts.json ? console.log(JSON.stringify({ event: "diff", added, removed })) : (() => {
869
- if (added.length) console.log(chalk2.blue(`Added: ${added.join(", ")}`));
870
- if (removed.length) console.log(chalk2.yellow(`Removed: ${removed.join(", ")}`));
1207
+ if (added.length) console.log(chalk3.blue(`Added: ${added.join(", ")}`));
1208
+ if (removed.length) console.log(chalk3.yellow(`Removed: ${removed.join(", ")}`));
871
1209
  })();
872
1210
  if (newFiles.length && !opts.json) {
873
1211
  const reason = opts.pipeline && opts.pipeline !== "all" ? `watch:${opts.pipeline}` : "watch";
@@ -875,7 +1213,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
875
1213
  }
876
1214
  lastFiles = newFiles;
877
1215
  } catch (e) {
878
- opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(chalk2.red("Watch pipeline failed:"), e?.message ?? e);
1216
+ opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(chalk3.red("Watch pipeline failed:"), e?.message ?? e);
879
1217
  }
880
1218
  };
881
1219
  const debounced = Number(opts.debounce) || 200;
@@ -900,12 +1238,12 @@ program.command("watch").description("Watch schema and regenerate on changes").o
900
1238
  );
901
1239
  } else {
902
1240
  console.log(
903
- chalk2.gray(
1241
+ chalk3.gray(
904
1242
  "Watching:\n " + Array.from(currentTargets).map((p) => path4.relative(process.cwd(), p)).join("\n ")
905
1243
  )
906
1244
  );
907
1245
  }
908
- watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(chalk2.red("Watcher error:"), err));
1246
+ watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(chalk3.red("Watcher error:"), err));
909
1247
  await run();
910
1248
  });
911
1249
  program.command("init").description("Scaffold a drzl.config.ts").option("-y, --yes", "accept defaults").action(async (_opts) => {
@@ -925,9 +1263,9 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
925
1263
  `;
926
1264
  try {
927
1265
  await fs2.writeFile(target, template, { flag: "wx" });
928
- console.log(chalk2.green(`Created ${target}`));
1266
+ console.log(chalk3.green(`Created ${target}`));
929
1267
  } catch (e) {
930
- console.error(chalk2.red("Init failed:"), e?.message ?? e);
1268
+ console.error(chalk3.red("Init failed:"), e?.message ?? e);
931
1269
  process.exit(1);
932
1270
  }
933
1271
  });
@@ -935,13 +1273,14 @@ function reportWideColumns(issues) {
935
1273
  const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
936
1274
  if (!wide.length) return;
937
1275
  console.warn(
938
- chalk2.yellow(`
1276
+ chalk3.yellow(`
939
1277
  ${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
940
1278
  );
941
- for (const i of wide.slice(0, 10)) console.warn(chalk2.gray(` - ${i.message}`));
942
- if (wide.length > 10) console.warn(chalk2.gray(` ... and ${wide.length - 10} more`));
1279
+ for (const i of wide.slice(0, 10)) console.warn(chalk3.gray(` - ${i.message}`));
1280
+ if (wide.length > 10) console.warn(chalk3.gray(` ... and ${wide.length - 10} more`));
943
1281
  const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
944
- for (const h of hints) console.warn(chalk2.gray(` ${h}`));
1282
+ for (const h of hints) console.warn(chalk3.gray(` ${h}`));
1283
+ console.warn(chalk3.gray(" Run `drzl doctor` for the full report."));
945
1284
  }
946
1285
  program.parseAsync(process.argv);
947
1286
  //# sourceMappingURL=cli.js.map