UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

195 lines (194 loc) 6.13 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { logger } from "../core/monitoring/logger.js"; import Database from "better-sqlite3"; import { join } from "path"; import { existsSync } from "fs"; class ContextService { // Using singleton logger from monitoring db = null; tasks = /* @__PURE__ */ new Map(); constructor() { this.initializeDatabase(); } initializeDatabase() { try { const dbPath = join(process.cwd(), ".stackmemory", "context.db"); if (existsSync(dbPath)) { this.db = new Database(dbPath); this.loadTasksFromDatabase(); } } catch (error) { logger.warn( "Could not connect to database, using in-memory storage", error ); } } loadTasksFromDatabase() { if (!this.db) return; try { this.db.exec(` CREATE TABLE IF NOT EXISTS tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT, status TEXT DEFAULT 'todo', priority TEXT, tags TEXT, external_id TEXT, external_identifier TEXT, external_url TEXT, metadata TEXT, created_at INTEGER, updated_at INTEGER ) `); const stmt = this.db.prepare("SELECT * FROM tasks"); const rows = stmt.all(); for (const row of rows) { const task = { id: row.id, title: row.title, description: row.description || "", status: row.status || "todo", priority: row.priority || void 0, tags: row.tags ? JSON.parse(row.tags) : [], externalId: row.external_id || void 0, externalIdentifier: row.external_identifier || void 0, externalUrl: row.external_url || void 0, metadata: row.metadata ? JSON.parse(row.metadata) : void 0, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at) }; this.tasks.set(task.id, task); } logger.info(`Loaded ${rows.length} tasks from database`); } catch (error) { logger.error("Failed to load tasks from database", error); } } async getTask(id) { return this.tasks.get(id) || null; } async getTaskByExternalId(externalId) { for (const task of this.tasks.values()) { if (task.externalId === externalId) { return task; } } return null; } async getAllTasks() { return Array.from(this.tasks.values()); } async createTask(taskData) { const task = { id: this.generateId(), title: taskData.title || "Untitled Task", description: taskData.description || "", status: taskData.status || "todo", priority: taskData.priority, tags: taskData.tags || [], externalId: taskData.externalId, externalIdentifier: taskData.externalIdentifier, externalUrl: taskData.externalUrl, metadata: taskData.metadata, createdAt: taskData.createdAt || /* @__PURE__ */ new Date(), updatedAt: taskData.updatedAt || /* @__PURE__ */ new Date() }; this.tasks.set(task.id, task); if (this.db) { try { const stmt = this.db.prepare(` INSERT INTO tasks (id, title, description, status, priority, tags, external_id, external_identifier, external_url, metadata, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); stmt.run( task.id, task.title, task.description, task.status, task.priority || null, JSON.stringify(task.tags), task.externalId || null, task.externalIdentifier || null, task.externalUrl || null, task.metadata ? JSON.stringify(task.metadata) : null, task.createdAt.getTime(), task.updatedAt.getTime() ); } catch (error) { logger.error("Failed to persist task to database", error); } } logger.debug(`Created task: ${task.id} - ${task.title}`); return task; } async updateTask(id, updates) { const task = this.tasks.get(id); if (!task) { return null; } const updatedTask = { ...task, ...updates, updatedAt: /* @__PURE__ */ new Date() }; this.tasks.set(id, updatedTask); if (this.db) { try { const stmt = this.db.prepare(` UPDATE tasks SET title = ?, description = ?, status = ?, priority = ?, tags = ?, external_id = ?, external_identifier = ?, external_url = ?, metadata = ?, updated_at = ? WHERE id = ? `); stmt.run( updatedTask.title, updatedTask.description, updatedTask.status, updatedTask.priority || null, JSON.stringify(updatedTask.tags), updatedTask.externalId || null, updatedTask.externalIdentifier || null, updatedTask.externalUrl || null, updatedTask.metadata ? JSON.stringify(updatedTask.metadata) : null, updatedTask.updatedAt.getTime(), id ); } catch (error) { logger.error("Failed to update task in database", error); } } logger.debug(`Updated task: ${id} - ${updatedTask.title}`); return updatedTask; } async deleteTask(id) { const deleted = this.tasks.delete(id); if (deleted) { if (this.db) { try { const stmt = this.db.prepare("DELETE FROM tasks WHERE id = ?"); stmt.run(id); } catch (error) { logger.error("Failed to delete task from database", error); } } logger.debug(`Deleted task: ${id}`); } return deleted; } generateId() { return "task_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9); } } export { ContextService }; //# sourceMappingURL=context-service.js.map