import { appendFile, mkdir, rm, readFile } from 'node:fs/promises'; import crypto from 'node:crypto'; import path from 'node:path'; export class ComputerAudit { constructor({ dir = path.join(process.env.XDG_DATA_HOME || path.join(process.env.HOME || '/tmp', '.local/share'), 'jarvis/audit') } = {}) { this.dir = dir; } async record(action, target = {}, result = {}) { const safeTarget = typeof target === 'string' ? target : { ref: target.ref, role: target.role, name: target.name, rect: target.rect }; const targetHash = crypto.createHash('sha256').update(JSON.stringify(safeTarget)).digest('hex'); const row = { ts: new Date().toISOString(), action, target_hash: targetHash, screenshot_hash: result.screenshotPath ? await this.hashFile(result.screenshotPath) : undefined, ok: Boolean(result.ok), reason: result.reason || undefined }; await mkdir(this.dir, { recursive: true }); await appendFile(path.join(this.dir, `cu-${row.ts.slice(0, 10).replaceAll('-', '')}.jsonl`), `${JSON.stringify(row)}\n`); return row; } async hashFile(file) { return crypto.createHash('sha256').update(await readFile(file)).digest('hex'); } async wipeTemp(dir = '/tmp/jarvis-cu') { await rm(dir, { recursive: true, force: true }); } }