fix: cache channel doctor hook discovery

This commit is contained in:
Gustavo Madeira Santana
2026-04-21 23:28:46 -04:00
parent c976fc2199
commit 61758e3a41
2 changed files with 37 additions and 7 deletions

View File

@@ -384,6 +384,11 @@ describe("channel doctor compatibility mutations", () => {
personal: {},
},
},
slack: {
accounts: {
team: {},
},
},
},
};
const env = { OPENCLAW_HOME: "/tmp/openclaw-test-home" };
@@ -396,6 +401,12 @@ describe("channel doctor compatibility mutations", () => {
shouldSkipDefaultEmptyGroupAllowlistWarning,
},
},
{
id: "slack",
doctor: {
collectEmptyAllowlistExtraWarnings,
},
},
],
});
@@ -422,13 +433,20 @@ describe("channel doctor compatibility mutations", () => {
prefix: "channels.matrix.accounts.personal",
}),
).toEqual(["channels.matrix.accounts.personal extra"]);
expect(
hooks.extraWarningsForAccount({
account: {},
channelName: "slack",
prefix: "channels.slack.accounts.team",
}),
).toEqual(["channels.slack.accounts.team extra"]);
expect(mocks.resolveReadOnlyChannelPluginsForConfig).toHaveBeenCalledTimes(1);
expect(mocks.resolveReadOnlyChannelPluginsForConfig).toHaveBeenCalledWith(cfg, {
env,
includePersistedAuthState: false,
});
expect(collectEmptyAllowlistExtraWarnings).toHaveBeenCalledTimes(2);
expect(collectEmptyAllowlistExtraWarnings).toHaveBeenCalledTimes(3);
expect(shouldSkipDefaultEmptyGroupAllowlistWarning).toHaveBeenCalledTimes(1);
});
});

View File

@@ -16,6 +16,11 @@ type ChannelDoctorEntry = {
doctor: ChannelDoctorAdapter;
};
type ChannelDoctorPluginCandidate = {
id: string;
doctor?: ChannelDoctorAdapter;
};
type ChannelDoctorLookupContext = {
cfg: OpenClawConfig;
env?: NodeJS.ProcessEnv;
@@ -113,6 +118,12 @@ function safeListReadOnlyChannelPlugins(context: ChannelDoctorLookupContext) {
}
}
function listReadOnlyChannelPluginsById(
context: ChannelDoctorLookupContext,
): Map<string, ChannelDoctorPluginCandidate> {
return new Map(safeListReadOnlyChannelPlugins(context).map((plugin) => [plugin.id, plugin]));
}
function mergeDoctorAdapters(
adapters: Array<ChannelDoctorAdapter | undefined>,
): ChannelDoctorAdapter | undefined {
@@ -162,16 +173,16 @@ function isValidChannelDoctorAdapterValue(
function listChannelDoctorEntries(
channelIds: readonly string[],
context: ChannelDoctorLookupContext,
options: {
readOnlyPluginsById?: ReadonlyMap<string, ChannelDoctorPluginCandidate>;
} = {},
): ChannelDoctorEntry[] {
if (channelIds.length === 0) {
return [];
}
const selectedIds = new Set(channelIds);
const readOnlyPluginsById = new Map(
safeListReadOnlyChannelPlugins(context)
.filter((plugin) => selectedIds.has(plugin.id))
.map((plugin) => [plugin.id, plugin]),
);
const readOnlyPluginsById =
options.readOnlyPluginsById ?? listReadOnlyChannelPluginsById(context);
const entries: ChannelDoctorEntry[] = [];
for (const id of selectedIds) {
@@ -224,13 +235,14 @@ function shouldSkipDefaultEmptyGroupAllowlistWarningForEntries(
export function createChannelDoctorEmptyAllowlistPolicyHooks(
context: ChannelDoctorLookupContext,
): ChannelDoctorEmptyAllowlistPolicyHooks {
const readOnlyPluginsById = listReadOnlyChannelPluginsById(context);
const entriesByChannel = new Map<string, ChannelDoctorEntry[]>();
const entriesForChannel = (channelName: string) => {
const existing = entriesByChannel.get(channelName);
if (existing) {
return existing;
}
const entries = listChannelDoctorEntries([channelName], context);
const entries = listChannelDoctorEntries([channelName], context, { readOnlyPluginsById });
entriesByChannel.set(channelName, entries);
return entries;
};