memshell 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -6
- package/src/index.js +46 -31
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memshell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Persistent memory for AI agents. Like localStorage but for LLMs.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
8
|
-
"mem.sh": "./bin/mem.js"
|
|
7
|
+
"memshell": "./bin/mem.js"
|
|
9
8
|
},
|
|
10
9
|
"scripts": {
|
|
11
10
|
"start": "node server.js",
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
"memory",
|
|
18
17
|
"llm",
|
|
19
18
|
"semantic-search",
|
|
20
|
-
"
|
|
19
|
+
"tfidf",
|
|
21
20
|
"chatgpt",
|
|
22
21
|
"langchain",
|
|
23
22
|
"vector",
|
|
@@ -26,7 +25,6 @@
|
|
|
26
25
|
"author": "justedv",
|
|
27
26
|
"license": "MIT",
|
|
28
27
|
"dependencies": {
|
|
29
|
-
"better-sqlite3": "^11.0.0",
|
|
30
28
|
"express": "^4.18.2"
|
|
31
29
|
},
|
|
32
30
|
"repository": {
|
|
@@ -34,4 +32,4 @@
|
|
|
34
32
|
"url": "https://github.com/justedv/mem.sh"
|
|
35
33
|
},
|
|
36
34
|
"homepage": "https://justedv.github.io/mem.sh"
|
|
37
|
-
}
|
|
35
|
+
}
|
package/src/index.js
CHANGED
|
@@ -64,60 +64,75 @@ class TfIdf {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// ──
|
|
67
|
+
// ── JSON File Store ────────────────────────────────────────────
|
|
68
68
|
class LocalStore {
|
|
69
69
|
constructor(dir) {
|
|
70
70
|
this.dir = dir || path.join(os.homedir(), '.mem');
|
|
71
|
-
this.dbPath = path.join(this.dir, 'mem.
|
|
71
|
+
this.dbPath = path.join(this.dir, 'mem.json');
|
|
72
72
|
this.tfidf = new TfIdf();
|
|
73
|
-
this.
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
CREATE TABLE IF NOT EXISTS memories (
|
|
84
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
85
|
-
text TEXT NOT NULL,
|
|
86
|
-
agent TEXT DEFAULT 'default',
|
|
87
|
-
created_at TEXT DEFAULT (datetime('now')),
|
|
88
|
-
metadata TEXT DEFAULT '{}'
|
|
89
|
-
)
|
|
90
|
-
`);
|
|
73
|
+
this._data = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_load() {
|
|
77
|
+
if (this._data) return this._data;
|
|
78
|
+
fs.mkdirSync(this.dir, { recursive: true });
|
|
79
|
+
try {
|
|
80
|
+
this._data = JSON.parse(fs.readFileSync(this.dbPath, 'utf8'));
|
|
81
|
+
} catch {
|
|
82
|
+
this._data = { nextId: 1, memories: [] };
|
|
91
83
|
}
|
|
92
|
-
return this.
|
|
84
|
+
return this._data;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_save() {
|
|
88
|
+
fs.writeFileSync(this.dbPath, JSON.stringify(this._data, null, 2));
|
|
93
89
|
}
|
|
94
90
|
|
|
95
91
|
set(text, opts = {}) {
|
|
92
|
+
const data = this._load();
|
|
96
93
|
const agent = opts.agent || 'default';
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
const entry = {
|
|
95
|
+
id: data.nextId++,
|
|
96
|
+
text,
|
|
97
|
+
agent,
|
|
98
|
+
created_at: new Date().toISOString(),
|
|
99
|
+
metadata: opts.metadata || {}
|
|
100
|
+
};
|
|
101
|
+
data.memories.push(entry);
|
|
102
|
+
this._save();
|
|
103
|
+
return { id: entry.id, text, agent };
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
recall(query, opts = {}) {
|
|
107
|
+
const data = this._load();
|
|
103
108
|
const agent = opts.agent || 'default';
|
|
104
109
|
const limit = opts.limit || 10;
|
|
105
|
-
const rows =
|
|
110
|
+
const rows = data.memories.filter(m => m.agent === agent);
|
|
106
111
|
return this.tfidf.rank(query, rows).slice(0, limit);
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
list(opts = {}) {
|
|
115
|
+
const data = this._load();
|
|
110
116
|
const agent = opts.agent || 'default';
|
|
111
|
-
return
|
|
117
|
+
return data.memories.filter(m => m.agent === agent).sort((a, b) => b.id - a.id);
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
forget(id) {
|
|
115
|
-
|
|
121
|
+
const data = this._load();
|
|
122
|
+
const numId = Number(id);
|
|
123
|
+
const before = data.memories.length;
|
|
124
|
+
data.memories = data.memories.filter(m => m.id !== numId);
|
|
125
|
+
this._save();
|
|
126
|
+
return { changes: before - data.memories.length };
|
|
116
127
|
}
|
|
117
128
|
|
|
118
129
|
clear(opts = {}) {
|
|
130
|
+
const data = this._load();
|
|
119
131
|
const agent = opts.agent || 'default';
|
|
120
|
-
|
|
132
|
+
const before = data.memories.length;
|
|
133
|
+
data.memories = data.memories.filter(m => m.agent !== agent);
|
|
134
|
+
this._save();
|
|
135
|
+
return { changes: before - data.memories.length };
|
|
121
136
|
}
|
|
122
137
|
}
|
|
123
138
|
|
|
@@ -129,9 +144,9 @@ class ApiClient {
|
|
|
129
144
|
this.agent = opts.agent || 'default';
|
|
130
145
|
}
|
|
131
146
|
|
|
132
|
-
_req(method,
|
|
147
|
+
_req(method, urlPath, body) {
|
|
133
148
|
return new Promise((resolve, reject) => {
|
|
134
|
-
const url = new URL(this.base +
|
|
149
|
+
const url = new URL(this.base + urlPath);
|
|
135
150
|
const mod = url.protocol === 'https:' ? https : http;
|
|
136
151
|
const headers = { 'Content-Type': 'application/json' };
|
|
137
152
|
if (this.key) headers['X-Mem-Key'] = this.key;
|
|
@@ -153,7 +168,7 @@ class ApiClient {
|
|
|
153
168
|
recall(query, opts = {}) { return this._req('GET', `/mem/recall?q=${encodeURIComponent(query)}&limit=${opts.limit || 10}`); }
|
|
154
169
|
list() { return this._req('GET', '/mem/list'); }
|
|
155
170
|
forget(id) { return this._req('DELETE', `/mem/${id}`); }
|
|
156
|
-
clear() { return this._req('DELETE', '/mem'); }
|
|
171
|
+
clear() { return this._req('DELETE', '/mem?confirm=true'); }
|
|
157
172
|
}
|
|
158
173
|
|
|
159
174
|
// ── Exports ────────────────────────────────────────────────────
|