Download src/worm.ts from Snapkitty/holy-agents: direct link, hf CLI and curl.
- Browser
- Download file 2.78 kB
-
https://huggingface.co/Snapkitty/holy-agents/resolve/main/src/worm.ts
- Command line
-
hf download hf://Snapkitty/holy-agents/src/worm.ts
-
curl -L -o worm.ts https://huggingface.co/Snapkitty/holy-agents/resolve/main/src/worm.ts
2.78 kB
| import * as fs from 'node:fs'; | |
| import * as path from 'node:path'; | |
| import { fileURLToPath } from 'node:url'; | |
| import { sha256, computeEntryHash } from './hash.js'; | |
| import type { WormEntry, Verdict, AgentName } from './types.js'; | |
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| const WORM_DIR = path.join(__dirname, '..', '..', 'worm'); | |
| const WORM_FILE = path.join(WORM_DIR, 'holy_agents.jsonl'); | |
| function ensureDir(): void { | |
| if (!fs.existsSync(WORM_DIR)) fs.mkdirSync(WORM_DIR, { recursive: true }); | |
| } | |
| export function readEntries(): WormEntry[] { | |
| ensureDir(); | |
| if (!fs.existsSync(WORM_FILE)) return []; | |
| const content = fs.readFileSync(WORM_FILE, 'utf-8'); | |
| const lines = content.split('\n').filter(Boolean); | |
| const entries: WormEntry[] = []; | |
| for (let i = 0; i < lines.length; i++) { | |
| try { | |
| entries.push(JSON.parse(lines[i])); | |
| } catch { | |
| console.error(`WORM: corrupt entry at line ${i + 1}, skipping`); | |
| } | |
| } | |
| return entries; | |
| } | |
| function appendLine(line: string): void { | |
| ensureDir(); | |
| fs.appendFileSync(WORM_FILE, line + '\n', 'utf-8'); | |
| } | |
| export function appendEntry(event_id: string, agent: AgentName, action: string, verdict: Verdict, citations: string[]): WormEntry { | |
| const entries = readEntries(); | |
| const seq = entries.length + 1; | |
| const prevHash = entries.length === 0 ? 'GENESIS' : entries[entries.length - 1].hash; | |
| const timestamp = new Date().toISOString(); | |
| const entry: WormEntry = { | |
| seq, | |
| prev_hash: prevHash, | |
| hash: '', | |
| timestamp, | |
| event_id, | |
| agent, | |
| action, | |
| verdict, | |
| citations | |
| }; | |
| entry.hash = computeEntryHash({ seq, prev_hash: prevHash, event_id, agent, action, verdict, timestamp }); | |
| appendLine(JSON.stringify(entry)); | |
| return entry; | |
| } | |
| export function getEntries(): WormEntry[] { | |
| return readEntries(); | |
| } | |
| export function verifyChain(): { valid: boolean; errors: string[] } { | |
| const entries = readEntries(); | |
| const errors: string[] = []; | |
| if (entries.length === 0) return { valid: true, errors: [] }; | |
| for (let i = 0; i < entries.length; i++) { | |
| const entry = entries[i]; | |
| if (entry.seq !== i + 1) errors.push(`entry ${i}: expected seq ${i + 1}, got ${entry.seq}`); | |
| const expectedPrev = i === 0 ? 'GENESIS' : entries[i - 1].hash; | |
| if (entry.prev_hash !== expectedPrev) errors.push(`entry ${i}: prev_hash mismatch`); | |
| const recomputed = computeEntryHash({ | |
| seq: entry.seq, prev_hash: entry.prev_hash, event_id: entry.event_id, | |
| agent: entry.agent, action: entry.action, verdict: entry.verdict, timestamp: entry.timestamp | |
| }); | |
| if (recomputed !== entry.hash) errors.push(`entry ${i}: hash mismatch`); | |
| } | |
| return { valid: errors.length === 0, errors }; | |
| } | |