@kiyeonjeon21/datacontext 0.2.0 → 0.3.1

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 (55) hide show
  1. package/.cursorrules +12 -0
  2. package/.env.example +8 -0
  3. package/.github/workflows/ci.yml +21 -1
  4. package/.github/workflows/publish.yml +21 -1
  5. package/CHANGELOG.md +41 -0
  6. package/README.md +247 -239
  7. package/cursor-mcp-config.json.example +29 -0
  8. package/datacontext.db +0 -0
  9. package/dist/api/server.d.ts.map +1 -1
  10. package/dist/api/server.js +145 -0
  11. package/dist/api/server.js.map +1 -1
  12. package/dist/api/start-server.d.ts +10 -0
  13. package/dist/api/start-server.d.ts.map +1 -0
  14. package/dist/api/start-server.js +73 -0
  15. package/dist/api/start-server.js.map +1 -0
  16. package/dist/cli/index.js +462 -0
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/core/context-service.d.ts +72 -0
  19. package/dist/core/context-service.d.ts.map +1 -1
  20. package/dist/core/context-service.js +132 -0
  21. package/dist/core/context-service.js.map +1 -1
  22. package/dist/core/index.d.ts +2 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/core/index.js +5 -1
  25. package/dist/core/index.js.map +1 -1
  26. package/dist/core/llm-service.d.ts +141 -0
  27. package/dist/core/llm-service.d.ts.map +1 -0
  28. package/dist/core/llm-service.js +284 -0
  29. package/dist/core/llm-service.js.map +1 -0
  30. package/dist/knowledge/store.d.ts +56 -3
  31. package/dist/knowledge/store.d.ts.map +1 -1
  32. package/dist/knowledge/store.js +193 -7
  33. package/dist/knowledge/store.js.map +1 -1
  34. package/dist/knowledge/types.d.ts +43 -1
  35. package/dist/knowledge/types.d.ts.map +1 -1
  36. package/dist/knowledge/types.js.map +1 -1
  37. package/dist/mcp/tools.d.ts.map +1 -1
  38. package/dist/mcp/tools.js +365 -0
  39. package/dist/mcp/tools.js.map +1 -1
  40. package/docs/API.md +173 -0
  41. package/docs/DEMO_SCRIPT.md +210 -0
  42. package/docs/MCP_TEST_GUIDE.md +414 -0
  43. package/docs/SYNC_GUIDE.md +242 -0
  44. package/package.json +4 -1
  45. package/src/api/server.ts +160 -0
  46. package/src/api/start-server.ts +78 -0
  47. package/src/cli/index.ts +534 -0
  48. package/src/core/context-service.ts +182 -0
  49. package/src/core/index.ts +7 -0
  50. package/src/core/llm-service.ts +359 -0
  51. package/src/knowledge/store.ts +232 -7
  52. package/src/knowledge/types.ts +45 -1
  53. package/src/mcp/tools.ts +415 -0
  54. package/test-glossary.yaml +55 -0
  55. package/test-mcp.db +0 -0
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ /**
3
+ * LLM Service Module
4
+ *
5
+ * Provides AI-powered features using Claude API.
6
+ * Used for auto-generating glossary terms, descriptions, and query suggestions.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const llm = createLLMService();
11
+ *
12
+ * // Generate glossary from user's raw terms
13
+ * const terms = await llm.generateGlossary(
14
+ * "활성 사용자, 최근 주문, VIP 고객",
15
+ * schemaContext
16
+ * );
17
+ *
18
+ * // Generate table descriptions
19
+ * const descriptions = await llm.generateTableDescriptions(tableInfo);
20
+ * ```
21
+ */
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.LLMService = void 0;
27
+ exports.createLLMService = createLLMService;
28
+ exports.isLLMAvailable = isLLMAvailable;
29
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
30
+ const types_js_1 = require("../knowledge/types.js");
31
+ /** LLM Service class */
32
+ class LLMService {
33
+ client;
34
+ model;
35
+ maxTokens;
36
+ constructor(config = {}) {
37
+ const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
38
+ if (!apiKey) {
39
+ throw new Error('Anthropic API key not found. Set ANTHROPIC_API_KEY environment variable or pass apiKey in config.');
40
+ }
41
+ this.client = new sdk_1.default({ apiKey });
42
+ this.model = config.model || process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-20250514';
43
+ this.maxTokens = config.maxTokens || 4096;
44
+ }
45
+ /**
46
+ * Generate glossary terms from user's raw input
47
+ *
48
+ * Takes natural language terms and generates structured BusinessTerm entries
49
+ * with SQL expressions and proper categorization.
50
+ *
51
+ * @param rawTerms - User's raw term input (comma-separated, YAML, or natural language)
52
+ * @param context - Database schema context
53
+ * @param schemaHash - Current schema hash for metadata
54
+ * @returns Array of generated BusinessTerm entries
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const terms = await llm.generateGlossary(
59
+ * "활성 사용자 = status가 1인 사용자\n최근 주문 = 30일 이내 주문",
60
+ * { tables: [{ name: 'users', columns: [...] }] },
61
+ * "abc123"
62
+ * );
63
+ * ```
64
+ */
65
+ async generateGlossary(rawTerms, context, schemaHash = '') {
66
+ const systemPrompt = `You are a database context expert. Your job is to analyze user-provided business terms and generate structured glossary entries that can be used to translate natural language queries into accurate SQL.
67
+
68
+ IMPORTANT RULES:
69
+ 1. Generate SQL expressions that are syntactically correct for the given schema
70
+ 2. Match terms to actual table/column names in the schema
71
+ 3. Be precise with data types (e.g., integer status codes, date intervals)
72
+ 4. Include synonyms in multiple languages if the term suggests it
73
+ 5. Categorize terms appropriately: status, time, money, entity, metric, filter, custom
74
+
75
+ OUTPUT FORMAT: Return a JSON array of term objects. Each object must have:
76
+ - term: The primary term name
77
+ - synonyms: Array of alternative names (include English, Korean if applicable)
78
+ - definition: Clear explanation of what this term means
79
+ - sqlExpression: SQL condition or expression (if applicable)
80
+ - appliesTo: { tables?: string[], columns?: string[] }
81
+ - category: One of: status, time, money, entity, metric, filter, custom
82
+ - examples: Array of example usage in natural language queries
83
+
84
+ Return ONLY the JSON array, no other text.`;
85
+ const schemaInfo = this.formatSchemaContext(context);
86
+ const userPrompt = `DATABASE SCHEMA:
87
+ ${schemaInfo}
88
+
89
+ ${context.existingTerms?.length ? `EXISTING TERMS (avoid duplicates):
90
+ ${context.existingTerms.map(t => `- ${t.term}: ${t.definition}`).join('\n')}
91
+ ` : ''}
92
+
93
+ USER'S RAW TERMS TO PROCESS:
94
+ ${rawTerms}
95
+
96
+ Generate structured glossary entries for these terms. Match them to the actual schema above.`;
97
+ try {
98
+ const response = await this.client.messages.create({
99
+ model: this.model,
100
+ max_tokens: this.maxTokens,
101
+ messages: [
102
+ { role: 'user', content: userPrompt }
103
+ ],
104
+ system: systemPrompt,
105
+ });
106
+ const content = response.content[0];
107
+ if (content.type !== 'text') {
108
+ throw new Error('Unexpected response type from Claude');
109
+ }
110
+ // Parse JSON response
111
+ const generated = this.parseJsonResponse(content.text);
112
+ // Convert to BusinessTerm with metadata
113
+ return generated.map(term => ({
114
+ ...(0, types_js_1.createKnowledgeMeta)('auto', schemaHash),
115
+ type: 'business_term',
116
+ term: term.term,
117
+ synonyms: term.synonyms || [],
118
+ definition: term.definition,
119
+ sqlExpression: term.sqlExpression,
120
+ appliesTo: term.appliesTo,
121
+ category: term.category,
122
+ examples: term.examples,
123
+ isActive: true,
124
+ }));
125
+ }
126
+ catch (error) {
127
+ throw new Error(`Failed to generate glossary: ${error instanceof Error ? error.message : String(error)}`);
128
+ }
129
+ }
130
+ /**
131
+ * Generate table/column descriptions from schema
132
+ *
133
+ * Analyzes table and column names to generate meaningful descriptions.
134
+ * Useful for cold-start when no documentation exists.
135
+ *
136
+ * @param tableInfo - Table schema information
137
+ * @param schemaHash - Current schema hash
138
+ * @returns Generated TableDescription
139
+ */
140
+ async generateTableDescription(tableInfo, schemaHash = '') {
141
+ const systemPrompt = `You are a database documentation expert. Analyze the table structure and generate clear, useful descriptions.
142
+
143
+ OUTPUT FORMAT: Return a JSON object with:
144
+ - description: One sentence describing the table's purpose
145
+ - purpose: Detailed explanation of the table's role
146
+ - columns: Array of { name: string, description: string, valueMappings?: Record<string, string> }
147
+ - tags: Array of relevant tags
148
+
149
+ Return ONLY the JSON object, no other text.`;
150
+ const sampleDataStr = tableInfo.sampleData
151
+ ? `\n\nSAMPLE DATA:\n${JSON.stringify(tableInfo.sampleData.slice(0, 3), null, 2)}`
152
+ : '';
153
+ const userPrompt = `TABLE: ${tableInfo.name}
154
+
155
+ COLUMNS:
156
+ ${tableInfo.columns.map(c => `- ${c.name} (${c.type}${c.nullable ? ', nullable' : ''})`).join('\n')}
157
+ ${sampleDataStr}
158
+
159
+ Generate descriptions for this table and its columns.`;
160
+ try {
161
+ const response = await this.client.messages.create({
162
+ model: this.model,
163
+ max_tokens: this.maxTokens,
164
+ messages: [
165
+ { role: 'user', content: userPrompt }
166
+ ],
167
+ system: systemPrompt,
168
+ });
169
+ const content = response.content[0];
170
+ if (content.type !== 'text') {
171
+ throw new Error('Unexpected response type from Claude');
172
+ }
173
+ return this.parseJsonResponse(content.text);
174
+ }
175
+ catch (error) {
176
+ throw new Error(`Failed to generate table description: ${error instanceof Error ? error.message : String(error)}`);
177
+ }
178
+ }
179
+ /**
180
+ * Enhance a user query with glossary context
181
+ *
182
+ * Takes a natural language query and returns an enhanced version
183
+ * with term definitions resolved.
184
+ *
185
+ * @param query - User's natural language query
186
+ * @param terms - Available business terms
187
+ * @returns Enhanced query with context
188
+ */
189
+ async enhanceQueryWithGlossary(query, terms) {
190
+ if (terms.length === 0) {
191
+ return { enhancedQuery: query, usedTerms: [], suggestedConditions: [] };
192
+ }
193
+ const systemPrompt = `You are a query enhancement assistant. Your job is to identify business terms in user queries and suggest SQL conditions based on the glossary.
194
+
195
+ OUTPUT FORMAT: Return a JSON object with:
196
+ - enhancedQuery: The query with term definitions inline
197
+ - usedTerms: Array of term names that were found in the query
198
+ - suggestedConditions: Array of SQL conditions to apply
199
+
200
+ Return ONLY the JSON object, no other text.`;
201
+ const glossaryStr = terms
202
+ .filter(t => t.isActive)
203
+ .map(t => `- "${t.term}" (${t.synonyms.join(', ')}): ${t.definition}${t.sqlExpression ? ` → SQL: ${t.sqlExpression}` : ''}`)
204
+ .join('\n');
205
+ const userPrompt = `GLOSSARY:
206
+ ${glossaryStr}
207
+
208
+ USER QUERY:
209
+ ${query}
210
+
211
+ Identify any terms from the glossary used in this query and suggest SQL conditions.`;
212
+ try {
213
+ const response = await this.client.messages.create({
214
+ model: this.model,
215
+ max_tokens: 1024,
216
+ messages: [
217
+ { role: 'user', content: userPrompt }
218
+ ],
219
+ system: systemPrompt,
220
+ });
221
+ const content = response.content[0];
222
+ if (content.type !== 'text') {
223
+ return { enhancedQuery: query, usedTerms: [], suggestedConditions: [] };
224
+ }
225
+ return this.parseJsonResponse(content.text);
226
+ }
227
+ catch {
228
+ return { enhancedQuery: query, usedTerms: [], suggestedConditions: [] };
229
+ }
230
+ }
231
+ /**
232
+ * Parse JSON response from Claude, handling markdown code blocks
233
+ */
234
+ parseJsonResponse(text) {
235
+ // Remove markdown code blocks if present
236
+ let cleaned = text.trim();
237
+ if (cleaned.startsWith('```json')) {
238
+ cleaned = cleaned.slice(7);
239
+ }
240
+ else if (cleaned.startsWith('```')) {
241
+ cleaned = cleaned.slice(3);
242
+ }
243
+ if (cleaned.endsWith('```')) {
244
+ cleaned = cleaned.slice(0, -3);
245
+ }
246
+ cleaned = cleaned.trim();
247
+ try {
248
+ return JSON.parse(cleaned);
249
+ }
250
+ catch {
251
+ throw new Error(`Failed to parse JSON response: ${text.slice(0, 200)}...`);
252
+ }
253
+ }
254
+ /**
255
+ * Format schema context for prompts
256
+ */
257
+ formatSchemaContext(context) {
258
+ return context.tables
259
+ .map(table => {
260
+ const cols = table.columns
261
+ .map(c => ` - ${c.name} (${c.type}${c.nullable ? ', nullable' : ''})`)
262
+ .join('\n');
263
+ return `Table: ${table.name}\n${cols}`;
264
+ })
265
+ .join('\n\n');
266
+ }
267
+ }
268
+ exports.LLMService = LLMService;
269
+ /**
270
+ * Create an LLM service instance
271
+ *
272
+ * @param config - Service configuration
273
+ * @returns LLMService instance
274
+ */
275
+ function createLLMService(config = {}) {
276
+ return new LLMService(config);
277
+ }
278
+ /**
279
+ * Check if LLM service is available (API key configured)
280
+ */
281
+ function isLLMAvailable() {
282
+ return !!process.env.ANTHROPIC_API_KEY;
283
+ }
284
+ //# sourceMappingURL=llm-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-service.js","sourceRoot":"","sources":["../../src/core/llm-service.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;;;;AAyUH,4CAEC;AAKD,wCAEC;AAhVD,4DAA0C;AAE1C,oDAAwE;AAwCxE,wBAAwB;AACxB,MAAa,UAAU;IACb,MAAM,CAAY;IAClB,KAAK,CAAS;IACd,SAAS,CAAS;IAE1B,YAAY,SAA2B,EAAE;QACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAE9D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,mGAAmG,CACpG,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,aAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,0BAA0B,CAAC;QACvF,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,OAAsB,EACtB,aAAqB,EAAE;QAEvB,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;2CAkBkB,CAAC;QAExC,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAErD,MAAM,UAAU,GAAG;EACrB,UAAU;;EAEV,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;EAChC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAC1E,CAAC,CAAC,CAAC,EAAE;;;EAGJ,QAAQ;;6FAEmF,CAAC;QAE1F,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI,CAAC,SAAS;gBAC1B,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;iBACtC;gBACD,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YAED,sBAAsB;YACtB,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAkB,OAAO,CAAC,IAAI,CAAC,CAAC;YAExE,wCAAwC;YACxC,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC5B,GAAG,IAAA,8BAAmB,EAAC,MAAM,EAAE,UAAU,CAAC;gBAC1C,IAAI,EAAE,eAAwB;gBAC9B,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5G,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,wBAAwB,CAC5B,SAIC,EACD,aAAqB,EAAE;QAEvB,MAAM,YAAY,GAAG;;;;;;;;4CAQmB,CAAC;QAEzC,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU;YACxC,CAAC,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;YAClF,CAAC,CAAC,EAAE,CAAC;QAEP,MAAM,UAAU,GAAG,UAAU,SAAS,CAAC,IAAI;;;EAG7C,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;EACjG,aAAa;;sDAEuC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI,CAAC,SAAS;gBAC1B,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;iBACtC;gBACD,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrH,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,wBAAwB,CAC5B,KAAa,EACb,KAAqB;QAMrB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC;QAC1E,CAAC;QAED,MAAM,YAAY,GAAG;;;;;;;4CAOmB,CAAC;QAEzC,MAAM,WAAW,GAAG,KAAK;aACtB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;aAC3H,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,UAAU,GAAG;EACrB,WAAW;;;EAGX,KAAK;;oFAE6E,CAAC;QAEjF,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE;oBACR,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;iBACtC;gBACD,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC;YAC1E,CAAC;YAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAI,IAAY;QACvC,yCAAyC;QACzC,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,OAAsB;QAChD,OAAO,OAAO,CAAC,MAAM;aAClB,GAAG,CAAC,KAAK,CAAC,EAAE;YACX,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO;iBACvB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;iBACtE,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO,UAAU,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACzC,CAAC,CAAC;aACD,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;CACF;AApRD,gCAoRC;AAED;;;;;GAKG;AACH,SAAgB,gBAAgB,CAAC,SAA2B,EAAE;IAC5D,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc;IAC5B,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * Knowledge Store
3
3
  * Local JSON-based storage for table descriptions, query examples, and business rules
4
4
  */
5
- import type { TableDescription, QueryExample, BusinessRule, KnowledgeEntry, ColumnDescription } from './types.js';
5
+ import type { TableDescription, QueryExample, BusinessRule, BusinessTerm, KnowledgeEntry, ColumnDescription, TermCategory } from './types.js';
6
6
  export declare class KnowledgeStore {
7
7
  private dataPath;
8
8
  private data;
@@ -87,14 +87,66 @@ export declare class KnowledgeStore {
87
87
  priority?: number;
88
88
  schemaHash?: string;
89
89
  }): Promise<BusinessRule>;
90
+ /**
91
+ * Get all business terms
92
+ */
93
+ getBusinessTerms(): BusinessTerm[];
94
+ /**
95
+ * Get active business terms
96
+ */
97
+ getActiveTerms(): BusinessTerm[];
98
+ /**
99
+ * Get business terms for specific tables
100
+ */
101
+ getTermsForTables(tables: string[]): BusinessTerm[];
102
+ /**
103
+ * Find terms matching a query (by term name or synonyms)
104
+ */
105
+ findMatchingTerms(query: string): BusinessTerm[];
106
+ /**
107
+ * Add a business term
108
+ */
109
+ addBusinessTerm(term: string, definition: string, options?: {
110
+ synonyms?: string[];
111
+ sqlExpression?: string;
112
+ appliesTo?: {
113
+ tables?: string[];
114
+ columns?: string[];
115
+ };
116
+ category?: TermCategory;
117
+ examples?: string[];
118
+ schemaHash?: string;
119
+ }): Promise<BusinessTerm>;
120
+ /**
121
+ * Add multiple business terms at once
122
+ */
123
+ addBusinessTerms(terms: BusinessTerm[]): Promise<BusinessTerm[]>;
124
+ /**
125
+ * Update a business term
126
+ */
127
+ updateBusinessTerm(id: string, updates: Partial<Omit<BusinessTerm, 'id' | 'type' | 'createdAt'>>): Promise<BusinessTerm>;
128
+ /**
129
+ * Delete a business term
130
+ */
131
+ deleteBusinessTerm(id: string): Promise<void>;
90
132
  /**
91
133
  * Get all knowledge entries that may be outdated (schema drift)
92
134
  */
93
135
  getOutdatedEntries(currentSchemaHash: string): KnowledgeEntry[];
94
136
  /**
95
137
  * Build context for AI from knowledge store
96
- */
97
- buildContext(tables: string[]): string;
138
+ *
139
+ * Generates a comprehensive context string including:
140
+ * - Table descriptions and column details
141
+ * - Business glossary/terms with SQL mappings
142
+ * - Business rules and conditions
143
+ * - Query examples
144
+ *
145
+ * @param tables - Tables to include context for
146
+ * @param userQuery - Optional user query to match relevant terms
147
+ * @returns Formatted context string for AI
148
+ */
149
+ buildContext(tables: string[], userQuery?: string): string;
98
150
  private createEmptyData;
99
151
  /**
100
152
  * Get raw knowledge data (for API/export)
@@ -111,6 +163,7 @@ export declare class KnowledgeStore {
111
163
  }>;
112
164
  queryExamples: QueryExample[];
113
165
  businessRules: BusinessRule[];
166
+ businessTerms: BusinessTerm[];
114
167
  };
115
168
  }
116
169
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/knowledge/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/knowledge/store.ts"],"names":[],"mappings":"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"}
@@ -236,6 +236,144 @@ class KnowledgeStore {
236
236
  await this.save();
237
237
  return rule;
238
238
  }
239
+ // ============ Business Terms (Glossary) ============
240
+ /**
241
+ * Get all business terms
242
+ */
243
+ getBusinessTerms() {
244
+ return this.data?.businessTerms ?? [];
245
+ }
246
+ /**
247
+ * Get active business terms
248
+ */
249
+ getActiveTerms() {
250
+ return this.data?.businessTerms.filter(t => t.isActive) ?? [];
251
+ }
252
+ /**
253
+ * Get business terms for specific tables
254
+ */
255
+ getTermsForTables(tables) {
256
+ return this.data?.businessTerms.filter(term => term.isActive &&
257
+ (term.appliesTo?.tables?.some(t => tables.includes(t)) ?? true)) ?? [];
258
+ }
259
+ /**
260
+ * Find terms matching a query (by term name or synonyms)
261
+ */
262
+ findMatchingTerms(query) {
263
+ const lowerQuery = query.toLowerCase();
264
+ return this.data?.businessTerms.filter(term => {
265
+ if (!term.isActive)
266
+ return false;
267
+ // Check term name
268
+ if (term.term.toLowerCase().includes(lowerQuery))
269
+ return true;
270
+ if (lowerQuery.includes(term.term.toLowerCase()))
271
+ return true;
272
+ // Check synonyms
273
+ for (const syn of term.synonyms) {
274
+ if (syn.toLowerCase().includes(lowerQuery))
275
+ return true;
276
+ if (lowerQuery.includes(syn.toLowerCase()))
277
+ return true;
278
+ }
279
+ return false;
280
+ }) ?? [];
281
+ }
282
+ /**
283
+ * Add a business term
284
+ */
285
+ async addBusinessTerm(term, definition, options = {}) {
286
+ if (!this.data) {
287
+ throw new Error('Knowledge store not loaded');
288
+ }
289
+ // Check for duplicates
290
+ const existing = this.data.businessTerms.find(t => t.term.toLowerCase() === term.toLowerCase());
291
+ if (existing) {
292
+ // Update existing term
293
+ return this.updateBusinessTerm(existing.id, {
294
+ definition,
295
+ ...options,
296
+ });
297
+ }
298
+ const schemaHash = options.schemaHash ?? this.data.schemaHash;
299
+ const newTerm = {
300
+ ...(0, types_js_1.createKnowledgeMeta)('user', schemaHash),
301
+ type: 'business_term',
302
+ term,
303
+ synonyms: options.synonyms ?? [],
304
+ definition,
305
+ sqlExpression: options.sqlExpression,
306
+ appliesTo: options.appliesTo,
307
+ category: options.category,
308
+ examples: options.examples,
309
+ isActive: true,
310
+ };
311
+ this.data.businessTerms.push(newTerm);
312
+ await this.save();
313
+ return newTerm;
314
+ }
315
+ /**
316
+ * Add multiple business terms at once
317
+ */
318
+ async addBusinessTerms(terms) {
319
+ if (!this.data) {
320
+ throw new Error('Knowledge store not loaded');
321
+ }
322
+ const added = [];
323
+ for (const term of terms) {
324
+ // Check for duplicates
325
+ const existingIndex = this.data.businessTerms.findIndex(t => t.term.toLowerCase() === term.term.toLowerCase());
326
+ if (existingIndex >= 0) {
327
+ // Update existing
328
+ this.data.businessTerms[existingIndex] = {
329
+ ...this.data.businessTerms[existingIndex],
330
+ ...term,
331
+ updatedAt: new Date().toISOString(),
332
+ };
333
+ added.push(this.data.businessTerms[existingIndex]);
334
+ }
335
+ else {
336
+ // Add new
337
+ this.data.businessTerms.push(term);
338
+ added.push(term);
339
+ }
340
+ }
341
+ await this.save();
342
+ return added;
343
+ }
344
+ /**
345
+ * Update a business term
346
+ */
347
+ async updateBusinessTerm(id, updates) {
348
+ if (!this.data) {
349
+ throw new Error('Knowledge store not loaded');
350
+ }
351
+ const index = this.data.businessTerms.findIndex(t => t.id === id);
352
+ if (index < 0) {
353
+ throw new Error(`Business term not found: ${id}`);
354
+ }
355
+ const updated = {
356
+ ...this.data.businessTerms[index],
357
+ ...updates,
358
+ updatedAt: new Date().toISOString(),
359
+ };
360
+ this.data.businessTerms[index] = updated;
361
+ await this.save();
362
+ return updated;
363
+ }
364
+ /**
365
+ * Delete a business term
366
+ */
367
+ async deleteBusinessTerm(id) {
368
+ if (!this.data) {
369
+ throw new Error('Knowledge store not loaded');
370
+ }
371
+ const index = this.data.businessTerms.findIndex(t => t.id === id);
372
+ if (index >= 0) {
373
+ this.data.businessTerms.splice(index, 1);
374
+ await this.save();
375
+ }
376
+ }
239
377
  // ============ Utilities ============
240
378
  /**
241
379
  * Get all knowledge entries that may be outdated (schema drift)
@@ -260,13 +398,55 @@ class KnowledgeStore {
260
398
  outdated.push(br);
261
399
  }
262
400
  }
401
+ for (const bt of this.data.businessTerms ?? []) {
402
+ if (bt.schemaHash !== currentSchemaHash) {
403
+ outdated.push(bt);
404
+ }
405
+ }
263
406
  return outdated;
264
407
  }
265
408
  /**
266
409
  * Build context for AI from knowledge store
410
+ *
411
+ * Generates a comprehensive context string including:
412
+ * - Table descriptions and column details
413
+ * - Business glossary/terms with SQL mappings
414
+ * - Business rules and conditions
415
+ * - Query examples
416
+ *
417
+ * @param tables - Tables to include context for
418
+ * @param userQuery - Optional user query to match relevant terms
419
+ * @returns Formatted context string for AI
267
420
  */
268
- buildContext(tables) {
421
+ buildContext(tables, userQuery) {
269
422
  const parts = [];
423
+ // Add business glossary FIRST (helps AI understand terminology)
424
+ const terms = userQuery
425
+ ? this.findMatchingTerms(userQuery)
426
+ : this.getTermsForTables(tables);
427
+ if (terms.length > 0) {
428
+ parts.push('## Business Glossary');
429
+ parts.push('Use these term definitions when interpreting user requests:');
430
+ parts.push('');
431
+ for (const term of terms) {
432
+ let termInfo = `**${term.term}**`;
433
+ if (term.synonyms.length > 0) {
434
+ termInfo += ` (also: ${term.synonyms.join(', ')})`;
435
+ }
436
+ parts.push(termInfo);
437
+ parts.push(` Definition: ${term.definition}`);
438
+ if (term.sqlExpression) {
439
+ parts.push(` SQL: \`${term.sqlExpression}\``);
440
+ }
441
+ if (term.appliesTo?.tables?.length) {
442
+ parts.push(` Applies to: ${term.appliesTo.tables.join(', ')}`);
443
+ }
444
+ if (term.examples?.length) {
445
+ parts.push(` Example usage: "${term.examples[0]}"`);
446
+ }
447
+ parts.push('');
448
+ }
449
+ }
270
450
  // Add table descriptions
271
451
  for (const tableName of tables) {
272
452
  const desc = this.getTableDescription(tableName);
@@ -295,10 +475,11 @@ class KnowledgeStore {
295
475
  const rules = this.getActiveRulesForTables(tables);
296
476
  if (rules.length > 0) {
297
477
  parts.push('## Business Rules');
478
+ parts.push('Always apply these rules when querying:');
298
479
  for (const rule of rules) {
299
- parts.push(`- ${rule.name}: ${rule.description}`);
480
+ parts.push(`- **${rule.name}**: ${rule.description}`);
300
481
  if (rule.condition) {
301
- parts.push(` Condition: ${rule.condition}`);
482
+ parts.push(` SQL condition: \`${rule.condition}\``);
302
483
  }
303
484
  }
304
485
  parts.push('');
@@ -307,11 +488,14 @@ class KnowledgeStore {
307
488
  const examples = this.getQueryExamplesForTables(tables);
308
489
  if (examples.length > 0) {
309
490
  parts.push('## Query Examples');
491
+ parts.push('Reference these verified examples:');
310
492
  for (const ex of examples.slice(0, 5)) { // Limit to 5 examples
311
- parts.push(`Intent: ${ex.intent}`);
312
- parts.push(`SQL: ${ex.sql}`);
493
+ parts.push(`Intent: "${ex.intent}"`);
494
+ parts.push('```sql');
495
+ parts.push(ex.sql);
496
+ parts.push('```');
313
497
  if (ex.explanation) {
314
- parts.push(`Explanation: ${ex.explanation}`);
498
+ parts.push(`Note: ${ex.explanation}`);
315
499
  }
316
500
  parts.push('');
317
501
  }
@@ -327,6 +511,7 @@ class KnowledgeStore {
327
511
  tableDescriptions: [],
328
512
  queryExamples: [],
329
513
  businessRules: [],
514
+ businessTerms: [],
330
515
  };
331
516
  }
332
517
  /**
@@ -334,7 +519,7 @@ class KnowledgeStore {
334
519
  */
335
520
  getData() {
336
521
  if (!this.data) {
337
- return { tables: [], queryExamples: [], businessRules: [] };
522
+ return { tables: [], queryExamples: [], businessRules: [], businessTerms: [] };
338
523
  }
339
524
  return {
340
525
  tables: this.data.tableDescriptions.map(td => ({
@@ -345,6 +530,7 @@ class KnowledgeStore {
345
530
  })),
346
531
  queryExamples: this.data.queryExamples,
347
532
  businessRules: this.data.businessRules,
533
+ businessTerms: this.data.businessTerms ?? [],
348
534
  };
349
535
  }
350
536
  }