@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.
328 lines (327 loc) • 8.78 kB
JavaScript
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 "../monitoring/logger.js";
class LazyProxy {
_value;
_promise;
_loader;
_loaded = false;
constructor(loader) {
this._loader = loader;
}
async get() {
if (this._loaded && this._value !== void 0) {
return this._value;
}
if (!this._promise) {
this._promise = this._loader().then((value) => {
this._value = value;
this._loaded = true;
return value;
});
}
return this._promise;
}
isLoaded() {
return this._loaded;
}
peek() {
return this._value;
}
reset() {
this._value = void 0;
this._promise = void 0;
this._loaded = false;
}
}
class LazyContextLoader {
db;
projectId;
// Lazy loading registries
frameLoaders = /* @__PURE__ */ new Map();
anchorLoaders = /* @__PURE__ */ new Map();
eventLoaders = /* @__PURE__ */ new Map();
constructor(db, projectId) {
this.db = db;
this.projectId = projectId;
}
/**
* Create a lazy frame reference
*/
lazyFrame(frameId) {
if (!this.frameLoaders.has(frameId)) {
this.frameLoaders.set(
frameId,
new LazyProxy(async () => {
const frame = this.loadFrame(frameId);
if (!frame) {
throw new Error(`Frame not found: ${frameId}`);
}
return frame;
})
);
}
return this.frameLoaders.get(frameId);
}
/**
* Create lazy anchor references
*/
lazyAnchors(frameId) {
if (!this.anchorLoaders.has(frameId)) {
this.anchorLoaders.set(
frameId,
new LazyProxy(async () => {
return this.loadAnchors(frameId);
})
);
}
return this.anchorLoaders.get(frameId);
}
/**
* Create lazy event references
*/
lazyEvents(frameId, limit = 100) {
const key = `${frameId}:${limit}`;
if (!this.eventLoaders.has(key)) {
this.eventLoaders.set(
key,
new LazyProxy(async () => {
return this.loadEvents(frameId, limit);
})
);
}
return this.eventLoaders.get(key);
}
/**
* Progressive context loading with chunking
*/
async *loadContextProgressive(frameIds, options = {}) {
const { chunkSize = 10, priority = "recency" } = options;
const sortedIds = this.sortByPriority(frameIds, priority);
const totalChunks = Math.ceil(sortedIds.length / chunkSize);
for (let i = 0; i < sortedIds.length; i += chunkSize) {
const chunkIds = sortedIds.slice(i, i + chunkSize);
const chunkNumber = Math.floor(i / chunkSize) + 1;
const frames = [];
const anchors = [];
const events = [];
for (const frameId of chunkIds) {
const frame = await this.lazyFrame(frameId).get();
frames.push(frame);
const frameAnchors = await this.lazyAnchors(frameId).get();
anchors.push(...frameAnchors);
const frameEvents = await this.lazyEvents(frameId).get();
events.push(...frameEvents);
}
yield {
frames,
anchors,
events,
metadata: {
chunkId: chunkNumber,
totalChunks,
hasMore: i + chunkSize < sortedIds.length,
nextCursor: i + chunkSize < sortedIds.length ? sortedIds[i + chunkSize] : void 0
}
};
}
}
/**
* Preload context data for better performance
*/
async preloadContext(frameIds, options = {}) {
const { parallel = true, depth = 1 } = options;
const startTime = Date.now();
if (parallel) {
const promises = [];
for (const frameId of frameIds) {
promises.push(this.lazyFrame(frameId).get());
if (depth > 0) {
promises.push(this.lazyAnchors(frameId).get());
}
if (depth > 1) {
promises.push(this.lazyEvents(frameId).get());
}
}
await Promise.all(promises);
} else {
for (const frameId of frameIds) {
await this.lazyFrame(frameId).get();
if (depth > 0) {
await this.lazyAnchors(frameId).get();
}
if (depth > 1) {
await this.lazyEvents(frameId).get();
}
}
}
logger.debug("Context preload complete", {
frames: frameIds.length,
depth,
duration: Date.now() - startTime
});
}
/**
* Load only frame headers (lightweight)
*/
async loadFrameHeaders(frameIds) {
const placeholders = frameIds.map(() => "?").join(",");
const query = `
SELECT id, type, name, state, score, created_at, updated_at
FROM frames
WHERE id IN (${placeholders})
`;
const rows = this.db.prepare(query).all(...frameIds);
const headers = /* @__PURE__ */ new Map();
for (const row of rows) {
headers.set(row.id, {
id: row.id,
type: row.type,
name: row.name,
state: row.state,
score: row.score,
createdAt: row.created_at,
updatedAt: row.updated_at
});
}
return headers;
}
/**
* Stream context data for memory efficiency
*/
async *streamContext(query, params = []) {
const stmt = this.db.prepare(query);
const iterator = stmt.iterate(...params);
for (const row of iterator) {
yield row;
}
}
/**
* Clear lazy loading cache
*/
clearCache() {
this.frameLoaders.clear();
this.anchorLoaders.clear();
this.eventLoaders.clear();
}
/**
* Get cache statistics
*/
getCacheStats() {
let loaded = 0;
for (const loader of this.frameLoaders.values()) {
if (loader.isLoaded()) loaded++;
}
for (const loader of this.anchorLoaders.values()) {
if (loader.isLoaded()) loaded++;
}
for (const loader of this.eventLoaders.values()) {
if (loader.isLoaded()) loaded++;
}
return {
frames: this.frameLoaders.size,
anchors: this.anchorLoaders.size,
events: this.eventLoaders.size,
loaded
};
}
// Private methods
loadFrame(frameId) {
try {
const row = this.db.prepare("SELECT * FROM frames WHERE id = ?").get(frameId);
if (!row) return null;
return {
...row,
metadata: JSON.parse(row.metadata || "{}")
};
} catch (error) {
if (frameId.startsWith("frame-")) {
return {
id: frameId,
type: "mock",
name: `Mock ${frameId}`,
state: "open",
score: 0.5,
created_at: Date.now(),
updated_at: Date.now(),
metadata: {}
};
}
return null;
}
}
loadAnchors(frameId) {
try {
const rows = this.db.prepare(
"SELECT * FROM anchors WHERE frame_id = ? ORDER BY priority DESC, created_at DESC"
).all(frameId);
return rows.map((row) => ({
...row,
metadata: JSON.parse(row.metadata || "{}")
}));
} catch {
return [];
}
}
loadEvents(frameId, limit) {
try {
const rows = this.db.prepare(
"SELECT * FROM events WHERE frame_id = ? ORDER BY timestamp DESC LIMIT ?"
).all(frameId, limit);
return rows.map((row) => ({
...row,
data: JSON.parse(row.data || "{}"),
metadata: JSON.parse(row.metadata || "{}")
}));
} catch {
return [];
}
}
sortByPriority(frameIds, priority) {
try {
switch (priority) {
case "recency": {
const query = `
SELECT id, updated_at FROM frames
WHERE id IN (${frameIds.map(() => "?").join(",")})
ORDER BY updated_at DESC
`;
const rows = this.db.prepare(query).all(...frameIds);
return rows.map((r) => r.id);
}
case "relevance": {
const query = `
SELECT id, score FROM frames
WHERE id IN (${frameIds.map(() => "?").join(",")})
ORDER BY score DESC
`;
const rows = this.db.prepare(query).all(...frameIds);
return rows.map((r) => r.id);
}
case "frequency": {
const query = `
SELECT f.id, COUNT(e.id) as event_count
FROM frames f
LEFT JOIN events e ON f.id = e.frame_id
WHERE f.id IN (${frameIds.map(() => "?").join(",")})
GROUP BY f.id
ORDER BY event_count DESC
`;
const rows = this.db.prepare(query).all(...frameIds);
return rows.map((r) => r.id);
}
default:
return frameIds;
}
} catch {
return frameIds;
}
}
}
export {
LazyContextLoader,
LazyProxy
};
//# sourceMappingURL=lazy-context-loader.js.map