UNPKG

@vibe-validate/history

Version:

Validation history tracking via git notes for vibe-validate

138 lines 4.6 kB
/** * Run cache reader - Read run cache entries from git notes * * Run cache is stored at: refs/notes/vibe-validate/run/{treeHash}/{cacheKey} * where cacheKey = encodeURIComponent(workdir ? `${workdir}:${command}` : command) */ import { execSync } from 'node:child_process'; import { parse as parseYaml } from 'yaml'; const GIT_TIMEOUT = 30000; const GIT_OPTIONS = { encoding: 'utf8', timeout: GIT_TIMEOUT, stdio: ['pipe', 'pipe', 'ignore'], }; /** * List all run cache entries for a tree hash * * @param treeHash - Git tree hash * @returns Array of run cache entry metadata */ export async function listRunCacheEntries(treeHash) { try { // List all notes under refs/notes/vibe-validate/run/{treeHash}/* const output = execSync(`git for-each-ref --format="%(refname) %(objectname)" refs/notes/vibe-validate/run/${treeHash}/`, GIT_OPTIONS); if (!output.trim()) { return []; } // Parse output: "refs/notes/vibe-validate/run/{treeHash}/{cacheKey} {noteObjectName}" const entries = output .trim() .split('\n') .map((line) => { const [refPath] = line.split(' '); // Extract cache key from ref path const regex = /refs\/notes\/vibe-validate\/run\/([^/]+)\/(.+)$/; const match = regex.exec(refPath); if (!match) return null; const [, treeHashFromRef, cacheKey] = match; return { treeHash: treeHashFromRef, cacheKey, refPath, }; }) .filter(Boolean); return entries; } catch { // No run cache exists - expected for tree hashes without run cache return []; } } /** * Get a specific run cache entry * * @param treeHash - Git tree hash * @param cacheKey - URL-encoded cache key * @returns Run cache note or null if not found */ export async function getRunCacheEntry(treeHash, cacheKey) { try { const refPath = `vibe-validate/run/${treeHash}/${cacheKey}`; const yaml = execSync(`git notes --ref=${refPath} show HEAD`, GIT_OPTIONS); const note = parseYaml(yaml); return note; } catch { // Entry doesn't exist or parse failed return null; } } /** * Get all run cache entries for a tree hash * * @param treeHash - Git tree hash * @returns Array of all run cache notes for this tree hash */ export async function getAllRunCacheForTree(treeHash) { const entries = await listRunCacheEntries(treeHash); const notes = []; for (const entry of entries) { const note = await getRunCacheEntry(entry.treeHash, entry.cacheKey); if (note) { notes.push(note); } } // Sort by timestamp (newest first) for deterministic ordering notes.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); return notes; } /** * List all tree hashes that have run cache entries * * @returns Array of tree hashes with run cache */ export async function listRunCacheTreeHashes() { try { // List all notes under refs/notes/vibe-validate/run/ const output = execSync('git for-each-ref --format="%(refname)" refs/notes/vibe-validate/run/', GIT_OPTIONS); if (!output.trim()) { return []; } // Parse output and extract unique tree hashes const treeHashes = new Set(); const lines = output.trim().split('\n'); for (const line of lines) { // Extract tree hash from ref path: refs/notes/vibe-validate/run/{treeHash}/... const regex = /refs\/notes\/vibe-validate\/run\/([^/]+)/; const match = regex.exec(line); if (match) { treeHashes.add(match[1]); } } return Array.from(treeHashes); } catch { // No run cache exists - expected for repos without run cache return []; } } /** * Get all run cache entries across all tree hashes * * @returns Array of all run cache notes */ export async function getAllRunCacheEntries() { const treeHashes = await listRunCacheTreeHashes(); const allNotes = []; for (const treeHash of treeHashes) { const notes = await getAllRunCacheForTree(treeHash); allNotes.push(...notes); } // Sort by timestamp (newest first) allNotes.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); return allNotes; } //# sourceMappingURL=run-cache-reader.js.map