Esqueleto inicial: sabia-core + sabia-cli + UI local, OpenWolf

- sabia-core: descoberta de interfaces, controle de modo monitor/canal
  via iw (ponte até ter nl80211 nativo), captura crua 802.11 via
  AF_PACKET (sem libpcap), parsing de radiotap e quadros de
  gerenciamento (beacon/probe/EAPOL), agregação em tabela de APs/
  clientes, escrita de .pcap, trilha de auditoria encadeada por hash,
  auto-atualização via GitHub releases (curl, sem dependências de
  rede extras)
- sabia-cli: `sabia iface`, `sabia scan`, `sabia update`,
  `sabia audit-verify`, `sabia ui` (servidor local + navegador,
  protegido por token, mesma filosofia do Guará)
- OpenWolf inicializado para memória de projeto entre agentes
This commit is contained in:
Lucas committed 2026-10-23 08:22:04 -03:00
commit e989413018
76 files changed
+8386

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as crypto from 'node:crypto';
import {withFileLock,HOOK_LOCK_BUDGET_MS} from './anatomy-lock.js';
import {nextBugId} from './bug-id.js';
import {sharedWolfDir} from './knowledge-root.js';
export interface BugObservation {error_message:string;file:string;root_cause:string;fix:string;tags:string[];line?:number;status?:string;observed_worktree?:string;}
export function recordBug(wolfDir:string,bug:BugObservation):void {
const dir=path.join(wolfDir,'bug-pending');fs.mkdirSync(dir,{recursive:true});
const id=crypto.randomUUID();const file=path.join(dir,id+'.json');
const fd=fs.openSync(file,'wx',0o600);
try {fs.writeFileSync(fd,JSON.stringify({id,at:new Date().toISOString(),bug}));fs.fsyncSync(fd);} finally {fs.closeSync(fd);}
reconcileBugs(wolfDir);
}
export function reconcileBugs(wolfDir:string):boolean {
const pending=path.join(wolfDir,'bug-pending');let names:string[];
try {names=fs.readdirSync(pending).filter(n=>n.endsWith('.json'));} catch {return true;}
if (!names.length) return true;
const file=path.join(sharedWolfDir(wolfDir),'buglog.json');
const ok=withFileLock(file+'.lock',HOOK_LOCK_BUDGET_MS,()=>{
let log:any={version:1,bugs:[]};
try {log=JSON.parse(fs.readFileSync(file,'utf8'));} catch(e) {if ((e as NodeJS.ErrnoException).code!=='ENOENT') throw e;}
if (Array.isArray(log)) log={version:1,bugs:log};
if (!log || !Array.isArray(log.bugs)) throw new Error('Invalid buglog; observations retained without overwriting it');
log.applied_observations ??= {};
for (const name of names) {
let event:any;
try {event=JSON.parse(fs.readFileSync(path.join(pending,name),'utf8'));} catch(e) {if ((e as NodeJS.ErrnoException).code==='ENOENT') continue;throw e;}
if (!event.id || !event.bug || typeof event.bug.file!=='string') throw new Error('Invalid bug observation retained');
if (log.applied_observations[event.id]) continue;
const b=event.bug as BugObservation;
const existing=log.bugs.find((old:any)=>old?.file===b.file && old.error_message===b.error_message && old.fix===b.fix);
if (existing) {existing.occurrences=(Number.isSafeInteger(existing.occurrences)?existing.occurrences:0)+1;existing.last_seen=event.at;}
else log.bugs.push({...b,id:nextBugId(log),timestamp:event.at,last_seen:event.at,occurrences:1,related_bugs:[]});
log.applied_observations[event.id]=true;
}
const tmp=file+'.'+crypto.randomUUID()+'.tmp';
try {const fd=fs.openSync(tmp,'wx',0o600);try {fs.writeFileSync(fd,JSON.stringify(log,null,2));fs.fsyncSync(fd);}finally{fs.closeSync(fd);}fs.renameSync(tmp,file);}finally{try{fs.unlinkSync(tmp);}catch{}}
for(const name of names){try{fs.unlinkSync(path.join(pending,name));}catch{}}
return true;
});
return ok===true;
}