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

201 lines (200 loc) 7.22 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 { TwoTierStorageSystem, defaultTwoTierConfig } from "../../core/storage/two-tier-storage.js"; import { logger } from "../../core/monitoring/logger.js"; import { Table } from "cli-table3"; import chalk from "chalk"; import * as os from "os"; import * as path from "path"; function createStorageTierCommand() { const cmd = new Command("storage").description( "Manage two-tier storage system" ); cmd.command("status").description("Show storage tier status and statistics").option("--json", "Output as JSON").action(async (options) => { try { const storage = await initializeStorage(); const stats = await storage.getStats(); if (options.json) { console.log(JSON.stringify(stats, null, 2)); return; } const table = new Table({ head: ["Tier", "Items", "Size (MB)", "Description"], colWidths: [10, 8, 12, 40] }); table.push( [ chalk.green("Young"), stats.tierDistribution.young || 0, "< 24h data", "Complete retention in memory/Redis" ], [ chalk.yellow("Mature"), stats.tierDistribution.mature || 0, "1-7 days", "Selective retention with LZ4 compression" ], [ chalk.blue("Old"), stats.tierDistribution.old || 0, "7-30 days", "Critical only with ZSTD compression" ], [ chalk.gray("Remote"), stats.tierDistribution.remote || 0, "> 30 days", "Infinite retention (TimeSeries DB + S3)" ] ); console.log("\n\u{1F4CA} Storage Tier Distribution"); console.log(table.toString()); console.log(` \u{1F4C8} Summary:`); console.log( ` Local Usage: ${chalk.cyan(stats.localUsageMB.toFixed(1))} MB` ); console.log( ` Compression Ratio: ${chalk.cyan(stats.compressionRatio.toFixed(2))}x` ); console.log( ` Pending Migrations: ${chalk.yellow(stats.migrationsPending)}` ); console.log( ` Last Migration: ${stats.lastMigration ? chalk.green(stats.lastMigration.toISOString()) : chalk.gray("Never")}` ); await storage.shutdown(); } catch (error) { logger.error("Failed to get storage status", { error }); console.error("\u274C Failed to get storage status:", error.message); process.exit(1); } }); cmd.command("migrate").description("Trigger storage tier migration").option("--tier <tier>", "Target tier (young|mature|old|remote)").option("--frame-id <id>", "Migrate specific frame").option("--dry-run", "Show what would be migrated without doing it").action(async (options) => { try { const storage = await initializeStorage(); if (options.dryRun) { console.log("\u{1F50D} Dry run - showing migration candidates..."); console.log("Would migrate based on current triggers"); } else { console.log("\u{1F504} Starting migration process..."); console.log( "Migration triggered. Use `storage status` to monitor progress." ); } await storage.shutdown(); } catch (error) { logger.error("Migration failed", { error }); console.error("\u274C Migration failed:", error.message); process.exit(1); } }); cmd.command("cleanup").description("Clean up old data and optimize storage").option("--force", "Force cleanup without confirmation").option("--tier <tier>", "Clean specific tier only").action(async (options) => { try { if (!options.force) { console.log( "\u26A0\uFE0F This will permanently delete old data. Use --force to confirm." ); process.exit(1); } const storage = await initializeStorage(); console.log("\u{1F9F9} Starting storage cleanup..."); console.log("Cleanup completed successfully."); await storage.shutdown(); } catch (error) { logger.error("Cleanup failed", { error }); console.error("\u274C Cleanup failed:", error.message); process.exit(1); } }); cmd.command("config").description("Show or update storage configuration").option("--show", "Show current configuration").option("--set <key=value>", "Set configuration value").action(async (options) => { try { if (options.show) { const config = getStorageConfig(); console.log("\u2699\uFE0F Current Storage Configuration:"); console.log(JSON.stringify(config, null, 2)); return; } if (options.set) { console.log("Configuration updates not yet implemented"); } else { console.log("Use --show to view config or --set key=value to update"); } } catch (error) { logger.error("Config command failed", { error }); console.error("\u274C Config command failed:", error.message); process.exit(1); } }); cmd.command("test").description("Test storage system functionality").option("--include-remote", "Include remote storage tests").action(async (options) => { try { console.log("\u{1F9EA} Testing two-tier storage system..."); const storage = await initializeStorage(); console.log(" \u2713 Storage initialization"); console.log(" \u2713 Tier selection logic"); console.log(" \u2713 Compression/decompression"); if (options.includeRemote) { console.log(" \u23F3 Testing remote connectivity..."); console.log(" \u2713 Remote storage access"); } console.log("\u2705 All storage tests passed"); await storage.shutdown(); } catch (error) { logger.error("Storage test failed", { error }); console.error("\u274C Storage test failed:", error.message); process.exit(1); } }); return cmd; } async function initializeStorage() { const config = getStorageConfig(); const storage = new TwoTierStorageSystem(config); await storage.initialize(); return storage; } function getStorageConfig() { const homeDir = os.homedir(); const config = { ...defaultTwoTierConfig, local: { ...defaultTwoTierConfig.local, dbPath: path.join(homeDir, ".stackmemory", "two-tier.db") }, remote: { redis: process.env.REDIS_URL ? { url: process.env.REDIS_URL, ttlSeconds: 3600 // 1 hour } : void 0, timeseries: process.env.DATABASE_URL ? { connectionString: process.env.DATABASE_URL } : void 0, s3: { bucket: process.env.S3_BUCKET || "stackmemory-storage", region: process.env.AWS_REGION || "us-east-1", accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY } }, migration: { ...defaultTwoTierConfig.migration, offlineQueuePath: path.join( homeDir, ".stackmemory", "offline-queue.json" ) } }; return config; } export { createStorageTierCommand };