diff --git a/ccw/src/core/core-memory-store.ts b/ccw/src/core/core-memory-store.ts index 6d4f6ebc..68c4976e 100644 --- a/ccw/src/core/core-memory-store.ts +++ b/ccw/src/core/core-memory-store.ts @@ -1383,6 +1383,55 @@ export function getMemoriesFromProject(projectId: string): CoreMemory[] { })); } +/** + * Find a memory by ID across all projects + * Searches through all project databases to locate a specific memory + */ +export function findMemoryAcrossProjects(memoryId: string): { memory: CoreMemory; projectId: string } | null { + const projectsDir = join(getCCWHome(), 'projects'); + + if (!existsSync(projectsDir)) { + return null; + } + + const entries = readdirSync(projectsDir, { withFileTypes: true }); + + for (const entry of entries) { + if (!entry.isDirectory()) continue; + + const projectId = entry.name; + const coreMemoryDb = join(projectsDir, projectId, 'core-memory', 'core_memory.db'); + + if (!existsSync(coreMemoryDb)) continue; + + try { + const db = new Database(coreMemoryDb, { readonly: true }); + const row = db.prepare('SELECT * FROM memories WHERE id = ?').get(memoryId) as any; + db.close(); + + if (row) { + return { + memory: { + id: row.id, + content: row.content, + summary: row.summary || '', + raw_output: row.raw_output, + created_at: row.created_at, + updated_at: row.updated_at, + archived: Boolean(row.archived), + metadata: row.metadata + }, + projectId + }; + } + } catch { + // Database might be locked or corrupted, skip + } + } + + return null; +} + /** * Export memories to a JSON file */ diff --git a/ccw/src/tools/core-memory.ts b/ccw/src/tools/core-memory.ts index caa8dfaf..6f5166dc 100644 --- a/ccw/src/tools/core-memory.ts +++ b/ccw/src/tools/core-memory.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import type { ToolSchema, ToolResult } from '../types/tool.js'; -import { getCoreMemoryStore } from '../core/core-memory-store.js'; +import { getCoreMemoryStore, findMemoryAcrossProjects } from '../core/core-memory-store.js'; import * as MemoryEmbedder from '../core/memory-embedder-bridge.js'; import { StoragePaths } from '../config/storage-paths.js'; import { join } from 'path'; @@ -41,9 +41,17 @@ interface CoreMemory { updated_at: string; } +/** Compact memory info for list operation */ +interface CoreMemoryCompact { + id: string; + preview: string; // Truncated content/summary preview + archived: boolean; + updated_at: string; +} + interface ListResult { operation: 'list'; - memories: CoreMemory[]; + memories: CoreMemoryCompact[]; total: number; } @@ -112,18 +120,36 @@ function getDatabasePath(): string { return join(paths.root, 'core-memory', 'core_memory.db'); } +/** Max preview length for list operation */ +const PREVIEW_MAX_LENGTH = 100; + /** * Operation: list - * List all memories + * List all memories with compact output */ function executeList(params: Params): ListResult { const { limit } = params; const store = getCoreMemoryStore(getProjectPath()); const memories = store.getMemories({ limit }) as CoreMemory[]; + // Convert to compact format with truncated preview + const compactMemories: CoreMemoryCompact[] = memories.map((m) => { + const source = m.summary || m.content; + const preview = source.length > PREVIEW_MAX_LENGTH + ? source.substring(0, PREVIEW_MAX_LENGTH) + '...' + : source; + + return { + id: m.id, + preview, + archived: m.archived, + updated_at: m.updated_at, + }; + }); + return { operation: 'list', - memories, + memories: compactMemories, total: memories.length, }; } @@ -154,6 +180,7 @@ function executeImport(params: Params): ImportResult { /** * Operation: export * Export a memory as plain text + * Searches current project first, then all projects if not found */ function executeExport(params: Params): ExportResult { const { id } = params; @@ -162,11 +189,20 @@ function executeExport(params: Params): ExportResult { throw new Error('Parameter "id" is required for export operation'); } + // Try current project first const store = getCoreMemoryStore(getProjectPath()); - const memory = store.getMemory(id); + let memory = store.getMemory(id); + + // If not found, search across all projects + if (!memory) { + const result = findMemoryAcrossProjects(id); + if (result) { + memory = result.memory; + } + } if (!memory) { - throw new Error(`Memory "${id}" not found`); + throw new Error(`Memory "${id}" not found in any project`); } return {