yamchart 0.7.2 → 0.8.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/CLAUDE.md +51 -0
- package/dist/{advisor-5BTRAICH.js → advisor-57BOMUUF.js} +11 -10
- package/dist/{advisor-5BTRAICH.js.map → advisor-57BOMUUF.js.map} +1 -1
- package/dist/{chunk-5VA43CTW.js → chunk-E2UZXDF6.js} +37 -42
- package/dist/chunk-E2UZXDF6.js.map +1 -0
- package/dist/{chunk-SSUVEADJ.js → chunk-JYQKDWLG.js} +76 -14
- package/dist/chunk-JYQKDWLG.js.map +1 -0
- package/dist/{chunk-565OEBW7.js → chunk-OTAUP5RC.js} +3 -3
- package/dist/chunk-UND73EOB.js +449 -0
- package/dist/chunk-UND73EOB.js.map +1 -0
- package/dist/{chunk-UDRJFEJU.js → chunk-X6LQGWUX.js} +349 -176
- package/dist/chunk-X6LQGWUX.js.map +1 -0
- package/dist/{connection-utils-AGSQ5HNN.js → connection-utils-FTSZU2VF.js} +5 -4
- package/dist/{describe-AA4UT4U6.js → describe-TGIOBNJB.js} +5 -4
- package/dist/{describe-AA4UT4U6.js.map → describe-TGIOBNJB.js.map} +1 -1
- package/dist/{dev-EUWIRL4N.js → dev-MRZ76V74.js} +485 -44
- package/dist/dev-MRZ76V74.js.map +1 -0
- package/dist/{dist-LZNDQDH3.js → dist-PVHFUYP2.js} +23 -3
- package/dist/{dist-YTGUIBKG.js → dist-WDTDQDTX.js} +72 -1
- package/dist/dist-WDTDQDTX.js.map +1 -0
- package/dist/index.js +135 -17
- package/dist/index.js.map +1 -1
- package/dist/{init-CI4VARQG.js → init-UYQE5DPU.js} +2 -2
- package/dist/{init-CI4VARQG.js.map → init-UYQE5DPU.js.map} +1 -1
- package/dist/public/assets/EventManagement-BlxJ2TFw.js +18 -0
- package/dist/public/assets/{LoginPage-BwMmpq8e.js → LoginPage-BT8ikmPn.js} +1 -1
- package/dist/public/assets/PublicViewer-B4uFxgbt.js +1 -0
- package/dist/public/assets/{SetupWizard-DU8R2dPp.js → SetupWizard-njrOhCzw.js} +1 -1
- package/dist/public/assets/ShareManagement-Bg16oJhW.js +1 -0
- package/dist/public/assets/UserManagement-tiCIT4UY.js +1 -0
- package/dist/public/assets/index-B41yj3io.js +187 -0
- package/dist/public/assets/{index-C0hWblBI.css → index-BZ25r23j.css} +1 -1
- package/dist/public/assets/{index.es-YeJujQ5o.js → index.es-BuktD_R2.js} +1 -1
- package/dist/public/assets/{jspdf.es.min-BzZgn3ka.js → jspdf.es.min-DFRl2hZQ.js} +3 -3
- package/dist/public/index.html +2 -2
- package/dist/{query-THDVBBVZ.js → query-JRMMNXX6.js} +5 -4
- package/dist/{query-THDVBBVZ.js.map → query-JRMMNXX6.js.map} +1 -1
- package/dist/{sample-6WPQS7PA.js → sample-VGIY4U4J.js} +5 -4
- package/dist/{sample-6WPQS7PA.js.map → sample-VGIY4U4J.js.map} +1 -1
- package/dist/{search-657DXBRS.js → search-QSYNG4SR.js} +5 -4
- package/dist/{search-657DXBRS.js.map → search-QSYNG4SR.js.map} +1 -1
- package/dist/semantic-RAP3S5PQ.js +39 -0
- package/dist/semantic-RAP3S5PQ.js.map +1 -0
- package/dist/{sync-warehouse-4KBV5S3L.js → sync-warehouse-XHTBZH25.js} +5 -4
- package/dist/{sync-warehouse-4KBV5S3L.js.map → sync-warehouse-XHTBZH25.js.map} +1 -1
- package/dist/{tables-KLDBUUSE.js → tables-UOO342TA.js} +5 -4
- package/dist/{tables-KLDBUUSE.js.map → tables-UOO342TA.js.map} +1 -1
- package/dist/templates/default/.claude/skills/databricks/SKILL.md +76 -0
- package/dist/templates/default/.claude/skills/dbt-advisor/SKILL.md +107 -0
- package/dist/templates/default/.claude/skills/duckdb/SKILL.md +67 -0
- package/dist/templates/default/.claude/skills/mysql/SKILL.md +69 -0
- package/dist/templates/default/.claude/skills/postgres/SKILL.md +69 -0
- package/dist/templates/default/.claude/skills/snowflake/SKILL.md +64 -0
- package/dist/templates/default/CLAUDE.md +7 -0
- package/dist/templates/default/docs/yamchart-reference.md +222 -1
- package/dist/{test-JSAWS5ZP.js → test-TXRZWNXK.js} +5 -4
- package/dist/{test-JSAWS5ZP.js.map → test-TXRZWNXK.js.map} +1 -1
- package/dist/update-UKMEWCSO.js +220 -0
- package/dist/update-UKMEWCSO.js.map +1 -0
- package/package.json +5 -3
- package/dist/chunk-5VA43CTW.js.map +0 -1
- package/dist/chunk-SSUVEADJ.js.map +0 -1
- package/dist/chunk-UDRJFEJU.js.map +0 -1
- package/dist/dev-EUWIRL4N.js.map +0 -1
- package/dist/dist-YTGUIBKG.js.map +0 -1
- package/dist/public/assets/PublicViewer-vIDojjIR.js +0 -1
- package/dist/public/assets/ShareManagement-7iS6lM2T.js +0 -1
- package/dist/public/assets/UserManagement-By7YRZrF.js +0 -1
- package/dist/public/assets/index-CXx1PiRF.js +0 -174
- package/dist/update-HCR6MYJX.js +0 -88
- package/dist/update-HCR6MYJX.js.map +0 -1
- /package/dist/{chunk-565OEBW7.js.map → chunk-OTAUP5RC.js.map} +0 -0
- /package/dist/{connection-utils-AGSQ5HNN.js.map → connection-utils-FTSZU2VF.js.map} +0 -0
- /package/dist/{dist-LZNDQDH3.js.map → dist-PVHFUYP2.js.map} +0 -0
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
QueryCompiler,
|
|
7
7
|
SQLiteConnector,
|
|
8
8
|
SnowflakeConnector,
|
|
9
|
+
SqlList,
|
|
9
10
|
VERSION,
|
|
10
11
|
checkSchema,
|
|
11
12
|
computePreviousPeriod,
|
|
@@ -27,8 +28,18 @@ import {
|
|
|
27
28
|
runAll,
|
|
28
29
|
runAssertion,
|
|
29
30
|
runModel,
|
|
31
|
+
serializeDateValue,
|
|
30
32
|
templateHasVariable
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-JYQKDWLG.js";
|
|
34
|
+
import {
|
|
35
|
+
SemanticModelBuilder,
|
|
36
|
+
SemanticQueryCompiler,
|
|
37
|
+
SemanticValidationError,
|
|
38
|
+
classifyCatalogColumns,
|
|
39
|
+
classifyField,
|
|
40
|
+
inferAggregationType,
|
|
41
|
+
validateSemanticQuery
|
|
42
|
+
} from "./chunk-UND73EOB.js";
|
|
32
43
|
import "./chunk-DGUM43GV.js";
|
|
33
44
|
export {
|
|
34
45
|
DATE_PRESETS,
|
|
@@ -37,9 +48,15 @@ export {
|
|
|
37
48
|
PostgresConnector,
|
|
38
49
|
QueryCompiler,
|
|
39
50
|
SQLiteConnector,
|
|
51
|
+
SemanticModelBuilder,
|
|
52
|
+
SemanticQueryCompiler,
|
|
53
|
+
SemanticValidationError,
|
|
40
54
|
SnowflakeConnector,
|
|
55
|
+
SqlList,
|
|
41
56
|
VERSION,
|
|
42
57
|
checkSchema,
|
|
58
|
+
classifyCatalogColumns,
|
|
59
|
+
classifyField,
|
|
43
60
|
computePreviousPeriod,
|
|
44
61
|
createTemplateContext,
|
|
45
62
|
expandCustomDateRange,
|
|
@@ -48,6 +65,7 @@ export {
|
|
|
48
65
|
expandThis,
|
|
49
66
|
extractTemplateVariables,
|
|
50
67
|
formatPeriodLabel,
|
|
68
|
+
inferAggregationType,
|
|
51
69
|
isCustomDateRange,
|
|
52
70
|
isDatePreset,
|
|
53
71
|
isRelativeDateRange,
|
|
@@ -59,6 +77,8 @@ export {
|
|
|
59
77
|
runAll,
|
|
60
78
|
runAssertion,
|
|
61
79
|
runModel,
|
|
62
|
-
|
|
80
|
+
serializeDateValue,
|
|
81
|
+
templateHasVariable,
|
|
82
|
+
validateSemanticQuery
|
|
63
83
|
};
|
|
64
|
-
//# sourceMappingURL=dist-
|
|
84
|
+
//# sourceMappingURL=dist-PVHFUYP2.js.map
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import "./chunk-JYQKDWLG.js";
|
|
2
|
+
import {
|
|
3
|
+
SemanticModelBuilder,
|
|
4
|
+
SemanticQueryCompiler
|
|
5
|
+
} from "./chunk-UND73EOB.js";
|
|
1
6
|
import "./chunk-DGUM43GV.js";
|
|
2
7
|
|
|
3
8
|
// ../../packages/advisor/dist/dbt/knowledge.js
|
|
@@ -251,6 +256,38 @@ var TOOL_DEFINITIONS = [
|
|
|
251
256
|
required: ["topic"]
|
|
252
257
|
}
|
|
253
258
|
},
|
|
259
|
+
{
|
|
260
|
+
name: "list_semantic_entities",
|
|
261
|
+
description: "List all semantic entities (auto-generated from the catalog) with their measures and dimensions. Use this to understand what data is available for structured queries without writing SQL.",
|
|
262
|
+
parameters: { type: "object", properties: {}, required: [] }
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: "semantic_query",
|
|
266
|
+
description: "Run a structured query against the semantic layer. Specify an entity, measures to aggregate, and optional dimensions to group by. Returns the compiled SQL.",
|
|
267
|
+
parameters: {
|
|
268
|
+
type: "object",
|
|
269
|
+
properties: {
|
|
270
|
+
entity: { type: "string", description: "Entity name (e.g. fct_revenue)" },
|
|
271
|
+
measures: { type: "array", items: { type: "string" }, description: "Measure names to aggregate" },
|
|
272
|
+
dimensions: { type: "array", items: { type: "string" }, description: "Dimension names to group by (optional)" },
|
|
273
|
+
filters: {
|
|
274
|
+
type: "array",
|
|
275
|
+
items: {
|
|
276
|
+
type: "object",
|
|
277
|
+
properties: {
|
|
278
|
+
dimension: { type: "string" },
|
|
279
|
+
operator: { type: "string", description: "equals, not_equals, contains, gt, gte, lt, lte, in, not_in" },
|
|
280
|
+
value: { description: "Filter value (string, number, or array for in/not_in)" }
|
|
281
|
+
},
|
|
282
|
+
required: ["dimension", "operator", "value"]
|
|
283
|
+
},
|
|
284
|
+
description: "Optional filters"
|
|
285
|
+
},
|
|
286
|
+
limit: { type: "number", description: "Row limit (default: 100)" }
|
|
287
|
+
},
|
|
288
|
+
required: ["entity", "measures"]
|
|
289
|
+
}
|
|
290
|
+
},
|
|
254
291
|
// Action tools
|
|
255
292
|
{
|
|
256
293
|
name: "propose_model",
|
|
@@ -407,6 +444,40 @@ async function executeToolCall(context, toolName, input) {
|
|
|
407
444
|
const topic = input.topic;
|
|
408
445
|
return loadKnowledge(topic);
|
|
409
446
|
}
|
|
447
|
+
case "list_semantic_entities": {
|
|
448
|
+
if (!context.yamchart.catalogJson) {
|
|
449
|
+
return "No catalog available. Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate it.";
|
|
450
|
+
}
|
|
451
|
+
const builder = new SemanticModelBuilder();
|
|
452
|
+
const model = builder.build({ catalog: { models: context.yamchart.catalogJson.models } });
|
|
453
|
+
return JSON.stringify(model.entities.map((e) => ({
|
|
454
|
+
name: e.name,
|
|
455
|
+
source_table: e.source_table,
|
|
456
|
+
description: e.description,
|
|
457
|
+
measures: e.measures.map((m) => ({ name: m.name, type: m.type })),
|
|
458
|
+
dimensions: e.dimensions.map((d) => ({ name: d.name, type: d.type }))
|
|
459
|
+
})));
|
|
460
|
+
}
|
|
461
|
+
case "semantic_query": {
|
|
462
|
+
if (!context.yamchart.catalogJson) {
|
|
463
|
+
return JSON.stringify({ error: "No catalog available. Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate it." });
|
|
464
|
+
}
|
|
465
|
+
try {
|
|
466
|
+
const builder = new SemanticModelBuilder();
|
|
467
|
+
const model = builder.build({ catalog: { models: context.yamchart.catalogJson.models } });
|
|
468
|
+
const compiler = new SemanticQueryCompiler();
|
|
469
|
+
const sql = compiler.compile(model, {
|
|
470
|
+
model: input.entity,
|
|
471
|
+
measures: input.measures || [],
|
|
472
|
+
dimensions: input.dimensions || [],
|
|
473
|
+
filters: input.filters || [],
|
|
474
|
+
limit: input.limit || 100
|
|
475
|
+
});
|
|
476
|
+
return JSON.stringify({ sql, entity: input.entity });
|
|
477
|
+
} catch (err) {
|
|
478
|
+
return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
410
481
|
case "propose_model":
|
|
411
482
|
return JSON.stringify({
|
|
412
483
|
status: "proposed",
|
|
@@ -716,4 +787,4 @@ export {
|
|
|
716
787
|
updateSchemaYml,
|
|
717
788
|
writeDbtModel
|
|
718
789
|
};
|
|
719
|
-
//# sourceMappingURL=dist-
|
|
790
|
+
//# sourceMappingURL=dist-WDTDQDTX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/advisor/src/dbt/knowledge.ts","../../../packages/advisor/src/dbt/project.ts","../../../packages/advisor/src/tools.ts","../../../packages/advisor/src/agent.ts","../../../packages/advisor/src/providers/anthropic.ts","../../../packages/advisor/src/dbt/writer.ts"],"sourcesContent":["import { readFile } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst KNOWLEDGE_DIR = join(__dirname, '..', 'knowledge');\n\nexport const KNOWLEDGE_TOPICS = [\n 'materializations',\n 'incremental',\n 'macros',\n 'testing',\n 'naming',\n 'performance',\n 'sources',\n] as const;\n\nexport type KnowledgeTopic = (typeof KNOWLEDGE_TOPICS)[number];\n\nexport async function loadKnowledge(topic: string): Promise<string> {\n if (!KNOWLEDGE_TOPICS.includes(topic as KnowledgeTopic)) {\n return `Unknown topic: \"${topic}\". Available topics: ${KNOWLEDGE_TOPICS.join(', ')}`;\n }\n\n const filePath = join(KNOWLEDGE_DIR, `${topic}.md`);\n return readFile(filePath, 'utf-8');\n}\n\nexport function getKnowledgeOverview(): string {\n return `You have access to a dbt knowledge base via the get_knowledge tool. Available topics:\n${KNOWLEDGE_TOPICS.map((t) => `- ${t}`).join('\\n')}\n\nUse get_knowledge when you need specifics on materializations, incremental strategies, Jinja macros, testing, naming conventions, or performance optimization.`;\n}\n","import { readFile } from 'fs/promises';\nimport { join, basename, relative, dirname } from 'path';\nimport fg from 'fast-glob';\nimport { parse as parseYaml } from 'yaml';\n\nexport interface DbtConventions {\n folderStructure: string[];\n namingPrefixes: Record<string, string>;\n commonMaterializations: Record<string, string>;\n schemaYmlPattern: 'per-folder' | 'per-model' | 'single-file';\n testPatterns: string[];\n}\n\nexport interface DbtModelInfo {\n name: string;\n path: string;\n layer: string;\n materialization: string;\n folder: string;\n}\n\ninterface DbtProjectYml {\n name: string;\n 'model-paths'?: string[];\n model_paths?: string[];\n}\n\nasync function getModelPaths(projectPath: string): Promise<string[]> {\n const content = await readFile(join(projectPath, 'dbt_project.yml'), 'utf-8');\n const parsed = parseYaml(content) as DbtProjectYml;\n return parsed['model-paths'] ?? parsed.model_paths ?? ['models'];\n}\n\nfunction extractMaterialization(sql: string): string {\n const match = sql.match(/materialized\\s*=\\s*['\"](\\w+)['\"]/);\n return match?.[1] ?? 'view';\n}\n\nfunction detectLayer(relativePath: string): string {\n const parts = relativePath.split('/');\n return parts[0] ?? 'unknown';\n}\n\nfunction detectPrefix(\n models: Array<{ name: string; layer: string }>\n): Record<string, string> {\n const prefixesByLayer = new Map<string, Map<string, number>>();\n\n for (const model of models) {\n const underscoreIdx = model.name.indexOf('_');\n if (underscoreIdx === -1) continue;\n const prefix = model.name.slice(0, underscoreIdx + 1);\n\n if (!prefixesByLayer.has(model.layer)) {\n prefixesByLayer.set(model.layer, new Map());\n }\n const counts = prefixesByLayer.get(model.layer)!;\n counts.set(prefix, (counts.get(prefix) ?? 0) + 1);\n }\n\n const result: Record<string, string> = {};\n for (const [layer, counts] of prefixesByLayer) {\n let maxCount = 0;\n let maxPrefix = '';\n for (const [prefix, count] of counts) {\n if (count > maxCount) {\n maxCount = count;\n maxPrefix = prefix;\n }\n }\n if (maxPrefix && maxCount >= 2) {\n result[layer] = maxPrefix;\n }\n }\n\n return result;\n}\n\nfunction detectMaterializations(\n models: Array<{ layer: string; materialization: string }>\n): Record<string, string> {\n const matByLayer = new Map<string, Map<string, number>>();\n\n for (const model of models) {\n if (!matByLayer.has(model.layer)) {\n matByLayer.set(model.layer, new Map());\n }\n const counts = matByLayer.get(model.layer)!;\n counts.set(model.materialization, (counts.get(model.materialization) ?? 0) + 1);\n }\n\n const result: Record<string, string> = {};\n for (const [layer, counts] of matByLayer) {\n let maxCount = 0;\n let maxMat = '';\n for (const [mat, count] of counts) {\n if (count > maxCount) {\n maxCount = count;\n maxMat = mat;\n }\n }\n if (maxMat) result[layer] = maxMat;\n }\n\n return result;\n}\n\nasync function detectSchemaYmlPattern(\n projectPath: string,\n modelPaths: string[]\n): Promise<'per-folder' | 'per-model' | 'single-file'> {\n const ymlFiles: string[] = [];\n for (const mp of modelPaths) {\n const pattern = join(projectPath, mp, '**/*.yml');\n const files = await fg(pattern, { ignore: ['**/node_modules/**'] });\n ymlFiles.push(...files);\n }\n\n if (ymlFiles.length === 0) return 'per-folder';\n if (ymlFiles.length === 1) return 'single-file';\n\n const dirs = new Set(ymlFiles.map((f) => dirname(f)));\n return dirs.size > 1 ? 'per-folder' : 'single-file';\n}\n\nexport async function detectConventions(projectPath: string): Promise<DbtConventions> {\n const modelPaths = await getModelPaths(projectPath);\n const models = await listDbtModels(projectPath);\n\n const folders = [...new Set(models.map((m) => m.layer))].filter((l) => l !== 'unknown');\n\n return {\n folderStructure: folders,\n namingPrefixes: detectPrefix(models),\n commonMaterializations: detectMaterializations(models),\n schemaYmlPattern: await detectSchemaYmlPattern(projectPath, modelPaths),\n testPatterns: [],\n };\n}\n\nexport async function listDbtModels(projectPath: string): Promise<DbtModelInfo[]> {\n const modelPaths = await getModelPaths(projectPath);\n const models: DbtModelInfo[] = [];\n\n for (const mp of modelPaths) {\n const pattern = join(projectPath, mp, '**/*.sql');\n const files = await fg(pattern, { ignore: ['**/node_modules/**'] });\n\n for (const file of files) {\n const relPath = relative(join(projectPath, mp), file);\n const name = basename(file, '.sql');\n const sql = await readFile(file, 'utf-8');\n const materialization = extractMaterialization(sql);\n const layer = detectLayer(relPath);\n const folder = dirname(relPath);\n\n models.push({ name, path: relPath, layer, materialization, folder });\n }\n }\n\n return models;\n}\n\nexport async function readDbtModel(\n projectPath: string,\n modelName: string\n): Promise<string | null> {\n const models = await listDbtModels(projectPath);\n const model = models.find((m) => m.name === modelName);\n if (!model) return null;\n\n const modelPaths = await getModelPaths(projectPath);\n for (const mp of modelPaths) {\n const fullPath = join(projectPath, mp, model.path);\n try {\n return await readFile(fullPath, 'utf-8');\n } catch {\n continue;\n }\n }\n return null;\n}\n","import type { ToolDefinition } from './providers/types.js';\nimport type { AdvisorContext } from './context.js';\nimport { loadKnowledge } from './dbt/knowledge.js';\nimport { readDbtModel } from './dbt/project.js';\nimport { SemanticModelBuilder, SemanticQueryCompiler } from '@yamchart/query';\nimport type { SemanticFilter } from '@yamchart/schema';\n\nexport type { AdvisorContext } from './context.js';\n\nexport const TOOL_DEFINITIONS: ToolDefinition[] = [\n // Read-only tools\n {\n name: 'list_yamchart_models',\n description: 'List all yamchart SQL models with names, descriptions, parameters, and return columns',\n parameters: { type: 'object', properties: {}, required: [] },\n },\n {\n name: 'list_charts',\n description: 'List all yamchart charts showing which models they reference and their chart type',\n parameters: { type: 'object', properties: {}, required: [] },\n },\n {\n name: 'get_catalog',\n description: 'Get the dbt catalog (.yamchart/catalog.md) with upstream table schemas and column metadata',\n parameters: { type: 'object', properties: {}, required: [] },\n },\n {\n name: 'get_warehouse_table',\n description: 'Get detailed column metadata and sample rows for a specific warehouse table from the cached catalog. Instant — reads from local catalog, no live query. Use the fully-qualified name (e.g. RAW.PAYMENTS).',\n parameters: {\n type: 'object',\n properties: {\n table: { type: 'string', description: 'Fully-qualified table name (e.g. RAW.PAYMENTS, STAGING.CUSTOMERS)' },\n },\n required: ['table'],\n },\n },\n {\n name: 'get_warehouse_tables',\n description: 'Get detailed metadata for multiple warehouse tables at once from the cached catalog.',\n parameters: {\n type: 'object',\n properties: {\n tables: { type: 'array', items: { type: 'string' }, description: 'List of fully-qualified table names' },\n },\n required: ['tables'],\n },\n },\n {\n name: 'introspect_warehouse',\n description: 'Query the live warehouse. Use for discovering raw tables not yet modeled in dbt.',\n parameters: {\n type: 'object',\n properties: {\n sql: { type: 'string', description: 'SQL query to execute (e.g. SHOW TABLES, SELECT * FROM information_schema.columns)' },\n },\n required: ['sql'],\n },\n },\n {\n name: 'sample_data',\n description: 'Preview rows from a table in the warehouse',\n parameters: {\n type: 'object',\n properties: {\n table: { type: 'string', description: 'Table name (can be schema-qualified)' },\n limit: { type: 'number', description: 'Number of rows to return (default: 5)' },\n },\n required: ['table'],\n },\n },\n {\n name: 'read_dbt_model',\n description: 'Read the full SQL source of an existing dbt model',\n parameters: {\n type: 'object',\n properties: {\n model_name: { type: 'string', description: 'Name of the dbt model to read' },\n },\n required: ['model_name'],\n },\n },\n {\n name: 'list_dbt_models',\n description: 'List all dbt models with their layer (staging/intermediate/marts), materialization, and folder',\n parameters: { type: 'object', properties: {}, required: [] },\n },\n {\n name: 'get_knowledge',\n description: 'Look up dbt reference documentation on a topic: materializations, incremental, macros, testing, naming, performance',\n parameters: {\n type: 'object',\n properties: {\n topic: { type: 'string', description: 'Topic name: materializations, incremental, macros, testing, naming, performance' },\n },\n required: ['topic'],\n },\n },\n {\n name: 'list_semantic_entities',\n description: 'List all semantic entities (auto-generated from the catalog) with their measures and dimensions. Use this to understand what data is available for structured queries without writing SQL.',\n parameters: { type: 'object', properties: {}, required: [] },\n },\n {\n name: 'semantic_query',\n description: 'Run a structured query against the semantic layer. Specify an entity, measures to aggregate, and optional dimensions to group by. Returns the compiled SQL.',\n parameters: {\n type: 'object',\n properties: {\n entity: { type: 'string', description: 'Entity name (e.g. fct_revenue)' },\n measures: { type: 'array', items: { type: 'string' }, description: 'Measure names to aggregate' },\n dimensions: { type: 'array', items: { type: 'string' }, description: 'Dimension names to group by (optional)' },\n filters: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n operator: { type: 'string', description: 'equals, not_equals, contains, gt, gte, lt, lte, in, not_in' },\n value: { description: 'Filter value (string, number, or array for in/not_in)' },\n },\n required: ['dimension', 'operator', 'value'],\n },\n description: 'Optional filters',\n },\n limit: { type: 'number', description: 'Row limit (default: 100)' },\n },\n required: ['entity', 'measures'],\n },\n },\n\n // Action tools\n {\n name: 'propose_model',\n description: 'Propose a new dbt model. Call this when you have a suggestion to present to the user.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Model name (snake_case)' },\n description: { type: 'string', description: 'One-line description of what this model does' },\n sql: { type: 'string', description: 'Full SQL for the model (may include Jinja)' },\n layer: { type: 'string', description: 'dbt layer: staging, intermediate, or marts' },\n materialization: { type: 'string', description: 'Materialization: view, table, or incremental' },\n explanation: { type: 'string', description: 'Why this model is useful (2-3 sentences)' },\n subfolder: { type: 'string', description: 'Optional subfolder within the layer (e.g. \"stripe\", \"core\")' },\n columns: {\n type: 'array',\n description: 'Column definitions for schema.yml',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n description: { type: 'string' },\n tests: { type: 'array', items: { type: 'string' } },\n },\n required: ['name'],\n },\n },\n },\n required: ['name', 'description', 'sql', 'layer', 'materialization', 'explanation'],\n },\n },\n {\n name: 'write_dbt_model',\n description: 'Write a proposed dbt model SQL file to the dbt project. Only call after proposing and user confirmation.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Model name (must match a previous proposal)' },\n },\n required: ['name'],\n },\n },\n {\n name: 'update_schema_yml',\n description: 'Add or update the model entry in the appropriate schema.yml file. Only call after writing the model.',\n parameters: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'Model name (must match a written model)' },\n },\n required: ['name'],\n },\n },\n];\n\nexport async function executeToolCall(\n context: AdvisorContext,\n toolName: string,\n input: Record<string, unknown>\n): Promise<string> {\n switch (toolName) {\n case 'list_yamchart_models':\n return JSON.stringify(\n context.yamchart.models.map((m) => ({\n name: m.name,\n description: m.description,\n params: m.params,\n returns: m.returns,\n }))\n );\n\n case 'list_charts':\n return JSON.stringify(\n context.yamchart.charts.map((c) => ({\n name: c.name,\n title: c.title,\n model: c.model,\n type: c.type,\n }))\n );\n\n case 'get_catalog':\n return context.yamchart.catalog ?? 'No dbt catalog found. Run `yamchart sync-dbt` to create one.';\n\n case 'get_warehouse_table': {\n if (!context.yamchart.catalogJson) {\n return 'Warehouse catalog not available. Run `yamchart sync-warehouse` to populate it.';\n }\n const tableName = (input.table as string).toUpperCase();\n const match = context.yamchart.catalogJson.models.find(\n (m) => (m.table || '').toUpperCase() === tableName || m.name.toUpperCase() === tableName\n );\n if (!match) {\n return JSON.stringify({ error: `Table not found in catalog: ${input.table}. Use get_catalog to see available tables.` });\n }\n return JSON.stringify({\n name: match.name,\n table: match.table,\n tableType: match.tableType,\n source: match.source,\n columns: match.columns,\n sampleRows: match.sampleRows || [],\n });\n }\n\n case 'get_warehouse_tables': {\n if (!context.yamchart.catalogJson) {\n return 'Warehouse catalog not available. Run `yamchart sync-warehouse` to populate it.';\n }\n const tableNames = (input.tables as string[]).map((t) => t.toUpperCase());\n const results = tableNames.map((name) => {\n const match = context.yamchart.catalogJson!.models.find(\n (m) => (m.table || '').toUpperCase() === name || m.name.toUpperCase() === name\n );\n if (!match) {\n return { error: `Not found: ${name}` };\n }\n return {\n name: match.name,\n table: match.table,\n tableType: match.tableType,\n source: match.source,\n columns: match.columns,\n sampleRows: match.sampleRows || [],\n };\n });\n return JSON.stringify(results);\n }\n\n case 'introspect_warehouse': {\n if (!context.warehouse) {\n return 'Warehouse introspection not available. No database connection configured.';\n }\n const sql = input.sql as string;\n try {\n const result = await context.warehouse.executeSql(sql);\n return JSON.stringify(result);\n } catch (err) {\n return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n case 'sample_data': {\n if (!context.warehouse) {\n return 'Warehouse not available. No database connection configured.';\n }\n const table = input.table as string;\n const limit = (input.limit as number) ?? 5;\n try {\n const result = await context.warehouse.executeSql(\n `SELECT * FROM ${table} LIMIT ${limit}`\n );\n return JSON.stringify(result);\n } catch (err) {\n return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n case 'read_dbt_model': {\n const modelName = input.model_name as string;\n const sql = await readDbtModel(context.dbt.projectPath, modelName);\n if (!sql) {\n return JSON.stringify({ error: `Model not found: ${modelName}` });\n }\n return JSON.stringify({ name: modelName, sql });\n }\n\n case 'list_dbt_models':\n return JSON.stringify(\n context.dbt.models.map((m) => ({\n name: m.name,\n path: m.path,\n layer: m.layer,\n materialization: m.materialization,\n folder: m.folder,\n }))\n );\n\n case 'get_knowledge': {\n const topic = input.topic as string;\n return loadKnowledge(topic);\n }\n\n case 'list_semantic_entities': {\n if (!context.yamchart.catalogJson) {\n return 'No catalog available. Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate it.';\n }\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: context.yamchart.catalogJson.models } });\n return JSON.stringify(\n model.entities.map((e) => ({\n name: e.name,\n source_table: e.source_table,\n description: e.description,\n measures: e.measures.map((m) => ({ name: m.name, type: m.type })),\n dimensions: e.dimensions.map((d) => ({ name: d.name, type: d.type })),\n }))\n );\n }\n\n case 'semantic_query': {\n if (!context.yamchart.catalogJson) {\n return JSON.stringify({ error: 'No catalog available. Run `yamchart sync-warehouse` or `yamchart sync-dbt` to populate it.' });\n }\n try {\n const builder = new SemanticModelBuilder();\n const model = builder.build({ catalog: { models: context.yamchart.catalogJson.models } });\n const compiler = new SemanticQueryCompiler();\n const sql = compiler.compile(model, {\n model: input.entity as string,\n measures: (input.measures as string[]) || [],\n dimensions: (input.dimensions as string[]) || [],\n filters: (input.filters as SemanticFilter[]) || [],\n limit: (input.limit as number) || 100,\n });\n return JSON.stringify({ sql, entity: input.entity });\n } catch (err) {\n return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });\n }\n }\n\n case 'propose_model':\n return JSON.stringify({\n status: 'proposed',\n name: input.name,\n description: input.description,\n sql: input.sql,\n layer: input.layer,\n materialization: input.materialization,\n explanation: input.explanation,\n subfolder: input.subfolder,\n columns: input.columns,\n });\n\n case 'write_dbt_model':\n // Actual writing happens in the CLI command, not here.\n // The agent tool just signals intent — the CLI confirms with the user.\n return JSON.stringify({\n status: 'pending_confirmation',\n name: input.name,\n message: 'Model write requested. Waiting for user confirmation.',\n });\n\n case 'update_schema_yml':\n return JSON.stringify({\n status: 'pending_confirmation',\n name: input.name,\n message: 'Schema.yml update requested. Waiting for user confirmation.',\n });\n\n default:\n return JSON.stringify({ error: `Unknown tool: ${toolName}` });\n }\n}\n","import type {\n LLMProvider,\n Message,\n ContentBlock,\n TextBlock,\n ToolUseBlock,\n ToolResultBlock,\n} from './providers/types.js';\nimport type { AdvisorContext } from './context.js';\nimport { TOOL_DEFINITIONS, executeToolCall } from './tools.js';\nimport { getKnowledgeOverview } from './dbt/knowledge.js';\n\nexport interface Proposal {\n name: string;\n description: string;\n sql: string;\n layer: string;\n materialization: string;\n explanation: string;\n subfolder?: string;\n columns?: Array<{ name: string; description?: string; tests?: string[] }>;\n}\n\nexport interface AgentResult {\n response: string;\n proposals: Proposal[];\n messages: Message[];\n}\n\nexport const SYSTEM_PROMPT = `You are a dbt advisor for yamchart projects. You analyze the BI layer (yamchart models, charts, dashboards) and the data engineering layer (dbt models, warehouse tables) to suggest improvements to dbt models.\n\nThink like a senior data engineer. Your goals:\n- Understand what the BI layer needs (charts, filters, drill-downs, date ranges)\n- Identify gaps in the dbt project (missing models, incomplete staging, opportunities for pre-aggregation)\n- Suggest new dbt models that serve the BI layer better\n- Follow the project's existing conventions (folder structure, naming, materializations)\n\nWhen proposing models:\n- Match the project's naming conventions (detect and follow existing prefixes like stg_, fct_, dim_)\n- Place models in the correct layer and folder\n- Choose appropriate materializations\n- Include column descriptions and tests in proposals\n- Explain WHY the model helps, not just WHAT it does\n- Use ref() and source() macros correctly\n\nWhen working with cross-database tables:\n- If a table lives outside the primary analytics database, recommend creating a dbt source definition in sources.yml\n- Follow the pattern: source → staging model → downstream refs\n- Use get_knowledge('sources') for detailed source patterns\n- Check the warehouse catalog (get_warehouse_tables) to identify tables in other databases\n\nWhen in audit mode:\n- Evaluate: coverage gaps, convention violations, materialization mismatches, missing tests\n- Rank suggestions by impact\n- Be concise — focus on actionable improvements\n\n${getKnowledgeOverview()}\n\nWhen you have a suggestion, call propose_model with the full SQL and metadata. Do NOT call write_dbt_model or update_schema_yml directly — the user will be prompted to confirm before writing.`;\n\nconst MAX_TOOL_ROUNDS = 15;\n\nexport class AdvisorAgent {\n private provider: LLMProvider;\n\n constructor(provider: LLMProvider) {\n this.provider = provider;\n }\n\n async run(\n context: AdvisorContext,\n userMessages: Message[]\n ): Promise<AgentResult> {\n const proposals: Proposal[] = [];\n const messages: Message[] = [...userMessages];\n\n // Build context-specific system prompt\n const systemPrompt = this.buildSystemPrompt(context);\n\n for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {\n const response = await this.provider.chat({\n system: systemPrompt,\n messages,\n tools: TOOL_DEFINITIONS,\n });\n\n const textBlocks = response.content.filter(\n (b): b is TextBlock => b.type === 'text'\n );\n const toolUseBlocks = response.content.filter(\n (b): b is ToolUseBlock => b.type === 'tool_use'\n );\n\n // No tool calls — return final text response\n if (toolUseBlocks.length === 0) {\n const responseText = textBlocks.map((b) => b.text).join('\\n');\n return { response: responseText, proposals, messages };\n }\n\n // Add assistant message with tool calls\n messages.push({ role: 'assistant', content: response.content });\n\n // Execute each tool call\n const toolResults: ContentBlock[] = [];\n for (const toolUse of toolUseBlocks) {\n const result = await executeToolCall(context, toolUse.name, toolUse.input);\n\n // Collect proposals\n if (toolUse.name === 'propose_model') {\n const parsed = JSON.parse(result) as Record<string, unknown>;\n proposals.push({\n name: parsed.name as string,\n description: parsed.description as string,\n sql: toolUse.input.sql as string,\n layer: toolUse.input.layer as string,\n materialization: toolUse.input.materialization as string,\n explanation: toolUse.input.explanation as string,\n subfolder: toolUse.input.subfolder as string | undefined,\n columns: toolUse.input.columns as Proposal['columns'],\n });\n }\n\n toolResults.push({\n type: 'tool_result',\n tool_use_id: toolUse.id,\n content: result,\n } as ToolResultBlock);\n }\n\n // Add tool results as user message\n messages.push({ role: 'user', content: toolResults });\n }\n\n // Hit max rounds — return what we have\n return {\n response: 'Reached maximum tool call rounds. Here are the suggestions gathered so far.',\n proposals,\n messages,\n };\n }\n\n private buildSystemPrompt(context: AdvisorContext): string {\n const parts = [SYSTEM_PROMPT];\n\n // Add project summary\n parts.push(`\\n## Current Project Summary`);\n parts.push(`- Yamchart: ${context.yamchart.models.length} SQL models, ${context.yamchart.charts.length} charts, ${context.yamchart.dashboards.length} dashboards`);\n parts.push(`- dbt project: \"${context.dbt.projectName}\" at ${context.dbt.projectPath}`);\n parts.push(`- dbt models: ${context.dbt.models.length} (layers: ${context.dbt.conventions.folderStructure.join(', ') || 'none detected'})`);\n\n if (Object.keys(context.dbt.conventions.namingPrefixes).length > 0) {\n const prefixes = Object.entries(context.dbt.conventions.namingPrefixes)\n .map(([layer, prefix]) => `${layer}: ${prefix}`)\n .join(', ');\n parts.push(`- Naming prefixes: ${prefixes}`);\n }\n\n if (Object.keys(context.dbt.conventions.commonMaterializations).length > 0) {\n const mats = Object.entries(context.dbt.conventions.commonMaterializations)\n .map(([layer, mat]) => `${layer}: ${mat}`)\n .join(', ');\n parts.push(`- Materializations: ${mats}`);\n }\n\n parts.push(`- Schema.yml pattern: ${context.dbt.conventions.schemaYmlPattern}`);\n parts.push(`- Catalog: ${context.yamchart.catalog ? 'available' : 'not synced'}`);\n parts.push(`- Warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : 'not connected'}`);\n\n return parts.join('\\n');\n }\n}\n","import Anthropic from '@anthropic-ai/sdk';\nimport type {\n LLMProvider,\n LLMResponse,\n Message,\n ToolDefinition,\n ContentBlock,\n TextBlock,\n ToolUseBlock,\n} from './types.js';\n\nexport class AnthropicProvider implements LLMProvider {\n private client: Anthropic;\n private model: string;\n\n constructor(apiKey: string, model: string = 'claude-sonnet-4-5-20250929') {\n this.client = new Anthropic({ apiKey });\n this.model = model;\n }\n\n async chat(options: {\n system: string;\n messages: Message[];\n tools: ToolDefinition[];\n maxTokens?: number;\n }): Promise<LLMResponse> {\n const tools: Anthropic.Tool[] = options.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: {\n type: 'object' as const,\n properties: t.parameters.properties,\n required: t.parameters.required ?? [],\n },\n }));\n\n const messages: Anthropic.MessageParam[] = options.messages.map((m) => {\n if (typeof m.content === 'string') {\n return { role: m.role, content: m.content };\n }\n const blocks: Anthropic.ContentBlockParam[] = m.content.map((block) => {\n if (block.type === 'text') {\n return { type: 'text' as const, text: (block as TextBlock).text };\n }\n if (block.type === 'tool_use') {\n const tu = block as ToolUseBlock;\n return { type: 'tool_use' as const, id: tu.id, name: tu.name, input: tu.input };\n }\n if (block.type === 'tool_result') {\n const tr = block as { type: 'tool_result'; tool_use_id: string; content: string };\n return { type: 'tool_result' as const, tool_use_id: tr.tool_use_id, content: tr.content };\n }\n throw new Error(`Unknown block type: ${block.type}`);\n });\n return { role: m.role, content: blocks };\n });\n\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: options.maxTokens ?? 4096,\n system: options.system,\n tools,\n messages,\n });\n\n const content: ContentBlock[] = response.content.map((block) => {\n if (block.type === 'text') {\n return { type: 'text', text: block.text } as TextBlock;\n }\n if (block.type === 'tool_use') {\n return {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n input: block.input as Record<string, unknown>,\n } as ToolUseBlock;\n }\n throw new Error(`Unexpected block type: ${block.type}`);\n });\n\n return {\n content,\n stopReason: response.stop_reason === 'tool_use' ? 'tool_use' : 'end',\n };\n }\n}\n","import { readFile, writeFile, mkdir, access } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\nimport type { DbtConventions } from './project.js';\n\nexport function buildModelPath(\n modelName: string,\n layer: string | undefined,\n conventions: DbtConventions,\n subfolder?: string\n): string {\n const effectiveLayer = layer ?? (conventions.folderStructure.includes('marts') ? 'marts' : conventions.folderStructure[0] ?? 'models');\n const parts = ['models', effectiveLayer];\n if (subfolder) parts.push(subfolder);\n parts.push(`${modelName}.sql`);\n return parts.join('/');\n}\n\nexport function formatModelSql(options: {\n materialization: string;\n tags?: string[];\n sql: string;\n description?: string;\n}): string {\n const lines: string[] = [];\n\n // Only add config block for non-default materializations\n if (options.materialization !== 'view') {\n const configParts: string[] = [`materialized='${options.materialization}'`];\n if (options.tags && options.tags.length > 0) {\n configParts.push(`tags=[${options.tags.map((t) => `'${t}'`).join(', ')}]`);\n }\n lines.push(`{{\\n config(\\n ${configParts.join(',\\n ')}\\n )\\n}}\\n`);\n }\n\n lines.push(options.sql);\n return lines.join('\\n');\n}\n\nexport interface SchemaColumn {\n name: string;\n description?: string;\n tests?: string[];\n}\n\nexport function buildSchemaYmlEntry(options: {\n name: string;\n description: string;\n columns?: SchemaColumn[];\n}): string {\n const model: Record<string, unknown> = {\n name: options.name,\n description: options.description,\n };\n\n if (options.columns && options.columns.length > 0) {\n model.columns = options.columns.map((col) => {\n const entry: Record<string, unknown> = { name: col.name };\n if (col.description) entry.description = col.description;\n if (col.tests && col.tests.length > 0) entry.tests = col.tests;\n return entry;\n });\n }\n\n return stringifyYaml({ models: [model] }, { indent: 2 });\n}\n\nexport async function writeDbtModel(\n projectPath: string,\n modelPath: string,\n sql: string\n): Promise<string> {\n const fullPath = join(projectPath, modelPath);\n await mkdir(dirname(fullPath), { recursive: true });\n await writeFile(fullPath, sql + '\\n', 'utf-8');\n return fullPath;\n}\n\nexport async function updateSchemaYml(\n projectPath: string,\n schemaPath: string,\n entry: { name: string; description: string; columns?: SchemaColumn[] }\n): Promise<string> {\n const fullPath = join(projectPath, schemaPath);\n\n let existing: { version?: number; models?: Array<Record<string, unknown>> } = {\n version: 2,\n models: [],\n };\n\n try {\n await access(fullPath);\n const content = await readFile(fullPath, 'utf-8');\n existing = parseYaml(content) as typeof existing;\n if (!existing.models) existing.models = [];\n } catch {\n // File doesn't exist, start fresh\n await mkdir(dirname(fullPath), { recursive: true });\n }\n\n // Check if model already exists\n const idx = existing.models!.findIndex(\n (m) => m.name === entry.name\n );\n\n const modelEntry: Record<string, unknown> = {\n name: entry.name,\n description: entry.description,\n };\n if (entry.columns && entry.columns.length > 0) {\n modelEntry.columns = entry.columns.map((col) => {\n const c: Record<string, unknown> = { name: col.name };\n if (col.description) c.description = col.description;\n if (col.tests && col.tests.length > 0) c.tests = col.tests;\n return c;\n });\n }\n\n if (idx >= 0) {\n existing.models![idx] = modelEntry;\n } else {\n existing.models!.push(modelEntry);\n }\n\n await writeFile(fullPath, stringifyYaml(existing, { indent: 2 }), 'utf-8');\n return fullPath;\n}\n"],"mappings":"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","names":["readFile","join","dirname","readFile","join","dirname","parseYaml"]}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
findProjectRoot,
|
|
7
7
|
loadEnvFile,
|
|
8
8
|
validateProject
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-E2UZXDF6.js";
|
|
10
10
|
import {
|
|
11
11
|
detail,
|
|
12
12
|
error,
|
|
@@ -17,8 +17,9 @@ import {
|
|
|
17
17
|
success,
|
|
18
18
|
warning
|
|
19
19
|
} from "./chunk-HJVVHYVN.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-X6LQGWUX.js";
|
|
21
|
+
import "./chunk-JYQKDWLG.js";
|
|
22
|
+
import "./chunk-UND73EOB.js";
|
|
22
23
|
import "./chunk-DGUM43GV.js";
|
|
23
24
|
|
|
24
25
|
// src/index.ts
|
|
@@ -96,7 +97,7 @@ program.command("dev").description("Start development server with hot reload").a
|
|
|
96
97
|
detail("Run this command from a yamchart project directory");
|
|
97
98
|
process.exit(2);
|
|
98
99
|
}
|
|
99
|
-
const { runDevServer } = await import("./dev-
|
|
100
|
+
const { runDevServer } = await import("./dev-MRZ76V74.js");
|
|
100
101
|
await runDevServer(projectDir, {
|
|
101
102
|
port: parseInt(options.port, 10),
|
|
102
103
|
apiOnly: options.apiOnly ?? false,
|
|
@@ -104,7 +105,7 @@ program.command("dev").description("Start development server with hot reload").a
|
|
|
104
105
|
});
|
|
105
106
|
});
|
|
106
107
|
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) => {
|
|
107
|
-
const { initProject } = await import("./init-
|
|
108
|
+
const { initProject } = await import("./init-UYQE5DPU.js");
|
|
108
109
|
const targetDir = resolve(directory);
|
|
109
110
|
const result = await initProject(targetDir, options);
|
|
110
111
|
if (!result.success) {
|
|
@@ -168,7 +169,7 @@ program.command("sync-dbt").description("Sync dbt project metadata into AI-reada
|
|
|
168
169
|
if (!options.targetDatabase) {
|
|
169
170
|
try {
|
|
170
171
|
const { readFile } = await import("fs/promises");
|
|
171
|
-
const { resolveConnection } = await import("./connection-utils-
|
|
172
|
+
const { resolveConnection } = await import("./connection-utils-FTSZU2VF.js");
|
|
172
173
|
const { detectDatabaseMismatch } = await import("./rewrite-database-FDJIXKZ2.js");
|
|
173
174
|
const catalogJsonStr = await readFile(join(projectDir, ".yamchart", "catalog.json"), "utf-8");
|
|
174
175
|
const catalogData = JSON.parse(catalogJsonStr);
|
|
@@ -222,7 +223,7 @@ program.command("test").description("Run model tests (@returns schema checks and
|
|
|
222
223
|
}
|
|
223
224
|
loadEnvFile(projectDir);
|
|
224
225
|
try {
|
|
225
|
-
const { testProject, formatTestOutput } = await import("./test-
|
|
226
|
+
const { testProject, formatTestOutput } = await import("./test-TXRZWNXK.js");
|
|
226
227
|
const result = await testProject(projectDir, model, {
|
|
227
228
|
connection: options.connection,
|
|
228
229
|
json: options.json
|
|
@@ -245,7 +246,7 @@ program.command("test").description("Run model tests (@returns schema checks and
|
|
|
245
246
|
}
|
|
246
247
|
});
|
|
247
248
|
program.command("update").description("Check for yamchart updates").action(async () => {
|
|
248
|
-
const { runUpdate } = await import("./update-
|
|
249
|
+
const { runUpdate } = await import("./update-UKMEWCSO.js");
|
|
249
250
|
await runUpdate(pkg.version);
|
|
250
251
|
});
|
|
251
252
|
program.command("reset-password").description("Reset a user password (requires auth to be enabled)").requiredOption("-e, --email <email>", "Email address of the user").action(async (options) => {
|
|
@@ -270,7 +271,7 @@ program.command("tables").description("List tables and views in the connected da
|
|
|
270
271
|
}
|
|
271
272
|
loadEnvFile(projectDir);
|
|
272
273
|
try {
|
|
273
|
-
const { listTables } = await import("./tables-
|
|
274
|
+
const { listTables } = await import("./tables-UOO342TA.js");
|
|
274
275
|
const result = await listTables(projectDir, options);
|
|
275
276
|
if (options.json) {
|
|
276
277
|
console.log(JSON.stringify(result.tables, null, 2));
|
|
@@ -303,7 +304,7 @@ program.command("describe").description("Show columns and types for a table").ar
|
|
|
303
304
|
}
|
|
304
305
|
loadEnvFile(projectDir);
|
|
305
306
|
try {
|
|
306
|
-
const { describeTable } = await import("./describe-
|
|
307
|
+
const { describeTable } = await import("./describe-TGIOBNJB.js");
|
|
307
308
|
const result = await describeTable(projectDir, table, options);
|
|
308
309
|
if (options.json) {
|
|
309
310
|
console.log(JSON.stringify(result.columns, null, 2));
|
|
@@ -338,8 +339,8 @@ program.command("query").description("Execute SQL against a connection").argumen
|
|
|
338
339
|
}
|
|
339
340
|
loadEnvFile(projectDir);
|
|
340
341
|
try {
|
|
341
|
-
const { executeQuery } = await import("./query-
|
|
342
|
-
const { formatTable, formatJSON } = await import("./connection-utils-
|
|
342
|
+
const { executeQuery } = await import("./query-JRMMNXX6.js");
|
|
343
|
+
const { formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
|
|
343
344
|
const limit = options.limit ? parseInt(options.limit, 10) : void 0;
|
|
344
345
|
const result = await executeQuery(projectDir, sql, {
|
|
345
346
|
connection: options.connection,
|
|
@@ -366,8 +367,8 @@ program.command("sample").description("Show sample rows from a table or dbt mode
|
|
|
366
367
|
}
|
|
367
368
|
loadEnvFile(projectDir);
|
|
368
369
|
try {
|
|
369
|
-
const { sampleTable } = await import("./sample-
|
|
370
|
-
const { formatTable, formatJSON } = await import("./connection-utils-
|
|
370
|
+
const { sampleTable } = await import("./sample-VGIY4U4J.js");
|
|
371
|
+
const { formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
|
|
371
372
|
const limit = options.limit ? parseInt(options.limit, 10) : void 0;
|
|
372
373
|
const result = await sampleTable(projectDir, table, {
|
|
373
374
|
connection: options.connection,
|
|
@@ -397,7 +398,7 @@ program.command("search").description("Search for tables and columns by keyword"
|
|
|
397
398
|
}
|
|
398
399
|
loadEnvFile(projectDir);
|
|
399
400
|
try {
|
|
400
|
-
const { searchDatabase } = await import("./search-
|
|
401
|
+
const { searchDatabase } = await import("./search-QSYNG4SR.js");
|
|
401
402
|
const result = await searchDatabase(projectDir, keyword, options);
|
|
402
403
|
if (options.json) {
|
|
403
404
|
console.log(JSON.stringify(result.results, null, 2));
|
|
@@ -447,7 +448,7 @@ program.command("sync-warehouse").description("Sync warehouse table metadata int
|
|
|
447
448
|
}
|
|
448
449
|
loadEnvFile(projectDir);
|
|
449
450
|
try {
|
|
450
|
-
const { runSyncWarehouse } = await import("./sync-warehouse-
|
|
451
|
+
const { runSyncWarehouse } = await import("./sync-warehouse-XHTBZH25.js");
|
|
451
452
|
await runSyncWarehouse(projectDir, options);
|
|
452
453
|
} catch (err) {
|
|
453
454
|
error(err instanceof Error ? err.message : String(err));
|
|
@@ -493,7 +494,7 @@ program.command("advisor").description("AI-powered dbt model advisor \u2014 sugg
|
|
|
493
494
|
process.exit(2);
|
|
494
495
|
}
|
|
495
496
|
loadEnvFile(projectDir);
|
|
496
|
-
const { runAdvisor } = await import("./advisor-
|
|
497
|
+
const { runAdvisor } = await import("./advisor-57BOMUUF.js");
|
|
497
498
|
await runAdvisor(projectDir, question, {
|
|
498
499
|
top: options.top ? parseInt(options.top, 10) : 5,
|
|
499
500
|
json: options.json,
|
|
@@ -501,6 +502,123 @@ program.command("advisor").description("AI-powered dbt model advisor \u2014 sugg
|
|
|
501
502
|
connection: options.connection
|
|
502
503
|
});
|
|
503
504
|
});
|
|
505
|
+
var semanticCmd = program.command("semantic").description("Explore the semantic layer \u2014 auto-generated measures and dimensions from your catalog").option("--json", "Output as JSON").action(async (options) => {
|
|
506
|
+
const startPath = resolve(".");
|
|
507
|
+
const projectDir = await findProjectRoot(startPath);
|
|
508
|
+
if (!projectDir) {
|
|
509
|
+
error("yamchart.yaml not found");
|
|
510
|
+
detail("Run this command from a yamchart project directory");
|
|
511
|
+
process.exit(2);
|
|
512
|
+
}
|
|
513
|
+
loadEnvFile(projectDir);
|
|
514
|
+
try {
|
|
515
|
+
const { readFile } = await import("fs/promises");
|
|
516
|
+
const catalogPath = join(projectDir, ".yamchart", "catalog.json");
|
|
517
|
+
const catalogJson = JSON.parse(await readFile(catalogPath, "utf-8"));
|
|
518
|
+
const { listSemanticEntities } = await import("./semantic-RAP3S5PQ.js");
|
|
519
|
+
const result = listSemanticEntities(catalogJson);
|
|
520
|
+
if (options.json) {
|
|
521
|
+
console.log(JSON.stringify(result.entities, null, 2));
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (result.entities.length === 0) {
|
|
525
|
+
info("No semantic entities found.");
|
|
526
|
+
detail("Run `yamchart sync-dbt` or `yamchart sync-warehouse` to populate the catalog.");
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
header(`Semantic Layer \u2014 ${result.entities.length} entities`);
|
|
530
|
+
for (const entity of result.entities) {
|
|
531
|
+
console.log(` ${pc.bold(entity.name)}`);
|
|
532
|
+
console.log(` ${pc.dim(entity.source_table)}`);
|
|
533
|
+
if (entity.description) {
|
|
534
|
+
console.log(` ${entity.description}`);
|
|
535
|
+
}
|
|
536
|
+
if (entity.measures.length > 0) {
|
|
537
|
+
console.log(` Measures: ${entity.measures.map((m) => `${m.name} (${pc.dim(m.type)})`).join(", ")}`);
|
|
538
|
+
}
|
|
539
|
+
if (entity.dimensions.length > 0) {
|
|
540
|
+
console.log(` Dimensions: ${entity.dimensions.map((d) => `${d.name} (${pc.dim(d.type)})`).join(", ")}`);
|
|
541
|
+
}
|
|
542
|
+
console.log();
|
|
543
|
+
}
|
|
544
|
+
} catch (err) {
|
|
545
|
+
if (err instanceof Error && err.message.includes("ENOENT")) {
|
|
546
|
+
error("No catalog found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` first.");
|
|
547
|
+
} else {
|
|
548
|
+
error(err instanceof Error ? err.message : String(err));
|
|
549
|
+
}
|
|
550
|
+
process.exit(1);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
semanticCmd.command("query").description("Run a structured query against the semantic layer").requiredOption("-e, --entity <name>", "Entity name (e.g. fct_revenue)").requiredOption("-m, --measures <measures>", "Comma-separated measure names").option("-d, --dimensions <dimensions>", "Comma-separated dimension names").option("-f, --filter <filter...>", "Filters in format dimension=value").option("--order <field>", "Order by field").option("--desc", "Order descending (default: ascending)").option("-l, --limit <n>", "Row limit (default: 100)").option("-c, --connection <name>", "Connection to use").option("--json", "Output as JSON").option("--sql", "Print compiled SQL only (do not execute)").action(async (options) => {
|
|
554
|
+
const startPath = resolve(".");
|
|
555
|
+
const projectDir = await findProjectRoot(startPath);
|
|
556
|
+
if (!projectDir) {
|
|
557
|
+
error("yamchart.yaml not found");
|
|
558
|
+
process.exit(2);
|
|
559
|
+
}
|
|
560
|
+
loadEnvFile(projectDir);
|
|
561
|
+
try {
|
|
562
|
+
const { readFile } = await import("fs/promises");
|
|
563
|
+
const catalogPath = join(projectDir, ".yamchart", "catalog.json");
|
|
564
|
+
const catalogJson = JSON.parse(await readFile(catalogPath, "utf-8"));
|
|
565
|
+
const { querySemanticEntity } = await import("./semantic-RAP3S5PQ.js");
|
|
566
|
+
const filters = (options.filter || []).map((f) => {
|
|
567
|
+
const eqIdx = f.indexOf("=");
|
|
568
|
+
if (eqIdx === -1) throw new Error(`Invalid filter format: "${f}". Use dimension=value`);
|
|
569
|
+
return {
|
|
570
|
+
dimension: f.slice(0, eqIdx),
|
|
571
|
+
operator: "equals",
|
|
572
|
+
value: f.slice(eqIdx + 1)
|
|
573
|
+
};
|
|
574
|
+
});
|
|
575
|
+
const result = querySemanticEntity(catalogJson, {
|
|
576
|
+
entity: options.entity,
|
|
577
|
+
measures: options.measures.split(",").map((s) => s.trim()),
|
|
578
|
+
dimensions: options.dimensions ? options.dimensions.split(",").map((s) => s.trim()) : [],
|
|
579
|
+
filters,
|
|
580
|
+
order_by: options.order ? { field: options.order, direction: options.desc ? "desc" : "asc" } : void 0,
|
|
581
|
+
limit: options.limit ? parseInt(options.limit, 10) : 100
|
|
582
|
+
});
|
|
583
|
+
if (options.sql) {
|
|
584
|
+
console.log(result.sql);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const { resolveConnection, createConnector, formatTable, formatJSON } = await import("./connection-utils-FTSZU2VF.js");
|
|
588
|
+
const connection = await resolveConnection(projectDir, options.connection);
|
|
589
|
+
const connector = createConnector(connection, projectDir);
|
|
590
|
+
const start = performance.now();
|
|
591
|
+
await connector.connect();
|
|
592
|
+
const queryResult = await connector.execute(result.sql);
|
|
593
|
+
await connector.disconnect();
|
|
594
|
+
const durationMs = Math.round((performance.now() - start) * 100) / 100;
|
|
595
|
+
if (options.json) {
|
|
596
|
+
console.log(formatJSON({
|
|
597
|
+
columns: queryResult.columns,
|
|
598
|
+
rows: queryResult.rows,
|
|
599
|
+
rowCount: queryResult.rows.length,
|
|
600
|
+
durationMs
|
|
601
|
+
}));
|
|
602
|
+
} else {
|
|
603
|
+
detail(`Entity: ${result.entityName}`);
|
|
604
|
+
detail(`SQL: ${result.sql.replace(/\n/g, " ").slice(0, 120)}...`);
|
|
605
|
+
newline();
|
|
606
|
+
console.log(formatTable({
|
|
607
|
+
columns: queryResult.columns,
|
|
608
|
+
rows: queryResult.rows,
|
|
609
|
+
rowCount: queryResult.rows.length,
|
|
610
|
+
durationMs
|
|
611
|
+
}));
|
|
612
|
+
}
|
|
613
|
+
} catch (err) {
|
|
614
|
+
if (err instanceof Error && err.message.includes("ENOENT")) {
|
|
615
|
+
error("No catalog found. Run `yamchart sync-dbt` or `yamchart sync-warehouse` first.");
|
|
616
|
+
} else {
|
|
617
|
+
error(err instanceof Error ? err.message : String(err));
|
|
618
|
+
}
|
|
619
|
+
process.exit(1);
|
|
620
|
+
}
|
|
621
|
+
});
|
|
504
622
|
program.parse();
|
|
505
623
|
var updateNotification = null;
|
|
506
624
|
checkForUpdate(pkg.version).then((update) => {
|