import path from 'node:path'; import os from 'node:os'; import { defineChannelPluginEntry } from 'openclaw/plugin-sdk/channel-core'; import type { OpenClawPluginApi } from 'openclaw/plugin-sdk/core'; import { FabricClient } from './src/fabric-client.js'; import { IdentityRegistry } from './src/identity.js'; import { FabricInbound } from './src/inbound.js'; import { buildFabricChannelPlugin } from './src/channel.js'; import { registerFabricTools } from './src/tools.js'; type PluginConfig = { identityFilePath?: string; debugMode?: boolean }; function centerApiBase(api: OpenClawPluginApi): string { const section = ((api.config as Record)?.channels as Record)?.[ 'fabric' ]; return section?.centerApiBase ?? 'http://localhost:7001/api'; } let inbound: FabricInbound | null = null; export default defineChannelPluginEntry({ id: 'fabric', name: 'Fabric', description: 'Fabric channel plugin — OpenClaw agents speak in Fabric guilds', // Channel object: config/security/outbound. Visible turn replies flow // through the inbound channel-turn delivery adapter; outbound.sendText // covers proactive sends via the shared message tool. plugin: buildFabricChannelPlugin(async () => ({ messageId: undefined })), // registerFull: runtime pieces (transport, tools). Guarded so the long-lived // Fabric connections start once per gateway process. registerFull(api: OpenClawPluginApi) { const cfg = (api.pluginConfig ?? {}) as PluginConfig; const identityFilePath = cfg.identityFilePath ?? path.join(os.homedir(), '.openclaw', 'fabric-identity.json'); const client = new FabricClient(centerApiBase(api)); const identity = new IdentityRegistry(identityFilePath); registerFabricTools( { registerTool: (d) => api.registerTool(d as never), logger: api.logger }, client, identity, ); api.on('gateway_start', () => { const _G = globalThis as Record; if (_G._fabricInboundStarted) return; _G._fabricInboundStarted = true; inbound = new FabricInbound( (api as unknown as { runtime: any }).runtime, client, identity, api.logger, ); void inbound.start(); api.logger.info('fabric: inbound transport started'); }); api.on('gateway_stop', () => { inbound?.stop(); inbound = null; }); }, });