Skip to content

Commit 8161407

Browse files
committed
refactor: unify memory system across all components
- Migrate MCP server to use LibSQLMemoryStorage (SQLite-based) - Remove obsolete MemoryStorage (JSON-based) implementation - Delete all unused TUI component variants - Clean up unused imports and dependencies - Ensure all components use the same memory database Now CLI, TUI, and MCP all share the same SQLite memory storage.
1 parent d6edf74 commit 8161407

File tree

9 files changed

+1090
-1890
lines changed

9 files changed

+1090
-1890
lines changed

dist/chunk-VBFBG4QV.js

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// src/utils/libsql-storage.ts
2+
import { createClient } from "@libsql/client";
3+
import * as fs from "fs";
4+
import * as path from "path";
5+
var LibSQLMemoryStorage = class {
6+
client;
7+
dbPath;
8+
constructor() {
9+
const memoryDir = path.join(process.cwd(), ".sylphx-flow");
10+
if (!fs.existsSync(memoryDir)) {
11+
fs.mkdirSync(memoryDir, { recursive: true });
12+
}
13+
this.dbPath = path.join(memoryDir, "memory.db");
14+
this.client = createClient({
15+
url: `file:${this.dbPath}`
16+
});
17+
this.initializeTables();
18+
}
19+
async initializeTables() {
20+
const createTableSQL = `
21+
CREATE TABLE IF NOT EXISTS memory (
22+
key TEXT NOT NULL,
23+
namespace TEXT NOT NULL DEFAULT 'default',
24+
value TEXT NOT NULL,
25+
timestamp INTEGER NOT NULL,
26+
created_at TEXT NOT NULL,
27+
updated_at TEXT NOT NULL,
28+
PRIMARY KEY (key, namespace)
29+
)
30+
`;
31+
await this.client.execute(createTableSQL);
32+
await this.client.execute(`
33+
CREATE INDEX IF NOT EXISTS idx_memory_namespace ON memory(namespace);
34+
`);
35+
await this.client.execute(`
36+
CREATE INDEX IF NOT EXISTS idx_memory_timestamp ON memory(timestamp);
37+
`);
38+
await this.client.execute(`
39+
CREATE INDEX IF NOT EXISTS idx_memory_key ON memory(key);
40+
`);
41+
}
42+
serializeValue(value) {
43+
return JSON.stringify(value);
44+
}
45+
deserializeValue(value) {
46+
try {
47+
return JSON.parse(value);
48+
} catch {
49+
return value;
50+
}
51+
}
52+
async set(key, value, namespace = "default") {
53+
const now = /* @__PURE__ */ new Date();
54+
const timestamp = now.getTime();
55+
const created_at = now.toISOString();
56+
const updated_at = created_at;
57+
const serializedValue = this.serializeValue(value);
58+
const existing = await this.get(key, namespace);
59+
if (existing) {
60+
const updateSQL = `
61+
UPDATE memory
62+
SET value = ?, timestamp = ?, updated_at = ?
63+
WHERE key = ? AND namespace = ?
64+
`;
65+
await this.client.execute({
66+
sql: updateSQL,
67+
args: [serializedValue, timestamp, updated_at, key, namespace]
68+
});
69+
} else {
70+
const insertSQL = `
71+
INSERT INTO memory (key, namespace, value, timestamp, created_at, updated_at)
72+
VALUES (?, ?, ?, ?, ?, ?)
73+
`;
74+
await this.client.execute({
75+
sql: insertSQL,
76+
args: [key, namespace, serializedValue, timestamp, created_at, updated_at]
77+
});
78+
}
79+
}
80+
async get(key, namespace = "default") {
81+
const selectSQL = `
82+
SELECT key, namespace, value, timestamp, created_at, updated_at
83+
FROM memory
84+
WHERE key = ? AND namespace = ?
85+
`;
86+
const result = await this.client.execute({
87+
sql: selectSQL,
88+
args: [key, namespace]
89+
});
90+
if (result.rows.length === 0) {
91+
return null;
92+
}
93+
const row = result.rows[0];
94+
return {
95+
key: row.key,
96+
namespace: row.namespace,
97+
value: this.deserializeValue(row.value),
98+
timestamp: row.timestamp,
99+
created_at: row.created_at,
100+
updated_at: row.updated_at
101+
};
102+
}
103+
async getAll() {
104+
const selectSQL = `
105+
SELECT key, namespace, value, timestamp, created_at, updated_at
106+
FROM memory
107+
ORDER BY timestamp DESC
108+
`;
109+
const result = await this.client.execute(selectSQL);
110+
return result.rows.map((row) => ({
111+
key: row.key,
112+
namespace: row.namespace,
113+
value: this.deserializeValue(row.value),
114+
timestamp: row.timestamp,
115+
created_at: row.created_at,
116+
updated_at: row.updated_at
117+
}));
118+
}
119+
async search(pattern, namespace) {
120+
const searchPattern = pattern.replace(/\*/g, "%");
121+
let selectSQL = `
122+
SELECT key, namespace, value, timestamp, created_at, updated_at
123+
FROM memory
124+
WHERE key LIKE ? OR value LIKE ?
125+
`;
126+
const args = [searchPattern, searchPattern];
127+
if (namespace && namespace !== "all") {
128+
selectSQL += " AND namespace = ?";
129+
args.push(namespace);
130+
}
131+
selectSQL += " ORDER BY timestamp DESC";
132+
const result = await this.client.execute({
133+
sql: selectSQL,
134+
args
135+
});
136+
return result.rows.map((row) => ({
137+
key: row.key,
138+
namespace: row.namespace,
139+
value: this.deserializeValue(row.value),
140+
timestamp: row.timestamp,
141+
created_at: row.created_at,
142+
updated_at: row.updated_at
143+
}));
144+
}
145+
async delete(key, namespace = "default") {
146+
const deleteSQL = `
147+
DELETE FROM memory
148+
WHERE key = ? AND namespace = ?
149+
`;
150+
const result = await this.client.execute({
151+
sql: deleteSQL,
152+
args: [key, namespace]
153+
});
154+
return result.rowsAffected > 0;
155+
}
156+
async clear(namespace) {
157+
if (namespace && namespace !== "all") {
158+
const deleteSQL = "DELETE FROM memory WHERE namespace = ?";
159+
await this.client.execute({
160+
sql: deleteSQL,
161+
args: [namespace]
162+
});
163+
} else {
164+
const deleteSQL = "DELETE FROM memory";
165+
await this.client.execute(deleteSQL);
166+
}
167+
}
168+
async getStats() {
169+
const countResult = await this.client.execute("SELECT COUNT(*) as count FROM memory");
170+
const totalEntries = countResult.rows[0].count;
171+
const namespaceResult = await this.client.execute(`
172+
SELECT namespace, COUNT(*) as count
173+
FROM memory
174+
GROUP BY namespace
175+
ORDER BY namespace
176+
`);
177+
const namespaces = namespaceResult.rows.map((row) => row.namespace);
178+
const namespaceCounts = {};
179+
namespaceResult.rows.forEach((row) => {
180+
namespaceCounts[row.namespace] = row.count;
181+
});
182+
const timeResult = await this.client.execute(`
183+
SELECT
184+
MIN(created_at) as oldest,
185+
MAX(created_at) as newest
186+
FROM memory
187+
`);
188+
const timeRow = timeResult.rows[0];
189+
const oldestEntry = timeRow.oldest;
190+
const newestEntry = timeRow.newest;
191+
return {
192+
totalEntries,
193+
namespaces,
194+
namespaceCounts,
195+
oldestEntry,
196+
newestEntry
197+
};
198+
}
199+
// Load method for compatibility with existing code
200+
async load() {
201+
const entries = await this.getAll();
202+
const namespaces = {};
203+
entries.forEach((entry) => {
204+
if (!namespaces[entry.namespace]) {
205+
namespaces[entry.namespace] = {};
206+
}
207+
namespaces[entry.namespace][entry.key] = entry.value;
208+
});
209+
return { namespaces };
210+
}
211+
// Close database connection
212+
async close() {
213+
}
214+
// Get database path for debugging
215+
getDatabasePath() {
216+
return this.dbPath;
217+
}
218+
};
219+
220+
export {
221+
LibSQLMemoryStorage
222+
};

0 commit comments

Comments
 (0)