UNPKG

mcard-js

Version:

MCard - Content-addressable storage with cryptographic hashing, handle resolution, and vector search for Node.js and browsers

177 lines 7.24 kB
/** * Handle builtins for CLM execution. * * Implements handle_version and handle_prune operations. */ /** * Execute handle version operation. */ export async function executeHandleVersion(ctx) { const examples = ctx.examples || []; if (examples.length) { return runVersionExamples(examples); } // Single execution mode const inputData = ctx.input || ctx; const handle = inputData.handle || ctx.handle || ''; const versions = inputData.versions || ctx.versions || []; if (!handle) { return { success: false, error: 'handle is required' }; } if (!versions.length) { return { success: false, error: 'versions list is required' }; } return executeVersionSingle(handle, versions); } /** * Execute handle prune operation. */ export async function executeHandlePrune(ctx) { const examples = ctx.examples || []; if (examples.length) { return runPruneExamples(examples); } // Single execution mode const inputData = ctx.input || ctx; const handle = inputData.handle || ctx.handle || ''; const versions = inputData.versions || ctx.versions || []; const pruneType = inputData.prune_type || ctx.prune_type || 'all'; const olderThanSeconds = inputData.older_than_seconds || ctx.older_than_seconds; if (!handle) { return { success: false, error: 'handle is required' }; } return executePruneSingle(handle, versions, pruneType, olderThanSeconds); } // ─── Private Helpers ───────────────────────────────────────────────────────── async function runVersionExamples(examples) { const results = []; for (const example of examples) { const inputData = example.input || example; const handle = inputData.handle || ''; const versions = inputData.versions || []; if (!handle || !versions.length) { results.push({ example_name: example.name || 'unnamed', success: false, error: 'handle and versions required' }); continue; } const result = await executeVersionSingle(handle, versions); result.example_name = example.name || 'unnamed'; // Check expected if provided const expected = example.expected_output || {}; result.passed = expected.history_length !== undefined ? result.history_length === expected.history_length : result.success || false; results.push(result); } return { success: results.every(r => r.passed), results }; } async function executeVersionSingle(handle, versions) { const { SqliteNodeEngine } = await import('../../../../storage/SqliteNodeEngine.js'); const { CardCollection } = await import('../../../../model/CardCollection.js'); const { MCard } = await import('../../../../model/MCard.js'); const engine = new SqliteNodeEngine(':memory:'); const collection = new CardCollection(engine); try { // Add first version const firstContent = versions[0].content || versions[0]; const card = await MCard.create(firstContent); await collection.addWithHandle(card, handle); // Apply subsequent updates for (let i = 1; i < versions.length; i++) { const content = versions[i].content || versions[i]; const newCard = await MCard.create(content); await collection.updateHandle(handle, newCard); } // Get final state const finalCard = await collection.getByHandle(handle); const history = await collection.getHandleHistory(handle); const finalContent = finalCard ? new TextDecoder().decode(finalCard.content) : null; return { success: true, handle, final_hash: finalCard ? finalCard.hash : null, final_content: finalContent, history_length: history.length, history }; } catch (e) { return { success: false, error: e.message }; } } async function runPruneExamples(examples) { const results = []; for (const example of examples) { const inputData = example.input || example; const handle = inputData.handle || ''; const versions = inputData.versions || []; const pruneType = inputData.prune_type || 'all'; const olderThanSeconds = inputData.older_than_seconds; if (!handle) { results.push({ example_name: example.name || 'unnamed', success: false, error: 'handle is required' }); continue; } const result = await executePruneSingle(handle, versions, pruneType, olderThanSeconds); result.example_name = example.name || 'unnamed'; // Check expected if provided const expected = example.expected_output || {}; if (expected.history_after !== undefined) { result.passed = result.history_after === expected.history_after; } else if (expected.deleted !== undefined) { result.passed = result.deleted === expected.deleted; } else { result.passed = result.success || false; } results.push(result); } return { success: results.every(r => r.passed), results }; } async function executePruneSingle(handle, versions, pruneType, olderThanSeconds) { const { SqliteNodeEngine } = await import('../../../../storage/SqliteNodeEngine.js'); const { CardCollection } = await import('../../../../model/CardCollection.js'); const { MCard } = await import('../../../../model/MCard.js'); const engine = new SqliteNodeEngine(':memory:'); const collection = new CardCollection(engine); try { // Setup handle with versions if provided if (versions.length) { const firstContent = versions[0].content || versions[0]; const card = await MCard.create(firstContent); await collection.addWithHandle(card, handle); for (let i = 1; i < versions.length; i++) { const content = versions[i].content || versions[i]; const newCard = await MCard.create(content); await collection.updateHandle(handle, newCard); } } const historyBefore = (await collection.getHandleHistory(handle)).length; let deleted = 0; if (pruneType === 'all') { deleted = await collection.pruneHandleHistory(handle, { deleteAll: true }); } else if (pruneType === 'older_than' && olderThanSeconds !== undefined) { deleted = await collection.pruneHandleHistory(handle, { olderThan: `${olderThanSeconds}s` }); } const historyAfter = (await collection.getHandleHistory(handle)).length; return { success: true, handle, history_before: historyBefore, deleted, history_after: historyAfter }; } catch (e) { return { success: false, error: e.message }; } } //# sourceMappingURL=handle.js.map