@notbnull/mcp-cursor-taskmaster
Version:
A project-scoped MCP server requiring explicit --project-dir configuration for task management, memory retrieval, and agentic workflows
138 lines (137 loc) • 4.68 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryStore = void 0;
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
const path_1 = __importDefault(require("path"));
const promises_1 = __importDefault(require("fs/promises"));
const crypto_1 = __importDefault(require("crypto"));
class MemoryStore {
db;
dataDir;
constructor(projectDir) {
// Use the provided project directory directly - it's validated upstream
this.dataDir = path_1.default.join(path_1.default.resolve(projectDir), ".taskmaster");
}
async initialize() {
try {
// Ensure data directory exists
console.error(`MemoryStore: Creating directory ${this.dataDir}`);
await promises_1.default.mkdir(this.dataDir, { recursive: true });
// Initialize SQLite database
const dbPath = path_1.default.join(this.dataDir, "memories.db");
this.db = new better_sqlite3_1.default(dbPath);
// Create tables if they don't exist
this.db.exec(`
CREATE TABLE IF NOT EXISTS memories (
id TEXT PRIMARY KEY,
key TEXT UNIQUE NOT NULL,
content TEXT NOT NULL,
metadata TEXT,
timestamp TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_memories_key ON memories(key);
CREATE INDEX IF NOT EXISTS idx_memories_timestamp ON memories(timestamp);
`);
console.error(`MemoryStore: Successfully initialized in ${this.dataDir}`);
}
catch (error) {
console.error(`MemoryStore: Failed to initialize in ${this.dataDir}:`, error);
throw new Error(`Failed to initialize MemoryStore: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
async set(key, content, metadata) {
const id = crypto_1.default.randomUUID();
const timestamp = new Date().toISOString();
const stmt = this.db.prepare(`
INSERT OR REPLACE INTO memories (id, key, content, metadata, timestamp)
VALUES (?, ?, ?, ?, ?)
`);
stmt.run(id, key, content, metadata ? JSON.stringify(metadata) : null, timestamp);
return {
id,
key,
content,
metadata,
timestamp,
};
}
async get(key) {
const stmt = this.db.prepare(`
SELECT * FROM memories WHERE key = ?
`);
const row = stmt.get(key);
if (!row)
return null;
return {
id: row.id,
key: row.key,
content: row.content,
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
timestamp: row.timestamp,
};
}
async getById(id) {
const stmt = this.db.prepare(`
SELECT * FROM memories WHERE id = ?
`);
const row = stmt.get(id);
if (!row)
return null;
return {
id: row.id,
key: row.key,
content: row.content,
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
timestamp: row.timestamp,
};
}
async delete(key) {
const stmt = this.db.prepare(`
DELETE FROM memories WHERE key = ?
`);
const result = stmt.run(key);
return result.changes > 0;
}
async list(limit = 100, offset = 0) {
const stmt = this.db.prepare(`
SELECT * FROM memories
ORDER BY timestamp DESC
LIMIT ? OFFSET ?
`);
const rows = stmt.all(limit, offset);
return rows.map((row) => ({
id: row.id,
key: row.key,
content: row.content,
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
timestamp: row.timestamp,
}));
}
async search(query) {
const stmt = this.db.prepare(`
SELECT * FROM memories
WHERE content LIKE ? OR key LIKE ?
ORDER BY timestamp DESC
LIMIT 20
`);
const searchPattern = `%${query}%`;
const rows = stmt.all(searchPattern, searchPattern);
return rows.map((row) => ({
id: row.id,
key: row.key,
content: row.content,
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
timestamp: row.timestamp,
}));
}
close() {
if (this.db) {
this.db.close();
}
}
}
exports.MemoryStore = MemoryStore;
//# sourceMappingURL=memory-store.js.map