@ai-devkit/memory 0.1.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/README.md +149 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +46 -0
- package/dist/api.js.map +1 -0
- package/dist/database/connection.d.ts +27 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +107 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +37 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/migrations/001_initial.sql +50 -0
- package/dist/database/schema.d.ts +6 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +89 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/handlers/search.d.ts +3 -0
- package/dist/handlers/search.d.ts.map +1 -0
- package/dist/handlers/search.js +78 -0
- package/dist/handlers/search.js.map +1 -0
- package/dist/handlers/store.d.ts +3 -0
- package/dist/handlers/store.d.ts.map +1 -0
- package/dist/handlers/store.js +71 -0
- package/dist/handlers/store.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +172 -0
- package/dist/server.js.map +1 -0
- package/dist/services/normalizer.d.ts +21 -0
- package/dist/services/normalizer.d.ts.map +1 -0
- package/dist/services/normalizer.js +52 -0
- package/dist/services/normalizer.js.map +1 -0
- package/dist/services/ranker.d.ts +21 -0
- package/dist/services/ranker.d.ts.map +1 -0
- package/dist/services/ranker.js +70 -0
- package/dist/services/ranker.js.map +1 -0
- package/dist/services/search.d.ts +29 -0
- package/dist/services/search.d.ts.map +1 -0
- package/dist/services/search.js +92 -0
- package/dist/services/search.js.map +1 -0
- package/dist/services/validator.d.ts +11 -0
- package/dist/services/validator.d.ts.map +1 -0
- package/dist/services/validator.js +144 -0
- package/dist/services/validator.js.map +1 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/errors.d.ts +21 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +76 -0
- package/dist/utils/errors.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "rankResults", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return rankResults;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Calculate tag boost based on matching contextTags
|
|
13
|
+
* +10% per matching tag
|
|
14
|
+
*/ function calculateTagBoost(itemTags, contextTags) {
|
|
15
|
+
if (!contextTags || contextTags.length === 0) {
|
|
16
|
+
return 1.0;
|
|
17
|
+
}
|
|
18
|
+
const itemTagsLower = itemTags.map((t)=>t.toLowerCase());
|
|
19
|
+
const contextTagsLower = contextTags.map((t)=>t.toLowerCase());
|
|
20
|
+
let matchCount = 0;
|
|
21
|
+
for (const tag of contextTagsLower){
|
|
22
|
+
if (itemTagsLower.includes(tag)) {
|
|
23
|
+
matchCount++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return 1 + matchCount * 0.1;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Calculate scope boost
|
|
30
|
+
* +0.5 if scope matches query scope
|
|
31
|
+
* +0.2 if global
|
|
32
|
+
* 0 otherwise
|
|
33
|
+
*/ function calculateScopeBoost(itemScope, queryScope) {
|
|
34
|
+
if (queryScope && itemScope === queryScope) {
|
|
35
|
+
return 0.5;
|
|
36
|
+
}
|
|
37
|
+
if (itemScope === 'global') {
|
|
38
|
+
return 0.2;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
function rankResults(results, context) {
|
|
43
|
+
const ranked = results.map((result)=>{
|
|
44
|
+
let tags;
|
|
45
|
+
try {
|
|
46
|
+
tags = JSON.parse(result.tags);
|
|
47
|
+
} catch {
|
|
48
|
+
tags = [];
|
|
49
|
+
}
|
|
50
|
+
const tagBoost = calculateTagBoost(tags, context.contextTags ?? []);
|
|
51
|
+
const scopeBoost = calculateScopeBoost(result.scope, context.queryScope);
|
|
52
|
+
// BM25 returns negative values (closer to 0 = better match)
|
|
53
|
+
// We negate it to make higher values better
|
|
54
|
+
const normalizedBm25 = -result.bm25_score;
|
|
55
|
+
const finalScore = normalizedBm25 * tagBoost + scopeBoost;
|
|
56
|
+
return {
|
|
57
|
+
id: result.id,
|
|
58
|
+
title: result.title,
|
|
59
|
+
content: result.content,
|
|
60
|
+
tags,
|
|
61
|
+
scope: result.scope,
|
|
62
|
+
score: Math.round(finalScore * 1000) / 1000
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
// Sort by score descending
|
|
66
|
+
ranked.sort((a, b)=>b.score - a.score);
|
|
67
|
+
return ranked;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=ranker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/ranker.ts"],"sourcesContent":["import type { SearchResultItem } from '../types';\n\ninterface RawSearchResult {\n id: string;\n title: string;\n content: string;\n tags: string;\n scope: string;\n bm25_score: number;\n}\n\ninterface RankingContext {\n contextTags?: string[];\n queryScope?: string | null;\n}\n\n/**\n * Calculate tag boost based on matching contextTags\n * +10% per matching tag\n */\nfunction calculateTagBoost(itemTags: string[], contextTags: string[]): number {\n if (!contextTags || contextTags.length === 0) {\n return 1.0;\n }\n\n const itemTagsLower = itemTags.map(t => t.toLowerCase());\n const contextTagsLower = contextTags.map(t => t.toLowerCase());\n\n let matchCount = 0;\n for (const tag of contextTagsLower) {\n if (itemTagsLower.includes(tag)) {\n matchCount++;\n }\n }\n\n return 1 + (matchCount * 0.1);\n}\n\n/**\n * Calculate scope boost\n * +0.5 if scope matches query scope\n * +0.2 if global\n * 0 otherwise\n */\nfunction calculateScopeBoost(itemScope: string, queryScope?: string | null): number {\n if (queryScope && itemScope === queryScope) {\n return 0.5;\n }\n if (itemScope === 'global') {\n return 0.2;\n }\n return 0;\n}\n\n/**\n * Apply ranking formula to search results\n * \n * Formula: final_score = bm25_score × tag_boost + scope_boost\n */\nexport function rankResults(\n results: RawSearchResult[],\n context: RankingContext\n): SearchResultItem[] {\n const ranked = results.map(result => {\n let tags: string[];\n try {\n tags = JSON.parse(result.tags) as string[];\n } catch {\n tags = [];\n }\n\n const tagBoost = calculateTagBoost(tags, context.contextTags ?? []);\n const scopeBoost = calculateScopeBoost(result.scope, context.queryScope);\n\n // BM25 returns negative values (closer to 0 = better match)\n // We negate it to make higher values better\n const normalizedBm25 = -result.bm25_score;\n\n const finalScore = (normalizedBm25 * tagBoost) + scopeBoost;\n\n return {\n id: result.id,\n title: result.title,\n content: result.content,\n tags,\n scope: result.scope,\n score: Math.round(finalScore * 1000) / 1000,\n };\n });\n\n // Sort by score descending\n ranked.sort((a, b) => b.score - a.score);\n\n return ranked;\n}\n"],"names":["rankResults","calculateTagBoost","itemTags","contextTags","length","itemTagsLower","map","t","toLowerCase","contextTagsLower","matchCount","tag","includes","calculateScopeBoost","itemScope","queryScope","results","context","ranked","result","tags","JSON","parse","tagBoost","scopeBoost","scope","normalizedBm25","bm25_score","finalScore","id","title","content","score","Math","round","sort","a","b"],"mappings":";;;;+BA2DgBA;;;eAAAA;;;AA3ChB;;;CAGC,GACD,SAASC,kBAAkBC,QAAkB,EAAEC,WAAqB;IAChE,IAAI,CAACA,eAAeA,YAAYC,MAAM,KAAK,GAAG;QAC1C,OAAO;IACX;IAEA,MAAMC,gBAAgBH,SAASI,GAAG,CAACC,CAAAA,IAAKA,EAAEC,WAAW;IACrD,MAAMC,mBAAmBN,YAAYG,GAAG,CAACC,CAAAA,IAAKA,EAAEC,WAAW;IAE3D,IAAIE,aAAa;IACjB,KAAK,MAAMC,OAAOF,iBAAkB;QAChC,IAAIJ,cAAcO,QAAQ,CAACD,MAAM;YAC7BD;QACJ;IACJ;IAEA,OAAO,IAAKA,aAAa;AAC7B;AAEA;;;;;CAKC,GACD,SAASG,oBAAoBC,SAAiB,EAAEC,UAA0B;IACtE,IAAIA,cAAcD,cAAcC,YAAY;QACxC,OAAO;IACX;IACA,IAAID,cAAc,UAAU;QACxB,OAAO;IACX;IACA,OAAO;AACX;AAOO,SAASd,YACZgB,OAA0B,EAC1BC,OAAuB;IAEvB,MAAMC,SAASF,QAAQV,GAAG,CAACa,CAAAA;QACvB,IAAIC;QACJ,IAAI;YACAA,OAAOC,KAAKC,KAAK,CAACH,OAAOC,IAAI;QACjC,EAAE,OAAM;YACJA,OAAO,EAAE;QACb;QAEA,MAAMG,WAAWtB,kBAAkBmB,MAAMH,QAAQd,WAAW,IAAI,EAAE;QAClE,MAAMqB,aAAaX,oBAAoBM,OAAOM,KAAK,EAAER,QAAQF,UAAU;QAEvE,4DAA4D;QAC5D,4CAA4C;QAC5C,MAAMW,iBAAiB,CAACP,OAAOQ,UAAU;QAEzC,MAAMC,aAAa,AAACF,iBAAiBH,WAAYC;QAEjD,OAAO;YACHK,IAAIV,OAAOU,EAAE;YACbC,OAAOX,OAAOW,KAAK;YACnBC,SAASZ,OAAOY,OAAO;YACvBX;YACAK,OAAON,OAAOM,KAAK;YACnBO,OAAOC,KAAKC,KAAK,CAACN,aAAa,QAAQ;QAC3C;IACJ;IAEA,2BAA2B;IAC3BV,OAAOiB,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEL,KAAK,GAAGI,EAAEJ,KAAK;IAEvC,OAAOd;AACX"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FTS5 Query Builder
|
|
3
|
+
* Converts natural language queries to FTS5 match expressions
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Build FTS5 query from natural language input
|
|
7
|
+
*
|
|
8
|
+
* Strategy:
|
|
9
|
+
* - Split query into words
|
|
10
|
+
* - Use prefix matching (*) for partial matches
|
|
11
|
+
* - Escape special characters
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildFtsQuery(query: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Build FTS5 query with column boosting
|
|
16
|
+
* Uses bm25() with weights: title=10, content=5, tags=1
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildSearchQuery(ftsQuery: string, scope?: string | null, limit?: number): {
|
|
19
|
+
sql: string;
|
|
20
|
+
params: unknown[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Build simple search query without FTS (fallback for empty queries)
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildSimpleQuery(scope?: string | null, limit?: number): {
|
|
26
|
+
sql: string;
|
|
27
|
+
params: unknown[];
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/services/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,SAAI,GACV;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CA4BpC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,SAAI,GACV;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAmBpC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get buildFtsQuery () {
|
|
13
|
+
return buildFtsQuery;
|
|
14
|
+
},
|
|
15
|
+
get buildSearchQuery () {
|
|
16
|
+
return buildSearchQuery;
|
|
17
|
+
},
|
|
18
|
+
get buildSimpleQuery () {
|
|
19
|
+
return buildSimpleQuery;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* FTS5 Query Builder
|
|
24
|
+
* Converts natural language queries to FTS5 match expressions
|
|
25
|
+
*/ /**
|
|
26
|
+
* Escape special FTS5 characters to prevent query syntax errors
|
|
27
|
+
*/ function escapeFtsSpecialChars(text) {
|
|
28
|
+
// FTS5 special characters: " * ^ - : OR AND NOT ( )
|
|
29
|
+
return text.replace(/"/g, '""') // Escape quotes by doubling
|
|
30
|
+
.replace(/[*^():\-]/g, ' ') // Replace operators with space (including hyphen)
|
|
31
|
+
.replace(/\b(AND|OR|NOT)\b/gi, '') // Remove boolean operators
|
|
32
|
+
.trim().replace(/\s+/g, ' '); // Collapse multiple spaces
|
|
33
|
+
}
|
|
34
|
+
function buildFtsQuery(query) {
|
|
35
|
+
const escaped = escapeFtsSpecialChars(query);
|
|
36
|
+
const words = escaped.split(/\s+/).filter((w)=>w.length > 0);
|
|
37
|
+
if (words.length === 0) {
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
// Use prefix matching for each word
|
|
41
|
+
// This allows "api design" to match "API", "designing", etc.
|
|
42
|
+
return words.map((word)=>`${word}*`).join(' ');
|
|
43
|
+
}
|
|
44
|
+
function buildSearchQuery(ftsQuery, scope, limit = 5) {
|
|
45
|
+
const params = [];
|
|
46
|
+
let sql = `
|
|
47
|
+
SELECT
|
|
48
|
+
k.id,
|
|
49
|
+
k.title,
|
|
50
|
+
k.content,
|
|
51
|
+
k.tags,
|
|
52
|
+
k.scope,
|
|
53
|
+
k.created_at,
|
|
54
|
+
k.updated_at,
|
|
55
|
+
bm25(knowledge_fts, 10.0, 5.0, 1.0) as bm25_score
|
|
56
|
+
FROM knowledge k
|
|
57
|
+
JOIN knowledge_fts fts ON k.rowid = fts.rowid
|
|
58
|
+
WHERE knowledge_fts MATCH ?
|
|
59
|
+
`;
|
|
60
|
+
params.push(ftsQuery);
|
|
61
|
+
if (scope) {
|
|
62
|
+
sql += ` AND (k.scope = ? OR k.scope = 'global')`;
|
|
63
|
+
params.push(scope);
|
|
64
|
+
}
|
|
65
|
+
sql += ` ORDER BY bm25_score LIMIT ?`;
|
|
66
|
+
params.push(limit);
|
|
67
|
+
return {
|
|
68
|
+
sql,
|
|
69
|
+
params
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function buildSimpleQuery(scope, limit = 5) {
|
|
73
|
+
const params = [];
|
|
74
|
+
let sql = `
|
|
75
|
+
SELECT
|
|
76
|
+
id, title, content, tags, scope, created_at, updated_at,
|
|
77
|
+
0 as bm25_score
|
|
78
|
+
FROM knowledge
|
|
79
|
+
`;
|
|
80
|
+
if (scope) {
|
|
81
|
+
sql += ` WHERE scope = ? OR scope = 'global'`;
|
|
82
|
+
params.push(scope);
|
|
83
|
+
}
|
|
84
|
+
sql += ` ORDER BY created_at DESC LIMIT ?`;
|
|
85
|
+
params.push(limit);
|
|
86
|
+
return {
|
|
87
|
+
sql,
|
|
88
|
+
params
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/search.ts"],"sourcesContent":["/**\n * FTS5 Query Builder\n * Converts natural language queries to FTS5 match expressions\n */\n\n/**\n * Escape special FTS5 characters to prevent query syntax errors\n */\nfunction escapeFtsSpecialChars(text: string): string {\n // FTS5 special characters: \" * ^ - : OR AND NOT ( )\n return text\n .replace(/\"/g, '\"\"') // Escape quotes by doubling\n .replace(/[*^():\\-]/g, ' ') // Replace operators with space (including hyphen)\n .replace(/\\b(AND|OR|NOT)\\b/gi, '') // Remove boolean operators\n .trim()\n .replace(/\\s+/g, ' '); // Collapse multiple spaces\n}\n\n/**\n * Build FTS5 query from natural language input\n * \n * Strategy:\n * - Split query into words\n * - Use prefix matching (*) for partial matches\n * - Escape special characters\n */\nexport function buildFtsQuery(query: string): string {\n const escaped = escapeFtsSpecialChars(query);\n const words = escaped.split(/\\s+/).filter(w => w.length > 0);\n\n if (words.length === 0) {\n return '';\n }\n\n // Use prefix matching for each word\n // This allows \"api design\" to match \"API\", \"designing\", etc.\n return words.map(word => `${word}*`).join(' ');\n}\n\n/**\n * Build FTS5 query with column boosting\n * Uses bm25() with weights: title=10, content=5, tags=1\n */\nexport function buildSearchQuery(\n ftsQuery: string,\n scope?: string | null,\n limit = 5\n): { sql: string; params: unknown[] } {\n const params: unknown[] = [];\n\n let sql = `\n SELECT \n k.id,\n k.title,\n k.content,\n k.tags,\n k.scope,\n k.created_at,\n k.updated_at,\n bm25(knowledge_fts, 10.0, 5.0, 1.0) as bm25_score\n FROM knowledge k\n JOIN knowledge_fts fts ON k.rowid = fts.rowid\n WHERE knowledge_fts MATCH ?\n `;\n params.push(ftsQuery);\n\n if (scope) {\n sql += ` AND (k.scope = ? OR k.scope = 'global')`;\n params.push(scope);\n }\n\n sql += ` ORDER BY bm25_score LIMIT ?`;\n params.push(limit);\n\n return { sql, params };\n}\n\n/**\n * Build simple search query without FTS (fallback for empty queries)\n */\nexport function buildSimpleQuery(\n scope?: string | null,\n limit = 5\n): { sql: string; params: unknown[] } {\n const params: unknown[] = [];\n\n let sql = `\n SELECT \n id, title, content, tags, scope, created_at, updated_at,\n 0 as bm25_score\n FROM knowledge\n `;\n\n if (scope) {\n sql += ` WHERE scope = ? OR scope = 'global'`;\n params.push(scope);\n }\n\n sql += ` ORDER BY created_at DESC LIMIT ?`;\n params.push(limit);\n\n return { sql, params };\n}\n"],"names":["buildFtsQuery","buildSearchQuery","buildSimpleQuery","escapeFtsSpecialChars","text","replace","trim","query","escaped","words","split","filter","w","length","map","word","join","ftsQuery","scope","limit","params","sql","push"],"mappings":";;;;;;;;;;;QA0BgBA;eAAAA;;QAiBAC;eAAAA;;QAqCAC;eAAAA;;;AAhFhB;;;CAGC,GAED;;CAEC,GACD,SAASC,sBAAsBC,IAAY;IACvC,oDAAoD;IACpD,OAAOA,KACFC,OAAO,CAAC,MAAM,MAAO,4BAA4B;KACjDA,OAAO,CAAC,cAAc,KAAM,kDAAkD;KAC9EA,OAAO,CAAC,sBAAsB,IAAK,2BAA2B;KAC9DC,IAAI,GACJD,OAAO,CAAC,QAAQ,MAAO,2BAA2B;AAC3D;AAUO,SAASL,cAAcO,KAAa;IACvC,MAAMC,UAAUL,sBAAsBI;IACtC,MAAME,QAAQD,QAAQE,KAAK,CAAC,OAAOC,MAAM,CAACC,CAAAA,IAAKA,EAAEC,MAAM,GAAG;IAE1D,IAAIJ,MAAMI,MAAM,KAAK,GAAG;QACpB,OAAO;IACX;IAEA,oCAAoC;IACpC,6DAA6D;IAC7D,OAAOJ,MAAMK,GAAG,CAACC,CAAAA,OAAQ,GAAGA,KAAK,CAAC,CAAC,EAAEC,IAAI,CAAC;AAC9C;AAMO,SAASf,iBACZgB,QAAgB,EAChBC,KAAqB,EACrBC,QAAQ,CAAC;IAET,MAAMC,SAAoB,EAAE;IAE5B,IAAIC,MAAM,CAAC;;;;;;;;;;;;;EAab,CAAC;IACCD,OAAOE,IAAI,CAACL;IAEZ,IAAIC,OAAO;QACPG,OAAO,CAAC,wCAAwC,CAAC;QACjDD,OAAOE,IAAI,CAACJ;IAChB;IAEAG,OAAO,CAAC,4BAA4B,CAAC;IACrCD,OAAOE,IAAI,CAACH;IAEZ,OAAO;QAAEE;QAAKD;IAAO;AACzB;AAKO,SAASlB,iBACZgB,KAAqB,EACrBC,QAAQ,CAAC;IAET,MAAMC,SAAoB,EAAE;IAE5B,IAAIC,MAAM,CAAC;;;;;EAKb,CAAC;IAEC,IAAIH,OAAO;QACPG,OAAO,CAAC,oCAAoC,CAAC;QAC7CD,OAAOE,IAAI,CAACJ;IAChB;IAEAG,OAAO,CAAC,iCAAiC,CAAC;IAC1CD,OAAOE,IAAI,CAACH;IAEZ,OAAO;QAAEE;QAAKD;IAAO;AACzB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StoreKnowledgeInput } from '../types';
|
|
2
|
+
export interface ValidationResult {
|
|
3
|
+
valid: boolean;
|
|
4
|
+
errors: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function validateTitle(title: string): ValidationResult;
|
|
7
|
+
export declare function validateContent(content: string): ValidationResult;
|
|
8
|
+
export declare function validateTags(tags?: string[]): ValidationResult;
|
|
9
|
+
export declare function validateScope(scope?: string): ValidationResult;
|
|
10
|
+
export declare function validateStoreInput(input: StoreKnowledgeInput): void;
|
|
11
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/services/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAsBpD,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAgB7D;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAyBjE;AAED,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAkB9D;AAED,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAY9D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAkBnE"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get validateContent () {
|
|
13
|
+
return validateContent;
|
|
14
|
+
},
|
|
15
|
+
get validateScope () {
|
|
16
|
+
return validateScope;
|
|
17
|
+
},
|
|
18
|
+
get validateStoreInput () {
|
|
19
|
+
return validateStoreInput;
|
|
20
|
+
},
|
|
21
|
+
get validateTags () {
|
|
22
|
+
return validateTags;
|
|
23
|
+
},
|
|
24
|
+
get validateTitle () {
|
|
25
|
+
return validateTitle;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const _errors = require("../utils/errors");
|
|
29
|
+
const TITLE_MIN_LENGTH = 10;
|
|
30
|
+
const TITLE_MAX_LENGTH = 100;
|
|
31
|
+
const CONTENT_MIN_LENGTH = 50;
|
|
32
|
+
const CONTENT_MAX_LENGTH = 5000;
|
|
33
|
+
const TAGS_MAX_COUNT = 10;
|
|
34
|
+
const SCOPE_PATTERN = /^(global|project:[a-z0-9_-]+|repo:[a-z0-9_-]+)$/i;
|
|
35
|
+
const TAG_PATTERN = /^[a-z0-9][a-z0-9-]*$/i;
|
|
36
|
+
const GENERIC_PHRASES = [
|
|
37
|
+
'this is important',
|
|
38
|
+
'remember this',
|
|
39
|
+
'note to self',
|
|
40
|
+
'todo',
|
|
41
|
+
'fix this',
|
|
42
|
+
'do this',
|
|
43
|
+
'always do',
|
|
44
|
+
'never do'
|
|
45
|
+
];
|
|
46
|
+
function validateTitle(title) {
|
|
47
|
+
const errors = [];
|
|
48
|
+
if (!title || title.trim().length === 0) {
|
|
49
|
+
errors.push('Title is required');
|
|
50
|
+
} else {
|
|
51
|
+
const trimmed = title.trim();
|
|
52
|
+
if (trimmed.length < TITLE_MIN_LENGTH) {
|
|
53
|
+
errors.push(`Title must be at least ${TITLE_MIN_LENGTH} characters`);
|
|
54
|
+
}
|
|
55
|
+
if (trimmed.length > TITLE_MAX_LENGTH) {
|
|
56
|
+
errors.push(`Title must be at most ${TITLE_MAX_LENGTH} characters`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
valid: errors.length === 0,
|
|
61
|
+
errors
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function validateContent(content) {
|
|
65
|
+
const errors = [];
|
|
66
|
+
if (!content || content.trim().length === 0) {
|
|
67
|
+
errors.push('Content is required');
|
|
68
|
+
} else {
|
|
69
|
+
const trimmed = content.trim();
|
|
70
|
+
if (trimmed.length < CONTENT_MIN_LENGTH) {
|
|
71
|
+
errors.push(`Content must be at least ${CONTENT_MIN_LENGTH} characters`);
|
|
72
|
+
}
|
|
73
|
+
if (trimmed.length > CONTENT_MAX_LENGTH) {
|
|
74
|
+
errors.push(`Content must be at most ${CONTENT_MAX_LENGTH} characters`);
|
|
75
|
+
}
|
|
76
|
+
// Check for generic/low-quality content
|
|
77
|
+
const lowerContent = trimmed.toLowerCase();
|
|
78
|
+
for (const phrase of GENERIC_PHRASES){
|
|
79
|
+
if (lowerContent === phrase || lowerContent.startsWith(phrase + ' ')) {
|
|
80
|
+
errors.push('Content appears too generic. Please provide specific, actionable knowledge.');
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
valid: errors.length === 0,
|
|
87
|
+
errors
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function validateTags(tags) {
|
|
91
|
+
const errors = [];
|
|
92
|
+
if (!tags || tags.length === 0) {
|
|
93
|
+
return {
|
|
94
|
+
valid: true,
|
|
95
|
+
errors: []
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (tags.length > TAGS_MAX_COUNT) {
|
|
99
|
+
errors.push(`Maximum ${TAGS_MAX_COUNT} tags allowed`);
|
|
100
|
+
}
|
|
101
|
+
for (const tag of tags){
|
|
102
|
+
if (!TAG_PATTERN.test(tag)) {
|
|
103
|
+
errors.push(`Invalid tag "${tag}". Tags must be alphanumeric with hyphens.`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
valid: errors.length === 0,
|
|
108
|
+
errors
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function validateScope(scope) {
|
|
112
|
+
const errors = [];
|
|
113
|
+
if (!scope || scope === 'global') {
|
|
114
|
+
return {
|
|
115
|
+
valid: true,
|
|
116
|
+
errors: []
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (!SCOPE_PATTERN.test(scope)) {
|
|
120
|
+
errors.push('Invalid scope. Must be "global", "project:<name>", or "repo:<name>"');
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
valid: errors.length === 0,
|
|
124
|
+
errors
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function validateStoreInput(input) {
|
|
128
|
+
const allErrors = [];
|
|
129
|
+
const titleResult = validateTitle(input.title);
|
|
130
|
+
allErrors.push(...titleResult.errors);
|
|
131
|
+
const contentResult = validateContent(input.content);
|
|
132
|
+
allErrors.push(...contentResult.errors);
|
|
133
|
+
const tagsResult = validateTags(input.tags);
|
|
134
|
+
allErrors.push(...tagsResult.errors);
|
|
135
|
+
const scopeResult = validateScope(input.scope);
|
|
136
|
+
allErrors.push(...scopeResult.errors);
|
|
137
|
+
if (allErrors.length > 0) {
|
|
138
|
+
throw new _errors.ValidationError(allErrors.join('; '), {
|
|
139
|
+
errors: allErrors
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/validator.ts"],"sourcesContent":["import { ValidationError } from '../utils/errors';\nimport type { StoreKnowledgeInput } from '../types';\n\nconst TITLE_MIN_LENGTH = 10;\nconst TITLE_MAX_LENGTH = 100;\nconst CONTENT_MIN_LENGTH = 50;\nconst CONTENT_MAX_LENGTH = 5000;\nconst TAGS_MAX_COUNT = 10;\n\nconst SCOPE_PATTERN = /^(global|project:[a-z0-9_-]+|repo:[a-z0-9_-]+)$/i;\nconst TAG_PATTERN = /^[a-z0-9][a-z0-9-]*$/i;\n\nconst GENERIC_PHRASES = [\n 'this is important',\n 'remember this',\n 'note to self',\n 'todo',\n 'fix this',\n 'do this',\n 'always do',\n 'never do',\n];\n\nexport interface ValidationResult {\n valid: boolean;\n errors: string[];\n}\n\nexport function validateTitle(title: string): ValidationResult {\n const errors: string[] = [];\n\n if (!title || title.trim().length === 0) {\n errors.push('Title is required');\n } else {\n const trimmed = title.trim();\n if (trimmed.length < TITLE_MIN_LENGTH) {\n errors.push(`Title must be at least ${TITLE_MIN_LENGTH} characters`);\n }\n if (trimmed.length > TITLE_MAX_LENGTH) {\n errors.push(`Title must be at most ${TITLE_MAX_LENGTH} characters`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function validateContent(content: string): ValidationResult {\n const errors: string[] = [];\n\n if (!content || content.trim().length === 0) {\n errors.push('Content is required');\n } else {\n const trimmed = content.trim();\n if (trimmed.length < CONTENT_MIN_LENGTH) {\n errors.push(`Content must be at least ${CONTENT_MIN_LENGTH} characters`);\n }\n if (trimmed.length > CONTENT_MAX_LENGTH) {\n errors.push(`Content must be at most ${CONTENT_MAX_LENGTH} characters`);\n }\n\n // Check for generic/low-quality content\n const lowerContent = trimmed.toLowerCase();\n for (const phrase of GENERIC_PHRASES) {\n if (lowerContent === phrase || lowerContent.startsWith(phrase + ' ')) {\n errors.push('Content appears too generic. Please provide specific, actionable knowledge.');\n break;\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function validateTags(tags?: string[]): ValidationResult {\n const errors: string[] = [];\n\n if (!tags || tags.length === 0) {\n return { valid: true, errors: [] };\n }\n\n if (tags.length > TAGS_MAX_COUNT) {\n errors.push(`Maximum ${TAGS_MAX_COUNT} tags allowed`);\n }\n\n for (const tag of tags) {\n if (!TAG_PATTERN.test(tag)) {\n errors.push(`Invalid tag \"${tag}\". Tags must be alphanumeric with hyphens.`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function validateScope(scope?: string): ValidationResult {\n const errors: string[] = [];\n\n if (!scope || scope === 'global') {\n return { valid: true, errors: [] };\n }\n\n if (!SCOPE_PATTERN.test(scope)) {\n errors.push('Invalid scope. Must be \"global\", \"project:<name>\", or \"repo:<name>\"');\n }\n\n return { valid: errors.length === 0, errors };\n}\n\nexport function validateStoreInput(input: StoreKnowledgeInput): void {\n const allErrors: string[] = [];\n\n const titleResult = validateTitle(input.title);\n allErrors.push(...titleResult.errors);\n\n const contentResult = validateContent(input.content);\n allErrors.push(...contentResult.errors);\n\n const tagsResult = validateTags(input.tags);\n allErrors.push(...tagsResult.errors);\n\n const scopeResult = validateScope(input.scope);\n allErrors.push(...scopeResult.errors);\n\n if (allErrors.length > 0) {\n throw new ValidationError(allErrors.join('; '), { errors: allErrors });\n }\n}\n"],"names":["validateContent","validateScope","validateStoreInput","validateTags","validateTitle","TITLE_MIN_LENGTH","TITLE_MAX_LENGTH","CONTENT_MIN_LENGTH","CONTENT_MAX_LENGTH","TAGS_MAX_COUNT","SCOPE_PATTERN","TAG_PATTERN","GENERIC_PHRASES","title","errors","trim","length","push","trimmed","valid","content","lowerContent","toLowerCase","phrase","startsWith","tags","tag","test","scope","input","allErrors","titleResult","contentResult","tagsResult","scopeResult","ValidationError","join"],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface KnowledgeItem {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
content: string;
|
|
5
|
+
tags: string[];
|
|
6
|
+
scope: string;
|
|
7
|
+
normalizedTitle: string;
|
|
8
|
+
contentHash: string;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export type KnowledgeScope = 'global' | `project:${string}` | `repo:${string}`;
|
|
13
|
+
export interface StoreKnowledgeInput {
|
|
14
|
+
title: string;
|
|
15
|
+
content: string;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
scope?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface StoreKnowledgeResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
id?: string;
|
|
22
|
+
message: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SearchKnowledgeInput {
|
|
25
|
+
query: string;
|
|
26
|
+
contextTags?: string[];
|
|
27
|
+
scope?: string;
|
|
28
|
+
limit?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface SearchResultItem {
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
content: string;
|
|
34
|
+
tags: string[];
|
|
35
|
+
scope: string;
|
|
36
|
+
score: number;
|
|
37
|
+
}
|
|
38
|
+
export interface SearchKnowledgeResult {
|
|
39
|
+
results: SearchResultItem[];
|
|
40
|
+
totalMatches: number;
|
|
41
|
+
query: string;
|
|
42
|
+
}
|
|
43
|
+
export interface KnowledgeRow {
|
|
44
|
+
id: string;
|
|
45
|
+
title: string;
|
|
46
|
+
content: string;
|
|
47
|
+
tags: string;
|
|
48
|
+
scope: string;
|
|
49
|
+
normalized_title: string;
|
|
50
|
+
content_hash: string;
|
|
51
|
+
created_at: string;
|
|
52
|
+
updated_at: string;
|
|
53
|
+
}
|
|
54
|
+
export interface MetaRow {
|
|
55
|
+
key: string;
|
|
56
|
+
value: string;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,WAAW,MAAM,EAAE,GAAG,QAAQ,MAAM,EAAE,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class KnowledgeMemoryError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
4
|
+
constructor(message: string, code: string, details?: Record<string, unknown> | undefined);
|
|
5
|
+
toJSON(): Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare class ValidationError extends KnowledgeMemoryError {
|
|
8
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
9
|
+
}
|
|
10
|
+
export declare class DuplicateError extends KnowledgeMemoryError {
|
|
11
|
+
readonly existingId: string;
|
|
12
|
+
readonly duplicateType: 'title' | 'content';
|
|
13
|
+
constructor(message: string, existingId: string, duplicateType: 'title' | 'content');
|
|
14
|
+
}
|
|
15
|
+
export declare class StorageError extends KnowledgeMemoryError {
|
|
16
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
17
|
+
}
|
|
18
|
+
export declare class NotFoundError extends KnowledgeMemoryError {
|
|
19
|
+
constructor(message: string, id?: string);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;aAGvB,IAAI,EAAE,MAAM;aACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjD,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;IAOrD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOpC;AAED,qBAAa,eAAgB,SAAQ,oBAAoB;gBACzC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAIjE;AAED,qBAAa,cAAe,SAAQ,oBAAoB;aAGhC,UAAU,EAAE,MAAM;aAClB,aAAa,EAAE,OAAO,GAAG,SAAS;gBAFlD,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,OAAO,GAAG,SAAS;CAKzD;AAED,qBAAa,YAAa,SAAQ,oBAAoB;gBACtC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAIjE;AAED,qBAAa,aAAc,SAAQ,oBAAoB;gBACvC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM;CAI3C"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get DuplicateError () {
|
|
13
|
+
return DuplicateError;
|
|
14
|
+
},
|
|
15
|
+
get KnowledgeMemoryError () {
|
|
16
|
+
return KnowledgeMemoryError;
|
|
17
|
+
},
|
|
18
|
+
get NotFoundError () {
|
|
19
|
+
return NotFoundError;
|
|
20
|
+
},
|
|
21
|
+
get StorageError () {
|
|
22
|
+
return StorageError;
|
|
23
|
+
},
|
|
24
|
+
get ValidationError () {
|
|
25
|
+
return ValidationError;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
let KnowledgeMemoryError = class KnowledgeMemoryError extends Error {
|
|
29
|
+
code;
|
|
30
|
+
details;
|
|
31
|
+
constructor(message, code, details){
|
|
32
|
+
super(message), this.code = code, this.details = details;
|
|
33
|
+
this.name = 'KnowledgeMemoryError';
|
|
34
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
35
|
+
}
|
|
36
|
+
toJSON() {
|
|
37
|
+
return {
|
|
38
|
+
error: this.code,
|
|
39
|
+
message: this.message,
|
|
40
|
+
details: this.details
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
let ValidationError = class ValidationError extends KnowledgeMemoryError {
|
|
45
|
+
constructor(message, details){
|
|
46
|
+
super(message, 'VALIDATION_ERROR', details);
|
|
47
|
+
this.name = 'ValidationError';
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
let DuplicateError = class DuplicateError extends KnowledgeMemoryError {
|
|
51
|
+
existingId;
|
|
52
|
+
duplicateType;
|
|
53
|
+
constructor(message, existingId, duplicateType){
|
|
54
|
+
super(message, 'DUPLICATE_ERROR', {
|
|
55
|
+
existingId,
|
|
56
|
+
duplicateType
|
|
57
|
+
}), this.existingId = existingId, this.duplicateType = duplicateType;
|
|
58
|
+
this.name = 'DuplicateError';
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
let StorageError = class StorageError extends KnowledgeMemoryError {
|
|
62
|
+
constructor(message, details){
|
|
63
|
+
super(message, 'STORAGE_ERROR', details);
|
|
64
|
+
this.name = 'StorageError';
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
let NotFoundError = class NotFoundError extends KnowledgeMemoryError {
|
|
68
|
+
constructor(message, id){
|
|
69
|
+
super(message, 'NOT_FOUND_ERROR', id ? {
|
|
70
|
+
id
|
|
71
|
+
} : undefined);
|
|
72
|
+
this.name = 'NotFoundError';
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/errors.ts"],"sourcesContent":["export class KnowledgeMemoryError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'KnowledgeMemoryError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n error: this.code,\n message: this.message,\n details: this.details,\n };\n }\n}\n\nexport class ValidationError extends KnowledgeMemoryError {\n constructor(message: string, details?: Record<string, unknown>) {\n super(message, 'VALIDATION_ERROR', details);\n this.name = 'ValidationError';\n }\n}\n\nexport class DuplicateError extends KnowledgeMemoryError {\n constructor(\n message: string,\n public readonly existingId: string,\n public readonly duplicateType: 'title' | 'content'\n ) {\n super(message, 'DUPLICATE_ERROR', { existingId, duplicateType });\n this.name = 'DuplicateError';\n }\n}\n\nexport class StorageError extends KnowledgeMemoryError {\n constructor(message: string, details?: Record<string, unknown>) {\n super(message, 'STORAGE_ERROR', details);\n this.name = 'StorageError';\n }\n}\n\nexport class NotFoundError extends KnowledgeMemoryError {\n constructor(message: string, id?: string) {\n super(message, 'NOT_FOUND_ERROR', id ? { id } : undefined);\n this.name = 'NotFoundError';\n }\n}"],"names":["DuplicateError","KnowledgeMemoryError","NotFoundError","StorageError","ValidationError","Error","message","code","details","name","Object","setPrototypeOf","prototype","toJSON","error","existingId","duplicateType","id","undefined"],"mappings":";;;;;;;;;;;QA2BaA;eAAAA;;QA3BAC;eAAAA;;QA6CAC;eAAAA;;QAPAC;eAAAA;;QAlBAC;eAAAA;;;AApBN,IAAA,AAAMH,uBAAN,MAAMA,6BAA6BI;;;IACtC,YACIC,OAAe,EACf,AAAgBC,IAAY,EAC5B,AAAgBC,OAAiC,CACnD;QACE,KAAK,CAACF,eAHUC,OAAAA,WACAC,UAAAA;QAGhB,IAAI,CAACC,IAAI,GAAG;QACZC,OAAOC,cAAc,CAAC,IAAI,EAAE,WAAWC,SAAS;IACpD;IAEAC,SAAkC;QAC9B,OAAO;YACHC,OAAO,IAAI,CAACP,IAAI;YAChBD,SAAS,IAAI,CAACA,OAAO;YACrBE,SAAS,IAAI,CAACA,OAAO;QACzB;IACJ;AACJ;AAEO,IAAA,AAAMJ,kBAAN,MAAMA,wBAAwBH;IACjC,YAAYK,OAAe,EAAEE,OAAiC,CAAE;QAC5D,KAAK,CAACF,SAAS,oBAAoBE;QACnC,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ;AAEO,IAAA,AAAMT,iBAAN,MAAMA,uBAAuBC;;;IAChC,YACIK,OAAe,EACf,AAAgBS,UAAkB,EAClC,AAAgBC,aAAkC,CACpD;QACE,KAAK,CAACV,SAAS,mBAAmB;YAAES;YAAYC;QAAc,SAH9CD,aAAAA,iBACAC,gBAAAA;QAGhB,IAAI,CAACP,IAAI,GAAG;IAChB;AACJ;AAEO,IAAA,AAAMN,eAAN,MAAMA,qBAAqBF;IAC9B,YAAYK,OAAe,EAAEE,OAAiC,CAAE;QAC5D,KAAK,CAACF,SAAS,iBAAiBE;QAChC,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ;AAEO,IAAA,AAAMP,gBAAN,MAAMA,sBAAsBD;IAC/B,YAAYK,OAAe,EAAEW,EAAW,CAAE;QACtC,KAAK,CAACX,SAAS,mBAAmBW,KAAK;YAAEA;QAAG,IAAIC;QAChD,IAAI,CAACT,IAAI,GAAG;IAChB;AACJ"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ai-devkit/memory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight MCP-based memory service for AI agents - store and retrieve actionable knowledge",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./api": {
|
|
13
|
+
"types": "./dist/api.d.ts",
|
|
14
|
+
"default": "./dist/api.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"ai-devkit-memory": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "swc src -d dist --strip-leading-paths && tsc --emitDeclarationOnly && cp -r src/database/migrations dist/database/",
|
|
22
|
+
"dev": "swc src -d dist --strip-leading-paths --watch",
|
|
23
|
+
"start": "node dist/index.js",
|
|
24
|
+
"inspect": "npm run build && npx @modelcontextprotocol/inspector node dist/index.js",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "jest",
|
|
27
|
+
"test:coverage": "jest --coverage",
|
|
28
|
+
"lint": "eslint src/**/*.ts",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mcp",
|
|
33
|
+
"memory",
|
|
34
|
+
"ai",
|
|
35
|
+
"agent",
|
|
36
|
+
"knowledge",
|
|
37
|
+
"sqlite",
|
|
38
|
+
"fts5"
|
|
39
|
+
],
|
|
40
|
+
"author": "",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
44
|
+
"better-sqlite3": "^11.0.0",
|
|
45
|
+
"commander": "^12.0.0",
|
|
46
|
+
"uuid": "^10.0.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@swc/cli": "^0.5.2",
|
|
50
|
+
"@swc/core": "^1.10.0",
|
|
51
|
+
"@swc/jest": "^0.2.37",
|
|
52
|
+
"@types/better-sqlite3": "^7.6.11",
|
|
53
|
+
"@types/jest": "^29.5.12",
|
|
54
|
+
"@types/node": "^20.14.0",
|
|
55
|
+
"@types/uuid": "^10.0.0",
|
|
56
|
+
"chokidar": "^3.6.0",
|
|
57
|
+
"jest": "^29.7.0",
|
|
58
|
+
"typescript": "^5.4.5"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=18.0.0"
|
|
62
|
+
},
|
|
63
|
+
"files": [
|
|
64
|
+
"dist",
|
|
65
|
+
"README.md"
|
|
66
|
+
]
|
|
67
|
+
}
|