refactor: simplify channel doctor routing cleanup

This commit is contained in:
Gustavo Madeira Santana
2026-04-21 22:58:38 -04:00
parent 2dd324dad1
commit af6b44fdc4
4 changed files with 26 additions and 35 deletions

View File

@@ -62,7 +62,6 @@ export async function runDoctorRepairSequence(params: {
const emptyAllowlistWarnings = scanEmptyAllowlistPolicyWarnings(state.candidate, {
doctorFixCommand: params.doctorFixCommand,
env,
...createChannelDoctorEmptyAllowlistPolicyHooks({ cfg: state.candidate, env }),
});
if (emptyAllowlistWarnings.length > 0) {

View File

@@ -41,9 +41,7 @@ const channelDoctorBooleanKeys = new Set<keyof ChannelDoctorAdapter>([
"warnOnEmptyGroupSenderAllowlist",
]);
const channelDoctorStringEnumValues: Partial<
Record<keyof ChannelDoctorAdapter, ReadonlySet<string>>
> = {
const channelDoctorEnumValues: Partial<Record<keyof ChannelDoctorAdapter, ReadonlySet<string>>> = {
dmAllowFromMode: new Set(["topOnly", "topOrNested", "nestedOnly"]),
groupModel: new Set(["sender", "route", "hybrid"]),
};
@@ -106,36 +104,44 @@ function safeListReadOnlyChannelPlugins(context: ChannelDoctorLookupContext) {
function mergeDoctorAdapters(
adapters: Array<ChannelDoctorAdapter | undefined>,
): ChannelDoctorAdapter | undefined {
const merged: Record<string, unknown> = {};
const merged: Partial<Record<keyof ChannelDoctorAdapter, unknown>> = {};
for (const adapter of adapters) {
if (!adapter) {
continue;
}
for (const [key, value] of Object.entries(adapter)) {
if (merged[key] === undefined && isValidChannelDoctorAdapterValue(key, value)) {
merged[key] = value;
for (const [key, value] of Object.entries(adapter) as Array<
[keyof ChannelDoctorAdapter, unknown]
>) {
if (merged[key] !== undefined) {
continue;
}
if (!isValidChannelDoctorAdapterValue(key, value)) {
continue;
}
merged[key] = value;
}
}
return Object.keys(merged).length > 0 ? (merged as ChannelDoctorAdapter) : undefined;
}
function isValidChannelDoctorAdapterValue(key: string, value: unknown): boolean {
function isValidChannelDoctorAdapterValue(
key: keyof ChannelDoctorAdapter,
value: unknown,
): boolean {
if (value == null) {
return false;
}
const typedKey = key as keyof ChannelDoctorAdapter;
if (channelDoctorFunctionKeys.has(typedKey)) {
if (channelDoctorFunctionKeys.has(key)) {
return typeof value === "function";
}
if (channelDoctorBooleanKeys.has(typedKey)) {
if (channelDoctorBooleanKeys.has(key)) {
return typeof value === "boolean";
}
const enumValues = channelDoctorStringEnumValues[typedKey];
const enumValues = channelDoctorEnumValues[key];
if (enumValues) {
return typeof value === "string" && enumValues.has(value);
}
if (typedKey === "legacyConfigRules") {
if (key === "legacyConfigRules") {
return Array.isArray(value);
}
return false;
@@ -148,13 +154,14 @@ function listChannelDoctorEntries(
if (channelIds.length === 0) {
return [];
}
const byId = new Map<string, ChannelDoctorEntry>();
const selectedIds = new Set(channelIds);
const readOnlyPlugins = safeListReadOnlyChannelPlugins(context).filter((plugin) =>
selectedIds.has(plugin.id),
const readOnlyPluginsById = new Map(
safeListReadOnlyChannelPlugins(context)
.filter((plugin) => selectedIds.has(plugin.id))
.map((plugin) => [plugin.id, plugin]),
);
const readOnlyPluginsById = new Map(readOnlyPlugins.map((plugin) => [plugin.id, plugin]));
const entries: ChannelDoctorEntry[] = [];
for (const id of selectedIds) {
const doctor = mergeDoctorAdapters([
readOnlyPluginsById.get(id)?.doctor,
@@ -165,12 +172,9 @@ function listChannelDoctorEntries(
if (!doctor) {
continue;
}
const existing = byId.get(id);
if (!existing) {
byId.set(id, { doctor });
}
entries.push({ doctor });
}
return [...byId.values()];
return entries;
}
function toPluginEmptyAllowlistContext({

View File

@@ -4,19 +4,8 @@ import type { DoctorAccountRecord, DoctorAllowFromList } from "../types.js";
import { collectEmptyAllowlistPolicyWarningsForAccount } from "./empty-allowlist-policy.js";
import { asObjectRecord } from "./object.js";
export type EmptyAllowlistAccountScanParams = {
account: DoctorAccountRecord;
channelName: string;
cfg: OpenClawConfig;
dmPolicy?: string;
effectiveAllowFrom?: DoctorAllowFromList;
parent?: DoctorAccountRecord;
prefix: string;
};
type ScanEmptyAllowlistPolicyWarningsParams = {
doctorFixCommand: string;
env?: NodeJS.ProcessEnv;
extraWarningsForAccount?: (params: ChannelDoctorEmptyAllowlistAccountContext) => string[];
shouldSkipDefaultEmptyGroupAllowlistWarning?: (
params: ChannelDoctorEmptyAllowlistAccountContext,

View File

@@ -164,7 +164,6 @@ export async function collectDoctorPreviewWarnings(params: {
});
const emptyAllowlistWarnings = scanEmptyAllowlistPolicyWarnings(params.cfg, {
doctorFixCommand: params.doctorFixCommand,
env,
extraWarningsForAccount: emptyAllowlistHooks.extraWarningsForAccount,
shouldSkipDefaultEmptyGroupAllowlistWarning:
emptyAllowlistHooks.shouldSkipDefaultEmptyGroupAllowlistWarning,