/** * OpenKernel — Federation Types * * The mesh is provider/harness-agnostic. Everything on the wire is plain JSON: * a small envelope carrying one of a handful of message kinds, plus a compact * "stream frame" format tuned for high-frequency, animation-friendly rendering * in a harness UI (short keys, coalesced telemetry). * * Nothing here is InfiniBot-specific — the MOLTFED adapter translates these * neutral shapes into InfiniBot's message names so its neural-mesh map + hardware * panels light up without any InfiniBot changes. */ import type { Capability } from '../types.js'; /** Role of a node in the mesh. Governs connection direction + permissions. */ export type NodeRole = 'hub' | 'peer' | 'satellite' | 'relay'; /** Stable identity of a node, persisted to disk so it survives restarts. */ export interface NodeIdentity { nodeId: string; displayName: string; role: NodeRole; /** Public key (base64) — used for app-layer auth of peers. */ publicKey?: string; createdAt: number; } /** What a node can do — advertised to peers + the harness map. */ export interface NodeManifest { nodeId: string; displayName: string; role: NodeRole; version: string; platform: string; arch: string; /** e.g. "Raspberry Pi 5", "Windows Workstation". */ deviceFamily?: string; modelIdentifier?: string; /** Aggregate capabilities of this node's registered workers. */ capabilities: Capability[]; /** Worker types this node can run. */ workers: string[]; /** Slash/MCP commands this node exposes (for click-to-invoke). */ commands: string[]; /** Provider ids available on this node. */ providers: string[]; startedAt: number; } /** A peer known to this node. */ export interface PeerInfo { nodeId: string; displayName: string; role: NodeRole; /** Base URL we reach this peer at, e.g. http://100.x.y.z:47913 . */ url: string; connected: boolean; lastSeenAt: number; latencyMs?: number; manifest?: NodeManifest; /** Latest telemetry snapshot (load used by the compute router). */ hardware?: HardwareSnapshot; version?: string; } export interface HardwareSnapshot { cpu: { percent: number; perCorePercent: number[]; loadAvg: [number, number, number]; cores: number; model: string; }; memory: { totalBytes: number; usedBytes: number; freeBytes: number; percent: number; }; gpu: { vendor: string; utilizationPercent: number; vramUsedBytes: number; vramTotalBytes: number; name: string; } | null; disk: { mounts: Array<{ path: string; totalBytes: number; usedBytes: number; percent: number; }>; }; network: { interfaces: Array<{ name: string; rxBytesPerSec: number; txBytesPerSec: number; }>; }; system: { hostname: string; platform: string; arch: string; uptimeSec: number; kernelRelease: string; }; processes: Array<{ pid: number; name: string; cpuPercent: number; memoryBytes: number; }>; /** CPU package temperature in °C (Pi thermal zone / lm-sensors). null when the * platform doesn't expose it (e.g. most Windows hosts). */ temperatureC?: number | null; timestamp: number; } /** Node status entry consumed by the mesh map (neutral form of nodes.status). */ export interface NodeStatus { nodeId: string; displayName: string; role: NodeRole; platform: string; deviceFamily?: string; modelIdentifier?: string; version: string; capabilities: Capability[]; commands: string[]; connected: boolean; connectedAtMs?: number; /** 0–100 rough load, from the latest hardware snapshot. */ load?: number; lastSeenAt: number; /** Physical deployment this node belongs to (e.g. "Tel Aviv"). Sourced from * this node's own RoleContext.site — lets a fleet UI group by location as * a customer scales from one site to many, without per-site bespoke code. */ site?: string; } export type MessageKind = 'hello' | 'welcome' | 'heartbeat' | 'manifest' | 'task.dispatch' | 'task.accepted' | 'task.status' | 'task.result' | 'task.cancel' | 'command' | 'command.result' | 'config.request' | 'config.offer' | 'update.announce' | 'update.request' | 'role.get' | 'role.set' | 'agents.list' | 'agents.offer' | 'message.send' | 'message.accepted' | 'event' | 'telemetry' | 'ack' | 'error'; /** A dispatched/received task run — tracked for non-blocking handoff + monitoring. */ export interface RunRecord { runId: string; status: 'running' | 'completed' | 'failed'; description: string; missionId?: string; outputs?: Array<{ status: string; content?: string; error?: string; }>; error?: string; startedAt: number; completedAt?: number; /** Which executor ran this — 'kernel' (native) or a CLI backend id. */ agent?: string; /** The executor's native session id (CLI backends) — enables resume + messaging. */ sessionId?: string; } /** * A messageable CLI agent session on the mesh. Any run that used a CLI backend * and captured a native session id becomes an addressable agent — live while * running, dormant (but still resumable) once complete. Its address is * `nodeId/sessionId`; sending a message resumes that exact CLI session. */ export interface AgentHandle { /** runId that created/owns the session (the follow handle). */ agentId: string; /** node holding the session. */ nodeId: string; /** which CLI backend runs it — 'claude' | 'codex' | 'opencode'. */ backend: string; /** the CLI's native session id (what resume targets). */ sessionId: string; /** routable address: `${nodeId}/${sessionId}`. */ address: string; status: 'running' | 'completed' | 'failed'; description: string; lastActiveAt: number; } /** Result of a one-shot `infinicode maintain` run, pushed to an InfiniBot gateway. */ export interface MaintenanceReport { nodeId: string; role: string; site?: string; taskName: string; startedAt: number; finishedAt: number; durationMs: number; ok: boolean; summary: string; errors?: string[]; } /** Persistent per-device role + server-architecture context. */ export interface RoleContext { /** e.g. "RoboPanda" — the identity a spawned agent adopts. */ role: string; /** Physical deployment/location this device belongs to (e.g. "Tel Aviv"). * Optional — a single-site deployment can leave it unset. */ site?: string; /** Free-text description of this device's job + the wider architecture. */ architecture?: string; /** Extra structured context injected into every task run on this node. */ extra?: Record; updatedAt: number; } /** Signed, routable message envelope. */ export interface FederationEnvelope { /** Protocol version for forward-compat. */ v: number; /** Message id (for request/response correlation). */ id: string; kind: MessageKind; from: string; to?: string; ts: number; /** Correlation id — set on replies to the request's id. */ re?: string; data?: T; /** Optional bearer/token for app-layer auth. */ auth?: string; } /** * A minimal, high-frequency frame for the harness to render/animate. Short keys * keep bytes low for smooth 1–10 Hz updates. `t` is a frame type; the harness * switches on it to drive different animations. */ export interface StreamFrame { /** frame type: ev=event, hw=telemetry, hb=heartbeat, nd=node status, rt=routing */ t: 'ev' | 'hw' | 'hb' | 'nd' | 'rt' | 'log'; /** origin nodeId */ n: string; /** monotonic sequence for gap detection */ s: number; /** epoch ms */ ts: number; /** compact payload — shape depends on t */ d?: unknown; } /** A shareable slice of config a hub can push to satellites. */ export interface SharedConfig { /** Cloud providers (id/name/baseURL/apiKey/enabled). */ cloudProviders?: Array>; /** Default policy + model. */ policy?: string; defaultModel?: string; /** Free-form extra keys. */ extra?: Record; /** Version/etag so a satellite only re-applies when it changes. */ revision: number; updatedAt: number; } export interface UpdateAnnounce { version: string; /** How to fetch the update (npm tag, url, or "git"). */ channel: 'npm' | 'url' | 'git'; ref?: string; notes?: string; /** Minimum protocol version the update requires. */ minProtocol?: number; } export declare const FEDERATION_PROTOCOL_VERSION = 1; /** Default mesh ports — chosen to sit alongside InfiniBot's 47913/47914. */ export declare const DEFAULT_MESH_PORT = 47913;