harper-kb 0.2.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/LICENSE +21 -0
- package/README.md +288 -0
- package/config.yaml +13 -0
- package/dist/core/embeddings.d.ts +31 -0
- package/dist/core/embeddings.d.ts.map +1 -0
- package/dist/core/embeddings.js +199 -0
- package/dist/core/embeddings.js.map +1 -0
- package/dist/core/entries.d.ts +101 -0
- package/dist/core/entries.d.ts.map +1 -0
- package/dist/core/entries.js +304 -0
- package/dist/core/entries.js.map +1 -0
- package/dist/core/history.d.ts +31 -0
- package/dist/core/history.d.ts.map +1 -0
- package/dist/core/history.js +119 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/knowledge-base.d.ts +49 -0
- package/dist/core/knowledge-base.d.ts.map +1 -0
- package/dist/core/knowledge-base.js +117 -0
- package/dist/core/knowledge-base.js.map +1 -0
- package/dist/core/search.d.ts +34 -0
- package/dist/core/search.d.ts.map +1 -0
- package/dist/core/search.js +327 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/tags.d.ts +39 -0
- package/dist/core/tags.d.ts.map +1 -0
- package/dist/core/tags.js +97 -0
- package/dist/core/tags.js.map +1 -0
- package/dist/core/triage.d.ts +61 -0
- package/dist/core/triage.d.ts.map +1 -0
- package/dist/core/triage.js +136 -0
- package/dist/core/triage.js.map +1 -0
- package/dist/core/webhook-endpoints.d.ts +46 -0
- package/dist/core/webhook-endpoints.d.ts.map +1 -0
- package/dist/core/webhook-endpoints.js +85 -0
- package/dist/core/webhook-endpoints.js.map +1 -0
- package/dist/hooks.d.ts +67 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +53 -0
- package/dist/hooks.js.map +1 -0
- package/dist/http-utils.d.ts +38 -0
- package/dist/http-utils.d.ts.map +1 -0
- package/dist/http-utils.js +133 -0
- package/dist/http-utils.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/protocol.d.ts +25 -0
- package/dist/mcp/protocol.d.ts.map +1 -0
- package/dist/mcp/protocol.js +105 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/server.d.ts +28 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +144 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +26 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +706 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/oauth/authorize.d.ts +28 -0
- package/dist/oauth/authorize.d.ts.map +1 -0
- package/dist/oauth/authorize.js +421 -0
- package/dist/oauth/authorize.js.map +1 -0
- package/dist/oauth/init.d.ts +18 -0
- package/dist/oauth/init.d.ts.map +1 -0
- package/dist/oauth/init.js +30 -0
- package/dist/oauth/init.js.map +1 -0
- package/dist/oauth/keys.d.ts +34 -0
- package/dist/oauth/keys.d.ts.map +1 -0
- package/dist/oauth/keys.js +101 -0
- package/dist/oauth/keys.js.map +1 -0
- package/dist/oauth/metadata.d.ts +23 -0
- package/dist/oauth/metadata.d.ts.map +1 -0
- package/dist/oauth/metadata.js +57 -0
- package/dist/oauth/metadata.js.map +1 -0
- package/dist/oauth/middleware.d.ts +23 -0
- package/dist/oauth/middleware.d.ts.map +1 -0
- package/dist/oauth/middleware.js +65 -0
- package/dist/oauth/middleware.js.map +1 -0
- package/dist/oauth/register.d.ts +15 -0
- package/dist/oauth/register.d.ts.map +1 -0
- package/dist/oauth/register.js +78 -0
- package/dist/oauth/register.js.map +1 -0
- package/dist/oauth/token.d.ts +16 -0
- package/dist/oauth/token.d.ts.map +1 -0
- package/dist/oauth/token.js +184 -0
- package/dist/oauth/token.js.map +1 -0
- package/dist/oauth/validate.d.ts +40 -0
- package/dist/oauth/validate.d.ts.map +1 -0
- package/dist/oauth/validate.js +61 -0
- package/dist/oauth/validate.js.map +1 -0
- package/dist/resources/HistoryResource.d.ts +41 -0
- package/dist/resources/HistoryResource.d.ts.map +1 -0
- package/dist/resources/HistoryResource.js +61 -0
- package/dist/resources/HistoryResource.js.map +1 -0
- package/dist/resources/KnowledgeBaseResource.d.ts +60 -0
- package/dist/resources/KnowledgeBaseResource.d.ts.map +1 -0
- package/dist/resources/KnowledgeBaseResource.js +118 -0
- package/dist/resources/KnowledgeBaseResource.js.map +1 -0
- package/dist/resources/KnowledgeEntryResource.d.ts +61 -0
- package/dist/resources/KnowledgeEntryResource.d.ts.map +1 -0
- package/dist/resources/KnowledgeEntryResource.js +191 -0
- package/dist/resources/KnowledgeEntryResource.js.map +1 -0
- package/dist/resources/MeResource.d.ts +31 -0
- package/dist/resources/MeResource.d.ts.map +1 -0
- package/dist/resources/MeResource.js +40 -0
- package/dist/resources/MeResource.js.map +1 -0
- package/dist/resources/QueryLogResource.d.ts +22 -0
- package/dist/resources/QueryLogResource.d.ts.map +1 -0
- package/dist/resources/QueryLogResource.js +66 -0
- package/dist/resources/QueryLogResource.js.map +1 -0
- package/dist/resources/ServiceKeyResource.d.ts +52 -0
- package/dist/resources/ServiceKeyResource.d.ts.map +1 -0
- package/dist/resources/ServiceKeyResource.js +151 -0
- package/dist/resources/ServiceKeyResource.js.map +1 -0
- package/dist/resources/TagResource.d.ts +27 -0
- package/dist/resources/TagResource.d.ts.map +1 -0
- package/dist/resources/TagResource.js +41 -0
- package/dist/resources/TagResource.js.map +1 -0
- package/dist/resources/TriageResource.d.ts +53 -0
- package/dist/resources/TriageResource.d.ts.map +1 -0
- package/dist/resources/TriageResource.js +120 -0
- package/dist/resources/TriageResource.js.map +1 -0
- package/dist/resources/WebhookEndpointResource.d.ts +63 -0
- package/dist/resources/WebhookEndpointResource.d.ts.map +1 -0
- package/dist/resources/WebhookEndpointResource.js +115 -0
- package/dist/resources/WebhookEndpointResource.js.map +1 -0
- package/dist/types.d.ts +378 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/webhooks/github.d.ts +25 -0
- package/dist/webhooks/github.d.ts.map +1 -0
- package/dist/webhooks/github.js +165 -0
- package/dist/webhooks/github.js.map +1 -0
- package/dist/webhooks/middleware.d.ts +19 -0
- package/dist/webhooks/middleware.d.ts.map +1 -0
- package/dist/webhooks/middleware.js +144 -0
- package/dist/webhooks/middleware.js.map +1 -0
- package/dist/webhooks/types.d.ts +18 -0
- package/dist/webhooks/types.d.ts.map +1 -0
- package/dist/webhooks/types.js +5 -0
- package/dist/webhooks/types.js.map +1 -0
- package/package.json +69 -0
- package/schema/knowledge.graphql +136 -0
- package/schema/oauth.graphql +45 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Base Search
|
|
3
|
+
*
|
|
4
|
+
* Supports keyword, semantic (vector), and hybrid search modes.
|
|
5
|
+
* Applies applicability context filtering to boost/demote results.
|
|
6
|
+
* Logs all queries to the QueryLog table for analytics.
|
|
7
|
+
*
|
|
8
|
+
* All queries are scoped by kbId for multi-tenant isolation.
|
|
9
|
+
*/
|
|
10
|
+
import type { SearchParams, SearchResult, KnowledgeEntry, ApplicabilityContext } from '../types.ts';
|
|
11
|
+
/**
|
|
12
|
+
* Search the knowledge base.
|
|
13
|
+
*
|
|
14
|
+
* @param params - Search parameters including kbId, query, mode, tags, limit, context
|
|
15
|
+
* @returns Scored and sorted search results
|
|
16
|
+
*/
|
|
17
|
+
export declare function search(params: SearchParams): Promise<SearchResult[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Filter and re-score results based on applicability context.
|
|
20
|
+
*
|
|
21
|
+
* If the caller provides their environment context, results that match get a
|
|
22
|
+
* score boost, while results that specify a different scope get a score penalty
|
|
23
|
+
* (but are NOT hidden). Context dimensions are generic key-value pairs — each
|
|
24
|
+
* KB defines its own (e.g., product version, tier, region, platform).
|
|
25
|
+
*/
|
|
26
|
+
export declare function filterByApplicability(results: SearchResult[], context: ApplicabilityContext): SearchResult[];
|
|
27
|
+
/**
|
|
28
|
+
* List entries without search scoring.
|
|
29
|
+
*
|
|
30
|
+
* Returns entries sorted by updatedAt (newest first), with no relevance
|
|
31
|
+
* scoring. Used for browse mode where there's no search query.
|
|
32
|
+
*/
|
|
33
|
+
export declare function listEntries(kbId: string, tags?: string[], limit?: number): Promise<Omit<KnowledgeEntry, 'embedding'>[]>;
|
|
34
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/core/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA8CpG;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAiC1E;AAiJD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,oBAAoB,GAAG,YAAY,EAAE,CAsC5G;AAgED;;;;;GAKG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EAAE,EACf,KAAK,GAAE,MAAW,GAChB,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,EAAE,CAAC,CA2B9C"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Base Search
|
|
3
|
+
*
|
|
4
|
+
* Supports keyword, semantic (vector), and hybrid search modes.
|
|
5
|
+
* Applies applicability context filtering to boost/demote results.
|
|
6
|
+
* Logs all queries to the QueryLog table for analytics.
|
|
7
|
+
*
|
|
8
|
+
* All queries are scoped by kbId for multi-tenant isolation.
|
|
9
|
+
*/
|
|
10
|
+
import crypto from 'node:crypto';
|
|
11
|
+
import { generateEmbedding } from "./embeddings.js";
|
|
12
|
+
/** Default number of results to return */
|
|
13
|
+
const DEFAULT_LIMIT = 10;
|
|
14
|
+
/**
|
|
15
|
+
* Convert a Harper database record to a plain SearchResult object.
|
|
16
|
+
*
|
|
17
|
+
* Harper records use non-enumerable properties, so object spread
|
|
18
|
+
* ({...record}) produces an empty object. We must explicitly read
|
|
19
|
+
* each field.
|
|
20
|
+
*/
|
|
21
|
+
function toSearchResult(record, score, matchType) {
|
|
22
|
+
const entry = record;
|
|
23
|
+
return {
|
|
24
|
+
id: entry.id,
|
|
25
|
+
kbId: entry.kbId,
|
|
26
|
+
title: entry.title,
|
|
27
|
+
content: entry.content,
|
|
28
|
+
tags: entry.tags,
|
|
29
|
+
appliesTo: entry.appliesTo,
|
|
30
|
+
source: entry.source,
|
|
31
|
+
sourceUrl: entry.sourceUrl,
|
|
32
|
+
references: entry.references,
|
|
33
|
+
confidence: entry.confidence,
|
|
34
|
+
addedBy: entry.addedBy,
|
|
35
|
+
reviewedBy: entry.reviewedBy,
|
|
36
|
+
supersedesId: entry.supersedesId,
|
|
37
|
+
supersededById: entry.supersededById,
|
|
38
|
+
siblingIds: entry.siblingIds,
|
|
39
|
+
relatedIds: entry.relatedIds,
|
|
40
|
+
metadata: entry.metadata,
|
|
41
|
+
deprecated: entry.deprecated,
|
|
42
|
+
createdAt: entry.createdAt,
|
|
43
|
+
updatedAt: entry.updatedAt,
|
|
44
|
+
score,
|
|
45
|
+
matchType,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Score boost factor for applicability matches */
|
|
49
|
+
const APPLICABILITY_BOOST = 1.2;
|
|
50
|
+
/** Score penalty factor for applicability mismatches */
|
|
51
|
+
const APPLICABILITY_PENALTY = 0.8;
|
|
52
|
+
/**
|
|
53
|
+
* Search the knowledge base.
|
|
54
|
+
*
|
|
55
|
+
* @param params - Search parameters including kbId, query, mode, tags, limit, context
|
|
56
|
+
* @returns Scored and sorted search results
|
|
57
|
+
*/
|
|
58
|
+
export async function search(params) {
|
|
59
|
+
const { kbId, query, tags, limit = DEFAULT_LIMIT, context, mode = 'hybrid' } = params;
|
|
60
|
+
let results;
|
|
61
|
+
switch (mode) {
|
|
62
|
+
case 'keyword':
|
|
63
|
+
results = await keywordSearch(kbId, query, tags, limit);
|
|
64
|
+
break;
|
|
65
|
+
case 'semantic':
|
|
66
|
+
results = await semanticSearch(kbId, query, limit);
|
|
67
|
+
break;
|
|
68
|
+
case 'hybrid':
|
|
69
|
+
default:
|
|
70
|
+
results = await hybridSearch(kbId, query, tags, limit);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
// Apply applicability filtering (boost/demote based on context)
|
|
74
|
+
if (context) {
|
|
75
|
+
results = filterByApplicability(results, context);
|
|
76
|
+
}
|
|
77
|
+
// Re-sort by score after applicability adjustments
|
|
78
|
+
results.sort((a, b) => b.score - a.score);
|
|
79
|
+
// Trim to limit
|
|
80
|
+
results = results.slice(0, limit);
|
|
81
|
+
// Log the search query for analytics
|
|
82
|
+
await logQuery(kbId, query, context, results);
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Perform keyword-based search using Harper's condition-based search.
|
|
87
|
+
*/
|
|
88
|
+
async function keywordSearch(kbId, query, tags, limit = DEFAULT_LIMIT) {
|
|
89
|
+
// Run the title search
|
|
90
|
+
const titleResults = await collectResults(databases.kb.KnowledgeEntry.search({
|
|
91
|
+
conditions: [
|
|
92
|
+
{ attribute: 'kbId', comparator: 'equals', value: kbId },
|
|
93
|
+
{ attribute: 'title', comparator: 'contains', value: query },
|
|
94
|
+
{ attribute: 'deprecated', comparator: 'equals', value: false },
|
|
95
|
+
],
|
|
96
|
+
limit: limit * 2, // Fetch extra for merging
|
|
97
|
+
}));
|
|
98
|
+
// Also search by content
|
|
99
|
+
const contentResults = await collectResults(databases.kb.KnowledgeEntry.search({
|
|
100
|
+
conditions: [
|
|
101
|
+
{ attribute: 'kbId', comparator: 'equals', value: kbId },
|
|
102
|
+
{ attribute: 'content', comparator: 'contains', value: query },
|
|
103
|
+
{ attribute: 'deprecated', comparator: 'equals', value: false },
|
|
104
|
+
],
|
|
105
|
+
limit: limit * 2,
|
|
106
|
+
}));
|
|
107
|
+
// Merge and deduplicate
|
|
108
|
+
const seenIds = new Set();
|
|
109
|
+
const results = [];
|
|
110
|
+
// Title matches get higher score
|
|
111
|
+
for (const entry of titleResults) {
|
|
112
|
+
const typed = entry;
|
|
113
|
+
if (typed.id && !seenIds.has(typed.id)) {
|
|
114
|
+
seenIds.add(typed.id);
|
|
115
|
+
results.push(toSearchResult(entry, 1.0, 'keyword'));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Content matches get lower score
|
|
119
|
+
for (const entry of contentResults) {
|
|
120
|
+
const typed = entry;
|
|
121
|
+
if (typed.id && !seenIds.has(typed.id)) {
|
|
122
|
+
seenIds.add(typed.id);
|
|
123
|
+
results.push(toSearchResult(entry, 0.7, 'keyword'));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Filter by tags if needed (post-filter since conditions are ANDed)
|
|
127
|
+
if (tags && tags.length > 0) {
|
|
128
|
+
return results.filter((r) => {
|
|
129
|
+
const entryTags = r.tags || [];
|
|
130
|
+
return tags.some((tag) => entryTags.includes(tag));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return results;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Perform semantic (vector) search using HNSW index.
|
|
137
|
+
*/
|
|
138
|
+
async function semanticSearch(kbId, query, limit = DEFAULT_LIMIT) {
|
|
139
|
+
let queryVector;
|
|
140
|
+
try {
|
|
141
|
+
queryVector = await generateEmbedding(query);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
logger?.warn?.('Semantic search failed — embedding model not available:', error.message);
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
const rawResults = await collectResults(databases.kb.KnowledgeEntry.search({
|
|
148
|
+
conditions: [{ attribute: 'kbId', comparator: 'equals', value: kbId }],
|
|
149
|
+
sort: { attribute: 'embedding', target: queryVector },
|
|
150
|
+
limit: limit * 2, // Fetch extra to allow for deprecated filtering
|
|
151
|
+
}));
|
|
152
|
+
const results = [];
|
|
153
|
+
for (const entry of rawResults) {
|
|
154
|
+
const typed = entry;
|
|
155
|
+
if (typed.deprecated)
|
|
156
|
+
continue; // Skip deprecated entries
|
|
157
|
+
// Calculate cosine similarity score (HNSW returns nearest first)
|
|
158
|
+
// Score decreases with position (1.0 for first result, decreasing)
|
|
159
|
+
const positionScore = 1.0 - results.length / (limit * 2);
|
|
160
|
+
results.push(toSearchResult(entry, Math.max(0.1, positionScore), 'semantic'));
|
|
161
|
+
if (results.length >= limit)
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
return results;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Perform hybrid search: run both keyword and semantic, merge and deduplicate.
|
|
168
|
+
*/
|
|
169
|
+
async function hybridSearch(kbId, query, tags, limit = DEFAULT_LIMIT) {
|
|
170
|
+
// Run both searches in parallel
|
|
171
|
+
const [keywordResults, semanticResults] = await Promise.all([
|
|
172
|
+
keywordSearch(kbId, query, tags, limit),
|
|
173
|
+
semanticSearch(kbId, query, limit),
|
|
174
|
+
]);
|
|
175
|
+
// Merge and deduplicate
|
|
176
|
+
const resultMap = new Map();
|
|
177
|
+
// Add keyword results
|
|
178
|
+
for (const result of keywordResults) {
|
|
179
|
+
resultMap.set(result.id, result);
|
|
180
|
+
}
|
|
181
|
+
// Merge semantic results (combine scores if entry appears in both)
|
|
182
|
+
for (const result of semanticResults) {
|
|
183
|
+
const existing = resultMap.get(result.id);
|
|
184
|
+
if (existing) {
|
|
185
|
+
// Entry found in both — combine scores and mark as hybrid
|
|
186
|
+
existing.score = ((existing.score + result.score) / 2) * 1.3; // Boost for appearing in both
|
|
187
|
+
existing.matchType = 'hybrid';
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
resultMap.set(result.id, result);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const merged = Array.from(resultMap.values());
|
|
194
|
+
merged.sort((a, b) => b.score - a.score);
|
|
195
|
+
return merged.slice(0, limit);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Filter and re-score results based on applicability context.
|
|
199
|
+
*
|
|
200
|
+
* If the caller provides their environment context, results that match get a
|
|
201
|
+
* score boost, while results that specify a different scope get a score penalty
|
|
202
|
+
* (but are NOT hidden). Context dimensions are generic key-value pairs — each
|
|
203
|
+
* KB defines its own (e.g., product version, tier, region, platform).
|
|
204
|
+
*/
|
|
205
|
+
export function filterByApplicability(results, context) {
|
|
206
|
+
return results.map((result) => {
|
|
207
|
+
const appliesTo = result.appliesTo;
|
|
208
|
+
if (!appliesTo) {
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
let matchCount = 0;
|
|
212
|
+
let mismatchCount = 0;
|
|
213
|
+
let totalFields = 0;
|
|
214
|
+
for (const key of Object.keys(appliesTo)) {
|
|
215
|
+
if (context[key] === undefined)
|
|
216
|
+
continue;
|
|
217
|
+
totalFields++;
|
|
218
|
+
const matches = isVersionRange(appliesTo[key])
|
|
219
|
+
? versionMatches(context[key], appliesTo[key])
|
|
220
|
+
: context[key] === appliesTo[key];
|
|
221
|
+
if (matches) {
|
|
222
|
+
matchCount++;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
mismatchCount++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (totalFields === 0) {
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
let adjustedScore = result.score;
|
|
232
|
+
if (matchCount > 0) {
|
|
233
|
+
adjustedScore *= APPLICABILITY_BOOST;
|
|
234
|
+
}
|
|
235
|
+
if (mismatchCount > 0) {
|
|
236
|
+
adjustedScore *= APPLICABILITY_PENALTY;
|
|
237
|
+
}
|
|
238
|
+
return { ...result, score: adjustedScore };
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Detect whether a value looks like a semver range (starts with a range prefix).
|
|
243
|
+
*/
|
|
244
|
+
function isVersionRange(value) {
|
|
245
|
+
return /^[>=<~^]/.test(value);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Simple version matching.
|
|
249
|
+
* Supports exact match and basic semver range prefixes (>=, <=, ~, ^).
|
|
250
|
+
* For production use, consider a proper semver library.
|
|
251
|
+
*/
|
|
252
|
+
function versionMatches(actual, required) {
|
|
253
|
+
// Strip common prefixes for comparison
|
|
254
|
+
const cleanActual = actual.replace(/^[v=]/, '');
|
|
255
|
+
const cleanRequired = required.replace(/^[v=]/, '');
|
|
256
|
+
// Exact match
|
|
257
|
+
if (cleanActual === cleanRequired)
|
|
258
|
+
return true;
|
|
259
|
+
// Range prefix checks (simplified)
|
|
260
|
+
if (required.startsWith('>=')) {
|
|
261
|
+
return cleanActual >= required.slice(2);
|
|
262
|
+
}
|
|
263
|
+
if (required.startsWith('<=')) {
|
|
264
|
+
return cleanActual <= required.slice(2);
|
|
265
|
+
}
|
|
266
|
+
// For ~ and ^ ranges, just check major.minor match
|
|
267
|
+
if (required.startsWith('~') || required.startsWith('^')) {
|
|
268
|
+
const reqParts = required.slice(1).split('.');
|
|
269
|
+
const actParts = cleanActual.split('.');
|
|
270
|
+
return reqParts[0] === actParts[0] && (reqParts.length < 2 || reqParts[1] === actParts[1]);
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Log a search query to the QueryLog table for analytics.
|
|
276
|
+
*/
|
|
277
|
+
async function logQuery(kbId, query, context, results) {
|
|
278
|
+
try {
|
|
279
|
+
await databases.kb.QueryLog.put({
|
|
280
|
+
id: crypto.randomUUID(),
|
|
281
|
+
kbId,
|
|
282
|
+
query,
|
|
283
|
+
context: context || null,
|
|
284
|
+
resultCount: results.length,
|
|
285
|
+
topResultId: results.length > 0 ? results[0].id : null,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
// Don't fail the search if logging fails
|
|
290
|
+
logger?.warn?.('Failed to log search query:', error.message);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* List entries without search scoring.
|
|
295
|
+
*
|
|
296
|
+
* Returns entries sorted by updatedAt (newest first), with no relevance
|
|
297
|
+
* scoring. Used for browse mode where there's no search query.
|
|
298
|
+
*/
|
|
299
|
+
export async function listEntries(kbId, tags, limit = 30) {
|
|
300
|
+
const { stripEmbedding } = await import("./entries.js");
|
|
301
|
+
const conditions = [
|
|
302
|
+
{ attribute: 'kbId', comparator: 'equals', value: kbId },
|
|
303
|
+
{ attribute: 'deprecated', comparator: 'equals', value: false },
|
|
304
|
+
];
|
|
305
|
+
if (tags && tags.length > 0) {
|
|
306
|
+
for (const tag of tags) {
|
|
307
|
+
conditions.push({ attribute: 'tags', comparator: 'contains', value: tag });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const records = await collectResults(databases.kb.KnowledgeEntry.search({
|
|
311
|
+
conditions,
|
|
312
|
+
sort: { attribute: 'updatedAt', descending: true },
|
|
313
|
+
limit,
|
|
314
|
+
}));
|
|
315
|
+
return records.map((record) => stripEmbedding(record));
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Collect all results from an async iterable into an array.
|
|
319
|
+
*/
|
|
320
|
+
async function collectResults(iterable) {
|
|
321
|
+
const results = [];
|
|
322
|
+
for await (const item of iterable) {
|
|
323
|
+
results.push(item);
|
|
324
|
+
}
|
|
325
|
+
return results;
|
|
326
|
+
}
|
|
327
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/core/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag Management
|
|
3
|
+
*
|
|
4
|
+
* Manages knowledge base tags, including listing and synchronizing
|
|
5
|
+
* tag counts when entries are created, updated, or deleted.
|
|
6
|
+
*
|
|
7
|
+
* Tags are scoped per knowledge base. The tag ID is a composite key
|
|
8
|
+
* of `${kbId}:${tagName}` to allow the same tag name across different KBs.
|
|
9
|
+
*/
|
|
10
|
+
import type { KnowledgeTag } from '../types.ts';
|
|
11
|
+
/**
|
|
12
|
+
* List knowledge tags for a specific knowledge base.
|
|
13
|
+
*
|
|
14
|
+
* @param kbId - Knowledge base identifier
|
|
15
|
+
* @param limit - Maximum number of tags to return (default 500)
|
|
16
|
+
* @returns Tags from the KnowledgeTag table scoped to this KB
|
|
17
|
+
*/
|
|
18
|
+
export declare function listTags(kbId: string, limit?: number): Promise<KnowledgeTag[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Get a single tag by name within a knowledge base.
|
|
21
|
+
*
|
|
22
|
+
* @param kbId - Knowledge base identifier
|
|
23
|
+
* @param tagName - Tag name
|
|
24
|
+
* @returns The tag record, or null if not found
|
|
25
|
+
*/
|
|
26
|
+
export declare function getTag(kbId: string, tagName: string): Promise<KnowledgeTag | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Synchronize tag counts when entries are created, updated, or deleted.
|
|
29
|
+
*
|
|
30
|
+
* For tags added (in newTags but not in previousTags), increment entryCount
|
|
31
|
+
* or create the tag with count 1. For tags removed (in previousTags but not
|
|
32
|
+
* in newTags), decrement entryCount.
|
|
33
|
+
*
|
|
34
|
+
* @param kbId - Knowledge base identifier
|
|
35
|
+
* @param newTags - Tags on the entry after the change
|
|
36
|
+
* @param previousTags - Tags on the entry before the change (empty for new entries)
|
|
37
|
+
*/
|
|
38
|
+
export declare function syncTags(kbId: string, newTags: string[], previousTags?: string[]): Promise<void>;
|
|
39
|
+
//# sourceMappingURL=tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../src/core/tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CASjF;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAGxF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CtG"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag Management
|
|
3
|
+
*
|
|
4
|
+
* Manages knowledge base tags, including listing and synchronizing
|
|
5
|
+
* tag counts when entries are created, updated, or deleted.
|
|
6
|
+
*
|
|
7
|
+
* Tags are scoped per knowledge base. The tag ID is a composite key
|
|
8
|
+
* of `${kbId}:${tagName}` to allow the same tag name across different KBs.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Build a composite tag ID from kbId and tag name.
|
|
12
|
+
*/
|
|
13
|
+
function tagId(kbId, tagName) {
|
|
14
|
+
return `${kbId}:${tagName}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* List knowledge tags for a specific knowledge base.
|
|
18
|
+
*
|
|
19
|
+
* @param kbId - Knowledge base identifier
|
|
20
|
+
* @param limit - Maximum number of tags to return (default 500)
|
|
21
|
+
* @returns Tags from the KnowledgeTag table scoped to this KB
|
|
22
|
+
*/
|
|
23
|
+
export async function listTags(kbId, limit = 500) {
|
|
24
|
+
const results = [];
|
|
25
|
+
for await (const tag of databases.kb.KnowledgeTag.search({
|
|
26
|
+
conditions: [{ attribute: 'kbId', comparator: 'equals', value: kbId }],
|
|
27
|
+
limit,
|
|
28
|
+
})) {
|
|
29
|
+
results.push(tag);
|
|
30
|
+
}
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get a single tag by name within a knowledge base.
|
|
35
|
+
*
|
|
36
|
+
* @param kbId - Knowledge base identifier
|
|
37
|
+
* @param tagName - Tag name
|
|
38
|
+
* @returns The tag record, or null if not found
|
|
39
|
+
*/
|
|
40
|
+
export async function getTag(kbId, tagName) {
|
|
41
|
+
const tag = await databases.kb.KnowledgeTag.get(tagId(kbId, tagName));
|
|
42
|
+
return tag;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Synchronize tag counts when entries are created, updated, or deleted.
|
|
46
|
+
*
|
|
47
|
+
* For tags added (in newTags but not in previousTags), increment entryCount
|
|
48
|
+
* or create the tag with count 1. For tags removed (in previousTags but not
|
|
49
|
+
* in newTags), decrement entryCount.
|
|
50
|
+
*
|
|
51
|
+
* @param kbId - Knowledge base identifier
|
|
52
|
+
* @param newTags - Tags on the entry after the change
|
|
53
|
+
* @param previousTags - Tags on the entry before the change (empty for new entries)
|
|
54
|
+
*/
|
|
55
|
+
export async function syncTags(kbId, newTags, previousTags) {
|
|
56
|
+
const prev = new Set(previousTags || []);
|
|
57
|
+
const next = new Set(newTags);
|
|
58
|
+
// Tags that were added
|
|
59
|
+
const added = newTags.filter((tag) => !prev.has(tag));
|
|
60
|
+
// Tags that were removed
|
|
61
|
+
const removed = (previousTags || []).filter((tag) => !next.has(tag));
|
|
62
|
+
// Increment counts for added tags
|
|
63
|
+
for (const tagName of added) {
|
|
64
|
+
const id = tagId(kbId, tagName);
|
|
65
|
+
const existing = await databases.kb.KnowledgeTag.get(id);
|
|
66
|
+
if (existing) {
|
|
67
|
+
await databases.kb.KnowledgeTag.put({
|
|
68
|
+
...existing,
|
|
69
|
+
id,
|
|
70
|
+
kbId,
|
|
71
|
+
entryCount: (existing.entryCount || 0) + 1,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
await databases.kb.KnowledgeTag.put({
|
|
76
|
+
id,
|
|
77
|
+
kbId,
|
|
78
|
+
entryCount: 1,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Decrement counts for removed tags
|
|
83
|
+
for (const tagName of removed) {
|
|
84
|
+
const id = tagId(kbId, tagName);
|
|
85
|
+
const existing = await databases.kb.KnowledgeTag.get(id);
|
|
86
|
+
if (existing) {
|
|
87
|
+
const currentCount = existing.entryCount || 0;
|
|
88
|
+
await databases.kb.KnowledgeTag.put({
|
|
89
|
+
...existing,
|
|
90
|
+
id,
|
|
91
|
+
kbId,
|
|
92
|
+
entryCount: Math.max(0, currentCount - 1),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/core/tags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Triage Queue Management
|
|
3
|
+
*
|
|
4
|
+
* Handles the intake queue for new knowledge submissions from webhooks
|
|
5
|
+
* and other sources. Items go through pending -> processing -> accepted/dismissed.
|
|
6
|
+
*
|
|
7
|
+
* All operations are scoped by kbId for multi-tenant isolation.
|
|
8
|
+
*/
|
|
9
|
+
import type { TriageItem, TriageAction, TriageProcessOptions } from '../types.ts';
|
|
10
|
+
/**
|
|
11
|
+
* Submit a new item to the triage queue.
|
|
12
|
+
*
|
|
13
|
+
* @param kbId - Knowledge base identifier
|
|
14
|
+
* @param source - Source identifier (e.g., "github-webhook", "slack-bot", "manual")
|
|
15
|
+
* @param summary - Brief summary of the knowledge to triage
|
|
16
|
+
* @param rawPayload - Original raw payload from the source
|
|
17
|
+
* @param sourceId - Optional deduplication key from the source system
|
|
18
|
+
* @returns The created triage item
|
|
19
|
+
*/
|
|
20
|
+
export declare function submitTriage(kbId: string, source: string, summary: string, rawPayload?: unknown, sourceId?: string): Promise<TriageItem>;
|
|
21
|
+
/**
|
|
22
|
+
* Find a triage item by its source-specific ID for deduplication.
|
|
23
|
+
*
|
|
24
|
+
* @param kbId - Knowledge base identifier
|
|
25
|
+
* @param sourceId - The source-specific identifier
|
|
26
|
+
* @returns The matching triage item, or null if not found
|
|
27
|
+
*/
|
|
28
|
+
export declare function findBySourceId(kbId: string, sourceId: string): Promise<TriageItem | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Process a triage item with the given action.
|
|
31
|
+
*
|
|
32
|
+
* - "accepted": Optionally creates a new knowledge entry from provided data
|
|
33
|
+
* - "dismissed": Marks the item as dismissed
|
|
34
|
+
* - "linked": Links the triage item to an existing knowledge entry
|
|
35
|
+
*
|
|
36
|
+
* @param id - Triage item ID
|
|
37
|
+
* @param action - Action to take
|
|
38
|
+
* @param processedBy - Who processed this item
|
|
39
|
+
* @param options - Additional options (entry data for accept, linked entry ID)
|
|
40
|
+
* @returns The updated triage item
|
|
41
|
+
* @throws Error if the triage item does not exist
|
|
42
|
+
*/
|
|
43
|
+
export declare function processTriage(id: string, action: TriageAction, processedBy: string, options?: TriageProcessOptions): Promise<TriageItem>;
|
|
44
|
+
/**
|
|
45
|
+
* List pending triage items for a specific knowledge base.
|
|
46
|
+
*
|
|
47
|
+
* @param kbId - Knowledge base identifier
|
|
48
|
+
* @param limit - Maximum number of items to return (default 200)
|
|
49
|
+
* @returns Array of triage items with status "pending"
|
|
50
|
+
*/
|
|
51
|
+
export declare function listPending(kbId: string, limit?: number): Promise<TriageItem[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Dismiss a triage item.
|
|
54
|
+
*
|
|
55
|
+
* Convenience method that calls processTriage with action "dismissed".
|
|
56
|
+
*
|
|
57
|
+
* @param id - Triage item ID
|
|
58
|
+
* @param processedBy - Who dismissed this item
|
|
59
|
+
*/
|
|
60
|
+
export declare function dismissTriage(id: string, processedBy: string): Promise<void>;
|
|
61
|
+
//# sourceMappingURL=triage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/core/triage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,oBAAoB,EAAuB,MAAM,aAAa,CAAC;AAEvG;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,OAAO,EACpB,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CAgBrB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAW/F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CAClC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAYlF;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElF"}
|