@ai-devkit/memory 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/api.d.ts +4 -4
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +17 -46
  4. package/dist/api.js.map +1 -1
  5. package/dist/database/connection.d.ts.map +1 -1
  6. package/dist/database/connection.js +15 -45
  7. package/dist/database/connection.js.map +1 -1
  8. package/dist/database/index.d.ts +3 -3
  9. package/dist/database/index.d.ts.map +1 -1
  10. package/dist/database/index.js +2 -35
  11. package/dist/database/index.js.map +1 -1
  12. package/dist/database/schema.d.ts +1 -1
  13. package/dist/database/schema.d.ts.map +1 -1
  14. package/dist/database/schema.js +12 -34
  15. package/dist/database/schema.js.map +1 -1
  16. package/dist/handlers/search.d.ts +1 -1
  17. package/dist/handlers/search.d.ts.map +1 -1
  18. package/dist/handlers/search.js +12 -22
  19. package/dist/handlers/search.js.map +1 -1
  20. package/dist/handlers/store.d.ts +1 -1
  21. package/dist/handlers/store.d.ts.map +1 -1
  22. package/dist/handlers/store.js +17 -27
  23. package/dist/handlers/store.js.map +1 -1
  24. package/dist/handlers/update.d.ts +1 -1
  25. package/dist/handlers/update.d.ts.map +1 -1
  26. package/dist/handlers/update.js +16 -26
  27. package/dist/handlers/update.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +5 -21
  31. package/dist/index.js.map +1 -1
  32. package/dist/server.js +18 -39
  33. package/dist/server.js.map +1 -1
  34. package/dist/services/normalizer.js +17 -34
  35. package/dist/services/normalizer.js.map +1 -1
  36. package/dist/services/ranker.d.ts +1 -1
  37. package/dist/services/ranker.d.ts.map +1 -1
  38. package/dist/services/ranker.js +5 -11
  39. package/dist/services/ranker.js.map +1 -1
  40. package/dist/services/search.js +15 -24
  41. package/dist/services/search.js.map +1 -1
  42. package/dist/services/validator.d.ts +1 -1
  43. package/dist/services/validator.d.ts.map +1 -1
  44. package/dist/services/validator.js +9 -39
  45. package/dist/services/validator.js.map +1 -1
  46. package/dist/types/index.js +1 -4
  47. package/dist/types/index.js.map +1 -1
  48. package/dist/utils/errors.js +10 -37
  49. package/dist/utils/errors.js.map +1 -1
  50. package/package.json +15 -12
@@ -1,24 +1,3 @@
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
1
  /**
23
2
  * FTS5 Query Builder
24
3
  * Converts natural language queries to FTS5 match expressions
@@ -31,7 +10,14 @@ _export(exports, {
31
10
  .replace(/\b(AND|OR|NOT)\b/gi, '') // Remove boolean operators
32
11
  .trim().replace(/\s+/g, ' '); // Collapse multiple spaces
33
12
  }
34
- function buildFtsQuery(query) {
13
+ /**
14
+ * Build FTS5 query from natural language input
15
+ *
16
+ * Strategy:
17
+ * - Split query into words
18
+ * - Use prefix matching (*) for partial matches
19
+ * - Escape special characters
20
+ */ export function buildFtsQuery(query) {
35
21
  const escaped = escapeFtsSpecialChars(query);
36
22
  const words = escaped.split(/\s+/).filter((w)=>w.length > 0);
37
23
  if (words.length === 0) {
@@ -41,7 +27,10 @@ function buildFtsQuery(query) {
41
27
  // This allows "api design" to match "API", "designing", etc.
42
28
  return words.map((word)=>`${word}*`).join(' ');
43
29
  }
44
- function buildSearchQuery(ftsQuery, scope, limit = 5) {
30
+ /**
31
+ * Build FTS5 query with column boosting
32
+ * Uses bm25() with weights: title=10, content=5, tags=1
33
+ */ export function buildSearchQuery(ftsQuery, scope, limit = 5) {
45
34
  const params = [];
46
35
  let sql = `
47
36
  SELECT
@@ -69,7 +58,9 @@ function buildSearchQuery(ftsQuery, scope, limit = 5) {
69
58
  params
70
59
  };
71
60
  }
72
- function buildSimpleQuery(scope, limit = 5) {
61
+ /**
62
+ * Build simple search query without FTS (fallback for empty queries)
63
+ */ export function buildSimpleQuery(scope, limit = 5) {
73
64
  const params = [];
74
65
  let sql = `
75
66
  SELECT
@@ -1 +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,aAAa,KAAM,kDAAkD;KAC7EA,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"}
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":["escapeFtsSpecialChars","text","replace","trim","buildFtsQuery","query","escaped","words","split","filter","w","length","map","word","join","buildSearchQuery","ftsQuery","scope","limit","params","sql","push","buildSimpleQuery"],"mappings":"AAAA;;;CAGC,GAED;;CAEC,GACD,SAASA,sBAAsBC,IAAY;IACvC,oDAAoD;IACpD,OAAOA,KACFC,OAAO,CAAC,MAAM,MAAO,4BAA4B;KACjDA,OAAO,CAAC,aAAa,KAAM,kDAAkD;KAC7EA,OAAO,CAAC,sBAAsB,IAAK,2BAA2B;KAC9DC,IAAI,GACJD,OAAO,CAAC,QAAQ,MAAO,2BAA2B;AAC3D;AAEA;;;;;;;CAOC,GACD,OAAO,SAASE,cAAcC,KAAa;IACvC,MAAMC,UAAUN,sBAAsBK;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;AAEA;;;CAGC,GACD,OAAO,SAASC,iBACZC,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;AAEA;;CAEC,GACD,OAAO,SAASG,iBACZL,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"}
@@ -1,4 +1,4 @@
1
- import type { StoreKnowledgeInput, UpdateKnowledgeInput } from '../types';
1
+ import type { StoreKnowledgeInput, UpdateKnowledgeInput } from '../types/index.js';
2
2
  export interface ValidationResult {
3
3
  valid: boolean;
4
4
  errors: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/services/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAsB1E,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,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAqCrE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAkBnE"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/services/validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAsBnF,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,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAqCrE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAkBnE"}
@@ -1,34 +1,4 @@
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
- get validateUpdateInput () {
28
- return validateUpdateInput;
29
- }
30
- });
31
- const _errors = require("../utils/errors");
1
+ import { ValidationError } from '../utils/errors.js';
32
2
  const TITLE_MIN_LENGTH = 10;
33
3
  const TITLE_MAX_LENGTH = 100;
34
4
  const CONTENT_MIN_LENGTH = 50;
@@ -46,7 +16,7 @@ const GENERIC_PHRASES = [
46
16
  'always do',
47
17
  'never do'
48
18
  ];
49
- function validateTitle(title) {
19
+ export function validateTitle(title) {
50
20
  const errors = [];
51
21
  if (!title || title.trim().length === 0) {
52
22
  errors.push('Title is required');
@@ -64,7 +34,7 @@ function validateTitle(title) {
64
34
  errors
65
35
  };
66
36
  }
67
- function validateContent(content) {
37
+ export function validateContent(content) {
68
38
  const errors = [];
69
39
  if (!content || content.trim().length === 0) {
70
40
  errors.push('Content is required');
@@ -90,7 +60,7 @@ function validateContent(content) {
90
60
  errors
91
61
  };
92
62
  }
93
- function validateTags(tags) {
63
+ export function validateTags(tags) {
94
64
  const errors = [];
95
65
  if (!tags || tags.length === 0) {
96
66
  return {
@@ -111,7 +81,7 @@ function validateTags(tags) {
111
81
  errors
112
82
  };
113
83
  }
114
- function validateScope(scope) {
84
+ export function validateScope(scope) {
115
85
  const errors = [];
116
86
  if (!scope || scope === 'global') {
117
87
  return {
@@ -127,7 +97,7 @@ function validateScope(scope) {
127
97
  errors
128
98
  };
129
99
  }
130
- function validateUpdateInput(input) {
100
+ export function validateUpdateInput(input) {
131
101
  const allErrors = [];
132
102
  if (!input.id || input.id.trim().length === 0) {
133
103
  allErrors.push('ID is required');
@@ -153,12 +123,12 @@ function validateUpdateInput(input) {
153
123
  allErrors.push(...scopeResult.errors);
154
124
  }
155
125
  if (allErrors.length > 0) {
156
- throw new _errors.ValidationError(allErrors.join('; '), {
126
+ throw new ValidationError(allErrors.join('; '), {
157
127
  errors: allErrors
158
128
  });
159
129
  }
160
130
  }
161
- function validateStoreInput(input) {
131
+ export function validateStoreInput(input) {
162
132
  const allErrors = [];
163
133
  const titleResult = validateTitle(input.title);
164
134
  allErrors.push(...titleResult.errors);
@@ -169,7 +139,7 @@ function validateStoreInput(input) {
169
139
  const scopeResult = validateScope(input.scope);
170
140
  allErrors.push(...scopeResult.errors);
171
141
  if (allErrors.length > 0) {
172
- throw new _errors.ValidationError(allErrors.join('; '), {
142
+ throw new ValidationError(allErrors.join('; '), {
173
143
  errors: allErrors
174
144
  });
175
145
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/validator.ts"],"sourcesContent":["import { ValidationError } from '../utils/errors';\nimport type { StoreKnowledgeInput, UpdateKnowledgeInput } 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 validateUpdateInput(input: UpdateKnowledgeInput): void {\n const allErrors: string[] = [];\n\n if (!input.id || input.id.trim().length === 0) {\n allErrors.push('ID is required');\n }\n\n const hasUpdateField = input.title !== undefined || input.content !== undefined ||\n input.tags !== undefined || input.scope !== undefined;\n\n if (!hasUpdateField) {\n allErrors.push('At least one field to update is required (title, content, tags, or scope)');\n }\n\n if (input.title !== undefined) {\n const titleResult = validateTitle(input.title);\n allErrors.push(...titleResult.errors);\n }\n\n if (input.content !== undefined) {\n const contentResult = validateContent(input.content);\n allErrors.push(...contentResult.errors);\n }\n\n if (input.tags !== undefined) {\n const tagsResult = validateTags(input.tags);\n allErrors.push(...tagsResult.errors);\n }\n\n if (input.scope !== undefined) {\n const scopeResult = validateScope(input.scope);\n allErrors.push(...scopeResult.errors);\n }\n\n if (allErrors.length > 0) {\n throw new ValidationError(allErrors.join('; '), { errors: allErrors });\n }\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","validateUpdateInput","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","id","hasUpdateField","undefined","titleResult","contentResult","tagsResult","scopeResult","ValidationError","join"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/validator.ts"],"sourcesContent":["import { ValidationError } from '../utils/errors.js';\nimport type { StoreKnowledgeInput, UpdateKnowledgeInput } from '../types/index.js';\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 validateUpdateInput(input: UpdateKnowledgeInput): void {\n const allErrors: string[] = [];\n\n if (!input.id || input.id.trim().length === 0) {\n allErrors.push('ID is required');\n }\n\n const hasUpdateField = input.title !== undefined || input.content !== undefined ||\n input.tags !== undefined || input.scope !== undefined;\n\n if (!hasUpdateField) {\n allErrors.push('At least one field to update is required (title, content, tags, or scope)');\n }\n\n if (input.title !== undefined) {\n const titleResult = validateTitle(input.title);\n allErrors.push(...titleResult.errors);\n }\n\n if (input.content !== undefined) {\n const contentResult = validateContent(input.content);\n allErrors.push(...contentResult.errors);\n }\n\n if (input.tags !== undefined) {\n const tagsResult = validateTags(input.tags);\n allErrors.push(...tagsResult.errors);\n }\n\n if (input.scope !== undefined) {\n const scopeResult = validateScope(input.scope);\n allErrors.push(...scopeResult.errors);\n }\n\n if (allErrors.length > 0) {\n throw new ValidationError(allErrors.join('; '), { errors: allErrors });\n }\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":["ValidationError","TITLE_MIN_LENGTH","TITLE_MAX_LENGTH","CONTENT_MIN_LENGTH","CONTENT_MAX_LENGTH","TAGS_MAX_COUNT","SCOPE_PATTERN","TAG_PATTERN","GENERIC_PHRASES","validateTitle","title","errors","trim","length","push","trimmed","valid","validateContent","content","lowerContent","toLowerCase","phrase","startsWith","validateTags","tags","tag","test","validateScope","scope","validateUpdateInput","input","allErrors","id","hasUpdateField","undefined","titleResult","contentResult","tagsResult","scopeResult","join","validateStoreInput"],"mappings":"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"}
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
1
+ export { };
5
2
 
6
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/index.ts"],"names":[],"mappings":""}
1
+ {"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export interface KnowledgeItem {\n id: string;\n title: string;\n content: string;\n tags: string[];\n scope: string;\n normalizedTitle: string;\n contentHash: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport type KnowledgeScope = 'global' | `project:${string}` | `repo:${string}`;\n\nexport interface StoreKnowledgeInput {\n title: string;\n content: string;\n tags?: string[];\n scope?: string;\n}\n\nexport interface StoreKnowledgeResult {\n success: boolean;\n id?: string;\n message: string;\n}\n\nexport interface UpdateKnowledgeInput {\n id: string;\n title?: string;\n content?: string;\n tags?: string[];\n scope?: string;\n}\n\nexport interface UpdateKnowledgeResult {\n success: boolean;\n id: string;\n message: string;\n}\n\nexport interface SearchKnowledgeInput {\n query: string;\n contextTags?: string[];\n scope?: string;\n limit?: number;\n}\n\nexport interface SearchResultItem {\n id: string;\n title: string;\n content: string;\n tags: string[];\n scope: string;\n score: number;\n}\n\nexport interface SearchKnowledgeResult {\n results: SearchResultItem[];\n totalMatches: number;\n query: string;\n}\n\nexport interface KnowledgeRow {\n id: string;\n title: string;\n content: string;\n tags: string;\n scope: string;\n normalized_title: string;\n content_hash: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface MetaRow {\n key: string;\n value: string;\n}"],"names":[],"mappings":"AA2EA,WAGC"}
@@ -1,31 +1,4 @@
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 {
1
+ export class KnowledgeMemoryError extends Error {
29
2
  code;
30
3
  details;
31
4
  constructor(message, code, details){
@@ -40,14 +13,14 @@ let KnowledgeMemoryError = class KnowledgeMemoryError extends Error {
40
13
  details: this.details
41
14
  };
42
15
  }
43
- };
44
- let ValidationError = class ValidationError extends KnowledgeMemoryError {
16
+ }
17
+ export class ValidationError extends KnowledgeMemoryError {
45
18
  constructor(message, details){
46
19
  super(message, 'VALIDATION_ERROR', details);
47
20
  this.name = 'ValidationError';
48
21
  }
49
- };
50
- let DuplicateError = class DuplicateError extends KnowledgeMemoryError {
22
+ }
23
+ export class DuplicateError extends KnowledgeMemoryError {
51
24
  existingId;
52
25
  duplicateType;
53
26
  constructor(message, existingId, duplicateType){
@@ -57,20 +30,20 @@ let DuplicateError = class DuplicateError extends KnowledgeMemoryError {
57
30
  }), this.existingId = existingId, this.duplicateType = duplicateType;
58
31
  this.name = 'DuplicateError';
59
32
  }
60
- };
61
- let StorageError = class StorageError extends KnowledgeMemoryError {
33
+ }
34
+ export class StorageError extends KnowledgeMemoryError {
62
35
  constructor(message, details){
63
36
  super(message, 'STORAGE_ERROR', details);
64
37
  this.name = 'StorageError';
65
38
  }
66
- };
67
- let NotFoundError = class NotFoundError extends KnowledgeMemoryError {
39
+ }
40
+ export class NotFoundError extends KnowledgeMemoryError {
68
41
  constructor(message, id){
69
42
  super(message, 'NOT_FOUND_ERROR', id ? {
70
43
  id
71
44
  } : undefined);
72
45
  this.name = 'NotFoundError';
73
46
  }
74
- };
47
+ }
75
48
 
76
49
  //# sourceMappingURL=errors.js.map
@@ -1 +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"}
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":["KnowledgeMemoryError","Error","message","code","details","name","Object","setPrototypeOf","prototype","toJSON","error","ValidationError","DuplicateError","existingId","duplicateType","StorageError","NotFoundError","id","undefined"],"mappings":"AAAA,OAAO,MAAMA,6BAA6BC;;;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;AAEA,OAAO,MAAMO,wBAAwBX;IACjC,YAAYE,OAAe,EAAEE,OAAiC,CAAE;QAC5D,KAAK,CAACF,SAAS,oBAAoBE;QACnC,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMO,uBAAuBZ;;;IAChC,YACIE,OAAe,EACf,AAAgBW,UAAkB,EAClC,AAAgBC,aAAkC,CACpD;QACE,KAAK,CAACZ,SAAS,mBAAmB;YAAEW;YAAYC;QAAc,SAH9CD,aAAAA,iBACAC,gBAAAA;QAGhB,IAAI,CAACT,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMU,qBAAqBf;IAC9B,YAAYE,OAAe,EAAEE,OAAiC,CAAE;QAC5D,KAAK,CAACF,SAAS,iBAAiBE;QAChC,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMW,sBAAsBhB;IAC/B,YAAYE,OAAe,EAAEe,EAAW,CAAE;QACtC,KAAK,CAACf,SAAS,mBAAmBe,KAAK;YAAEA;QAAG,IAAIC;QAChD,IAAI,CAACb,IAAI,GAAG;IAChB;AACJ"}
package/package.json CHANGED
@@ -1,17 +1,18 @@
1
1
  {
2
2
  "name": "@ai-devkit/memory",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
+ "type": "module",
4
5
  "description": "Local MCP memory for AI coding agents to reuse project decisions, conventions, and fixes across sessions",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
8
  "exports": {
8
9
  ".": {
9
10
  "types": "./dist/index.d.ts",
10
- "default": "./dist/index.js"
11
+ "import": "./dist/index.js"
11
12
  },
12
13
  "./api": {
13
14
  "types": "./dist/api.d.ts",
14
- "default": "./dist/api.js"
15
+ "import": "./dist/api.js"
15
16
  }
16
17
  },
17
18
  "bin": {
@@ -23,11 +24,12 @@
23
24
  "start": "node dist/index.js",
24
25
  "inspect": "npm run build && npx @modelcontextprotocol/inspector node dist/index.js",
25
26
  "typecheck": "tsc --noEmit",
26
- "test": "jest",
27
- "test:coverage": "jest --coverage",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "test:coverage": "vitest run --coverage",
28
30
  "lint": "eslint src/**/*.ts",
29
31
  "clean": "rm -rf dist",
30
- "benchmark": "npx ts-node --swc scripts/benchmark.ts --items=5000 --searches=300"
32
+ "benchmark": "node --import 'ts-node/register/esm' scripts/benchmark.ts --items=5000 --searches=300"
31
33
  },
32
34
  "keywords": [
33
35
  "mcp",
@@ -42,21 +44,22 @@
42
44
  "license": "MIT",
43
45
  "dependencies": {
44
46
  "@modelcontextprotocol/sdk": "^1.0.0",
47
+ "@typescript-eslint/eslint-plugin": "8.60.1",
48
+ "@typescript-eslint/parser": "8.60.1",
45
49
  "better-sqlite3": "^12.6.2",
46
- "uuid": "^10.0.0"
50
+ "uuid": "^14.0.0"
47
51
  },
48
52
  "devDependencies": {
49
- "@swc/cli": "^0.5.2",
53
+ "@swc/cli": "^0.8.1",
50
54
  "@swc/core": "^1.10.0",
51
- "@swc/jest": "^0.2.37",
52
55
  "@types/better-sqlite3": "^7.6.11",
53
- "@types/jest": "^29.5.12",
54
56
  "@types/node": "^20.14.0",
55
57
  "@types/uuid": "^10.0.0",
58
+ "@vitest/coverage-v8": "^4.1.8",
56
59
  "chokidar": "^3.6.0",
57
- "jest": "^29.7.0",
58
60
  "ts-node": "^10.9.2",
59
- "typescript": "^5.4.5"
61
+ "typescript": "^5.5.0",
62
+ "vitest": "^4.1.8"
60
63
  },
61
64
  "engines": {
62
65
  "node": ">=20.20.0"