#!/usr/bin/env node import { createRequire } from "node:module"; import { dirname, extname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { existsSync, readFileSync } from "node:fs"; import { mkdir, readFile, stat, writeFile } from "node:fs/promises"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const defaultStorageRoot = resolve(repoRoot, ".voidbot"); const defaultStatusDir = resolve(defaultStorageRoot, "status"); const defaultSnapshotPath = resolve(defaultStatusDir, "swarm-state.json"); const defaultDashboardPath = resolve(defaultStatusDir, "swarm-dashboard.html"); const defaultCultMeshStorePath = resolve(defaultStatusDir, "cultmesh", "voidbot-swarm-state.cc"); const providerId = "voidbot.swarm"; const operatorDmProviderId = "voidbot.operator-dm"; const verseId = "voidbot.local"; const rootVerse = "asgard"; const currentMachine = "starfire"; const canonicalService = `${rootVerse}.voidbot`; const locatedService = `${rootVerse}.${currentMachine}.voidbot`; const snapshotDocumentType = "voidbot.swarm_state_snapshot"; const snapshotSchemaId = "voidbot.swarm_state_snapshot.v1"; const providerAdvertisementDocumentType = "gamecult.eve.provider_advertisement"; const providerAdvertisementSchemaId = "gamecult.eve.provider_advertisement.v1"; const eveBindingDocumentType = "gamecult.eve.interface_binding"; const eveBindingSchemaId = "gamecult.eve.interface_binding.v1"; const surfaceDocumentType = "gamecult.eve.surface_state"; const surfaceSchemaId = "gamecult.eve.surface_state.v1"; const operatorDmRequestDocumentType = "gamecult.operator_dm_request"; const operatorDmRequestSchemaId = "gamecult.operator_dm_request.v1"; const args = parseArgs(process.argv.slice(2)); const env = await readDotEnv(resolve(repoRoot, ".env")); const storageRoot = resolveConfigPath(env.STORAGE_ROOT, defaultStorageRoot); const statusDir = resolve(storageRoot, "status"); const heartbeatStatePath = resolveConfigPath( env.REPO_PERSONA_HEARTBEAT_STATE_PATH, resolve(statusDir, "repo-persona-heartbeats.json"), ); const orchestratorPath = resolve(statusDir, "gamecult-orchestrator.json"); const pausePath = resolve(repoRoot, "state", "agent-swarm-paused.json"); const snapshotPath = resolveConfigPath(args.snapshot, defaultSnapshotPath.replace(defaultStatusDir, statusDir)); const dashboardPath = resolveConfigPath(args.out, defaultDashboardPath.replace(defaultStatusDir, statusDir)); const cultMeshStorePath = resolveConfigPath( args.cultmeshStore, defaultCultMeshStorePath.replace(defaultStatusDir, statusDir), ); const requireCultMeshAdvertisement = !isFlagEnabled(args.public) && !isFlagEnabled(args.allowUnmeshed); const renderResult = await render(); if (args.open) { console.log(pathToFileURL(renderResult.dashboardPath).href); } if (args.serve) { throw new Error("VoidBot swarm is exposed through CultMesh/Eve, not a web server. Use npm run swarm:render-dashboard to publish the CultMesh surface."); } else { console.log(`Swarm dashboard HTML: ${renderResult.dashboardPath}`); console.log(`Swarm snapshot JSON: ${renderResult.snapshotPath}`); console.log(`CultMesh snapshot store: ${renderResult.cultMeshStorePath}`); } async function render() { let snapshot = await buildSnapshot(); if (isFlagEnabled(args.public)) { snapshot = redactSnapshot(snapshot); } await mkdir(dirname(snapshotPath), { recursive: true }); await mkdir(dirname(dashboardPath), { recursive: true }); const pendingEveState = buildEveProviderState(snapshot); const cultMeshWrite = await writeCultMeshPublication(snapshot, pendingEveState, cultMeshStorePath); if (requireCultMeshAdvertisement && cultMeshWrite.writeStatus !== "ok") { throw new Error(`VoidBot swarm CultMesh advertisement failed: ${cultMeshWrite.writeError ?? cultMeshWrite.writeStatus}`); } const finalSnapshot = { ...snapshot, cultMesh: { ...snapshot.cultMesh, ...cultMeshWrite, }, }; const finalEveState = buildEveProviderState(finalSnapshot); await writeFile(snapshotPath, `${JSON.stringify(finalSnapshot, null, 2)}\n`, "utf8"); await writeFile(dashboardPath, renderHtml(finalSnapshot), "utf8"); return { dashboardPath, snapshotPath, cultMeshStorePath, }; } async function buildSnapshot() { const now = new Date(); const heartbeat = await readJsonFile(heartbeatStatePath); const orchestrator = await readJsonFile(orchestratorPath); const pause = await readJsonFile(pausePath); const identityMetadata = await readIdentityMetadata(env.REPO_DISCORD_IDENTITIES_PATH); const heartbeatMtime = await getMtime(heartbeatStatePath); const orchestratorMtime = await getMtime(orchestratorPath); const paused = pause.ok ? pause.value?.paused !== false : false; const pauseReason = pause.ok && typeof pause.value?.reason === "string" ? pause.value.reason : undefined; const participants = Array.isArray(heartbeat.value?.participants) ? heartbeat.value.participants : []; const pendingMentions = Array.isArray(heartbeat.value?.pendingMentions) ? heartbeat.value.pendingMentions : []; const initiativeClock = numberOrNull(heartbeat.value?.initiativeClock); const participantSnapshots = participants.map((participant) => projectParticipant(participant, pendingMentions, initiativeClock, identityMetadata), ); const personaStates = await readPersonaStates(identityMetadata); for (const participant of participantSnapshots) { participant.personaState = personaStates.get(participant.identityId.toLowerCase()) ?? { readable: false, path: participant.personaStatePath, error: participant.personaStatePath ? "State file was not readable." : "No Persona state path registered.", tree: [], }; participant.restState = participant.personaState.restState ?? null; } const activeTurns = participantSnapshots.filter((participant) => participant.activeJobId); const readyNow = participantSnapshots.filter((participant) => participant.status === "active" && !participant.activeJobId && participant.restState?.isNapping !== true && typeof participant.nextTurnInMinutes === "number" && participant.nextTurnInMinutes <= 0, ); const nextParticipant = [...participantSnapshots] .filter((participant) => typeof participant.nextTurnInMinutes === "number") .sort((left, right) => left.nextTurnInMinutes - right.nextTurnInMinutes)[0]; const organs = projectOrgans(orchestrator.value); const recentEvents = Array.isArray(heartbeat.value?.history) ? heartbeat.value.history.slice(-24).reverse().map(projectHistoryEvent) : []; const controls = projectControls(heartbeat.value?.controls); const upcomingTurns = buildUpcomingTurns(participantSnapshots); const lastShuffle = findLastShuffleEvent(recentEvents); return { schemaVersion: snapshotSchemaId, generatedAt: now.toISOString(), title: "VoidBot Swarm State", sources: { heartbeatStatePath, heartbeatStateUpdatedAt: heartbeatMtime, heartbeatStateReadable: heartbeat.ok, heartbeatStateError: heartbeat.ok ? undefined : heartbeat.error, orchestratorPath, orchestratorUpdatedAt: orchestratorMtime, orchestratorReadable: orchestrator.ok, orchestratorError: orchestrator.ok ? undefined : orchestrator.error, pausePath, pauseReadable: pause.ok, pauseError: pause.ok ? undefined : pause.error, }, cultMesh: { documentType: snapshotDocumentType, schemaId: snapshotSchemaId, documentKey: "voidbot-swarm", storePath: cultMeshStorePath, writeStatus: "pending", providerId, verseId, rootVerse, canonicalService, locatedService, cultMeshAddress: primaryCultMeshAddress(), eveDeckEndpoint: primaryCultMeshAddress(), routes: providerRoutes(providerId, cultMeshStorePath), note: "VoidBot swarm is a CultMesh-advertised Eve provider. The web page is a local lowering of the same surface.", }, summary: { state: deriveSwarmState({ heartbeat, orchestrator, paused, activeTurns }), paused, pauseReason, participantCount: participantSnapshots.length, activeTurnCount: activeTurns.length, pendingMentionCount: pendingMentions.length, readyNowCount: readyNow.length, nextIdentityId: nextParticipant?.identityId ?? null, nextDisplayName: nextParticipant?.displayName ?? null, nextTurnInMinutes: nextParticipant?.nextTurnInMinutes ?? null, initiativeClock, baseRecoveryMinutes: numberOrNull(heartbeat.value?.baseRecoveryMinutes), globalHeat: numberOrNull(heartbeat.value?.globalHeat), cadenceMultiplier: controls.cadenceMultiplier, lastTickAt: stringOrNull(heartbeat.value?.lastTickAt), lastShuffle, }, controls, upcomingTurns, participants: participantSnapshots, activeTurns, pendingMentions: pendingMentions.map(projectPendingMention), orchestrator: { state: deriveOrchestratorState(organs), organs, }, recentEvents, }; } function projectControls(value) { const cadenceMultiplier = numberOrNull(value?.cadenceMultiplier) ?? 1; const manualTurnRequests = Array.isArray(value?.manualTurnRequests) ? value.manualTurnRequests.slice(-12).reverse().map((request) => ({ id: stringOrNull(request?.id), identityId: stringOrNull(request?.identityId), requestedAt: stringOrNull(request?.requestedAt), status: stringOrNull(request?.status) ?? "pending", note: stringOrNull(request?.note), })) : []; return { cadenceMultiplier, updatedAt: stringOrNull(value?.updatedAt), manualTurnRequests, }; } function buildUpcomingTurns(participants) { const ordered = [...participants] .filter((participant) => participant.status === "active") .sort((left, right) => { const activeDelta = Number(Boolean(right.activeJobId)) - Number(Boolean(left.activeJobId)); if (activeDelta) return activeDelta; return (left.nextTurnInMinutes ?? 999999) - (right.nextTurnInMinutes ?? 999999); }) .slice(0, 16); const maxMinutes = Math.max(1, ...ordered.map((participant) => Math.max(0, participant.nextTurnInMinutes ?? 0))); return ordered.map((participant, index) => ({ identityId: participant.identityId, displayName: participant.displayName, repoName: participant.repoName, avatarUrl: participant.avatarUrl, participantKind: participant.participantKind, activeJobId: participant.activeJobId, restState: participant.restState, pendingMentionCount: participant.pendingMentionCount, anchoredMentionCount: participant.anchoredMentionCount, unanchoredMentionCount: participant.unanchoredMentionCount, shuffleReason: participant.pendingMentionCount > 0 ? "mention" : participant.activeJobId ? "active" : participant.restState?.isNapping === true ? "nap" : null, nextTurnInMinutes: participant.nextTurnInMinutes, effectiveSpeed: participant.effectiveSpeed, heat: participant.heat, lane: index % 3, timelinePosition: participant.activeJobId ? 0 : Math.min(100, Math.max(0, ((Math.max(0, participant.nextTurnInMinutes ?? 0)) / maxMinutes) * 100)), })); } function findLastShuffleEvent(events) { const directMention = events.find((event) => event.type === "queued" && typeof event.pendingMentionCount === "number" && event.pendingMentionCount > 0 ); if (directMention) { return { kind: "direct_mention", identityId: directMention.identityId, observedAt: directMention.observedAt, }; } const manual = events.find((event) => event.type === "manual_turn_override_applied"); if (manual) { return { kind: "manual_override", identityId: manual.identityId, observedAt: manual.observedAt, }; } return null; } function projectParticipant(participant, pendingMentions, initiativeClock, identityMetadata) { const identityId = String(participant.identityId ?? "unknown"); const metadata = identityMetadata.get(identityId.toLowerCase()) ?? {}; const nextTurnAt = numberOrNull(participant.nextTurnAt); const lastTurnAt = numberOrNull(participant.lastTurnAt); const activeTurnStartedAt = numberOrNull(participant.activeTurnStartedAt); const channelCount = Array.isArray(participant.groups) ? participant.groups.filter((entry) => typeof entry === "string" && entry.startsWith("channel:")).length : 0; const participantMentions = pendingMentions.filter((mention) => mention?.identityId === identityId); const mentionCount = participantMentions.length; const anchoredMentionCount = participantMentions.filter((mention) => !isBlankString(mention?.sourceMessageId ?? mention?.messageId) && !isBlankString(mention?.sourceChannelId ?? mention?.channelId) ).length; const nextTurnInMinutes = typeof nextTurnAt === "number" && typeof initiativeClock === "number" ? round(nextTurnAt - initiativeClock, 3) : null; return { identityId, displayName: String(participant.displayName ?? metadata.displayName ?? identityId), repoName: String(participant.repoName ?? metadata.repoName ?? "unknown"), repoPath: stringOrNull(metadata.repoPath), personaStatePath: stringOrNull(metadata.personaStatePath), personaStatePath: stringOrNull(metadata.personaStatePath), description: stringOrNull(metadata.description), avatarUrl: metadata.avatarUrl ?? null, avatarPath: metadata.avatarPath ?? null, channelPermissions: Array.isArray(metadata.channelPermissions) ? metadata.channelPermissions.slice(0, 12).map((entry) => ({ label: stringOrNull(entry?.label), topic: stringOrNull(entry?.topic), speechThreshold: stringOrNull(entry?.speechThreshold), speedMultiplier: numberOrNull(entry?.speedMultiplier), })) : [], participantKind: String(participant.participantKind ?? "repo_persona"), turnKind: String(participant.turnKind ?? "repo_persona_rumination"), status: String(participant.status ?? "unknown"), currentLoad: numberOrNull(participant.currentLoad), heat: numberOrNull(participant.heat), effectiveSpeed: numberOrNull(participant.effectiveSpeed), initiativeSpeed: numberOrNull(participant.initiativeSpeed), nextTurnAt, nextTurnInMinutes, lastTurnAt, activeTurnStartedAt, activeJobId: stringOrNull(participant.activeJobId), lastQueuedAt: stringOrNull(participant.lastQueuedAt), queuedCount: numberOrNull(participant.queuedCount), pendingMentionCount: mentionCount, anchoredMentionCount, unanchoredMentionCount: Math.max(0, mentionCount - anchoredMentionCount), channelCount, constraintCount: Array.isArray(participant.constraints) ? participant.constraints.length : 0, constraints: Array.isArray(participant.constraints) ? participant.constraints.slice(0, 4).map(String) : [], }; } function projectOrgans(orchestrator) { const organs = orchestrator?.organs && typeof orchestrator.organs === "object" ? orchestrator.organs : {}; return Object.entries(organs).map(([id, organ]) => ({ id, label: String(organ?.label ?? id), intervalMinutes: numberOrNull(organ?.intervalMinutes), lastStartedAt: stringOrNull(organ?.lastStartedAt), lastFinishedAt: stringOrNull(organ?.lastFinishedAt), lastExitCode: numberOrNull(organ?.lastExitCode), lastStatus: String(organ?.lastStatus ?? "unknown"), lastLogPath: stringOrNull(organ?.lastLogPath), })); } function projectHistoryEvent(event) { return { type: String(event?.type ?? "event"), identityId: stringOrNull(event?.identityId), observedAt: stringOrNull(event?.observedAt ?? event?.queuedAt ?? event?.appliedAt), activeJobId: stringOrNull(event?.activeJobId), statusPath: stringOrNull(event?.statusPath), reason: stringOrNull(event?.reason), pendingMentionCount: numberOrNull(event?.pendingMentionCount), nextTurnAt: numberOrNull(event?.nextTurnAt), recoveryMinutes: numberOrNull(event?.recoveryMinutes), }; } async function readIdentityMetadata(registryPathValue) { const metadata = new Map(); const registryPath = resolveConfigPath(registryPathValue, resolve(repoRoot, ".voidbot", "private", "repo-discord-identities.json")); const registry = await readJsonFile(registryPath); const identities = Array.isArray(registry.value?.identities) ? registry.value.identities : Array.isArray(registry.value) ? registry.value : []; for (const identity of identities) { const id = typeof identity?.id === "string" ? identity.id.toLowerCase() : ""; if (id) { metadata.set(id, { id, displayName: stringOrNull(identity?.displayName), repoName: stringOrNull(identity?.repoName), repoPath: stringOrNull(identity?.repoPath), identityKind: stringOrNull(identity?.identityKind), personaStatePath: stringOrNull(identity?.personaStatePath), description: stringOrNull(identity?.description), avatarUrl: stringOrNull(identity?.avatarUrl), avatarPath: stringOrNull(identity?.avatarPath), channelPermissions: Array.isArray(identity?.channelPermissions) ? identity.channelPermissions : [], }); } } return metadata; } async function readPersonaStates(identityMetadata) { const states = new Map(); let core = null; try { const requireCore = createRequire(resolve(repoRoot, "packages", "core", "package.json")); core = requireCore(resolve(repoRoot, "packages", "core", "dist", "index.js")); } catch (error) { for (const [id, identity] of identityMetadata.entries()) { states.set(id, { readable: false, path: identity.personaStatePath ?? null, error: `Core typed-state loader unavailable: ${error instanceof Error ? error.message : String(error)}`, tree: [], }); } return states; } for (const [id, identity] of identityMetadata.entries()) { if (identity.identityKind === "native_persona" && extname(identity.personaStatePath ?? "").toLowerCase() !== ".cc") { states.set(id, readPersonaStateSummary(identity)); continue; } if (!identity.personaStatePath) { states.set(id, { readable: false, path: null, error: "No Persona state path registered.", tree: [], }); continue; } try { const typedState = await core.loadVoidSelfStateTypedDocuments({ canonicalPath: identity.personaStatePath, identity: { agentId: id, publicName: identity.displayName ?? id, publicDescription: identity.description ?? undefined, }, }); const rendered = core.buildVoidSelfStateContext ? core.buildVoidSelfStateContext(typedState, { sourcePath: identity.personaStatePath, identity: { agentId: id, publicName: identity.displayName ?? id, publicDescription: identity.description ?? undefined, }, }) : null; states.set(id, { readable: true, path: identity.personaStatePath, summary: truncate(rendered?.summary ?? "", 1200), counts: countPersonaState(typedState), restState: projectRestState(typedState), tree: buildPersonaStateTree(typedState), }); } catch (error) { states.set(id, { readable: false, path: identity.personaStatePath, error: error instanceof Error ? error.message : String(error), tree: [], }); } } return states; } function readPersonaStateSummary(identity) { if (!identity.personaStatePath) { return { readable: false, path: null, error: "No Persona state path registered.", tree: [], }; } try { const raw = readFileSync(resolve(identity.personaStatePath), "utf8"); const state = JSON.parse(stripBom(raw)); return { readable: true, kind: "native_persona", path: identity.personaStatePath, summary: truncate(state.publicDescription ?? state.presentation?.voiceSummary ?? "", 1200), counts: { memory: state.thoughtMemory?.memories?.length ?? 0, pressures: state.agencyPressure?.pressures?.length ?? 0, needs: state.affect?.needs?.length ?? 0, statusReads: state.affect?.statusReads?.length ?? 0, doctrine: state.affect?.doctrineStances?.length ?? 0, }, tree: buildJsonPersonaStateTree(state), }; } catch (error) { return { readable: false, kind: "native_persona", path: identity.personaStatePath, error: error instanceof Error ? error.message : String(error), tree: [], }; } } function buildJsonPersonaStateTree(state) { return [ node("Persona", "persona", [ leaf("Public Name", state.publicName), leaf("Description", state.publicDescription), leaf("Voice", state.presentation?.voiceSummary), collectionNode("Values", "values", state.values, valueNode), objectNode("Activation", "activationProfile", state.activationProfile), collectionNode("Private Notes", "privateNotes", state.privateNotes, valueNode), ]), node("Thought Memory", "thoughtMemory", [ collectionNode("Short Term", "thoughtMemory.shortTerm", state.thoughtMemory?.shortTerm, memoryNode), collectionNode("Durable Memories", "thoughtMemory.memories", state.thoughtMemory?.memories, memoryNode), collectionNode("Incubation", "thoughtMemory.incubation", state.thoughtMemory?.incubation, memoryNode), ]), node("Affect", "affect", [ collectionNode("Needs", "affect.needs", state.affect?.needs, valueNode), collectionNode("Status Reads", "affect.statusReads", state.affect?.statusReads, valueNode), collectionNode("Doctrine", "affect.doctrineStances", state.affect?.doctrineStances, valueNode), ]), ]; } function projectRestState(typedState) { const sleepCycle = typedState?.scheduledRuntime?.sleepCycle; if (!sleepCycle || typeof sleepCycle !== "object") { return null; } return { isNapping: sleepCycle.isNapping === true, napEndsAt: stringOrNull(sleepCycle.currentNapEndsAt), nextNapStartsAt: stringOrNull(sleepCycle.nextNapStartsAt), activeDreamThemes: Array.isArray(sleepCycle.activeDreamThemes) ? sleepCycle.activeDreamThemes.slice(0, 8).map(String) : [], }; } function countPersonaState(typedState) { return { shortTerm: typedState?.thoughtMemory?.shortTerm?.length ?? 0, memories: typedState?.thoughtMemory?.memories?.length ?? 0, incubation: typedState?.thoughtMemory?.incubation?.length ?? 0, bonds: typedState?.personaAffect?.socialBonds?.length ?? 0, pressures: typedState?.agencyPressure?.pressures?.length ?? 0, candidates: typedState?.candidateInterventions?.interventions?.length ?? 0, }; } function buildPersonaStateTree(typedState) { return [ node("Self Profile", "selfProfile", [ leaf("Public Name", typedState?.selfProfile?.publicName), leaf("Description", typedState?.selfProfile?.publicDescription), collectionNode("Values", "selfProfile.values", typedState?.selfProfile?.values, valueNode), objectNode("Activation", "selfProfile.activationProfile", typedState?.selfProfile?.activationProfile), collectionNode("Private Notes", "selfProfile.privateNotes", typedState?.selfProfile?.privateNotes, valueNode), ]), node("Thought Memory", "thoughtMemory", [ collectionNode("Short Term", "thoughtMemory.shortTerm", typedState?.thoughtMemory?.shortTerm, memoryNode), collectionNode("Durable Memories", "thoughtMemory.memories", typedState?.thoughtMemory?.memories, memoryNode), collectionNode("Incubation", "thoughtMemory.incubation", typedState?.thoughtMemory?.incubation, memoryNode), ]), node("Affect", "personaAffect", [ collectionNode("Needs", "personaAffect.needs", typedState?.personaAffect?.needs, valueNode), collectionNode("Social Bonds", "personaAffect.socialBonds", typedState?.personaAffect?.socialBonds, memoryNode), collectionNode("Status Reads", "personaAffect.statusReads", typedState?.personaAffect?.statusReads, memoryNode), objectNode("Mood", "personaAffect.moodDimensions", typedState?.personaAffect?.moodDimensions), collectionNode("Social Biases", "personaAffect.socialBiases", typedState?.personaAffect?.socialBiases, valueNode), ]), node("Agency", "agencyPressure", [ collectionNode("Pressures", "agencyPressure.pressures", typedState?.agencyPressure?.pressures, memoryNode), collectionNode("Candidates", "candidateInterventions.interventions", typedState?.candidateInterventions?.interventions, memoryNode), ]), node("Runtime", "scheduledRuntime", [ objectNode("Sleep Cycle", "scheduledRuntime.sleepCycle", typedState?.scheduledRuntime?.sleepCycle), objectNode("Speaking Pressure", "scheduledRuntime.speakingPressure", typedState?.scheduledRuntime?.speakingPressure), objectNode("Last Runs", "scheduledRuntime.lastRuns", typedState?.scheduledRuntime?.lastRuns), ]), ].filter(Boolean); } function node(label, path, children = []) { const compactChildren = children.filter(Boolean); return { kind: "branch", label, path, children: compactChildren, count: compactChildren.length }; } function leaf(label, value, path = label) { if (value === null || value === undefined || value === "") return null; return { kind: "leaf", label, path, title: label, preview: truncate(renderValuePreview(value), 120), detail: renderValueDetail(value), }; } function collectionNode(label, path, values, projector) { if (!Array.isArray(values) || values.length === 0) return node(label, path, [leaf("empty", "No entries.", `${path}.empty`)]); return node(label, path, values.slice(0, 80).map((value, index) => projector(value, `${path}.${index}`, index))); } function objectNode(label, path, value) { if (!value || typeof value !== "object") return node(label, path, [leaf("empty", "No entries.", `${path}.empty`)]); const children = Object.entries(value).slice(0, 80).map(([key, entry]) => { if (entry && typeof entry === "object") return objectNode(key, `${path}.${key}`, entry); return leaf(key, entry, `${path}.${key}`); }); return node(label, path, children); } function valueNode(value, path, index) { if (value && typeof value === "object") { const title = value.label ?? value.name ?? value.kind ?? value.id ?? `entry ${index + 1}`; return leaf(String(title), value, path); } return leaf(`entry ${index + 1}`, value, path); } function memoryNode(value, path, index) { if (!value || typeof value !== "object") return leaf(`entry ${index + 1}`, value, path); const target = value.target?.label ?? value.target?.id ?? value.targetKind ?? value.target ?? value.kind; const title = value.summary ?? value.claim ?? value.question ?? value.title ?? value.id ?? value.memoryId ?? `entry ${index + 1}`; const label = target ? `${target}: ${title}` : title; return { kind: "leaf", label: truncate(String(label), 120), path, title: String(title), preview: truncate(value.claim ?? value.question ?? value.tension ?? value.actionImplication ?? value.summary ?? renderValuePreview(value), 180), detail: renderMemoryDetail(value), }; } function renderMemoryDetail(value) { const lines = []; for (const key of ["kind", "summary", "claim", "question", "tension", "actionImplication", "status", "intensity", "createdAt", "updatedAt"]) { if (value?.[key] !== null && value?.[key] !== undefined && value?.[key] !== "") { lines.push(`${key}: ${renderValuePreview(value[key])}`); } } if (value?.target) lines.push(`target: ${renderValuePreview(value.target)}`); if (Array.isArray(value?.anchorRefs) && value.anchorRefs.length > 0) { lines.push(`anchors:\n${value.anchorRefs.map((anchor) => `- ${renderValuePreview(anchor)}`).join("\n")}`); } if (Array.isArray(value?.tags) && value.tags.length > 0) lines.push(`tags: ${value.tags.join(", ")}`); return lines.join("\n\n") || renderValueDetail(value); } function renderValuePreview(value) { if (typeof value === "string") return value; if (typeof value === "number" || typeof value === "boolean") return String(value); return JSON.stringify(value); } function renderValueDetail(value) { return typeof value === "string" ? value : JSON.stringify(value, null, 2); } function projectPendingMention(mention) { return { identityId: stringOrNull(mention?.identityId), sourceChannelId: stringOrNull(mention?.sourceChannelId ?? mention?.channelId), sourceMessageId: stringOrNull(mention?.sourceMessageId ?? mention?.messageId), createdAt: stringOrNull(mention?.createdAt ?? mention?.queuedAt), prompt: truncate(String(mention?.prompt ?? mention?.content ?? ""), 220), }; } function deriveSwarmState({ heartbeat, orchestrator, paused, activeTurns }) { if (!heartbeat.ok) return "missing"; if (paused) return "paused"; const organ = projectOrgans(orchestrator.value).find((entry) => entry.id === "repo-persona-heartbeats"); if (organ && organ.lastStatus && !["ok", "skipped_disabled"].includes(organ.lastStatus)) { return "warning"; } if (activeTurns.length > 0) return "running"; return "ready"; } function deriveOrchestratorState(organs) { if (organs.length === 0) return "missing"; if (organs.some((organ) => ["failed", "error", "stalled"].includes(organ.lastStatus))) return "warning"; if (organs.some((organ) => organ.lastStatus === "running")) return "running"; return "ok"; } async function writeCultMeshPublication(snapshot, eveState, storePath) { try { const cultPackages = loadCultPackages(); if (!cultPackages) { return { writeStatus: "skipped", writeError: "CultMesh/CultCache packages were not found in known local CultLib paths.", }; } const { CultMesh, defineDocumentType } = cultPackages; const snapshotDefinition = defineDocumentType({ type: snapshotDocumentType, schemaName: snapshotDocumentType, schemaId: snapshotSchemaId, schemaVersion: snapshotSchemaId, contentHash: snapshotSchemaId, canonicalSchemaJson: JSON.stringify({ schemaName: snapshotDocumentType, schemaVersion: snapshotSchemaId, description: "Redacted read-only VoidBot swarm state snapshot for CultMesh distribution.", }), global: false, schema: { parse(input) { if (!input || typeof input !== "object") { throw new Error("VoidBot swarm snapshot must be an object."); } return input; }, }, }); const providerDefinition = defineDocumentType({ type: providerAdvertisementDocumentType, schemaName: providerAdvertisementDocumentType, schemaId: providerAdvertisementSchemaId, schemaVersion: providerAdvertisementSchemaId, contentHash: providerAdvertisementSchemaId, global: false, name: "providerId", schema: { parse: parseObjectDocument("Eve provider advertisement") }, }); const surfaceDefinition = defineDocumentType({ type: surfaceDocumentType, schemaName: surfaceDocumentType, schemaId: surfaceSchemaId, schemaVersion: surfaceSchemaId, contentHash: surfaceSchemaId, global: false, name: "providerId", schema: { parse: parseObjectDocument("Eve surface state") }, }); const eveBindingDefinition = defineDocumentType({ type: eveBindingDocumentType, schemaName: eveBindingDocumentType, schemaId: eveBindingSchemaId, schemaVersion: eveBindingSchemaId, contentHash: eveBindingSchemaId, global: false, name: "bindingId", schema: { parse: parseObjectDocument("Eve interface binding") }, }); const operatorDmRequestDefinition = defineDocumentType({ type: operatorDmRequestDocumentType, schemaName: operatorDmRequestDocumentType, schemaId: operatorDmRequestSchemaId, schemaVersion: operatorDmRequestSchemaId, contentHash: operatorDmRequestSchemaId, global: false, name: "requestId", schema: { parse: parseObjectDocument("Operator DM request") }, }); const node = await CultMesh.createNode(storePath, { documents: [snapshotDefinition, providerDefinition, surfaceDefinition, eveBindingDefinition, operatorDmRequestDefinition], }); const providerAdvertisement = buildProviderAdvertisement(snapshot); const eveBinding = buildEveInterfaceBinding(snapshot, eveState); const operatorDmAdvertisement = buildOperatorDmProviderAdvertisement(snapshot); await node.put(snapshotDefinition, "voidbot-swarm", snapshot); await node.put(providerDefinition, providerId, providerAdvertisement); await node.put(providerDefinition, operatorDmProviderId, operatorDmAdvertisement); await node.put(surfaceDefinition, providerId, eveState); await node.put(eveBindingDefinition, providerId, eveBinding); await node.delete(surfaceDefinition, operatorDmProviderId); await node.delete(eveBindingDefinition, operatorDmProviderId); await node.flush?.(); return { writeStatus: "ok", storePath, documents: [snapshotDocumentType, providerAdvertisementDocumentType, surfaceDocumentType, eveBindingDocumentType, operatorDmRequestDocumentType], providerId, verseId, rootVerse, canonicalService, locatedService, cultMeshAddress: primaryCultMeshAddress(), eveBinding: { documentType: eveBindingDocumentType, schemaId: eveBindingSchemaId, key: providerId, }, eveDeckEndpoint: primaryCultMeshAddress(), routes: providerRoutes(providerId, storePath), writtenAt: new Date().toISOString(), }; } catch (error) { return { writeStatus: "failed", storePath, writeError: error instanceof Error ? error.message : String(error), }; } } function loadCultPackages() { const candidates = [ resolve(repoRoot, "..", "CultLib", "packages", "cultmesh-ts", "package.json"), ]; for (const packageJson of candidates) { if (!existsSync(packageJson)) { continue; } try { const requireCult = createRequire(packageJson); const { CultMesh } = requireCult("cultmesh-ts"); const { defineDocumentType } = requireCult("cultcache-ts"); if (CultMesh && defineDocumentType) { return { CultMesh, defineDocumentType }; } } catch { continue; } } return null; } function parseObjectDocument(label) { return (input) => { if (!input || typeof input !== "object") { throw new Error(`${label} must be an object.`); } return input; }; } function buildProviderAdvertisement(snapshot) { const endpoints = [ endpoint("tui", primaryCultMeshAddress(), surfaceSchemaId, ["tui", "nightwing-tui", "agent"]), endpoint("gui", `${locatedService}/swarm/eve/gui`, surfaceSchemaId, ["gui", "eve-native", "browser"]), ]; return { schemaVersion: providerAdvertisementSchemaId, providerId, verseId, rootVerse, canonicalService, locatedService, cultMeshAddress: primaryCultMeshAddress(), title: "VoidBot Swarm", description: "VoidBot swarm status, CTB order, controls, and selected Persona state as an Eve/CultUI surface.", version: String(snapshot.summary?.initiativeClock ?? Date.now()), status: snapshot.summary?.state ?? "unknown", updatedAt: snapshot.generatedAt, endpoints, routes: providerRoutes(providerId, snapshot.cultMesh?.storePath ?? cultMeshStorePath), provider: providerManifest(), controlSurface: { primary: primaryCultMeshAddress(), controls: { transport: "cultmesh-binding", documentType: eveBindingDocumentType, key: providerId, }, }, documents: [{ type: snapshotDocumentType, schemaId: snapshotSchemaId, key: "voidbot-swarm", }, { type: surfaceDocumentType, schemaId: surfaceSchemaId, key: providerId, }, { type: eveBindingDocumentType, schemaId: eveBindingSchemaId, key: providerId, }], }; } function buildEveInterfaceBinding(snapshot, eveState) { return { schemaVersion: eveBindingSchemaId, bindingId: providerId, providerId, verseId, rootVerse, canonicalService, locatedService, cultMeshAddress: primaryCultMeshAddress(), title: "VoidBot Swarm", kind: "eve-cultui-surface", updatedAt: snapshot.generatedAt, authority: { owner: "VoidBot swarm renderer", sourceDocuments: [{ type: snapshotDocumentType, schemaId: snapshotSchemaId, key: "voidbot-swarm", }], surfaceDocument: { type: surfaceDocumentType, schemaId: surfaceSchemaId, key: providerId, }, controlOwner: "VoidBot heartbeat state", }, surface: eveState.surface, stateSummary: { state: snapshot.summary?.state ?? "unknown", participantCount: snapshot.summary?.participantCount ?? 0, activeTurnCount: snapshot.summary?.activeTurnCount ?? 0, pendingMentionCount: snapshot.summary?.pendingMentionCount ?? 0, nextIdentityId: snapshot.summary?.nextIdentityId ?? null, nextDisplayName: snapshot.summary?.nextDisplayName ?? null, lastTickAt: snapshot.summary?.lastTickAt ?? null, }, controls: [{ id: "swarm.pause", label: "Pause swarm", command: "set-pause", writes: { documentType: eveBindingDocumentType, key: providerId, field: "controlIntent.pause", }, }, { id: "swarm.cadence", label: "Set cadence", command: "set-cadence-multiplier", writes: { documentType: eveBindingDocumentType, key: providerId, field: "controlIntent.cadenceMultiplier", }, }, { id: "swarm.force-turn", label: "Pull Persona forward", command: "force-turn", writes: { documentType: eveBindingDocumentType, key: providerId, field: "controlIntent.manualTurnRequests", }, }], rendererHints: { preferredLowerings: ["eve-native", "nightwing-tui", "browser"], viewportMode: "continuous-ops", tileId: "voidbot-swarm", minWidth: 112, minHeight: 30, preferredWidth: 156, preferredHeight: 58, priority: -30, density: "continuous", }, lowerings: [{ kind: "static-html", role: "local-debug-artifact", path: dashboardPath, }], }; } function providerManifest() { return { id: providerId, title: "VoidBot Swarm", description: "Native Eve tab for compact VoidBot CTB order with speed, heat, and turn state.", version: "1", endpoint: primaryCultMeshAddress(), cultMeshAddress: primaryCultMeshAddress(), endpoints: [ endpoint("tui", primaryCultMeshAddress(), surfaceSchemaId, ["tui", "nightwing-tui", "agent"]), endpoint("gui", `${locatedService}/swarm/eve/gui`, surfaceSchemaId, ["gui", "eve-native", "browser"]), ], routes: providerRoutes(providerId, cultMeshStorePath), capabilities: ["ctb", "agent-status", "cultmesh-snapshot"], usesCultMesh: true, transport: "CultMesh Eve interface binding.", }; } function buildOperatorDmProviderAdvertisement(snapshot) { return { schemaVersion: providerAdvertisementSchemaId, providerId: operatorDmProviderId, verseId, rootVerse, canonicalService, locatedService, cultMeshAddress: operatorDmCultMeshAddress(), title: "VoidBot Operator DM", description: "VoidBot-owned operator notification boundary for service alerts that need an owner DM.", version: String(snapshot.summary?.initiativeClock ?? Date.now()), status: ownerDmStatus(snapshot), updatedAt: snapshot.generatedAt, endpoints: [ endpoint("command", operatorDmCultMeshAddress(), operatorDmRequestSchemaId, ["command", "operator-alert"]), ], routes: providerRoutes(operatorDmProviderId, snapshot.cultMesh?.storePath ?? cultMeshStorePath), provider: operatorDmProviderManifest(snapshot), commandSurface: { primary: operatorDmCultMeshAddress(), transport: "cultmesh-interface-binding", commands: [ownerDmCommandDescriptor()], executionOwner: "VoidBot Discord owner-DM helper", executionNote: "Command delivery must be drained by VoidBot; Odin only discovers and lowers this provider-owned interface.", }, documents: [{ type: providerAdvertisementDocumentType, schemaId: providerAdvertisementSchemaId, key: operatorDmProviderId, }, { type: surfaceDocumentType, schemaId: surfaceSchemaId, key: operatorDmProviderId, }, { type: eveBindingDocumentType, schemaId: eveBindingSchemaId, key: operatorDmProviderId, }, { type: operatorDmRequestDocumentType, schemaId: operatorDmRequestSchemaId, key: "requestId", }], }; } function ownerDmCommandDescriptor() { return { id: "owner.dm.send", label: "Send owner DM", command: "owner.dm.send", transport: "cultmesh-command", payloadSchema: { schemaId: operatorDmRequestSchemaId, type: "object", required: ["message"], properties: { message: { type: "string", maxLength: 1800 }, severity: { type: "string" }, service: { type: "string" }, sourceId: { type: "string" }, reason: { type: "string" }, }, }, writes: { documentType: operatorDmRequestDocumentType, schemaId: operatorDmRequestSchemaId, owner: operatorDmProviderId, }, action: ownerDmCommandAction(), }; } function ownerDmCommandAction() { return { type: "owner.dm.send", command: "owner.dm.send", transport: "cultmesh-command", providerId: operatorDmProviderId, payloadSchemaId: operatorDmRequestSchemaId, }; } function operatorDmProviderManifest(snapshot) { return { id: operatorDmProviderId, title: "VoidBot Operator DM", description: "Provider-owned owner-DM command boundary for service intervention alerts.", version: "1", endpoint: operatorDmCultMeshAddress(), cultMeshAddress: operatorDmCultMeshAddress(), endpoints: [ endpoint("command", operatorDmCultMeshAddress(), operatorDmRequestSchemaId, ["command", "operator-alert"]), ], routes: providerRoutes(operatorDmProviderId, cultMeshStorePath), capabilities: ["operator-alerts", "owner-dm", "cultmesh-command"], usesCultMesh: true, status: ownerDmStatus(snapshot), transport: "CultMesh Eve interface binding.", commands: [ownerDmCommandDescriptor()], }; } function ownerDmStatus() { return env.DISCORD_BOT_TOKEN && env.DISCORD_OWNER_ID ? "active" : "degraded"; } function operatorDmCultMeshAddress() { return `${locatedService}/operator-dm/commands/owner-dm`; } function buildEveProviderState(snapshot) { const summary = snapshot.summary ?? {}; const participants = Array.isArray(snapshot.participants) ? snapshot.participants : []; const upcoming = Array.isArray(snapshot.upcomingTurns) ? snapshot.upcomingTurns : []; const orchestrator = snapshot.orchestrator ?? {}; const organs = Array.isArray(orchestrator.organs) ? orchestrator.organs : []; const watchdog = findSnapshotOrgan(organs, "voidbot-operations-watchdog") ?? findSnapshotOrgan(organs, "watchdog"); const nodes = [ { id: "voidbot-swarm", label: `VoidBot Swarm\n${summary.state ?? "unknown"}`, kind: "cultmesh-verse", visible: true, health: summary.state ?? "unknown", detail: `agents ${summary.participantCount ?? participants.length}; next ${summary.nextDisplayName ?? "none"}`, }, ...participants.slice(0, 24).map((participant, index) => ({ id: `face-${participant.identityId}`, label: `${participant.displayName}\n${participant.repoName}`, kind: "repo-persona", visible: true, x: -0.9 + (index % 6) * 0.36, y: -0.3 + Math.floor(index / 6) * 0.22, z: 0, rotation: 0, scale: 1, width: 0.26, height: 0.16, health: participant.activeJobId ? "running" : participant.restState?.isNapping ? "napping" : participant.status, detail: `next ${participant.nextTurnInMinutes ?? "?"}m; heat ${participant.heat ?? "?"}`, })), ]; return { type: "dashboard-state", schema: "mimir.eve_dashboard_state.v1", providerId, title: "VoidBot Swarm", version: Math.floor(Date.parse(snapshot.generatedAt ?? new Date().toISOString()) / 1000), updatedAt: snapshot.generatedAt, selectedNodeId: "voidbot-swarm", lutPreset: "terminal", nodes, surface: { schema: "gamecult.eve.surface.v1", id: "voidbot.swarm.surface", title: "VoidBot Swarm", root: eveNode("voidbot-cockpit", "cockpit", { title: "VoidBot Swarm", status: summary.state ?? "unknown", layout: { direction: "vertical", overflow: "scroll", gap: 8, padding: 8, grow: 5, minWidth: 112, minHeight: 30, preferredWidth: 156, preferredHeight: 58, priority: -30, density: "continuous", viewportMode: "continuous-ops", }, }, [ eveNode("ctb-rail", "rail", { title: "CTB order", layout: { direction: "vertical", overflow: "scroll", gap: 4, padding: 8, grow: 1, minWidth: 40, minHeight: 20 }, }, upcoming.slice(0, 14).map((turn, index) => eveNode(`turn-${stableId(turn.identityId)}-${index}`, "text", { role: "mono", text: formatTurnText(turn, index), status: turnStatus(turn), detail: `${turn.repoName ?? "repo"} / due ${minutesText(turn.nextTurnInMinutes)} / ${mentionDetail(turn)}`, }), )), ]), assets: [], }, }; } function eveNode(id, kind, props = {}, children = []) { return { id, kind, props, children }; } function stableId(value) { return String(value ?? "id") .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, "") || "id"; } function formatTurnText(turn, index) { const rank = String(index + 1).padStart(2, " "); const name = String(turn?.displayName ?? turn?.identityId ?? "face").padEnd(10, " "); const status = turnStatus(turn).padEnd(7, " "); const due = minutesText(turn?.nextTurnInMinutes).padStart(6, " "); const mention = mentionText(turn).padEnd(5, " "); return `${rank}. ${name} ${status} ${due} ${mention} s${formatNumber(turn?.effectiveSpeed, 3)} h${formatNumber(turn?.heat, 2)}`; } function turnStatus(turn) { if (turn?.activeJobId) return "active"; if (turn?.restState?.isNapping) return "nap"; if ((turn?.pendingMentionCount ?? 0) > 0) return "mention"; return "idle"; } function minutesText(value) { return typeof value === "number" ? value <= 0 ? `${value.toFixed(1)}m` : `${value.toFixed(value < 10 ? 1 : 0)}m` : "unknown"; } function mentionText(turn) { const count = turn?.pendingMentionCount ?? 0; if (count <= 0) return "-"; const unanchored = turn?.unanchoredMentionCount ?? 0; const anchored = turn?.anchoredMentionCount ?? Math.max(0, count - unanchored); if (unanchored > 0 && anchored <= 0) return `m?${count}`; if (unanchored > 0) return `m${anchored}?${unanchored}`; return `m${count}`; } function mentionDetail(turn) { const count = turn?.pendingMentionCount ?? 0; if (count <= 0) return "no pending mention"; const unanchored = turn?.unanchoredMentionCount ?? 0; if (unanchored > 0) { return `${count} pending mention(s), ${unanchored} missing source channel/message provenance`; } return `${count} pending anchored mention(s)`; } function formatNumber(value, decimals) { return typeof value === "number" && Number.isFinite(value) ? value.toFixed(decimals).replace(/\.?0+$/, "") : "?"; } function shortIso(value) { const timestamp = Date.parse(value ?? ""); if (!Number.isFinite(timestamp)) return "unknown"; const date = new Date(timestamp); return `${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")} ${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`; } function findSnapshotOrgan(organs, needle) { const lower = String(needle).toLowerCase(); return organs.find((organ) => String(organ?.id ?? "").toLowerCase().includes(lower) || String(organ?.label ?? "").toLowerCase().includes(lower)); } function renderHtml(snapshot) { return `