import path from 'node:path'; import os from 'node:os'; import { defineChannelPluginEntry } from 'openclaw/plugin-sdk/channel-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'; function centerApiBase(api) { const section = api.config?.channels?.['fabric']; return section?.centerApiBase ?? 'http://localhost:7001/api'; } let inbound = 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) { const cfg = (api.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), logger: api.logger }, client, identity); api.on('gateway_start', () => { const _G = globalThis; if (_G._fabricInboundStarted) return; _G._fabricInboundStarted = true; inbound = new FabricInbound(api.runtime, client, identity, api.logger); void inbound.start(); api.logger.info('fabric: inbound transport started'); }); api.on('gateway_stop', () => { inbound?.stop(); inbound = null; }); }, });