@ai-devkit/memory 0.3.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 +16 -72
- package/dist/api.d.ts +12 -3
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +44 -14
- package/dist/api.js.map +1 -1
- package/dist/handlers/update.d.ts +3 -0
- package/dist/handlers/update.d.ts.map +1 -0
- package/dist/handlers/update.js +78 -0
- package/dist/handlers/update.js.map +1 -0
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +49 -0
- package/dist/server.js.map +1 -1
- package/dist/services/validator.d.ts +2 -1
- package/dist/services/validator.d.ts.map +1 -1
- package/dist/services/validator.js +34 -0
- package/dist/services/validator.js.map +1 -1
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
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
|
|
3
|
+
A lightweight MCP-based memory service for AI agents. Store and retrieve knowledge using SQLite with full-text search.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@ai-devkit/memory)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
7
|
|
|
5
8
|
## Features
|
|
6
9
|
|
|
7
|
-
- 🔍 **Full-Text Search**
|
|
8
|
-
- 🏷️ **Tag-Based Filtering**
|
|
9
|
-
- 📁 **Scoped Knowledge**
|
|
10
|
-
- 🔄 **Deduplication**
|
|
11
|
-
- ⚡ **Fast**
|
|
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
|
-
|
|
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
|
-
###
|
|
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.
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4
|
-
|
|
5
|
-
export
|
|
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;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;
|
|
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,32 +15,62 @@ _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");
|
|
34
|
+
const _database = require("./database");
|
|
27
35
|
function memoryStoreCommand(options) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
try {
|
|
37
|
+
const input = {
|
|
38
|
+
title: options.title,
|
|
39
|
+
content: options.content,
|
|
40
|
+
tags: options.tags ? options.tags.split(',').map((t)=>t.trim()) : undefined,
|
|
41
|
+
scope: options.scope
|
|
42
|
+
};
|
|
43
|
+
return (0, _store.storeKnowledge)(input);
|
|
44
|
+
} finally{
|
|
45
|
+
(0, _database.closeDatabase)();
|
|
46
|
+
}
|
|
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
|
+
}
|
|
35
61
|
}
|
|
36
62
|
function memorySearchCommand(options) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
try {
|
|
64
|
+
const input = {
|
|
65
|
+
query: options.query,
|
|
66
|
+
contextTags: options.tags ? options.tags.split(',').map((t)=>t.trim()) : undefined,
|
|
67
|
+
scope: options.scope,
|
|
68
|
+
limit: options.limit
|
|
69
|
+
};
|
|
70
|
+
return (0, _search.searchKnowledge)(input);
|
|
71
|
+
} finally{
|
|
72
|
+
(0, _database.closeDatabase)();
|
|
73
|
+
}
|
|
44
74
|
}
|
|
45
75
|
|
|
46
76
|
//# sourceMappingURL=api.js.map
|
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 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 const input: StoreKnowledgeInput = {\n
|
|
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 @@
|
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -18,9 +18,13 @@ function _export_star(from, to) {
|
|
|
18
18
|
});
|
|
19
19
|
return from;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Only start MCP server when this file is run directly as a binary
|
|
22
|
+
// Not when imported as a library (e.g., by CLI commands)
|
|
23
|
+
if (require.main === module) {
|
|
24
|
+
(0, _server.runServer)().catch((error)=>{
|
|
25
|
+
console.error('Failed to start server:', error);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
25
29
|
|
|
26
30
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { runServer } from './server';\n\nexport * from './api';\n\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { runServer } from './server';\n\nexport * from './api';\n\n// Only start MCP server when this file is run directly as a binary\n// Not when imported as a library (e.g., by CLI commands)\nif (require.main === module) {\n runServer().catch((error: Error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n });\n}\n"],"names":["require","main","module","runServer","catch","error","console","process","exit"],"mappings":";;;;;wBAE0B;qBAEZ;;;;;;;;;;;;;;AAEd,mEAAmE;AACnE,yDAAyD;AACzD,IAAIA,QAAQC,IAAI,KAAKC,QAAQ;IACzBC,IAAAA,iBAAS,IAAGC,KAAK,CAAC,CAACC;QACfC,QAAQD,KAAK,CAAC,2BAA2BA;QACzCE,QAAQC,IAAI,CAAC;IACjB;AACJ"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;
|
|
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);
|
package/dist/server.js.map
CHANGED
|
@@ -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;
|
|
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":";;;;;;;;;;;QA8CgBA;eAAAA;;QA+CAC;eAAAA;;
|
|
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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"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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