@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.
- package/.cursorrules +12 -0
- package/.env.example +8 -0
- package/.github/workflows/ci.yml +21 -1
- package/.github/workflows/publish.yml +21 -1
- package/CHANGELOG.md +41 -0
- package/README.md +247 -239
- package/cursor-mcp-config.json.example +29 -0
- package/datacontext.db +0 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +145 -0
- package/dist/api/server.js.map +1 -1
- package/dist/api/start-server.d.ts +10 -0
- package/dist/api/start-server.d.ts.map +1 -0
- package/dist/api/start-server.js +73 -0
- package/dist/api/start-server.js.map +1 -0
- package/dist/cli/index.js +462 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/context-service.d.ts +72 -0
- package/dist/core/context-service.d.ts.map +1 -1
- package/dist/core/context-service.js +132 -0
- package/dist/core/context-service.js.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +5 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/llm-service.d.ts +141 -0
- package/dist/core/llm-service.d.ts.map +1 -0
- package/dist/core/llm-service.js +284 -0
- package/dist/core/llm-service.js.map +1 -0
- package/dist/knowledge/store.d.ts +56 -3
- package/dist/knowledge/store.d.ts.map +1 -1
- package/dist/knowledge/store.js +193 -7
- package/dist/knowledge/store.js.map +1 -1
- package/dist/knowledge/types.d.ts +43 -1
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/knowledge/types.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +365 -0
- package/dist/mcp/tools.js.map +1 -1
- package/docs/API.md +173 -0
- package/docs/DEMO_SCRIPT.md +210 -0
- package/docs/MCP_TEST_GUIDE.md +414 -0
- package/docs/SYNC_GUIDE.md +242 -0
- package/package.json +4 -1
- package/src/api/server.ts +160 -0
- package/src/api/start-server.ts +78 -0
- package/src/cli/index.ts +534 -0
- package/src/core/context-service.ts +182 -0
- package/src/core/index.ts +7 -0
- package/src/core/llm-service.ts +359 -0
- package/src/knowledge/store.ts +232 -7
- package/src/knowledge/types.ts +45 -1
- package/src/mcp/tools.ts +415 -0
- package/test-glossary.yaml +55 -0
- package/test-mcp.db +0 -0
package/src/api/server.ts
CHANGED
|
@@ -403,6 +403,166 @@ export function createApiServer(config: ApiServerConfig): express.Application {
|
|
|
403
403
|
}
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
+
// ============================================================
|
|
407
|
+
// Glossary (Business Terms) Endpoints
|
|
408
|
+
// ============================================================
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* List all business terms
|
|
412
|
+
* GET /api/terms?category=status&table=users
|
|
413
|
+
*/
|
|
414
|
+
app.get('/api/terms', (_req: Request, res: Response) => {
|
|
415
|
+
try {
|
|
416
|
+
const category = _req.query.category as string | undefined;
|
|
417
|
+
const table = _req.query.table as string | undefined;
|
|
418
|
+
|
|
419
|
+
let terms = service.getBusinessTerms();
|
|
420
|
+
|
|
421
|
+
// Apply filters
|
|
422
|
+
if (category) {
|
|
423
|
+
terms = terms.filter(t => t.category === category);
|
|
424
|
+
}
|
|
425
|
+
if (table) {
|
|
426
|
+
terms = terms.filter(t => t.appliesTo?.tables?.includes(table));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
res.json({
|
|
430
|
+
count: terms.length,
|
|
431
|
+
terms,
|
|
432
|
+
});
|
|
433
|
+
} catch (error) {
|
|
434
|
+
res.status(500).json({
|
|
435
|
+
error: error instanceof Error ? error.message : 'Failed to get terms'
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Search business terms
|
|
442
|
+
* GET /api/terms/search?q=활성
|
|
443
|
+
*/
|
|
444
|
+
app.get('/api/terms/search', (_req: Request, res: Response) => {
|
|
445
|
+
try {
|
|
446
|
+
const query = _req.query.q as string;
|
|
447
|
+
|
|
448
|
+
if (!query) {
|
|
449
|
+
res.status(400).json({ error: 'q (query) parameter is required' });
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const terms = service.findMatchingTerms(query);
|
|
454
|
+
|
|
455
|
+
res.json({
|
|
456
|
+
query,
|
|
457
|
+
count: terms.length,
|
|
458
|
+
terms,
|
|
459
|
+
suggestedConditions: terms
|
|
460
|
+
.filter(t => t.sqlExpression)
|
|
461
|
+
.map(t => t.sqlExpression),
|
|
462
|
+
});
|
|
463
|
+
} catch (error) {
|
|
464
|
+
res.status(500).json({
|
|
465
|
+
error: error instanceof Error ? error.message : 'Failed to search terms'
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Add a business term manually
|
|
472
|
+
* POST /api/terms
|
|
473
|
+
* Body: { term, definition, sql?, synonyms?, tables?, category? }
|
|
474
|
+
*/
|
|
475
|
+
app.post('/api/terms', async (req: Request, res: Response) => {
|
|
476
|
+
try {
|
|
477
|
+
const { term, definition, sql, synonyms, tables, category } = req.body;
|
|
478
|
+
|
|
479
|
+
if (!term || !definition) {
|
|
480
|
+
res.status(400).json({ error: 'term and definition are required' });
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const added = await service.addBusinessTerm(term, definition, {
|
|
485
|
+
sqlExpression: sql,
|
|
486
|
+
synonyms,
|
|
487
|
+
appliesTo: tables ? { tables } : undefined,
|
|
488
|
+
category,
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
res.json({ success: true, term: added });
|
|
492
|
+
} catch (error) {
|
|
493
|
+
res.status(500).json({
|
|
494
|
+
error: error instanceof Error ? error.message : 'Failed to add term'
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Generate glossary from raw terms using AI
|
|
501
|
+
* POST /api/terms/generate
|
|
502
|
+
* Body: { terms: string }
|
|
503
|
+
*/
|
|
504
|
+
app.post('/api/terms/generate', async (req: Request, res: Response) => {
|
|
505
|
+
try {
|
|
506
|
+
const { terms } = req.body;
|
|
507
|
+
|
|
508
|
+
if (!terms) {
|
|
509
|
+
res.status(400).json({ error: 'terms is required' });
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const generated = await service.generateGlossary(terms);
|
|
514
|
+
|
|
515
|
+
res.json({
|
|
516
|
+
success: true,
|
|
517
|
+
generated: generated.length,
|
|
518
|
+
terms: generated,
|
|
519
|
+
});
|
|
520
|
+
} catch (error) {
|
|
521
|
+
res.status(500).json({
|
|
522
|
+
error: error instanceof Error ? error.message : 'Failed to generate glossary'
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Delete a business term
|
|
529
|
+
* DELETE /api/terms/:id
|
|
530
|
+
*/
|
|
531
|
+
app.delete('/api/terms/:id', async (req: Request, res: Response) => {
|
|
532
|
+
try {
|
|
533
|
+
const { id } = req.params;
|
|
534
|
+
await service.deleteBusinessTerm(id);
|
|
535
|
+
res.json({ success: true, deleted: id });
|
|
536
|
+
} catch (error) {
|
|
537
|
+
res.status(500).json({
|
|
538
|
+
error: error instanceof Error ? error.message : 'Failed to delete term'
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Enhance a query with glossary terms
|
|
545
|
+
* POST /api/terms/enhance
|
|
546
|
+
* Body: { query: string }
|
|
547
|
+
*/
|
|
548
|
+
app.post('/api/terms/enhance', async (req: Request, res: Response) => {
|
|
549
|
+
try {
|
|
550
|
+
const { query } = req.body;
|
|
551
|
+
|
|
552
|
+
if (!query) {
|
|
553
|
+
res.status(400).json({ error: 'query is required' });
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const result = await service.enhanceQuery(query);
|
|
558
|
+
res.json(result);
|
|
559
|
+
} catch (error) {
|
|
560
|
+
res.status(500).json({
|
|
561
|
+
error: error instanceof Error ? error.message : 'Failed to enhance query'
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
406
566
|
// ============================================================
|
|
407
567
|
// Error Handler
|
|
408
568
|
// ============================================================
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Start DataContext REST API Server
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node dist/api/start-server.js
|
|
7
|
+
* DATABASE_URL=sqlite:./test.db npm run serve
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import 'dotenv/config';
|
|
11
|
+
import { createPostgresAdapter } from '../adapters/postgres.js';
|
|
12
|
+
import { createSQLiteAdapter } from '../adapters/sqlite.js';
|
|
13
|
+
import { createDataContextService } from '../core/context-service.js';
|
|
14
|
+
import { KnowledgeStore } from '../knowledge/store.js';
|
|
15
|
+
import { startApiServer } from './server.js';
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
const port = parseInt(process.env.PORT || '3000', 10);
|
|
19
|
+
const dbUrl = process.env.DATABASE_URL || 'sqlite:./datacontext.db';
|
|
20
|
+
|
|
21
|
+
console.log('[datacontext-api] Starting server...');
|
|
22
|
+
console.log(`[datacontext-api] Port: ${port}`);
|
|
23
|
+
console.log(`[datacontext-api] Database: ${dbUrl.split('?')[0]}`);
|
|
24
|
+
|
|
25
|
+
// Create appropriate adapter based on URL
|
|
26
|
+
let adapter;
|
|
27
|
+
if (dbUrl.startsWith('postgres://') || dbUrl.startsWith('postgresql://')) {
|
|
28
|
+
adapter = createPostgresAdapter(dbUrl);
|
|
29
|
+
} else if (dbUrl.startsWith('sqlite:')) {
|
|
30
|
+
const dbPath = dbUrl.replace('sqlite:', '');
|
|
31
|
+
adapter = createSQLiteAdapter(dbPath);
|
|
32
|
+
} else {
|
|
33
|
+
console.error('[datacontext-api] Unsupported database URL. Use postgres:// or sqlite:');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Create knowledge store
|
|
38
|
+
const databaseId = dbUrl.split('/').pop()?.split('?')[0] || 'default';
|
|
39
|
+
const knowledge = new KnowledgeStore(databaseId);
|
|
40
|
+
|
|
41
|
+
// Create service
|
|
42
|
+
const service = createDataContextService({
|
|
43
|
+
adapter,
|
|
44
|
+
knowledge,
|
|
45
|
+
safety: {
|
|
46
|
+
readOnly: true,
|
|
47
|
+
timeoutMs: 30000,
|
|
48
|
+
maxRows: 1000,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Initialize service
|
|
53
|
+
await service.initialize();
|
|
54
|
+
console.log('[datacontext-api] ✓ Service initialized');
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
await startApiServer({
|
|
58
|
+
service,
|
|
59
|
+
port,
|
|
60
|
+
cors: true,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log('[datacontext-api] ✓ Server started successfully');
|
|
64
|
+
console.log('[datacontext-api] ✓ API: http://localhost:' + port + '/api');
|
|
65
|
+
console.log('[datacontext-api] ✓ Health: http://localhost:' + port + '/health');
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log('[datacontext-api] Press Ctrl+C to stop');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('[datacontext-api] Failed to start server:', error);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
main().catch((error) => {
|
|
75
|
+
console.error('[datacontext-api] Fatal error:', error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
|