@vdpeijl/kb-mcp 0.1.2

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 (106) hide show
  1. package/README.md +416 -0
  2. package/dist/scripts/postinstall.d.ts +3 -0
  3. package/dist/scripts/postinstall.d.ts.map +1 -0
  4. package/dist/scripts/postinstall.js +110 -0
  5. package/dist/scripts/postinstall.js.map +1 -0
  6. package/dist/src/cli.d.ts +3 -0
  7. package/dist/src/cli.d.ts.map +1 -0
  8. package/dist/src/cli.js +22 -0
  9. package/dist/src/cli.js.map +1 -0
  10. package/dist/src/commands/doctor.d.ts +3 -0
  11. package/dist/src/commands/doctor.d.ts.map +1 -0
  12. package/dist/src/commands/doctor.js +93 -0
  13. package/dist/src/commands/doctor.js.map +1 -0
  14. package/dist/src/commands/init.d.ts +3 -0
  15. package/dist/src/commands/init.d.ts.map +1 -0
  16. package/dist/src/commands/init.js +150 -0
  17. package/dist/src/commands/init.js.map +1 -0
  18. package/dist/src/commands/serve.d.ts +3 -0
  19. package/dist/src/commands/serve.d.ts.map +1 -0
  20. package/dist/src/commands/serve.js +22 -0
  21. package/dist/src/commands/serve.js.map +1 -0
  22. package/dist/src/commands/setup.d.ts +9 -0
  23. package/dist/src/commands/setup.d.ts.map +1 -0
  24. package/dist/src/commands/setup.js +115 -0
  25. package/dist/src/commands/setup.js.map +1 -0
  26. package/dist/src/commands/sources.d.ts +3 -0
  27. package/dist/src/commands/sources.d.ts.map +1 -0
  28. package/dist/src/commands/sources.js +258 -0
  29. package/dist/src/commands/sources.js.map +1 -0
  30. package/dist/src/commands/stats.d.ts +3 -0
  31. package/dist/src/commands/stats.d.ts.map +1 -0
  32. package/dist/src/commands/stats.js +48 -0
  33. package/dist/src/commands/stats.js.map +1 -0
  34. package/dist/src/commands/sync.d.ts +13 -0
  35. package/dist/src/commands/sync.d.ts.map +1 -0
  36. package/dist/src/commands/sync.js +106 -0
  37. package/dist/src/commands/sync.js.map +1 -0
  38. package/dist/src/config/index.d.ts +18 -0
  39. package/dist/src/config/index.d.ts.map +1 -0
  40. package/dist/src/config/index.js +67 -0
  41. package/dist/src/config/index.js.map +1 -0
  42. package/dist/src/config/paths.d.ts +21 -0
  43. package/dist/src/config/paths.d.ts.map +1 -0
  44. package/dist/src/config/paths.js +38 -0
  45. package/dist/src/config/paths.js.map +1 -0
  46. package/dist/src/config/schema.d.ts +133 -0
  47. package/dist/src/config/schema.d.ts.map +1 -0
  48. package/dist/src/config/schema.js +34 -0
  49. package/dist/src/config/schema.js.map +1 -0
  50. package/dist/src/db/articles.d.ts +39 -0
  51. package/dist/src/db/articles.d.ts.map +1 -0
  52. package/dist/src/db/articles.js +103 -0
  53. package/dist/src/db/articles.js.map +1 -0
  54. package/dist/src/db/chunks.d.ts +46 -0
  55. package/dist/src/db/chunks.d.ts.map +1 -0
  56. package/dist/src/db/chunks.js +129 -0
  57. package/dist/src/db/chunks.js.map +1 -0
  58. package/dist/src/db/index.d.ts +19 -0
  59. package/dist/src/db/index.d.ts.map +1 -0
  60. package/dist/src/db/index.js +86 -0
  61. package/dist/src/db/index.js.map +1 -0
  62. package/dist/src/db/schema.d.ts +10 -0
  63. package/dist/src/db/schema.d.ts.map +1 -0
  64. package/dist/src/db/schema.js +80 -0
  65. package/dist/src/db/schema.js.map +1 -0
  66. package/dist/src/db/sources.d.ts +48 -0
  67. package/dist/src/db/sources.d.ts.map +1 -0
  68. package/dist/src/db/sources.js +110 -0
  69. package/dist/src/db/sources.js.map +1 -0
  70. package/dist/src/index.d.ts +8 -0
  71. package/dist/src/index.d.ts.map +1 -0
  72. package/dist/src/index.js +87 -0
  73. package/dist/src/index.js.map +1 -0
  74. package/dist/src/search/embeddings.d.ts +22 -0
  75. package/dist/src/search/embeddings.d.ts.map +1 -0
  76. package/dist/src/search/embeddings.js +122 -0
  77. package/dist/src/search/embeddings.js.map +1 -0
  78. package/dist/src/search/index.d.ts +21 -0
  79. package/dist/src/search/index.d.ts.map +1 -0
  80. package/dist/src/search/index.js +50 -0
  81. package/dist/src/search/index.js.map +1 -0
  82. package/dist/src/sync/chunker.d.ts +15 -0
  83. package/dist/src/sync/chunker.d.ts.map +1 -0
  84. package/dist/src/sync/chunker.js +117 -0
  85. package/dist/src/sync/chunker.js.map +1 -0
  86. package/dist/src/sync/index.d.ts +24 -0
  87. package/dist/src/sync/index.d.ts.map +1 -0
  88. package/dist/src/sync/index.js +180 -0
  89. package/dist/src/sync/index.js.map +1 -0
  90. package/dist/src/sync/parser.d.ts +9 -0
  91. package/dist/src/sync/parser.d.ts.map +1 -0
  92. package/dist/src/sync/parser.js +91 -0
  93. package/dist/src/sync/parser.js.map +1 -0
  94. package/dist/src/sync/zendesk.d.ts +45 -0
  95. package/dist/src/sync/zendesk.d.ts.map +1 -0
  96. package/dist/src/sync/zendesk.js +161 -0
  97. package/dist/src/sync/zendesk.js.map +1 -0
  98. package/dist/src/utils/errors.d.ts +39 -0
  99. package/dist/src/utils/errors.d.ts.map +1 -0
  100. package/dist/src/utils/errors.js +62 -0
  101. package/dist/src/utils/errors.js.map +1 -0
  102. package/dist/src/utils/logger.d.ts +21 -0
  103. package/dist/src/utils/logger.d.ts.map +1 -0
  104. package/dist/src/utils/logger.js +25 -0
  105. package/dist/src/utils/logger.js.map +1 -0
  106. package/package.json +57 -0
@@ -0,0 +1,48 @@
1
+ import { defineCommand } from 'citty';
2
+ import { getDatabase, getDatabaseStats } from '../db/index.js';
3
+ import { getSourcesWithStats } from '../db/sources.js';
4
+ import { exitWithError } from '../utils/errors.js';
5
+ export default defineCommand({
6
+ meta: {
7
+ name: 'stats',
8
+ description: 'Show database statistics',
9
+ },
10
+ async run() {
11
+ try {
12
+ const db = await getDatabase();
13
+ const stats = await getDatabaseStats();
14
+ const sources = getSourcesWithStats(db);
15
+ console.log('\n📊 Database Statistics\n');
16
+ console.log(`Sources: ${stats.sources}`);
17
+ console.log(`Articles: ${stats.articles}`);
18
+ console.log(`Chunks: ${stats.chunks}`);
19
+ console.log(`Database Size: ${formatBytes(stats.databaseSize)}`);
20
+ if (sources.length > 0) {
21
+ console.log('\n📚 Sources:\n');
22
+ for (const source of sources) {
23
+ const status = source.enabled ? '✓' : '✗';
24
+ const lastSynced = source.lastSyncedAt
25
+ ? source.lastSyncedAt.toLocaleString()
26
+ : 'Never';
27
+ console.log(`${status} ${source.name} (${source.id})`);
28
+ console.log(` Articles: ${source.articleCount}`);
29
+ console.log(` Chunks: ${source.chunkCount}`);
30
+ console.log(` Last Synced: ${lastSynced}`);
31
+ console.log();
32
+ }
33
+ }
34
+ }
35
+ catch (error) {
36
+ exitWithError(error);
37
+ }
38
+ },
39
+ });
40
+ function formatBytes(bytes) {
41
+ if (bytes === 0)
42
+ return '0 Bytes';
43
+ const k = 1024;
44
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
45
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
46
+ return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
47
+ }
48
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/commands/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,eAAe,aAAa,CAAC;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,0BAA0B;KACxC;IACD,KAAK,CAAC,GAAG;QACP,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAC;YAExC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,kBAAkB,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAEjE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAE/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;oBAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY;wBACpC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE;wBACtC,CAAC,CAAC,OAAO,CAAC;oBAEZ,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;oBACvD,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;oBAClD,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;oBAC9C,OAAO,CAAC,GAAG,CAAC,kBAAkB,UAAU,EAAE,CAAC,CAAC;oBAC5C,OAAO,CAAC,GAAG,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAElC,MAAM,CAAC,GAAG,IAAI,CAAC;IACf,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,13 @@
1
+ declare const _default: import("citty").CommandDef<{
2
+ source: {
3
+ type: "string";
4
+ description: string;
5
+ };
6
+ full: {
7
+ type: "boolean";
8
+ description: string;
9
+ default: false;
10
+ };
11
+ }>;
12
+ export default _default;
13
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":";;;;;;;;;;;AAQA,wBAsGG"}
@@ -0,0 +1,106 @@
1
+ import { defineCommand } from 'citty';
2
+ import { loadConfig } from '../config/index.js';
3
+ import { getDatabase } from '../db/index.js';
4
+ import { getEnabledSources, getSource } from '../db/sources.js';
5
+ import { syncSource } from '../sync/index.js';
6
+ import { exitWithError } from '../utils/errors.js';
7
+ export default defineCommand({
8
+ meta: {
9
+ name: 'sync',
10
+ description: 'Sync knowledge bases',
11
+ },
12
+ args: {
13
+ source: {
14
+ type: 'string',
15
+ description: 'Sync specific source only',
16
+ },
17
+ full: {
18
+ type: 'boolean',
19
+ description: 'Full re-sync (re-embed everything)',
20
+ default: false,
21
+ },
22
+ },
23
+ async run({ args }) {
24
+ try {
25
+ const config = await loadConfig();
26
+ const db = await getDatabase();
27
+ // Sync sources from config to database
28
+ const { upsertSource } = await import('../db/sources.js');
29
+ for (const source of config.sources) {
30
+ upsertSource(db, source);
31
+ }
32
+ let sources;
33
+ if (args.source) {
34
+ const source = getSource(db, args.source);
35
+ if (!source) {
36
+ console.error(`\n✗ Source not found: ${args.source}\n`);
37
+ process.exit(1);
38
+ }
39
+ sources = [source];
40
+ }
41
+ else {
42
+ sources = getEnabledSources(db);
43
+ if (sources.length === 0) {
44
+ console.log('\nNo enabled sources to sync.\n');
45
+ console.log('Add a source with:');
46
+ console.log(' kb-mcp sources add\n');
47
+ return;
48
+ }
49
+ }
50
+ const fullResync = args.full === true;
51
+ if (fullResync) {
52
+ console.log('\n🔄 Running full re-sync (all articles will be re-processed)\n');
53
+ }
54
+ else {
55
+ console.log('\n🔄 Running incremental sync\n');
56
+ }
57
+ for (const source of sources) {
58
+ console.log(`\n📚 Syncing: ${source.name}`);
59
+ console.log('─'.repeat(50));
60
+ const startTime = Date.now();
61
+ let lastMessage = '';
62
+ const result = await syncSource(db, source, config, (progress) => {
63
+ const message = formatProgress(progress);
64
+ if (message !== lastMessage) {
65
+ // Clear previous line
66
+ if (lastMessage) {
67
+ process.stdout.write('\r\x1b[K');
68
+ }
69
+ process.stdout.write(message);
70
+ lastMessage = message;
71
+ }
72
+ }, fullResync);
73
+ // Clear progress line
74
+ if (lastMessage) {
75
+ process.stdout.write('\r\x1b[K');
76
+ }
77
+ const duration = (result.timeElapsed / 1000).toFixed(1);
78
+ console.log(`✓ Sync complete in ${duration}s`);
79
+ console.log(` Articles fetched: ${result.articlesFetched}`);
80
+ console.log(` Articles processed: ${result.articlesProcessed}`);
81
+ console.log(` Chunks created: ${result.chunksCreated}`);
82
+ }
83
+ console.log('\n✅ Sync completed successfully\n');
84
+ }
85
+ catch (error) {
86
+ exitWithError(error);
87
+ }
88
+ },
89
+ });
90
+ function formatProgress(progress) {
91
+ const { phase, current, total, message } = progress;
92
+ const phaseEmojis = {
93
+ fetching: '📥',
94
+ parsing: '📝',
95
+ chunking: '✂️',
96
+ embedding: '🔢',
97
+ storing: '💾',
98
+ };
99
+ const emoji = phaseEmojis[phase];
100
+ const percent = total > 0 ? Math.round((current / total) * 100) : 0;
101
+ if (total > 0 && current > 0) {
102
+ return `${emoji} ${message} (${percent}%)`;
103
+ }
104
+ return `${emoji} ${message}`;
105
+ }
106
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,eAAe,aAAa,CAAC;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,sBAAsB;KACpC;IACD,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2BAA2B;SACzC;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,oCAAoC;YACjD,OAAO,EAAE,KAAK;SACf;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;YAE/B,uCAAuC;YACvC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;YAC1D,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC;YAED,IAAI,OAAO,CAAC;YAEZ,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,MAAgB,CAAC,CAAC;gBAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,CAAC,KAAK,CAAC,yBAAyB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;oBACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBAED,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAC;gBAEhC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACzB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;oBAC/C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;oBAClC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;oBACtC,OAAO;gBACT,CAAC;YACH,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;YAEtC,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;YACjF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;YACjD,CAAC;YAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC7B,IAAI,WAAW,GAAG,EAAE,CAAC;gBAErB,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,EAAE,EACF,MAAM,EACN,MAAM,EACN,CAAC,QAAsB,EAAE,EAAE;oBACzB,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;oBAEzC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;wBAC5B,sBAAsB;wBACtB,IAAI,WAAW,EAAE,CAAC;4BAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;wBACnC,CAAC;wBAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBAC9B,WAAW,GAAG,OAAO,CAAC;oBACxB,CAAC;gBACH,CAAC,EACD,UAAU,CACX,CAAC;gBAEF,sBAAsB;gBACtB,IAAI,WAAW,EAAE,CAAC;oBAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACnC,CAAC;gBAED,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAExD,OAAO,CAAC,GAAG,CAAC,sBAAsB,QAAQ,GAAG,CAAC,CAAC;gBAC/C,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;gBACjE,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;YAC3D,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,cAAc,CAAC,QAAsB;IAC5C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC;IAEpD,MAAM,WAAW,GAAiC;QAChD,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,IAAI;KACd,CAAC;IAEF,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpE,IAAI,KAAK,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,KAAK,IAAI,OAAO,KAAK,OAAO,IAAI,CAAC;IAC7C,CAAC;IAED,OAAO,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type Config } from './schema.js';
2
+ /**
3
+ * Load configuration from disk
4
+ */
5
+ export declare function loadConfig(): Promise<Config>;
6
+ /**
7
+ * Save configuration to disk
8
+ */
9
+ export declare function saveConfig(config: Config): Promise<void>;
10
+ /**
11
+ * Check if configuration exists
12
+ */
13
+ export declare function configExists(): boolean;
14
+ /**
15
+ * Get a default configuration
16
+ */
17
+ export declare function getDefaultConfig(): Config;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA0ClD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAGtC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
@@ -0,0 +1,67 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { ZodError } from 'zod';
4
+ import { getXDGPaths, ensureDirectories } from './paths.js';
5
+ import { ConfigSchema } from './schema.js';
6
+ /**
7
+ * Load configuration from disk
8
+ */
9
+ export async function loadConfig() {
10
+ const paths = await ensureDirectories();
11
+ const configPath = paths.configFile;
12
+ // Check if config exists
13
+ if (!existsSync(configPath)) {
14
+ throw new Error(`Configuration file not found at ${configPath}\n\n` +
15
+ `Run 'kb-mcp init' to create a configuration file.`);
16
+ }
17
+ // Read and parse config file
18
+ const configData = await readFile(configPath, 'utf-8');
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(configData);
22
+ }
23
+ catch (error) {
24
+ throw new Error(`Invalid JSON in configuration file: ${configPath}\n\n` +
25
+ `Please check the file for syntax errors.`);
26
+ }
27
+ // Validate with Zod
28
+ try {
29
+ return ConfigSchema.parse(parsed);
30
+ }
31
+ catch (error) {
32
+ if (error instanceof ZodError) {
33
+ const issues = error.issues.map(issue => {
34
+ const path = issue.path.join('.');
35
+ return ` • ${path}: ${issue.message}`;
36
+ }).join('\n');
37
+ throw new Error(`Invalid configuration at ${configPath}\n\n${issues}\n\n` +
38
+ `Run 'kb-mcp init' to reconfigure, or edit the file manually.`);
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ /**
44
+ * Save configuration to disk
45
+ */
46
+ export async function saveConfig(config) {
47
+ const paths = await ensureDirectories();
48
+ const configPath = paths.configFile;
49
+ // Validate before saving
50
+ const validated = ConfigSchema.parse(config);
51
+ // Write to file with pretty formatting
52
+ await writeFile(configPath, JSON.stringify(validated, null, 2), 'utf-8');
53
+ }
54
+ /**
55
+ * Check if configuration exists
56
+ */
57
+ export function configExists() {
58
+ const paths = getXDGPaths();
59
+ return existsSync(paths.configFile);
60
+ }
61
+ /**
62
+ * Get a default configuration
63
+ */
64
+ export function getDefaultConfig() {
65
+ return ConfigSchema.parse({});
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAEpC,yBAAyB;IACzB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,mCAAmC,UAAU,MAAM;YACnD,mDAAmD,CACpD,CAAC;IACJ,CAAC;IAED,6BAA6B;IAC7B,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACvD,IAAI,MAAe,CAAC;IAEpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,uCAAuC,UAAU,MAAM;YACvD,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAClC,OAAO,OAAO,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACzC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,MAAM,IAAI,KAAK,CACb,4BAA4B,UAAU,OAAO,MAAM,MAAM;gBACzD,8DAA8D,CAC/D,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc;IAC7C,MAAM,KAAK,GAAG,MAAM,iBAAiB,EAAE,CAAC;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAEpC,yBAAyB;IACzB,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE7C,uCAAuC;IACvC,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Get XDG Base Directory paths or fallback to platform defaults
3
+ */
4
+ export declare function getXDGPaths(): {
5
+ config: string;
6
+ data: string;
7
+ configFile: string;
8
+ database: string;
9
+ logs: string;
10
+ };
11
+ /**
12
+ * Ensure all necessary directories exist
13
+ */
14
+ export declare function ensureDirectories(): Promise<{
15
+ config: string;
16
+ data: string;
17
+ configFile: string;
18
+ database: string;
19
+ logs: string;
20
+ }>;
21
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/config/paths.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,WAAW;;;;;;EAuB1B;AAED;;GAEG;AACH,wBAAsB,iBAAiB;;;;;;GAQtC"}
@@ -0,0 +1,38 @@
1
+ import { homedir, platform } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { mkdir } from 'node:fs/promises';
4
+ /**
5
+ * Get XDG Base Directory paths or fallback to platform defaults
6
+ */
7
+ export function getXDGPaths() {
8
+ const home = homedir();
9
+ const isWindows = platform() === 'win32';
10
+ // Config directory
11
+ const configHome = process.env.XDG_CONFIG_HOME ||
12
+ (isWindows
13
+ ? join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'kb-mcp')
14
+ : join(home, '.config', 'kb-mcp'));
15
+ // Data directory
16
+ const dataHome = process.env.XDG_DATA_HOME ||
17
+ (isWindows
18
+ ? join(process.env.LOCALAPPDATA || join(home, 'AppData', 'Local'), 'kb-mcp')
19
+ : join(home, '.local', 'share', 'kb-mcp'));
20
+ return {
21
+ config: configHome,
22
+ data: dataHome,
23
+ configFile: join(configHome, 'config.json'),
24
+ database: join(dataHome, 'kb.sqlite'),
25
+ logs: join(dataHome, 'logs'),
26
+ };
27
+ }
28
+ /**
29
+ * Ensure all necessary directories exist
30
+ */
31
+ export async function ensureDirectories() {
32
+ const paths = getXDGPaths();
33
+ await mkdir(paths.config, { recursive: true });
34
+ await mkdir(paths.data, { recursive: true });
35
+ await mkdir(paths.logs, { recursive: true });
36
+ return paths;
37
+ }
38
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAC;IAEzC,mBAAmB;IACnB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe;QAC5C,CAAC,SAAS;YACR,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC;YACzE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvC,iBAAiB;IACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa;QACxC,CAAC,SAAS;YACR,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC;YAC5E,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/C,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC;QAC3C,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC;QACrC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAE5B,MAAM,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,133 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for Ollama configuration
4
+ */
5
+ export declare const OllamaConfigSchema: z.ZodObject<{
6
+ baseUrl: z.ZodDefault<z.ZodString>;
7
+ model: z.ZodDefault<z.ZodString>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ baseUrl: string;
10
+ model: string;
11
+ }, {
12
+ baseUrl?: string | undefined;
13
+ model?: string | undefined;
14
+ }>;
15
+ /**
16
+ * Zod schema for sync configuration
17
+ */
18
+ export declare const SyncConfigSchema: z.ZodObject<{
19
+ chunkSize: z.ZodDefault<z.ZodNumber>;
20
+ chunkOverlap: z.ZodDefault<z.ZodNumber>;
21
+ }, "strip", z.ZodTypeAny, {
22
+ chunkSize: number;
23
+ chunkOverlap: number;
24
+ }, {
25
+ chunkSize?: number | undefined;
26
+ chunkOverlap?: number | undefined;
27
+ }>;
28
+ /**
29
+ * Zod schema for a knowledge base source
30
+ */
31
+ export declare const SourceSchema: z.ZodObject<{
32
+ id: z.ZodString;
33
+ name: z.ZodString;
34
+ baseUrl: z.ZodString;
35
+ locale: z.ZodString;
36
+ enabled: z.ZodDefault<z.ZodBoolean>;
37
+ }, "strip", z.ZodTypeAny, {
38
+ baseUrl: string;
39
+ id: string;
40
+ name: string;
41
+ locale: string;
42
+ enabled: boolean;
43
+ }, {
44
+ baseUrl: string;
45
+ id: string;
46
+ name: string;
47
+ locale: string;
48
+ enabled?: boolean | undefined;
49
+ }>;
50
+ /**
51
+ * Zod schema for the complete configuration
52
+ */
53
+ export declare const ConfigSchema: z.ZodObject<{
54
+ ollama: z.ZodDefault<z.ZodObject<{
55
+ baseUrl: z.ZodDefault<z.ZodString>;
56
+ model: z.ZodDefault<z.ZodString>;
57
+ }, "strip", z.ZodTypeAny, {
58
+ baseUrl: string;
59
+ model: string;
60
+ }, {
61
+ baseUrl?: string | undefined;
62
+ model?: string | undefined;
63
+ }>>;
64
+ sync: z.ZodDefault<z.ZodObject<{
65
+ chunkSize: z.ZodDefault<z.ZodNumber>;
66
+ chunkOverlap: z.ZodDefault<z.ZodNumber>;
67
+ }, "strip", z.ZodTypeAny, {
68
+ chunkSize: number;
69
+ chunkOverlap: number;
70
+ }, {
71
+ chunkSize?: number | undefined;
72
+ chunkOverlap?: number | undefined;
73
+ }>>;
74
+ sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
75
+ id: z.ZodString;
76
+ name: z.ZodString;
77
+ baseUrl: z.ZodString;
78
+ locale: z.ZodString;
79
+ enabled: z.ZodDefault<z.ZodBoolean>;
80
+ }, "strip", z.ZodTypeAny, {
81
+ baseUrl: string;
82
+ id: string;
83
+ name: string;
84
+ locale: string;
85
+ enabled: boolean;
86
+ }, {
87
+ baseUrl: string;
88
+ id: string;
89
+ name: string;
90
+ locale: string;
91
+ enabled?: boolean | undefined;
92
+ }>, "many">>;
93
+ }, "strip", z.ZodTypeAny, {
94
+ ollama: {
95
+ baseUrl: string;
96
+ model: string;
97
+ };
98
+ sync: {
99
+ chunkSize: number;
100
+ chunkOverlap: number;
101
+ };
102
+ sources: {
103
+ baseUrl: string;
104
+ id: string;
105
+ name: string;
106
+ locale: string;
107
+ enabled: boolean;
108
+ }[];
109
+ }, {
110
+ ollama?: {
111
+ baseUrl?: string | undefined;
112
+ model?: string | undefined;
113
+ } | undefined;
114
+ sync?: {
115
+ chunkSize?: number | undefined;
116
+ chunkOverlap?: number | undefined;
117
+ } | undefined;
118
+ sources?: {
119
+ baseUrl: string;
120
+ id: string;
121
+ name: string;
122
+ locale: string;
123
+ enabled?: boolean | undefined;
124
+ }[] | undefined;
125
+ }>;
126
+ /**
127
+ * TypeScript types inferred from schemas
128
+ */
129
+ export type OllamaConfig = z.infer<typeof OllamaConfigSchema>;
130
+ export type SyncConfig = z.infer<typeof SyncConfigSchema>;
131
+ export type Source = z.infer<typeof SourceSchema>;
132
+ export type Config = z.infer<typeof ConfigSchema>;
133
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;EAG7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;EAMvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIvB,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAClD,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Zod schema for Ollama configuration
4
+ */
5
+ export const OllamaConfigSchema = z.object({
6
+ baseUrl: z.string().url().default('http://localhost:11434'),
7
+ model: z.string().default('nomic-embed-text'),
8
+ });
9
+ /**
10
+ * Zod schema for sync configuration
11
+ */
12
+ export const SyncConfigSchema = z.object({
13
+ chunkSize: z.number().int().positive().default(500),
14
+ chunkOverlap: z.number().int().nonnegative().default(50),
15
+ });
16
+ /**
17
+ * Zod schema for a knowledge base source
18
+ */
19
+ export const SourceSchema = z.object({
20
+ id: z.string().min(1),
21
+ name: z.string().min(1),
22
+ baseUrl: z.string().url(),
23
+ locale: z.string().min(2),
24
+ enabled: z.boolean().default(true),
25
+ });
26
+ /**
27
+ * Zod schema for the complete configuration
28
+ */
29
+ export const ConfigSchema = z.object({
30
+ ollama: OllamaConfigSchema.default({}),
31
+ sync: SyncConfigSchema.default({}),
32
+ sources: z.array(SourceSchema).default([]),
33
+ });
34
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,wBAAwB,CAAC;IAC3D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC;CAC9C,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IACnD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACzD,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;CACnC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,MAAM,EAAE,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;IACtC,IAAI,EAAE,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;IAClC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC3C,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type Database from 'better-sqlite3';
2
+ export interface Article {
3
+ id: number;
4
+ sourceId: string;
5
+ title: string;
6
+ url: string;
7
+ sectionName?: string;
8
+ categoryName?: string;
9
+ updatedAt: Date;
10
+ }
11
+ /**
12
+ * Insert or update an article
13
+ */
14
+ export declare function upsertArticle(db: Database.Database, article: Article): void;
15
+ /**
16
+ * Get an article by ID and source
17
+ */
18
+ export declare function getArticle(db: Database.Database, id: number, sourceId: string): Article | null;
19
+ /**
20
+ * Get all articles for a source
21
+ */
22
+ export declare function getArticlesBySource(db: Database.Database, sourceId: string): Article[];
23
+ /**
24
+ * Get articles that have been updated since last sync
25
+ * Returns articles from Zendesk that are newer than what we have
26
+ */
27
+ export declare function getStaleArticleIds(db: Database.Database, sourceId: string, freshArticles: Array<{
28
+ id: number;
29
+ updated_at: string;
30
+ }>): Set<number>;
31
+ /**
32
+ * Delete an article and its chunks
33
+ */
34
+ export declare function deleteArticle(db: Database.Database, id: number, sourceId: string): void;
35
+ /**
36
+ * Delete articles that no longer exist in Zendesk
37
+ */
38
+ export declare function deleteOrphanedArticles(db: Database.Database, sourceId: string, validArticleIds: number[]): void;
39
+ //# sourceMappingURL=articles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../../src/db/articles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;CACjB;AAaD;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAuB3E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAiB9F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAatF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,GAAG,CAAC,MAAM,CAAC,CA8Bb;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAIvF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EAAE,GACxB,IAAI,CAcN"}