openclaw-mem 1.0.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/HOOK.md +125 -0
  2. package/LICENSE +1 -1
  3. package/MCP.json +11 -0
  4. package/README.md +158 -167
  5. package/backfill-embeddings.js +79 -0
  6. package/context-builder.js +703 -0
  7. package/database.js +625 -0
  8. package/debug-logger.js +280 -0
  9. package/extractor.js +268 -0
  10. package/gateway-llm.js +250 -0
  11. package/handler.js +941 -0
  12. package/mcp-http-api.js +424 -0
  13. package/mcp-server.js +605 -0
  14. package/mem-get.sh +24 -0
  15. package/mem-search.sh +17 -0
  16. package/monitor.js +112 -0
  17. package/package.json +58 -30
  18. package/realtime-monitor.js +371 -0
  19. package/session-watcher.js +192 -0
  20. package/setup.js +114 -0
  21. package/sync-recent.js +63 -0
  22. package/README_CN.md +0 -201
  23. package/bin/openclaw-mem.js +0 -117
  24. package/docs/locales/README_AR.md +0 -35
  25. package/docs/locales/README_DE.md +0 -35
  26. package/docs/locales/README_ES.md +0 -35
  27. package/docs/locales/README_FR.md +0 -35
  28. package/docs/locales/README_HE.md +0 -35
  29. package/docs/locales/README_HI.md +0 -35
  30. package/docs/locales/README_ID.md +0 -35
  31. package/docs/locales/README_IT.md +0 -35
  32. package/docs/locales/README_JA.md +0 -57
  33. package/docs/locales/README_KO.md +0 -35
  34. package/docs/locales/README_NL.md +0 -35
  35. package/docs/locales/README_PL.md +0 -35
  36. package/docs/locales/README_PT.md +0 -35
  37. package/docs/locales/README_RU.md +0 -35
  38. package/docs/locales/README_TH.md +0 -35
  39. package/docs/locales/README_TR.md +0 -35
  40. package/docs/locales/README_UK.md +0 -35
  41. package/docs/locales/README_VI.md +0 -35
  42. package/docs/logo.svg +0 -32
  43. package/lib/context-builder.js +0 -415
  44. package/lib/database.js +0 -309
  45. package/lib/handler.js +0 -494
  46. package/scripts/commands.js +0 -141
  47. package/scripts/init.js +0 -248
package/lib/database.js DELETED
@@ -1,309 +0,0 @@
1
- /**
2
- * OpenClaw-Mem Database Module
3
- * SQLite-based storage for observations, sessions, and summaries
4
- */
5
-
6
- import fs from 'node:fs';
7
- import path from 'node:path';
8
- import os from 'node:os';
9
- import Database from 'better-sqlite3';
10
-
11
- const DATA_DIR = path.join(os.homedir(), '.openclaw-mem');
12
- const DB_PATH = path.join(DATA_DIR, 'memory.db');
13
-
14
- // Ensure data directory exists
15
- if (!fs.existsSync(DATA_DIR)) {
16
- fs.mkdirSync(DATA_DIR, { recursive: true });
17
- }
18
-
19
- // Initialize database
20
- const db = new Database(DB_PATH);
21
- db.pragma('journal_mode = WAL');
22
-
23
- // Create tables
24
- db.exec(`
25
- -- Sessions table
26
- CREATE TABLE IF NOT EXISTS sessions (
27
- id TEXT PRIMARY KEY,
28
- project_path TEXT,
29
- session_key TEXT,
30
- started_at TEXT DEFAULT (datetime('now')),
31
- ended_at TEXT,
32
- status TEXT DEFAULT 'active',
33
- source TEXT
34
- );
35
-
36
- -- Observations table (tool calls)
37
- CREATE TABLE IF NOT EXISTS observations (
38
- id INTEGER PRIMARY KEY AUTOINCREMENT,
39
- session_id TEXT,
40
- timestamp TEXT DEFAULT (datetime('now')),
41
- tool_name TEXT NOT NULL,
42
- tool_input TEXT,
43
- tool_response TEXT,
44
- summary TEXT,
45
- concepts TEXT,
46
- tokens_discovery INTEGER DEFAULT 0,
47
- tokens_read INTEGER DEFAULT 0,
48
- FOREIGN KEY (session_id) REFERENCES sessions(id)
49
- );
50
-
51
- -- Summaries table
52
- CREATE TABLE IF NOT EXISTS summaries (
53
- id INTEGER PRIMARY KEY AUTOINCREMENT,
54
- session_id TEXT,
55
- content TEXT,
56
- request TEXT,
57
- completed TEXT,
58
- next_steps TEXT,
59
- created_at TEXT DEFAULT (datetime('now')),
60
- FOREIGN KEY (session_id) REFERENCES sessions(id)
61
- );
62
-
63
- -- Full-text search index
64
- CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5(
65
- tool_name,
66
- summary,
67
- concepts,
68
- content='observations',
69
- content_rowid='id'
70
- );
71
-
72
- -- Triggers for FTS sync
73
- CREATE TRIGGER IF NOT EXISTS observations_ai AFTER INSERT ON observations BEGIN
74
- INSERT INTO observations_fts(rowid, tool_name, summary, concepts)
75
- VALUES (new.id, new.tool_name, new.summary, new.concepts);
76
- END;
77
-
78
- CREATE TRIGGER IF NOT EXISTS observations_ad AFTER DELETE ON observations BEGIN
79
- INSERT INTO observations_fts(observations_fts, rowid, tool_name, summary, concepts)
80
- VALUES ('delete', old.id, old.tool_name, old.summary, old.concepts);
81
- END;
82
-
83
- CREATE TRIGGER IF NOT EXISTS observations_au AFTER UPDATE ON observations BEGIN
84
- INSERT INTO observations_fts(observations_fts, rowid, tool_name, summary, concepts)
85
- VALUES ('delete', old.id, old.tool_name, old.summary, old.concepts);
86
- INSERT INTO observations_fts(rowid, tool_name, summary, concepts)
87
- VALUES (new.id, new.tool_name, new.summary, new.concepts);
88
- END;
89
-
90
- -- Indexes
91
- CREATE INDEX IF NOT EXISTS idx_observations_session ON observations(session_id);
92
- CREATE INDEX IF NOT EXISTS idx_observations_timestamp ON observations(timestamp DESC);
93
- CREATE INDEX IF NOT EXISTS idx_observations_tool ON observations(tool_name);
94
- CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_path);
95
- `);
96
-
97
- // Prepared statements
98
- const stmts = {
99
- // Sessions
100
- createSession: db.prepare(`
101
- INSERT INTO sessions (id, project_path, session_key, source)
102
- VALUES (?, ?, ?, ?)
103
- `),
104
-
105
- getSession: db.prepare(`
106
- SELECT * FROM sessions WHERE id = ?
107
- `),
108
-
109
- endSession: db.prepare(`
110
- UPDATE sessions SET ended_at = datetime('now'), status = 'completed'
111
- WHERE id = ?
112
- `),
113
-
114
- getActiveSession: db.prepare(`
115
- SELECT * FROM sessions WHERE session_key = ? AND status = 'active'
116
- ORDER BY started_at DESC LIMIT 1
117
- `),
118
-
119
- // Observations
120
- saveObservation: db.prepare(`
121
- INSERT INTO observations (session_id, tool_name, tool_input, tool_response, summary, concepts, tokens_discovery, tokens_read)
122
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
123
- `),
124
-
125
- getObservation: db.prepare(`
126
- SELECT * FROM observations WHERE id = ?
127
- `),
128
-
129
- getObservations: db.prepare(`
130
- SELECT * FROM observations WHERE id IN (SELECT value FROM json_each(?))
131
- `),
132
-
133
- updateObservationSummary: db.prepare(`
134
- UPDATE observations SET summary = ?, concepts = ?, tokens_read = ?
135
- WHERE id = ?
136
- `),
137
-
138
- getRecentObservations: db.prepare(`
139
- SELECT o.*, s.project_path
140
- FROM observations o
141
- JOIN sessions s ON o.session_id = s.id
142
- WHERE s.project_path = ?
143
- ORDER BY o.timestamp DESC
144
- LIMIT ?
145
- `),
146
-
147
- getRecentObservationsAll: db.prepare(`
148
- SELECT o.*, s.project_path
149
- FROM observations o
150
- JOIN sessions s ON o.session_id = s.id
151
- ORDER BY o.timestamp DESC
152
- LIMIT ?
153
- `),
154
-
155
- searchObservations: db.prepare(`
156
- SELECT o.*, s.project_path,
157
- highlight(observations_fts, 1, '<mark>', '</mark>') as summary_highlight
158
- FROM observations_fts fts
159
- JOIN observations o ON fts.rowid = o.id
160
- JOIN sessions s ON o.session_id = s.id
161
- WHERE observations_fts MATCH ?
162
- ORDER BY rank
163
- LIMIT ?
164
- `),
165
-
166
- // Summaries
167
- saveSummary: db.prepare(`
168
- INSERT INTO summaries (session_id, content, request, completed, next_steps)
169
- VALUES (?, ?, ?, ?, ?)
170
- `),
171
-
172
- getRecentSummaries: db.prepare(`
173
- SELECT su.*, s.project_path
174
- FROM summaries su
175
- JOIN sessions s ON su.session_id = s.id
176
- WHERE s.project_path = ?
177
- ORDER BY su.created_at DESC
178
- LIMIT ?
179
- `),
180
-
181
- // Stats
182
- getStats: db.prepare(`
183
- SELECT
184
- (SELECT COUNT(*) FROM sessions) as total_sessions,
185
- (SELECT COUNT(*) FROM observations) as total_observations,
186
- (SELECT COUNT(*) FROM summaries) as total_summaries,
187
- (SELECT SUM(tokens_discovery) FROM observations) as total_discovery_tokens,
188
- (SELECT SUM(tokens_read) FROM observations) as total_read_tokens
189
- `)
190
- };
191
-
192
- // Database API
193
- export const database = {
194
- // Session operations
195
- createSession(id, projectPath, sessionKey, source = 'unknown') {
196
- try {
197
- stmts.createSession.run(id, projectPath, sessionKey, source);
198
- return { success: true, id };
199
- } catch (err) {
200
- // Session might already exist
201
- return { success: false, error: err.message };
202
- }
203
- },
204
-
205
- getSession(id) {
206
- return stmts.getSession.get(id);
207
- },
208
-
209
- getActiveSession(sessionKey) {
210
- return stmts.getActiveSession.get(sessionKey);
211
- },
212
-
213
- endSession(id) {
214
- stmts.endSession.run(id);
215
- },
216
-
217
- // Observation operations
218
- saveObservation(sessionId, toolName, toolInput, toolResponse, options = {}) {
219
- const {
220
- summary = null,
221
- concepts = null,
222
- tokensDiscovery = 0,
223
- tokensRead = 0
224
- } = options;
225
-
226
- const result = stmts.saveObservation.run(
227
- sessionId,
228
- toolName,
229
- JSON.stringify(toolInput),
230
- JSON.stringify(toolResponse),
231
- summary,
232
- concepts,
233
- tokensDiscovery,
234
- tokensRead
235
- );
236
-
237
- return { success: true, id: result.lastInsertRowid };
238
- },
239
-
240
- getObservation(id) {
241
- const row = stmts.getObservation.get(id);
242
- if (row) {
243
- row.tool_input = JSON.parse(row.tool_input || '{}');
244
- row.tool_response = JSON.parse(row.tool_response || '{}');
245
- }
246
- return row;
247
- },
248
-
249
- getObservations(ids) {
250
- const rows = stmts.getObservations.all(JSON.stringify(ids));
251
- return rows.map(row => ({
252
- ...row,
253
- tool_input: JSON.parse(row.tool_input || '{}'),
254
- tool_response: JSON.parse(row.tool_response || '{}')
255
- }));
256
- },
257
-
258
- updateObservationSummary(id, summary, concepts, tokensRead) {
259
- stmts.updateObservationSummary.run(summary, concepts, tokensRead, id);
260
- },
261
-
262
- getRecentObservations(projectPath, limit = 50) {
263
- const rows = projectPath
264
- ? stmts.getRecentObservations.all(projectPath, limit)
265
- : stmts.getRecentObservationsAll.all(limit);
266
-
267
- return rows.map(row => ({
268
- ...row,
269
- tool_input: JSON.parse(row.tool_input || '{}'),
270
- tool_response: JSON.parse(row.tool_response || '{}')
271
- }));
272
- },
273
-
274
- searchObservations(query, limit = 20) {
275
- try {
276
- const rows = stmts.searchObservations.all(query, limit);
277
- return rows.map(row => ({
278
- ...row,
279
- tool_input: JSON.parse(row.tool_input || '{}'),
280
- tool_response: JSON.parse(row.tool_response || '{}')
281
- }));
282
- } catch (err) {
283
- console.error('[openclaw-mem] Search error:', err.message);
284
- return [];
285
- }
286
- },
287
-
288
- // Summary operations
289
- saveSummary(sessionId, content, request = null, completed = null, nextSteps = null) {
290
- const result = stmts.saveSummary.run(sessionId, content, request, completed, nextSteps);
291
- return { success: true, id: result.lastInsertRowid };
292
- },
293
-
294
- getRecentSummaries(projectPath, limit = 5) {
295
- return stmts.getRecentSummaries.all(projectPath, limit);
296
- },
297
-
298
- // Stats
299
- getStats() {
300
- return stmts.getStats.get();
301
- },
302
-
303
- // Close database
304
- close() {
305
- db.close();
306
- }
307
- };
308
-
309
- export default database;