refactor: share extension channel status summaries

This commit is contained in:
Peter Steinberger 2026-03-14 02:07:04 +00:00
parent e885f1999f
commit 97dc493e2a
8 changed files with 72 additions and 74 deletions

View File

@ -30,6 +30,7 @@ import {
type OpenClawConfig, type OpenClawConfig,
} from "openclaw/plugin-sdk/googlechat"; } from "openclaw/plugin-sdk/googlechat";
import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/googlechat"; import { GoogleChatConfigSchema } from "openclaw/plugin-sdk/googlechat";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { import {
listGoogleChatAccountIds, listGoogleChatAccountIds,
resolveDefaultGoogleChatAccountId, resolveDefaultGoogleChatAccountId,
@ -473,19 +474,13 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
} }
return issues; return issues;
}), }),
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) =>
configured: snapshot.configured ?? false, buildPassiveProbedChannelStatusSummary(snapshot, {
credentialSource: snapshot.credentialSource ?? "none", credentialSource: snapshot.credentialSource ?? "none",
audienceType: snapshot.audienceType ?? null, audienceType: snapshot.audienceType ?? null,
audience: snapshot.audience ?? null, audience: snapshot.audience ?? null,
webhookPath: snapshot.webhookPath ?? null, webhookPath: snapshot.webhookPath ?? null,
webhookUrl: snapshot.webhookUrl ?? null, webhookUrl: snapshot.webhookUrl ?? null,
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}), }),
probeAccount: async ({ account }) => probeGoogleChat(account), probeAccount: async ({ account }) => probeGoogleChat(account),
buildAccountSnapshot: ({ account, runtime, probe }) => { buildAccountSnapshot: ({ account, runtime, probe }) => {

View File

@ -29,6 +29,7 @@ import {
type ChannelPlugin, type ChannelPlugin,
type ResolvedIMessageAccount, type ResolvedIMessageAccount,
} from "openclaw/plugin-sdk/imessage"; } from "openclaw/plugin-sdk/imessage";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { getIMessageRuntime } from "./runtime.js"; import { getIMessageRuntime } from "./runtime.js";
const meta = getChatChannelMeta("imessage"); const meta = getChatChannelMeta("imessage");
@ -264,16 +265,10 @@ export const imessagePlugin: ChannelPlugin<ResolvedIMessageAccount> = {
dbPath: null, dbPath: null,
}, },
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("imessage", accounts), collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("imessage", accounts),
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) =>
configured: snapshot.configured ?? false, buildPassiveProbedChannelStatusSummary(snapshot, {
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
cliPath: snapshot.cliPath ?? null, cliPath: snapshot.cliPath ?? null,
dbPath: snapshot.dbPath ?? null, dbPath: snapshot.dbPath ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}), }),
probeAccount: async ({ timeoutMs }) => probeAccount: async ({ timeoutMs }) =>
getIMessageRuntime().channel.imessage.probeIMessage(timeoutMs), getIMessageRuntime().channel.imessage.probeIMessage(timeoutMs),

View File

@ -21,6 +21,7 @@ import {
type ChannelMessageActionName, type ChannelMessageActionName,
type ChannelPlugin, type ChannelPlugin,
} from "openclaw/plugin-sdk/mattermost"; } from "openclaw/plugin-sdk/mattermost";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { MattermostConfigSchema } from "./config-schema.js"; import { MattermostConfigSchema } from "./config-schema.js";
import { resolveMattermostGroupRequireMention } from "./group-mentions.js"; import { resolveMattermostGroupRequireMention } from "./group-mentions.js";
import { import {
@ -419,17 +420,11 @@ export const mattermostPlugin: ChannelPlugin<ResolvedMattermostAccount> = {
lastStopAt: null, lastStopAt: null,
lastError: null, lastError: null,
}, },
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) =>
configured: snapshot.configured ?? false, buildPassiveProbedChannelStatusSummary(snapshot, {
botTokenSource: snapshot.botTokenSource ?? "none", botTokenSource: snapshot.botTokenSource ?? "none",
running: snapshot.running ?? false,
connected: snapshot.connected ?? false, connected: snapshot.connected ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
baseUrl: snapshot.baseUrl ?? null, baseUrl: snapshot.baseUrl ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}), }),
probeAccount: async ({ account, timeoutMs }) => { probeAccount: async ({ account, timeoutMs }) => {
const token = account.botToken?.trim(); const token = account.botToken?.trim();

View File

@ -7,6 +7,7 @@ import {
mapAllowFromEntries, mapAllowFromEntries,
type ChannelPlugin, type ChannelPlugin,
} from "openclaw/plugin-sdk/nostr"; } from "openclaw/plugin-sdk/nostr";
import { buildPassiveChannelStatusSummary } from "../../shared/channel-status-summary.js";
import type { NostrProfile } from "./config-schema.js"; import type { NostrProfile } from "./config-schema.js";
import { NostrConfigSchema } from "./config-schema.js"; import { NostrConfigSchema } from "./config-schema.js";
import type { MetricEvent, MetricsSnapshot } from "./metrics.js"; import type { MetricEvent, MetricsSnapshot } from "./metrics.js";
@ -160,13 +161,9 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = {
status: { status: {
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID), defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID),
collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("nostr", accounts), collectStatusIssues: (accounts) => collectStatusIssuesFromLastError("nostr", accounts),
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) =>
configured: snapshot.configured ?? false, buildPassiveChannelStatusSummary(snapshot, {
publicKey: snapshot.publicKey ?? null, publicKey: snapshot.publicKey ?? null,
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
}), }),
buildAccountSnapshot: ({ account, runtime }) => ({ buildAccountSnapshot: ({ account, runtime }) => ({
accountId: account.accountId, accountId: account.accountId,

View File

@ -0,0 +1,34 @@
type PassiveChannelStatusSnapshot = {
configured?: boolean;
running?: boolean;
lastStartAt?: number | null;
lastStopAt?: number | null;
lastError?: string | null;
probe?: unknown;
lastProbeAt?: number | null;
};
export function buildPassiveChannelStatusSummary<TExtra extends object>(
snapshot: PassiveChannelStatusSnapshot,
extra?: TExtra,
) {
return {
configured: snapshot.configured ?? false,
...(extra ?? ({} as TExtra)),
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
};
}
export function buildPassiveProbedChannelStatusSummary<TExtra extends object>(
snapshot: PassiveChannelStatusSnapshot,
extra?: TExtra,
) {
return {
...buildPassiveChannelStatusSummary(snapshot, extra),
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
};
}

View File

@ -38,6 +38,7 @@ import {
type ChannelPlugin, type ChannelPlugin,
type ResolvedSlackAccount, type ResolvedSlackAccount,
} from "openclaw/plugin-sdk/slack"; } from "openclaw/plugin-sdk/slack";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { getSlackRuntime } from "./runtime.js"; import { getSlackRuntime } from "./runtime.js";
const meta = getChatChannelMeta("slack"); const meta = getChatChannelMeta("slack");
@ -421,16 +422,10 @@ export const slackPlugin: ChannelPlugin<ResolvedSlackAccount> = {
lastStopAt: null, lastStopAt: null,
lastError: null, lastError: null,
}, },
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) =>
configured: snapshot.configured ?? false, buildPassiveProbedChannelStatusSummary(snapshot, {
botTokenSource: snapshot.botTokenSource ?? "none", botTokenSource: snapshot.botTokenSource ?? "none",
appTokenSource: snapshot.appTokenSource ?? "none", appTokenSource: snapshot.appTokenSource ?? "none",
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}), }),
probeAccount: async ({ account, timeoutMs }) => { probeAccount: async ({ account, timeoutMs }) => {
const token = account.botToken?.trim(); const token = account.botToken?.trim();

View File

@ -7,6 +7,7 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/twitch"; import type { OpenClawConfig } from "openclaw/plugin-sdk/twitch";
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/twitch"; import { buildChannelConfigSchema } from "openclaw/plugin-sdk/twitch";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { twitchMessageActions } from "./actions.js"; import { twitchMessageActions } from "./actions.js";
import { removeClientManager } from "./client-manager-registry.js"; import { removeClientManager } from "./client-manager-registry.js";
import { TwitchConfigSchema } from "./config-schema.js"; import { TwitchConfigSchema } from "./config-schema.js";
@ -169,15 +170,8 @@ export const twitchPlugin: ChannelPlugin<TwitchAccountConfig> = {
}, },
/** Build channel summary from snapshot */ /** Build channel summary from snapshot */
buildChannelSummary: ({ snapshot }: { snapshot: ChannelAccountSnapshot }) => ({ buildChannelSummary: ({ snapshot }: { snapshot: ChannelAccountSnapshot }) =>
configured: snapshot.configured ?? false, buildPassiveProbedChannelStatusSummary(snapshot),
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}),
/** Probe account connection */ /** Probe account connection */
probeAccount: async ({ probeAccount: async ({

View File

@ -29,6 +29,7 @@ import {
sendPayloadWithChunkedTextAndMedia, sendPayloadWithChunkedTextAndMedia,
setAccountEnabledInConfigSection, setAccountEnabledInConfigSection,
} from "openclaw/plugin-sdk/zalouser"; } from "openclaw/plugin-sdk/zalouser";
import { buildPassiveProbedChannelStatusSummary } from "../../shared/channel-status-summary.js";
import { import {
listZalouserAccountIds, listZalouserAccountIds,
resolveDefaultZalouserAccountId, resolveDefaultZalouserAccountId,
@ -652,15 +653,7 @@ export const zalouserPlugin: ChannelPlugin<ResolvedZalouserAccount> = {
lastError: null, lastError: null,
}, },
collectStatusIssues: collectZalouserStatusIssues, collectStatusIssues: collectZalouserStatusIssues,
buildChannelSummary: ({ snapshot }) => ({ buildChannelSummary: ({ snapshot }) => buildPassiveProbedChannelStatusSummary(snapshot),
configured: snapshot.configured ?? false,
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
probe: snapshot.probe,
lastProbeAt: snapshot.lastProbeAt ?? null,
}),
probeAccount: async ({ account, timeoutMs }) => probeZalouser(account.profile, timeoutMs), probeAccount: async ({ account, timeoutMs }) => probeZalouser(account.profile, timeoutMs),
buildAccountSnapshot: async ({ account, runtime }) => { buildAccountSnapshot: async ({ account, runtime }) => {
const configured = await checkZcaAuthenticated(account.profile); const configured = await checkZcaAuthenticated(account.profile);