@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.
156 lines (155 loc) • 5.02 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 Database from "better-sqlite3";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
import chalk from "chalk";
const projectRoot = process.cwd();
const stackDir = join(projectRoot, ".stackmemory");
const dbPath = join(stackDir, "context.db");
const configPath = join(stackDir, "config.json");
console.log(chalk.blue.bold("\n[StackMemory Status]\n"));
if (!existsSync(stackDir)) {
console.log(chalk.red("[X] .stackmemory directory not found"));
console.log(chalk.gray(" Run: stackmemory init"));
process.exit(1);
}
console.log(chalk.green("[OK] .stackmemory directory exists"));
if (existsSync(configPath)) {
try {
const config = JSON.parse(readFileSync(configPath, "utf-8"));
console.log(chalk.green("[OK] config.json found"));
console.log(chalk.gray(` version: ${config.version || "unknown"}`));
console.log(chalk.gray(` project: ${config.project || "unknown"}`));
console.log(
chalk.gray(` initialized: ${config.initialized || "unknown"}`)
);
} catch {
console.log(chalk.yellow("[!] config.json exists but failed to parse"));
}
} else {
console.log(chalk.yellow("[!] config.json not found"));
}
if (!existsSync(dbPath)) {
console.log(chalk.red("[X] context.db not found"));
process.exit(1);
}
console.log(chalk.green("[OK] context.db exists"));
const db = new Database(dbPath, { readonly: true });
const stats = {
contexts: db.prepare("SELECT COUNT(*) as count FROM contexts").get(),
frames: db.prepare("SELECT COUNT(*) as count FROM frames").get(),
attention: db.prepare("SELECT COUNT(*) as count FROM attention_log").get()
};
console.log(chalk.cyan("\n[Database Stats]"));
console.log(` Contexts: ${stats.contexts.count}`);
console.log(` Frames: ${stats.frames.count}`);
console.log(` Attention logs: ${stats.attention.count}`);
if (stats.contexts.count > 0) {
console.log(chalk.cyan("\n[Top Contexts by Importance]"));
const topContexts = db.prepare(
`
SELECT type, substr(content, 1, 60) as preview, importance, access_count
FROM contexts
ORDER BY importance DESC, access_count DESC
LIMIT 5
`
).all();
topContexts.forEach((ctx, i) => {
const importance = "*".repeat(Math.round(ctx.importance * 5));
console.log(
chalk.white(` ${i + 1}.`) + ` [${ctx.type}] ` + chalk.gray(`(${ctx.access_count} uses)`) + ` ${importance}`
);
console.log(chalk.gray(` ${ctx.preview}...`));
});
}
const activeFrames = db.prepare(
`
SELECT name, type, datetime(created_at, 'unixepoch') as started
FROM frames
WHERE state = 'active'
ORDER BY created_at DESC
LIMIT 3
`
).all();
if (activeFrames.length > 0) {
console.log(chalk.cyan("\n[Active Frames]"));
activeFrames.forEach((frame) => {
console.log(chalk.green(" *") + ` ${frame.name} (${frame.type})`);
console.log(chalk.gray(` Started: ${frame.started}`));
});
}
const recentAttention = db.prepare(
`
SELECT
substr(query, 1, 50) as query_preview,
COUNT(*) as count
FROM attention_log
WHERE timestamp > unixepoch() - 86400
GROUP BY query_preview
ORDER BY count DESC
LIMIT 3
`
).all();
if (recentAttention.length > 0) {
console.log(chalk.cyan("\n[Recent Query Patterns]"));
recentAttention.forEach((pattern) => {
console.log(
chalk.yellow(" ?") + ` "${pattern.query_preview}..." (${pattern.count}x)`
);
});
}
const oldContexts = db.prepare(
`
SELECT COUNT(*) as count
FROM contexts
WHERE last_accessed < unixepoch() - 86400 * 7
`
).get();
if (oldContexts.count > 0) {
console.log(
chalk.yellow(
`
[!] ${oldContexts.count} contexts haven't been accessed in 7+ days`
)
);
}
console.log(chalk.cyan("\n[MCP Configuration]"));
const mcpConfigPaths = [
join(
process.env.HOME || "",
"Library/Application Support/Claude/claude_desktop_config.json"
),
join(process.env.HOME || "", ".config/claude/claude_desktop_config.json")
];
let mcpFound = false;
for (const mcpPath of mcpConfigPaths) {
if (existsSync(mcpPath)) {
try {
const mcpConfig = JSON.parse(readFileSync(mcpPath, "utf-8"));
const hasStackMemory = mcpConfig.mcpServers?.stackmemory || mcpConfig.mcpServers?.["stackmemory-mcp"];
if (hasStackMemory) {
console.log(chalk.green(" [OK] MCP server configured"));
mcpFound = true;
} else {
console.log(
chalk.yellow(" [!] MCP config exists but stackmemory not configured")
);
}
} catch {
console.log(chalk.yellow(` [!] Failed to parse ${mcpPath}`));
}
break;
}
}
if (!mcpFound) {
console.log(chalk.gray(" [--] No MCP configuration found"));
}
console.log(
chalk.gray('\nTip: Run "npm run analyze" for detailed attention analysis\n')
);
db.close();
//# sourceMappingURL=status.js.map