UNPKG

scai

Version:

> **A local-first AI CLI for understanding, querying, and iterating on large codebases.** > **100% local • No token costs • No cloud • No prompt injection • Private by design**

255 lines (214 loc) 7.63 kB
import { getDbForRepo } from "./client.js"; export function initSchema() { const db = getDbForRepo(); // --- Global state --- db.exec(` CREATE TABLE IF NOT EXISTS global_state ( id INTEGER PRIMARY KEY CHECK (id = 1), -- user / system preferences default_execution_mode TEXT, -- explain | analyze | transform preferred_language TEXT, -- "en", "da", etc. -- learned conventions (lightweight) conventions_json TEXT, -- JSON: naming, formatting, habits memory_notes TEXT, -- freeform distilled memory -- bookkeeping created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); `); // --- Projects --- db.exec(` CREATE TABLE IF NOT EXISTS projects ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- binding (technical, not conceptual) repo_path TEXT NOT NULL, -- absolute path to repo root -- human-facing name TEXT NOT NULL, -- project name summary TEXT, -- evolving description -- distilled understanding goals_json TEXT, constraints_json TEXT, assumptions_json TEXT, -- bookkeeping created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_projects_repo ON projects(repo_path); `); // --- Tasks (controlled input only) --- db.exec(` CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, -- lifecycle -- active | completed | paused | needs-feedback status TEXT NOT NULL DEFAULT 'active', -- user-facing / context initial_query TEXT NOT NULL, summary TEXT, -- resolved intent agreed_intent TEXT, intent_category TEXT, normalized_query TEXT, intent_confidence REAL, -- focus / file selection relevant_files_json TEXT, missing_files_json TEXT, -- routing decision routing_decision_json TEXT, -- 🔴 task-level feedback / questions (append-only) task_questions_json TEXT, -- bookkeeping created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id); CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); `); // --- Task steps --- db.exec(` CREATE TABLE IF NOT EXISTS task_steps ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_id INTEGER NOT NULL, file_path TEXT NOT NULL, action TEXT, -- pending | completed | skipped | needs-feedback status TEXT NOT NULL DEFAULT 'pending', start_time INTEGER, end_time INTEGER, result_json TEXT, notes TEXT, step_index INTEGER, -- 🔴 step-level feedback / questions (append-only) step_questions_json TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_task_steps_task ON task_steps(task_id); CREATE INDEX IF NOT EXISTS idx_task_steps_status ON task_steps(status); CREATE UNIQUE INDEX IF NOT EXISTS idx_task_steps_task_file ON task_steps(task_id, file_path); `); // --- Core tables --- db.exec(` CREATE TABLE IF NOT EXISTS files ( id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT UNIQUE, -- full path filename TEXT, summary TEXT, -- optional, can be generated later content_text TEXT, -- actual file content type TEXT, -- file type last_modified TEXT, -- file system last modified indexed_at TEXT, -- timestamp when indexed functions_extracted_at TEXT, -- timestamp when functions/classes extracted processing_status TEXT NOT NULL DEFAULT 'unprocessed' -- tracks pipeline stage ); CREATE VIRTUAL TABLE IF NOT EXISTS files_fts USING fts5( filename, summary, path, content_text, content='files', content_rowid='id' ); `); // --- Folder capsules --- db.exec(` CREATE TABLE IF NOT EXISTS folder_capsules( id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT UNIQUE NOT NULL, depth INTEGER NOT NULL, capsule_json TEXT NOT NULL, confidence REAL, last_generated TEXT, source_file_count INTEGER ); CREATE INDEX IF NOT EXISTS idx_folder_capsules_path ON folder_capsules(path); CREATE INDEX IF NOT EXISTS idx_folder_capsules_depth ON folder_capsules(depth); `); // --- Functions table --- db.exec(` CREATE TABLE IF NOT EXISTS functions( id INTEGER PRIMARY KEY AUTOINCREMENT, file_id INTEGER REFERENCES files(id), name TEXT, unique_id TEXT UNIQUE, --e.g. "buildContextualPrompt@cli/src/utils/buildContextualPrompt.ts" start_line INTEGER, end_line INTEGER, content TEXT, lang TEXT ); CREATE INDEX IF NOT EXISTS idx_functions_file_id ON functions(file_id); CREATE INDEX IF NOT EXISTS idx_functions_unique_id ON functions(unique_id); `); // --- Graph-specific additions --- db.exec(` CREATE TABLE IF NOT EXISTS graph_classes( id INTEGER PRIMARY KEY AUTOINCREMENT, file_id INTEGER REFERENCES files(id), name TEXT, unique_id TEXT UNIQUE, start_line INTEGER, end_line INTEGER, content TEXT, lang TEXT ); CREATE INDEX IF NOT EXISTS idx_graph_classes_file_id ON graph_classes(file_id); CREATE INDEX IF NOT EXISTS idx_graph_classes_unique_id ON graph_classes(unique_id); `); db.exec(` CREATE TABLE IF NOT EXISTS graph_edges( id INTEGER PRIMARY KEY AUTOINCREMENT, source_type TEXT NOT NULL, source_unique_id TEXT NOT NULL, target_type TEXT NOT NULL, target_unique_id TEXT NOT NULL, relation TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_graph_edges_source ON graph_edges(source_type, source_unique_id); CREATE INDEX IF NOT EXISTS idx_graph_edges_target ON graph_edges(target_type, target_unique_id); CREATE INDEX IF NOT EXISTS idx_graph_edges_relation ON graph_edges(relation); `); db.exec(` CREATE TABLE IF NOT EXISTS graph_tags_master( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL ); CREATE TABLE IF NOT EXISTS graph_entity_tags( id INTEGER PRIMARY KEY AUTOINCREMENT, entity_type TEXT NOT NULL, entity_unique_id TEXT NOT NULL, tag_id INTEGER NOT NULL REFERENCES graph_tags_master(id), UNIQUE(entity_type, entity_unique_id, tag_id) ); CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_entity ON graph_entity_tags(entity_type, entity_unique_id); CREATE INDEX IF NOT EXISTS idx_graph_entity_tags_tag ON graph_entity_tags(tag_id); `); db.exec(` CREATE TABLE IF NOT EXISTS summaries( id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT UNIQUE, type TEXT NOT NULL CHECK(type IN('folder', 'project')), summary TEXT, last_generated TEXT, child_latest_modified TEXT ); CREATE INDEX IF NOT EXISTS idx_summaries_type ON summaries(type); CREATE INDEX IF NOT EXISTS idx_summaries_path ON summaries(path); `); console.log("✅ Graph schema initialized (files, functions, classes, edges, tags, summaries, FTS content_text)"); }