knowledge-mcp-server 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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +205 -0
- package/dist/analytics.d.ts +24 -0
- package/dist/analytics.js +102 -0
- package/dist/analytics.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +98 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +39 -0
- package/dist/config.js +80 -0
- package/dist/config.js.map +1 -0
- package/dist/embeddings.d.ts +26 -0
- package/dist/embeddings.js +534 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/formatter.d.ts +51 -0
- package/dist/formatter.js +273 -0
- package/dist/formatter.js.map +1 -0
- package/dist/generate-embeddings.d.ts +8 -0
- package/dist/generate-embeddings.js +146 -0
- package/dist/generate-embeddings.js.map +1 -0
- package/dist/graph.d.ts +20 -0
- package/dist/graph.js +133 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +65 -0
- package/dist/init.js.map +1 -0
- package/dist/loader.d.ts +26 -0
- package/dist/loader.js +151 -0
- package/dist/loader.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/query-classifier.d.ts +23 -0
- package/dist/query-classifier.js +111 -0
- package/dist/query-classifier.js.map +1 -0
- package/dist/reranker.d.ts +7 -0
- package/dist/reranker.js +38 -0
- package/dist/reranker.js.map +1 -0
- package/dist/search.d.ts +17 -0
- package/dist/search.js +299 -0
- package/dist/search.js.map +1 -0
- package/dist/validator.d.ts +23 -0
- package/dist/validator.js +97 -0
- package/dist/validator.js.map +1 -0
- package/dist/writer.d.ts +36 -0
- package/dist/writer.js +360 -0
- package/dist/writer.js.map +1 -0
- package/package.json +58 -0
package/dist/search.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { getAncestors, getRelated } from "./graph.js";
|
|
2
|
+
import { classifyQuery, expandSynonyms } from "./query-classifier.js";
|
|
3
|
+
import { cosineSimilarity, embedQuery, bm25Score, tokenize } from "./embeddings.js";
|
|
4
|
+
import { formatSearchResults, } from "./formatter.js";
|
|
5
|
+
import { rerank } from "./reranker.js";
|
|
6
|
+
import { log } from "./logger.js";
|
|
7
|
+
// Stage 1: Query classification (rule-based)
|
|
8
|
+
function classifyAndMerge(options, classifierConfig) {
|
|
9
|
+
const classification = classifyQuery(options.query, classifierConfig);
|
|
10
|
+
// Merge explicit filters with classified ones
|
|
11
|
+
const domains = options.domains?.length ? options.domains : classification.domains;
|
|
12
|
+
const phases = options.phases?.length ? options.phases : classification.phases;
|
|
13
|
+
return { domains, phases, queryType: classification.queryType };
|
|
14
|
+
}
|
|
15
|
+
// Stage 2: Metadata pre-filter (uses phaseIndex for O(1) phase lookups)
|
|
16
|
+
function metadataFilter(graph, domains, phases, tags, type) {
|
|
17
|
+
let candidates = null;
|
|
18
|
+
// Domain filter
|
|
19
|
+
if (domains.length > 0) {
|
|
20
|
+
candidates = new Set();
|
|
21
|
+
for (const domain of domains) {
|
|
22
|
+
const domainDocs = graph.domainIndex.get(domain.toLowerCase());
|
|
23
|
+
if (domainDocs) {
|
|
24
|
+
for (const id of domainDocs)
|
|
25
|
+
candidates.add(id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Phase filter (using phaseIndex instead of iterating all documents)
|
|
30
|
+
if (phases.length > 0) {
|
|
31
|
+
const phaseFiltered = new Set();
|
|
32
|
+
for (const phase of phases) {
|
|
33
|
+
const phaseDocs = graph.phaseIndex.get(phase);
|
|
34
|
+
if (phaseDocs) {
|
|
35
|
+
for (const id of phaseDocs)
|
|
36
|
+
phaseFiltered.add(id);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (candidates) {
|
|
40
|
+
candidates = new Set([...candidates].filter((id) => phaseFiltered.has(id)));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
candidates = phaseFiltered;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Tag filter
|
|
47
|
+
if (tags && tags.length > 0) {
|
|
48
|
+
const tagFiltered = new Set();
|
|
49
|
+
for (const tag of tags) {
|
|
50
|
+
const tagDocs = graph.tagIndex.get(tag.toLowerCase());
|
|
51
|
+
if (tagDocs) {
|
|
52
|
+
for (const id of tagDocs)
|
|
53
|
+
tagFiltered.add(id);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (candidates) {
|
|
57
|
+
candidates = new Set([...candidates].filter((id) => tagFiltered.has(id)));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
candidates = tagFiltered;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Type filter
|
|
64
|
+
if (type) {
|
|
65
|
+
const typeDocs = graph.typeIndex.get(type);
|
|
66
|
+
const typeFiltered = typeDocs ? new Set(typeDocs) : new Set();
|
|
67
|
+
if (candidates) {
|
|
68
|
+
candidates = new Set([...candidates].filter((id) => typeFiltered.has(id)));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
candidates = typeFiltered;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// No filters → all documents
|
|
75
|
+
if (!candidates) {
|
|
76
|
+
candidates = new Set(graph.documents.keys());
|
|
77
|
+
}
|
|
78
|
+
return candidates;
|
|
79
|
+
}
|
|
80
|
+
// Determine which fields a query matched against
|
|
81
|
+
function detectMatchedOn(query, doc) {
|
|
82
|
+
const queryTokens = new Set(tokenize(query));
|
|
83
|
+
const parts = [];
|
|
84
|
+
const titleTokens = tokenize(doc.title);
|
|
85
|
+
if (titleTokens.some((t) => queryTokens.has(t)))
|
|
86
|
+
parts.push("title");
|
|
87
|
+
const tagTokens = doc.tags.flatMap((t) => tokenize(t));
|
|
88
|
+
if (tagTokens.some((t) => queryTokens.has(t)))
|
|
89
|
+
parts.push("tags");
|
|
90
|
+
const bodyTokens = tokenize(doc.contentBody.slice(0, 2000));
|
|
91
|
+
if (bodyTokens.some((t) => queryTokens.has(t)))
|
|
92
|
+
parts.push("body");
|
|
93
|
+
return parts.length > 0 ? parts.join("+") : "semantic";
|
|
94
|
+
}
|
|
95
|
+
// Reciprocal Rank Fusion constant
|
|
96
|
+
const RRF_K = 60;
|
|
97
|
+
// Stage 3: Hybrid scoring — vector + BM25 merged via RRF when embeddings available
|
|
98
|
+
async function scoreDocuments(graph, candidates, query, bm25Index, synonymMap) {
|
|
99
|
+
let queryVector = null;
|
|
100
|
+
// Expand synonyms for BM25 (vector embeddings handle semantic similarity natively)
|
|
101
|
+
const expandedQuery = expandSynonyms(query, synonymMap);
|
|
102
|
+
// Always compute BM25 scores (using synonym-expanded query)
|
|
103
|
+
const bm25Scored = [];
|
|
104
|
+
for (const id of candidates) {
|
|
105
|
+
const doc = graph.documents.get(id);
|
|
106
|
+
if (!doc)
|
|
107
|
+
continue;
|
|
108
|
+
const score = bm25Score(expandedQuery, id, bm25Index);
|
|
109
|
+
bm25Scored.push({ doc, score });
|
|
110
|
+
}
|
|
111
|
+
bm25Scored.sort((a, b) => b.score - a.score);
|
|
112
|
+
// Try vector similarity
|
|
113
|
+
if (graph.embeddings.available) {
|
|
114
|
+
queryVector = await embedQuery(query);
|
|
115
|
+
}
|
|
116
|
+
if (queryVector) {
|
|
117
|
+
// Hybrid: compute vector scores, merge with RRF
|
|
118
|
+
const vectorScored = [];
|
|
119
|
+
for (const id of candidates) {
|
|
120
|
+
const docVector = graph.embeddings.vectors.get(id);
|
|
121
|
+
const doc = graph.documents.get(id);
|
|
122
|
+
if (!doc)
|
|
123
|
+
continue;
|
|
124
|
+
const score = docVector ? cosineSimilarity(queryVector, docVector) : 0;
|
|
125
|
+
vectorScored.push({ doc, score });
|
|
126
|
+
}
|
|
127
|
+
vectorScored.sort((a, b) => b.score - a.score);
|
|
128
|
+
// Build rank maps
|
|
129
|
+
const vectorRank = new Map();
|
|
130
|
+
const bm25Rank = new Map();
|
|
131
|
+
for (let i = 0; i < vectorScored.length; i++) {
|
|
132
|
+
vectorRank.set(vectorScored[i].doc.id, i + 1);
|
|
133
|
+
}
|
|
134
|
+
for (let i = 0; i < bm25Scored.length; i++) {
|
|
135
|
+
bm25Rank.set(bm25Scored[i].doc.id, i + 1);
|
|
136
|
+
}
|
|
137
|
+
// Merge via RRF
|
|
138
|
+
const merged = [];
|
|
139
|
+
const allIds = new Set([...vectorRank.keys(), ...bm25Rank.keys()]);
|
|
140
|
+
for (const id of allIds) {
|
|
141
|
+
const doc = graph.documents.get(id);
|
|
142
|
+
if (!doc)
|
|
143
|
+
continue;
|
|
144
|
+
const vr = vectorRank.get(id) ?? vectorScored.length + 1;
|
|
145
|
+
const br = bm25Rank.get(id) ?? bm25Scored.length + 1;
|
|
146
|
+
const score = 1 / (RRF_K + vr) + 1 / (RRF_K + br);
|
|
147
|
+
merged.push({ doc, score });
|
|
148
|
+
}
|
|
149
|
+
merged.sort((a, b) => b.score - a.score);
|
|
150
|
+
return { scored: merged, queryVector, searchMethod: "vector+bm25" };
|
|
151
|
+
}
|
|
152
|
+
// BM25-only fallback
|
|
153
|
+
return { scored: bm25Scored, queryVector, searchMethod: "bm25_fallback" };
|
|
154
|
+
}
|
|
155
|
+
// Stage 4: Hierarchical expansion + graph walk
|
|
156
|
+
function expandResults(graph, topResults, maxTotal, bm25Index, queryVector, query, maxRelated, searchMethod) {
|
|
157
|
+
const seen = new Set();
|
|
158
|
+
const formattedDocs = [];
|
|
159
|
+
// 4a: Collect unique ancestors (never dropped)
|
|
160
|
+
const ancestorDocs = [];
|
|
161
|
+
for (const { doc } of topResults) {
|
|
162
|
+
const ancestors = getAncestors(graph, doc.id);
|
|
163
|
+
for (const a of ancestors) {
|
|
164
|
+
if (!seen.has(a.id)) {
|
|
165
|
+
seen.add(a.id);
|
|
166
|
+
ancestorDocs.push(a);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const a of ancestorDocs) {
|
|
171
|
+
formattedDocs.push({ doc: a, relevance: "ancestor" });
|
|
172
|
+
}
|
|
173
|
+
// Primary results (with annotations)
|
|
174
|
+
for (const { doc, score } of topResults) {
|
|
175
|
+
if (!seen.has(doc.id)) {
|
|
176
|
+
seen.add(doc.id);
|
|
177
|
+
formattedDocs.push({
|
|
178
|
+
doc,
|
|
179
|
+
relevance: "primary",
|
|
180
|
+
similarity: score,
|
|
181
|
+
matchedOn: detectMatchedOn(query, doc),
|
|
182
|
+
scoringMethod: searchMethod,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// 4b: Related-link expansion (skip if maxRelated is 0)
|
|
187
|
+
if (maxRelated <= 0)
|
|
188
|
+
return formattedDocs;
|
|
189
|
+
// Compute median primary score for BM25 threshold
|
|
190
|
+
const primaryScores = topResults.map((r) => r.score).sort((a, b) => a - b);
|
|
191
|
+
const medianPrimaryScore = primaryScores.length > 0 ? primaryScores[Math.floor(primaryScores.length / 2)] : 0;
|
|
192
|
+
const relatedCandidates = [];
|
|
193
|
+
const topForExpansion = topResults.slice(0, 4);
|
|
194
|
+
for (const { doc } of topForExpansion) {
|
|
195
|
+
const related = getRelated(graph, doc.id);
|
|
196
|
+
for (const r of related) {
|
|
197
|
+
if (!seen.has(r.id)) {
|
|
198
|
+
// Score the related doc — use embeddings if available, BM25 fallback
|
|
199
|
+
let score;
|
|
200
|
+
let useVector = false;
|
|
201
|
+
const docVector = queryVector ? graph.embeddings.vectors.get(r.id) : undefined;
|
|
202
|
+
if (queryVector && docVector) {
|
|
203
|
+
score = cosineSimilarity(queryVector, docVector);
|
|
204
|
+
useVector = true;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
score = bm25Score(query, r.id, bm25Index);
|
|
208
|
+
}
|
|
209
|
+
// Score threshold: filter out low-relevance related docs
|
|
210
|
+
const minScore = useVector ? 0.3 : 0.4 * medianPrimaryScore;
|
|
211
|
+
if (score >= minScore) {
|
|
212
|
+
relatedCandidates.push({ doc: r, score, sourceId: doc.id });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Sort related by score, take up to budget
|
|
218
|
+
relatedCandidates.sort((a, b) => b.score - a.score);
|
|
219
|
+
const budget = maxTotal - formattedDocs.length;
|
|
220
|
+
const relatedToAdd = relatedCandidates.slice(0, Math.min(maxRelated, budget));
|
|
221
|
+
for (const { doc, score, sourceId } of relatedToAdd) {
|
|
222
|
+
if (!seen.has(doc.id)) {
|
|
223
|
+
seen.add(doc.id);
|
|
224
|
+
formattedDocs.push({
|
|
225
|
+
doc,
|
|
226
|
+
relevance: "graph-expanded",
|
|
227
|
+
similarity: score > 0 ? score : undefined,
|
|
228
|
+
expandedFrom: sourceId,
|
|
229
|
+
scoringMethod: searchMethod,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return formattedDocs;
|
|
234
|
+
}
|
|
235
|
+
export async function knowledgeSearch(graph, bm25Index, options, classifierConfig) {
|
|
236
|
+
const maxResults = options.maxResults || 10;
|
|
237
|
+
const detailLevel = options.detailLevel || "normal";
|
|
238
|
+
const searchStart = Date.now();
|
|
239
|
+
// Stage 1: Classify query
|
|
240
|
+
const { domains, phases, queryType } = classifyAndMerge(options, classifierConfig);
|
|
241
|
+
// Stage 2: Metadata pre-filter
|
|
242
|
+
const candidates = metadataFilter(graph, domains, phases, options.tags, options.type);
|
|
243
|
+
// Stage 3: Score documents
|
|
244
|
+
const { scored: rawScored, queryVector, searchMethod, } = await scoreDocuments(graph, candidates, options.query, bm25Index, classifierConfig.synonymMap);
|
|
245
|
+
// Re-rank top candidates (title match, decision boost, staleness, exact phrase)
|
|
246
|
+
const reranked = rerank(rawScored.slice(0, 20), options.query, queryType);
|
|
247
|
+
const remaining = rawScored.slice(20);
|
|
248
|
+
// Filter drafts (unless explicitly included), penalize deprecated (0.5x score)
|
|
249
|
+
const scored = [...reranked, ...remaining]
|
|
250
|
+
.filter((s) => options.includeDrafts || s.doc.status !== "draft")
|
|
251
|
+
.map((s) => (s.doc.status === "deprecated" ? { ...s, score: s.score * 0.5 } : s));
|
|
252
|
+
scored.sort((a, b) => b.score - a.score);
|
|
253
|
+
// Adaptive top-N based on query type
|
|
254
|
+
let topN;
|
|
255
|
+
let maxRelated;
|
|
256
|
+
switch (queryType) {
|
|
257
|
+
case "broad":
|
|
258
|
+
topN = Math.min(4, scored.length);
|
|
259
|
+
maxRelated = 2;
|
|
260
|
+
break;
|
|
261
|
+
case "decision":
|
|
262
|
+
topN = Math.min(3, scored.length);
|
|
263
|
+
maxRelated = 0;
|
|
264
|
+
break;
|
|
265
|
+
case "specific":
|
|
266
|
+
default:
|
|
267
|
+
topN = Math.min(6, scored.length);
|
|
268
|
+
maxRelated = 3;
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
const topResults = scored.slice(0, topN);
|
|
272
|
+
// Stage 4: Expand with ancestors + related
|
|
273
|
+
const formatted = expandResults(graph, topResults, maxResults, bm25Index, queryVector, options.query, maxRelated, searchMethod);
|
|
274
|
+
// Compute facets from all scored candidates (not just top-N)
|
|
275
|
+
const facets = {
|
|
276
|
+
domains: new Map(),
|
|
277
|
+
types: new Map(),
|
|
278
|
+
phases: new Map(),
|
|
279
|
+
};
|
|
280
|
+
for (const { doc } of scored) {
|
|
281
|
+
facets.domains.set(doc.domain, (facets.domains.get(doc.domain) || 0) + 1);
|
|
282
|
+
facets.types.set(doc.type, (facets.types.get(doc.type) || 0) + 1);
|
|
283
|
+
for (const p of doc.phase) {
|
|
284
|
+
const key = `phase-${p}`;
|
|
285
|
+
facets.phases.set(key, (facets.phases.get(key) || 0) + 1);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
log.info("search", {
|
|
289
|
+
query: options.query,
|
|
290
|
+
queryType,
|
|
291
|
+
method: searchMethod,
|
|
292
|
+
candidates: candidates.size,
|
|
293
|
+
results: formatted.length,
|
|
294
|
+
ms: Date.now() - searchStart,
|
|
295
|
+
});
|
|
296
|
+
// Stage 5: Format for Claude
|
|
297
|
+
return formatSearchResults(options.query, formatted, detailLevel, searchMethod, facets);
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { KnowledgeGraph } from "./graph.js";
|
|
2
|
+
export interface ValidationReport {
|
|
3
|
+
orphans: string[];
|
|
4
|
+
brokenRelated: Array<{
|
|
5
|
+
doc: string;
|
|
6
|
+
ref: string;
|
|
7
|
+
}>;
|
|
8
|
+
brokenChildren: Array<{
|
|
9
|
+
doc: string;
|
|
10
|
+
ref: string;
|
|
11
|
+
}>;
|
|
12
|
+
circularParents: string[];
|
|
13
|
+
noTags: string[];
|
|
14
|
+
emptySummaries: string[];
|
|
15
|
+
staleDocs: string[];
|
|
16
|
+
embeddingCoverage: {
|
|
17
|
+
total: number;
|
|
18
|
+
covered: number;
|
|
19
|
+
percent: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function validateGraph(graph: KnowledgeGraph): ValidationReport;
|
|
23
|
+
export declare function formatValidationReport(report: ValidationReport): string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const SIX_MONTHS_MS = 180 * 24 * 60 * 60 * 1000;
|
|
2
|
+
export function validateGraph(graph) {
|
|
3
|
+
const now = Date.now();
|
|
4
|
+
const report = {
|
|
5
|
+
orphans: [],
|
|
6
|
+
brokenRelated: [],
|
|
7
|
+
brokenChildren: [],
|
|
8
|
+
circularParents: [],
|
|
9
|
+
noTags: [],
|
|
10
|
+
emptySummaries: [],
|
|
11
|
+
staleDocs: [],
|
|
12
|
+
embeddingCoverage: { total: 0, covered: 0, percent: 0 },
|
|
13
|
+
};
|
|
14
|
+
for (const doc of graph.documents.values()) {
|
|
15
|
+
// Orphan check: has a parentId that doesn't exist (and isn't a top-level domain doc)
|
|
16
|
+
if (doc.parentId && doc.parentId !== "root" && !graph.documents.has(doc.parentId)) {
|
|
17
|
+
report.orphans.push(doc.id);
|
|
18
|
+
}
|
|
19
|
+
// Broken related references
|
|
20
|
+
for (const ref of doc.related) {
|
|
21
|
+
if (!graph.documents.has(ref)) {
|
|
22
|
+
report.brokenRelated.push({ doc: doc.id, ref });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Broken children references
|
|
26
|
+
for (const ref of doc.childrenIds) {
|
|
27
|
+
if (!graph.documents.has(ref)) {
|
|
28
|
+
report.brokenChildren.push({ doc: doc.id, ref });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Circular parent chain detection
|
|
32
|
+
const visited = new Set();
|
|
33
|
+
let current = doc.id;
|
|
34
|
+
let circular = false;
|
|
35
|
+
while (current) {
|
|
36
|
+
if (visited.has(current)) {
|
|
37
|
+
circular = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
visited.add(current);
|
|
41
|
+
current = graph.documents.get(current)?.parentId ?? null;
|
|
42
|
+
}
|
|
43
|
+
if (circular) {
|
|
44
|
+
report.circularParents.push(doc.id);
|
|
45
|
+
}
|
|
46
|
+
// Docs with zero tags
|
|
47
|
+
if (doc.tags.length === 0) {
|
|
48
|
+
report.noTags.push(doc.id);
|
|
49
|
+
}
|
|
50
|
+
// Summary nodes without children
|
|
51
|
+
if (doc.type === "summary" && doc.childrenIds.length === 0) {
|
|
52
|
+
report.emptySummaries.push(doc.id);
|
|
53
|
+
}
|
|
54
|
+
// Stale docs (>6 months since last update)
|
|
55
|
+
if (doc.lastUpdated) {
|
|
56
|
+
const docDate = new Date(doc.lastUpdated).getTime();
|
|
57
|
+
if (!isNaN(docDate) && now - docDate > SIX_MONTHS_MS) {
|
|
58
|
+
report.staleDocs.push(doc.id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Embedding coverage
|
|
63
|
+
const total = graph.documents.size;
|
|
64
|
+
const covered = [...graph.documents.keys()].filter((id) => graph.embeddings.vectors.has(id)).length;
|
|
65
|
+
report.embeddingCoverage = {
|
|
66
|
+
total,
|
|
67
|
+
covered,
|
|
68
|
+
percent: total > 0 ? Math.round((covered / total) * 100) : 0,
|
|
69
|
+
};
|
|
70
|
+
return report;
|
|
71
|
+
}
|
|
72
|
+
export function formatValidationReport(report) {
|
|
73
|
+
const lines = ["Knowledge Graph Validation Report", "=".repeat(38), ""];
|
|
74
|
+
const addSection = (title, items) => {
|
|
75
|
+
lines.push(`${title}: ${items.length === 0 ? "none" : items.length}`);
|
|
76
|
+
for (const item of items) {
|
|
77
|
+
lines.push(` - ${item}`);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
addSection("Orphaned documents", report.orphans);
|
|
81
|
+
addSection("Broken related references", report.brokenRelated.map((r) => `${r.doc} → ${r.ref}`));
|
|
82
|
+
addSection("Broken children references", report.brokenChildren.map((r) => `${r.doc} → ${r.ref}`));
|
|
83
|
+
addSection("Circular parent chains", report.circularParents);
|
|
84
|
+
addSection("Documents with no tags", report.noTags);
|
|
85
|
+
addSection("Empty summary nodes (no children)", report.emptySummaries);
|
|
86
|
+
addSection("Stale documents (>6 months)", report.staleDocs);
|
|
87
|
+
lines.push("");
|
|
88
|
+
lines.push(`Embedding coverage: ${report.embeddingCoverage.covered}/${report.embeddingCoverage.total} (${report.embeddingCoverage.percent}%)`);
|
|
89
|
+
const issueCount = report.orphans.length +
|
|
90
|
+
report.brokenRelated.length +
|
|
91
|
+
report.brokenChildren.length +
|
|
92
|
+
report.circularParents.length;
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(issueCount === 0 ? "No integrity issues found." : `${issueCount} integrity issue(s) found.`);
|
|
95
|
+
return lines.join("\n");
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dist/writer.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type DocumentStatus } from "./loader.js";
|
|
2
|
+
import { type Bm25Index } from "./embeddings.js";
|
|
3
|
+
import type { KnowledgeGraph } from "./graph.js";
|
|
4
|
+
export type TfIdfIndex = Bm25Index;
|
|
5
|
+
export interface WriteParams {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
type: string;
|
|
9
|
+
domain: string;
|
|
10
|
+
subdomain?: string;
|
|
11
|
+
tags: string[];
|
|
12
|
+
phase: number[];
|
|
13
|
+
related?: string[];
|
|
14
|
+
children?: string[];
|
|
15
|
+
content: string;
|
|
16
|
+
status?: DocumentStatus;
|
|
17
|
+
superseded_by?: string;
|
|
18
|
+
decision_status?: "proposed" | "accepted" | "deprecated" | "superseded" | "finalized";
|
|
19
|
+
alternatives_considered?: string[];
|
|
20
|
+
decision_date?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface WriteResult {
|
|
23
|
+
id: string;
|
|
24
|
+
filePath: string;
|
|
25
|
+
parentId: string | null;
|
|
26
|
+
status: "created" | "updated";
|
|
27
|
+
tfidfIndex: Bm25Index;
|
|
28
|
+
warnings: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface DeleteResult {
|
|
31
|
+
id: string;
|
|
32
|
+
warnings: string[];
|
|
33
|
+
tfidfIndex: Bm25Index;
|
|
34
|
+
}
|
|
35
|
+
export declare function writeDocument(graph: KnowledgeGraph, tfidfIndex: Bm25Index, knowledgeDir: string, params: WriteParams, validDomains?: string[] | null, validPhaseIds?: number[] | null): WriteResult;
|
|
36
|
+
export declare function deleteDocument(graph: KnowledgeGraph, tfidfIndex: Bm25Index, knowledgeDir: string, id: string): DeleteResult;
|