yamchart 0.8.1 → 0.8.3

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 (68) hide show
  1. package/dist/{advisor-57BOMUUF.js → advisor-JMWAAWJO.js} +10 -10
  2. package/dist/chunk-4W6IVOKO.js +362 -0
  3. package/dist/chunk-4W6IVOKO.js.map +1 -0
  4. package/dist/{chunk-JYQKDWLG.js → chunk-5N3FYFBV.js} +72 -1
  5. package/dist/chunk-5N3FYFBV.js.map +1 -0
  6. package/dist/{chunk-OTAUP5RC.js → chunk-7AVPKKYY.js} +5 -5
  7. package/dist/chunk-7AVPKKYY.js.map +1 -0
  8. package/dist/{chunk-X6LQGWUX.js → chunk-KP4CYPBL.js} +9 -2
  9. package/dist/chunk-KP4CYPBL.js.map +1 -0
  10. package/dist/{chunk-E2UZXDF6.js → chunk-N6PUISAQ.js} +4 -4
  11. package/dist/compare-ZN6RUOOQ.js +87 -0
  12. package/dist/compare-ZN6RUOOQ.js.map +1 -0
  13. package/dist/{connection-utils-FTSZU2VF.js → connection-utils-VEKXRCOM.js} +4 -4
  14. package/dist/describe-X55JPLES.js +29 -0
  15. package/dist/describe-X55JPLES.js.map +1 -0
  16. package/dist/{dev-MRZ76V74.js → dev-NZLS72PG.js} +9 -7
  17. package/dist/dev-NZLS72PG.js.map +1 -0
  18. package/dist/{dist-PVHFUYP2.js → dist-E2PVGIPT.js} +4 -2
  19. package/dist/{dist-WDTDQDTX.js → dist-GVNWQXFR.js} +2 -2
  20. package/dist/index.js +314 -32
  21. package/dist/index.js.map +1 -1
  22. package/dist/{lineage-XSITWW2O.js → lineage-T5NRHHZN.js} +32 -5
  23. package/dist/{lineage-XSITWW2O.js.map → lineage-T5NRHHZN.js.map} +1 -1
  24. package/dist/public/assets/{EventManagement-BlxJ2TFw.js → EventManagement-7MyQq5KD.js} +1 -1
  25. package/dist/public/assets/{LoginPage-BT8ikmPn.js → LoginPage-BypxvDY2.js} +1 -1
  26. package/dist/public/assets/{PublicViewer-B4uFxgbt.js → PublicViewer-CdDaYqTc.js} +1 -1
  27. package/dist/public/assets/{SetupWizard-njrOhCzw.js → SetupWizard-CEGLuSGr.js} +1 -1
  28. package/dist/public/assets/{ShareManagement-Bg16oJhW.js → ShareManagement-DcPZNRdx.js} +1 -1
  29. package/dist/public/assets/{UserManagement-tiCIT4UY.js → UserManagement-VZ9Qvds0.js} +1 -1
  30. package/dist/public/assets/{index-BZ25r23j.css → index-B_fusLA_.css} +1 -1
  31. package/dist/public/assets/index-Cxn1i3jV.js +187 -0
  32. package/dist/public/assets/{index.es-BuktD_R2.js → index.es-06ls9Fpg.js} +1 -1
  33. package/dist/public/assets/{jspdf.es.min-DFRl2hZQ.js → jspdf.es.min-DER4Hnpt.js} +3 -3
  34. package/dist/public/index.html +3 -3
  35. package/dist/{query-JRMMNXX6.js → query-3F5V5CZH.js} +4 -4
  36. package/dist/{sample-VGIY4U4J.js → sample-SWYXGWOM.js} +4 -4
  37. package/dist/search-ARIDL6DA.js +28 -0
  38. package/dist/search-ARIDL6DA.js.map +1 -0
  39. package/dist/source-resolver-UHKZVOOC.js +18 -0
  40. package/dist/source-resolver-UHKZVOOC.js.map +1 -0
  41. package/dist/{sync-warehouse-XHTBZH25.js → sync-warehouse-J4E2R2PW.js} +4 -4
  42. package/dist/tables-VAR2ZKUA.js +30 -0
  43. package/dist/tables-VAR2ZKUA.js.map +1 -0
  44. package/dist/templates/default/docs/yamchart-reference.md +23 -4
  45. package/dist/templates/default/yamchart.yaml +1 -1
  46. package/dist/templates/empty/yamchart.yaml +1 -1
  47. package/dist/{test-TXRZWNXK.js → test-SV5SLSLM.js} +4 -4
  48. package/package.json +1 -1
  49. package/dist/chunk-JYQKDWLG.js.map +0 -1
  50. package/dist/chunk-OTAUP5RC.js.map +0 -1
  51. package/dist/chunk-X6LQGWUX.js.map +0 -1
  52. package/dist/describe-TGIOBNJB.js +0 -44
  53. package/dist/describe-TGIOBNJB.js.map +0 -1
  54. package/dist/dev-MRZ76V74.js.map +0 -1
  55. package/dist/public/assets/index-B41yj3io.js +0 -187
  56. package/dist/search-QSYNG4SR.js +0 -39
  57. package/dist/search-QSYNG4SR.js.map +0 -1
  58. package/dist/tables-UOO342TA.js +0 -40
  59. package/dist/tables-UOO342TA.js.map +0 -1
  60. /package/dist/{advisor-57BOMUUF.js.map → advisor-JMWAAWJO.js.map} +0 -0
  61. /package/dist/{chunk-E2UZXDF6.js.map → chunk-N6PUISAQ.js.map} +0 -0
  62. /package/dist/{connection-utils-FTSZU2VF.js.map → connection-utils-VEKXRCOM.js.map} +0 -0
  63. /package/dist/{dist-PVHFUYP2.js.map → dist-E2PVGIPT.js.map} +0 -0
  64. /package/dist/{dist-WDTDQDTX.js.map → dist-GVNWQXFR.js.map} +0 -0
  65. /package/dist/{query-JRMMNXX6.js.map → query-3F5V5CZH.js.map} +0 -0
  66. /package/dist/{sample-VGIY4U4J.js.map → sample-SWYXGWOM.js.map} +0 -0
  67. /package/dist/{sync-warehouse-XHTBZH25.js.map → sync-warehouse-J4E2R2PW.js.map} +0 -0
  68. /package/dist/{test-TXRZWNXK.js.map → test-SV5SLSLM.js.map} +0 -0
@@ -4,6 +4,7 @@ import {
4
4
  MySQLConnector,
5
5
  PostgresConnector,
6
6
  QueryCompiler,
7
+ ReconnectingConnector,
7
8
  SQLiteConnector,
8
9
  SnowflakeConnector,
9
10
  SqlList,
@@ -30,7 +31,7 @@ import {
30
31
  runModel,
31
32
  serializeDateValue,
32
33
  templateHasVariable
33
- } from "./chunk-JYQKDWLG.js";
34
+ } from "./chunk-5N3FYFBV.js";
34
35
  import {
35
36
  SemanticModelBuilder,
36
37
  SemanticQueryCompiler,
@@ -47,6 +48,7 @@ export {
47
48
  MySQLConnector,
48
49
  PostgresConnector,
49
50
  QueryCompiler,
51
+ ReconnectingConnector,
50
52
  SQLiteConnector,
51
53
  SemanticModelBuilder,
52
54
  SemanticQueryCompiler,
@@ -81,4 +83,4 @@ export {
81
83
  templateHasVariable,
82
84
  validateSemanticQuery
83
85
  };
84
- //# sourceMappingURL=dist-PVHFUYP2.js.map
86
+ //# sourceMappingURL=dist-E2PVGIPT.js.map
@@ -1,4 +1,4 @@
1
- import "./chunk-JYQKDWLG.js";
1
+ import "./chunk-5N3FYFBV.js";
2
2
  import {
3
3
  SemanticModelBuilder,
4
4
  SemanticQueryCompiler
@@ -787,4 +787,4 @@ export {
787
787
  updateSchemaYml,
788
788
  writeDbtModel
789
789
  };
790
- //# sourceMappingURL=dist-WDTDQDTX.js.map
790
+ //# sourceMappingURL=dist-GVNWQXFR.js.map
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  findProjectRoot,
7
7
  loadEnvFile,
8
8
  validateProject
9
- } from "./chunk-E2UZXDF6.js";
9
+ } from "./chunk-N6PUISAQ.js";
10
10
  import {
11
11
  detail,
12
12
  error,
@@ -17,8 +17,8 @@ import {
17
17
  success,
18
18
  warning
19
19
  } from "./chunk-HJVVHYVN.js";
20
- import "./chunk-X6LQGWUX.js";
21
- import "./chunk-JYQKDWLG.js";
20
+ import "./chunk-KP4CYPBL.js";
21
+ import "./chunk-5N3FYFBV.js";
22
22
  import "./chunk-UND73EOB.js";
23
23
  import "./chunk-DGUM43GV.js";
24
24
 
@@ -97,11 +97,12 @@ program.command("dev").description("Start development server with hot reload").a
97
97
  detail("Run this command from a yamchart project directory");
98
98
  process.exit(2);
99
99
  }
100
- const { runDevServer } = await import("./dev-MRZ76V74.js");
100
+ const { runDevServer } = await import("./dev-NZLS72PG.js");
101
101
  await runDevServer(projectDir, {
102
102
  port: parseInt(options.port, 10),
103
103
  apiOnly: options.apiOnly ?? false,
104
- open: options.open
104
+ open: options.open,
105
+ version: pkg.version
105
106
  });
106
107
  });
107
108
  program.command("init").description("Create a new yamchart project").argument("[directory]", "Target directory", ".").option("--example", "Create full example project with sample database").option("--empty", "Create only yamchart.yaml (no connections, models, or charts)").option("--force", "Overwrite existing files").action(async (directory, options) => {
@@ -169,7 +170,7 @@ program.command("sync-dbt").description("Sync dbt project metadata into AI-reada
169
170
  if (!options.targetDatabase) {
170
171
  try {
171
172
  const { readFile } = await import("fs/promises");
172
- const { resolveConnection } = await import("./connection-utils-FTSZU2VF.js");
173
+ const { resolveConnection } = await import("./connection-utils-VEKXRCOM.js");
173
174
  const { detectDatabaseMismatch } = await import("./rewrite-database-FDJIXKZ2.js");
174
175
  const catalogJsonStr = await readFile(join(projectDir, ".yamchart", "catalog.json"), "utf-8");
175
176
  const catalogData = JSON.parse(catalogJsonStr);
@@ -223,7 +224,7 @@ program.command("test").description("Run model tests (@returns schema checks and
223
224
  }
224
225
  loadEnvFile(projectDir);
225
226
  try {
226
- const { testProject, formatTestOutput } = await import("./test-TXRZWNXK.js");
227
+ const { testProject, formatTestOutput } = await import("./test-SV5SLSLM.js");
227
228
  const result = await testProject(projectDir, model, {
228
229
  connection: options.connection,
229
230
  json: options.json
@@ -261,7 +262,7 @@ program.command("reset-password").description("Reset a user password (requires a
261
262
  const { resetPassword } = await import("./reset-password-IZQTDTU7.js");
262
263
  await resetPassword(projectDir, options.email);
263
264
  });
264
- program.command("tables").description("List tables and views in the connected database").option("-c, --connection <name>", "Connection to use (overrides default)").option("-s, --schema <name>", "Filter to schema").option("-d, --database <name>", "Filter to database (Snowflake/Databricks)").option("--json", "Output as JSON").action(async (options) => {
265
+ program.command("tables").description("List tables and views in the connected database").option("-c, --connection <name>", "Connection to use (overrides default)").option("-s, --schema <name>", "Filter to schema").option("-d, --database <name>", "Filter to database (Snowflake/Databricks)").option("--json", "Output as JSON").option("--source <type>", "Data source: auto, catalog, model, or db (default: auto)").option("--compare", "Compare local metadata against live database").action(async (options) => {
265
266
  const startPath = resolve(".");
266
267
  const projectDir = await findProjectRoot(startPath);
267
268
  if (!projectDir) {
@@ -271,12 +272,48 @@ program.command("tables").description("List tables and views in the connected da
271
272
  }
272
273
  loadEnvFile(projectDir);
273
274
  try {
274
- const { listTables } = await import("./tables-UOO342TA.js");
275
- const result = await listTables(projectDir, options);
275
+ if (options.compare) {
276
+ const { resolveTablesSource } = await import("./source-resolver-UHKZVOOC.js");
277
+ const { compareTables, formatCompareTables } = await import("./compare-ZN6RUOOQ.js");
278
+ let localResult;
279
+ try {
280
+ localResult = await resolveTablesSource(projectDir, "catalog", options.connection, {
281
+ schema: options.schema,
282
+ database: options.database
283
+ });
284
+ } catch {
285
+ try {
286
+ localResult = await resolveTablesSource(projectDir, "model", options.connection, {
287
+ schema: options.schema,
288
+ database: options.database
289
+ });
290
+ } catch {
291
+ error("Cannot compare \u2014 no local metadata found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` first.");
292
+ process.exit(1);
293
+ }
294
+ }
295
+ const dbResult = await resolveTablesSource(projectDir, "db", options.connection, {
296
+ schema: options.schema,
297
+ database: options.database
298
+ });
299
+ const diffs = compareTables(localResult.tables, dbResult.tables);
300
+ if (options.json) {
301
+ console.log(JSON.stringify(diffs, null, 2));
302
+ } else {
303
+ console.log(formatCompareTables(localResult.source, diffs));
304
+ }
305
+ return;
306
+ }
307
+ const { listTables } = await import("./tables-VAR2ZKUA.js");
308
+ const result = await listTables(projectDir, {
309
+ ...options,
310
+ source: options.source || "auto"
311
+ });
276
312
  if (options.json) {
277
313
  console.log(JSON.stringify(result.tables, null, 2));
278
314
  } else {
279
- header(`Tables in ${result.connectionName} (${result.connectionType})`);
315
+ const sourceLabel = result.source === "db" ? `${result.connectionName} (${result.connectionType})` : `Source: ${result.source}`;
316
+ header(`Tables in ${sourceLabel}`);
280
317
  if (result.tables.length === 0) {
281
318
  info("No tables found");
282
319
  } else {
@@ -286,7 +323,7 @@ program.command("tables").description("List tables and views in the connected da
286
323
  console.log(` ${schema}${table.name}${typeLabel}`);
287
324
  }
288
325
  newline();
289
- info(`${result.tables.length} table(s) found (${result.durationMs.toFixed(0)}ms)`);
326
+ info(`${result.tables.length} table(s) found${result.durationMs > 0 ? ` (${result.durationMs.toFixed(0)}ms)` : ""}`);
290
327
  }
291
328
  }
292
329
  } catch (err) {
@@ -294,7 +331,7 @@ program.command("tables").description("List tables and views in the connected da
294
331
  process.exit(1);
295
332
  }
296
333
  });
297
- program.command("describe").description("Show columns and types for a table").argument("<table>", "Table name (can be fully qualified, e.g. schema.table)").option("-c, --connection <name>", "Connection to use (overrides default)").option("--json", "Output as JSON").action(async (table, options) => {
334
+ program.command("describe").description("Show columns and types for a table").argument("<table>", "Table name (can be fully qualified, e.g. schema.table)").option("-c, --connection <name>", "Connection to use (overrides default)").option("--json", "Output as JSON").option("--source <type>", "Data source: auto, catalog, model, or db (default: auto)").option("--compare", "Compare local metadata against live database").action(async (table, options) => {
298
335
  const startPath = resolve(".");
299
336
  const projectDir = await findProjectRoot(startPath);
300
337
  if (!projectDir) {
@@ -304,15 +341,42 @@ program.command("describe").description("Show columns and types for a table").ar
304
341
  }
305
342
  loadEnvFile(projectDir);
306
343
  try {
307
- const { describeTable } = await import("./describe-TGIOBNJB.js");
308
- const result = await describeTable(projectDir, table, options);
344
+ if (options.compare) {
345
+ const { resolveDescribeSource } = await import("./source-resolver-UHKZVOOC.js");
346
+ const { compareColumns, formatCompareColumns } = await import("./compare-ZN6RUOOQ.js");
347
+ let localResult;
348
+ try {
349
+ localResult = await resolveDescribeSource(projectDir, table, "catalog", options.connection);
350
+ } catch {
351
+ try {
352
+ localResult = await resolveDescribeSource(projectDir, table, "model", options.connection);
353
+ } catch {
354
+ error("Cannot compare \u2014 no local metadata found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` first.");
355
+ process.exit(1);
356
+ }
357
+ }
358
+ const dbResult = await resolveDescribeSource(projectDir, table, "db", options.connection);
359
+ const diffs = compareColumns(localResult.columns, dbResult.columns);
360
+ if (options.json) {
361
+ console.log(JSON.stringify(diffs, null, 2));
362
+ } else {
363
+ console.log(formatCompareColumns(localResult.table, localResult.source, diffs));
364
+ }
365
+ return;
366
+ }
367
+ const { describeTable } = await import("./describe-X55JPLES.js");
368
+ const result = await describeTable(projectDir, table, {
369
+ ...options,
370
+ source: options.source || "auto"
371
+ });
309
372
  if (options.json) {
310
373
  console.log(JSON.stringify(result.columns, null, 2));
311
374
  } else {
312
375
  if (result.resolvedFrom) {
313
376
  detail(`Resolved "${result.resolvedFrom}" \u2192 ${result.table}`);
314
377
  }
315
- header(`${result.table} (${result.connectionName})`);
378
+ const sourceLabel = result.source === "db" ? `${result.connectionName} (${result.connectionType})` : `Source: ${result.source}`;
379
+ header(`${result.table} (${sourceLabel})`);
316
380
  const nameWidth = Math.max(4, ...result.columns.map((c) => c.name.length));
317
381
  const typeWidth = Math.max(4, ...result.columns.map((c) => c.type.length));
318
382
  console.log(` ${"name".padEnd(nameWidth)} ${"type".padEnd(typeWidth)} nullable`);
@@ -322,7 +386,7 @@ program.command("describe").description("Show columns and types for a table").ar
322
386
  console.log(` ${col.name.padEnd(nameWidth)} ${pc.dim(col.type.padEnd(typeWidth))} ${nullable}`);
323
387
  }
324
388
  newline();
325
- info(`${result.columns.length} column(s) (${result.durationMs.toFixed(0)}ms)`);
389
+ info(`${result.columns.length} column(s)${result.durationMs > 0 ? ` (${result.durationMs.toFixed(0)}ms)` : ""}`);
326
390
  }
327
391
  } catch (err) {
328
392
  error(err instanceof Error ? err.message : String(err));
@@ -339,8 +403,8 @@ program.command("query").description("Execute SQL against a connection").argumen
339
403
  }
340
404
  loadEnvFile(projectDir);
341
405
  try {
342
- const { executeQuery } = await import("./query-JRMMNXX6.js");
343
- const { formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
406
+ const { executeQuery } = await import("./query-3F5V5CZH.js");
407
+ const { formatTable, formatJSON } = await import("./connection-utils-VEKXRCOM.js");
344
408
  const limit = options.limit ? parseInt(options.limit, 10) : void 0;
345
409
  const result = await executeQuery(projectDir, sql, {
346
410
  connection: options.connection,
@@ -367,8 +431,8 @@ program.command("sample").description("Show sample rows from a table or dbt mode
367
431
  }
368
432
  loadEnvFile(projectDir);
369
433
  try {
370
- const { sampleTable } = await import("./sample-VGIY4U4J.js");
371
- const { formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
434
+ const { sampleTable } = await import("./sample-SWYXGWOM.js");
435
+ const { formatTable, formatJSON } = await import("./connection-utils-VEKXRCOM.js");
372
436
  const limit = options.limit ? parseInt(options.limit, 10) : void 0;
373
437
  const result = await sampleTable(projectDir, table, {
374
438
  connection: options.connection,
@@ -388,7 +452,7 @@ program.command("sample").description("Show sample rows from a table or dbt mode
388
452
  process.exit(1);
389
453
  }
390
454
  });
391
- program.command("search").description("Search for tables and columns by keyword").argument("<keyword>", "Keyword to search for").option("-c, --connection <name>", "Connection to use (overrides default)").option("--json", "Output as JSON").action(async (keyword, options) => {
455
+ program.command("search").description("Search for tables and columns by keyword").argument("<keyword>", "Keyword to search for").option("-c, --connection <name>", "Connection to use (overrides default)").option("--json", "Output as JSON").option("--source <type>", "Data source: auto, catalog, model, or db (default: auto)").action(async (keyword, options) => {
392
456
  const startPath = resolve(".");
393
457
  const projectDir = await findProjectRoot(startPath);
394
458
  if (!projectDir) {
@@ -398,12 +462,16 @@ program.command("search").description("Search for tables and columns by keyword"
398
462
  }
399
463
  loadEnvFile(projectDir);
400
464
  try {
401
- const { searchDatabase } = await import("./search-QSYNG4SR.js");
402
- const result = await searchDatabase(projectDir, keyword, options);
465
+ const { searchDatabase } = await import("./search-ARIDL6DA.js");
466
+ const result = await searchDatabase(projectDir, keyword, {
467
+ ...options,
468
+ source: options.source || "auto"
469
+ });
403
470
  if (options.json) {
404
471
  console.log(JSON.stringify(result.results, null, 2));
405
472
  } else {
406
- header(`Search results for "${result.keyword}" in ${result.connectionName} (${result.connectionType})`);
473
+ const sourceLabel = result.source === "db" ? `${result.connectionName} (${result.connectionType})` : `Source: ${result.source}`;
474
+ header(`Search results for "${result.keyword}" in ${sourceLabel}`);
407
475
  const tables = result.results.filter((r) => r.type === "table");
408
476
  const columns = result.results.filter((r) => r.type === "column");
409
477
  if (tables.length > 0) {
@@ -431,7 +499,216 @@ program.command("search").description("Search for tables and columns by keyword"
431
499
  detail("No matches found");
432
500
  }
433
501
  newline();
434
- info(`${result.results.length} result(s) (${result.durationMs.toFixed(0)}ms)`);
502
+ info(`${result.results.length} result(s)${result.durationMs > 0 ? ` (${result.durationMs.toFixed(0)}ms)` : ""}`);
503
+ }
504
+ } catch (err) {
505
+ error(err instanceof Error ? err.message : String(err));
506
+ process.exit(1);
507
+ }
508
+ });
509
+ var catalogCmd = program.command("catalog").description("Explore cached local metadata (no database connection needed)");
510
+ catalogCmd.command("tables").description("List tables from cached catalog").option("-s, --schema <name>", "Filter to schema").option("--json", "Output as JSON").action(async (options) => {
511
+ const startPath = resolve(".");
512
+ const projectDir = await findProjectRoot(startPath);
513
+ if (!projectDir) {
514
+ error("yamchart.yaml not found");
515
+ detail("Run this command from a yamchart project directory");
516
+ process.exit(2);
517
+ }
518
+ try {
519
+ const { listTables } = await import("./tables-VAR2ZKUA.js");
520
+ const result = await listTables(projectDir, {
521
+ source: "catalog",
522
+ schema: options.schema
523
+ });
524
+ if (options.json) {
525
+ console.log(JSON.stringify(result.tables, null, 2));
526
+ } else {
527
+ header("Tables (from catalog)");
528
+ if (result.tables.length === 0) {
529
+ info("No tables found in catalog");
530
+ detail("Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate");
531
+ } else {
532
+ const filtered = options.schema ? result.tables.filter((t) => t.schema.toLowerCase().includes(options.schema.toLowerCase())) : result.tables;
533
+ for (const table of filtered) {
534
+ const schema = table.schema ? `${table.schema}.` : "";
535
+ const typeLabel = table.type === "VIEW" ? pc.dim(" (view)") : table.type === "SOURCE" ? pc.dim(" (source)") : "";
536
+ console.log(` ${schema}${table.name}${typeLabel}`);
537
+ }
538
+ newline();
539
+ info(`${filtered.length} table(s) from catalog`);
540
+ }
541
+ }
542
+ } catch (err) {
543
+ if (err instanceof Error && err.message.includes("No catalog found")) {
544
+ error("No catalog found");
545
+ detail("Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate");
546
+ } else {
547
+ error(err instanceof Error ? err.message : String(err));
548
+ }
549
+ process.exit(1);
550
+ }
551
+ });
552
+ catalogCmd.command("describe").description("Show cached columns and types for a table").argument("<table>", "Table name or model name").option("--json", "Output as JSON").action(async (table, options) => {
553
+ const startPath = resolve(".");
554
+ const projectDir = await findProjectRoot(startPath);
555
+ if (!projectDir) {
556
+ error("yamchart.yaml not found");
557
+ detail("Run this command from a yamchart project directory");
558
+ process.exit(2);
559
+ }
560
+ try {
561
+ const { describeTable } = await import("./describe-X55JPLES.js");
562
+ const result = await describeTable(projectDir, table, { source: "catalog" });
563
+ if (options.json) {
564
+ console.log(JSON.stringify(result.columns, null, 2));
565
+ } else {
566
+ if (result.resolvedFrom) {
567
+ detail(`Resolved "${result.resolvedFrom}" \u2192 ${result.table}`);
568
+ }
569
+ header(`${result.table} (from catalog)`);
570
+ const nameWidth = Math.max(4, ...result.columns.map((c) => c.name.length));
571
+ const typeWidth = Math.max(4, ...result.columns.map((c) => c.type.length));
572
+ console.log(` ${"name".padEnd(nameWidth)} ${"type".padEnd(typeWidth)} nullable`);
573
+ console.log(` ${"\u2500".repeat(nameWidth)} ${"\u2500".repeat(typeWidth)} ${"\u2500".repeat(8)}`);
574
+ for (const col of result.columns) {
575
+ const nullable = col.nullable === "YES" ? pc.dim("yes") : "no";
576
+ console.log(` ${col.name.padEnd(nameWidth)} ${pc.dim(col.type.padEnd(typeWidth))} ${nullable}`);
577
+ }
578
+ newline();
579
+ info(`${result.columns.length} column(s)`);
580
+ }
581
+ } catch (err) {
582
+ if (err instanceof Error && err.message.includes("No catalog found")) {
583
+ error("No catalog found");
584
+ detail("Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate");
585
+ } else if (err instanceof Error && err.message.includes("not found in catalog")) {
586
+ error(err.message);
587
+ detail("Try `yamchart catalog search` to find available tables");
588
+ } else {
589
+ error(err instanceof Error ? err.message : String(err));
590
+ }
591
+ process.exit(1);
592
+ }
593
+ });
594
+ catalogCmd.command("search").description("Search cached metadata for tables and columns").argument("<keyword>", "Keyword to search for").option("--json", "Output as JSON").action(async (keyword, options) => {
595
+ const startPath = resolve(".");
596
+ const projectDir = await findProjectRoot(startPath);
597
+ if (!projectDir) {
598
+ error("yamchart.yaml not found");
599
+ detail("Run this command from a yamchart project directory");
600
+ process.exit(2);
601
+ }
602
+ try {
603
+ const { searchDatabase } = await import("./search-ARIDL6DA.js");
604
+ const result = await searchDatabase(projectDir, keyword, { source: "catalog" });
605
+ if (options.json) {
606
+ console.log(JSON.stringify(result.results, null, 2));
607
+ } else {
608
+ header(`Search results for "${keyword}" (from catalog)`);
609
+ const tables = result.results.filter((r) => r.type === "table");
610
+ const columns = result.results.filter((r) => r.type === "column");
611
+ if (tables.length > 0) {
612
+ newline();
613
+ console.log(" Tables:");
614
+ for (const t of tables) {
615
+ const qualified = t.schema ? `${t.schema}.${t.table}` : t.table;
616
+ console.log(` ${qualified}`);
617
+ }
618
+ }
619
+ if (columns.length > 0) {
620
+ newline();
621
+ console.log(" Columns:");
622
+ const nameWidth = Math.max(...columns.map((c) => {
623
+ const qualified = c.schema ? `${c.schema}.${c.table}.${c.column}` : `${c.table}.${c.column}`;
624
+ return qualified.length;
625
+ }));
626
+ for (const c of columns) {
627
+ const qualified = c.schema ? `${c.schema}.${c.table}.${c.column}` : `${c.table}.${c.column}`;
628
+ const colType = c.columnType ? pc.dim(c.columnType) : "";
629
+ console.log(` ${qualified.padEnd(nameWidth + 2)}${colType}`);
630
+ }
631
+ }
632
+ if (result.results.length === 0) {
633
+ detail("No matches found in catalog");
634
+ detail("Try `yamchart search <keyword>` to search the live database");
635
+ }
636
+ newline();
637
+ info(`${result.results.length} result(s) from catalog`);
638
+ }
639
+ } catch (err) {
640
+ if (err instanceof Error && err.message.includes("No catalog found")) {
641
+ error("No catalog found");
642
+ detail("Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate");
643
+ } else {
644
+ error(err instanceof Error ? err.message : String(err));
645
+ }
646
+ process.exit(1);
647
+ }
648
+ });
649
+ catalogCmd.command("status").description("Show catalog sync status").option("--json", "Output as JSON").action(async (options) => {
650
+ const startPath = resolve(".");
651
+ const projectDir = await findProjectRoot(startPath);
652
+ if (!projectDir) {
653
+ error("yamchart.yaml not found");
654
+ detail("Run this command from a yamchart project directory");
655
+ process.exit(2);
656
+ }
657
+ try {
658
+ const { readFile } = await import("fs/promises");
659
+ const catalogPath = join(projectDir, ".yamchart", "catalog.json");
660
+ let catalogData;
661
+ try {
662
+ catalogData = JSON.parse(await readFile(catalogPath, "utf-8"));
663
+ } catch {
664
+ if (options.json) {
665
+ console.log(JSON.stringify({ exists: false }));
666
+ } else {
667
+ error("No catalog found");
668
+ detail("Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate");
669
+ }
670
+ process.exit(1);
671
+ return;
672
+ }
673
+ const models = catalogData.models || [];
674
+ const dbtModels = models.filter((m) => m.source === "dbt");
675
+ const warehouseModels = models.filter((m) => m.source === "warehouse");
676
+ const sourceModels = models.filter((m) => m.source === "dbt-source");
677
+ const totalColumns = models.reduce((sum, m) => sum + (m.columns?.length || 0), 0);
678
+ let syncState = null;
679
+ try {
680
+ const syncPath = join(projectDir, ".yamchart", "warehouse-sync.json");
681
+ syncState = JSON.parse(await readFile(syncPath, "utf-8"));
682
+ } catch {
683
+ }
684
+ if (options.json) {
685
+ console.log(JSON.stringify({
686
+ exists: true,
687
+ syncedAt: catalogData.syncedAt,
688
+ source: catalogData.source,
689
+ models: models.length,
690
+ dbtModels: dbtModels.length,
691
+ warehouseModels: warehouseModels.length,
692
+ sourceModels: sourceModels.length,
693
+ totalColumns,
694
+ warehouseSync: syncState ? {
695
+ syncedAt: syncState.syncedAt,
696
+ connection: syncState.connection,
697
+ schemas: syncState.schemas
698
+ } : null
699
+ }, null, 2));
700
+ } else {
701
+ header("Catalog Status");
702
+ console.log(` Last synced: ${catalogData.syncedAt || "unknown"}`);
703
+ console.log(` Models: ${models.length} total (${dbtModels.length} dbt, ${warehouseModels.length} warehouse, ${sourceModels.length} sources)`);
704
+ console.log(` Columns: ${totalColumns}`);
705
+ if (syncState) {
706
+ newline();
707
+ console.log(` Warehouse sync:`);
708
+ console.log(` Connection: ${syncState.connection || "default"}`);
709
+ console.log(` Schemas: ${syncState.schemas?.join(", ") || "all"}`);
710
+ console.log(` Last sync: ${syncState.syncedAt || "unknown"}`);
711
+ }
435
712
  }
436
713
  } catch (err) {
437
714
  error(err instanceof Error ? err.message : String(err));
@@ -448,14 +725,14 @@ program.command("sync-warehouse").description("Sync warehouse table metadata int
448
725
  }
449
726
  loadEnvFile(projectDir);
450
727
  try {
451
- const { runSyncWarehouse } = await import("./sync-warehouse-XHTBZH25.js");
728
+ const { runSyncWarehouse } = await import("./sync-warehouse-J4E2R2PW.js");
452
729
  await runSyncWarehouse(projectDir, options);
453
730
  } catch (err) {
454
731
  error(err instanceof Error ? err.message : String(err));
455
732
  process.exit(1);
456
733
  }
457
734
  });
458
- program.command("lineage").description("Show upstream dependencies for a model").argument("<model>", "Model name to trace lineage for").option("--depth <n>", "Maximum depth to trace (default: unlimited)").option("--json", "Output as JSON").action(async (model, options) => {
735
+ program.command("lineage").description("Show upstream dependencies for a model").argument("<model>", "Model name to trace lineage for").option("--depth <n>", "Maximum depth to trace (default: unlimited)").option("--json", "Output as JSON").option("--source <type>", "Data source: auto, catalog, model, or db (default: auto)").action(async (model, options) => {
459
736
  const startPath = resolve(".");
460
737
  const projectDir = await findProjectRoot(startPath);
461
738
  if (!projectDir) {
@@ -463,10 +740,15 @@ program.command("lineage").description("Show upstream dependencies for a model")
463
740
  detail("Run this command from a yamchart project directory");
464
741
  process.exit(2);
465
742
  }
743
+ loadEnvFile(projectDir);
466
744
  try {
467
- const { getLineage } = await import("./lineage-XSITWW2O.js");
745
+ const { getLineage } = await import("./lineage-T5NRHHZN.js");
468
746
  const depth = options.depth ? parseInt(options.depth, 10) : void 0;
469
- const result = await getLineage(projectDir, model, { depth, json: options.json });
747
+ const result = await getLineage(projectDir, model, {
748
+ depth,
749
+ json: options.json,
750
+ source: options.source || "auto"
751
+ });
470
752
  if (options.json) {
471
753
  console.log(JSON.stringify(result.tree, null, 2));
472
754
  } else {
@@ -494,7 +776,7 @@ program.command("advisor").description("AI-powered dbt model advisor \u2014 sugg
494
776
  process.exit(2);
495
777
  }
496
778
  loadEnvFile(projectDir);
497
- const { runAdvisor } = await import("./advisor-57BOMUUF.js");
779
+ const { runAdvisor } = await import("./advisor-JMWAAWJO.js");
498
780
  await runAdvisor(projectDir, question, {
499
781
  top: options.top ? parseInt(options.top, 10) : 5,
500
782
  json: options.json,
@@ -584,7 +866,7 @@ semanticCmd.command("query").description("Run a structured query against the sem
584
866
  console.log(result.sql);
585
867
  return;
586
868
  }
587
- const { resolveConnection, createConnector, formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
869
+ const { resolveConnection, createConnector, formatTable, formatJSON } = await import("./connection-utils-VEKXRCOM.js");
588
870
  const connection = await resolveConnection(projectDir, options.connection);
589
871
  const connector = createConnector(connection, projectDir);
590
872
  const start = performance.now();