Initial commit: Cortex — AI project memory & knowledge graph
SQLite-backed knowledge graph with CLI interface. Supports nodes (memory, component, task, decision) connected by typed edges, with hybrid search (BM25 + Ollama embeddings).
This commit is contained in:
72
src/core/db.ts
Normal file
72
src/core/db.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
const SCHEMA = `
|
||||
CREATE TABLE IF NOT EXISTS nodes (
|
||||
id TEXT PRIMARY KEY,
|
||||
kind TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
status TEXT,
|
||||
tags TEXT DEFAULT '[]',
|
||||
metadata TEXT DEFAULT '{}',
|
||||
embedding BLOB,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
is_stale INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS edges (
|
||||
id TEXT PRIMARY KEY,
|
||||
from_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
to_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
type TEXT NOT NULL,
|
||||
metadata TEXT DEFAULT '{}',
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS node_tags (
|
||||
node_id TEXT NOT NULL REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
tag TEXT NOT NULL,
|
||||
PRIMARY KEY (node_id, tag)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_kind ON nodes(kind);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_status ON nodes(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_created ON nodes(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_stale ON nodes(is_stale);
|
||||
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_tags_tag ON node_tags(tag);
|
||||
`;
|
||||
|
||||
let _db: Database.Database | null = null;
|
||||
|
||||
export function getMemoryDir(): string {
|
||||
return path.join(process.cwd(), '.memory');
|
||||
}
|
||||
|
||||
export function getDb(): Database.Database {
|
||||
if (_db) return _db;
|
||||
|
||||
const dir = getMemoryDir();
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
_db = new Database(path.join(dir, 'cortex.db'));
|
||||
_db.pragma('journal_mode = WAL');
|
||||
_db.pragma('foreign_keys = ON');
|
||||
_db.exec(SCHEMA);
|
||||
|
||||
return _db;
|
||||
}
|
||||
|
||||
export function closeDb(): void {
|
||||
if (_db) {
|
||||
_db.close();
|
||||
_db = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user