mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 07:04:32 +00:00
Channels: move single-account config into accounts.default (#27334)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 50b5771808
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
committed by
GitHub
parent
da6a96ed33
commit
dfa0b5b4fc
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { ZodIssue } from "zod";
|
||||
import { normalizeChatChannelId } from "../channels/registry.js";
|
||||
import {
|
||||
isNumericTelegramUserId,
|
||||
normalizeTelegramAllowFromEntry,
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
isTrustedSafeBinPath,
|
||||
normalizeTrustedSafeBinDirs,
|
||||
} from "../infra/exec-safe-bin-trust.js";
|
||||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/session-key.js";
|
||||
import {
|
||||
isDiscordMutableAllowEntry,
|
||||
isGoogleChatMutableAllowEntry,
|
||||
@@ -207,6 +209,103 @@ function asObjectRecord(value: unknown): Record<string, unknown> | null {
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function normalizeBindingChannelKey(raw?: string | null): string {
|
||||
const normalized = normalizeChatChannelId(raw);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
}
|
||||
return (raw ?? "").trim().toLowerCase();
|
||||
}
|
||||
|
||||
export function collectMissingDefaultAccountBindingWarnings(cfg: OpenClawConfig): string[] {
|
||||
const channels = asObjectRecord(cfg.channels);
|
||||
if (!channels) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const bindings = Array.isArray(cfg.bindings) ? cfg.bindings : [];
|
||||
const warnings: string[] = [];
|
||||
|
||||
for (const [channelKey, rawChannel] of Object.entries(channels)) {
|
||||
const channel = asObjectRecord(rawChannel);
|
||||
if (!channel) {
|
||||
continue;
|
||||
}
|
||||
const accounts = asObjectRecord(channel.accounts);
|
||||
if (!accounts) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const normalizedAccountIds = Array.from(
|
||||
new Set(
|
||||
Object.keys(accounts)
|
||||
.map((accountId) => normalizeAccountId(accountId))
|
||||
.filter(Boolean),
|
||||
),
|
||||
);
|
||||
if (normalizedAccountIds.length === 0 || normalizedAccountIds.includes(DEFAULT_ACCOUNT_ID)) {
|
||||
continue;
|
||||
}
|
||||
const accountIdSet = new Set(normalizedAccountIds);
|
||||
const channelPattern = normalizeBindingChannelKey(channelKey);
|
||||
|
||||
let hasWildcardBinding = false;
|
||||
const coveredAccountIds = new Set<string>();
|
||||
for (const binding of bindings) {
|
||||
const bindingRecord = asObjectRecord(binding);
|
||||
if (!bindingRecord) {
|
||||
continue;
|
||||
}
|
||||
const match = asObjectRecord(bindingRecord.match);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchChannel =
|
||||
typeof match.channel === "string" ? normalizeBindingChannelKey(match.channel) : "";
|
||||
if (!matchChannel || matchChannel !== channelPattern) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rawAccountId = typeof match.accountId === "string" ? match.accountId.trim() : "";
|
||||
if (!rawAccountId) {
|
||||
continue;
|
||||
}
|
||||
if (rawAccountId === "*") {
|
||||
hasWildcardBinding = true;
|
||||
continue;
|
||||
}
|
||||
const normalizedBindingAccountId = normalizeAccountId(rawAccountId);
|
||||
if (accountIdSet.has(normalizedBindingAccountId)) {
|
||||
coveredAccountIds.add(normalizedBindingAccountId);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasWildcardBinding) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uncoveredAccountIds = normalizedAccountIds.filter(
|
||||
(accountId) => !coveredAccountIds.has(accountId),
|
||||
);
|
||||
if (uncoveredAccountIds.length === 0) {
|
||||
continue;
|
||||
}
|
||||
if (coveredAccountIds.size > 0) {
|
||||
warnings.push(
|
||||
`- channels.${channelKey}: accounts.default is missing and account bindings only cover a subset of configured accounts. Uncovered accounts: ${uncoveredAccountIds.join(", ")}. Add bindings[].match.accountId for uncovered accounts (or "*"), or add channels.${channelKey}.accounts.default.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
warnings.push(
|
||||
`- channels.${channelKey}: accounts.default is missing and no valid account-scoped binding exists for configured accounts (${normalizedAccountIds.join(", ")}). Channel-only bindings (no accountId) match only default. Add bindings[].match.accountId for one of these accounts (or "*"), or add channels.${channelKey}.accounts.default.`,
|
||||
);
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function collectTelegramAccountScopes(
|
||||
cfg: OpenClawConfig,
|
||||
): Array<{ prefix: string; account: Record<string, unknown> }> {
|
||||
@@ -1421,6 +1520,12 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const missingDefaultAccountBindingWarnings =
|
||||
collectMissingDefaultAccountBindingWarnings(candidate);
|
||||
if (missingDefaultAccountBindingWarnings.length > 0) {
|
||||
note(missingDefaultAccountBindingWarnings.join("\n"), "Doctor warnings");
|
||||
}
|
||||
|
||||
if (shouldRepair) {
|
||||
const repair = await maybeRepairTelegramAllowFromUsernames(candidate);
|
||||
if (repair.changes.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user