yamchart 0.9.5 → 0.10.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 (74) hide show
  1. package/dist/{advisor-SC64RTZO.js → advisor-O2BRAI4T.js} +24 -14
  2. package/dist/advisor-O2BRAI4T.js.map +1 -0
  3. package/dist/{chunk-NXQ6ZO3V.js → chunk-5FHV22X2.js} +6 -6
  4. package/dist/chunk-5FHV22X2.js.map +1 -0
  5. package/dist/chunk-FN6R2LAC.js +15442 -0
  6. package/dist/chunk-FN6R2LAC.js.map +1 -0
  7. package/dist/chunk-QJ5CPQJK.js +2053 -0
  8. package/dist/chunk-QJ5CPQJK.js.map +1 -0
  9. package/dist/{chunk-S7YQXEKM.js → chunk-QUIDZO5G.js} +103 -275
  10. package/dist/chunk-QUIDZO5G.js.map +1 -0
  11. package/dist/{chunk-RMIDEBHD.js → chunk-S2CH4HUZ.js} +6 -6
  12. package/dist/{chunk-UND73EOB.js → chunk-UFDQ3C7Q.js} +473 -4
  13. package/dist/chunk-UFDQ3C7Q.js.map +1 -0
  14. package/dist/{chunk-H4L3FNLS.js → chunk-ZBCQNWVN.js} +2 -2
  15. package/dist/{chunk-RM6MNDVF.js → chunk-ZIY22VO7.js} +192 -11
  16. package/dist/chunk-ZIY22VO7.js.map +1 -0
  17. package/dist/{connection-utils-C4FQGBW6.js → connection-utils-FEUWER5I.js} +5 -5
  18. package/dist/{describe-X75C2VDU.js → describe-MEP72B56.js} +6 -6
  19. package/dist/{dev-GWXHBBWB.js → dev-LZ4YHNDJ.js} +1315 -73
  20. package/dist/dev-LZ4YHNDJ.js.map +1 -0
  21. package/dist/dist-5IFWLWND.js +48 -0
  22. package/dist/{dist-MX5K2ABB.js → dist-PPAD6KOM.js} +44 -2
  23. package/dist/{dist-JMLAZUL7.js → dist-XNCED7JW.js} +29 -12
  24. package/dist/fileFromPath-7TNUU6RI.js +130 -0
  25. package/dist/fileFromPath-7TNUU6RI.js.map +1 -0
  26. package/dist/index.js +24 -24
  27. package/dist/public/assets/DataView-DUCz_96y.js +9 -0
  28. package/dist/public/assets/{EventManagement-CTuAJ0eF.js → EventManagement-BnmeJDQl.js} +1 -1
  29. package/dist/public/assets/{ExplorePage-ZJ3zNjNQ.js → ExplorePage-kk4z9ldZ.js} +1 -1
  30. package/dist/public/assets/{LoginPage-wygea4BI.js → LoginPage-CzaFkkjg.js} +1 -1
  31. package/dist/public/assets/{PublicViewer-8YqGrVVB.js → PublicViewer-irjxqH6a.js} +1 -1
  32. package/dist/public/assets/{SetupWizard-DqDBwHrF.js → SetupWizard-ConWIcmy.js} +1 -1
  33. package/dist/public/assets/{ShareManagement-TAAdI_gY.js → ShareManagement-CP4wdwLR.js} +1 -1
  34. package/dist/public/assets/SourceDetailView-DZS5518E.js +1 -0
  35. package/dist/public/assets/{UserManagement-B4kZHyri.js → UserManagement-AubGd9hl.js} +1 -1
  36. package/dist/public/assets/data-3vtzSuAZ.js +1 -0
  37. package/dist/public/assets/{index-CfyF2Wf-.css → index-C1X8RW4Z.css} +1 -1
  38. package/dist/public/assets/{index-BgzSjgIu.js → index-jlfTO7f5.js} +44 -44
  39. package/dist/public/assets/{index.es-AB-GdGyc.js → index.es-CgnvEWi5.js} +1 -1
  40. package/dist/public/assets/{jspdf.es.min-ChRx2mOQ.js → jspdf.es.min-Cw5WefMt.js} +3 -3
  41. package/dist/public/index.html +2 -2
  42. package/dist/{query-QNRDS74I.js → query-2H3YOPI2.js} +5 -5
  43. package/dist/{sample-SKLHBZBU.js → sample-ODUGGSFA.js} +5 -5
  44. package/dist/{search-4KMETZVX.js → search-IPE4ISFB.js} +6 -6
  45. package/dist/{semantic-6WKELH5V.js → semantic-K3MYXXJI.js} +3 -2
  46. package/dist/{semantic-6WKELH5V.js.map → semantic-K3MYXXJI.js.map} +1 -1
  47. package/dist/{source-resolver-R7WBIL7M.js → source-resolver-HZQLOODU.js} +6 -6
  48. package/dist/source-resolver-HZQLOODU.js.map +1 -0
  49. package/dist/{sync-warehouse-UWRNUXE7.js → sync-warehouse-26L6JDSV.js} +10 -10
  50. package/dist/{tables-V65QUGHK.js → tables-K5NAN2WK.js} +6 -6
  51. package/dist/templates/default/docs/yamchart-reference.md +42 -0
  52. package/dist/{test-UE5OWG3E.js → test-SRHVOXZB.js} +8 -7
  53. package/dist/{test-UE5OWG3E.js.map → test-SRHVOXZB.js.map} +1 -1
  54. package/package.json +3 -3
  55. package/dist/advisor-SC64RTZO.js.map +0 -1
  56. package/dist/chunk-NXQ6ZO3V.js.map +0 -1
  57. package/dist/chunk-RM6MNDVF.js.map +0 -1
  58. package/dist/chunk-S7YQXEKM.js.map +0 -1
  59. package/dist/chunk-UND73EOB.js.map +0 -1
  60. package/dist/dev-GWXHBBWB.js.map +0 -1
  61. package/dist/dist-MNXSMGV6.js +0 -790
  62. package/dist/dist-MNXSMGV6.js.map +0 -1
  63. /package/dist/{chunk-RMIDEBHD.js.map → chunk-S2CH4HUZ.js.map} +0 -0
  64. /package/dist/{chunk-H4L3FNLS.js.map → chunk-ZBCQNWVN.js.map} +0 -0
  65. /package/dist/{connection-utils-C4FQGBW6.js.map → connection-utils-FEUWER5I.js.map} +0 -0
  66. /package/dist/{describe-X75C2VDU.js.map → describe-MEP72B56.js.map} +0 -0
  67. /package/dist/{dist-JMLAZUL7.js.map → dist-5IFWLWND.js.map} +0 -0
  68. /package/dist/{dist-MX5K2ABB.js.map → dist-PPAD6KOM.js.map} +0 -0
  69. /package/dist/{source-resolver-R7WBIL7M.js.map → dist-XNCED7JW.js.map} +0 -0
  70. /package/dist/{query-QNRDS74I.js.map → query-2H3YOPI2.js.map} +0 -0
  71. /package/dist/{sample-SKLHBZBU.js.map → sample-ODUGGSFA.js.map} +0 -0
  72. /package/dist/{search-4KMETZVX.js.map → search-IPE4ISFB.js.map} +0 -0
  73. /package/dist/{sync-warehouse-UWRNUXE7.js.map → sync-warehouse-26L6JDSV.js.map} +0 -0
  74. /package/dist/{tables-V65QUGHK.js.map → tables-K5NAN2WK.js.map} +0 -0
@@ -1,790 +0,0 @@
1
- import "./chunk-S7YQXEKM.js";
2
- import {
3
- SemanticModelBuilder,
4
- SemanticQueryCompiler
5
- } from "./chunk-UND73EOB.js";
6
- import "./chunk-7D4SUZUM.js";
7
-
8
- // ../../packages/advisor/dist/dbt/knowledge.js
9
- import { readFile } from "fs/promises";
10
- import { join, dirname } from "path";
11
- import { fileURLToPath } from "url";
12
- var __dirname = dirname(fileURLToPath(import.meta.url));
13
- var KNOWLEDGE_DIR = join(__dirname, "..", "knowledge");
14
- var KNOWLEDGE_TOPICS = [
15
- "materializations",
16
- "incremental",
17
- "macros",
18
- "testing",
19
- "naming",
20
- "performance",
21
- "sources"
22
- ];
23
- async function loadKnowledge(topic) {
24
- if (!KNOWLEDGE_TOPICS.includes(topic)) {
25
- return `Unknown topic: "${topic}". Available topics: ${KNOWLEDGE_TOPICS.join(", ")}`;
26
- }
27
- const filePath = join(KNOWLEDGE_DIR, `${topic}.md`);
28
- return readFile(filePath, "utf-8");
29
- }
30
- function getKnowledgeOverview() {
31
- return `You have access to a dbt knowledge base via the get_knowledge tool. Available topics:
32
- ${KNOWLEDGE_TOPICS.map((t) => `- ${t}`).join("\n")}
33
-
34
- Use get_knowledge when you need specifics on materializations, incremental strategies, Jinja macros, testing, naming conventions, or performance optimization.`;
35
- }
36
-
37
- // ../../packages/advisor/dist/dbt/project.js
38
- import { readFile as readFile2 } from "fs/promises";
39
- import { join as join2, basename, relative, dirname as dirname2 } from "path";
40
- import fg from "fast-glob";
41
- import { parse as parseYaml } from "yaml";
42
- async function getModelPaths(projectPath) {
43
- const content = await readFile2(join2(projectPath, "dbt_project.yml"), "utf-8");
44
- const parsed = parseYaml(content);
45
- return parsed["model-paths"] ?? parsed.model_paths ?? ["models"];
46
- }
47
- function extractMaterialization(sql) {
48
- const match = sql.match(/materialized\s*=\s*['"](\w+)['"]/);
49
- return match?.[1] ?? "view";
50
- }
51
- function detectLayer(relativePath) {
52
- const parts = relativePath.split("/");
53
- return parts[0] ?? "unknown";
54
- }
55
- function detectPrefix(models) {
56
- const prefixesByLayer = /* @__PURE__ */ new Map();
57
- for (const model of models) {
58
- const underscoreIdx = model.name.indexOf("_");
59
- if (underscoreIdx === -1)
60
- continue;
61
- const prefix = model.name.slice(0, underscoreIdx + 1);
62
- if (!prefixesByLayer.has(model.layer)) {
63
- prefixesByLayer.set(model.layer, /* @__PURE__ */ new Map());
64
- }
65
- const counts = prefixesByLayer.get(model.layer);
66
- counts.set(prefix, (counts.get(prefix) ?? 0) + 1);
67
- }
68
- const result = {};
69
- for (const [layer, counts] of prefixesByLayer) {
70
- let maxCount = 0;
71
- let maxPrefix = "";
72
- for (const [prefix, count] of counts) {
73
- if (count > maxCount) {
74
- maxCount = count;
75
- maxPrefix = prefix;
76
- }
77
- }
78
- if (maxPrefix && maxCount >= 2) {
79
- result[layer] = maxPrefix;
80
- }
81
- }
82
- return result;
83
- }
84
- function detectMaterializations(models) {
85
- const matByLayer = /* @__PURE__ */ new Map();
86
- for (const model of models) {
87
- if (!matByLayer.has(model.layer)) {
88
- matByLayer.set(model.layer, /* @__PURE__ */ new Map());
89
- }
90
- const counts = matByLayer.get(model.layer);
91
- counts.set(model.materialization, (counts.get(model.materialization) ?? 0) + 1);
92
- }
93
- const result = {};
94
- for (const [layer, counts] of matByLayer) {
95
- let maxCount = 0;
96
- let maxMat = "";
97
- for (const [mat, count] of counts) {
98
- if (count > maxCount) {
99
- maxCount = count;
100
- maxMat = mat;
101
- }
102
- }
103
- if (maxMat)
104
- result[layer] = maxMat;
105
- }
106
- return result;
107
- }
108
- async function detectSchemaYmlPattern(projectPath, modelPaths) {
109
- const ymlFiles = [];
110
- for (const mp of modelPaths) {
111
- const pattern = join2(projectPath, mp, "**/*.yml");
112
- const files = await fg(pattern, { ignore: ["**/node_modules/**"] });
113
- ymlFiles.push(...files);
114
- }
115
- if (ymlFiles.length === 0)
116
- return "per-folder";
117
- if (ymlFiles.length === 1)
118
- return "single-file";
119
- const dirs = new Set(ymlFiles.map((f) => dirname2(f)));
120
- return dirs.size > 1 ? "per-folder" : "single-file";
121
- }
122
- async function detectConventions(projectPath) {
123
- const modelPaths = await getModelPaths(projectPath);
124
- const models = await listDbtModels(projectPath);
125
- const folders = [...new Set(models.map((m) => m.layer))].filter((l) => l !== "unknown");
126
- return {
127
- folderStructure: folders,
128
- namingPrefixes: detectPrefix(models),
129
- commonMaterializations: detectMaterializations(models),
130
- schemaYmlPattern: await detectSchemaYmlPattern(projectPath, modelPaths),
131
- testPatterns: []
132
- };
133
- }
134
- async function listDbtModels(projectPath) {
135
- const modelPaths = await getModelPaths(projectPath);
136
- const models = [];
137
- for (const mp of modelPaths) {
138
- const pattern = join2(projectPath, mp, "**/*.sql");
139
- const files = await fg(pattern, { ignore: ["**/node_modules/**"] });
140
- for (const file of files) {
141
- const relPath = relative(join2(projectPath, mp), file);
142
- const name = basename(file, ".sql");
143
- const sql = await readFile2(file, "utf-8");
144
- const materialization = extractMaterialization(sql);
145
- const layer = detectLayer(relPath);
146
- const folder = dirname2(relPath);
147
- models.push({ name, path: relPath, layer, materialization, folder });
148
- }
149
- }
150
- return models;
151
- }
152
- async function readDbtModel(projectPath, modelName) {
153
- const models = await listDbtModels(projectPath);
154
- const model = models.find((m) => m.name === modelName);
155
- if (!model)
156
- return null;
157
- const modelPaths = await getModelPaths(projectPath);
158
- for (const mp of modelPaths) {
159
- const fullPath = join2(projectPath, mp, model.path);
160
- try {
161
- return await readFile2(fullPath, "utf-8");
162
- } catch {
163
- continue;
164
- }
165
- }
166
- return null;
167
- }
168
-
169
- // ../../packages/advisor/dist/tools.js
170
- var TOOL_DEFINITIONS = [
171
- // Read-only tools
172
- {
173
- name: "list_yamchart_models",
174
- description: "List all yamchart SQL models with names, descriptions, parameters, and return columns",
175
- parameters: { type: "object", properties: {}, required: [] }
176
- },
177
- {
178
- name: "list_charts",
179
- description: "List all yamchart charts showing which models they reference and their chart type",
180
- parameters: { type: "object", properties: {}, required: [] }
181
- },
182
- {
183
- name: "get_catalog",
184
- description: "Get the dbt catalog (.yamchart/catalog.md) with upstream table schemas and column metadata",
185
- parameters: { type: "object", properties: {}, required: [] }
186
- },
187
- {
188
- name: "get_warehouse_table",
189
- description: "Get detailed column metadata and sample rows for a specific warehouse table from the cached catalog. Instant \u2014 reads from local catalog, no live query. Use the fully-qualified name (e.g. RAW.PAYMENTS).",
190
- parameters: {
191
- type: "object",
192
- properties: {
193
- table: { type: "string", description: "Fully-qualified table name (e.g. RAW.PAYMENTS, STAGING.CUSTOMERS)" }
194
- },
195
- required: ["table"]
196
- }
197
- },
198
- {
199
- name: "get_warehouse_tables",
200
- description: "Get detailed metadata for multiple warehouse tables at once from the cached catalog.",
201
- parameters: {
202
- type: "object",
203
- properties: {
204
- tables: { type: "array", items: { type: "string" }, description: "List of fully-qualified table names" }
205
- },
206
- required: ["tables"]
207
- }
208
- },
209
- {
210
- name: "introspect_warehouse",
211
- description: "Query the live warehouse. Use for discovering raw tables not yet modeled in dbt.",
212
- parameters: {
213
- type: "object",
214
- properties: {
215
- sql: { type: "string", description: "SQL query to execute (e.g. SHOW TABLES, SELECT * FROM information_schema.columns)" }
216
- },
217
- required: ["sql"]
218
- }
219
- },
220
- {
221
- name: "sample_data",
222
- description: "Preview rows from a table in the warehouse",
223
- parameters: {
224
- type: "object",
225
- properties: {
226
- table: { type: "string", description: "Table name (can be schema-qualified)" },
227
- limit: { type: "number", description: "Number of rows to return (default: 5)" }
228
- },
229
- required: ["table"]
230
- }
231
- },
232
- {
233
- name: "read_dbt_model",
234
- description: "Read the full SQL source of an existing dbt model",
235
- parameters: {
236
- type: "object",
237
- properties: {
238
- model_name: { type: "string", description: "Name of the dbt model to read" }
239
- },
240
- required: ["model_name"]
241
- }
242
- },
243
- {
244
- name: "list_dbt_models",
245
- description: "List all dbt models with their layer (staging/intermediate/marts), materialization, and folder",
246
- parameters: { type: "object", properties: {}, required: [] }
247
- },
248
- {
249
- name: "get_knowledge",
250
- description: "Look up dbt reference documentation on a topic: materializations, incremental, macros, testing, naming, performance",
251
- parameters: {
252
- type: "object",
253
- properties: {
254
- topic: { type: "string", description: "Topic name: materializations, incremental, macros, testing, naming, performance" }
255
- },
256
- required: ["topic"]
257
- }
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
- },
291
- // Action tools
292
- {
293
- name: "propose_model",
294
- description: "Propose a new dbt model. Call this when you have a suggestion to present to the user.",
295
- parameters: {
296
- type: "object",
297
- properties: {
298
- name: { type: "string", description: "Model name (snake_case)" },
299
- description: { type: "string", description: "One-line description of what this model does" },
300
- sql: { type: "string", description: "Full SQL for the model (may include Jinja)" },
301
- layer: { type: "string", description: "dbt layer: staging, intermediate, or marts" },
302
- materialization: { type: "string", description: "Materialization: view, table, or incremental" },
303
- explanation: { type: "string", description: "Why this model is useful (2-3 sentences)" },
304
- subfolder: { type: "string", description: 'Optional subfolder within the layer (e.g. "stripe", "core")' },
305
- columns: {
306
- type: "array",
307
- description: "Column definitions for schema.yml",
308
- items: {
309
- type: "object",
310
- properties: {
311
- name: { type: "string" },
312
- description: { type: "string" },
313
- tests: { type: "array", items: { type: "string" } }
314
- },
315
- required: ["name"]
316
- }
317
- }
318
- },
319
- required: ["name", "description", "sql", "layer", "materialization", "explanation"]
320
- }
321
- },
322
- {
323
- name: "write_dbt_model",
324
- description: "Write a proposed dbt model SQL file to the dbt project. Only call after proposing and user confirmation.",
325
- parameters: {
326
- type: "object",
327
- properties: {
328
- name: { type: "string", description: "Model name (must match a previous proposal)" }
329
- },
330
- required: ["name"]
331
- }
332
- },
333
- {
334
- name: "update_schema_yml",
335
- description: "Add or update the model entry in the appropriate schema.yml file. Only call after writing the model.",
336
- parameters: {
337
- type: "object",
338
- properties: {
339
- name: { type: "string", description: "Model name (must match a written model)" }
340
- },
341
- required: ["name"]
342
- }
343
- }
344
- ];
345
- async function executeToolCall(context, toolName, input) {
346
- switch (toolName) {
347
- case "list_yamchart_models":
348
- return JSON.stringify(context.yamchart.models.map((m) => ({
349
- name: m.name,
350
- description: m.description,
351
- params: m.params,
352
- returns: m.returns
353
- })));
354
- case "list_charts":
355
- return JSON.stringify(context.yamchart.charts.map((c) => ({
356
- name: c.name,
357
- title: c.title,
358
- model: c.model,
359
- type: c.type
360
- })));
361
- case "get_catalog":
362
- return context.yamchart.catalog ?? "No dbt catalog found. Run `yamchart sync-dbt` to create one.";
363
- case "get_warehouse_table": {
364
- if (!context.yamchart.catalogJson) {
365
- return "Warehouse catalog not available. Run `yamchart sync-warehouse` to populate it.";
366
- }
367
- const tableName = input.table.toUpperCase();
368
- const match = context.yamchart.catalogJson.models.find((m) => (m.table || "").toUpperCase() === tableName || m.name.toUpperCase() === tableName);
369
- if (!match) {
370
- return JSON.stringify({ error: `Table not found in catalog: ${input.table}. Use get_catalog to see available tables.` });
371
- }
372
- return JSON.stringify({
373
- name: match.name,
374
- table: match.table,
375
- tableType: match.tableType,
376
- source: match.source,
377
- columns: match.columns,
378
- sampleRows: match.sampleRows || []
379
- });
380
- }
381
- case "get_warehouse_tables": {
382
- if (!context.yamchart.catalogJson) {
383
- return "Warehouse catalog not available. Run `yamchart sync-warehouse` to populate it.";
384
- }
385
- const tableNames = input.tables.map((t) => t.toUpperCase());
386
- const results = tableNames.map((name) => {
387
- const match = context.yamchart.catalogJson.models.find((m) => (m.table || "").toUpperCase() === name || m.name.toUpperCase() === name);
388
- if (!match) {
389
- return { error: `Not found: ${name}` };
390
- }
391
- return {
392
- name: match.name,
393
- table: match.table,
394
- tableType: match.tableType,
395
- source: match.source,
396
- columns: match.columns,
397
- sampleRows: match.sampleRows || []
398
- };
399
- });
400
- return JSON.stringify(results);
401
- }
402
- case "introspect_warehouse": {
403
- if (!context.warehouse) {
404
- return "Warehouse introspection not available. No database connection configured.";
405
- }
406
- const sql = input.sql;
407
- try {
408
- const result = await context.warehouse.executeSql(sql);
409
- return JSON.stringify(result);
410
- } catch (err) {
411
- return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });
412
- }
413
- }
414
- case "sample_data": {
415
- if (!context.warehouse) {
416
- return "Warehouse not available. No database connection configured.";
417
- }
418
- const table = input.table;
419
- const limit = input.limit ?? 5;
420
- try {
421
- const result = await context.warehouse.executeSql(`SELECT * FROM ${table} LIMIT ${limit}`);
422
- return JSON.stringify(result);
423
- } catch (err) {
424
- return JSON.stringify({ error: err instanceof Error ? err.message : String(err) });
425
- }
426
- }
427
- case "read_dbt_model": {
428
- const modelName = input.model_name;
429
- const sql = await readDbtModel(context.dbt.projectPath, modelName);
430
- if (!sql) {
431
- return JSON.stringify({ error: `Model not found: ${modelName}` });
432
- }
433
- return JSON.stringify({ name: modelName, sql });
434
- }
435
- case "list_dbt_models":
436
- return JSON.stringify(context.dbt.models.map((m) => ({
437
- name: m.name,
438
- path: m.path,
439
- layer: m.layer,
440
- materialization: m.materialization,
441
- folder: m.folder
442
- })));
443
- case "get_knowledge": {
444
- const topic = input.topic;
445
- return loadKnowledge(topic);
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
- }
481
- case "propose_model":
482
- return JSON.stringify({
483
- status: "proposed",
484
- name: input.name,
485
- description: input.description,
486
- sql: input.sql,
487
- layer: input.layer,
488
- materialization: input.materialization,
489
- explanation: input.explanation,
490
- subfolder: input.subfolder,
491
- columns: input.columns
492
- });
493
- case "write_dbt_model":
494
- return JSON.stringify({
495
- status: "pending_confirmation",
496
- name: input.name,
497
- message: "Model write requested. Waiting for user confirmation."
498
- });
499
- case "update_schema_yml":
500
- return JSON.stringify({
501
- status: "pending_confirmation",
502
- name: input.name,
503
- message: "Schema.yml update requested. Waiting for user confirmation."
504
- });
505
- default:
506
- return JSON.stringify({ error: `Unknown tool: ${toolName}` });
507
- }
508
- }
509
-
510
- // ../../packages/advisor/dist/agent.js
511
- var 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.
512
-
513
- Think like a senior data engineer. Your goals:
514
- - Understand what the BI layer needs (charts, filters, drill-downs, date ranges)
515
- - Identify gaps in the dbt project (missing models, incomplete staging, opportunities for pre-aggregation)
516
- - Suggest new dbt models that serve the BI layer better
517
- - Follow the project's existing conventions (folder structure, naming, materializations)
518
-
519
- When proposing models:
520
- - Match the project's naming conventions (detect and follow existing prefixes like stg_, fct_, dim_)
521
- - Place models in the correct layer and folder
522
- - Choose appropriate materializations
523
- - Include column descriptions and tests in proposals
524
- - Explain WHY the model helps, not just WHAT it does
525
- - Use ref() and source() macros correctly
526
-
527
- When working with cross-database tables:
528
- - If a table lives outside the primary analytics database, recommend creating a dbt source definition in sources.yml
529
- - Follow the pattern: source \u2192 staging model \u2192 downstream refs
530
- - Use get_knowledge('sources') for detailed source patterns
531
- - Check the warehouse catalog (get_warehouse_tables) to identify tables in other databases
532
-
533
- When in audit mode:
534
- - Evaluate: coverage gaps, convention violations, materialization mismatches, missing tests
535
- - Rank suggestions by impact
536
- - Be concise \u2014 focus on actionable improvements
537
-
538
- ${getKnowledgeOverview()}
539
-
540
- When you have a suggestion, call propose_model with the full SQL and metadata. Do NOT call write_dbt_model or update_schema_yml directly \u2014 the user will be prompted to confirm before writing.`;
541
- var MAX_TOOL_ROUNDS = 15;
542
- var AdvisorAgent = class {
543
- provider;
544
- constructor(provider) {
545
- this.provider = provider;
546
- }
547
- async run(context, userMessages) {
548
- const proposals = [];
549
- const messages = [...userMessages];
550
- const systemPrompt = this.buildSystemPrompt(context);
551
- for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
552
- const response = await this.provider.chat({
553
- system: systemPrompt,
554
- messages,
555
- tools: TOOL_DEFINITIONS
556
- });
557
- const textBlocks = response.content.filter((b) => b.type === "text");
558
- const toolUseBlocks = response.content.filter((b) => b.type === "tool_use");
559
- if (toolUseBlocks.length === 0) {
560
- const responseText = textBlocks.map((b) => b.text).join("\n");
561
- return { response: responseText, proposals, messages };
562
- }
563
- messages.push({ role: "assistant", content: response.content });
564
- const toolResults = [];
565
- for (const toolUse of toolUseBlocks) {
566
- const result = await executeToolCall(context, toolUse.name, toolUse.input);
567
- if (toolUse.name === "propose_model") {
568
- const parsed = JSON.parse(result);
569
- proposals.push({
570
- name: parsed.name,
571
- description: parsed.description,
572
- sql: toolUse.input.sql,
573
- layer: toolUse.input.layer,
574
- materialization: toolUse.input.materialization,
575
- explanation: toolUse.input.explanation,
576
- subfolder: toolUse.input.subfolder,
577
- columns: toolUse.input.columns
578
- });
579
- }
580
- toolResults.push({
581
- type: "tool_result",
582
- tool_use_id: toolUse.id,
583
- content: result
584
- });
585
- }
586
- messages.push({ role: "user", content: toolResults });
587
- }
588
- return {
589
- response: "Reached maximum tool call rounds. Here are the suggestions gathered so far.",
590
- proposals,
591
- messages
592
- };
593
- }
594
- buildSystemPrompt(context) {
595
- const parts = [SYSTEM_PROMPT];
596
- parts.push(`
597
- ## Current Project Summary`);
598
- parts.push(`- Yamchart: ${context.yamchart.models.length} SQL models, ${context.yamchart.charts.length} charts, ${context.yamchart.dashboards.length} dashboards`);
599
- parts.push(`- dbt project: "${context.dbt.projectName}" at ${context.dbt.projectPath}`);
600
- parts.push(`- dbt models: ${context.dbt.models.length} (layers: ${context.dbt.conventions.folderStructure.join(", ") || "none detected"})`);
601
- if (Object.keys(context.dbt.conventions.namingPrefixes).length > 0) {
602
- const prefixes = Object.entries(context.dbt.conventions.namingPrefixes).map(([layer, prefix]) => `${layer}: ${prefix}`).join(", ");
603
- parts.push(`- Naming prefixes: ${prefixes}`);
604
- }
605
- if (Object.keys(context.dbt.conventions.commonMaterializations).length > 0) {
606
- const mats = Object.entries(context.dbt.conventions.commonMaterializations).map(([layer, mat]) => `${layer}: ${mat}`).join(", ");
607
- parts.push(`- Materializations: ${mats}`);
608
- }
609
- parts.push(`- Schema.yml pattern: ${context.dbt.conventions.schemaYmlPattern}`);
610
- parts.push(`- Catalog: ${context.yamchart.catalog ? "available" : "not synced"}`);
611
- parts.push(`- Warehouse: ${context.warehouse ? `connected (${context.warehouse.connectionType})` : "not connected"}`);
612
- return parts.join("\n");
613
- }
614
- };
615
-
616
- // ../../packages/advisor/dist/providers/anthropic.js
617
- import Anthropic from "@anthropic-ai/sdk";
618
- var AnthropicProvider = class {
619
- client;
620
- model;
621
- constructor(apiKey, model = "claude-sonnet-4-5-20250929") {
622
- this.client = new Anthropic({ apiKey });
623
- this.model = model;
624
- }
625
- async chat(options) {
626
- const tools = options.tools.map((t) => ({
627
- name: t.name,
628
- description: t.description,
629
- input_schema: {
630
- type: "object",
631
- properties: t.parameters.properties,
632
- required: t.parameters.required ?? []
633
- }
634
- }));
635
- const messages = options.messages.map((m) => {
636
- if (typeof m.content === "string") {
637
- return { role: m.role, content: m.content };
638
- }
639
- const blocks = m.content.map((block) => {
640
- if (block.type === "text") {
641
- return { type: "text", text: block.text };
642
- }
643
- if (block.type === "tool_use") {
644
- const tu = block;
645
- return { type: "tool_use", id: tu.id, name: tu.name, input: tu.input };
646
- }
647
- if (block.type === "tool_result") {
648
- const tr = block;
649
- return { type: "tool_result", tool_use_id: tr.tool_use_id, content: tr.content };
650
- }
651
- throw new Error(`Unknown block type: ${block.type}`);
652
- });
653
- return { role: m.role, content: blocks };
654
- });
655
- const response = await this.client.messages.create({
656
- model: this.model,
657
- max_tokens: options.maxTokens ?? 4096,
658
- system: options.system,
659
- tools,
660
- messages
661
- });
662
- const content = response.content.map((block) => {
663
- if (block.type === "text") {
664
- return { type: "text", text: block.text };
665
- }
666
- if (block.type === "tool_use") {
667
- return {
668
- type: "tool_use",
669
- id: block.id,
670
- name: block.name,
671
- input: block.input
672
- };
673
- }
674
- throw new Error(`Unexpected block type: ${block.type}`);
675
- });
676
- return {
677
- content,
678
- stopReason: response.stop_reason === "tool_use" ? "tool_use" : "end"
679
- };
680
- }
681
- };
682
-
683
- // ../../packages/advisor/dist/dbt/writer.js
684
- import { readFile as readFile3, writeFile, mkdir, access } from "fs/promises";
685
- import { join as join3, dirname as dirname3 } from "path";
686
- import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
687
- function buildModelPath(modelName, layer, conventions, subfolder) {
688
- const effectiveLayer = layer ?? (conventions.folderStructure.includes("marts") ? "marts" : conventions.folderStructure[0] ?? "models");
689
- const parts = ["models", effectiveLayer];
690
- if (subfolder)
691
- parts.push(subfolder);
692
- parts.push(`${modelName}.sql`);
693
- return parts.join("/");
694
- }
695
- function formatModelSql(options) {
696
- const lines = [];
697
- if (options.materialization !== "view") {
698
- const configParts = [`materialized='${options.materialization}'`];
699
- if (options.tags && options.tags.length > 0) {
700
- configParts.push(`tags=[${options.tags.map((t) => `'${t}'`).join(", ")}]`);
701
- }
702
- lines.push(`{{
703
- config(
704
- ${configParts.join(",\n ")}
705
- )
706
- }}
707
- `);
708
- }
709
- lines.push(options.sql);
710
- return lines.join("\n");
711
- }
712
- function buildSchemaYmlEntry(options) {
713
- const model = {
714
- name: options.name,
715
- description: options.description
716
- };
717
- if (options.columns && options.columns.length > 0) {
718
- model.columns = options.columns.map((col) => {
719
- const entry = { name: col.name };
720
- if (col.description)
721
- entry.description = col.description;
722
- if (col.tests && col.tests.length > 0)
723
- entry.tests = col.tests;
724
- return entry;
725
- });
726
- }
727
- return stringifyYaml({ models: [model] }, { indent: 2 });
728
- }
729
- async function writeDbtModel(projectPath, modelPath, sql) {
730
- const fullPath = join3(projectPath, modelPath);
731
- await mkdir(dirname3(fullPath), { recursive: true });
732
- await writeFile(fullPath, sql + "\n", "utf-8");
733
- return fullPath;
734
- }
735
- async function updateSchemaYml(projectPath, schemaPath, entry) {
736
- const fullPath = join3(projectPath, schemaPath);
737
- let existing = {
738
- version: 2,
739
- models: []
740
- };
741
- try {
742
- await access(fullPath);
743
- const content = await readFile3(fullPath, "utf-8");
744
- existing = parseYaml2(content);
745
- if (!existing.models)
746
- existing.models = [];
747
- } catch {
748
- await mkdir(dirname3(fullPath), { recursive: true });
749
- }
750
- const idx = existing.models.findIndex((m) => m.name === entry.name);
751
- const modelEntry = {
752
- name: entry.name,
753
- description: entry.description
754
- };
755
- if (entry.columns && entry.columns.length > 0) {
756
- modelEntry.columns = entry.columns.map((col) => {
757
- const c = { name: col.name };
758
- if (col.description)
759
- c.description = col.description;
760
- if (col.tests && col.tests.length > 0)
761
- c.tests = col.tests;
762
- return c;
763
- });
764
- }
765
- if (idx >= 0) {
766
- existing.models[idx] = modelEntry;
767
- } else {
768
- existing.models.push(modelEntry);
769
- }
770
- await writeFile(fullPath, stringifyYaml(existing, { indent: 2 }), "utf-8");
771
- return fullPath;
772
- }
773
- export {
774
- AdvisorAgent,
775
- AnthropicProvider,
776
- KNOWLEDGE_TOPICS,
777
- SYSTEM_PROMPT,
778
- TOOL_DEFINITIONS,
779
- buildModelPath,
780
- buildSchemaYmlEntry,
781
- detectConventions,
782
- formatModelSql,
783
- getKnowledgeOverview,
784
- listDbtModels,
785
- loadKnowledge,
786
- readDbtModel,
787
- updateSchemaYml,
788
- writeDbtModel
789
- };
790
- //# sourceMappingURL=dist-MNXSMGV6.js.map