@ai-devkit/memory 0.4.0 → 0.5.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 CHANGED
@@ -1,15 +1,17 @@
1
1
  # @ai-devkit/memory
2
2
 
3
- A lightweight MCP-based memory service for AI agents. Store and retrieve actionable knowledge using SQLite with FTS5 full-text search.
3
+ A lightweight MCP-based memory service for AI agents. Store and retrieve knowledge using SQLite with full-text search.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@ai-devkit/memory.svg)](https://www.npmjs.com/package/@ai-devkit/memory)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
7
 
5
8
  ## Features
6
9
 
7
- - 🔍 **Full-Text Search** - FTS5 with BM25 ranking
8
- - 🏷️ **Tag-Based Filtering** - Boost results by contextTags
9
- - 📁 **Scoped Knowledge** - global, project, or repo-specific rules
10
- - 🔄 **Deduplication** - Prevents duplicate content
11
- - ⚡ **Fast** - SQLite with WAL mode, <50ms search latency
12
- - 📦 **Portable** - Single database file, no external dependencies
10
+ - 🔍 **Full-Text Search** FTS5 with BM25 ranking
11
+ - 🏷️ **Tag-Based Filtering** Organize and find knowledge by tags
12
+ - 📁 **Scoped Knowledge** Global, project, or repo-specific rules
13
+ - 🔄 **Deduplication** Prevents duplicate content automatically
14
+ - ⚡ **Fast** SQLite with WAL mode, <50ms search latency
13
15
 
14
16
  ## Installation
15
17
 
@@ -19,9 +21,7 @@ npm install @ai-devkit/memory
19
21
 
20
22
  ## Quick Start
21
23
 
22
- ### As MCP Server
23
-
24
- Add to your MCP client configuration:
24
+ Add to your MCP client configuration (e.g., Claude Code, Cursor):
25
25
 
26
26
  ```json
27
27
  {
@@ -34,23 +34,21 @@ Add to your MCP client configuration:
34
34
  }
35
35
  ```
36
36
 
37
- ### Using the Tools
38
-
39
- #### Store Knowledge
37
+ ### Store Knowledge
40
38
 
41
39
  ```json
42
40
  {
43
41
  "tool": "memory.storeKnowledge",
44
42
  "arguments": {
45
43
  "title": "Always use Response DTOs for API endpoints",
46
- "content": "When building REST APIs, always use Response DTOs instead of returning domain entities directly. This provides better API versioning, security, and decoupling.",
44
+ "content": "When building REST APIs, always use Response DTOs instead of returning domain entities directly.",
47
45
  "tags": ["api", "backend", "dto"],
48
46
  "scope": "global"
49
47
  }
50
48
  }
51
49
  ```
52
50
 
53
- #### Search Knowledge
51
+ ### Search Knowledge
54
52
 
55
53
  ```json
56
54
  {
@@ -63,65 +61,11 @@ Add to your MCP client configuration:
63
61
  }
64
62
  ```
65
63
 
66
- ## API Reference
67
-
68
- ### `memory.storeKnowledge`
69
-
70
- Store a new knowledge item.
71
-
72
- | Parameter | Type | Required | Description |
73
- |-----------|------|----------|-------------|
74
- | `title` | string | ✅ | Short description (10-100 chars) |
75
- | `content` | string | ✅ | Detailed explanation in markdown (50-5000 chars) |
76
- | `tags` | string[] | ❌ | Domain keywords (max 10) |
77
- | `scope` | string | ❌ | `global`, `project:<name>`, or `repo:<name>` |
64
+ ## Documentation
78
65
 
79
- ### `memory.searchKnowledge`
80
-
81
- Search for relevant knowledge.
82
-
83
- | Parameter | Type | Required | Description |
84
- |-----------|------|----------|-------------|
85
- | `query` | string | ✅ | Natural language task description (3-500 chars) |
86
- | `contextTags` | string[] | ❌ | Tags to boost matching results |
87
- | `scope` | string | ❌ | Scope filter (project results prioritized) |
88
- | `limit` | number | ❌ | Max results (1-20, default: 5) |
89
-
90
- ## Ranking Algorithm
91
-
92
- Results are ranked using:
93
-
94
- ```
95
- final_score = bm25_score × tag_boost + scope_boost
66
+ 📖 **For the full API reference, ranking details, and advanced usage, visit:**
96
67
 
97
- Where:
98
- bm25_score = FTS5 bm25() with column weights (title=10, content=5, tags=1)
99
- tag_boost = 1 + (matching_tags × 0.1)
100
- scope_boost = +0.5 if scope matches, +0.2 if global
101
- ```
102
-
103
- ## Database Location
104
-
105
- Default: `~/.ai-devkit/memory.db`
106
-
107
- ## Development
108
-
109
- ```bash
110
- # Install dependencies
111
- npm install
112
-
113
- # Build
114
- npm run build
115
-
116
- # Run tests
117
- npm test
118
-
119
- # Run with MCP Inspector
120
- npm run inspect
121
-
122
- # Start server
123
- npm run start
124
- ```
68
+ **[ai-devkit.com/docs](https://ai-devkit.com/docs/)**
125
69
 
126
70
  ## License
127
71
 
package/dist/api.d.ts CHANGED
@@ -1,14 +1,22 @@
1
1
  import { storeKnowledge } from './handlers/store';
2
2
  import { searchKnowledge } from './handlers/search';
3
- import type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult } from './types';
4
- export { storeKnowledge, searchKnowledge };
5
- export type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult };
3
+ import { updateKnowledge } from './handlers/update';
4
+ import type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult, UpdateKnowledgeInput, UpdateKnowledgeResult } from './types';
5
+ export { storeKnowledge, searchKnowledge, updateKnowledge };
6
+ export type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult, UpdateKnowledgeInput, UpdateKnowledgeResult };
6
7
  export interface MemoryStoreOptions {
7
8
  title: string;
8
9
  content: string;
9
10
  tags?: string;
10
11
  scope?: string;
11
12
  }
13
+ export interface MemoryUpdateOptions {
14
+ id: string;
15
+ title?: string;
16
+ content?: string;
17
+ tags?: string;
18
+ scope?: string;
19
+ }
12
20
  export interface MemorySearchOptions {
13
21
  query: string;
14
22
  tags?: string;
@@ -16,5 +24,6 @@ export interface MemorySearchOptions {
16
24
  limit?: number;
17
25
  }
18
26
  export declare function memoryStoreCommand(options: MemoryStoreOptions): StoreKnowledgeResult;
27
+ export declare function memoryUpdateCommand(options: MemoryUpdateOptions): UpdateKnowledgeResult;
19
28
  export declare function memorySearchCommand(options: MemorySearchOptions): SearchKnowledgeResult;
20
29
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEtH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAC3C,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,CAAC;AAGvG,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,oBAAoB,CAapF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,qBAAqB,CAavF"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAEnK,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC;AAC5D,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,CAAC;AAGpJ,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,oBAAoB,CAapF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,qBAAqB,CAcvF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,qBAAqB,CAavF"}
package/dist/api.js CHANGED
@@ -15,15 +15,22 @@ _export(exports, {
15
15
  get memoryStoreCommand () {
16
16
  return memoryStoreCommand;
17
17
  },
18
+ get memoryUpdateCommand () {
19
+ return memoryUpdateCommand;
20
+ },
18
21
  get searchKnowledge () {
19
22
  return _search.searchKnowledge;
20
23
  },
21
24
  get storeKnowledge () {
22
25
  return _store.storeKnowledge;
26
+ },
27
+ get updateKnowledge () {
28
+ return _update.updateKnowledge;
23
29
  }
24
30
  });
25
31
  const _store = require("./handlers/store");
26
32
  const _search = require("./handlers/search");
33
+ const _update = require("./handlers/update");
27
34
  const _database = require("./database");
28
35
  function memoryStoreCommand(options) {
29
36
  try {
@@ -38,6 +45,20 @@ function memoryStoreCommand(options) {
38
45
  (0, _database.closeDatabase)();
39
46
  }
40
47
  }
48
+ function memoryUpdateCommand(options) {
49
+ try {
50
+ const input = {
51
+ id: options.id,
52
+ title: options.title,
53
+ content: options.content,
54
+ tags: options.tags ? options.tags.split(',').map((t)=>t.trim()) : undefined,
55
+ scope: options.scope
56
+ };
57
+ return (0, _update.updateKnowledge)(input);
58
+ } finally{
59
+ (0, _database.closeDatabase)();
60
+ }
61
+ }
41
62
  function memorySearchCommand(options) {
42
63
  try {
43
64
  const input = {
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import { storeKnowledge } from './handlers/store';\nimport { searchKnowledge } from './handlers/search';\nimport { closeDatabase } from './database';\nimport type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult } from './types';\n\nexport { storeKnowledge, searchKnowledge };\nexport type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult };\n\n// CLI command handlers for integration with main ai-devkit CLI\nexport interface MemoryStoreOptions {\n title: string;\n content: string;\n tags?: string;\n scope?: string;\n}\n\nexport interface MemorySearchOptions {\n query: string;\n tags?: string;\n scope?: string;\n limit?: number;\n}\n\nexport function memoryStoreCommand(options: MemoryStoreOptions): StoreKnowledgeResult {\n try {\n const input: StoreKnowledgeInput = {\n title: options.title,\n content: options.content,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n scope: options.scope,\n };\n\n return storeKnowledge(input);\n } finally {\n closeDatabase();\n }\n}\n\nexport function memorySearchCommand(options: MemorySearchOptions): SearchKnowledgeResult {\n try {\n const input: SearchKnowledgeInput = {\n query: options.query,\n contextTags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n scope: options.scope,\n limit: options.limit,\n };\n\n return searchKnowledge(input);\n } finally {\n closeDatabase();\n }\n}\n"],"names":["memorySearchCommand","memoryStoreCommand","searchKnowledge","storeKnowledge","options","input","title","content","tags","split","map","t","trim","undefined","scope","closeDatabase","query","contextTags","limit"],"mappings":";;;;;;;;;;;QAsCgBA;eAAAA;;QAfAC;eAAAA;;QAlBSC;eAAAA,uBAAe;;QAA/BC;eAAAA,qBAAc;;;uBALQ;wBACC;0BACF;AAqBvB,SAASF,mBAAmBG,OAA2B;IAC1D,IAAI;QACA,MAAMC,QAA6B;YAC/BC,OAAOF,QAAQE,KAAK;YACpBC,SAASH,QAAQG,OAAO;YACxBC,MAAMJ,QAAQI,IAAI,GAAGJ,QAAQI,IAAI,CAACC,KAAK,CAAC,KAAKC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI,MAAMC;YAClEC,OAAOV,QAAQU,KAAK;QACxB;QAEA,OAAOX,IAAAA,qBAAc,EAACE;IAC1B,SAAU;QACNU,IAAAA,uBAAa;IACjB;AACJ;AAEO,SAASf,oBAAoBI,OAA4B;IAC5D,IAAI;QACA,MAAMC,QAA8B;YAChCW,OAAOZ,QAAQY,KAAK;YACpBC,aAAab,QAAQI,IAAI,GAAGJ,QAAQI,IAAI,CAACC,KAAK,CAAC,KAAKC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI,MAAMC;YACzEC,OAAOV,QAAQU,KAAK;YACpBI,OAAOd,QAAQc,KAAK;QACxB;QAEA,OAAOhB,IAAAA,uBAAe,EAACG;IAC3B,SAAU;QACNU,IAAAA,uBAAa;IACjB;AACJ"}
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import { storeKnowledge } from './handlers/store';\nimport { searchKnowledge } from './handlers/search';\nimport { updateKnowledge } from './handlers/update';\nimport { closeDatabase } from './database';\nimport type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult, UpdateKnowledgeInput, UpdateKnowledgeResult } from './types';\n\nexport { storeKnowledge, searchKnowledge, updateKnowledge };\nexport type { StoreKnowledgeInput, SearchKnowledgeInput, StoreKnowledgeResult, SearchKnowledgeResult, UpdateKnowledgeInput, UpdateKnowledgeResult };\n\n// CLI command handlers for integration with main ai-devkit CLI\nexport interface MemoryStoreOptions {\n title: string;\n content: string;\n tags?: string;\n scope?: string;\n}\n\nexport interface MemoryUpdateOptions {\n id: string;\n title?: string;\n content?: string;\n tags?: string;\n scope?: string;\n}\n\nexport interface MemorySearchOptions {\n query: string;\n tags?: string;\n scope?: string;\n limit?: number;\n}\n\nexport function memoryStoreCommand(options: MemoryStoreOptions): StoreKnowledgeResult {\n try {\n const input: StoreKnowledgeInput = {\n title: options.title,\n content: options.content,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n scope: options.scope,\n };\n\n return storeKnowledge(input);\n } finally {\n closeDatabase();\n }\n}\n\nexport function memoryUpdateCommand(options: MemoryUpdateOptions): UpdateKnowledgeResult {\n try {\n const input: UpdateKnowledgeInput = {\n id: options.id,\n title: options.title,\n content: options.content,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n scope: options.scope,\n };\n\n return updateKnowledge(input);\n } finally {\n closeDatabase();\n }\n}\n\nexport function memorySearchCommand(options: MemorySearchOptions): SearchKnowledgeResult {\n try {\n const input: SearchKnowledgeInput = {\n query: options.query,\n contextTags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n scope: options.scope,\n limit: options.limit,\n };\n\n return searchKnowledge(input);\n } finally {\n closeDatabase();\n }\n}\n"],"names":["memorySearchCommand","memoryStoreCommand","memoryUpdateCommand","searchKnowledge","storeKnowledge","updateKnowledge","options","input","title","content","tags","split","map","t","trim","undefined","scope","closeDatabase","id","query","contextTags","limit"],"mappings":";;;;;;;;;;;QA+DgBA;eAAAA;;QA/BAC;eAAAA;;QAeAC;eAAAA;;QAzCSC;eAAAA,uBAAe;;QAA/BC;eAAAA,qBAAc;;QAAmBC;eAAAA,uBAAe;;;uBAN1B;wBACC;wBACA;0BACF;AA6BvB,SAASJ,mBAAmBK,OAA2B;IAC1D,IAAI;QACA,MAAMC,QAA6B;YAC/BC,OAAOF,QAAQE,KAAK;YACpBC,SAASH,QAAQG,OAAO;YACxBC,MAAMJ,QAAQI,IAAI,GAAGJ,QAAQI,IAAI,CAACC,KAAK,CAAC,KAAKC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI,MAAMC;YAClEC,OAAOV,QAAQU,KAAK;QACxB;QAEA,OAAOZ,IAAAA,qBAAc,EAACG;IAC1B,SAAU;QACNU,IAAAA,uBAAa;IACjB;AACJ;AAEO,SAASf,oBAAoBI,OAA4B;IAC5D,IAAI;QACA,MAAMC,QAA8B;YAChCW,IAAIZ,QAAQY,EAAE;YACdV,OAAOF,QAAQE,KAAK;YACpBC,SAASH,QAAQG,OAAO;YACxBC,MAAMJ,QAAQI,IAAI,GAAGJ,QAAQI,IAAI,CAACC,KAAK,CAAC,KAAKC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI,MAAMC;YAClEC,OAAOV,QAAQU,KAAK;QACxB;QAEA,OAAOX,IAAAA,uBAAe,EAACE;IAC3B,SAAU;QACNU,IAAAA,uBAAa;IACjB;AACJ;AAEO,SAASjB,oBAAoBM,OAA4B;IAC5D,IAAI;QACA,MAAMC,QAA8B;YAChCY,OAAOb,QAAQa,KAAK;YACpBC,aAAad,QAAQI,IAAI,GAAGJ,QAAQI,IAAI,CAACC,KAAK,CAAC,KAAKC,GAAG,CAACC,CAAAA,IAAKA,EAAEC,IAAI,MAAMC;YACzEC,OAAOV,QAAQU,KAAK;YACpBK,OAAOf,QAAQe,KAAK;QACxB;QAEA,OAAOlB,IAAAA,uBAAe,EAACI;IAC3B,SAAU;QACNU,IAAAA,uBAAa;IACjB;AACJ"}
@@ -0,0 +1,3 @@
1
+ import type { UpdateKnowledgeInput, UpdateKnowledgeResult } from '../types';
2
+ export declare function updateKnowledge(input: UpdateKnowledgeInput): UpdateKnowledgeResult;
3
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/handlers/update.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAgB,MAAM,UAAU,CAAC;AAE1F,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CAkFlF"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "updateKnowledge", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return updateKnowledge;
9
+ }
10
+ });
11
+ const _database = require("../database");
12
+ const _validator = require("../services/validator");
13
+ const _normalizer = require("../services/normalizer");
14
+ const _errors = require("../utils/errors");
15
+ function updateKnowledge(input) {
16
+ (0, _validator.validateUpdateInput)(input);
17
+ const db = (0, _database.getDatabase)();
18
+ const now = new Date().toISOString();
19
+ try {
20
+ return db.transaction(()=>{
21
+ const existing = db.queryOne('SELECT * FROM knowledge WHERE id = ?', [
22
+ input.id
23
+ ]);
24
+ if (!existing) {
25
+ throw new _errors.NotFoundError(`Knowledge item not found: ${input.id}`, input.id);
26
+ }
27
+ const title = input.title !== undefined ? input.title.trim() : existing.title;
28
+ const content = input.content !== undefined ? input.content.trim() : existing.content;
29
+ const tags = input.tags !== undefined ? (0, _normalizer.normalizeTags)(input.tags) : JSON.parse(existing.tags);
30
+ const scope = input.scope !== undefined ? (0, _normalizer.normalizeScope)(input.scope) : existing.scope;
31
+ const normalizedTitle = (0, _normalizer.normalizeTitle)(title);
32
+ const contentHash = (0, _normalizer.hashContent)(content);
33
+ const existingByTitle = db.queryOne('SELECT id FROM knowledge WHERE normalized_title = ? AND scope = ? AND id != ?', [
34
+ normalizedTitle,
35
+ scope,
36
+ input.id
37
+ ]);
38
+ if (existingByTitle) {
39
+ throw new _errors.DuplicateError('Knowledge with similar title already exists in this scope', existingByTitle.id, 'title');
40
+ }
41
+ const existingByHash = db.queryOne('SELECT id FROM knowledge WHERE content_hash = ? AND scope = ? AND id != ?', [
42
+ contentHash,
43
+ scope,
44
+ input.id
45
+ ]);
46
+ if (existingByHash) {
47
+ throw new _errors.DuplicateError('Knowledge with identical content already exists in this scope', existingByHash.id, 'content');
48
+ }
49
+ db.execute(`UPDATE knowledge SET
50
+ title = ?, content = ?, tags = ?, scope = ?,
51
+ normalized_title = ?, content_hash = ?, updated_at = ?
52
+ WHERE id = ?`, [
53
+ title,
54
+ content,
55
+ JSON.stringify(tags),
56
+ scope,
57
+ normalizedTitle,
58
+ contentHash,
59
+ now,
60
+ input.id
61
+ ]);
62
+ return {
63
+ success: true,
64
+ id: input.id,
65
+ message: 'Knowledge updated successfully'
66
+ };
67
+ });
68
+ } catch (error) {
69
+ if (error instanceof _errors.DuplicateError || error instanceof _errors.NotFoundError) {
70
+ throw error;
71
+ }
72
+ throw new _errors.StorageError('Failed to update knowledge', {
73
+ originalError: error instanceof Error ? error.message : String(error)
74
+ });
75
+ }
76
+ }
77
+
78
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/handlers/update.ts"],"sourcesContent":["import { getDatabase } from '../database';\nimport { validateUpdateInput } from '../services/validator';\nimport { normalizeTitle, normalizeScope, normalizeTags, hashContent } from '../services/normalizer';\nimport { DuplicateError, NotFoundError, StorageError } from '../utils/errors';\nimport type { UpdateKnowledgeInput, UpdateKnowledgeResult, KnowledgeRow } from '../types';\n\nexport function updateKnowledge(input: UpdateKnowledgeInput): UpdateKnowledgeResult {\n validateUpdateInput(input);\n\n const db = getDatabase();\n const now = new Date().toISOString();\n\n try {\n return db.transaction(() => {\n const existing = db.queryOne<KnowledgeRow>(\n 'SELECT * FROM knowledge WHERE id = ?',\n [input.id]\n );\n\n if (!existing) {\n throw new NotFoundError(`Knowledge item not found: ${input.id}`, input.id);\n }\n\n const title = input.title !== undefined ? input.title.trim() : existing.title;\n const content = input.content !== undefined ? input.content.trim() : existing.content;\n const tags = input.tags !== undefined ? normalizeTags(input.tags) : JSON.parse(existing.tags);\n const scope = input.scope !== undefined ? normalizeScope(input.scope) : existing.scope;\n const normalizedTitle = normalizeTitle(title);\n const contentHash = hashContent(content);\n\n const existingByTitle = db.queryOne<KnowledgeRow>(\n 'SELECT id FROM knowledge WHERE normalized_title = ? AND scope = ? AND id != ?',\n [normalizedTitle, scope, input.id]\n );\n\n if (existingByTitle) {\n throw new DuplicateError(\n 'Knowledge with similar title already exists in this scope',\n existingByTitle.id,\n 'title'\n );\n }\n\n const existingByHash = db.queryOne<KnowledgeRow>(\n 'SELECT id FROM knowledge WHERE content_hash = ? AND scope = ? AND id != ?',\n [contentHash, scope, input.id]\n );\n\n if (existingByHash) {\n throw new DuplicateError(\n 'Knowledge with identical content already exists in this scope',\n existingByHash.id,\n 'content'\n );\n }\n\n db.execute(\n `UPDATE knowledge SET\n title = ?, content = ?, tags = ?, scope = ?,\n normalized_title = ?, content_hash = ?, updated_at = ?\n WHERE id = ?`,\n [\n title,\n content,\n JSON.stringify(tags),\n scope,\n normalizedTitle,\n contentHash,\n now,\n input.id\n ]\n );\n\n return {\n success: true,\n id: input.id,\n message: 'Knowledge updated successfully'\n };\n });\n } catch (error) {\n if (error instanceof DuplicateError || error instanceof NotFoundError) {\n throw error;\n }\n throw new StorageError(\n 'Failed to update knowledge',\n { originalError: error instanceof Error ? error.message : String(error) }\n );\n }\n}\n"],"names":["updateKnowledge","input","validateUpdateInput","db","getDatabase","now","Date","toISOString","transaction","existing","queryOne","id","NotFoundError","title","undefined","trim","content","tags","normalizeTags","JSON","parse","scope","normalizeScope","normalizedTitle","normalizeTitle","contentHash","hashContent","existingByTitle","DuplicateError","existingByHash","execute","stringify","success","message","error","StorageError","originalError","Error","String"],"mappings":";;;;+BAMgBA;;;eAAAA;;;0BANY;2BACQ;4BACuC;wBACf;AAGrD,SAASA,gBAAgBC,KAA2B;IACvDC,IAAAA,8BAAmB,EAACD;IAEpB,MAAME,KAAKC,IAAAA,qBAAW;IACtB,MAAMC,MAAM,IAAIC,OAAOC,WAAW;IAElC,IAAI;QACA,OAAOJ,GAAGK,WAAW,CAAC;YAClB,MAAMC,WAAWN,GAAGO,QAAQ,CACxB,wCACA;gBAACT,MAAMU,EAAE;aAAC;YAGd,IAAI,CAACF,UAAU;gBACX,MAAM,IAAIG,qBAAa,CAAC,CAAC,0BAA0B,EAAEX,MAAMU,EAAE,EAAE,EAAEV,MAAMU,EAAE;YAC7E;YAEA,MAAME,QAAQZ,MAAMY,KAAK,KAAKC,YAAYb,MAAMY,KAAK,CAACE,IAAI,KAAKN,SAASI,KAAK;YAC7E,MAAMG,UAAUf,MAAMe,OAAO,KAAKF,YAAYb,MAAMe,OAAO,CAACD,IAAI,KAAKN,SAASO,OAAO;YACrF,MAAMC,OAAOhB,MAAMgB,IAAI,KAAKH,YAAYI,IAAAA,yBAAa,EAACjB,MAAMgB,IAAI,IAAIE,KAAKC,KAAK,CAACX,SAASQ,IAAI;YAC5F,MAAMI,QAAQpB,MAAMoB,KAAK,KAAKP,YAAYQ,IAAAA,0BAAc,EAACrB,MAAMoB,KAAK,IAAIZ,SAASY,KAAK;YACtF,MAAME,kBAAkBC,IAAAA,0BAAc,EAACX;YACvC,MAAMY,cAAcC,IAAAA,uBAAW,EAACV;YAEhC,MAAMW,kBAAkBxB,GAAGO,QAAQ,CAC/B,iFACA;gBAACa;gBAAiBF;gBAAOpB,MAAMU,EAAE;aAAC;YAGtC,IAAIgB,iBAAiB;gBACjB,MAAM,IAAIC,sBAAc,CACpB,6DACAD,gBAAgBhB,EAAE,EAClB;YAER;YAEA,MAAMkB,iBAAiB1B,GAAGO,QAAQ,CAC9B,6EACA;gBAACe;gBAAaJ;gBAAOpB,MAAMU,EAAE;aAAC;YAGlC,IAAIkB,gBAAgB;gBAChB,MAAM,IAAID,sBAAc,CACpB,iEACAC,eAAelB,EAAE,EACjB;YAER;YAEAR,GAAG2B,OAAO,CACN,CAAC;;;4BAGW,CAAC,EACb;gBACIjB;gBACAG;gBACAG,KAAKY,SAAS,CAACd;gBACfI;gBACAE;gBACAE;gBACApB;gBACAJ,MAAMU,EAAE;aACX;YAGL,OAAO;gBACHqB,SAAS;gBACTrB,IAAIV,MAAMU,EAAE;gBACZsB,SAAS;YACb;QACJ;IACJ,EAAE,OAAOC,OAAO;QACZ,IAAIA,iBAAiBN,sBAAc,IAAIM,iBAAiBtB,qBAAa,EAAE;YACnE,MAAMsB;QACV;QACA,MAAM,IAAIC,oBAAY,CAClB,8BACA;YAAEC,eAAeF,iBAAiBG,QAAQH,MAAMD,OAAO,GAAGK,OAAOJ;QAAO;IAEhF;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAsEnE,wBAAgB,YAAY,IAAI,MAAM,CA8ErC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAI/C"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAuGnE,wBAAgB,YAAY,IAAI,MAAM,CA2FrC;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAI/C"}
package/dist/server.js CHANGED
@@ -21,6 +21,7 @@ const _stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
21
21
  const _types = require("@modelcontextprotocol/sdk/types.js");
22
22
  const _store = require("./handlers/store");
23
23
  const _search = require("./handlers/search");
24
+ const _update = require("./handlers/update");
24
25
  const _errors = require("./utils/errors");
25
26
  const SERVER_NAME = 'ai-devkit-memory';
26
27
  const SERVER_VERSION = '0.1.0';
@@ -56,6 +57,41 @@ const STORE_TOOL = {
56
57
  ]
57
58
  }
58
59
  };
60
+ const UPDATE_TOOL = {
61
+ name: 'memory.updateKnowledge',
62
+ description: 'Update an existing knowledge item by ID. Use this to correct outdated or inaccurate knowledge.',
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ id: {
67
+ type: 'string',
68
+ description: 'UUID of the knowledge item to update'
69
+ },
70
+ title: {
71
+ type: 'string',
72
+ description: 'New title (10-100 chars). Only provide if changing.'
73
+ },
74
+ content: {
75
+ type: 'string',
76
+ description: 'New content in markdown format (50-5000 chars). Only provide if changing.'
77
+ },
78
+ tags: {
79
+ type: 'array',
80
+ items: {
81
+ type: 'string'
82
+ },
83
+ description: 'New tags (replaces existing). Only provide if changing. Max 10 tags.'
84
+ },
85
+ scope: {
86
+ type: 'string',
87
+ description: 'New scope: "global", "project:<name>", or "repo:<name>". Only provide if changing.'
88
+ }
89
+ },
90
+ required: [
91
+ 'id'
92
+ ]
93
+ }
94
+ };
59
95
  const SEARCH_TOOL = {
60
96
  name: 'memory.searchKnowledge',
61
97
  description: 'Search for relevant knowledge based on a task description. Returns ranked results.',
@@ -101,6 +137,7 @@ function createServer() {
101
137
  return {
102
138
  tools: [
103
139
  STORE_TOOL,
140
+ UPDATE_TOOL,
104
141
  SEARCH_TOOL
105
142
  ]
106
143
  };
@@ -121,6 +158,18 @@ function createServer() {
121
158
  ]
122
159
  };
123
160
  }
161
+ if (name === 'memory.updateKnowledge') {
162
+ const input = args;
163
+ const result = (0, _update.updateKnowledge)(input);
164
+ return {
165
+ content: [
166
+ {
167
+ type: 'text',
168
+ text: JSON.stringify(result, null, 2)
169
+ }
170
+ ]
171
+ };
172
+ }
124
173
  if (name === 'memory.searchKnowledge') {
125
174
  const input = args;
126
175
  const result = (0, _search.searchKnowledge)(input);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { storeKnowledge } from './handlers/store';\nimport { searchKnowledge } from './handlers/search';\nimport { KnowledgeMemoryError } from './utils/errors';\nimport type { StoreKnowledgeInput, SearchKnowledgeInput } from './types';\n\nconst SERVER_NAME = 'ai-devkit-memory';\nconst SERVER_VERSION = '0.1.0';\n\nconst STORE_TOOL = {\n name: 'memory.storeKnowledge',\n description: 'Store a new knowledge item. Use this to save actionable guidelines, rules, or patterns for future reference.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n title: {\n type: 'string',\n description: 'Short, explicit description of the rule (5-12 words, 10-100 chars)',\n },\n content: {\n type: 'string',\n description: 'Detailed explanation in markdown format. Supports code blocks and examples. (50-5000 chars)',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional domain keywords (e.g., [\"api\", \"backend\"]). Max 10 tags.',\n },\n scope: {\n type: 'string',\n description: 'Optional scope: \"global\", \"project:<name>\", or \"repo:<name>\". Default: \"global\"',\n },\n },\n required: ['title', 'content'],\n },\n};\n\nconst SEARCH_TOOL = {\n name: 'memory.searchKnowledge',\n description: 'Search for relevant knowledge based on a task description. Returns ranked results.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n query: {\n type: 'string',\n description: 'Natural language task description to search for relevant knowledge (3-500 chars)',\n },\n contextTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional tags to boost matching results (e.g., [\"api\", \"backend\"])',\n },\n scope: {\n type: 'string',\n description: 'Optional project/repo scope filter. Results from this scope are prioritized.',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (1-20, default: 5)',\n },\n },\n required: ['query'],\n },\n};\n\nexport function createServer(): Server {\n const server = new Server(\n {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // List available tools\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [STORE_TOOL, SEARCH_TOOL],\n };\n });\n\n // Handle tool calls\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n if (name === 'memory.storeKnowledge') {\n const input = args as unknown as StoreKnowledgeInput;\n const result = storeKnowledge(input);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'memory.searchKnowledge') {\n const input = args as unknown as SearchKnowledgeInput;\n const result = searchKnowledge(input);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: 'UNKNOWN_TOOL', message: `Unknown tool: ${name}` }),\n },\n ],\n isError: true,\n };\n } catch (error) {\n const errorResponse = error instanceof KnowledgeMemoryError\n ? error.toJSON()\n : { error: 'INTERNAL_ERROR', message: error instanceof Error ? error.message : String(error) };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(errorResponse, null, 2),\n },\n ],\n isError: true,\n };\n }\n });\n\n return server;\n}\n\nexport async function runServer(): Promise<void> {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n"],"names":["createServer","runServer","SERVER_NAME","SERVER_VERSION","STORE_TOOL","name","description","inputSchema","type","properties","title","content","tags","items","scope","required","SEARCH_TOOL","query","contextTags","limit","server","Server","version","capabilities","tools","setRequestHandler","ListToolsRequestSchema","CallToolRequestSchema","request","arguments","args","params","input","result","storeKnowledge","text","JSON","stringify","searchKnowledge","error","message","isError","errorResponse","KnowledgeMemoryError","toJSON","Error","String","transport","StdioServerTransport","connect"],"mappings":";;;;;;;;;;;QAsEgBA;eAAAA;;QAgFMC;eAAAA;;;uBAtJC;uBACc;uBAI9B;uBACwB;wBACC;wBACK;AAGrC,MAAMC,cAAc;AACpB,MAAMC,iBAAiB;AAEvB,MAAMC,aAAa;IACfC,MAAM;IACNC,aAAa;IACbC,aAAa;QACTC,MAAM;QACNC,YAAY;YACRC,OAAO;gBACHF,MAAM;gBACNF,aAAa;YACjB;YACAK,SAAS;gBACLH,MAAM;gBACNF,aAAa;YACjB;YACAM,MAAM;gBACFJ,MAAM;gBACNK,OAAO;oBAAEL,MAAM;gBAAS;gBACxBF,aAAa;YACjB;YACAQ,OAAO;gBACHN,MAAM;gBACNF,aAAa;YACjB;QACJ;QACAS,UAAU;YAAC;YAAS;SAAU;IAClC;AACJ;AAEA,MAAMC,cAAc;IAChBX,MAAM;IACNC,aAAa;IACbC,aAAa;QACTC,MAAM;QACNC,YAAY;YACRQ,OAAO;gBACHT,MAAM;gBACNF,aAAa;YACjB;YACAY,aAAa;gBACTV,MAAM;gBACNK,OAAO;oBAAEL,MAAM;gBAAS;gBACxBF,aAAa;YACjB;YACAQ,OAAO;gBACHN,MAAM;gBACNF,aAAa;YACjB;YACAa,OAAO;gBACHX,MAAM;gBACNF,aAAa;YACjB;QACJ;QACAS,UAAU;YAAC;SAAQ;IACvB;AACJ;AAEO,SAASf;IACZ,MAAMoB,SAAS,IAAIC,aAAM,CACrB;QACIhB,MAAMH;QACNoB,SAASnB;IACb,GACA;QACIoB,cAAc;YACVC,OAAO,CAAC;QACZ;IACJ;IAGJ,uBAAuB;IACvBJ,OAAOK,iBAAiB,CAACC,6BAAsB,EAAE;QAC7C,OAAO;YACHF,OAAO;gBAACpB;gBAAYY;aAAY;QACpC;IACJ;IAEA,oBAAoB;IACpBI,OAAOK,iBAAiB,CAACE,4BAAqB,EAAE,OAAOC;QACnD,MAAM,EAAEvB,IAAI,EAAEwB,WAAWC,IAAI,EAAE,GAAGF,QAAQG,MAAM;QAEhD,IAAI;YACA,IAAI1B,SAAS,yBAAyB;gBAClC,MAAM2B,QAAQF;gBACd,MAAMG,SAASC,IAAAA,qBAAc,EAACF;gBAC9B,OAAO;oBACHrB,SAAS;wBACL;4BACIH,MAAM;4BACN2B,MAAMC,KAAKC,SAAS,CAACJ,QAAQ,MAAM;wBACvC;qBACH;gBACL;YACJ;YAEA,IAAI5B,SAAS,0BAA0B;gBACnC,MAAM2B,QAAQF;gBACd,MAAMG,SAASK,IAAAA,uBAAe,EAACN;gBAC/B,OAAO;oBACHrB,SAAS;wBACL;4BACIH,MAAM;4BACN2B,MAAMC,KAAKC,SAAS,CAACJ,QAAQ,MAAM;wBACvC;qBACH;gBACL;YACJ;YAEA,OAAO;gBACHtB,SAAS;oBACL;wBACIH,MAAM;wBACN2B,MAAMC,KAAKC,SAAS,CAAC;4BAAEE,OAAO;4BAAgBC,SAAS,CAAC,cAAc,EAAEnC,MAAM;wBAAC;oBACnF;iBACH;gBACDoC,SAAS;YACb;QACJ,EAAE,OAAOF,OAAO;YACZ,MAAMG,gBAAgBH,iBAAiBI,4BAAoB,GACrDJ,MAAMK,MAAM,KACZ;gBAAEL,OAAO;gBAAkBC,SAASD,iBAAiBM,QAAQN,MAAMC,OAAO,GAAGM,OAAOP;YAAO;YAEjG,OAAO;gBACH5B,SAAS;oBACL;wBACIH,MAAM;wBACN2B,MAAMC,KAAKC,SAAS,CAACK,eAAe,MAAM;oBAC9C;iBACH;gBACDD,SAAS;YACb;QACJ;IACJ;IAEA,OAAOrB;AACX;AAEO,eAAenB;IAClB,MAAMmB,SAASpB;IACf,MAAM+C,YAAY,IAAIC,2BAAoB;IAC1C,MAAM5B,OAAO6B,OAAO,CAACF;AACzB"}
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { storeKnowledge } from './handlers/store';\nimport { searchKnowledge } from './handlers/search';\nimport { updateKnowledge } from './handlers/update';\nimport { KnowledgeMemoryError } from './utils/errors';\nimport type { StoreKnowledgeInput, SearchKnowledgeInput, UpdateKnowledgeInput } from './types';\n\nconst SERVER_NAME = 'ai-devkit-memory';\nconst SERVER_VERSION = '0.1.0';\n\nconst STORE_TOOL = {\n name: 'memory.storeKnowledge',\n description: 'Store a new knowledge item. Use this to save actionable guidelines, rules, or patterns for future reference.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n title: {\n type: 'string',\n description: 'Short, explicit description of the rule (5-12 words, 10-100 chars)',\n },\n content: {\n type: 'string',\n description: 'Detailed explanation in markdown format. Supports code blocks and examples. (50-5000 chars)',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional domain keywords (e.g., [\"api\", \"backend\"]). Max 10 tags.',\n },\n scope: {\n type: 'string',\n description: 'Optional scope: \"global\", \"project:<name>\", or \"repo:<name>\". Default: \"global\"',\n },\n },\n required: ['title', 'content'],\n },\n};\n\nconst UPDATE_TOOL = {\n name: 'memory.updateKnowledge',\n description: 'Update an existing knowledge item by ID. Use this to correct outdated or inaccurate knowledge.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n id: {\n type: 'string',\n description: 'UUID of the knowledge item to update',\n },\n title: {\n type: 'string',\n description: 'New title (10-100 chars). Only provide if changing.',\n },\n content: {\n type: 'string',\n description: 'New content in markdown format (50-5000 chars). Only provide if changing.',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'New tags (replaces existing). Only provide if changing. Max 10 tags.',\n },\n scope: {\n type: 'string',\n description: 'New scope: \"global\", \"project:<name>\", or \"repo:<name>\". Only provide if changing.',\n },\n },\n required: ['id'],\n },\n};\n\nconst SEARCH_TOOL = {\n name: 'memory.searchKnowledge',\n description: 'Search for relevant knowledge based on a task description. Returns ranked results.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n query: {\n type: 'string',\n description: 'Natural language task description to search for relevant knowledge (3-500 chars)',\n },\n contextTags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional tags to boost matching results (e.g., [\"api\", \"backend\"])',\n },\n scope: {\n type: 'string',\n description: 'Optional project/repo scope filter. Results from this scope are prioritized.',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (1-20, default: 5)',\n },\n },\n required: ['query'],\n },\n};\n\nexport function createServer(): Server {\n const server = new Server(\n {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // List available tools\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [STORE_TOOL, UPDATE_TOOL, SEARCH_TOOL],\n };\n });\n\n // Handle tool calls\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n if (name === 'memory.storeKnowledge') {\n const input = args as unknown as StoreKnowledgeInput;\n const result = storeKnowledge(input);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'memory.updateKnowledge') {\n const input = args as unknown as UpdateKnowledgeInput;\n const result = updateKnowledge(input);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n if (name === 'memory.searchKnowledge') {\n const input = args as unknown as SearchKnowledgeInput;\n const result = searchKnowledge(input);\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify({ error: 'UNKNOWN_TOOL', message: `Unknown tool: ${name}` }),\n },\n ],\n isError: true,\n };\n } catch (error) {\n const errorResponse = error instanceof KnowledgeMemoryError\n ? error.toJSON()\n : { error: 'INTERNAL_ERROR', message: error instanceof Error ? error.message : String(error) };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(errorResponse, null, 2),\n },\n ],\n isError: true,\n };\n }\n });\n\n return server;\n}\n\nexport async function runServer(): Promise<void> {\n const server = createServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n"],"names":["createServer","runServer","SERVER_NAME","SERVER_VERSION","STORE_TOOL","name","description","inputSchema","type","properties","title","content","tags","items","scope","required","UPDATE_TOOL","id","SEARCH_TOOL","query","contextTags","limit","server","Server","version","capabilities","tools","setRequestHandler","ListToolsRequestSchema","CallToolRequestSchema","request","arguments","args","params","input","result","storeKnowledge","text","JSON","stringify","updateKnowledge","searchKnowledge","error","message","isError","errorResponse","KnowledgeMemoryError","toJSON","Error","String","transport","StdioServerTransport","connect"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { StoreKnowledgeInput } from '../types';
1
+ import type { StoreKnowledgeInput, UpdateKnowledgeInput } from '../types';
2
2
  export interface ValidationResult {
3
3
  valid: boolean;
4
4
  errors: string[];
@@ -7,5 +7,6 @@ export declare function validateTitle(title: string): ValidationResult;
7
7
  export declare function validateContent(content: string): ValidationResult;
8
8
  export declare function validateTags(tags?: string[]): ValidationResult;
9
9
  export declare function validateScope(scope?: string): ValidationResult;
10
+ export declare function validateUpdateInput(input: UpdateKnowledgeInput): void;
10
11
  export declare function validateStoreInput(input: StoreKnowledgeInput): void;
11
12
  //# sourceMappingURL=validator.d.ts.map
@@ -1 +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"}
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"}
@@ -23,6 +23,9 @@ _export(exports, {
23
23
  },
24
24
  get validateTitle () {
25
25
  return validateTitle;
26
+ },
27
+ get validateUpdateInput () {
28
+ return validateUpdateInput;
26
29
  }
27
30
  });
28
31
  const _errors = require("../utils/errors");
@@ -124,6 +127,37 @@ function validateScope(scope) {
124
127
  errors
125
128
  };
126
129
  }
130
+ function validateUpdateInput(input) {
131
+ const allErrors = [];
132
+ if (!input.id || input.id.trim().length === 0) {
133
+ allErrors.push('ID is required');
134
+ }
135
+ const hasUpdateField = input.title !== undefined || input.content !== undefined || input.tags !== undefined || input.scope !== undefined;
136
+ if (!hasUpdateField) {
137
+ allErrors.push('At least one field to update is required (title, content, tags, or scope)');
138
+ }
139
+ if (input.title !== undefined) {
140
+ const titleResult = validateTitle(input.title);
141
+ allErrors.push(...titleResult.errors);
142
+ }
143
+ if (input.content !== undefined) {
144
+ const contentResult = validateContent(input.content);
145
+ allErrors.push(...contentResult.errors);
146
+ }
147
+ if (input.tags !== undefined) {
148
+ const tagsResult = validateTags(input.tags);
149
+ allErrors.push(...tagsResult.errors);
150
+ }
151
+ if (input.scope !== undefined) {
152
+ const scopeResult = validateScope(input.scope);
153
+ allErrors.push(...scopeResult.errors);
154
+ }
155
+ if (allErrors.length > 0) {
156
+ throw new _errors.ValidationError(allErrors.join('; '), {
157
+ errors: allErrors
158
+ });
159
+ }
160
+ }
127
161
  function validateStoreInput(input) {
128
162
  const allErrors = [];
129
163
  const titleResult = validateTitle(input.title);
@@ -1 +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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"}
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":";;;;;;;;;;;QA8CgBA;eAAAA;;QA+CAC;eAAAA;;QAqDAC;eAAAA;;QAzEAC;eAAAA;;QA7CAC;eAAAA;;QA+EAC;eAAAA;;;wBA3GgB;AAGhC,MAAMC,mBAAmB;AACzB,MAAMC,mBAAmB;AACzB,MAAMC,qBAAqB;AAC3B,MAAMC,qBAAqB;AAC3B,MAAMC,iBAAiB;AAEvB,MAAMC,gBAAgB;AACtB,MAAMC,cAAc;AAEpB,MAAMC,kBAAkB;IACpB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACH;AAOM,SAAST,cAAcU,KAAa;IACvC,MAAMC,SAAmB,EAAE;IAE3B,IAAI,CAACD,SAASA,MAAME,IAAI,GAAGC,MAAM,KAAK,GAAG;QACrCF,OAAOG,IAAI,CAAC;IAChB,OAAO;QACH,MAAMC,UAAUL,MAAME,IAAI;QAC1B,IAAIG,QAAQF,MAAM,GAAGX,kBAAkB;YACnCS,OAAOG,IAAI,CAAC,CAAC,uBAAuB,EAAEZ,iBAAiB,WAAW,CAAC;QACvE;QACA,IAAIa,QAAQF,MAAM,GAAGV,kBAAkB;YACnCQ,OAAOG,IAAI,CAAC,CAAC,sBAAsB,EAAEX,iBAAiB,WAAW,CAAC;QACtE;IACJ;IAEA,OAAO;QAAEa,OAAOL,OAAOE,MAAM,KAAK;QAAGF;IAAO;AAChD;AAEO,SAASf,gBAAgBqB,OAAe;IAC3C,MAAMN,SAAmB,EAAE;IAE3B,IAAI,CAACM,WAAWA,QAAQL,IAAI,GAAGC,MAAM,KAAK,GAAG;QACzCF,OAAOG,IAAI,CAAC;IAChB,OAAO;QACH,MAAMC,UAAUE,QAAQL,IAAI;QAC5B,IAAIG,QAAQF,MAAM,GAAGT,oBAAoB;YACrCO,OAAOG,IAAI,CAAC,CAAC,yBAAyB,EAAEV,mBAAmB,WAAW,CAAC;QAC3E;QACA,IAAIW,QAAQF,MAAM,GAAGR,oBAAoB;YACrCM,OAAOG,IAAI,CAAC,CAAC,wBAAwB,EAAET,mBAAmB,WAAW,CAAC;QAC1E;QAEA,wCAAwC;QACxC,MAAMa,eAAeH,QAAQI,WAAW;QACxC,KAAK,MAAMC,UAAUX,gBAAiB;YAClC,IAAIS,iBAAiBE,UAAUF,aAAaG,UAAU,CAACD,SAAS,MAAM;gBAClET,OAAOG,IAAI,CAAC;gBACZ;YACJ;QACJ;IACJ;IAEA,OAAO;QAAEE,OAAOL,OAAOE,MAAM,KAAK;QAAGF;IAAO;AAChD;AAEO,SAASZ,aAAauB,IAAe;IACxC,MAAMX,SAAmB,EAAE;IAE3B,IAAI,CAACW,QAAQA,KAAKT,MAAM,KAAK,GAAG;QAC5B,OAAO;YAAEG,OAAO;YAAML,QAAQ,EAAE;QAAC;IACrC;IAEA,IAAIW,KAAKT,MAAM,GAAGP,gBAAgB;QAC9BK,OAAOG,IAAI,CAAC,CAAC,QAAQ,EAAER,eAAe,aAAa,CAAC;IACxD;IAEA,KAAK,MAAMiB,OAAOD,KAAM;QACpB,IAAI,CAACd,YAAYgB,IAAI,CAACD,MAAM;YACxBZ,OAAOG,IAAI,CAAC,CAAC,aAAa,EAAES,IAAI,0CAA0C,CAAC;QAC/E;IACJ;IAEA,OAAO;QAAEP,OAAOL,OAAOE,MAAM,KAAK;QAAGF;IAAO;AAChD;AAEO,SAASd,cAAc4B,KAAc;IACxC,MAAMd,SAAmB,EAAE;IAE3B,IAAI,CAACc,SAASA,UAAU,UAAU;QAC9B,OAAO;YAAET,OAAO;YAAML,QAAQ,EAAE;QAAC;IACrC;IAEA,IAAI,CAACJ,cAAciB,IAAI,CAACC,QAAQ;QAC5Bd,OAAOG,IAAI,CAAC;IAChB;IAEA,OAAO;QAAEE,OAAOL,OAAOE,MAAM,KAAK;QAAGF;IAAO;AAChD;AAEO,SAASV,oBAAoByB,KAA2B;IAC3D,MAAMC,YAAsB,EAAE;IAE9B,IAAI,CAACD,MAAME,EAAE,IAAIF,MAAME,EAAE,CAAChB,IAAI,GAAGC,MAAM,KAAK,GAAG;QAC3Cc,UAAUb,IAAI,CAAC;IACnB;IAEA,MAAMe,iBAAiBH,MAAMhB,KAAK,KAAKoB,aAAaJ,MAAMT,OAAO,KAAKa,aAClEJ,MAAMJ,IAAI,KAAKQ,aAAaJ,MAAMD,KAAK,KAAKK;IAEhD,IAAI,CAACD,gBAAgB;QACjBF,UAAUb,IAAI,CAAC;IACnB;IAEA,IAAIY,MAAMhB,KAAK,KAAKoB,WAAW;QAC3B,MAAMC,cAAc/B,cAAc0B,MAAMhB,KAAK;QAC7CiB,UAAUb,IAAI,IAAIiB,YAAYpB,MAAM;IACxC;IAEA,IAAIe,MAAMT,OAAO,KAAKa,WAAW;QAC7B,MAAME,gBAAgBpC,gBAAgB8B,MAAMT,OAAO;QACnDU,UAAUb,IAAI,IAAIkB,cAAcrB,MAAM;IAC1C;IAEA,IAAIe,MAAMJ,IAAI,KAAKQ,WAAW;QAC1B,MAAMG,aAAalC,aAAa2B,MAAMJ,IAAI;QAC1CK,UAAUb,IAAI,IAAImB,WAAWtB,MAAM;IACvC;IAEA,IAAIe,MAAMD,KAAK,KAAKK,WAAW;QAC3B,MAAMI,cAAcrC,cAAc6B,MAAMD,KAAK;QAC7CE,UAAUb,IAAI,IAAIoB,YAAYvB,MAAM;IACxC;IAEA,IAAIgB,UAAUd,MAAM,GAAG,GAAG;QACtB,MAAM,IAAIsB,uBAAe,CAACR,UAAUS,IAAI,CAAC,OAAO;YAAEzB,QAAQgB;QAAU;IACxE;AACJ;AAEO,SAAS7B,mBAAmB4B,KAA0B;IACzD,MAAMC,YAAsB,EAAE;IAE9B,MAAMI,cAAc/B,cAAc0B,MAAMhB,KAAK;IAC7CiB,UAAUb,IAAI,IAAIiB,YAAYpB,MAAM;IAEpC,MAAMqB,gBAAgBpC,gBAAgB8B,MAAMT,OAAO;IACnDU,UAAUb,IAAI,IAAIkB,cAAcrB,MAAM;IAEtC,MAAMsB,aAAalC,aAAa2B,MAAMJ,IAAI;IAC1CK,UAAUb,IAAI,IAAImB,WAAWtB,MAAM;IAEnC,MAAMuB,cAAcrC,cAAc6B,MAAMD,KAAK;IAC7CE,UAAUb,IAAI,IAAIoB,YAAYvB,MAAM;IAEpC,IAAIgB,UAAUd,MAAM,GAAG,GAAG;QACtB,MAAM,IAAIsB,uBAAe,CAACR,UAAUS,IAAI,CAAC,OAAO;YAAEzB,QAAQgB;QAAU;IACxE;AACJ"}
@@ -21,6 +21,18 @@ export interface StoreKnowledgeResult {
21
21
  id?: string;
22
22
  message: string;
23
23
  }
24
+ export interface UpdateKnowledgeInput {
25
+ id: string;
26
+ title?: string;
27
+ content?: string;
28
+ tags?: string[];
29
+ scope?: string;
30
+ }
31
+ export interface UpdateKnowledgeResult {
32
+ success: boolean;
33
+ id: string;
34
+ message: string;
35
+ }
24
36
  export interface SearchKnowledgeInput {
25
37
  query: string;
26
38
  contextTags?: string[];
@@ -1 +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"}
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,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-devkit/memory",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Lightweight MCP-based memory service for AI agents - store and retrieve actionable knowledge",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",