UNPKG

@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

135 lines (134 loc) 4.16 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { Command } from "commander"; import { existsSync, readFileSync } from "fs"; import { join } from "path"; import { homedir } from "os"; let countTokens; try { const tokenizer = await import("@anthropic-ai/tokenizer"); countTokens = tokenizer.countTokens; } catch { countTokens = (text) => Math.ceil(text.length / 3.5); } function readFileSafe(filePath) { try { if (existsSync(filePath)) { return readFileSync(filePath, "utf-8"); } } catch { } return null; } function createAuditCommand() { const audit = new Command("audit").description( "Measure context overhead (tokens injected before first message)" ).option("--json", "Output as JSON", false).action(async (options) => { const projectRoot = process.cwd(); const home = homedir(); const entries = []; const globalClaudeMd = readFileSafe(join(home, ".claude", "CLAUDE.md")); if (globalClaudeMd) { entries.push({ source: "~/.claude/CLAUDE.md", tokens: countTokens(globalClaudeMd), percent: 0 }); } const projectClaudeMd = readFileSafe(join(projectRoot, "CLAUDE.md")); if (projectClaudeMd) { entries.push({ source: "./CLAUDE.md", tokens: countTokens(projectClaudeMd), percent: 0 }); } const projectSlug = projectRoot.replace(/\//g, "-"); const memoryPath = join( home, ".claude", "projects", projectSlug, "memory", "MEMORY.md" ); const memoryMd = readFileSafe(memoryPath); if (memoryMd) { entries.push({ source: "auto-memory/MEMORY.md", tokens: countTokens(memoryMd), percent: 0 }); } const handoffPath = join(projectRoot, ".stackmemory", "handoff.md"); const handoffMd = readFileSafe(handoffPath); if (handoffMd) { entries.push({ source: ".stackmemory/handoff.md", tokens: countTokens(handoffMd), percent: 0 }); } try { const { MCPToolDefinitions } = await import("../../integrations/mcp/tool-definitions.js"); const defs = new MCPToolDefinitions(); const allTools = defs.getAllToolDefinitions(); const schemasJson = JSON.stringify(allTools); entries.push({ source: "MCP tool schemas", tokens: countTokens(schemasJson), percent: 0 }); } catch { } try { const dbPath = join(projectRoot, ".stackmemory", "context.db"); if (existsSync(dbPath)) { const { default: Database } = await import("better-sqlite3"); const { FrameManager } = await import("../../core/context/index.js"); const db = new Database(dbPath); const fm = new FrameManager(db, "cli-project"); const hotStack = fm.getHotStackContext(); if (hotStack) { entries.push({ source: "Active frames (hot stack)", tokens: countTokens(hotStack), percent: 0 }); } db.close(); } } catch { } const totalTokens = entries.reduce((sum, e) => sum + e.tokens, 0); for (const entry of entries) { entry.percent = totalTokens > 0 ? Math.round(entry.tokens / totalTokens * 1e3) / 10 : 0; } if (options.json) { console.log(JSON.stringify({ entries, totalTokens }, null, 2)); return; } console.log("\nContext Overhead Audit"); console.log("\u2500".repeat(60)); console.log( `${"Source".padEnd(32)} ${"Tokens".padStart(8)} ${"%".padStart(7)}` ); console.log("\u2500".repeat(60)); for (const entry of entries) { console.log( `${entry.source.padEnd(32)} ${String(entry.tokens).padStart(8)} ${(entry.percent + "%").padStart(7)}` ); } console.log("\u2500".repeat(60)); console.log( `${"TOTAL".padEnd(32)} ${String(totalTokens).padStart(8)} ${"100%".padStart(7)}` ); console.log(""); }); return audit; } export { createAuditCommand };