























@@ -1,12 +1,22 @@
11import { resolveChannelDmAllowFrom } from "../../../channels/plugins/dm-access.js";
2+import { normalizeAnyChannelId } from "../../../channels/registry.js";
3+import { GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA } from "../../../config/bundled-channel-config-metadata.generated.js";
24import type { OpenClawConfig } from "../../../config/types.openclaw.js";
35import { normalizeStringEntries } from "../../../shared/string-normalization.js";
46import { getDoctorChannelCapabilities } from "../channel-capabilities.js";
57import { asObjectRecord } from "./object.js";
6879const PSEUDO_CHANNEL_KEYS = new Set(["defaults", "modelByChannel", "tools"]);
10+const ACCOUNT_SCHEMA_WILDCARD = "*";
11+const CHANNEL_GROUP_ALLOW_FROM_PATH = ["groupAllowFrom"] as const;
12+const ACCOUNT_GROUP_ALLOW_FROM_PATH = [
13+"accounts",
14+ACCOUNT_SCHEMA_WILDCARD,
15+"groupAllowFrom",
16+] as const;
817918type ChannelRecord = Record<string, unknown>;
19+type SchemaPath = readonly string[];
10201121function isDisabled(record: ChannelRecord): boolean {
1222return record.enabled === false;
@@ -43,14 +53,72 @@ function readOwnDmAllowFrom(params: { channelName: string; account: ChannelRecor
4353);
4454}
455556+function findGeneratedChannelConfigSchema(channelName: string): Record<string, unknown> | undefined {
57+const normalizedChannelId = normalizeAnyChannelId(channelName);
58+return GENERATED_BUNDLED_CHANNEL_CONFIG_METADATA.find(
59+(entry) => entry.channelId === channelName || entry.channelId === normalizedChannelId,
60+)?.schema;
61+}
62+63+function schemaAllowsConfigPath(schema: unknown, path: SchemaPath): boolean {
64+if (path.length === 0) {
65+return true;
66+}
67+const node = asObjectRecord(schema);
68+if (!node) {
69+return true;
70+}
71+72+const anyOf = Array.isArray(node.anyOf) ? node.anyOf : undefined;
73+if (anyOf) {
74+return anyOf.some((branch) => schemaAllowsConfigPath(branch, path));
75+}
76+const oneOf = Array.isArray(node.oneOf) ? node.oneOf : undefined;
77+if (oneOf) {
78+return oneOf.some((branch) => schemaAllowsConfigPath(branch, path));
79+}
80+const allOf = Array.isArray(node.allOf) ? node.allOf : undefined;
81+if (allOf) {
82+return allOf.every((branch) => schemaAllowsConfigPath(branch, path));
83+}
84+85+const [segment, ...rest] = path;
86+const properties = asObjectRecord(node.properties);
87+if (
88+segment !== ACCOUNT_SCHEMA_WILDCARD &&
89+properties &&
90+Object.prototype.hasOwnProperty.call(properties, segment)
91+) {
92+return schemaAllowsConfigPath(properties[segment], rest);
93+}
94+95+const additionalProperties = node.additionalProperties;
96+if (additionalProperties === false) {
97+return false;
98+}
99+if (additionalProperties && typeof additionalProperties === "object") {
100+return schemaAllowsConfigPath(additionalProperties, rest);
101+}
102+return true;
103+}
104+105+function generatedSchemaAllowsGroupAllowFrom(channelName: string, path: SchemaPath): boolean {
106+const schema = findGeneratedChannelConfigSchema(channelName);
107+return !schema || schemaAllowsConfigPath(schema, path);
108+}
109+46110function migrateRecord(params: {
47111account: ChannelRecord;
112+canWriteGroupAllowFrom: boolean;
48113channelName: string;
49114changes: string[];
50115parent?: ChannelRecord;
51116parentHadGroupAllowFrom?: boolean;
52117prefix: string;
53118}): boolean {
119+if (!params.canWriteGroupAllowFrom) {
120+return false;
121+}
54122if (readGroupAllowFrom(params.account).length > 0) {
55123return false;
56124}
@@ -102,8 +170,13 @@ export function maybeRepairGroupAllowFromFallback(cfg: OpenClawConfig): {
102170}
103171104172const hadGroupAllowFrom = readGroupAllowFrom(channelConfig).length > 0;
173+const canWriteChannelGroupAllowFrom = generatedSchemaAllowsGroupAllowFrom(
174+channelName,
175+CHANNEL_GROUP_ALLOW_FROM_PATH,
176+);
105177migrateRecord({
106178account: channelConfig,
179+canWriteGroupAllowFrom: canWriteChannelGroupAllowFrom,
107180 channelName,
108181 changes,
109182prefix: `channels.${channelName}`,
@@ -113,13 +186,18 @@ export function maybeRepairGroupAllowFromFallback(cfg: OpenClawConfig): {
113186if (!accounts) {
114187continue;
115188}
189+const canWriteAccountGroupAllowFrom = generatedSchemaAllowsGroupAllowFrom(
190+channelName,
191+ACCOUNT_GROUP_ALLOW_FROM_PATH,
192+);
116193for (const [accountId, accountConfig] of Object.entries(accounts)) {
117194const account = asObjectRecord(accountConfig);
118195if (!account || isDisabled(account)) {
119196continue;
120197}
121198migrateRecord({
122199 account,
200+canWriteGroupAllowFrom: canWriteAccountGroupAllowFrom,
123201 channelName,
124202 changes,
125203parent: channelConfig,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。