@ansvar/rwandan-law-mcp 1.0.0

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 (124) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +83 -0
  3. package/dist/__tests__/contract/golden.test.d.ts +9 -0
  4. package/dist/__tests__/contract/golden.test.d.ts.map +1 -0
  5. package/dist/__tests__/contract/golden.test.js +76 -0
  6. package/dist/__tests__/contract/golden.test.js.map +1 -0
  7. package/dist/api/health.d.ts +3 -0
  8. package/dist/api/health.d.ts.map +1 -0
  9. package/dist/api/health.js +101 -0
  10. package/dist/api/health.js.map +1 -0
  11. package/dist/api/mcp.d.ts +3 -0
  12. package/dist/api/mcp.d.ts.map +1 -0
  13. package/dist/api/mcp.js +119 -0
  14. package/dist/api/mcp.js.map +1 -0
  15. package/dist/scripts/build-db.d.ts +11 -0
  16. package/dist/scripts/build-db.d.ts.map +1 -0
  17. package/dist/scripts/build-db.js +375 -0
  18. package/dist/scripts/build-db.js.map +1 -0
  19. package/dist/scripts/drift-detect.d.ts +9 -0
  20. package/dist/scripts/drift-detect.d.ts.map +1 -0
  21. package/dist/scripts/drift-detect.js +62 -0
  22. package/dist/scripts/drift-detect.js.map +1 -0
  23. package/dist/scripts/ingest.d.ts +10 -0
  24. package/dist/scripts/ingest.d.ts.map +1 -0
  25. package/dist/scripts/ingest.js +333 -0
  26. package/dist/scripts/ingest.js.map +1 -0
  27. package/dist/scripts/lib/fetcher.d.ts +26 -0
  28. package/dist/scripts/lib/fetcher.d.ts.map +1 -0
  29. package/dist/scripts/lib/fetcher.js +102 -0
  30. package/dist/scripts/lib/fetcher.js.map +1 -0
  31. package/dist/scripts/lib/parser.d.ts +60 -0
  32. package/dist/scripts/lib/parser.d.ts.map +1 -0
  33. package/dist/scripts/lib/parser.js +560 -0
  34. package/dist/scripts/lib/parser.js.map +1 -0
  35. package/dist/scripts/lib/pdf.d.ts +7 -0
  36. package/dist/scripts/lib/pdf.d.ts.map +1 -0
  37. package/dist/scripts/lib/pdf.js +124 -0
  38. package/dist/scripts/lib/pdf.js.map +1 -0
  39. package/dist/src/capabilities.d.ts +16 -0
  40. package/dist/src/capabilities.d.ts.map +1 -0
  41. package/dist/src/capabilities.js +43 -0
  42. package/dist/src/capabilities.js.map +1 -0
  43. package/dist/src/constants.d.ts +7 -0
  44. package/dist/src/constants.d.ts.map +1 -0
  45. package/dist/src/constants.js +7 -0
  46. package/dist/src/constants.js.map +1 -0
  47. package/dist/src/index.d.ts +8 -0
  48. package/dist/src/index.d.ts.map +1 -0
  49. package/dist/src/index.js +80 -0
  50. package/dist/src/index.js.map +1 -0
  51. package/dist/src/tools/about.d.ts +45 -0
  52. package/dist/src/tools/about.d.ts.map +1 -0
  53. package/dist/src/tools/about.js +54 -0
  54. package/dist/src/tools/about.js.map +1 -0
  55. package/dist/src/tools/build-legal-stance.d.ts +21 -0
  56. package/dist/src/tools/build-legal-stance.d.ts.map +1 -0
  57. package/dist/src/tools/build-legal-stance.js +46 -0
  58. package/dist/src/tools/build-legal-stance.js.map +1 -0
  59. package/dist/src/tools/check-currency.d.ts +20 -0
  60. package/dist/src/tools/check-currency.d.ts.map +1 -0
  61. package/dist/src/tools/check-currency.js +41 -0
  62. package/dist/src/tools/check-currency.js.map +1 -0
  63. package/dist/src/tools/format-citation.d.ts +14 -0
  64. package/dist/src/tools/format-citation.d.ts.map +1 -0
  65. package/dist/src/tools/format-citation.js +28 -0
  66. package/dist/src/tools/format-citation.js.map +1 -0
  67. package/dist/src/tools/get-eu-basis.d.ts +21 -0
  68. package/dist/src/tools/get-eu-basis.d.ts.map +1 -0
  69. package/dist/src/tools/get-eu-basis.js +52 -0
  70. package/dist/src/tools/get-eu-basis.js.map +1 -0
  71. package/dist/src/tools/get-provision-eu-basis.d.ts +20 -0
  72. package/dist/src/tools/get-provision-eu-basis.d.ts.map +1 -0
  73. package/dist/src/tools/get-provision-eu-basis.js +45 -0
  74. package/dist/src/tools/get-provision-eu-basis.js.map +1 -0
  75. package/dist/src/tools/get-provision.d.ts +24 -0
  76. package/dist/src/tools/get-provision.d.ts.map +1 -0
  77. package/dist/src/tools/get-provision.js +80 -0
  78. package/dist/src/tools/get-provision.js.map +1 -0
  79. package/dist/src/tools/get-rwandan-implementations.d.ts +21 -0
  80. package/dist/src/tools/get-rwandan-implementations.d.ts.map +1 -0
  81. package/dist/src/tools/get-rwandan-implementations.js +42 -0
  82. package/dist/src/tools/get-rwandan-implementations.js.map +1 -0
  83. package/dist/src/tools/list-sources.d.ts +25 -0
  84. package/dist/src/tools/list-sources.d.ts.map +1 -0
  85. package/dist/src/tools/list-sources.js +41 -0
  86. package/dist/src/tools/list-sources.js.map +1 -0
  87. package/dist/src/tools/registry.d.ts +13 -0
  88. package/dist/src/tools/registry.d.ts.map +1 -0
  89. package/dist/src/tools/registry.js +365 -0
  90. package/dist/src/tools/registry.js.map +1 -0
  91. package/dist/src/tools/search-eu-implementations.d.ts +24 -0
  92. package/dist/src/tools/search-eu-implementations.d.ts.map +1 -0
  93. package/dist/src/tools/search-eu-implementations.js +58 -0
  94. package/dist/src/tools/search-eu-implementations.js.map +1 -0
  95. package/dist/src/tools/search-legislation.d.ts +24 -0
  96. package/dist/src/tools/search-legislation.d.ts.map +1 -0
  97. package/dist/src/tools/search-legislation.js +54 -0
  98. package/dist/src/tools/search-legislation.js.map +1 -0
  99. package/dist/src/tools/validate-citation.d.ts +20 -0
  100. package/dist/src/tools/validate-citation.d.ts.map +1 -0
  101. package/dist/src/tools/validate-citation.js +107 -0
  102. package/dist/src/tools/validate-citation.js.map +1 -0
  103. package/dist/src/tools/validate-eu-compliance.d.ts +20 -0
  104. package/dist/src/tools/validate-eu-compliance.d.ts.map +1 -0
  105. package/dist/src/tools/validate-eu-compliance.js +98 -0
  106. package/dist/src/tools/validate-eu-compliance.js.map +1 -0
  107. package/dist/src/utils/as-of-date.d.ts +9 -0
  108. package/dist/src/utils/as-of-date.d.ts.map +1 -0
  109. package/dist/src/utils/as-of-date.js +25 -0
  110. package/dist/src/utils/as-of-date.js.map +1 -0
  111. package/dist/src/utils/fts-query.d.ts +19 -0
  112. package/dist/src/utils/fts-query.d.ts.map +1 -0
  113. package/dist/src/utils/fts-query.js +47 -0
  114. package/dist/src/utils/fts-query.js.map +1 -0
  115. package/dist/src/utils/metadata.d.ts +16 -0
  116. package/dist/src/utils/metadata.d.ts.map +1 -0
  117. package/dist/src/utils/metadata.js +22 -0
  118. package/dist/src/utils/metadata.js.map +1 -0
  119. package/dist/src/utils/statute-id.d.ts +18 -0
  120. package/dist/src/utils/statute-id.d.ts.map +1 -0
  121. package/dist/src/utils/statute-id.js +34 -0
  122. package/dist/src/utils/statute-id.js.map +1 -0
  123. package/package.json +74 -0
  124. package/server.json +30 -0
@@ -0,0 +1,375 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Database builder for Rwandan Law MCP server.
4
+ *
5
+ * Builds the SQLite database from seed JSON files in data/seed/.
6
+ * Follows the Switzerland Law MCP reference pattern.
7
+ *
8
+ * Usage: npm run build:db
9
+ */
10
+ import Database from 'better-sqlite3';
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ const SEED_DIR = path.resolve(__dirname, '../data/seed');
17
+ const DB_PATH = path.resolve(__dirname, '../data/database.db');
18
+ // Database schema
19
+ const SCHEMA = `
20
+ -- Legal documents (statutes)
21
+ CREATE TABLE legal_documents (
22
+ id TEXT PRIMARY KEY,
23
+ type TEXT NOT NULL CHECK(type IN ('statute', 'bill', 'case_law')),
24
+ title TEXT NOT NULL,
25
+ title_en TEXT,
26
+ short_name TEXT,
27
+ status TEXT NOT NULL DEFAULT 'in_force'
28
+ CHECK(status IN ('in_force', 'amended', 'repealed', 'not_yet_in_force')),
29
+ issued_date TEXT,
30
+ in_force_date TEXT,
31
+ url TEXT,
32
+ description TEXT,
33
+ last_updated TEXT DEFAULT (datetime('now'))
34
+ );
35
+
36
+ -- Individual provisions from statutes
37
+ CREATE TABLE legal_provisions (
38
+ id INTEGER PRIMARY KEY,
39
+ document_id TEXT NOT NULL REFERENCES legal_documents(id),
40
+ provision_ref TEXT NOT NULL,
41
+ chapter TEXT,
42
+ section TEXT NOT NULL,
43
+ title TEXT,
44
+ content TEXT NOT NULL,
45
+ metadata TEXT,
46
+ UNIQUE(document_id, provision_ref)
47
+ );
48
+
49
+ CREATE INDEX idx_provisions_doc ON legal_provisions(document_id);
50
+ CREATE INDEX idx_provisions_chapter ON legal_provisions(document_id, chapter);
51
+
52
+ -- FTS5 for provision search
53
+ CREATE VIRTUAL TABLE provisions_fts USING fts5(
54
+ content, title,
55
+ content='legal_provisions',
56
+ content_rowid='id',
57
+ tokenize='unicode61'
58
+ );
59
+
60
+ CREATE TRIGGER provisions_ai AFTER INSERT ON legal_provisions BEGIN
61
+ INSERT INTO provisions_fts(rowid, content, title)
62
+ VALUES (new.id, new.content, new.title);
63
+ END;
64
+
65
+ CREATE TRIGGER provisions_ad AFTER DELETE ON legal_provisions BEGIN
66
+ INSERT INTO provisions_fts(provisions_fts, rowid, content, title)
67
+ VALUES ('delete', old.id, old.content, old.title);
68
+ END;
69
+
70
+ CREATE TRIGGER provisions_au AFTER UPDATE ON legal_provisions BEGIN
71
+ INSERT INTO provisions_fts(provisions_fts, rowid, content, title)
72
+ VALUES ('delete', old.id, old.content, old.title);
73
+ INSERT INTO provisions_fts(rowid, content, title)
74
+ VALUES (new.id, new.content, new.title);
75
+ END;
76
+
77
+ -- Cross-references between provisions/documents
78
+ CREATE TABLE cross_references (
79
+ id INTEGER PRIMARY KEY,
80
+ source_document_id TEXT NOT NULL REFERENCES legal_documents(id),
81
+ source_provision_ref TEXT,
82
+ target_document_id TEXT NOT NULL REFERENCES legal_documents(id),
83
+ target_provision_ref TEXT,
84
+ ref_type TEXT NOT NULL DEFAULT 'references'
85
+ CHECK(ref_type IN ('references', 'amended_by', 'implements', 'see_also'))
86
+ );
87
+
88
+ CREATE INDEX idx_xref_source ON cross_references(source_document_id);
89
+ CREATE INDEX idx_xref_target ON cross_references(target_document_id);
90
+
91
+ -- Legal term definitions
92
+ CREATE TABLE definitions (
93
+ id INTEGER PRIMARY KEY,
94
+ document_id TEXT NOT NULL REFERENCES legal_documents(id),
95
+ term TEXT NOT NULL,
96
+ term_en TEXT,
97
+ definition TEXT NOT NULL,
98
+ source_provision TEXT,
99
+ UNIQUE(document_id, term)
100
+ );
101
+
102
+ -- FTS5 for definition search
103
+ CREATE VIRTUAL TABLE definitions_fts USING fts5(
104
+ term, definition,
105
+ content='definitions',
106
+ content_rowid='id',
107
+ tokenize='unicode61'
108
+ );
109
+
110
+ CREATE TRIGGER definitions_ai AFTER INSERT ON definitions BEGIN
111
+ INSERT INTO definitions_fts(rowid, term, definition)
112
+ VALUES (new.id, new.term, new.definition);
113
+ END;
114
+
115
+ CREATE TRIGGER definitions_ad AFTER DELETE ON definitions BEGIN
116
+ INSERT INTO definitions_fts(definitions_fts, rowid, term, definition)
117
+ VALUES ('delete', old.id, old.term, old.definition);
118
+ END;
119
+
120
+ CREATE TRIGGER definitions_au AFTER UPDATE ON definitions BEGIN
121
+ INSERT INTO definitions_fts(definitions_fts, rowid, term, definition)
122
+ VALUES ('delete', old.id, old.term, old.definition);
123
+ INSERT INTO definitions_fts(rowid, term, definition)
124
+ VALUES (new.id, new.term, new.definition);
125
+ END;
126
+
127
+ -- EU Documents (directives and regulations)
128
+ CREATE TABLE eu_documents (
129
+ id TEXT PRIMARY KEY,
130
+ type TEXT NOT NULL CHECK (type IN ('directive', 'regulation')),
131
+ year INTEGER NOT NULL CHECK (year >= 1957 AND year <= 2100),
132
+ number INTEGER NOT NULL CHECK (number > 0),
133
+ community TEXT CHECK (community IN ('EU', 'EC', 'EEC', 'Euratom')),
134
+ celex_number TEXT,
135
+ title TEXT,
136
+ title_en TEXT,
137
+ short_name TEXT,
138
+ adoption_date TEXT,
139
+ entry_into_force_date TEXT,
140
+ in_force BOOLEAN DEFAULT 1,
141
+ amended_by TEXT,
142
+ repeals TEXT,
143
+ url_eur_lex TEXT,
144
+ description TEXT,
145
+ last_updated TEXT DEFAULT CURRENT_TIMESTAMP
146
+ );
147
+
148
+ CREATE INDEX idx_eu_documents_type_year ON eu_documents(type, year DESC);
149
+
150
+ -- EU References (links national provisions to EU documents)
151
+ CREATE TABLE eu_references (
152
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
153
+ source_type TEXT NOT NULL CHECK (source_type IN ('provision', 'document', 'case_law')),
154
+ source_id TEXT NOT NULL,
155
+ document_id TEXT NOT NULL REFERENCES legal_documents(id),
156
+ provision_id INTEGER REFERENCES legal_provisions(id),
157
+ eu_document_id TEXT NOT NULL REFERENCES eu_documents(id),
158
+ eu_article TEXT,
159
+ reference_type TEXT NOT NULL CHECK (reference_type IN (
160
+ 'implements', 'supplements', 'applies', 'references', 'complies_with',
161
+ 'derogates_from', 'amended_by', 'repealed_by', 'cites_article'
162
+ )),
163
+ reference_context TEXT,
164
+ full_citation TEXT,
165
+ is_primary_implementation BOOLEAN DEFAULT 0,
166
+ implementation_status TEXT CHECK (implementation_status IN ('complete', 'partial', 'pending', 'unknown')),
167
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
168
+ last_verified TEXT,
169
+ UNIQUE(source_id, eu_document_id, eu_article)
170
+ );
171
+
172
+ CREATE INDEX idx_eu_references_document ON eu_references(document_id, eu_document_id);
173
+ CREATE INDEX idx_eu_references_eu_document ON eu_references(eu_document_id, document_id);
174
+ CREATE INDEX idx_eu_references_provision ON eu_references(provision_id, eu_document_id);
175
+
176
+ -- Build metadata
177
+ CREATE TABLE db_metadata (
178
+ key TEXT PRIMARY KEY,
179
+ value TEXT NOT NULL
180
+ );
181
+ `;
182
+ function normalizeWhitespace(text) {
183
+ return text.replace(/\s+/g, ' ').trim();
184
+ }
185
+ function dedupeProvisions(provisions) {
186
+ const byRef = new Map();
187
+ for (const prov of provisions) {
188
+ const ref = prov.provision_ref.trim();
189
+ const existing = byRef.get(ref);
190
+ if (!existing || normalizeWhitespace(prov.content).length > normalizeWhitespace(existing.content).length) {
191
+ byRef.set(ref, { ...prov, provision_ref: ref });
192
+ }
193
+ }
194
+ return Array.from(byRef.values());
195
+ }
196
+ function extractEuReferences(text) {
197
+ if (!text || text.trim().length === 0)
198
+ return [];
199
+ const refs = [];
200
+ const seen = new Set();
201
+ const patterns = [
202
+ /\b(Regulation|Directive)\s*\((EU|EC|EEC|Euratom)\)\s*(?:No\.?\s*)?(\d{2,4})\/(\d{1,4})\b/gi,
203
+ /\b(Regulation|Directive)\s*(?:No\.?\s*)?(\d{2,4})\/(\d{1,4})\/(EU|EC|EEC|Euratom)\b/gi,
204
+ /\b(Regulation|Directive)\s*(?:No\.?\s*)?(\d{2,4})\/(\d{1,4})\b/gi,
205
+ ];
206
+ for (const pattern of patterns) {
207
+ let match;
208
+ while ((match = pattern.exec(text)) !== null) {
209
+ const type = match[1].toLowerCase();
210
+ let rawYear, rawNumber, communityRaw;
211
+ if (pattern === patterns[0]) {
212
+ communityRaw = match[2];
213
+ rawYear = match[3];
214
+ rawNumber = match[4];
215
+ }
216
+ else if (pattern === patterns[1]) {
217
+ rawYear = match[2];
218
+ rawNumber = match[3];
219
+ communityRaw = match[4];
220
+ }
221
+ else {
222
+ rawYear = match[2];
223
+ rawNumber = match[3];
224
+ communityRaw = undefined;
225
+ }
226
+ const parsedYear = Number.parseInt(rawYear, 10);
227
+ const year = rawYear.length === 2 ? (parsedYear >= 50 ? 1900 + parsedYear : 2000 + parsedYear) : parsedYear;
228
+ const number = Number.parseInt(rawNumber, 10);
229
+ if (year <= 0 || Number.isNaN(number) || number <= 0)
230
+ continue;
231
+ const community = (communityRaw?.toUpperCase() ?? 'EU');
232
+ const euDocumentId = `${type}:${year}/${number}`;
233
+ const start = Math.max(0, match.index - 120);
234
+ const end = Math.min(text.length, match.index + match[0].length + 120);
235
+ const referenceContext = text.slice(start, end).replace(/\s+/g, ' ').trim();
236
+ const euArticle = referenceContext.match(/\bArticle\s+(\d+[A-Za-z]?(?:\(\d+\))?)/i)?.[1] ?? null;
237
+ const referenceType = /\b(implement|align|transpos|equivalent)\b/i.test(referenceContext) ? 'implements' : 'references';
238
+ const dedupeKey = `${euDocumentId}:${euArticle ?? ''}`;
239
+ if (seen.has(dedupeKey))
240
+ continue;
241
+ seen.add(dedupeKey);
242
+ refs.push({
243
+ type, community, year, number, euDocumentId, euArticle,
244
+ fullCitation: match[0], referenceContext, referenceType,
245
+ });
246
+ }
247
+ }
248
+ return refs;
249
+ }
250
+ function buildDatabase() {
251
+ console.log('Building Rwandan Law MCP database...\n');
252
+ if (fs.existsSync(DB_PATH)) {
253
+ fs.unlinkSync(DB_PATH);
254
+ console.log(' Deleted existing database.\n');
255
+ }
256
+ const dataDir = path.dirname(DB_PATH);
257
+ if (!fs.existsSync(dataDir)) {
258
+ fs.mkdirSync(dataDir, { recursive: true });
259
+ }
260
+ const db = new Database(DB_PATH);
261
+ db.pragma('foreign_keys = ON');
262
+ db.pragma('journal_mode = WAL');
263
+ db.exec(SCHEMA);
264
+ const insertDoc = db.prepare(`
265
+ INSERT INTO legal_documents (id, type, title, title_en, short_name, status, issued_date, in_force_date, url, description)
266
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
267
+ `);
268
+ const insertProvision = db.prepare(`
269
+ INSERT INTO legal_provisions (document_id, provision_ref, chapter, section, title, content, metadata)
270
+ VALUES (?, ?, ?, ?, ?, ?, ?)
271
+ `);
272
+ const insertDefinition = db.prepare(`
273
+ INSERT OR IGNORE INTO definitions (document_id, term, term_en, definition, source_provision)
274
+ VALUES (?, ?, ?, ?, ?)
275
+ `);
276
+ const insertEuDocument = db.prepare(`
277
+ INSERT OR IGNORE INTO eu_documents (id, type, year, number, community, title, short_name, url_eur_lex, description)
278
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
279
+ `);
280
+ const insertEuReference = db.prepare(`
281
+ INSERT INTO eu_references
282
+ (source_type, source_id, document_id, provision_id, eu_document_id, eu_article,
283
+ reference_type, reference_context, full_citation, is_primary_implementation,
284
+ implementation_status, last_verified)
285
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
286
+ `);
287
+ if (!fs.existsSync(SEED_DIR)) {
288
+ console.log(`No seed directory at ${SEED_DIR} — creating empty database.`);
289
+ db.close();
290
+ return;
291
+ }
292
+ const seedFiles = fs.readdirSync(SEED_DIR)
293
+ .filter(f => f.endsWith('.json') && !f.startsWith('.') && !f.startsWith('_'));
294
+ if (seedFiles.length === 0) {
295
+ console.log('No seed files found. Database created with empty schema.');
296
+ db.close();
297
+ return;
298
+ }
299
+ let totalDocs = 0;
300
+ let totalProvisions = 0;
301
+ let totalDefs = 0;
302
+ let totalEuDocuments = 0;
303
+ let totalEuReferences = 0;
304
+ const primaryImplementationByDocument = new Set();
305
+ const loadAll = db.transaction(() => {
306
+ for (const file of seedFiles) {
307
+ const filePath = path.join(SEED_DIR, file);
308
+ const content = fs.readFileSync(filePath, 'utf-8');
309
+ const seed = JSON.parse(content);
310
+ insertDoc.run(seed.id, seed.type ?? 'statute', seed.title, seed.title_en ?? null, seed.short_name ?? null, seed.status ?? 'in_force', seed.issued_date ?? null, seed.in_force_date ?? null, seed.url ?? null, seed.description ?? null);
311
+ totalDocs++;
312
+ if (seed.provisions && seed.provisions.length > 0) {
313
+ const deduped = dedupeProvisions(seed.provisions);
314
+ for (const prov of deduped) {
315
+ const insertResult = insertProvision.run(seed.id, prov.provision_ref, prov.chapter ?? null, prov.section, prov.title ?? null, prov.content, prov.metadata ? JSON.stringify(prov.metadata) : null);
316
+ totalProvisions++;
317
+ const provisionId = Number(insertResult.lastInsertRowid);
318
+ const extractedRefs = extractEuReferences(prov.content);
319
+ if (extractedRefs.length > 0) {
320
+ const sourceId = `${seed.id}:${prov.provision_ref}`;
321
+ const lastVerified = new Date().toISOString();
322
+ for (const ref of extractedRefs) {
323
+ const eurLexType = ref.type === 'regulation' ? 'reg' : 'dir';
324
+ const eurLexUrl = `https://eur-lex.europa.eu/eli/${eurLexType}/${ref.year}/${ref.number}/oj`;
325
+ const shortName = `${ref.type === 'regulation' ? 'Regulation' : 'Directive'} ${ref.year}/${ref.number}`;
326
+ const euInsert = insertEuDocument.run(ref.euDocumentId, ref.type, ref.year, ref.number, ref.community, shortName, shortName, eurLexUrl, 'Auto-extracted from Rwandan statute text');
327
+ if (euInsert.changes > 0)
328
+ totalEuDocuments++;
329
+ const primaryKey = `${seed.id}:${ref.euDocumentId}`;
330
+ const isPrimary = ref.referenceType === 'implements' && !primaryImplementationByDocument.has(primaryKey) ? 1 : 0;
331
+ if (isPrimary === 1)
332
+ primaryImplementationByDocument.add(primaryKey);
333
+ try {
334
+ const refInsert = insertEuReference.run('provision', sourceId, seed.id, provisionId, ref.euDocumentId, ref.euArticle, ref.referenceType, ref.referenceContext, ref.fullCitation, isPrimary, isPrimary === 1 ? 'complete' : 'unknown', lastVerified);
335
+ if (refInsert.changes > 0)
336
+ totalEuReferences++;
337
+ }
338
+ catch {
339
+ // Ignore duplicate references
340
+ }
341
+ }
342
+ }
343
+ }
344
+ }
345
+ for (const def of seed.definitions ?? []) {
346
+ insertDefinition.run(seed.id, def.term, null, def.definition, def.source_provision ?? null);
347
+ totalDefs++;
348
+ }
349
+ }
350
+ });
351
+ loadAll();
352
+ // Write build metadata
353
+ const insertMeta = db.prepare('INSERT INTO db_metadata (key, value) VALUES (?, ?)');
354
+ const writeMeta = db.transaction(() => {
355
+ insertMeta.run('tier', 'free');
356
+ insertMeta.run('schema_version', '2');
357
+ insertMeta.run('built_at', new Date().toISOString());
358
+ insertMeta.run('builder', 'build-db.ts');
359
+ insertMeta.run('jurisdiction', 'RW');
360
+ insertMeta.run('source', 'rwandalii-law-catalog-akn-and-pdf');
361
+ insertMeta.run('licence', 'See sources.yml');
362
+ });
363
+ writeMeta();
364
+ // Set journal_mode to DELETE for WASM compatibility
365
+ db.pragma('journal_mode = DELETE');
366
+ db.exec('ANALYZE');
367
+ db.exec('VACUUM');
368
+ db.close();
369
+ const size = fs.statSync(DB_PATH).size;
370
+ console.log(`\nBuild complete: ${totalDocs} documents, ${totalProvisions} provisions, ` +
371
+ `${totalDefs} definitions, ${totalEuDocuments} EU documents, ${totalEuReferences} EU references`);
372
+ console.log(`Output: ${DB_PATH} (${(size / 1024 / 1024).toFixed(1)} MB)`);
373
+ }
374
+ buildDatabase();
375
+ //# sourceMappingURL=build-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-db.js","sourceRoot":"","sources":["../../scripts/build-db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Drift detection for Rwandan Law MCP.
4
+ *
5
+ * Checks if upstream www.riigiteataja.ee content has changed since last ingestion.
6
+ * Uses the golden-hashes.json fixture to verify content integrity.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=drift-detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift-detect.d.ts","sourceRoot":"","sources":["../../scripts/drift-detect.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Drift detection for Rwandan Law MCP.
4
+ *
5
+ * Checks if upstream www.riigiteataja.ee content has changed since last ingestion.
6
+ * Uses the golden-hashes.json fixture to verify content integrity.
7
+ */
8
+ import { readFileSync } from 'fs';
9
+ import { join, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const hashesPath = join(__dirname, '../fixtures/golden-hashes.json');
13
+ async function main() {
14
+ console.log('Rwandan Law MCP — Drift Detection');
15
+ console.log('=====================================\n');
16
+ const fixture = JSON.parse(readFileSync(hashesPath, 'utf-8'));
17
+ console.log(`Checking ${fixture.provisions.length} provisions...\n`);
18
+ let passed = 0;
19
+ let failed = 0;
20
+ let skipped = 0;
21
+ for (const hash of fixture.provisions) {
22
+ if (hash.expected_sha256 === 'COMPUTE_ON_FIRST_INGEST') {
23
+ console.log(` SKIP ${hash.id}: Not yet ingested`);
24
+ skipped++;
25
+ continue;
26
+ }
27
+ try {
28
+ const response = await fetch(hash.upstream_url, {
29
+ headers: { 'User-Agent': 'Rwandan-Law-MCP/1.0 drift-detect' },
30
+ });
31
+ if (response.status !== 200) {
32
+ console.log(` WARN ${hash.id}: HTTP ${response.status}`);
33
+ failed++;
34
+ continue;
35
+ }
36
+ const body = await response.text();
37
+ if (hash.expected_snippet && body.toLowerCase().includes(hash.expected_snippet.toLowerCase())) {
38
+ console.log(` OK ${hash.id}: Snippet found`);
39
+ passed++;
40
+ }
41
+ else {
42
+ console.log(` DRIFT ${hash.id}: Expected snippet "${hash.expected_snippet}" not found`);
43
+ failed++;
44
+ }
45
+ }
46
+ catch (error) {
47
+ const msg = error instanceof Error ? error.message : String(error);
48
+ console.log(` ERROR ${hash.id}: ${msg}`);
49
+ failed++;
50
+ }
51
+ }
52
+ console.log(`\nResults: ${passed} passed, ${failed} failed, ${skipped} skipped`);
53
+ if (failed > 0) {
54
+ console.log('\nDrift detected! Data may need re-ingestion.');
55
+ process.exit(1);
56
+ }
57
+ }
58
+ main().catch(error => {
59
+ console.error('Fatal error:', error);
60
+ process.exit(1);
61
+ });
62
+ //# sourceMappingURL=drift-detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift-detect.js","sourceRoot":"","sources":["../../scripts/drift-detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Rwanda Law MCP -- full-catalog ingestion.
4
+ *
5
+ * Sources:
6
+ * - RwandaLII law catalog API (`/search/api/documents/`)
7
+ * - RwandaLII law detail pages (AKN HTML or PDF-backed)
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../scripts/ingest.ts"],"names":[],"mappings":";AACA;;;;;;GAMG"}