@stackmemoryai/stackmemory
Version:
Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a
116 lines (115 loc) • 3.05 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
class DatabaseAdapter {
projectId;
config;
constructor(projectId, config) {
this.projectId = projectId;
this.config = config || {};
}
// Paginated table reads (for migration)
async getTablePage(table, offset, limit) {
void table;
void offset;
void limit;
return [];
}
/** Returns the configured embedding provider, if any */
getEmbeddingProvider() {
return void 0;
}
// Maintenance state (no-op defaults, overridden in SQLiteAdapter)
async getMaintenanceState(_key) {
return null;
}
async setMaintenanceState(_key, _value) {
}
// Garbage collection (no-op default, overridden in SQLiteAdapter)
async runGC(_options) {
return {
framesDeleted: 0,
eventsDeleted: 0,
anchorsDeleted: 0,
embeddingsDeleted: 0,
ftsEntriesDeleted: 0
};
}
// Retrieval logging (no-op defaults, overridden in SQLiteAdapter)
async logRetrieval(_entry) {
}
async getRetrievalStats(_sinceDays) {
return {
totalQueries: 0,
avgLatencyMs: 0,
p95LatencyMs: 0,
strategyDistribution: {},
avgResultsCount: 0,
queriesWithNoResults: 0
};
}
// Project registry (no-op defaults, overridden in SQLiteAdapter)
async registerProject(_project) {
}
async getRegisteredProjects() {
return [];
}
async setActiveProject(_projectId) {
}
async getActiveProject() {
return null;
}
async removeProject(_projectId) {
return false;
}
async touchProject(_projectId) {
}
// Utility methods
generateId() {
return crypto.randomUUID();
}
sanitizeQuery(query) {
console.warn(
"sanitizeQuery() is deprecated and unsafe - use parameterized queries"
);
return query.replace(/[;'"\\]/g, "");
}
buildWhereClause(conditions) {
const clauses = Object.entries(conditions).map(([key, value]) => {
if (value === null) {
return `${key} IS NULL`;
} else if (Array.isArray(value)) {
return `${key} IN (${value.map(() => "?").join(",")})`;
} else {
return `${key} = ?`;
}
});
return clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
}
buildOrderByClause(orderBy, direction) {
if (!orderBy) return "";
const isSafe = /^[a-zA-Z0-9_.]+$/.test(orderBy);
if (!isSafe) {
return "";
}
const dir = direction === "DESC" ? "DESC" : "ASC";
return ` ORDER BY ${orderBy} ${dir}`;
}
buildLimitClause(limit, offset) {
if (!limit) return "";
let clause = ` LIMIT ${limit}`;
if (offset) clause += ` OFFSET ${offset}`;
return clause;
}
}
class FeatureAwareDatabaseAdapter extends DatabaseAdapter {
async canUseFeature(feature) {
const features = this.getFeatures();
return features[feature] || false;
}
}
export {
DatabaseAdapter,
FeatureAwareDatabaseAdapter
};