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.

193 lines (192 loc) 6.76 kB
#!/usr/bin/env tsx import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { ChromaClient } from "chromadb"; import * as fs from "fs"; import * as path from "path"; import * as os from "os"; import * as readline from "readline"; import dotenv from "dotenv"; dotenv.config(); async function testChromaDBConnection() { const apiKey = process.env.CHROMADB_API_KEY; const tenant = process.env.CHROMADB_TENANT; const database = process.env.CHROMADB_DATABASE || "stackmemory"; if (!apiKey || !tenant) { console.error("\u274C Missing ChromaDB credentials in .env"); console.log(" CHROMADB_API_KEY:", apiKey ? "\u2713 Set" : "\u2717 Missing"); console.log(" CHROMADB_TENANT:", tenant ? "\u2713 Set" : "\u2717 Missing"); console.log(" CHROMADB_DATABASE:", database); return null; } console.log("\u{1F504} Connecting to ChromaDB Cloud..."); console.log(" Tenant:", tenant); console.log(" Database:", database); try { const client = new ChromaClient({ ssl: true, host: "api.trychroma.com", port: 443, headers: { "X-Chroma-Token": apiKey }, tenant, database }); const heartbeat = await client.heartbeat(); console.log("\u2705 ChromaDB connection successful:", heartbeat); return client; } catch (error) { console.error("\u274C Failed to connect to ChromaDB:", error.message); return null; } } async function getOrCreateCollection(client) { const collectionName = "stackmemory_contexts"; try { const collections = await client.listCollections(); console.log("\u{1F4DA} Existing collections:", collections.map((c) => c.name).join(", ") || "none"); const collection = await client.getOrCreateCollection({ name: collectionName, metadata: { description: "StackMemory context storage", created_by: "test-chromadb-sync", version: "2.0.0" } }); console.log(`\u2705 Collection '${collectionName}' ready`); const count = await collection.count(); console.log(` Current entries: ${count}`); return collection; } catch (error) { console.error("\u274C Failed to create/get collection:", error.message); return null; } } async function loadLocalContexts() { const storageFile = path.join(os.homedir(), ".stackmemory", "context-storage", "contexts.jsonl"); if (!fs.existsSync(storageFile)) { console.log("\u26A0\uFE0F No local contexts found"); return []; } const contexts = []; const fileStream = fs.createReadStream(storageFile); const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity }); for await (const line of rl) { if (line.trim()) { try { contexts.push(JSON.parse(line)); } catch (error) { console.warn("Failed to parse line:", line.substring(0, 50)); } } } console.log(`\u{1F4C1} Loaded ${contexts.length} local contexts`); return contexts; } async function syncContextsToChromaDB(collection, contexts) { console.log(` \u{1F504} Syncing ${contexts.length} contexts to ChromaDB...`); let synced = 0; let failed = 0; const batchSize = 10; for (let i = 0; i < contexts.length; i += batchSize) { const batch = contexts.slice(i, Math.min(i + batchSize, contexts.length)); const ids = []; const documents = []; const metadatas = []; for (const ctx of batch) { ids.push(ctx.id || `ctx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`); documents.push(ctx.content || JSON.stringify(ctx)); const metadata = { timestamp: ctx.timestamp || ctx.stored_at || (/* @__PURE__ */ new Date()).toISOString(), type: ctx.type || "context", user_id: ctx.user_id || process.env.USER || "default", project: ctx.project || "stackmemory" }; if (ctx.session_id) metadata.session_id = ctx.session_id; if (ctx.metadata) { Object.entries(ctx.metadata).forEach(([key, value]) => { if (value !== void 0 && value !== null) { metadata[key] = String(value); } }); } metadatas.push(metadata); } try { await collection.upsert({ ids, documents, metadatas }); synced += batch.length; console.log(` \u2713 Batch ${Math.floor(i / batchSize) + 1}: ${batch.length} contexts synced`); } catch (error) { failed += batch.length; console.error(` \u2717 Batch ${Math.floor(i / batchSize) + 1} failed:`, error.message); } } console.log(` \u{1F4CA} Sync complete:`); console.log(` \u2705 Synced: ${synced}`); console.log(` \u274C Failed: ${failed}`); return { synced, failed }; } async function queryRecentContexts(collection) { console.log("\n\u{1F50D} Querying recent contexts..."); try { const results = await collection.query({ queryTexts: ["task complete code change"], nResults: 5 }); if (results.ids && results.ids[0].length > 0) { console.log(`Found ${results.ids[0].length} relevant contexts:`); for (let i = 0; i < results.ids[0].length; i++) { const metadata = results.metadatas[0][i]; const document = results.documents[0][i]; console.log(` \u{1F4C4} Context ${i + 1}:`); console.log(` ID: ${results.ids[0][i]}`); console.log(` Type: ${metadata.type}`); console.log(` Timestamp: ${metadata.timestamp}`); console.log(` Content: ${document.substring(0, 100)}...`); } } else { console.log("No contexts found"); } } catch (error) { console.error("Failed to query contexts:", error.message); } } async function main() { console.log("\u{1F680} ChromaDB Sync Test\n"); const client = await testChromaDBConnection(); if (!client) { console.error("\n\u274C Cannot proceed without ChromaDB connection"); console.log("\n\u{1F4DD} To fix:"); console.log("1. Ensure you have a ChromaDB Cloud account"); console.log("2. Add credentials to .env:"); console.log(" CHROMADB_API_KEY=your-api-key"); console.log(" CHROMADB_TENANT=your-tenant-id"); console.log(" CHROMADB_DATABASE=stackmemory"); process.exit(1); } const collection = await getOrCreateCollection(client); if (!collection) { process.exit(1); } const contexts = await loadLocalContexts(); if (contexts.length > 0) { await syncContextsToChromaDB(collection, contexts); } await queryRecentContexts(collection); console.log("\n\u2705 Test complete!"); } main().catch(console.error); //# sourceMappingURL=test-chromadb-sync.js.map