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

90 lines (89 loc) 3.49 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 chalk from "chalk"; import { ContextCapture } from "../../core/worktree/capture.js"; function createSnapshotCommand() { const cmd = new Command("snapshot").alias("snap").description("Point-in-time snapshot of work (what changed and why)"); cmd.command("save").alias("s").description("Save a snapshot of current branch state").option("-t, --task <name>", "Task name or description").option( "-b, --base <branch>", "Base branch to diff against (default: auto-detect)" ).option( "-d, --decision <decisions...>", "Key decisions made during this task" ).option("--json", "Output as JSON").action((options) => { const capture = new ContextCapture(); const result = capture.capture({ task: options.task, baseBranch: options.base, decisions: options.decision }); if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } console.log(chalk.green("\nSnapshot saved.\n")); console.log(chalk.gray(` Branch: ${result.branch}`)); console.log(chalk.gray(` Base: ${result.baseBranch}`)); console.log(chalk.gray(` Changed: ${result.filesChanged.length} files`)); console.log(chalk.gray(` Created: ${result.filesCreated.length} files`)); console.log(chalk.gray(` Deleted: ${result.filesDeleted.length} files`)); console.log(chalk.gray(` Commits: ${result.commits.length}`)); if (result.decisions.length > 0) { console.log(chalk.cyan("\n Decisions:")); result.decisions.forEach((d) => console.log(chalk.gray(` - ${d}`))); } if (result.duration) { console.log(chalk.gray(` Duration: ${result.duration}`)); } console.log(chalk.gray(` Saved: ${result.id}`)); }); cmd.command("list").alias("ls").description("List recent snapshots").option("-n, --limit <n>", "Number of captures to show", "10").option("--json", "Output as JSON").action((options) => { const capture = new ContextCapture(); const captures = capture.list(parseInt(options.limit)); if (captures.length === 0) { console.log(chalk.yellow("No snapshots found.")); return; } if (options.json) { console.log(JSON.stringify(captures, null, 2)); return; } console.log(chalk.cyan(` Recent Snapshots (${captures.length}): `)); for (const cap of captures) { const date = new Date(cap.timestamp).toLocaleDateString(); const files = cap.filesChanged.length + cap.filesCreated.length; console.log( chalk.gray( ` ${date} ${cap.branch.padEnd(30)} ${files} files ${cap.commits.length} commits` ) ); } }); cmd.command("show [branch]").description("Show snapshot details (latest or by branch)").option("--json", "Output as JSON").action((branch, options) => { const capturer = new ContextCapture(); const result = capturer.getLatest(branch); if (!result) { console.log( chalk.yellow( branch ? `No snapshot found for branch: ${branch}` : "No snapshots found." ) ); return; } if (options.json) { console.log(JSON.stringify(result, null, 2)); return; } console.log(capturer.format(result)); }); return cmd; } export { createSnapshotCommand };