yamchart 0.8.6 → 0.8.8

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 (56) hide show
  1. package/dist/{advisor-54JBE2EV.js → advisor-IJBW56F5.js} +3 -3
  2. package/dist/agent-2DFNL2UB.js +8 -0
  3. package/dist/{chunk-GLCEDWGH.js → chunk-232AMQ5T.js} +2 -2
  4. package/dist/{chunk-NCPWAWIM.js → chunk-34ZVFILD.js} +3 -3
  5. package/dist/chunk-77U26A7F.js +677 -0
  6. package/dist/chunk-77U26A7F.js.map +1 -0
  7. package/dist/{chunk-YMQ4PWVJ.js → chunk-B5ZLCKNF.js} +2 -2
  8. package/dist/{chunk-C7A7TKSY.js → chunk-D3ELUYYE.js} +26 -3
  9. package/dist/chunk-D3ELUYYE.js.map +1 -0
  10. package/dist/{connection-utils-MXEF6X7K.js → connection-utils-ZLSV5OLQ.js} +3 -3
  11. package/dist/{describe-XKLBZEWG.js → describe-VO4CEYL2.js} +4 -4
  12. package/dist/{dev-Z2R2DBWO.js → dev-JUA73B6D.js} +534 -46
  13. package/dist/dev-JUA73B6D.js.map +1 -0
  14. package/dist/{dist-LJR7TAW4.js → dist-PINRLZVT.js} +4 -2
  15. package/dist/index.js +20 -20
  16. package/dist/public/assets/{EventManagement-D4H5tTvO.js → EventManagement-DQY1Sic0.js} +2 -2
  17. package/dist/public/assets/ExplorePage-C9M-fQ3Y.js +1 -0
  18. package/dist/public/assets/{LoginPage-DMhioiI7.js → LoginPage-XYLwfbfw.js} +1 -1
  19. package/dist/public/assets/PublicViewer-CZJYS0wF.js +1 -0
  20. package/dist/public/assets/{SetupWizard-CZTQ6YDE.js → SetupWizard-fle7FC4b.js} +1 -1
  21. package/dist/public/assets/{ShareManagement-BFm5OVCy.js → ShareManagement-b3j4jzn3.js} +1 -1
  22. package/dist/public/assets/{UserManagement-BbbEGHYl.js → UserManagement-DwZ-AaqI.js} +1 -1
  23. package/dist/public/assets/{index-B_fusLA_.css → index-CRcgti3B.css} +1 -1
  24. package/dist/public/assets/index-m_Jm3sB1.js +188 -0
  25. package/dist/public/assets/{index.es-D6Nmj80H.js → index.es-Bd2YVqtj.js} +1 -1
  26. package/dist/public/assets/{jspdf.es.min-Cm41KBzd.js → jspdf.es.min-CpRfbJ_H.js} +3 -3
  27. package/dist/public/index.html +2 -2
  28. package/dist/{query-MXMFI5TB.js → query-PXJMSDKR.js} +3 -3
  29. package/dist/{sample-HDPYNAKS.js → sample-M24H3M73.js} +3 -3
  30. package/dist/{search-6CPEPJTI.js → search-UCJS7X5D.js} +4 -4
  31. package/dist/{source-resolver-PCASPRSD.js → source-resolver-RXNB7A64.js} +4 -4
  32. package/dist/source-resolver-RXNB7A64.js.map +1 -0
  33. package/dist/{sync-warehouse-XC7YYZKC.js → sync-warehouse-S75DWVTG.js} +3 -3
  34. package/dist/{tables-26PNVZIC.js → tables-W3M3JDJO.js} +4 -4
  35. package/dist/templates/default/docs/yamchart-reference.md +56 -0
  36. package/dist/templates/default/yamchart.yaml +3 -0
  37. package/dist/{test-APA44AIF.js → test-67AXD5PI.js} +3 -3
  38. package/package.json +4 -3
  39. package/dist/chunk-C7A7TKSY.js.map +0 -1
  40. package/dist/dev-Z2R2DBWO.js.map +0 -1
  41. package/dist/public/assets/PublicViewer-B9JKXczX.js +0 -1
  42. package/dist/public/assets/index-h1PV1M6v.js +0 -187
  43. /package/dist/{advisor-54JBE2EV.js.map → advisor-IJBW56F5.js.map} +0 -0
  44. /package/dist/{connection-utils-MXEF6X7K.js.map → agent-2DFNL2UB.js.map} +0 -0
  45. /package/dist/{chunk-GLCEDWGH.js.map → chunk-232AMQ5T.js.map} +0 -0
  46. /package/dist/{chunk-NCPWAWIM.js.map → chunk-34ZVFILD.js.map} +0 -0
  47. /package/dist/{chunk-YMQ4PWVJ.js.map → chunk-B5ZLCKNF.js.map} +0 -0
  48. /package/dist/{dist-LJR7TAW4.js.map → connection-utils-ZLSV5OLQ.js.map} +0 -0
  49. /package/dist/{describe-XKLBZEWG.js.map → describe-VO4CEYL2.js.map} +0 -0
  50. /package/dist/{source-resolver-PCASPRSD.js.map → dist-PINRLZVT.js.map} +0 -0
  51. /package/dist/{query-MXMFI5TB.js.map → query-PXJMSDKR.js.map} +0 -0
  52. /package/dist/{sample-HDPYNAKS.js.map → sample-M24H3M73.js.map} +0 -0
  53. /package/dist/{search-6CPEPJTI.js.map → search-UCJS7X5D.js.map} +0 -0
  54. /package/dist/{sync-warehouse-XC7YYZKC.js.map → sync-warehouse-S75DWVTG.js.map} +0 -0
  55. /package/dist/{tables-26PNVZIC.js.map → tables-W3M3JDJO.js.map} +0 -0
  56. /package/dist/{test-APA44AIF.js.map → test-67AXD5PI.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadEnvFile,
3
3
  validateProject
4
- } from "./chunk-GLCEDWGH.js";
4
+ } from "./chunk-232AMQ5T.js";
5
5
  import {
6
6
  box,
7
7
  detail,
@@ -23,7 +23,11 @@ import {
23
23
  SemanticQuerySchema,
24
24
  deepMerge,
25
25
  resolveProjectConfig
26
- } from "./chunk-C7A7TKSY.js";
26
+ } from "./chunk-D3ELUYYE.js";
27
+ import {
28
+ StreamingChatAgent,
29
+ filterCatalogEntries
30
+ } from "./chunk-77U26A7F.js";
27
31
  import {
28
32
  AuthDatabase,
29
33
  generateSessionToken,
@@ -63,7 +67,7 @@ import {
63
67
  import "./chunk-DGUM43GV.js";
64
68
 
65
69
  // src/commands/dev.ts
66
- import { resolve } from "path";
70
+ import { resolve as resolve2 } from "path";
67
71
  import { homedir } from "os";
68
72
 
69
73
  // ../server/dist/server.js
@@ -76,6 +80,257 @@ import { readFile, readdir, access } from "fs/promises";
76
80
  import { join, extname, relative, dirname } from "path";
77
81
  import { parse as parseYaml } from "yaml";
78
82
  import { watch } from "chokidar";
83
+
84
+ // ../../packages/chat/dist/registry.js
85
+ import { parse } from "yaml";
86
+
87
+ // ../../packages/chat/dist/agents/dashboard-analyst.js
88
+ var DASHBOARD_ANALYST = {
89
+ name: "dashboard-analyst",
90
+ title: "Dashboard Analyst",
91
+ description: "Summarizes dashboards, explains trends, answers data questions, and can apply filters to the dashboard.",
92
+ systemPrompt: `You are an AI dashboard analyst for a business intelligence platform.
93
+
94
+ Your job is to help users understand their data by:
95
+ - Summarizing what a dashboard or chart shows
96
+ - Explaining trends, outliers, and patterns in the data
97
+ - Answering questions about metrics and KPIs
98
+ - Suggesting and applying filters to explore data
99
+ - Running ad-hoc SQL to explore data beyond existing charts
100
+
101
+ ## Rules
102
+ - Be concise. Dashboard users want quick answers, not essays.
103
+ - Use numbers and percentages when discussing data.
104
+ - When you query data, summarize the key findings \u2014 don't dump raw rows.
105
+ - If asked about a trend, explain the direction, magnitude, and possible causes.
106
+ - When suggesting filters, explain what you expect to see.
107
+ - Use the apply_filter tool when the user asks to filter or drill down.
108
+ - If the existing charts don't have the data needed, use run_sql to query the database directly.
109
+ - Use call_agent to delegate to specialized agents when you need expertise you don't have.
110
+ - Use suggest_actions to offer follow-up exploration or save options after answering.
111
+ - If you don't have enough data to answer, say so and suggest what to query.
112
+
113
+ ## Data Visualization in Responses
114
+ When you have tabular data to share, use these markdown code fences:
115
+
116
+ For charts (line, bar, pie, scatter):
117
+ \`\`\`chart
118
+ {"type":"line","data":[{"date":"2025-01-01","value":100},...],"x":"date","y":"value","title":"Optional Title"}
119
+ \`\`\`
120
+
121
+ For data tables:
122
+ \`\`\`data
123
+ {"columns":[{"name":"date","type":"date"},{"name":"value","type":"number"}],"rows":[{"date":"2025-01-01","value":100},...]}
124
+ \`\`\`
125
+
126
+ Choose charts for trends and comparisons, tables for detailed breakdowns. Keep data concise \u2014 summarize large result sets.`,
127
+ tools: ["query_model", "get_chart_config", "get_dashboard_summary", "apply_filter", "compare_periods", "run_sql", "call_agent", "get_catalog_tables", "suggest_actions", "save_model", "save_chart", "add_to_dashboard"],
128
+ builtIn: true
129
+ };
130
+
131
+ // ../../packages/chat/dist/agents/sql-explorer.js
132
+ var SQL_EXPLORER = {
133
+ name: "sql-explorer",
134
+ title: "SQL Explorer",
135
+ description: "Runs ad-hoc SQL queries against the connected database for deep data exploration and period comparisons.",
136
+ systemPrompt: `You are a SQL expert helping users explore their data warehouse.
137
+
138
+ Your job is to:
139
+ - Write and execute SQL queries to answer user questions
140
+ - Compare data across time periods
141
+ - Find specific records or aggregations
142
+ - Explain query results clearly
143
+
144
+ ## Rules
145
+ - Always LIMIT your queries (default: 50 rows) to avoid large payloads.
146
+ - Use clear column aliases so results are readable.
147
+ - When comparing periods, use the compare_periods tool for models, or write explicit SQL for ad-hoc comparisons.
148
+ - Explain what your query does before showing results.
149
+ - If a query fails, explain the error and try a corrected version.
150
+ - Never run destructive queries (INSERT, UPDATE, DELETE, DROP, etc.).
151
+
152
+ ## Data Visualization in Responses
153
+ When you have tabular data to share, use these markdown code fences:
154
+
155
+ For charts (line, bar, pie, scatter):
156
+ \`\`\`chart
157
+ {"type":"line","data":[{"date":"2025-01-01","value":100},...],"x":"date","y":"value","title":"Optional Title"}
158
+ \`\`\`
159
+
160
+ For data tables:
161
+ \`\`\`data
162
+ {"columns":[{"name":"date","type":"date"},{"name":"value","type":"number"}],"rows":[{"date":"2025-01-01","value":100},...]}
163
+ \`\`\`
164
+
165
+ Choose charts for trends and comparisons, tables for detailed breakdowns. Keep data concise \u2014 summarize large result sets.`,
166
+ tools: ["query_model", "run_sql", "compare_periods", "get_chart_config", "call_agent", "get_catalog_tables", "suggest_actions", "save_model", "save_chart"],
167
+ builtIn: true
168
+ };
169
+
170
+ // ../../packages/chat/dist/agents/data-explorer.js
171
+ var DATA_EXPLORER = {
172
+ name: "data-explorer",
173
+ title: "Data Explorer",
174
+ description: "Open-ended data exploration, visualization, and dashboard building.",
175
+ systemPrompt: `You are an AI data explorer for a business intelligence platform.
176
+
177
+ Your job is to help users explore their data warehouse, build visualizations, and create dashboards \u2014 starting from curiosity and ending with saved, reusable charts.
178
+
179
+ ## Discovery First
180
+ - Always start with get_catalog_tables to understand what data is available before writing SQL.
181
+ - Prefer querying named models (query_model) over raw SQL when a model already exists.
182
+ - When no model exists, use run_sql to explore \u2014 then offer to save the query as a model.
183
+
184
+ ## Rules
185
+ - All SQL must be read-only (SELECT only). Never run INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, or CREATE.
186
+ - Always LIMIT queries to 50 rows by default. Use LIMIT explicitly.
187
+ - Use clear column aliases so results are readable.
188
+ - When a query fails, explain the error and try a corrected version.
189
+ - Explain what you're querying and why before showing results.
190
+
191
+ ## Proactive Visualization
192
+ After retrieving data, always visualize it \u2014 don't just dump raw rows. Choose the right form:
193
+ - Trends over time \u2192 line chart
194
+ - Comparisons across categories \u2192 bar chart
195
+ - Part-to-whole \u2192 pie chart
196
+ - Single key metric \u2192 show as bold text or KPI
197
+ - Detailed breakdowns \u2192 data table
198
+
199
+ For charts (line, bar, pie, scatter):
200
+ \`\`\`chart
201
+ {"type":"line","data":[{"date":"2025-01-01","value":100},...],"x":"date","y":"value","title":"Optional Title"}
202
+ \`\`\`
203
+
204
+ For data tables:
205
+ \`\`\`data
206
+ {"columns":[{"name":"date","type":"date"},{"name":"value","type":"number"}],"rows":[{"date":"2025-01-01","value":100},...]}
207
+ \`\`\`
208
+
209
+ Keep visualizations concise \u2014 summarize large result sets rather than showing every row.
210
+
211
+ ## Saving Work
212
+ When a user wants to keep a query or chart:
213
+ 1. Use save_model to create a reusable SQL model file.
214
+ 2. Use save_chart to create a chart YAML referencing that model.
215
+ 3. Use create_dashboard to assemble saved charts into a new dashboard.
216
+ 4. After saving, use suggest_actions to offer navigation or further exploration.
217
+
218
+ ## Suggesting Next Steps
219
+ Always use suggest_actions after answering a question to offer natural follow-up options:
220
+ - Explore related dimensions or time periods
221
+ - Save the current query as a model
222
+ - Create a chart from the data
223
+ - Add the chart to a dashboard
224
+
225
+ ## Collaboration
226
+ Use call_agent to delegate to specialized agents when needed:
227
+ - Dashboard Analyst for questions about existing dashboards
228
+ - SQL Explorer for complex multi-step SQL investigations`,
229
+ tools: ["run_sql", "query_model", "get_catalog_tables", "compare_periods", "save_model", "save_chart", "create_dashboard", "suggest_actions", "call_agent"],
230
+ builtIn: true
231
+ };
232
+
233
+ // ../../packages/chat/dist/registry.js
234
+ var AgentRegistry = class {
235
+ agents = /* @__PURE__ */ new Map();
236
+ constructor() {
237
+ this.agents.set(DASHBOARD_ANALYST.name, DASHBOARD_ANALYST);
238
+ this.agents.set(SQL_EXPLORER.name, SQL_EXPLORER);
239
+ this.agents.set(DATA_EXPLORER.name, DATA_EXPLORER);
240
+ }
241
+ getAgent(name) {
242
+ return this.agents.get(name);
243
+ }
244
+ listAgents() {
245
+ return Array.from(this.agents.values());
246
+ }
247
+ registerAgent(config) {
248
+ this.agents.set(config.name, config);
249
+ }
250
+ loadFromYaml(yamlContent, filePath, onWarning) {
251
+ try {
252
+ const raw = parse(yamlContent);
253
+ if (!raw || typeof raw !== "object") {
254
+ onWarning?.(`Skipping ${filePath}: not a valid YAML object`);
255
+ return;
256
+ }
257
+ if (!raw.name || typeof raw.name !== "string") {
258
+ onWarning?.(`Skipping ${filePath}: missing required "name" field`);
259
+ return;
260
+ }
261
+ if (!raw.description || typeof raw.description !== "string") {
262
+ onWarning?.(`Skipping ${filePath}: missing required "description" field`);
263
+ return;
264
+ }
265
+ if (!raw.system_prompt || typeof raw.system_prompt !== "string") {
266
+ onWarning?.(`Skipping ${filePath}: missing required "system_prompt" field`);
267
+ return;
268
+ }
269
+ const config = {
270
+ name: raw.name,
271
+ title: raw.title ?? raw.name,
272
+ description: raw.description,
273
+ systemPrompt: raw.system_prompt,
274
+ tools: Array.isArray(raw.tools) ? raw.tools.filter((t) => typeof t === "string") : [],
275
+ builtIn: false,
276
+ model: typeof raw.model === "string" ? raw.model : void 0,
277
+ models: Array.isArray(raw.models) ? raw.models.filter((m) => typeof m === "string") : void 0
278
+ };
279
+ this.agents.set(config.name, config);
280
+ } catch (err) {
281
+ onWarning?.(`Skipping ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
282
+ }
283
+ }
284
+ clearProjectAgents() {
285
+ for (const [name, config] of this.agents) {
286
+ if (!config.builtIn)
287
+ this.agents.delete(name);
288
+ }
289
+ }
290
+ };
291
+
292
+ // ../../packages/chat/dist/router.js
293
+ var SQL_PATTERNS = [
294
+ /\bselect\b.*\bfrom\b/i,
295
+ /\brun\s+(a\s+)?query\b/i,
296
+ /\bwrite\s+(a\s+)?query\b/i,
297
+ /\bshow\s+(me\s+)?the\s+sql\b/i,
298
+ /\bexecute\s+sql\b/i,
299
+ /\bjoin\b.*\btable/i
300
+ ];
301
+ var DEFAULT_AGENT = "dashboard-analyst";
302
+ var RouterAgent = class {
303
+ registry;
304
+ constructor(registry) {
305
+ this.registry = registry;
306
+ }
307
+ selectAgent(message, context, explicitAgent) {
308
+ if (explicitAgent) {
309
+ const agent = this.registry.getAgent(explicitAgent);
310
+ if (agent)
311
+ return agent;
312
+ }
313
+ if (context?.type === "explore") {
314
+ return this.registry.getAgent("data-explorer") || this.registry.getAgent(DEFAULT_AGENT);
315
+ }
316
+ if (SQL_PATTERNS.some((pattern) => pattern.test(message))) {
317
+ const sqlExplorer = this.registry.getAgent("sql-explorer");
318
+ if (sqlExplorer)
319
+ return sqlExplorer;
320
+ }
321
+ return this.registry.getAgent(DEFAULT_AGENT);
322
+ }
323
+ };
324
+
325
+ // ../../packages/chat/dist/stream.js
326
+ function formatSSEEvent(event) {
327
+ return `event: ${event.type}
328
+ data: ${JSON.stringify(event.data)}
329
+
330
+ `;
331
+ }
332
+
333
+ // ../server/dist/services/config-loader.js
79
334
  var ConfigLoader = class {
80
335
  projectDir;
81
336
  project = null;
@@ -92,6 +347,7 @@ var ConfigLoader = class {
92
347
  validationErrors = /* @__PURE__ */ new Map();
93
348
  watcher = null;
94
349
  onChangeCallbacks = [];
350
+ agentRegistry = new AgentRegistry();
95
351
  env;
96
352
  constructor(projectDir, env) {
97
353
  this.projectDir = projectDir;
@@ -116,6 +372,7 @@ var ConfigLoader = class {
116
372
  await this.loadDashboards();
117
373
  await this.loadSchedules();
118
374
  await this.loadEvents();
375
+ await this.loadAgents();
119
376
  }
120
377
  async loadProject() {
121
378
  const projectPath = join(this.projectDir, "yamchart.yaml");
@@ -321,6 +578,20 @@ var ConfigLoader = class {
321
578
  console.warn(`Invalid events.yaml: ${result.error.message}`);
322
579
  }
323
580
  }
581
+ async loadAgents() {
582
+ const agentsDir = join(this.projectDir, "agents");
583
+ this.agentRegistry.clearProjectAgents();
584
+ try {
585
+ const files = await readdir(agentsDir);
586
+ for (const file of files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"))) {
587
+ const content = await readFile(join(agentsDir, file), "utf-8");
588
+ this.agentRegistry.loadFromYaml(content, `agents/${file}`, (msg) => {
589
+ console.warn(msg);
590
+ });
591
+ }
592
+ } catch {
593
+ }
594
+ }
324
595
  startWatching() {
325
596
  if (this.watcher)
326
597
  return;
@@ -332,7 +603,8 @@ var ConfigLoader = class {
332
603
  join(this.projectDir, "models"),
333
604
  join(this.projectDir, "dashboards"),
334
605
  join(this.projectDir, "schedules"),
335
- join(this.projectDir, "events.yaml")
606
+ join(this.projectDir, "events.yaml"),
607
+ join(this.projectDir, "agents")
336
608
  ];
337
609
  this.watcher = watch(watchPaths, {
338
610
  ignored: /(^|[\/\\])\../,
@@ -453,6 +725,9 @@ Fix: run "ulimit -n 10240" before starting yamchart dev, or add it to your shell
453
725
  getValidationErrors() {
454
726
  return this.validationErrors;
455
727
  }
728
+ getAgentRegistry() {
729
+ return this.agentRegistry;
730
+ }
456
731
  };
457
732
 
458
733
  // ../server/dist/services/cache.js
@@ -1485,8 +1760,8 @@ async function semanticRoutes(fastify, options) {
1485
1760
  });
1486
1761
  }
1487
1762
  const { writeFileSync, mkdirSync } = await import("fs");
1488
- const { join: join7, dirname: dirname3 } = await import("path");
1489
- const fullPath = join7(projectDir, filePath);
1763
+ const { join: join9, dirname: dirname3 } = await import("path");
1764
+ const fullPath = join9(projectDir, filePath);
1490
1765
  mkdirSync(dirname3(fullPath), { recursive: true });
1491
1766
  writeFileSync(fullPath, sql, "utf-8");
1492
1767
  return { saved: true, path: filePath };
@@ -1599,7 +1874,7 @@ var SlackNotifier = class {
1599
1874
  let response = await fetch(webhookUrl, options);
1600
1875
  if (!response.ok) {
1601
1876
  if (this.retryDelayMs > 0) {
1602
- await new Promise((resolve2) => setTimeout(resolve2, this.retryDelayMs));
1877
+ await new Promise((resolve3) => setTimeout(resolve3, this.retryDelayMs));
1603
1878
  }
1604
1879
  response = await fetch(webhookUrl, options);
1605
1880
  if (!response.ok) {
@@ -1858,11 +2133,11 @@ function __rest(s, e) {
1858
2133
  }
1859
2134
  function __awaiter(thisArg, _arguments, P, generator) {
1860
2135
  function adopt(value) {
1861
- return value instanceof P ? value : new P(function(resolve2) {
1862
- resolve2(value);
2136
+ return value instanceof P ? value : new P(function(resolve3) {
2137
+ resolve3(value);
1863
2138
  });
1864
2139
  }
1865
- return new (P || (P = Promise))(function(resolve2, reject) {
2140
+ return new (P || (P = Promise))(function(resolve3, reject) {
1866
2141
  function fulfilled(value) {
1867
2142
  try {
1868
2143
  step(generator.next(value));
@@ -1878,7 +2153,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
1878
2153
  }
1879
2154
  }
1880
2155
  function step(result) {
1881
- result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
2156
+ result.done ? resolve3(result.value) : adopt(result.value).then(fulfilled, rejected);
1882
2157
  }
1883
2158
  step((generator = generator.apply(thisArg, _arguments || [])).next());
1884
2159
  });
@@ -4409,15 +4684,15 @@ var RealtimeChannel = class _RealtimeChannel {
4409
4684
  }
4410
4685
  }
4411
4686
  } else {
4412
- return new Promise((resolve2) => {
4687
+ return new Promise((resolve3) => {
4413
4688
  var _a2, _b2, _c;
4414
4689
  const push = this._push(args.type, args, opts.timeout || this.timeout);
4415
4690
  if (args.type === "broadcast" && !((_c = (_b2 = (_a2 = this.params) === null || _a2 === void 0 ? void 0 : _a2.config) === null || _b2 === void 0 ? void 0 : _b2.broadcast) === null || _c === void 0 ? void 0 : _c.ack)) {
4416
- resolve2("ok");
4691
+ resolve3("ok");
4417
4692
  }
4418
- push.receive("ok", () => resolve2("ok"));
4419
- push.receive("error", () => resolve2("error"));
4420
- push.receive("timeout", () => resolve2("timed out"));
4693
+ push.receive("ok", () => resolve3("ok"));
4694
+ push.receive("error", () => resolve3("error"));
4695
+ push.receive("timeout", () => resolve3("timed out"));
4421
4696
  });
4422
4697
  }
4423
4698
  }
@@ -4445,16 +4720,16 @@ var RealtimeChannel = class _RealtimeChannel {
4445
4720
  };
4446
4721
  this.joinPush.destroy();
4447
4722
  let leavePush = null;
4448
- return new Promise((resolve2) => {
4723
+ return new Promise((resolve3) => {
4449
4724
  leavePush = new Push(this, CHANNEL_EVENTS.leave, {}, timeout);
4450
4725
  leavePush.receive("ok", () => {
4451
4726
  onClose();
4452
- resolve2("ok");
4727
+ resolve3("ok");
4453
4728
  }).receive("timeout", () => {
4454
4729
  onClose();
4455
- resolve2("timed out");
4730
+ resolve3("timed out");
4456
4731
  }).receive("error", () => {
4457
- resolve2("error");
4732
+ resolve3("error");
4458
4733
  });
4459
4734
  leavePush.send();
4460
4735
  if (!this._canPush()) {
@@ -4533,8 +4808,8 @@ var RealtimeChannel = class _RealtimeChannel {
4533
4808
  _trigger(type, payload, ref) {
4534
4809
  var _a, _b;
4535
4810
  const typeLower = type.toLocaleLowerCase();
4536
- const { close, error: error2, leave, join: join7 } = CHANNEL_EVENTS;
4537
- const events = [close, error2, leave, join7];
4811
+ const { close, error: error2, leave, join: join9 } = CHANNEL_EVENTS;
4812
+ const events = [close, error2, leave, join9];
4538
4813
  if (ref && events.indexOf(typeLower) >= 0 && ref !== this._joinRef()) {
4539
4814
  return;
4540
4815
  }
@@ -6150,7 +6425,7 @@ var _getRequestParams = (method, options, parameters, body) => {
6150
6425
  return _objectSpread2(_objectSpread2({}, params), parameters);
6151
6426
  };
6152
6427
  async function _handleRequest(fetcher, method, url, options, parameters, body, namespace) {
6153
- return new Promise((resolve2, reject) => {
6428
+ return new Promise((resolve3, reject) => {
6154
6429
  fetcher(url, _getRequestParams(method, options, parameters, body)).then((result) => {
6155
6430
  if (!result.ok) throw result;
6156
6431
  if (options === null || options === void 0 ? void 0 : options.noResolveJson) return result;
@@ -6160,7 +6435,7 @@ async function _handleRequest(fetcher, method, url, options, parameters, body, n
6160
6435
  if (!contentType || !contentType.includes("application/json")) return {};
6161
6436
  }
6162
6437
  return result.json();
6163
- }).then((data) => resolve2(data)).catch((error2) => handleError(error2, reject, options, namespace));
6438
+ }).then((data) => resolve3(data)).catch((error2) => handleError(error2, reject, options, namespace));
6164
6439
  });
6165
6440
  }
6166
6441
  function createFetchApi(namespace = "storage") {
@@ -13914,6 +14189,12 @@ async function publicRoutes(fastify, options) {
13914
14189
  }
13915
14190
 
13916
14191
  // ../server/dist/routes/chat.js
14192
+ import { resolve, join as join6 } from "path";
14193
+ import { readFile as readFile3 } from "fs/promises";
14194
+ function isChatEnabled(configLoader) {
14195
+ const project = configLoader.getProject();
14196
+ return !!(project?.features?.chat && process.env.ANTHROPIC_API_KEY);
14197
+ }
13917
14198
  async function chatRoutes(fastify, options) {
13918
14199
  const { configLoader, queryService } = options;
13919
14200
  fastify.post("/api/chat/generate-text", async (request, reply) => {
@@ -14052,6 +14333,210 @@ async function chatRoutes(fastify, options) {
14052
14333
  return reply.status(500).send({ error: message });
14053
14334
  }
14054
14335
  });
14336
+ fastify.get("/api/chat/agents", async (request, reply) => {
14337
+ if (!isChatEnabled(configLoader)) {
14338
+ return reply.code(404).send({ error: "Chat not enabled" });
14339
+ }
14340
+ const registry = configLoader.getAgentRegistry();
14341
+ const agents = registry.listAgents().map((a) => ({
14342
+ name: a.name,
14343
+ title: a.title,
14344
+ description: a.description,
14345
+ builtIn: a.builtIn
14346
+ }));
14347
+ return agents;
14348
+ });
14349
+ fastify.post("/api/chat/stream", async (request, reply) => {
14350
+ if (!isChatEnabled(configLoader)) {
14351
+ return reply.code(404).send({ error: "Chat not enabled" });
14352
+ }
14353
+ const body = request.body;
14354
+ if (!body.message) {
14355
+ return reply.code(400).send({ error: "message is required" });
14356
+ }
14357
+ const apiKey = process.env.ANTHROPIC_API_KEY;
14358
+ const registry = configLoader.getAgentRegistry();
14359
+ const router = new RouterAgent(registry);
14360
+ const chatContext = body.context ?? { type: "general" };
14361
+ const agentConfig = router.selectAgent(body.message, chatContext, body.agent);
14362
+ reply.raw.writeHead(200, {
14363
+ "Content-Type": "text/event-stream",
14364
+ "Cache-Control": "no-cache",
14365
+ Connection: "keep-alive"
14366
+ });
14367
+ const emitEvent = (event) => {
14368
+ reply.raw.write(formatSSEEvent(event));
14369
+ };
14370
+ emitEvent({ type: "agent_selected", data: { name: agentConfig.name, title: agentConfig.title } });
14371
+ const project = configLoader.getProject();
14372
+ const toolContext = {
14373
+ configLoader: {
14374
+ getChartByName: (name) => configLoader.getChartByName(name),
14375
+ getDashboardByName: (name) => configLoader.getDashboardByName(name),
14376
+ getDashboards: () => configLoader.getDashboards(),
14377
+ getCharts: () => configLoader.getCharts(),
14378
+ getModels: () => configLoader.getModels?.() ?? [],
14379
+ getProject: () => configLoader.getProject(),
14380
+ load: () => configLoader.load()
14381
+ },
14382
+ queryService: {
14383
+ executeChart: (chart, params, userCtx) => queryService.executeChart(chart, params, userCtx),
14384
+ executeRawSql: (sql) => queryService.executeRawSql(sql)
14385
+ },
14386
+ projectDir: options.projectDir,
14387
+ catalogPath: resolve(options.projectDir, ".yamchart", "catalog.json"),
14388
+ agentRegistry: configLoader.getAgentRegistry(),
14389
+ userContext: request.user ? { id: request.user.id, email: request.user.email, role: request.user.role } : void 0,
14390
+ emitEvent,
14391
+ chatContext,
14392
+ catalogFilter: project?.catalog?.include
14393
+ };
14394
+ let systemPrompt = agentConfig.systemPrompt;
14395
+ if (chatContext.type === "dashboard" && chatContext.name) {
14396
+ const dashboard = configLoader.getDashboardByName(chatContext.name);
14397
+ if (dashboard) {
14398
+ const chartRefs = [];
14399
+ const extractRefs = (layout) => {
14400
+ for (const row of layout.rows ?? []) {
14401
+ for (const widget of row.widgets ?? []) {
14402
+ if (widget.type === "chart" && widget.ref)
14403
+ chartRefs.push(widget.ref);
14404
+ }
14405
+ }
14406
+ };
14407
+ if (dashboard.layout)
14408
+ extractRefs(dashboard.layout);
14409
+ if (dashboard.tabs) {
14410
+ for (const tab of dashboard.tabs) {
14411
+ if (tab.layout)
14412
+ extractRefs(tab.layout);
14413
+ }
14414
+ }
14415
+ const chartDetails = [];
14416
+ for (const ref of chartRefs) {
14417
+ const chart = configLoader.getChartByName(ref);
14418
+ if (!chart)
14419
+ continue;
14420
+ const model = chart.source?.model ? `, model: "${chart.source.model}"` : "";
14421
+ const params = chart.parameters?.length ? `, params: [${chart.parameters.map((p) => `${p.name}(${p.type})`).join(", ")}]` : "";
14422
+ chartDetails.push(` - "${ref}" (${chart.chart?.type ?? "unknown"}${model}${params}): ${chart.title ?? ref}`);
14423
+ }
14424
+ const filters = dashboard.filters?.length ? `
14425
+ Dashboard filters: ${dashboard.filters.map((f) => `${f.name}(${f.type}, default: ${f.default ?? "none"})`).join(", ")}` : "";
14426
+ systemPrompt += `
14427
+
14428
+ The user is viewing the "${dashboard.title ?? dashboard.name}" dashboard (id: "${dashboard.name}").${filters}
14429
+ Charts on this dashboard:
14430
+ ${chartDetails.join("\n")}
14431
+
14432
+ IMPORTANT: When using query_model, pass the chart name (e.g. "${chartRefs[0] ?? "chart-name"}") \u2014 NOT the model name. The chart name is what appears before the parentheses above.`;
14433
+ }
14434
+ } else if (chatContext.type === "chart" && chatContext.name) {
14435
+ const chart = configLoader.getChartByName(chatContext.name);
14436
+ if (chart) {
14437
+ const model = chart.source?.model ? ` Model: "${chart.source.model}".` : "";
14438
+ const params = chart.parameters?.length ? ` Parameters: ${chart.parameters.map((p) => `${p.name}(${p.type})`).join(", ")}.` : "";
14439
+ systemPrompt += `
14440
+
14441
+ The user is viewing the "${chart.title ?? chart.name}" chart (id: "${chart.name}", type: ${chart.chart?.type}).${model}${params}`;
14442
+ }
14443
+ } else if (chatContext.type === "explore") {
14444
+ const catalogPath = join6(options.projectDir, ".yamchart", "catalog.json");
14445
+ const tableLines = [];
14446
+ try {
14447
+ const catalogData = JSON.parse(await readFile3(catalogPath, "utf-8"));
14448
+ const filteredModels = filterCatalogEntries(catalogData.models ?? [], project?.catalog?.include);
14449
+ for (const entry of filteredModels) {
14450
+ const fullName = entry.table ?? entry.name;
14451
+ const cols = (entry.columns ?? []).map((c) => c.name).join(", ");
14452
+ const colSuffix = cols ? ` (${entry.columns?.length} columns: ${cols})` : "";
14453
+ tableLines.push(`- ${fullName}${colSuffix}`);
14454
+ }
14455
+ } catch {
14456
+ }
14457
+ const configModels = configLoader.getModels?.() ?? [];
14458
+ const modelLines = configModels.map((m) => m.metadata.description ? `- ${m.metadata.name}: ${m.metadata.description}` : `- ${m.metadata.name}`);
14459
+ if (tableLines.length === 0 && modelLines.length === 0) {
14460
+ systemPrompt += "\n\nNo catalog data available. Use get_catalog_tables or run_sql to discover tables.";
14461
+ } else {
14462
+ const parts = ["\n"];
14463
+ if (tableLines.length > 0) {
14464
+ parts.push("## Available Tables", ...tableLines);
14465
+ }
14466
+ if (modelLines.length > 0) {
14467
+ if (parts.length > 1)
14468
+ parts.push("");
14469
+ parts.push("## Available Models", ...modelLines);
14470
+ }
14471
+ systemPrompt += parts.join("\n");
14472
+ }
14473
+ }
14474
+ const messages = [];
14475
+ for (const msg of body.history ?? []) {
14476
+ messages.push({ role: msg.role, content: msg.content });
14477
+ }
14478
+ messages.push({ role: "user", content: body.message });
14479
+ try {
14480
+ const agent = new StreamingChatAgent(agentConfig, apiKey);
14481
+ await agent.run(systemPrompt, messages, toolContext, emitEvent);
14482
+ } catch (err) {
14483
+ emitEvent({
14484
+ type: "error",
14485
+ data: { message: err instanceof Error ? err.message : "Stream failed" }
14486
+ });
14487
+ }
14488
+ reply.raw.end();
14489
+ });
14490
+ }
14491
+
14492
+ // ../server/dist/routes/catalog.js
14493
+ import { join as join7 } from "path";
14494
+ import { readFile as readFile4 } from "fs/promises";
14495
+ async function catalogRoutes(fastify, options) {
14496
+ const { configLoader, projectDir } = options;
14497
+ fastify.get("/api/catalog/summary", async (_request2, reply) => {
14498
+ const connections = configLoader.getConnections().map((c) => ({
14499
+ name: c.name,
14500
+ type: c.type
14501
+ }));
14502
+ const configModels = configLoader.getModels().map((m) => ({
14503
+ name: m.metadata.name,
14504
+ description: m.metadata.description
14505
+ }));
14506
+ const catalogPath = join7(projectDir, ".yamchart", "catalog.json");
14507
+ let tables = [];
14508
+ try {
14509
+ const catalogData = JSON.parse(await readFile4(catalogPath, "utf-8"));
14510
+ const allCatalogModels = catalogData.models ?? [];
14511
+ const project = configLoader.getProject();
14512
+ const catalogModels = filterCatalogEntries(allCatalogModels, project?.catalog?.include);
14513
+ tables = catalogModels.map((m) => {
14514
+ const fullName = m.table ?? m.name ?? "";
14515
+ const parts = fullName.split(".");
14516
+ const tableName = parts[parts.length - 1] ?? fullName;
14517
+ const schema = parts.length > 1 ? parts.slice(0, -1).join(".") : void 0;
14518
+ const columns = (m.columns ?? []).map((c) => ({
14519
+ name: c.name,
14520
+ type: c.data_type
14521
+ }));
14522
+ return {
14523
+ name: tableName,
14524
+ ...schema ? { schema } : {},
14525
+ connection: m.connection ?? (connections[0]?.name ?? "default"),
14526
+ columnCount: columns.length,
14527
+ columns
14528
+ };
14529
+ });
14530
+ } catch {
14531
+ }
14532
+ return reply.send({
14533
+ connections,
14534
+ tables,
14535
+ models: configModels,
14536
+ tableCount: tables.length,
14537
+ modelCount: configModels.length
14538
+ });
14539
+ });
14055
14540
  }
14056
14541
 
14057
14542
  // ../server/dist/routes/events.js
@@ -14093,18 +14578,18 @@ data: ${data}
14093
14578
  }
14094
14579
 
14095
14580
  // ../server/dist/server.js
14096
- import { join as join6, dirname as dirname2 } from "path";
14581
+ import { join as join8, dirname as dirname2 } from "path";
14097
14582
  import { fileURLToPath } from "url";
14098
- import { access as access2, readFile as readFile3 } from "fs/promises";
14583
+ import { access as access2, readFile as readFile5 } from "fs/promises";
14099
14584
  import { watch as fsWatch } from "fs";
14100
14585
  var __dirname = dirname2(fileURLToPath(import.meta.url));
14101
- var packageJsonPath = join6(__dirname, "..", "package.json");
14102
- var packageJson = JSON.parse(await readFile3(packageJsonPath, "utf-8"));
14586
+ var packageJsonPath = join8(__dirname, "..", "package.json");
14587
+ var packageJson = JSON.parse(await readFile5(packageJsonPath, "utf-8"));
14103
14588
  var VERSION = packageJson.version;
14104
14589
  async function enrichRefsFromCatalog(projectDir, refs) {
14105
14590
  try {
14106
- const catalogPath = join6(projectDir, ".yamchart", "catalog.json");
14107
- const catalogData = JSON.parse(await readFile3(catalogPath, "utf-8"));
14591
+ const catalogPath = join8(projectDir, ".yamchart", "catalog.json");
14592
+ const catalogData = JSON.parse(await readFile5(catalogPath, "utf-8"));
14108
14593
  for (const model of catalogData.models ?? []) {
14109
14594
  if (model.name && model.table) {
14110
14595
  refs[model.name] = model.table;
@@ -14114,7 +14599,7 @@ async function enrichRefsFromCatalog(projectDir, refs) {
14114
14599
  }
14115
14600
  }
14116
14601
  async function createServer(options) {
14117
- const { projectDir, port = 3001, host = "0.0.0.0", watch: watch2 = false, serveStatic = process.env.NODE_ENV === "production", staticDir = join6(__dirname, "public"), auth } = options;
14602
+ const { projectDir, port = 3001, host = "0.0.0.0", watch: watch2 = false, serveStatic = process.env.NODE_ENV === "production", staticDir = join8(__dirname, "public"), auth } = options;
14118
14603
  if (auth) {
14119
14604
  initAuthServer(auth.supabaseUrl, auth.supabaseServiceKey);
14120
14605
  }
@@ -14248,6 +14733,7 @@ async function createServer(options) {
14248
14733
  await protectedRoutes.register(chartEventsRoutes, { configLoader, projectDir });
14249
14734
  await protectedRoutes.register(dashboardRoutes, { configLoader, gitService, projectDir, queryService });
14250
14735
  await protectedRoutes.register(chatRoutes, { configLoader, queryService, projectDir });
14736
+ await protectedRoutes.register(catalogRoutes, { configLoader, projectDir });
14251
14737
  });
14252
14738
  } else if (authDb) {
14253
14739
  const localMiddleware = createLocalAuthMiddleware(authDb);
@@ -14258,6 +14744,7 @@ async function createServer(options) {
14258
14744
  await protectedRoutes.register(chartEventsRoutes, { configLoader, projectDir });
14259
14745
  await protectedRoutes.register(dashboardRoutes, { configLoader, gitService, projectDir, queryService });
14260
14746
  await protectedRoutes.register(chatRoutes, { configLoader, queryService, projectDir });
14747
+ await protectedRoutes.register(catalogRoutes, { configLoader, projectDir });
14261
14748
  await protectedRoutes.register(sharesRoutes, { authDb });
14262
14749
  });
14263
14750
  } else {
@@ -14266,8 +14753,9 @@ async function createServer(options) {
14266
14753
  await fastify.register(chartEventsRoutes, { configLoader, projectDir });
14267
14754
  await fastify.register(dashboardRoutes, { configLoader, gitService, projectDir, queryService });
14268
14755
  await fastify.register(chatRoutes, { configLoader, queryService, projectDir });
14756
+ await fastify.register(catalogRoutes, { configLoader, projectDir });
14269
14757
  }
14270
- const assetsDir = join6(projectDir, "assets");
14758
+ const assetsDir = join8(projectDir, "assets");
14271
14759
  try {
14272
14760
  await access2(assetsDir);
14273
14761
  await fastify.register(fastifyStatic, {
@@ -14278,10 +14766,10 @@ async function createServer(options) {
14278
14766
  } catch {
14279
14767
  }
14280
14768
  if (project.theme?.customCss) {
14281
- const cssPath = join6(projectDir, project.theme.customCss);
14769
+ const cssPath = join8(projectDir, project.theme.customCss);
14282
14770
  fastify.get("/api/theme/custom.css", async (_request2, reply) => {
14283
14771
  try {
14284
- const content = await readFile3(cssPath, "utf-8");
14772
+ const content = await readFile5(cssPath, "utf-8");
14285
14773
  return reply.type("text/css").send(content);
14286
14774
  } catch {
14287
14775
  return reply.status(404).send("");
@@ -14337,7 +14825,7 @@ async function createServer(options) {
14337
14825
  fastify.log.info(`Semantic model rebuilt: ${semanticService.getModel()?.entities.length ?? 0} entities`);
14338
14826
  broadcastConfigChange();
14339
14827
  });
14340
- const catalogPath = join6(projectDir, ".yamchart", "catalog.json");
14828
+ const catalogPath = join8(projectDir, ".yamchart", "catalog.json");
14341
14829
  try {
14342
14830
  catalogWatcher = fsWatch(catalogPath, () => {
14343
14831
  semanticService.buildFromDisk();
@@ -14402,15 +14890,15 @@ async function runDevServer(projectDir, options) {
14402
14890
  let localAuth;
14403
14891
  try {
14404
14892
  const { readFileSync: readFileSync2 } = await import("fs");
14405
- const { parse } = await import("yaml");
14406
- const { resolveProjectConfig: resolveProjectConfig2, deepMerge: deepMerge3 } = await import("./dist-LJR7TAW4.js");
14407
- const raw = readFileSync2(resolve(projectDir, "yamchart.yaml"), "utf-8");
14408
- const rawConfig = parse(raw);
14893
+ const { parse: parse2 } = await import("yaml");
14894
+ const { resolveProjectConfig: resolveProjectConfig2, deepMerge: deepMerge3 } = await import("./dist-PINRLZVT.js");
14895
+ const raw = readFileSync2(resolve2(projectDir, "yamchart.yaml"), "utf-8");
14896
+ const rawConfig = parse2(raw);
14409
14897
  const resolvedEnv = options.env || process.env.YAMCHART_ENV || void 0;
14410
14898
  let projectConfig = resolveProjectConfig2(rawConfig, resolvedEnv);
14411
14899
  try {
14412
- const localRaw = readFileSync2(resolve(projectDir, "yamchart.local.yaml"), "utf-8");
14413
- const localOverrides = parse(localRaw);
14900
+ const localRaw = readFileSync2(resolve2(projectDir, "yamchart.local.yaml"), "utf-8");
14901
+ const localOverrides = parse2(localRaw);
14414
14902
  if (localOverrides && typeof localOverrides === "object") {
14415
14903
  projectConfig = deepMerge3(projectConfig, localOverrides);
14416
14904
  }
@@ -14419,16 +14907,16 @@ async function runDevServer(projectDir, options) {
14419
14907
  if (projectConfig?.auth?.enabled) {
14420
14908
  localAuth = {
14421
14909
  enabled: true,
14422
- dbPath: projectConfig.auth.db_path ? resolve(projectConfig.auth.db_path.replace(/^~/, homedir())) : resolve(homedir(), ".yamchart", "auth.db"),
14910
+ dbPath: projectConfig.auth.db_path ? resolve2(projectConfig.auth.db_path.replace(/^~/, homedir())) : resolve2(homedir(), ".yamchart", "auth.db"),
14423
14911
  sessionTtlMs: projectConfig.auth.session_ttl ? parseTtl(projectConfig.auth.session_ttl) : 30 * 24 * 60 * 60 * 1e3
14424
14912
  };
14425
14913
  }
14426
- const connectionDir = resolve(projectDir, "connections");
14914
+ const connectionDir = resolve2(projectDir, "connections");
14427
14915
  const targetConn = process.env.YAMCHART_CONNECTION || projectConfig?.defaults?.connection;
14428
14916
  if (targetConn) {
14429
14917
  try {
14430
- const connRaw = readFileSync2(resolve(connectionDir, `${targetConn}.yaml`), "utf-8");
14431
- const connConfig = parse(connRaw);
14918
+ const connRaw = readFileSync2(resolve2(connectionDir, `${targetConn}.yaml`), "utf-8");
14919
+ const connConfig = parse2(connRaw);
14432
14920
  if (connConfig?.auth?.type === "externalbrowser") {
14433
14921
  usesBrowserAuth = true;
14434
14922
  }
@@ -14495,4 +14983,4 @@ async function runDevServer(projectDir, options) {
14495
14983
  export {
14496
14984
  runDevServer
14497
14985
  };
14498
- //# sourceMappingURL=dev-Z2R2DBWO.js.map
14986
+ //# sourceMappingURL=dev-JUA73B6D.js.map