yamchart 0.5.3 → 0.6.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.
Files changed (41) hide show
  1. package/dist/{advisor-CXXGXZ5V.js → advisor-IJG6UFTJ.js} +15 -7
  2. package/dist/advisor-IJG6UFTJ.js.map +1 -0
  3. package/dist/{chunk-ZN3AJM76.js → chunk-EHM6AMMA.js} +78 -2
  4. package/dist/chunk-EHM6AMMA.js.map +1 -0
  5. package/dist/chunk-WYS4ULBE.js +125 -0
  6. package/dist/chunk-WYS4ULBE.js.map +1 -0
  7. package/dist/{describe-Y4VD4JQX.js → describe-HD2RJQX3.js} +2 -2
  8. package/dist/{dev-7SWSX2X7.js → dev-LCYHM7UA.js} +19 -3
  9. package/dist/dev-LCYHM7UA.js.map +1 -0
  10. package/dist/{dist-ZRRM3OWF.js → dist-D5NLPC5X.js} +62 -1
  11. package/dist/dist-D5NLPC5X.js.map +1 -0
  12. package/dist/index.js +49 -6
  13. package/dist/index.js.map +1 -1
  14. package/dist/lineage-TX33DUDP.js +81 -0
  15. package/dist/lineage-TX33DUDP.js.map +1 -0
  16. package/dist/public/assets/{LoginPage-BhzP7Hkq.js → LoginPage-NNsbTBPo.js} +1 -1
  17. package/dist/public/assets/{PublicViewer-owhT_M21.js → PublicViewer-DDsvIFas.js} +1 -1
  18. package/dist/public/assets/{SetupWizard-BbV-9haQ.js → SetupWizard-CY-o51--.js} +1 -1
  19. package/dist/public/assets/{ShareManagement-BWDdV-hd.js → ShareManagement-B-Kz0tT8.js} +1 -1
  20. package/dist/public/assets/{UserManagement-DGGk6XAr.js → UserManagement-B6LjBcOb.js} +1 -1
  21. package/dist/public/assets/{index-Ce_q4or4.js → index-IDI-DDZi.js} +11 -11
  22. package/dist/public/assets/{index.es-DZ9bSPjd.js → index.es-DK8yr16j.js} +1 -1
  23. package/dist/public/assets/{jspdf.es.min-BZhCusuH.js → jspdf.es.min-CDLoTXR9.js} +3 -3
  24. package/dist/public/index.html +1 -1
  25. package/dist/{search-CXBNM2KK.js → search-ECGHSZBU.js} +2 -2
  26. package/dist/{sync-dbt-HICRXDB2.js → sync-dbt-RKEHTN4P.js} +35 -54
  27. package/dist/sync-dbt-RKEHTN4P.js.map +1 -0
  28. package/dist/sync-warehouse-WPNGI6YP.js +367 -0
  29. package/dist/sync-warehouse-WPNGI6YP.js.map +1 -0
  30. package/dist/{tables-ZY3NRC6E.js → tables-5BVEKUPB.js} +2 -2
  31. package/dist/templates/default/CLAUDE.md +2 -0
  32. package/dist/templates/default/docs/yamchart-reference.md +54 -0
  33. package/package.json +4 -4
  34. package/dist/advisor-CXXGXZ5V.js.map +0 -1
  35. package/dist/chunk-ZN3AJM76.js.map +0 -1
  36. package/dist/dev-7SWSX2X7.js.map +0 -1
  37. package/dist/dist-ZRRM3OWF.js.map +0 -1
  38. package/dist/sync-dbt-HICRXDB2.js.map +0 -1
  39. /package/dist/{describe-Y4VD4JQX.js.map → describe-HD2RJQX3.js.map} +0 -0
  40. /package/dist/{search-CXBNM2KK.js.map → search-ECGHSZBU.js.map} +0 -0
  41. /package/dist/{tables-ZY3NRC6E.js.map → tables-5BVEKUPB.js.map} +0 -0
@@ -117,6 +117,13 @@ async function buildContext(projectDir, options) {
117
117
  } catch {
118
118
  }
119
119
  const catalog = await loadCatalogMarkdown(projectDir);
120
+ let catalogJson = null;
121
+ try {
122
+ const raw = await readFile(join(projectDir, ".yamchart", "catalog.json"), "utf-8");
123
+ const parsed = JSON.parse(raw);
124
+ catalogJson = { models: parsed.models || [] };
125
+ } catch {
126
+ }
120
127
  const dbtPath = await getDbtProjectPath(projectDir, options.dbtPath);
121
128
  let dbt = {
122
129
  projectPath: dbtPath ?? "",
@@ -132,7 +139,7 @@ async function buildContext(projectDir, options) {
132
139
  };
133
140
  if (dbtPath) {
134
141
  try {
135
- const { detectConventions, listDbtModels } = await import("./dist-ZRRM3OWF.js");
142
+ const { detectConventions, listDbtModels } = await import("./dist-D5NLPC5X.js");
136
143
  const dbtProjectYml = await readFile(join(dbtPath, "dbt_project.yml"), "utf-8");
137
144
  const dbtConfig = parseYaml(dbtProjectYml);
138
145
  const conventions = await detectConventions(dbtPath);
@@ -171,7 +178,8 @@ async function buildContext(projectDir, options) {
171
178
  models: yamchartModels,
172
179
  charts: yamchartCharts,
173
180
  dashboards: yamchartDashboards,
174
- catalog
181
+ catalog,
182
+ catalogJson
175
183
  },
176
184
  dbt,
177
185
  warehouse
@@ -227,7 +235,7 @@ async function runAdvisor(projectDir, questionOrMode, options) {
227
235
  `warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : "not connected"}`
228
236
  );
229
237
  console.log("");
230
- const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-ZRRM3OWF.js");
238
+ const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import("./dist-D5NLPC5X.js");
231
239
  const provider = new AnthropicProvider(apiKey);
232
240
  const agent = new AdvisorAgent(provider);
233
241
  const isAudit = questionOrMode === "audit";
@@ -272,7 +280,7 @@ ${pc.bold(`[${i + 1}]`)} ${formatProposal(proposal, context.dbt.conventions, bui
272
280
  spin2.stop();
273
281
  console.log(result.response);
274
282
  if (result.proposals.length > 0) {
275
- const { buildModelPath: bmp } = await import("./dist-ZRRM3OWF.js");
283
+ const { buildModelPath: bmp } = await import("./dist-D5NLPC5X.js");
276
284
  for (const proposal of result.proposals) {
277
285
  console.log(
278
286
  `
@@ -313,7 +321,7 @@ ${formatProposal(proposal, context.dbt.conventions, bmp)}`
313
321
  conversationHistory.length = 0;
314
322
  conversationHistory.push(...result.messages);
315
323
  if (result.proposals.length > 0) {
316
- const { buildModelPath: bmp } = await import("./dist-ZRRM3OWF.js");
324
+ const { buildModelPath: bmp } = await import("./dist-D5NLPC5X.js");
317
325
  for (const proposal of result.proposals) {
318
326
  console.log(
319
327
  `
@@ -331,7 +339,7 @@ async function offerApply(context, proposals) {
331
339
  return;
332
340
  }
333
341
  const { confirm } = await import("@inquirer/prompts");
334
- const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-ZRRM3OWF.js");
342
+ const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } = await import("./dist-D5NLPC5X.js");
335
343
  for (const proposal of proposals) {
336
344
  console.log("");
337
345
  const shouldApply = await confirm({
@@ -370,4 +378,4 @@ async function offerApply(context, proposals) {
370
378
  export {
371
379
  runAdvisor
372
380
  };
373
- //# sourceMappingURL=advisor-CXXGXZ5V.js.map
381
+ //# sourceMappingURL=advisor-IJG6UFTJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/advisor.ts"],"sourcesContent":["import { readFile, readdir, access } from 'fs/promises';\nimport { join } from 'path';\nimport { parse as parseYaml } from 'yaml';\nimport { createInterface } from 'readline';\nimport pc from 'picocolors';\nimport * as output from '../utils/output.js';\nimport { resolveConnection, createConnector } from './connection-utils.js';\nimport type { Message, AdvisorContext, Proposal, CatalogJsonData } from '@yamchart/advisor';\n\nexport interface AdvisorOptions {\n top?: number;\n json?: boolean;\n dbtPath?: string;\n connection?: string;\n}\n\nasync function loadCatalogMarkdown(projectDir: string): Promise<string | null> {\n try {\n const catalogPath = join(projectDir, '.yamchart', 'catalog.md');\n await access(catalogPath);\n return readFile(catalogPath, 'utf-8');\n } catch {\n return null;\n }\n}\n\nasync function getDbtProjectPath(projectDir: string, override?: string): Promise<string | null> {\n if (override) return override;\n\n try {\n const dbtSourcePath = join(projectDir, '.yamchart', 'dbt-source.yaml');\n const content = await readFile(dbtSourcePath, 'utf-8');\n const parsed = parseYaml(content) as { path?: string };\n if (parsed.path) {\n return join(projectDir, parsed.path);\n }\n } catch {\n // No saved dbt source config\n }\n\n return null;\n}\n\nasync function buildContext(\n projectDir: string,\n options: AdvisorOptions,\n): Promise<AdvisorContext> {\n // 1. Load yamchart models\n const { parseModelMetadata } = await import('@yamchart/query');\n const modelsDir = join(projectDir, 'models');\n const yamchartModels: AdvisorContext['yamchart']['models'] = [];\n\n try {\n const files = await readdir(modelsDir, { recursive: true });\n for (const file of files) {\n if (!String(file).endsWith('.sql')) continue;\n const content = await readFile(join(modelsDir, String(file)), 'utf-8');\n try {\n const metadata = parseModelMetadata(content);\n yamchartModels.push({\n name: metadata.name,\n description: metadata.description,\n sql: metadata.sql,\n params: metadata.params?.map((p) => ({ name: p.name, type: p.type })),\n returns: metadata.returns?.map((r) => ({ name: r.name, type: r.type })),\n });\n } catch {\n // Skip unparseable models\n }\n }\n } catch {\n // No models dir\n }\n\n // 2. Load yamchart charts\n const chartsDir = join(projectDir, 'charts');\n const yamchartCharts: AdvisorContext['yamchart']['charts'] = [];\n\n try {\n const files = await readdir(chartsDir, { recursive: true });\n for (const file of files) {\n const fname = String(file);\n if (!fname.endsWith('.yaml') && !fname.endsWith('.yml')) continue;\n const content = await readFile(join(chartsDir, fname), 'utf-8');\n try {\n const parsed = parseYaml(content) as {\n name?: string;\n title?: string;\n source?: { model?: string };\n chart?: { type?: string };\n };\n if (parsed.name && parsed.source?.model) {\n yamchartCharts.push({\n name: parsed.name,\n title: parsed.title,\n model: parsed.source.model,\n type: parsed.chart?.type ?? 'unknown',\n });\n }\n } catch {\n // Skip unparseable charts\n }\n }\n } catch {\n // No charts dir\n }\n\n // 3. Load yamchart dashboards\n const dashboardsDir = join(projectDir, 'dashboards');\n const yamchartDashboards: AdvisorContext['yamchart']['dashboards'] = [];\n\n try {\n const files = await readdir(dashboardsDir, { recursive: true });\n for (const file of files) {\n const fname = String(file);\n if (!fname.endsWith('.yaml') && !fname.endsWith('.yml')) continue;\n const content = await readFile(join(dashboardsDir, fname), 'utf-8');\n try {\n const parsed = parseYaml(content) as {\n name?: string;\n title?: string;\n layout?: { rows?: Array<{ widgets?: Array<{ ref?: string }> }> };\n };\n if (parsed.name) {\n const charts: string[] = [];\n for (const row of parsed.layout?.rows ?? []) {\n for (const widget of row.widgets ?? []) {\n if (widget.ref) charts.push(widget.ref);\n }\n }\n yamchartDashboards.push({\n name: parsed.name,\n title: parsed.title,\n charts,\n });\n }\n } catch {\n // Skip\n }\n }\n } catch {\n // No dashboards dir\n }\n\n // 4. Load catalog\n const catalog = await loadCatalogMarkdown(projectDir);\n\n // 4b. Load catalog.json (warehouse table metadata)\n let catalogJson: CatalogJsonData | null = null;\n try {\n const raw = await readFile(join(projectDir, '.yamchart', 'catalog.json'), 'utf-8');\n const parsed = JSON.parse(raw);\n catalogJson = { models: parsed.models || [] };\n } catch {\n // No catalog.json available\n }\n\n // 5. Load dbt project\n const dbtPath = await getDbtProjectPath(projectDir, options.dbtPath);\n let dbt: AdvisorContext['dbt'] = {\n projectPath: dbtPath ?? '',\n projectName: 'unknown',\n conventions: {\n folderStructure: [],\n namingPrefixes: {},\n commonMaterializations: {},\n schemaYmlPattern: 'per-folder',\n testPatterns: [],\n },\n models: [],\n };\n\n if (dbtPath) {\n try {\n const { detectConventions, listDbtModels } = await import('@yamchart/advisor');\n const dbtProjectYml = await readFile(join(dbtPath, 'dbt_project.yml'), 'utf-8');\n const dbtConfig = parseYaml(dbtProjectYml) as { name?: string };\n\n const conventions = await detectConventions(dbtPath);\n const models = await listDbtModels(dbtPath);\n\n dbt = {\n projectPath: dbtPath,\n projectName: dbtConfig.name ?? 'unknown',\n conventions,\n models,\n };\n } catch (err) {\n output.warning(\n `Could not read dbt project: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // 6. Set up warehouse connection (optional)\n let warehouse: AdvisorContext['warehouse'] = null;\n\n try {\n const connection = await resolveConnection(projectDir, options.connection);\n const connector = createConnector(connection, projectDir);\n await connector.connect();\n\n warehouse = {\n connectionType: connection.type,\n executeSql: async (sql: string) => {\n const result = await connector.execute(sql);\n return {\n columns: result.columns.map((c) => c.name),\n rows: result.rows,\n };\n },\n };\n } catch {\n // No connection available — advisor works without it\n }\n\n return {\n yamchart: {\n models: yamchartModels,\n charts: yamchartCharts,\n dashboards: yamchartDashboards,\n catalog,\n catalogJson,\n },\n dbt,\n warehouse,\n };\n}\n\nfunction formatProposal(\n proposal: Proposal,\n conventions: AdvisorContext['dbt']['conventions'],\n buildModelPathFn: (\n name: string,\n layer: string | undefined,\n conventions: AdvisorContext['dbt']['conventions'],\n subfolder?: string,\n ) => string,\n): string {\n const path = buildModelPathFn(\n proposal.name,\n proposal.layer,\n conventions,\n proposal.subfolder,\n );\n\n const lines = [\n pc.bold(` ${proposal.name}`),\n ` ${pc.dim(proposal.explanation)}`,\n ` Path: ${pc.cyan(path)} (${proposal.materialization})`,\n '',\n pc.dim(' ' + '\\u2500'.repeat(30)),\n proposal.sql\n .split('\\n')\n .map((l: string) => ` ${pc.dim(l)}`)\n .join('\\n'),\n pc.dim(' ' + '\\u2500'.repeat(30)),\n ];\n return lines.join('\\n');\n}\n\nexport async function runAdvisor(\n projectDir: string,\n questionOrMode: string | undefined,\n options: AdvisorOptions,\n): Promise<void> {\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (!apiKey) {\n output.error('ANTHROPIC_API_KEY environment variable is required');\n output.detail('Set it in your .env file or shell environment');\n process.exit(1);\n }\n\n const spin = output.spinner('Loading project context...');\n const context = await buildContext(projectDir, options);\n spin.stop();\n\n // Print startup banner\n console.log('');\n output.header('dbt advisor');\n if (context.dbt.projectPath) {\n output.detail(\n `dbt project: ${context.dbt.projectName} at ${context.dbt.projectPath}`,\n );\n output.detail(\n `dbt models: ${context.dbt.models.length} (layers: ${context.dbt.conventions.folderStructure.join(', ') || 'none'})`,\n );\n } else {\n output.warning(\n 'No dbt project found. Run `yamchart sync-dbt --path <dbt-project>` to connect one.',\n );\n }\n output.detail(\n `yamchart: ${context.yamchart.models.length} models, ${context.yamchart.charts.length} charts, ${context.yamchart.dashboards.length} dashboards`,\n );\n output.detail(`catalog: ${context.yamchart.catalog ? 'loaded' : 'not synced'}`);\n output.detail(\n `warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : 'not connected'}`,\n );\n console.log('');\n\n // Create agent\n const { AdvisorAgent, AnthropicProvider, buildModelPath } = await import(\n '@yamchart/advisor'\n );\n const provider = new AnthropicProvider(apiKey);\n const agent = new AdvisorAgent(provider);\n\n const isAudit = questionOrMode === 'audit';\n\n if (isAudit) {\n // One-shot audit mode\n const top = options.top ?? 5;\n const auditPrompt = `Run a comprehensive audit of this project. Return your top ${top} suggestions ranked by impact. For each, call propose_model with the full SQL.`;\n\n const auditSpin = output.spinner('Running audit...');\n const result = await agent.run(context, [\n { role: 'user', content: auditPrompt },\n ]);\n auditSpin.stop();\n\n if (options.json) {\n console.log(\n JSON.stringify(\n { text: result.response, proposals: result.proposals },\n null,\n 2,\n ),\n );\n return;\n }\n\n console.log(result.response);\n\n if (result.proposals.length > 0) {\n console.log('');\n output.header(`${result.proposals.length} suggestion(s):`);\n\n for (let i = 0; i < result.proposals.length; i++) {\n const proposal = result.proposals[i]!;\n console.log(\n `\\n${pc.bold(`[${i + 1}]`)} ${formatProposal(proposal, context.dbt.conventions, buildModelPath)}`,\n );\n }\n\n // Offer to apply\n await offerApply(context, result.proposals);\n }\n return;\n }\n\n // Interactive mode\n if (questionOrMode) {\n // Single question mode\n const spin2 = output.spinner('Thinking...');\n const result = await agent.run(context, [\n { role: 'user', content: questionOrMode },\n ]);\n spin2.stop();\n\n console.log(result.response);\n\n if (result.proposals.length > 0) {\n const { buildModelPath: bmp } = await import('@yamchart/advisor');\n for (const proposal of result.proposals) {\n console.log(\n `\\n${formatProposal(proposal, context.dbt.conventions, bmp)}`,\n );\n }\n await offerApply(context, result.proposals);\n }\n return;\n }\n\n // Multi-turn interactive mode\n console.log(\n pc.dim(\n ' Ask me anything, or type \"audit\" for a full analysis. Type \"exit\" to quit.\\n',\n ),\n );\n\n const conversationHistory: Message[] = [];\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n const prompt = (): Promise<string> =>\n new Promise((resolve) => rl.question(pc.green('> '), resolve));\n\n while (true) {\n const userInput = await prompt();\n if (!userInput.trim()) continue;\n if (userInput.trim().toLowerCase() === 'exit') {\n rl.close();\n break;\n }\n\n if (userInput.trim().toLowerCase() === 'audit') {\n conversationHistory.push({\n role: 'user',\n content: `Run a comprehensive audit. Return your top ${options.top ?? 5} suggestions ranked by impact.`,\n });\n } else {\n conversationHistory.push({ role: 'user', content: userInput });\n }\n\n const spin3 = output.spinner('Thinking...');\n const result = await agent.run(context, conversationHistory);\n spin3.stop();\n\n console.log('\\n' + result.response);\n\n // Update conversation history with the full exchange\n conversationHistory.length = 0;\n conversationHistory.push(...result.messages);\n\n if (result.proposals.length > 0) {\n const { buildModelPath: bmp } = await import('@yamchart/advisor');\n for (const proposal of result.proposals) {\n console.log(\n `\\n${formatProposal(proposal, context.dbt.conventions, bmp)}`,\n );\n }\n await offerApply(context, result.proposals);\n }\n\n console.log('');\n }\n}\n\nasync function offerApply(\n context: AdvisorContext,\n proposals: Proposal[],\n): Promise<void> {\n if (!context.dbt.projectPath) {\n output.warning('No dbt project path configured \\u2014 cannot write files');\n return;\n }\n\n const { confirm } = await import('@inquirer/prompts');\n const { writeDbtModel, buildModelPath, formatModelSql, updateSchemaYml } =\n await import('@yamchart/advisor');\n\n for (const proposal of proposals) {\n console.log('');\n const shouldApply = await confirm({\n message: `Apply ${proposal.name} to dbt project?`,\n default: false,\n });\n\n if (!shouldApply) continue;\n\n const modelPath = buildModelPath(\n proposal.name,\n proposal.layer,\n context.dbt.conventions,\n proposal.subfolder,\n );\n\n const sql = formatModelSql({\n materialization: proposal.materialization,\n sql: proposal.sql,\n });\n\n await writeDbtModel(context.dbt.projectPath, modelPath, sql);\n output.success(`Created ${modelPath}`);\n\n // Update schema.yml\n const schemaDir = modelPath.split('/').slice(0, -1).join('/');\n const schemaPath = `${schemaDir}/schema.yml`;\n\n try {\n await updateSchemaYml(context.dbt.projectPath, schemaPath, {\n name: proposal.name,\n description: proposal.description,\n columns: proposal.columns,\n });\n output.success(`Updated ${schemaPath}`);\n } catch (err) {\n output.warning(\n `Could not update schema.yml: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -241,10 +241,86 @@ function getSearchQuery(type, keyword) {
241
241
  throw new Error(`Unsupported database type: ${type}`);
242
242
  }
243
243
  }
244
+ function getColumnsQuery(type, options) {
245
+ switch (type) {
246
+ case "duckdb":
247
+ case "postgres": {
248
+ const conditions = [
249
+ "table_schema NOT IN ('information_schema', 'pg_catalog')"
250
+ ];
251
+ if (options?.schema) {
252
+ conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);
253
+ }
254
+ const sql = `SELECT table_schema, table_name, column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(" AND ")} ORDER BY table_schema, table_name, ordinal_position`;
255
+ return {
256
+ sql,
257
+ normalize: (rows) => rows.map((row) => ({
258
+ schema: String(row.table_schema),
259
+ table: String(row.table_name),
260
+ name: String(row.column_name),
261
+ type: String(row.data_type),
262
+ nullable: String(row.is_nullable)
263
+ }))
264
+ };
265
+ }
266
+ case "mysql": {
267
+ const conditions = [];
268
+ if (options?.schema) {
269
+ conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);
270
+ }
271
+ let sql = "SELECT table_schema, table_name, column_name, column_type, is_nullable FROM information_schema.columns";
272
+ if (conditions.length > 0) {
273
+ sql += ` WHERE ${conditions.join(" AND ")}`;
274
+ }
275
+ sql += " ORDER BY table_schema, table_name, ordinal_position";
276
+ return {
277
+ sql,
278
+ normalize: (rows) => rows.map((row) => ({
279
+ schema: String(getField(row, "table_schema", "TABLE_SCHEMA")),
280
+ table: String(getField(row, "table_name", "TABLE_NAME")),
281
+ name: String(getField(row, "column_name", "COLUMN_NAME")),
282
+ type: String(getField(row, "column_type", "COLUMN_TYPE")),
283
+ nullable: String(getField(row, "is_nullable", "IS_NULLABLE"))
284
+ }))
285
+ };
286
+ }
287
+ case "snowflake": {
288
+ const conditions = [];
289
+ if (options?.schema) {
290
+ conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);
291
+ }
292
+ if (options?.database) {
293
+ conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);
294
+ }
295
+ let sql = "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS";
296
+ if (conditions.length > 0) {
297
+ sql += ` WHERE ${conditions.join(" AND ")}`;
298
+ }
299
+ sql += " ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION";
300
+ return {
301
+ sql,
302
+ normalize: (rows) => rows.map((row) => ({
303
+ schema: String(row.TABLE_SCHEMA),
304
+ table: String(row.TABLE_NAME),
305
+ name: String(row.COLUMN_NAME),
306
+ type: String(row.DATA_TYPE),
307
+ nullable: String(row.IS_NULLABLE)
308
+ }))
309
+ };
310
+ }
311
+ case "sqlite":
312
+ throw new Error(
313
+ "SQLite does not support bulk column queries. Use getDescribeQuery per table."
314
+ );
315
+ default:
316
+ throw new Error(`Unsupported database type: ${type}`);
317
+ }
318
+ }
244
319
 
245
320
  export {
246
321
  getTablesQuery,
247
322
  getDescribeQuery,
248
- getSearchQuery
323
+ getSearchQuery,
324
+ getColumnsQuery
249
325
  };
250
- //# sourceMappingURL=chunk-ZN3AJM76.js.map
326
+ //# sourceMappingURL=chunk-EHM6AMMA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/introspection.ts"],"sourcesContent":["/**\n * Per-engine SQL generation and result normalization for database introspection.\n *\n * Pure logic — no I/O, no connectors. Generates SQL strings and provides\n * normalize functions to transform raw query results into consistent shapes.\n */\n\nexport interface NormalizedTable {\n schema: string;\n name: string;\n type: string;\n}\n\nexport interface NormalizedColumn {\n name: string;\n type: string;\n nullable: string;\n}\n\nexport interface SearchResult {\n type: 'table' | 'column';\n schema: string;\n table: string;\n column?: string;\n columnType?: string;\n}\n\nexport interface TablesQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedTable[];\n}\n\nexport interface DescribeQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedColumn[];\n}\n\nexport interface SearchQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => SearchResult[];\n}\n\nexport interface NormalizedColumnWithTable {\n schema: string;\n table: string;\n name: string;\n type: string;\n nullable: string;\n}\n\nexport interface ColumnsQuery {\n sql: string;\n normalize: (rows: Record<string, unknown>[]) => NormalizedColumnWithTable[];\n}\n\n/**\n * Escape a SQL string literal value by doubling single quotes.\n */\nfunction escapeSqlValue(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\n/**\n * Normalize table_type values: 'BASE TABLE' -> 'TABLE', everything else uppercased.\n */\nfunction normalizeTableType(tableType: string): string {\n const upper = tableType.toUpperCase();\n if (upper === 'BASE TABLE') return 'TABLE';\n return upper;\n}\n\n/**\n * Helper to read a property from a row, trying lowercase first then uppercase.\n * MySQL drivers may return column names in either case.\n */\nfunction getField(row: Record<string, unknown>, lowercase: string, uppercase: string): unknown {\n if (lowercase in row) return row[lowercase];\n if (uppercase in row) return row[uppercase];\n return undefined;\n}\n\n/**\n * Generate a SQL query to list tables/views and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n */\nexport function getTablesQuery(\n type: string,\n options?: { schema?: string; database?: string },\n): TablesQuery {\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const conditions = [\n \"table_schema NOT IN ('information_schema', 'pg_catalog')\",\n ];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n const sql = `SELECT table_schema, table_name, table_type FROM information_schema.tables WHERE ${conditions.join(' AND ')}`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n name: String(row.table_name),\n type: normalizeTableType(String(row.table_type)),\n })),\n };\n }\n\n case 'mysql': {\n let sql = 'SELECT table_schema, table_name, table_type FROM information_schema.tables';\n if (options?.schema) {\n sql += ` WHERE table_schema = '${escapeSqlValue(options.schema)}'`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n name: String(getField(row, 'table_name', 'TABLE_NAME')),\n type: normalizeTableType(String(getField(row, 'table_type', 'TABLE_TYPE'))),\n })),\n };\n }\n\n case 'snowflake': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);\n }\n if (options?.database) {\n conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);\n }\n let sql = 'SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.TABLE_SCHEMA),\n name: String(row.TABLE_NAME),\n type: normalizeTableType(String(row.TABLE_TYPE)),\n })),\n };\n }\n\n case 'sqlite': {\n const sql = \"SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'\";\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: '',\n name: String(row.name),\n type: String(row.type).toUpperCase(),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to describe a table's columns and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n * Accepts schema-qualified names (e.g. 'public.orders', 'ANALYTICS.PUBLIC.ORDERS').\n */\nexport function getDescribeQuery(type: string, table: string): DescribeQuery {\n switch (type) {\n case 'duckdb': {\n return {\n sql: `DESCRIBE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.column_type),\n nullable: String(row.null),\n })),\n };\n }\n\n case 'postgres': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n case 'mysql': {\n const parts = table.split('.');\n const tableName = parts.length > 1 ? parts[parts.length - 1]! : table;\n const schemaName = parts.length > 1 ? parts[0]! : null;\n\n const conditions = [`table_name = '${escapeSqlValue(tableName)}'`];\n if (schemaName) {\n conditions.push(`table_schema = '${escapeSqlValue(schemaName)}'`);\n }\n\n const sql = `SELECT column_name, column_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(getField(row, 'column_name', 'COLUMN_NAME')),\n type: String(getField(row, 'column_type', 'COLUMN_TYPE')),\n nullable: String(getField(row, 'is_nullable', 'IS_NULLABLE')),\n })),\n };\n }\n\n case 'snowflake': {\n return {\n sql: `DESCRIBE TABLE ${table}`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: String(row['null?']) === 'Y' ? 'YES' : 'NO',\n })),\n };\n }\n\n case 'sqlite': {\n return {\n sql: `PRAGMA table_info(${table})`,\n normalize: (rows) =>\n rows.map((row) => ({\n name: String(row.name),\n type: String(row.type),\n nullable: Number(row.notnull) === 1 ? 'NO' : 'YES',\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to search for tables and columns matching a keyword.\n *\n * Supported types: duckdb, postgres, mysql, snowflake, sqlite.\n */\nexport function getSearchQuery(type: string, keyword: string): SearchQuery {\n const escaped = escapeSqlValue(keyword);\n\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const sql = [\n `SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,\n `FROM information_schema.tables`,\n `WHERE table_schema NOT IN ('information_schema', 'pg_catalog')`,\n `AND table_name ILIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,\n `FROM information_schema.columns`,\n `WHERE table_schema NOT IN ('information_schema', 'pg_catalog')`,\n `AND column_name ILIKE '%${escaped}%'`,\n `ORDER BY match_type, table_schema, table_name`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(row.match_type) as 'table' | 'column',\n schema: String(row.table_schema),\n table: String(row.table_name),\n ...(row.column_name ? { column: String(row.column_name) } : {}),\n ...(row.data_type ? { columnType: String(row.data_type) } : {}),\n })),\n };\n }\n\n case 'mysql': {\n const sql = [\n `SELECT 'table' AS match_type, table_schema, table_name, NULL AS column_name, NULL AS data_type`,\n `FROM information_schema.tables`,\n `WHERE table_name LIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS match_type, table_schema, table_name, column_name, data_type`,\n `FROM information_schema.columns`,\n `WHERE column_name LIKE '%${escaped}%'`,\n `ORDER BY match_type, table_schema, table_name`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(getField(row, 'match_type', 'MATCH_TYPE')) as 'table' | 'column',\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n table: String(getField(row, 'table_name', 'TABLE_NAME')),\n ...(getField(row, 'column_name', 'COLUMN_NAME')\n ? { column: String(getField(row, 'column_name', 'COLUMN_NAME')) }\n : {}),\n ...(getField(row, 'data_type', 'DATA_TYPE')\n ? { columnType: String(getField(row, 'data_type', 'DATA_TYPE')) }\n : {}),\n })),\n };\n }\n\n case 'snowflake': {\n const sql = [\n `SELECT 'table' AS MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME, NULL AS COLUMN_NAME, NULL AS DATA_TYPE`,\n `FROM INFORMATION_SCHEMA.TABLES`,\n `WHERE TABLE_NAME ILIKE '%${escaped}%'`,\n `UNION ALL`,\n `SELECT 'column' AS MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE`,\n `FROM INFORMATION_SCHEMA.COLUMNS`,\n `WHERE COLUMN_NAME ILIKE '%${escaped}%'`,\n `ORDER BY MATCH_TYPE, TABLE_SCHEMA, TABLE_NAME`,\n ].join(' ');\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: String(row.MATCH_TYPE) as 'table' | 'column',\n schema: String(row.TABLE_SCHEMA),\n table: String(row.TABLE_NAME),\n ...(row.COLUMN_NAME ? { column: String(row.COLUMN_NAME) } : {}),\n ...(row.DATA_TYPE ? { columnType: String(row.DATA_TYPE) } : {}),\n })),\n };\n }\n\n case 'sqlite': {\n const sql = `SELECT name FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' AND name LIKE '%${escaped}%'`;\n\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n type: 'table' as const,\n schema: '',\n table: String(row.name),\n })),\n };\n }\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n\n/**\n * Generate a SQL query to fetch ALL columns across all tables in a single bulk query,\n * and a normalizer for the results.\n *\n * Supported types: duckdb, postgres, mysql, snowflake.\n * SQLite is not supported (no information_schema); use getDescribeQuery per table.\n */\nexport function getColumnsQuery(\n type: string,\n options?: { schema?: string; database?: string },\n): ColumnsQuery {\n switch (type) {\n case 'duckdb':\n case 'postgres': {\n const conditions = [\n \"table_schema NOT IN ('information_schema', 'pg_catalog')\",\n ];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n const sql = `SELECT table_schema, table_name, column_name, data_type, is_nullable FROM information_schema.columns WHERE ${conditions.join(' AND ')} ORDER BY table_schema, table_name, ordinal_position`;\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.table_schema),\n table: String(row.table_name),\n name: String(row.column_name),\n type: String(row.data_type),\n nullable: String(row.is_nullable),\n })),\n };\n }\n\n case 'mysql': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`table_schema = '${escapeSqlValue(options.schema)}'`);\n }\n let sql = 'SELECT table_schema, table_name, column_name, column_type, is_nullable FROM information_schema.columns';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n sql += ' ORDER BY table_schema, table_name, ordinal_position';\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(getField(row, 'table_schema', 'TABLE_SCHEMA')),\n table: String(getField(row, 'table_name', 'TABLE_NAME')),\n name: String(getField(row, 'column_name', 'COLUMN_NAME')),\n type: String(getField(row, 'column_type', 'COLUMN_TYPE')),\n nullable: String(getField(row, 'is_nullable', 'IS_NULLABLE')),\n })),\n };\n }\n\n case 'snowflake': {\n const conditions: string[] = [];\n if (options?.schema) {\n conditions.push(`TABLE_SCHEMA = '${escapeSqlValue(options.schema)}'`);\n }\n if (options?.database) {\n conditions.push(`TABLE_CATALOG = '${escapeSqlValue(options.database)}'`);\n }\n let sql = 'SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS';\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`;\n }\n sql += ' ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION';\n return {\n sql,\n normalize: (rows) =>\n rows.map((row) => ({\n schema: String(row.TABLE_SCHEMA),\n table: String(row.TABLE_NAME),\n name: String(row.COLUMN_NAME),\n type: String(row.DATA_TYPE),\n nullable: String(row.IS_NULLABLE),\n })),\n };\n }\n\n case 'sqlite':\n throw new Error(\n 'SQLite does not support bulk column queries. Use getDescribeQuery per table.',\n );\n\n default:\n throw new Error(`Unsupported database type: ${type}`);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,125 @@
1
+ // src/dbt/catalog.ts
2
+ function generateCatalogMd(data) {
3
+ const lines = [];
4
+ lines.push("# Data Catalog");
5
+ lines.push("");
6
+ lines.push(`> Source: ${data.source.type}:${data.source.path || data.source.repo || "unknown"}`);
7
+ lines.push(`> Last synced: ${data.syncedAt.split("T")[0]}`);
8
+ lines.push(`> Models: ${data.stats.modelsIncluded} included, ${data.stats.modelsExcluded} filtered out`);
9
+ lines.push("");
10
+ lines.push("---");
11
+ lines.push("");
12
+ lines.push("## Models");
13
+ lines.push("");
14
+ const dbtModels = data.models.filter((m) => m.source !== "warehouse" && m.source !== "dbt-source");
15
+ for (const model of dbtModels) {
16
+ lines.push(`### ${model.name}`);
17
+ lines.push("");
18
+ lines.push(model.description);
19
+ lines.push("");
20
+ if (model.table) {
21
+ lines.push(`**Table:** \`${model.table}\``);
22
+ }
23
+ if (model.tags.length > 0) {
24
+ lines.push(`**Tags:** ${model.tags.map((t) => `\`${t}\``).join(", ")}`);
25
+ }
26
+ if (model.dependsOn?.length) {
27
+ const deps = model.dependsOn.map((d) => {
28
+ const parts = d.split(".");
29
+ if (parts[0] === "source") {
30
+ return `source:${parts.slice(2).join(".")}`;
31
+ }
32
+ return parts[parts.length - 1];
33
+ });
34
+ lines.push(`**Depends on:** ${deps.join(", ")}`);
35
+ }
36
+ lines.push("");
37
+ if (model.columns.length > 0) {
38
+ lines.push("| Column | Type | Description | Hints |");
39
+ lines.push("|--------|------|-------------|-------|");
40
+ for (const col of model.columns) {
41
+ const type = col.data_type || "";
42
+ const hints = col.hints.join(", ");
43
+ lines.push(`| ${col.name} | ${type} | ${col.description} | ${hints} |`);
44
+ }
45
+ lines.push("");
46
+ }
47
+ lines.push("**Yamchart models:**");
48
+ if (model.yamchartModels.length > 0) {
49
+ for (const ym of model.yamchartModels) {
50
+ lines.push(`- [\`${ym.name}\`](../${ym.path}) - ${ym.description || "No description"}`);
51
+ }
52
+ } else {
53
+ lines.push("None yet");
54
+ }
55
+ lines.push("");
56
+ lines.push("---");
57
+ lines.push("");
58
+ }
59
+ const dbtSources = data.models.filter((m) => m.source === "dbt-source");
60
+ if (dbtSources.length > 0) {
61
+ lines.push("## Sources");
62
+ lines.push("");
63
+ lines.push("| Source | Table | Columns |");
64
+ lines.push("|--------|-------|---------|");
65
+ for (const src of dbtSources) {
66
+ lines.push(`| ${src.name} | \`${src.table || ""}\` | ${src.columns.length} |`);
67
+ }
68
+ lines.push("");
69
+ }
70
+ return lines.join("\n");
71
+ }
72
+ function generateCatalogJson(data) {
73
+ return JSON.stringify(data, null, 2);
74
+ }
75
+ var MAX_TABLES_PER_ROW = 5;
76
+ function generateWarehouseSection(models, connectionName, syncDate) {
77
+ const warehouseModels = models.filter((m) => m.source === "warehouse");
78
+ if (warehouseModels.length === 0) return "";
79
+ const schemaGroups = /* @__PURE__ */ new Map();
80
+ for (const model of warehouseModels) {
81
+ const table = model.table || model.name;
82
+ const dotIndex = table.lastIndexOf(".");
83
+ let schema;
84
+ let tableName;
85
+ if (dotIndex >= 0) {
86
+ schema = table.substring(0, dotIndex);
87
+ tableName = table.substring(dotIndex + 1);
88
+ } else {
89
+ schema = "(default)";
90
+ tableName = table;
91
+ }
92
+ const existing = schemaGroups.get(schema);
93
+ if (existing) {
94
+ existing.push(tableName);
95
+ } else {
96
+ schemaGroups.set(schema, [tableName]);
97
+ }
98
+ }
99
+ const lines = [];
100
+ lines.push("## Warehouse Tables");
101
+ lines.push("");
102
+ lines.push(`> ${warehouseModels.length} tables synced from ${connectionName} on ${syncDate}`);
103
+ lines.push("");
104
+ lines.push("| Schema | Tables |");
105
+ lines.push("|--------|--------|");
106
+ for (const [schema, tables] of schemaGroups) {
107
+ let tableList;
108
+ if (tables.length <= MAX_TABLES_PER_ROW) {
109
+ tableList = tables.join(", ");
110
+ } else {
111
+ const shown = tables.slice(0, MAX_TABLES_PER_ROW).join(", ");
112
+ tableList = `${shown} (+${tables.length - MAX_TABLES_PER_ROW} more)`;
113
+ }
114
+ lines.push(`| ${schema} | ${tableList} |`);
115
+ }
116
+ lines.push("");
117
+ return lines.join("\n");
118
+ }
119
+
120
+ export {
121
+ generateCatalogMd,
122
+ generateCatalogJson,
123
+ generateWarehouseSection
124
+ };
125
+ //# sourceMappingURL=chunk-WYS4ULBE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dbt/catalog.ts"],"sourcesContent":["import type { DbtModel, DbtColumn } from './types.js';\nimport type { YamchartModel } from './scanner.js';\n\nexport interface CatalogModel extends DbtModel {\n yamchartModels: YamchartModel[];\n}\n\nexport interface CatalogData {\n syncedAt: string;\n source: { type: string; path?: string; repo?: string };\n stats: { modelsIncluded: number; modelsExcluded: number };\n models: CatalogModel[];\n}\n\n/**\n * Generate catalog.md content.\n */\nexport function generateCatalogMd(data: CatalogData): string {\n const lines: string[] = [];\n\n // Header\n lines.push('# Data Catalog');\n lines.push('');\n lines.push(`> Source: ${data.source.type}:${data.source.path || data.source.repo || 'unknown'}`);\n lines.push(`> Last synced: ${data.syncedAt.split('T')[0]}`);\n lines.push(`> Models: ${data.stats.modelsIncluded} included, ${data.stats.modelsExcluded} filtered out`);\n lines.push('');\n lines.push('---');\n lines.push('');\n lines.push('## Models');\n lines.push('');\n\n // Only render non-warehouse, non-source models in the Models section\n const dbtModels = data.models.filter((m) => m.source !== 'warehouse' && m.source !== 'dbt-source');\n\n // Each model\n for (const model of dbtModels) {\n lines.push(`### ${model.name}`);\n lines.push('');\n lines.push(model.description);\n lines.push('');\n\n if (model.table) {\n lines.push(`**Table:** \\`${model.table}\\``);\n }\n\n if (model.tags.length > 0) {\n lines.push(`**Tags:** ${model.tags.map(t => `\\`${t}\\``).join(', ')}`);\n }\n\n if (model.dependsOn?.length) {\n const deps = model.dependsOn.map((d) => {\n const parts = d.split('.');\n if (parts[0] === 'source') {\n return `source:${parts.slice(2).join('.')}`;\n }\n return parts[parts.length - 1];\n });\n lines.push(`**Depends on:** ${deps.join(', ')}`);\n }\n\n lines.push('');\n\n // Column table\n if (model.columns.length > 0) {\n lines.push('| Column | Type | Description | Hints |');\n lines.push('|--------|------|-------------|-------|');\n\n for (const col of model.columns) {\n const type = col.data_type || '';\n const hints = col.hints.join(', ');\n lines.push(`| ${col.name} | ${type} | ${col.description} | ${hints} |`);\n }\n\n lines.push('');\n }\n\n // Yamchart models using this\n lines.push('**Yamchart models:**');\n if (model.yamchartModels.length > 0) {\n for (const ym of model.yamchartModels) {\n lines.push(`- [\\`${ym.name}\\`](../${ym.path}) - ${ym.description || 'No description'}`);\n }\n } else {\n lines.push('None yet');\n }\n\n lines.push('');\n lines.push('---');\n lines.push('');\n }\n\n // Render dbt sources in a compact table\n const dbtSources = data.models.filter((m) => m.source === 'dbt-source');\n if (dbtSources.length > 0) {\n lines.push('## Sources');\n lines.push('');\n lines.push('| Source | Table | Columns |');\n lines.push('|--------|-------|---------|');\n for (const src of dbtSources) {\n lines.push(`| ${src.name} | \\`${src.table || ''}\\` | ${src.columns.length} |`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Generate catalog.json content.\n */\nexport function generateCatalogJson(data: CatalogData): string {\n return JSON.stringify(data, null, 2);\n}\n\nconst MAX_TABLES_PER_ROW = 5;\n\n/**\n * Render a compact grouped index of warehouse tables for catalog.md.\n * Designed for LLM token efficiency: ~500 tokens regardless of warehouse size.\n */\nexport function generateWarehouseSection(\n models: CatalogModel[],\n connectionName: string,\n syncDate: string,\n): string {\n const warehouseModels = models.filter(m => m.source === 'warehouse');\n if (warehouseModels.length === 0) return '';\n\n // Group tables by schema\n const schemaGroups = new Map<string, string[]>();\n for (const model of warehouseModels) {\n const table = model.table || model.name;\n const dotIndex = table.lastIndexOf('.');\n let schema: string;\n let tableName: string;\n if (dotIndex >= 0) {\n schema = table.substring(0, dotIndex);\n tableName = table.substring(dotIndex + 1);\n } else {\n schema = '(default)';\n tableName = table;\n }\n const existing = schemaGroups.get(schema);\n if (existing) {\n existing.push(tableName);\n } else {\n schemaGroups.set(schema, [tableName]);\n }\n }\n\n const lines: string[] = [];\n lines.push('## Warehouse Tables');\n lines.push('');\n lines.push(`> ${warehouseModels.length} tables synced from ${connectionName} on ${syncDate}`);\n lines.push('');\n lines.push('| Schema | Tables |');\n lines.push('|--------|--------|');\n\n for (const [schema, tables] of schemaGroups) {\n let tableList: string;\n if (tables.length <= MAX_TABLES_PER_ROW) {\n tableList = tables.join(', ');\n } else {\n const shown = tables.slice(0, MAX_TABLES_PER_ROW).join(', ');\n tableList = `${shown} (+${tables.length - MAX_TABLES_PER_ROW} more)`;\n }\n lines.push(`| ${schema} | ${tableList} |`);\n }\n\n lines.push('');\n return lines.join('\\n');\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDescribeQuery
3
- } from "./chunk-ZN3AJM76.js";
3
+ } from "./chunk-EHM6AMMA.js";
4
4
  import {
5
5
  resolveTableName
6
6
  } from "./chunk-VJC24RKT.js";
@@ -40,4 +40,4 @@ async function describeTable(projectDir, table, options) {
40
40
  export {
41
41
  describeTable
42
42
  };
43
- //# sourceMappingURL=describe-Y4VD4JQX.js.map
43
+ //# sourceMappingURL=describe-HD2RJQX3.js.map
@@ -13608,7 +13608,7 @@ async function chatRoutes(fastify, options) {
13608
13608
  systemParts.push("Output ONLY the new text to insert. Do NOT repeat the existing content.");
13609
13609
  }
13610
13610
  const systemPrompt = systemParts.join("\n");
13611
- const { AnthropicProvider } = await import("./dist-ZRRM3OWF.js");
13611
+ const { AnthropicProvider } = await import("./dist-D5NLPC5X.js");
13612
13612
  const provider = new AnthropicProvider(apiKey);
13613
13613
  const response = await provider.chat({
13614
13614
  system: systemPrompt,
@@ -13748,9 +13748,25 @@ async function createServer(options) {
13748
13748
  version: VERSION,
13749
13749
  project: configLoader.getProject().name,
13750
13750
  environment: process.env.NODE_ENV || "development",
13751
- connection: currentConnection ? buildConnectionInfo(currentConnection) : void 0
13751
+ connection: currentConnection ? buildConnectionInfo(currentConnection) : void 0,
13752
+ connectionStatus: connector.isConnected() ? "connected" : "disconnected",
13753
+ authType: defaultConnection.type === "snowflake" && defaultConnection.auth ? defaultConnection.auth.type : void 0
13752
13754
  };
13753
13755
  });
13756
+ fastify.post("/api/connections/reconnect", async (_request2, reply) => {
13757
+ try {
13758
+ try {
13759
+ await connector.disconnect();
13760
+ } catch {
13761
+ }
13762
+ await connector.connect();
13763
+ return { success: true };
13764
+ } catch (err) {
13765
+ return reply.status(500).send({
13766
+ error: err instanceof Error ? err.message : "Reconnection failed"
13767
+ });
13768
+ }
13769
+ });
13754
13770
  if (authDb) {
13755
13771
  const secureCookies = process.env.NODE_ENV === "production";
13756
13772
  const sessionTtlMs = options.localAuth.sessionTtlMs;
@@ -14007,4 +14023,4 @@ async function runDevServer(projectDir, options) {
14007
14023
  export {
14008
14024
  runDevServer
14009
14025
  };
14010
- //# sourceMappingURL=dev-7SWSX2X7.js.map
14026
+ //# sourceMappingURL=dev-LCYHM7UA.js.map