From bcd47d8b3943e5edb0885ef8dbd25be09183d118 Mon Sep 17 00:00:00 2001 From: orion Date: Sat, 4 Apr 2026 08:55:00 +0000 Subject: [PATCH] feat: populate monitor agents from openclaw list --- plugin/core/openclaw-agents.ts | 85 ++++++++++++++++++++++++++++++++++ plugin/index.ts | 3 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 plugin/core/openclaw-agents.ts diff --git a/plugin/core/openclaw-agents.ts b/plugin/core/openclaw-agents.ts new file mode 100644 index 0000000..b48a3c6 --- /dev/null +++ b/plugin/core/openclaw-agents.ts @@ -0,0 +1,85 @@ +import { execFile } from 'child_process'; +import { promisify } from 'util'; + +const execFileAsync = promisify(execFile); + +export interface OpenClawAgentInfo { + name: string; + isDefault?: boolean; + identity?: string; + workspace?: string; + agentDir?: string; + model?: string; + routingRules?: number; + routing?: string; +} + +export async function listOpenClawAgents(logger?: { debug?: (...args: any[]) => void; warn?: (...args: any[]) => void }): Promise { + try { + const { stdout } = await execFileAsync('openclaw', ['agents', 'list'], { + timeout: 15000, + maxBuffer: 1024 * 1024, + }); + return parseOpenClawAgents(stdout); + } catch (err) { + logger?.warn?.('Failed to run `openclaw agents list`', err); + return []; + } +} + +export function parseOpenClawAgents(text: string): OpenClawAgentInfo[] { + const lines = text.split(/\r?\n/); + const out: OpenClawAgentInfo[] = []; + let current: OpenClawAgentInfo | null = null; + + const push = () => { + if (current) out.push(current); + current = null; + }; + + for (const raw of lines) { + const line = raw.trimEnd(); + if (!line.trim() || line.startsWith('Agents:') || line.startsWith('Routing rules map') || line.startsWith('Channel status reflects')) continue; + if (line.startsWith('- ')) { + push(); + const m = line.match(/^-\s+(.+?)(?:\s+\((default)\))?$/); + current = { + name: m?.[1] || line.slice(2).trim(), + isDefault: m?.[2] === 'default', + }; + continue; + } + if (!current) continue; + const trimmed = line.trim(); + const idx = trimmed.indexOf(':'); + if (idx === -1) continue; + const key = trimmed.slice(0, idx).trim(); + const value = trimmed.slice(idx + 1).trim(); + switch (key) { + case 'Identity': + current.identity = value; + break; + case 'Workspace': + current.workspace = value; + break; + case 'Agent dir': + current.agentDir = value; + break; + case 'Model': + current.model = value; + break; + case 'Routing rules': { + const n = Number(value); + current.routingRules = Number.isFinite(n) ? n : undefined; + break; + } + case 'Routing': + current.routing = value; + break; + default: + break; + } + } + push(); + return out; +} diff --git a/plugin/index.ts b/plugin/index.ts index 62c69d4..24f0f1d 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -14,6 +14,7 @@ import { hostname, freemem, totalmem, uptime, loadavg, platform } from 'os'; import { getPluginConfig } from './core/config'; import { MonitorBridgeClient, type OpenClawMeta } from './core/monitor-bridge'; +import { listOpenClawAgents } from './core/openclaw-agents'; import { registerGatewayStartHook } from './hooks/gateway-start'; import { registerGatewayStopHook } from './hooks/gateway-stop'; import { @@ -120,7 +121,7 @@ export default { const meta: OpenClawMeta = { version: api.version || 'unknown', plugin_version: '0.3.1', - agents: [], // TODO: populate from api agent list when available + agents: await listOpenClawAgents(logger), }; const ok = await bridgeClient.pushOpenClawMeta(meta);