Files
sabia/.opencode/plugin/openwolf/session-state.ts
T
Lucas e989413018 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
2026-10-23 08:22:04 -03:00

21 lines
1.4 KiB
TypeScript

/** Complete state at every ingress, including a missed SessionStart (#96 @davdittrich). */
export function normalizeSession(value: unknown, id: string, now = new Date().toISOString()): Record<string, any> {
const s: Record<string, any> = value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
s.session_id = id;
if (typeof s.started !== "string" || !Number.isFinite(Date.parse(s.started))) s.started = now;
for (const key of ["files_read", "edit_counts", "reminders_sent", "injected_by_source"]) {
if (!s[key] || typeof s[key] !== "object" || Array.isArray(s[key])) s[key] = {};
}
for (const key of ["files_written", "pending_reminders"]) if (!Array.isArray(s[key])) s[key] = [];
for (const key of ["anatomy_hits", "anatomy_misses", "repeated_reads_warned", "stop_count", "cerebrum_warnings"]) {
if (!Number.isSafeInteger(s[key]) || s[key] < 0) s[key] = 0;
}
for (const [file, r] of Object.entries(s.files_read) as Array<[string, any]>) {
if (!r || typeof r !== "object") { delete s.files_read[file]; continue; }
r.count = Number.isSafeInteger(r.count) && r.count >= 0 ? r.count : 0;
r.tokens = Number.isFinite(r.tokens) && r.tokens >= 0 ? r.tokens : 0;
}
s.files_written = s.files_written.filter((w: any) => w && typeof w.file === "string").map((w: any) => ({ ...w, tokens: Number.isFinite(w.tokens) && w.tokens >= 0 ? w.tokens : 0 }));
return s;
}