@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
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
+