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.

201 lines (200 loc) 7.93 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 { sessionManager } from "../../core/session/index.js"; import { logger } from "../../core/monitoring/logger.js"; import chalk from "chalk"; function createSessionCommands() { const sessionCommand = new Command("session").description( "Manage StackMemory sessions" ); sessionCommand.command("list").description("List all sessions").option("--project", "Show only sessions for current project").option("--active", "Show only active sessions").option("--all", "Show all sessions including closed").action(async (options) => { try { await sessionManager.initialize(); const filter = {}; if (options.project) { const projectHash = await getProjectHash(); filter.projectId = projectHash; } if (options.active && !options.all) { filter.state = "active"; } const sessions = await sessionManager.listSessions(filter); if (sessions.length === 0) { console.log("No sessions found"); return; } console.log(chalk.bold("\n\u{1F4CB} StackMemory Sessions:\n")); sessions.forEach((session) => { const age = formatAge(Date.now() - session.lastActiveAt); const status = session.state === "active" ? chalk.green("\u25CF") : session.state === "suspended" ? chalk.yellow("\u25CF") : chalk.gray("\u25CF"); console.log(`${status} ${chalk.bold(session.sessionId.slice(0, 8))}`); console.log(` Project: ${session.projectId}`); if (session.branch) { console.log(` Branch: ${session.branch}`); } console.log(` State: ${session.state}`); console.log(` Last active: ${age} ago`); console.log(""); }); console.log(chalk.gray(`Total: ${sessions.length} session(s)`)); } catch (error) { logger.error("Failed to list sessions", error); console.error("\u274C Failed to list sessions:", error.message); process.exit(1); } }); sessionCommand.command("current").description("Show current session information").action(async () => { try { await sessionManager.initialize(); const session = sessionManager.getCurrentSession(); if (!session) { console.log("No active session"); return; } const duration = formatDuration(Date.now() - session.startedAt); console.log(chalk.bold("\n\u{1F50D} Current Session:\n")); console.log(`Session ID: ${chalk.cyan(session.sessionId)}`); console.log(`Run ID: ${session.runId}`); console.log(`Project: ${session.projectId}`); if (session.branch) { console.log(`Branch: ${session.branch}`); } console.log(`State: ${session.state}`); console.log(`Duration: ${duration}`); if (session.metadata.user) { console.log(`User: ${session.metadata.user}`); } if (session.metadata.tags && session.metadata.tags.length > 0) { console.log(`Tags: ${session.metadata.tags.join(", ")}`); } } catch (error) { logger.error("Failed to show current session", error); console.error( "\u274C Failed to show current session:", error.message ); process.exit(1); } }); sessionCommand.command("switch <sessionId>").description("Switch to a different session").action(async (sessionId) => { try { await sessionManager.initialize(); const current = sessionManager.getCurrentSession(); if (current) { await sessionManager.suspendSession(); console.log(`Suspended session: ${current.sessionId.slice(0, 8)}`); } const session = await sessionManager.resumeSession(sessionId); console.log( chalk.green( `\u2705 Switched to session: ${session.sessionId.slice(0, 8)}` ) ); console.log(` Project: ${session.projectId}`); if (session.branch) { console.log(` Branch: ${session.branch}`); } } catch (error) { logger.error("Failed to switch session", error); console.error("\u274C Failed to switch session:", error.message); process.exit(1); } }); sessionCommand.command("suspend [sessionId]").description("Suspend a session (current if not specified)").action(async (sessionId) => { try { await sessionManager.initialize(); await sessionManager.suspendSession(sessionId); const id = sessionId || sessionManager.getCurrentSession()?.sessionId; console.log(chalk.yellow(`\u23F8\uFE0F Suspended session: ${id?.slice(0, 8)}`)); } catch (error) { logger.error("Failed to suspend session", error); console.error( "\u274C Failed to suspend session:", error.message ); process.exit(1); } }); sessionCommand.command("resume <sessionId>").description("Resume a suspended session").action(async (sessionId) => { try { await sessionManager.initialize(); const session = await sessionManager.resumeSession(sessionId); console.log( chalk.green(`\u25B6\uFE0F Resumed session: ${session.sessionId.slice(0, 8)}`) ); console.log(` Project: ${session.projectId}`); if (session.branch) { console.log(` Branch: ${session.branch}`); } } catch (error) { logger.error("Failed to resume session", error); console.error("\u274C Failed to resume session:", error.message); process.exit(1); } }); sessionCommand.command("merge <sourceId> <targetId>").description("Merge two sessions").action(async (sourceId, targetId) => { try { await sessionManager.initialize(); const merged = await sessionManager.mergeSessions(sourceId, targetId); console.log(chalk.green(`\u2705 Merged sessions successfully`)); console.log(` Target: ${merged.sessionId.slice(0, 8)}`); console.log(` Source ${sourceId.slice(0, 8)} has been closed`); } catch (error) { logger.error("Failed to merge sessions", error); console.error("\u274C Failed to merge sessions:", error.message); process.exit(1); } }); sessionCommand.command("cleanup").description("Clean up old closed sessions").option("--days <days>", "Remove sessions older than N days", "30").action(async (options) => { try { await sessionManager.initialize(); const days = parseInt(options.days); const maxAge = days * 24 * 60 * 60 * 1e3; const cleaned = await sessionManager.cleanupStaleSessions(maxAge); console.log(chalk.green(`\u2705 Cleaned up ${cleaned} old session(s)`)); } catch (error) { logger.error("Failed to cleanup sessions", error); console.error( "\u274C Failed to cleanup sessions:", error.message ); process.exit(1); } }); return sessionCommand; } async function getProjectHash() { const crypto = await import("crypto"); const cwd = process.cwd(); const hash = crypto.createHash("sha256"); hash.update(cwd); return hash.digest("hex").substring(0, 12); } function formatAge(ms) { const seconds = Math.floor(ms / 1e3); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (days > 0) return `${days}d`; if (hours > 0) return `${hours}h`; if (minutes > 0) return `${minutes}m`; return `${seconds}s`; } function formatDuration(ms) { const seconds = Math.floor(ms / 1e3); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const h = hours; const m = minutes % 60; const s = seconds % 60; if (h > 0) return `${h}h ${m}m ${s}s`; if (m > 0) return `${m}m ${s}s`; return `${s}s`; } export { createSessionCommands }; //# sourceMappingURL=session.js.map