UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

1,502 lines 64.1 kB
/**
 * V3 CLI Memory Command
 * Memory operations for AgentDB integration
 */
import { output } from '../output.js';
import { select, confirm, input } from '../prompt.js';
import { callMCPTool, MCPClientError } from '../mcp-client.js';
// Memory backends
const BACKENDS = [
    { value: 'agentdb', label: 'AgentDB', hint: 'Vector database with HNSW indexing (150x-12,500x faster)' },
    { value: 'sqlite', label: 'SQLite', hint: 'Lightweight local storage' },
    { value: 'hybrid', label: 'Hybrid', hint: 'SQLite + AgentDB (recommended)' },
    { value: 'memory', label: 'In-Memory', hint: 'Fast but non-persistent' }
];
// #2105: shared --path option for memory subcommands.
// Precedence: --path > CLAUDE_FLOW_DB_PATH env var > default root
const DB_PATH_OPTION = {
    name: 'path',
    description: 'Override DB file path (also: CLAUDE_FLOW_DB_PATH env var). ' +
        'Precedence: --path > CLAUDE_FLOW_DB_PATH > CLAUDE_FLOW_MEMORY_PATH/memory.db > cwd/.swarm/memory.db',
    type: 'string',
};
// Store command
const storeCommand = {
    name: 'store',
    description: 'Store data in memory',
    options: [
        {
            name: 'key',
            short: 'k',
            description: 'Storage key/namespace',
            type: 'string',
            required: true
        },
        {
            name: 'value',
            // Note: No short flag - global -v is reserved for verbose
            description: 'Value to store (use --value)',
            type: 'string'
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Memory namespace',
            type: 'string',
            default: 'default'
        },
        {
            name: 'ttl',
            description: 'Time to live in seconds',
            type: 'number'
        },
        {
            name: 'tags',
            description: 'Comma-separated tags',
            type: 'string'
        },
        {
            name: 'vector',
            description: 'Store as vector embedding',
            type: 'boolean',
            default: false
        },
        {
            name: 'upsert',
            short: 'u',
            description: 'Update if key exists (insert or replace)',
            type: 'boolean',
            default: false
        },
        DB_PATH_OPTION
    ],
    examples: [
        { command: 'claude-flow memory store -k "api/auth" -v "JWT implementation"', description: 'Store text' },
        { command: 'claude-flow memory store -k "pattern/singleton" --vector', description: 'Store vector' },
        { command: 'claude-flow memory store -k "pattern" -v "updated" --upsert', description: 'Update existing' }
    ],
    action: async (ctx) => {
        const key = ctx.flags.key;
        let value = ctx.flags.value || ctx.args[0];
        const namespace = ctx.flags.namespace;
        const ttl = ctx.flags.ttl;
        const tags = ctx.flags.tags ? ctx.flags.tags.split(',') : [];
        const asVector = ctx.flags.vector;
        const upsert = ctx.flags.upsert;
        if (!key) {
            output.printError('Key is required. Use --key or -k');
            return { success: false, exitCode: 1 };
        }
        if (!value && ctx.interactive) {
            value = await input({
                message: 'Enter value to store:',
                validate: (v) => v.length > 0 || 'Value is required'
            });
        }
        if (!value) {
            output.printError('Value is required. Use --value');
            return { success: false, exitCode: 1 };
        }
        const storeData = {
            key,
            namespace,
            value,
            ttl,
            tags,
            asVector,
            storedAt: new Date().toISOString(),
            size: Buffer.byteLength(value, 'utf8')
        };
        output.printInfo(`Storing in ${namespace}/${key}...`);
        // Use direct sql.js storage with automatic embedding generation
        try {
            const { storeEntry, resolveDbPath: _rdbStore } = await import('../memory/memory-initializer.js');
            const dbPath = _rdbStore(ctx.flags.path);
            if (asVector) {
                output.writeln(output.dim('  Generating embedding vector...'));
            }
            const result = await storeEntry({
                key,
                value,
                namespace,
                generateEmbeddingFlag: true, // Always generate embeddings for semantic search
                tags,
                ttl,
                upsert,
                dbPath
            });
            if (!result.success) {
                output.printError(result.error || 'Failed to store');
                return { success: false, exitCode: 1 };
            }
            output.writeln();
            output.printTable({
                columns: [
                    { key: 'property', header: 'Property', width: 15 },
                    { key: 'val', header: 'Value', width: 40 }
                ],
                data: [
                    { property: 'Key', val: key },
                    { property: 'Namespace', val: namespace },
                    { property: 'Size', val: `${storeData.size} bytes` },
                    { property: 'TTL', val: ttl ? `${ttl}s` : 'None' },
                    { property: 'Tags', val: tags.length > 0 ? tags.join(', ') : 'None' },
                    { property: 'Vector', val: result.embedding ? `Yes (${result.embedding.dimensions}-dim)` : 'No' },
                    { property: 'ID', val: result.id.substring(0, 20) }
                ]
            });
            output.writeln();
            output.printSuccess('Data stored successfully');
            return { success: true, data: { ...storeData, id: result.id, embedding: result.embedding } };
        }
        catch (error) {
            output.printError(`Failed to store: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Retrieve command
const retrieveCommand = {
    name: 'retrieve',
    aliases: ['get'],
    description: 'Retrieve data from memory',
    options: [
        {
            name: 'key',
            short: 'k',
            description: 'Storage key',
            type: 'string'
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Memory namespace',
            type: 'string',
            default: 'default'
        },
        // #2073: --format is the GLOBAL option (parser.ts:78) with choices
        // ['text', 'json', 'table'] and default 'text'. The retrieve handler
        // discriminates: 'json' emits parseable JSON, anything else (text/box/...)
        // emits the human-readable box. No per-command override needed; we just
        // document the behavior in the help text via examples.
        {
            // #2073: --value-only emits ONLY the value string (no wrapper).
            // Designed for piping into JSON.parse without any cleanup.
            name: 'value-only',
            description: 'Print only the stored value to stdout (no wrapper)',
            type: 'boolean',
            default: false
        },
        DB_PATH_OPTION
    ],
    action: async (ctx) => {
        const key = ctx.flags.key || ctx.args[0];
        const namespace = ctx.flags.namespace;
        if (!key) {
            output.printError('Key is required');
            return { success: false, exitCode: 1 };
        }
        // Use sql.js directly for consistent data access
        try {
            const { getEntry, resolveDbPath: _rdbRetrieve } = await import('../memory/memory-initializer.js');
            const dbPathRetrieve = _rdbRetrieve(ctx.flags.path);
            const result = await getEntry({ key, namespace, dbPath: dbPathRetrieve });
            if (!result.success) {
                output.printError(`Failed to retrieve: ${result.error}`);
                return { success: false, exitCode: 1 };
            }
            if (!result.found || !result.entry) {
                output.printWarning(`Key not found: ${key}`);
                return { success: false, exitCode: 1, data: { key, found: false } };
            }
            const entry = result.entry;
            // #2073: --value-only emits just the raw value (no decoration) for
            // piping into JSON.parse / jq / other downstream parsers without
            // any cleanup.
            if (ctx.flags['value-only'] || ctx.flags.valueOnly) {
                // Use process.stdout.write directly to bypass any printer-side
                // transformation of quotes/structural characters.
                process.stdout.write(entry.content);
                if (process.stdout.isTTY)
                    process.stdout.write('\n');
                return { success: true, data: entry };
            }
            if (ctx.flags.format === 'json') {
                output.printJson(entry);
                return { success: true, data: entry };
            }
            output.writeln();
            output.printBox([
                `Namespace: ${entry.namespace}`,
                `Key: ${entry.key}`,
                `Size: ${entry.content.length} bytes`,
                `Access Count: ${entry.accessCount}`,
                `Tags: ${entry.tags.length > 0 ? entry.tags.join(', ') : 'None'}`,
                `Vector: ${entry.hasEmbedding ? 'Yes' : 'No'}`,
                '',
                output.bold('Value:'),
                entry.content
            ].join('\n'), 'Memory Entry');
            return { success: true, data: entry };
        }
        catch (error) {
            output.printError(`Failed to retrieve: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Search command
const searchCommand = {
    name: 'search',
    description: 'Search memory with semantic/vector search',
    options: [
        {
            name: 'query',
            short: 'q',
            description: 'Search query',
            type: 'string',
            required: true
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Memory namespace',
            type: 'string'
        },
        {
            name: 'limit',
            short: 'l',
            description: 'Maximum results',
            type: 'number',
            default: 10
        },
        {
            name: 'threshold',
            description: 'Similarity threshold (0-1)',
            type: 'number',
            default: 0.7
        },
        {
            name: 'type',
            short: 't',
            description: 'Search type (semantic, keyword, hybrid)',
            type: 'string',
            default: 'semantic',
            choices: ['semantic', 'keyword', 'hybrid']
        },
        {
            name: 'build-hnsw',
            description: 'Build/rebuild HNSW index before searching (enables 150x-12,500x speedup)',
            type: 'boolean',
            default: false
        },
        {
            name: 'smart',
            short: 's',
            description: 'Use SmartRetrieval pipeline (query expansion, RRF, MMR, recency)',
            type: 'boolean',
            default: false
        },
        DB_PATH_OPTION
    ],
    examples: [
        { command: 'claude-flow memory search -q "authentication patterns"', description: 'Semantic search' },
        { command: 'claude-flow memory search -q "JWT" -t keyword', description: 'Keyword search' },
        { command: 'claude-flow memory search -q "test" --build-hnsw', description: 'Build HNSW index and search' },
        { command: 'claude-flow memory search -q "auth patterns" --smart', description: 'SmartRetrieval with RRF + MMR' }
    ],
    action: async (ctx) => {
        const query = ctx.flags.query || ctx.args[0];
        const namespace = ctx.flags.namespace || 'all';
        const limit = ctx.flags.limit || 10;
        const threshold = ctx.flags.threshold || 0.3;
        const searchType = ctx.flags.type || 'semantic';
        const buildHnsw = (ctx.flags['build-hnsw'] || ctx.flags.buildHnsw);
        if (!query) {
            output.printError('Query is required. Use --query or -q');
            return { success: false, exitCode: 1 };
        }
        // Build/rebuild HNSW index if requested
        if (buildHnsw) {
            output.printInfo('Building HNSW index...');
            try {
                const { getHNSWIndex, getHNSWStatus } = await import('../memory/memory-initializer.js');
                const startTime = Date.now();
                const index = await getHNSWIndex({ forceRebuild: true });
                const buildTime = Date.now() - startTime;
                if (index) {
                    const status = getHNSWStatus();
                    output.printSuccess(`HNSW index built (${status.entryCount} vectors, ${buildTime}ms)`);
                    output.writeln(output.dim(`  Dimensions: ${status.dimensions}, Metric: cosine`));
                    output.writeln(output.dim(`  Search speedup: ${status.entryCount > 10000 ? '12,500x' : status.entryCount > 1000 ? '150x' : '10x'}`));
                }
                else {
                    output.printWarning('HNSW index not available (install @ruvector/core for acceleration)');
                }
                output.writeln();
            }
            catch (error) {
                output.printWarning(`HNSW build failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
                output.writeln(output.dim('  Falling back to brute-force search'));
                output.writeln();
            }
        }
        output.printInfo(`Searching: "${query}" (${searchType})`);
        output.writeln();
        // Use direct sql.js search with vector similarity
        try {
            const { searchEntries, resolveDbPath: _rdbSearch } = await import('../memory/memory-initializer.js');
            const dbPathSearch = _rdbSearch(ctx.flags.path);
            const useSmart = (ctx.flags.smart || ctx.flags.s);
            let results;
            let searchTimeMs;
            let smartStats;
            let backendLabel = 'HNSW + sql.js';
            // #1846: feature-detect smartSearch — older published builds of
            // @claude-flow/memory don't expose it. Fall through to plain
            // semantic search with a one-line warning instead of throwing.
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            let smartSearchFn;
            if (useSmart) {
                try {
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    const memMod = await import('@claude-flow/memory');
                    if (typeof memMod.smartSearch === 'function') {
                        smartSearchFn = memMod.smartSearch;
                    }
                }
                catch {
                    /* memory package not loadable */
                }
                if (!smartSearchFn) {
                    output.printWarning('Smart search requested but smartSearch is not available on the installed @claude-flow/memory build (#1846). Falling back to standard semantic search.');
                }
            }
            if (useSmart && smartSearchFn) {
                // Adapt searchEntries to the SearchFn interface
                const rawSearch = async (req) => {
                    const r = await searchEntries({
                        query: req.query,
                        namespace: req.namespace || namespace,
                        limit: req.limit || limit * 3,
                        threshold: req.threshold ?? threshold,
                        dbPath: dbPathSearch,
                    });
                    return {
                        results: r.results.map(e => ({
                            id: e.id,
                            key: e.key,
                            content: e.content,
                            score: e.score,
                            namespace: e.namespace,
                        })),
                    };
                };
                const smartResult = await smartSearchFn(rawSearch, {
                    query,
                    namespace,
                    limit,
                    threshold,
                });
                results = smartResult.results.map((r) => ({
                    key: r.key,
                    score: r.score,
                    namespace: r.namespace,
                    preview: r.content,
                }));
                searchTimeMs = smartResult.stats.durationMs;
                smartStats = smartResult.stats;
                backendLabel = 'SmartRetrieval (RRF + MMR + Recency)';
            }
            else {
                const searchResult = await searchEntries({
                    query,
                    namespace,
                    limit,
                    threshold,
                    dbPath: dbPathSearch
                });
                if (!searchResult.success) {
                    output.printError(searchResult.error || 'Search failed');
                    return { success: false, exitCode: 1 };
                }
                results = searchResult.results.map(r => ({
                    key: r.key,
                    score: r.score,
                    namespace: r.namespace,
                    preview: r.content
                }));
                searchTimeMs = searchResult.searchTime;
            }
            if (ctx.flags.format === 'json') {
                output.printJson({ query, searchType, results, searchTime: `${searchTimeMs}ms`, ...(smartStats ? { stats: smartStats } : {}) });
                return { success: true, data: results };
            }
            // Performance stats
            output.writeln(output.dim(`  Search time: ${searchTimeMs}ms`));
            if (useSmart && smartStats) {
                output.writeln(output.dim(`  Backend: ${backendLabel}`));
                output.writeln(output.dim(`  Variants: ${smartStats.variantCount}, Raw candidates: ${smartStats.rawCandidateCount}`));
            }
            output.writeln();
            if (results.length === 0) {
                output.printWarning('No results found');
                output.writeln(output.dim('Try: claude-flow memory store -k "key" --value "data"'));
                return { success: true, data: [] };
            }
            output.printTable({
                columns: [
                    { key: 'key', header: 'Key', width: 20 },
                    { key: 'score', header: 'Score', width: 8, align: 'right', format: (v) => Number(v).toFixed(2) },
                    { key: 'namespace', header: 'Namespace', width: 12 },
                    { key: 'preview', header: 'Preview', width: 35 }
                ],
                data: results
            });
            output.writeln();
            output.printInfo(`Found ${results.length} results`);
            return { success: true, data: results };
        }
        catch (error) {
            output.printError(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// List command
const listCommand = {
    name: 'list',
    aliases: ['ls'],
    description: 'List memory entries',
    options: [
        {
            name: 'namespace',
            short: 'n',
            description: 'Filter by namespace',
            type: 'string'
        },
        {
            name: 'tags',
            short: 't',
            description: 'Filter by tags (comma-separated)',
            type: 'string'
        },
        {
            name: 'limit',
            short: 'l',
            description: 'Maximum entries',
            type: 'number',
            default: 20
        },
        DB_PATH_OPTION
    ],
    action: async (ctx) => {
        const namespace = ctx.flags.namespace;
        const limit = ctx.flags.limit;
        // Use sql.js directly for consistent data access
        try {
            const { listEntries, resolveDbPath: _rdbList } = await import('../memory/memory-initializer.js');
            const dbPathList = _rdbList(ctx.flags.path);
            const listResult = await listEntries({ namespace, limit, offset: 0, dbPath: dbPathList });
            if (!listResult.success) {
                output.printError(`Failed to list: ${listResult.error}`);
                return { success: false, exitCode: 1 };
            }
            // Format entries for display
            const entries = listResult.entries.map(e => ({
                key: e.key,
                namespace: e.namespace,
                size: e.size + ' B',
                vector: e.hasEmbedding ? '✓' : '-',
                accessCount: e.accessCount,
                updated: formatRelativeTime(e.updatedAt)
            }));
            if (ctx.flags.format === 'json') {
                output.printJson(listResult.entries);
                return { success: true, data: listResult.entries };
            }
            output.writeln();
            output.writeln(output.bold('Memory Entries'));
            output.writeln();
            if (entries.length === 0) {
                output.printWarning('No entries found');
                output.printInfo('Store data: claude-flow memory store -k "key" --value "data"');
                return { success: true, data: [] };
            }
            output.printTable({
                columns: [
                    { key: 'key', header: 'Key', width: 25 },
                    { key: 'namespace', header: 'Namespace', width: 12 },
                    { key: 'size', header: 'Size', width: 10, align: 'right' },
                    { key: 'vector', header: 'Vector', width: 8, align: 'center' },
                    { key: 'accessCount', header: 'Accessed', width: 10, align: 'right' },
                    { key: 'updated', header: 'Updated', width: 12 }
                ],
                data: entries
            });
            output.writeln();
            output.printInfo(`Showing ${entries.length} of ${listResult.total} entries`);
            return { success: true, data: listResult.entries };
        }
        catch (error) {
            output.printError(`Failed to list: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Helper function to format relative time
function formatRelativeTime(isoDate) {
    const now = Date.now();
    const date = new Date(isoDate).getTime();
    const diff = now - date;
    const seconds = Math.floor(diff / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    const days = Math.floor(hours / 24);
    if (days > 0)
        return `${days}d ago`;
    if (hours > 0)
        return `${hours}h ago`;
    if (minutes > 0)
        return `${minutes}m ago`;
    return 'just now';
}
// Delete command
const deleteCommand = {
    name: 'delete',
    aliases: ['rm'],
    description: 'Delete memory entry',
    options: [
        {
            name: 'key',
            short: 'k',
            description: 'Storage key',
            type: 'string'
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Memory namespace',
            type: 'string',
            default: 'default'
        },
        {
            name: 'force',
            short: 'f',
            description: 'Skip confirmation',
            type: 'boolean',
            default: false
        },
        DB_PATH_OPTION
    ],
    examples: [
        { command: 'claude-flow memory delete -k "mykey"', description: 'Delete entry with default namespace' },
        { command: 'claude-flow memory delete -k "lesson" -n "lessons"', description: 'Delete entry from specific namespace' },
        { command: 'claude-flow memory delete mykey -f', description: 'Delete without confirmation' }
    ],
    action: async (ctx) => {
        // Support both --key flag and positional argument
        const key = ctx.flags.key || ctx.args[0];
        const namespace = ctx.flags.namespace || 'default';
        const force = ctx.flags.force;
        if (!key) {
            output.printError('Key is required. Use: memory delete -k "key" [-n "namespace"]');
            return { success: false, exitCode: 1 };
        }
        if (!force && ctx.interactive) {
            const confirmed = await confirm({
                message: `Delete memory entry "${key}" from namespace "${namespace}"?`,
                default: false
            });
            if (!confirmed) {
                output.printInfo('Operation cancelled');
                return { success: true };
            }
        }
        // Use sql.js directly for consistent data access (Issue #980)
        try {
            const { deleteEntry, resolveDbPath: _rdbDelete } = await import('../memory/memory-initializer.js');
            const dbPathDelete = _rdbDelete(ctx.flags.path);
            const result = await deleteEntry({ key, namespace, dbPath: dbPathDelete });
            if (!result.success) {
                output.printError(result.error || 'Failed to delete');
                return { success: false, exitCode: 1 };
            }
            if (result.deleted) {
                output.printSuccess(`Deleted "${key}" from namespace "${namespace}"`);
                output.printInfo(`Remaining entries: ${result.remainingEntries}`);
            }
            else {
                output.printWarning(`Key not found: "${key}" in namespace "${namespace}"`);
            }
            return { success: result.deleted, data: result };
        }
        catch (error) {
            output.printError(`Failed to delete: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Stats command
const statsCommand = {
    name: 'stats',
    description: 'Show memory statistics',
    options: [DB_PATH_OPTION],
    action: async (ctx) => {
        // Call MCP memory/stats tool for real statistics
        try {
            const statsResult = await callMCPTool('memory_stats', {});
            const stats = {
                backend: statsResult.backend,
                entries: {
                    total: statsResult.totalEntries,
                    vectors: 0, // Would need vector backend support
                    text: statsResult.totalEntries
                },
                storage: {
                    total: statsResult.totalSize,
                    location: statsResult.location
                },
                version: statsResult.version,
                oldestEntry: statsResult.oldestEntry,
                newestEntry: statsResult.newestEntry
            };
            if (ctx.flags.format === 'json') {
                output.printJson(stats);
                return { success: true, data: stats };
            }
            output.writeln();
            output.writeln(output.bold('Memory Statistics'));
            output.writeln();
            output.writeln(output.bold('Overview'));
            output.printTable({
                columns: [
                    { key: 'metric', header: 'Metric', width: 20 },
                    { key: 'value', header: 'Value', width: 30, align: 'right' }
                ],
                data: [
                    { metric: 'Backend', value: stats.backend },
                    { metric: 'Version', value: stats.version },
                    { metric: 'Total Entries', value: stats.entries.total.toLocaleString() },
                    { metric: 'Total Storage', value: stats.storage.total },
                    { metric: 'Location', value: stats.storage.location }
                ]
            });
            output.writeln();
            output.writeln(output.bold('Timeline'));
            output.printTable({
                columns: [
                    { key: 'metric', header: 'Metric', width: 20 },
                    { key: 'value', header: 'Value', width: 30, align: 'right' }
                ],
                data: [
                    { metric: 'Oldest Entry', value: stats.oldestEntry || 'N/A' },
                    { metric: 'Newest Entry', value: stats.newestEntry || 'N/A' }
                ]
            });
            // #1622 — Surface the active embedding provider in `memory stats` so
            // users can tell which backend resolved at runtime (the 6-level
            // fallback chain in loadEmbeddingModel ranges from full ONNX to a
            // 128-dim hash that has no semantic understanding). Calling
            // loadEmbeddingModel() is cheap when the model is already cached;
            // a fresh call still resolves quickly because we only need the
            // metadata, not a real embedding.
            try {
                const { loadEmbeddingModel, getHNSWStatus } = await import('../memory/memory-initializer.js');
                const embedding = await loadEmbeddingModel({ verbose: false });
                const hnsw = getHNSWStatus();
                // Map model name → semantic capability so users can spot the
                // hash-fallback case without reading docs.
                const semanticProviders = new Set([
                    'Xenova/all-MiniLM-L6-v2',
                    'Xenova/all-mpnet-base-v2',
                    'Xenova/bge-small-en-v1.5',
                    'agentic-flow',
                    'agentic-flow/reasoningbank',
                    'ruvector/onnx',
                    'cached',
                ]);
                const isSemantic = embedding.success && semanticProviders.has(embedding.modelName);
                output.writeln();
                output.writeln(output.bold('Embedding'));
                output.printTable({
                    columns: [
                        { key: 'metric', header: 'Metric', width: 20 },
                        { key: 'value', header: 'Value', width: 30, align: 'right' }
                    ],
                    data: [
                        {
                            metric: 'Provider',
                            value: embedding.success
                                ? embedding.modelName
                                : output.warning(`unavailable: ${embedding.error || 'unknown'}`),
                        },
                        { metric: 'Dimensions', value: String(embedding.dimensions) },
                        {
                            metric: 'Semantic Search',
                            value: isSemantic
                                ? output.success('yes')
                                : output.warning('no — using hash fallback'),
                        },
                        {
                            metric: 'HNSW Index',
                            // ruflo#1989 / #1987: `hnsw.entryCount` is in-process JS state
                            // (the live HNSW index of the current Node process). A fresh
                            // `memory stats` invocation has never indexed anything, so it
                            // reports 0 even when the persistent DB has thousands of
                            // entries with embeddings. Use the persistent count from the
                            // MCP tool (`entriesWithEmbeddings`, which is the actual
                            // count of rows that have a vector) as the source of truth.
                            value: (() => {
                                const persisted = typeof statsResult.entriesWithEmbeddings === 'number'
                                    ? statsResult.entriesWithEmbeddings
                                    : null;
                                const live = hnsw.entryCount || 0;
                                const total = persisted !== null ? Math.max(persisted, live) : live;
                                if (!hnsw.available)
                                    return output.dim('not active');
                                if (total === 0)
                                    return output.warning('available but not initialized');
                                return output.success(`active (${total.toLocaleString()} entries)`);
                            })(),
                        },
                    ]
                });
            }
            catch (e) {
                // Don't fail the whole stats command if introspection breaks —
                // the rest of the dashboard is still useful.
                output.writeln();
                output.writeln(output.bold('Embedding'));
                output.printInfo(`Provider info unavailable: ${e instanceof Error ? e.message : String(e)}`);
            }
            output.writeln();
            output.printInfo('V3 Performance: 150x-12,500x faster search with HNSW indexing');
            return { success: true, data: stats };
        }
        catch (error) {
            output.printError(`Failed to get stats: ${error instanceof Error ? error.message : 'Unknown error'}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Configure command
const configureCommand = {
    name: 'configure',
    aliases: ['config'],
    description: 'Configure memory backend',
    options: [
        {
            name: 'backend',
            short: 'b',
            description: 'Memory backend',
            type: 'string',
            choices: BACKENDS.map(b => b.value)
        },
        {
            name: 'path',
            description: 'Storage path',
            type: 'string'
        },
        {
            name: 'cache-size',
            description: 'Cache size in MB',
            type: 'number'
        },
        {
            name: 'hnsw-m',
            description: 'HNSW M parameter',
            type: 'number',
            default: 16
        },
        {
            name: 'hnsw-ef',
            description: 'HNSW ef parameter',
            type: 'number',
            default: 200
        }
    ],
    action: async (ctx) => {
        let backend = ctx.flags.backend;
        if (!backend && ctx.interactive) {
            backend = await select({
                message: 'Select memory backend:',
                options: BACKENDS,
                default: 'hybrid'
            });
        }
        const config = {
            backend: backend || 'hybrid',
            path: ctx.flags.path || './data/memory',
            cacheSize: ctx.flags.cacheSize || 256,
            hnsw: {
                m: ctx.flags.hnswM || 16,
                ef: ctx.flags.hnswEf || 200
            }
        };
        output.writeln();
        output.printInfo('Memory Configuration');
        output.writeln();
        output.printTable({
            columns: [
                { key: 'setting', header: 'Setting', width: 20 },
                { key: 'value', header: 'Value', width: 25 }
            ],
            data: [
                { setting: 'Backend', value: config.backend },
                { setting: 'Storage Path', value: config.path },
                { setting: 'Cache Size', value: `${config.cacheSize} MB` },
                { setting: 'HNSW M', value: config.hnsw.m },
                { setting: 'HNSW ef', value: config.hnsw.ef }
            ]
        });
        output.writeln();
        output.printSuccess('Memory configuration updated');
        return { success: true, data: config };
    }
};
// Cleanup command
const cleanupCommand = {
    name: 'cleanup',
    description: 'Clean up stale and expired memory entries',
    options: [
        {
            name: 'dry-run',
            short: 'd',
            description: 'Show what would be deleted',
            type: 'boolean',
            default: false
        },
        {
            name: 'older-than',
            short: 'o',
            description: 'Delete entries older than (e.g., "7d", "30d")',
            type: 'string'
        },
        {
            name: 'expired-only',
            short: 'e',
            description: 'Only delete expired TTL entries',
            type: 'boolean',
            default: false
        },
        {
            name: 'low-quality',
            short: 'l',
            description: 'Delete low quality patterns (threshold)',
            type: 'number'
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Clean specific namespace only',
            type: 'string'
        },
        {
            name: 'force',
            short: 'f',
            description: 'Skip confirmation',
            type: 'boolean',
            default: false
        }
    ],
    examples: [
        { command: 'claude-flow memory cleanup --dry-run', description: 'Preview cleanup' },
        { command: 'claude-flow memory cleanup --older-than 30d', description: 'Delete entries older than 30 days' },
        { command: 'claude-flow memory cleanup --expired-only', description: 'Clean expired entries' }
    ],
    action: async (ctx) => {
        const dryRun = ctx.flags.dryRun;
        const force = ctx.flags.force;
        if (dryRun) {
            output.writeln(output.warning('DRY RUN - No changes will be made'));
        }
        output.printInfo('Analyzing memory for cleanup...');
        try {
            const result = await callMCPTool('memory_cleanup', {
                dryRun,
                olderThan: ctx.flags.olderThan,
                expiredOnly: ctx.flags.expiredOnly,
                lowQualityThreshold: ctx.flags.lowQuality,
                namespace: ctx.flags.namespace,
            });
            if (ctx.flags.format === 'json') {
                output.printJson(result);
                return { success: true, data: result };
            }
            output.writeln();
            output.writeln(output.bold('Cleanup Analysis'));
            output.printTable({
                columns: [
                    { key: 'category', header: 'Category', width: 20 },
                    { key: 'count', header: 'Count', width: 15, align: 'right' }
                ],
                data: [
                    { category: 'Expired (TTL)', count: result.candidates.expired },
                    { category: 'Stale (unused)', count: result.candidates.stale },
                    { category: 'Low Quality', count: result.candidates.lowQuality },
                    { category: output.bold('Total'), count: output.bold(String(result.candidates.total)) }
                ]
            });
            if (!dryRun && result.candidates.total > 0 && !force) {
                const confirmed = await confirm({
                    message: `Delete ${result.candidates.total} entries (${result.freed.formatted})?`,
                    default: false
                });
                if (!confirmed) {
                    output.printInfo('Cleanup cancelled');
                    return { success: true, data: result };
                }
            }
            if (!dryRun) {
                output.writeln();
                output.printSuccess(`Cleaned ${result.deleted.entries} entries`);
                output.printList([
                    `Vectors removed: ${result.deleted.vectors}`,
                    `Patterns removed: ${result.deleted.patterns}`,
                    `Space freed: ${result.freed.formatted}`,
                    `Duration: ${result.duration}ms`
                ]);
            }
            return { success: true, data: result };
        }
        catch (error) {
            if (error instanceof MCPClientError) {
                output.printError(`Cleanup error: ${error.message}`);
            }
            else {
                output.printError(`Unexpected error: ${String(error)}`);
            }
            return { success: false, exitCode: 1 };
        }
    }
};
// Compress command
const compressCommand = {
    name: 'compress',
    description: 'Compress and optimize memory storage',
    options: [
        {
            name: 'level',
            short: 'l',
            description: 'Compression level (fast, balanced, max)',
            type: 'string',
            choices: ['fast', 'balanced', 'max'],
            default: 'balanced'
        },
        {
            name: 'target',
            short: 't',
            description: 'Target (vectors, text, patterns, all)',
            type: 'string',
            choices: ['vectors', 'text', 'patterns', 'all'],
            default: 'all'
        },
        {
            name: 'quantize',
            short: 'z',
            description: 'Enable vector quantization (reduces memory 4-32x)',
            type: 'boolean',
            default: false
        },
        {
            name: 'bits',
            description: 'Quantization bits (4, 8, 16)',
            type: 'number',
            default: 8
        },
        {
            name: 'rebuild-index',
            short: 'r',
            description: 'Rebuild HNSW index after compression',
            type: 'boolean',
            default: true
        }
    ],
    examples: [
        { command: 'claude-flow memory compress', description: 'Balanced compression' },
        { command: 'claude-flow memory compress --quantize --bits 4', description: '4-bit quantization (32x reduction)' },
        { command: 'claude-flow memory compress -l max -t vectors', description: 'Max compression on vectors' }
    ],
    action: async (ctx) => {
        const level = ctx.flags.level || 'balanced';
        const target = ctx.flags.target || 'all';
        const quantize = ctx.flags.quantize;
        const bits = ctx.flags.bits || 8;
        const rebuildIndex = ctx.flags.rebuildIndex ?? true;
        output.writeln();
        output.writeln(output.bold('Memory Compression'));
        output.writeln(output.dim(`Level: ${level}, Target: ${target}, Quantize: ${quantize ? `${bits}-bit` : 'no'}`));
        output.writeln();
        const spinner = output.createSpinner({ text: 'Analyzing current storage...', spinner: 'dots' });
        spinner.start();
        try {
            const result = await callMCPTool('memory_compress', {
                level,
                target,
                quantize,
                bits,
                rebuildIndex,
            });
            spinner.succeed('Compression complete');
            if (ctx.flags.format === 'json') {
                output.printJson(result);
                return { success: true, data: result };
            }
            output.writeln();
            output.writeln(output.bold('Storage Comparison'));
            output.printTable({
                columns: [
                    { key: 'category', header: 'Category', width: 15 },
                    { key: 'before', header: 'Before', width: 12, align: 'right' },
                    { key: 'after', header: 'After', width: 12, align: 'right' },
                    { key: 'saved', header: 'Saved', width: 12, align: 'right' }
                ],
                data: [
                    { category: 'Vectors', before: result.before.vectorsSize, after: result.after.vectorsSize, saved: '-' },
                    { category: 'Text', before: result.before.textSize, after: result.after.textSize, saved: '-' },
                    { category: 'Patterns', before: result.before.patternsSize, after: result.after.patternsSize, saved: '-' },
                    { category: 'Index', before: result.before.indexSize, after: result.after.indexSize, saved: '-' },
                    { category: output.bold('Total'), before: result.before.totalSize, after: result.after.totalSize, saved: output.success(result.compression.formattedSaved) }
                ]
            });
            output.writeln();
            output.printBox([
                `Compression Ratio: ${result.compression.ratio.toFixed(2)}x`,
                `Space Saved: ${result.compression.formattedSaved}`,
                `Quantization: ${result.compression.quantizationApplied ? `Yes (${bits}-bit)` : 'No'}`,
                `Index Rebuilt: ${result.compression.indexRebuilt ? 'Yes' : 'No'}`,
                `Duration: ${(result.duration / 1000).toFixed(1)}s`
            ].join('\n'), 'Results');
            if (result.performance) {
                output.writeln();
                output.writeln(output.bold('Performance Impact'));
                output.printList([
                    `Search latency: ${result.performance.searchLatencyBefore.toFixed(2)}ms → ${result.performance.searchLatencyAfter.toFixed(2)}ms`,
                    `Speedup: ${output.success(result.performance.searchSpeedup)}`
                ]);
            }
            return { success: true, data: result };
        }
        catch (error) {
            spinner.fail('Compression failed');
            if (error instanceof MCPClientError) {
                output.printError(`Compression error: ${error.message}`);
            }
            else {
                output.printError(`Unexpected error: ${String(error)}`);
            }
            return { success: false, exitCode: 1 };
        }
    }
};
// Export command
const exportCommand = {
    name: 'export',
    description: 'Export memory to file',
    options: [
        {
            name: 'output',
            short: 'o',
            description: 'Output file path',
            type: 'string',
            required: true
        },
        {
            name: 'format',
            short: 'f',
            description: 'Export format (json, csv, binary)',
            type: 'string',
            choices: ['json', 'csv', 'binary'],
            default: 'json'
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Export specific namespace',
            type: 'string'
        },
        {
            name: 'include-vectors',
            description: 'Include vector embeddings',
            type: 'boolean',
            default: true
        }
    ],
    examples: [
        { command: 'claude-flow memory export -o ./backup.json', description: 'Export all to JSON' },
        { command: 'claude-flow memory export -o ./data.csv -f csv', description: 'Export to CSV' }
    ],
    action: async (ctx) => {
        const outputPath = ctx.flags.output;
        const format = ctx.flags.format || 'json';
        if (!outputPath) {
            output.printError('Output path is required. Use --output or -o');
            return { success: false, exitCode: 1 };
        }
        output.printInfo(`Exporting memory to ${outputPath}...`);
        try {
            const result = await callMCPTool('memory_export', {
                outputPath,
                format,
                namespace: ctx.flags.namespace,
                includeVectors: ctx.flags.includeVectors ?? true,
            });
            output.printSuccess(`Exported to ${result.outputPath}`);
            output.printList([
                `Entries: ${result.exported.entries}`,
                `Vectors: ${result.exported.vectors}`,
                `Patterns: ${result.exported.patterns}`,
                `File size: ${result.fileSize}`
            ]);
            return { success: true, data: result };
        }
        catch (error) {
            if (error instanceof MCPClientError) {
                output.printError(`Export error: ${error.message}`);
            }
            else {
                output.printError(`Unexpected error: ${String(error)}`);
            }
            return { success: false, exitCode: 1 };
        }
    }
};
// Import command
const importCommand = {
    name: 'import',
    description: 'Import memory from file',
    options: [
        {
            name: 'input',
            short: 'i',
            description: 'Input file path',
            type: 'string',
            required: true
        },
        {
            name: 'merge',
            short: 'm',
            description: 'Merge with existing (skip duplicates)',
            type: 'boolean',
            default: true
        },
        {
            name: 'namespace',
            short: 'n',
            description: 'Import into specific namespace',
            type: 'string'
        }
    ],
    examples: [
        { command: 'claude-flow memory import -i ./backup.json', description: 'Import from file' },
        { command: 'claude-flow memory import -i ./data.json -n archive', description: 'Import to namespace' }
    ],
    action: async (ctx) => {
        const inputPath = ctx.flags.input || ctx.args[0];
        if (!inputPath) {
            output.printError('Input path is required. Use --input or -i');
            return { success: false, exitCode: 1 };
        }
        output.printInfo(`Importing memory from ${inputPath}...`);
        try {
            const result = await callMCPTool('memory_import', {
                inputPath,
                merge: ctx.flags.merge ?? true,
                namespace: ctx.flags.namespace,
            });
            output.printSuccess(`Imported from ${result.inputPath}`);
            output.printList([
                `Entries: ${result.imported.entries}`,
                `Vectors: ${result.imported.vectors}`,
                `Patterns: ${result.imported.patterns}`,
                `Skipped (duplicates): ${result.skipped}`,
                `Duration: ${result.duration}ms`
            ]);
            return { success: true, data: result };
        }
        catch (error) {
            if (error instanceof MCPClientError) {
                output.printError(`Import error: ${error.message}`);
            }
            else {
                output.printError(`Unexpected error: ${String(error)}`);
            }
            return { success: false, exitCode: 1 };
        }
    }
};
// Init subcommand - initialize memory database using sql.js
const initMemoryCommand = {
    name: 'init',
    description: 'Initialize memory database with sql.js (WASM SQLite) - includes vector embeddings, pattern learning, temporal decay',
    options: [
        {
            name: 'backend',
            short: 'b',
            description: 'Backend type: hybrid (default), sqlite, or agentdb',
            type: 'string',
            default: 'hybrid'
        },
        {
            name: 'path',
            short: 'p',
            description: 'Database path',
            type: 'string'
        },
        {
            name: 'force',
            short: 'f',
            description: 'Overwrite existing database',
            type: 'boolean',
            default: false
        },
        {
            name: 'verbose',
            description: 'Show detailed initialization output',
            type: 'boolean',
            default: false
        },
        {
            name: 'verify',
            description: 'Run verification tests after initialization',
            type: 'boolean',
            default: true
        },
        {
            name: 'load-embeddings',
            description: 'Pre-load ONNX embedding model (lazy by default)',
            type: 'boolean',
            default: false
        }
    ],
    examples: [
        { command: 'claude-flow memory init', description: 'Initialize hybrid backend with all features' },
        { command: 'claude-flow memory init -b agentdb', description: 'Initialize AgentDB backend' },
        { command: 'claude-flow memory init -p ./data/memory.db --force', description: 'Reinitialize at custom path' },
        { command: 'claude-flow memory init --verbose --verify', description: 'Initialize with full verification' }
    ],
    action: async (ctx) => {
        const backend = ctx.flags.backend || 'hybrid';
        const customPath = ctx.flags.path;
        const force = ctx.flags.force;
        const verbose = ctx.flags.verbose;
        const verify = ctx.flags.verify !== false; // Default true
        const loadEmbeddings = ctx.flags.loadEmbeddings;
        output.writeln();
        output.writeln(output.bold('Initializing Memory Database'));
        output.writeln(output.dim('─'.repeat(50)));
        const spinner = output.createSpinner({ text: 'Initializing schema...', spinner: 'dots' });
        spinner.start();
        try {
            // Import the memory initializer
            const { initializeMemoryDatabase, loadEmbeddingModel, verifyMemoryInit } = await import('../memory/memory-initializer.js');
            const result = await initializeMemoryDatabase({
                backend,
                dbPath: customPath,
                force,
                verbose
            });
            if (!result.success) {
                spinner.fail('Initialization failed');
                output.printError(result.error || 'Unknown error');
                return { success: false, exitCode: 1 };
            }
            // #1791.6 — DB already initialized and --force not passed: friendly no-op.
            if (result.alreadyExists) {
                spinner.succeed(`Memory database already initialized at ${result.dbPath}`);
                output.printInfo('Use `--force` to reinitialize from scratch (destructive).');
                return { success: true, exitCode: 0 };
            }
            spinner.succeed('Schema initialized');
            // Lazy load or pre-load embedding model
            if (loadEmbeddings) {
                const embeddingSpinner = output.createSpinner({ text: 'Loading embedding model...', spinner: 'dots' });
                embeddingSpinner.start();
                const embeddingResult = await loadEmbeddingModel({ verbose });
                if (embeddingResult.success) {
                    embeddingSpinner.succeed(`Embedding model loaded: ${embeddingResult.modelName} (${embeddingResult.dimensions}-dim, ${embeddingResult.loadTime}ms)`);
                }
                else {
                    embeddingSpinner.stop(output.warning(`Embedding model: ${embeddingResult.error || 'Using fallback'}`));
                }
            }
            output.writeln();
            // Show features enabled with detailed capabilities
            const featureLines = [
                `Backend:           ${result.backend}`,
                `Schema Version:    ${result.schemaVersion}`,
                `Database Path:     ${result.dbPath}`,
                '',
                output.bold('Features:'),
                `  Vector Embeddings: ${result.features.vectorEmbeddings ? output.success('✓ Enabled') : output.dim('✗ Disabled')}`,
                `  Pattern Learning:  ${result.features.patternLearning ? output.success('✓ Enabled') : output.dim('✗ Disabled')}`,
                `  Temporal Decay:    ${result.features.temporalDecay ? output.success('✓ Enabled') : output.dim('✗ Disabled')}`,
                `  HNSW Indexing:     ${result.features.hnswIndexing ? output.success('✓ Enabled') : output.dim('✗ Disabled')}`,
                `  Migration Tracking: ${result.features.migrationTracking ? output.success('✓ Enabled') : output.dim('✗ Disabled')}`
            ];
            if (verbose) {
                featureLines.push('', output.bold('HNSW Configuration:'), `  M (connections):     16`, `  ef (construction):   200`, `  ef (search):         100`, `  Metric:              cosine`, '', output.bold('Pattern Learning:'), `  Confidence scoring:  0.0 - 1.0`, `  Temporal decay:      Half-life 30 days`, `  Pattern versioning:  Enabled`, `  Types: task-routing, error-recovery, optimization, coordination, prediction`);
            }
            output.printBox(featureLines.join('\n'), 'Configuration');
            output.writeln();
            // ADR-053: Show ControllerRegistry activation results
            if (result.controllers) {
                const { activated, failed, initTimeMs } = result.controllers;
                if (activated.length > 0 || failed.length > 0) {
                    const controllerLines = [
                        output.bold('AgentDB Controllers:'),
                        `  Activated: ${activated.length}  Failed: ${failed.length}  Init: ${Math.round(initTimeMs)}ms`,
                    ];
                    if (verbose && activated.length > 0) {
                        controllerLines.push('');
                        for (const name of activated) {
                            controllerLines.push(`  ${output.success('✓')} ${name}`);
                        }
                    }
                    if (failed.length > 0 && verbose) {
                        controllerLines.push('');
                        for (const name of failed) {
                            controllerLines.push(`  ${output.dim('✗')} ${name}`);
                        }
                    }
                    output.printBox(controllerLines.join('\n'), 'Controller Registry (ADR-053)');
                    output.writeln();
                }
            }
            // Show tables created
            if (verbose && result.tablesCreated.length > 0) {
                output.writeln(output.bold('Tables Created:'));
                output.printTable({
                    columns: [
                        { key: 'table', header: 'Table', width: 22 },
                        { key: 'purpose', header: 'Purpose', width: 38 }
                    ],
                    data: [
                        { table: 'memory_entries', purpose: 'Core memory storage with embeddings' },
                        { table: 'patterns', purpose: 'Learned patterns with confidence scores' },
                        { table: 'pattern_history', purpose: 'Pattern versioning and evolution' },
                        { table: 'trajectories', purpose: 'SONA learning trajectories' },
                        { table: 'trajectory_steps', purpose: 'Individual trajectory steps' },
                        { table: 'migration_state', purpose: 'Migration progress tracking' },
                        { table: 'sessions', purpose: 'Context persistence' },
                        { table: 'vector_indexes', purpose: 'HNSW index configuration' },
                        { table: 'metadata', purpose: 'System metadata' }
                    ]
                });
                output.writeln();
                output.writeln(output.bold('Indexes Created:'));
                output.printList(result.indexesCreated.slice(0, 8).map(idx => output.dim(idx)));
                if (result.indexesCreated.length > 8) {
                    output.writeln(output.dim(`  ... and ${result.indexesCreated.length - 8} more`));
                }
                output.writeln();
            }
            // Run verification if enabled
            if (verify) {
                const verifySpinner = output.createSpinner({ text: 'Verifying initialization...', spinner: 'dots' });
                verifySpinner.start();
                const verification = await verifyMemoryInit(result.dbPath, { verbose });
                if (verification.success) {
                    verifySpinner.succeed(`Verification passed (${verification.summary.passed}/${verification.summary.total} tests)`);
                }
                else {
                    verifySpinner.fail(`Verification failed (${verification.summary.failed}/${verification.summary.total} tests failed)`);
                }
                if (verbose || !verification.success) {
                    output.writeln();
                    output.writeln(output.bold('Verification Results:'));
                    output.printTable({
                        columns: [
                            { key: 'status', header: '', width: 3 },
                            { key: 'name', header: 'Test', width: 22 },
                            { key: 'details', header: 'Details', width: 30 },
                            { key: 'duration', header: 'Time', width: 8, align: 'right' }
                        ],
                        data: verification.tests.map(t => ({
                            status: t.passed ? output.success('✓') : output.error('✗'),
                            name: t.name,
                            details: t.details || '',
                            duration: t.duration ? `${t.duration}ms` : '-'
                        }))
                    });
                }
                output.writeln();
            }
            // Show next steps
            output.writeln(output.bold('Next Steps:'));
            output.printList([
                `Store data: ${output.highlight('claude-flow memory store -k "key" --value "data"')}`,
                `Search: ${output.highlight('claude-flow memory search -q "query"')}`,
                `Train patterns: ${output.highlight('claude-flow neural train -p coordination')}`,
                `View stats: ${output.highlight('claude-flow memory stats')}`
            ]);
            // Also sync to .claude directory
            const fs = await import('fs');
            const path = await import('path');
            const claudeDir = path.join(process.cwd(), '.claude');
            const claudeDbPath = path.join(claudeDir, 'memory.db');
            if (!fs.existsSync(claudeDir)) {
                fs.mkdirSync(claudeDir, { recursive: true });
            }
            if (fs.existsSync(result.dbPath) && (!fs.existsSync(claudeDbPath) || force)) {
                fs.copyFileSync(result.dbPath, claudeDbPath);
                output.writeln();
                output.writeln(output.dim(`Synced to: ${claudeDbPath}`));
            }
            // Fix #1428: ONNX worker threads keep the event loop alive after init.
            // Force-exit after a short delay to allow final I/O to flush.
            if (typeof globalThis !== 'undefined') {
                setTimeout(() => {
                    process.exit(0);
                }, 500).unref();
            }
            return {
                success: true,
                data: result
            };
        }
        catch (error) {
            spinner.fail('Initialization failed');
            output.printError(`Failed to initialize memory: ${error instanceof Error ? error.message : String(error)}`);
            return { success: false, exitCode: 1 };
        }
    }
};
// Main memory command
export const memoryCommand = {
    name: 'memory',
    description: 'Memory management commands',
    subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand],
    options: [],
    examples: [
        { command: 'claude-flow memory store -k "key" -v "value"', description: 'Store data' },
        { command: 'claude-flow memory search -q "auth patterns"', description: 'Search memory' },
        { command: 'claude-flow memory stats', description: 'Show statistics' }
    ],
    action: async (ctx) => {
        output.writeln();
        output.writeln(output.bold('Memory Management Commands'));
        output.writeln();
        output.writeln('Usage: claude-flow memory <subcommand> [options]');
        output.writeln();
        output.writeln('Subcommands:');
        output.printList([
            `${output.highlight('init')}       - Initialize memory database (sql.js)`,
            `${output.highlight('store')}      - Store data in memory`,
            `${output.highlight('retrieve')}   - Retrieve data from memory`,
            `${output.highlight('search')}     - Semantic/vector search`,
            `${output.highlight('list')}       - List memory entries`,
            `${output.highlight('delete')}     - Delete memory entry`,
            `${output.highlight('stats')}      - Show statistics`,
            `${output.highlight('configure')}  - Configure backend`,
            `${output.highlight('cleanup')}    - Clean expired entries`,
            `${output.highlight('compress')}   - Compress database`,
            `${output.highlight('export')}     - Export memory to file`,
            `${output.highlight('import')}     - Import from file`
        ]);
        return { success: true };
    }
};
export default memoryCommand;
//# sourceMappingURL=memory.js.map