@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
74 lines (73 loc) • 2.51 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 { Command } from "commander";
import Database from "better-sqlite3";
import { join } from "path";
import { existsSync, writeFileSync, mkdirSync } from "fs";
import { execSync } from "child_process";
import {
generateChronologicalDigest
} from "../../core/digest/chronological-digest.js";
function findProjectRoot() {
let dir = process.cwd();
while (dir !== "/") {
if (existsSync(join(dir, ".git"))) return dir;
dir = join(dir, "..");
}
return process.cwd();
}
function getProjectId(projectRoot) {
let identifier;
try {
identifier = execSync("git config --get remote.origin.url", {
cwd: projectRoot,
stdio: "pipe",
timeout: 5e3
}).toString().trim();
} catch {
identifier = projectRoot;
}
const cleaned = identifier.replace(/\.git$/, "").replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
return cleaned.substring(cleaned.length - 50) || "unknown";
}
function createDigestCommands() {
const digest = new Command("digest").description("Generate chronological activity digest").argument("<period>", "Time period: today, yesterday, or week").option("-o, --output <path>", "Custom output path").action((period, options) => {
const validPeriods = ["today", "yesterday", "week"];
if (!validPeriods.includes(period)) {
console.error(
`Invalid period "${period}". Use: ${validPeriods.join(", ")}`
);
process.exit(1);
}
const projectRoot = findProjectRoot();
const dbPath = join(projectRoot, ".stackmemory", "context.db");
if (!existsSync(dbPath)) {
console.error(
"No StackMemory database found. Run stackmemory in a project first."
);
process.exit(1);
}
const db = new Database(dbPath, { readonly: true });
const projectId = getProjectId(projectRoot);
try {
const markdown = generateChronologicalDigest(
db,
period,
projectId
);
const smDir = join(projectRoot, ".stackmemory");
if (!existsSync(smDir)) mkdirSync(smDir, { recursive: true });
const outputPath = options.output || join(smDir, `${period}.md`);
writeFileSync(outputPath, markdown);
console.log(`Digest written to ${outputPath}`);
} finally {
db.close();
}
});
return digest;
}
export {
createDigestCommands
};