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:
commit
e989413018
76 files changed
+8386
No files matched your search
@@ -0,0 +1,155 @@
|
||||
import {activityState,showActivityToast} from './visibility.js'
|
||||
import {scheduleUpdate, updateNotice} from "./runtime-updates.js"
|
||||
import { mutateJSON, HOOK_LOCK_BUDGET_MS } from "./anatomy-lock.js"
|
||||
import {readJSON,sessionFilePath} from "./fs.js"
|
||||
import { approvedMemory } from "./trusted-memory.js"
|
||||
import { recordUsage, reconcileOpenCode } from "./usage.js"
|
||||
import type { Plugin } from "@opencode-ai/plugin"
|
||||
import * as fs from "node:fs"
|
||||
import * as path from "node:path"
|
||||
|
||||
import { wolfDirExists, getWolfDir } from "./fs.js"
|
||||
import { handleSessionStart, deleteSession } from "./session.js"
|
||||
import { handlePreRead } from "./pre-read.js"
|
||||
import { handlePreWrite } from "./pre-write.js"
|
||||
import { handlePostRead } from "./post-read.js"
|
||||
import { handlePostWrite } from "./post-write.js"
|
||||
import { handleStop } from "./stop.js"
|
||||
|
||||
/**
|
||||
* OpenCode event payloads have carried the session id in different places
|
||||
* across versions: top-level `session_id`/`sessionID` in older builds, and
|
||||
* nested under `properties` (`properties.info.id` for session.created,
|
||||
* `properties.sessionID` elsewhere) in newer ones. Accept all shapes.
|
||||
*/
|
||||
function extractSessionId(source: unknown): string {
|
||||
if (!source || typeof source !== "object") return ""
|
||||
const obj = source as {
|
||||
session_id?: unknown
|
||||
sessionID?: unknown
|
||||
properties?: { info?: { id?: unknown }; sessionID?: unknown }
|
||||
}
|
||||
const candidates = [
|
||||
obj.session_id,
|
||||
obj.sessionID,
|
||||
obj.properties?.info?.id,
|
||||
obj.properties?.sessionID,
|
||||
]
|
||||
for (const c of candidates) {
|
||||
if (typeof c === "string" && c) return c
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
export const OpenWolf: Plugin = async ({ directory, client }) => {
|
||||
let reconciliation: Promise<void> = Promise.resolve()
|
||||
const refreshUsage = (id?: string) => {
|
||||
reconciliation = reconciliation.then(() => reconcileOpenCode(directory,client,id)).catch(error => console.warn(`OpenWolf usage reconciliation: ${error}`))
|
||||
return reconciliation
|
||||
}
|
||||
if (wolfDirExists(directory)) void refreshUsage()
|
||||
|
||||
return {
|
||||
event: async ({ event }: { event: { type: string; [key: string]: unknown } }) => {
|
||||
if (event.type === "session.created" && !wolfDirExists(directory)) return
|
||||
|
||||
if (!wolfDirExists(directory)) return
|
||||
if (event.type === "message.updated") {
|
||||
try {recordUsage(directory, (event as any).properties?.info)} catch(error) {console.warn(String(error))}
|
||||
}
|
||||
const sessionId = extractSessionId(event)
|
||||
if (!sessionId) return
|
||||
|
||||
if (event.type === "session.created") {
|
||||
handleSessionStart(directory, sessionId)
|
||||
scheduleUpdate(directory)
|
||||
const notice=updateNotice(directory,sessionId)
|
||||
if(notice)showActivityToast(client,notice)
|
||||
}
|
||||
|
||||
if (event.type === "session.idle" || event.type === "session.error" || event.type === "session.deleted") {
|
||||
scheduleUpdate(directory)
|
||||
const update=updateNotice(directory,sessionId)
|
||||
const activity=update??activityState(directory,{agent:"opencode",session:sessionId,turn:String(readJSON<Record<string,unknown>>(sessionFilePath(path.join(getWolfDir(directory),"hooks"),sessionId),{}).stop_count??0),surface:"opencode-toast"}).message
|
||||
if(activity)showActivityToast(client,activity)
|
||||
await refreshUsage(sessionId)
|
||||
handleStop(directory, sessionId)
|
||||
}
|
||||
if (event.type === "session.deleted") {
|
||||
const file=sessionFilePath(path.join(getWolfDir(directory),"hooks"),sessionId)
|
||||
mutateJSON<Record<string,unknown>>(file,{},HOOK_LOCK_BUDGET_MS,state=>{state.ended=new Date().toISOString()})
|
||||
deleteSession(sessionId)
|
||||
}
|
||||
},
|
||||
|
||||
"tool.execute.before": async (input: { tool: string; sessionID: string }, output: { args: Record<string, unknown> }) => {
|
||||
if (!wolfDirExists(directory)) return
|
||||
|
||||
const sessionId = extractSessionId(input)
|
||||
if (!sessionId) return
|
||||
|
||||
const args: Record<string, unknown> = output.args || {}
|
||||
const tool = input.tool.toLowerCase()
|
||||
|
||||
if (tool === "read") {
|
||||
const filePath = String(args.filePath || args.file_path || "")
|
||||
const isRangedRead = args.offset !== undefined || args.limit !== undefined
|
||||
if (filePath) handlePreRead(directory, sessionId, filePath, isRangedRead)
|
||||
}
|
||||
|
||||
if (tool === "write" || tool === "edit") {
|
||||
const filePath = String(args.filePath || args.file_path || "")
|
||||
const content = String(args.content || "")
|
||||
const oldStr = String(args.old_string || args.oldString || "")
|
||||
const newStr = String(args.new_string || args.newString || "")
|
||||
if (filePath) handlePreWrite(directory, sessionId, filePath, content, oldStr, newStr)
|
||||
}
|
||||
},
|
||||
|
||||
"tool.execute.after": async (input: { tool: string; sessionID: string; args: Record<string, unknown>; callID?: string }, output: Record<string, unknown>) => {
|
||||
if (!wolfDirExists(directory)) return
|
||||
|
||||
const sessionId = extractSessionId(input)
|
||||
if (!sessionId) return
|
||||
|
||||
const tool = input.tool.toLowerCase()
|
||||
const args = input.args || {}
|
||||
|
||||
if (tool === "read") {
|
||||
const filePath = String(args.filePath || args.file_path || "")
|
||||
const content = String((output as any).output || "")
|
||||
if (filePath) handlePostRead(directory, sessionId, filePath, content, args.offset !== undefined || args.limit !== undefined, input.callID)
|
||||
}
|
||||
|
||||
if (tool === "write" || tool === "edit") {
|
||||
const filePath = String(args.filePath || args.file_path || "")
|
||||
const content = String(args.content || "")
|
||||
const oldStr = String(args.old_string || args.oldString || "")
|
||||
const newStr = String(args.new_string || args.newString || "")
|
||||
if (filePath) handlePostWrite(directory, sessionId, input.tool, filePath, content, oldStr, newStr)
|
||||
}
|
||||
},
|
||||
|
||||
stop: async (input: Record<string, unknown>) => {
|
||||
if (!wolfDirExists(directory)) return
|
||||
|
||||
const sessionId = extractSessionId(input)
|
||||
if (!sessionId) return
|
||||
|
||||
handleStop(directory, sessionId)
|
||||
},
|
||||
|
||||
"experimental.chat.system.transform": async (_input: Record<string, unknown>, output: { system: string[] }) => {
|
||||
if (!wolfDirExists(directory)) return
|
||||
|
||||
const wolfDir = getWolfDir(directory)
|
||||
const openwolfPath = path.join(wolfDir, "OPENWOLF.md")
|
||||
if (fs.existsSync(openwolfPath)) {
|
||||
try {
|
||||
const openwolfContent = approvedMemory(wolfDir, "OPENWOLF.md")
|
||||
output.system.push(`\n<openwolf-protocol>\n${openwolfContent}\n</openwolf-protocol>`)
|
||||
} catch {}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user