From e2eee18e055f239801259b5cf52a8e40195ec310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E5=A4=A9?= Date: Sat, 23 May 2026 03:25:22 +0800 Subject: [PATCH] fix(channels): preserve Discord application id --- scripts/dev-api.js | 3 +++ src-tauri/src/commands/messaging.rs | 6 ++++++ src/pages/channels.js | 1 + tests/channel-config-normalization.test.js | 25 ++++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/scripts/dev-api.js b/scripts/dev-api.js index 696f180..20f2db3 100644 --- a/scripts/dev-api.js +++ b/scripts/dev-api.js @@ -2605,6 +2605,7 @@ export function buildMessagingPlatformFormValues(platform, saved = {}, options = if (storageKey === 'discord') { putSecretAwareFormValue(form, saved, 'token') + putStringFormValue(form, saved, 'applicationId') putAccessPolicyFormValues(form, saved) const guilds = saved.guilds && typeof saved.guilds === 'object' ? saved.guilds : null const guildId = guilds ? Object.keys(guilds)[0] : '' @@ -3130,6 +3131,7 @@ function buildOpenClawMessagingPlatformEntry(platform, form, currentSaved = {}) if (Array.isArray(form.allowFrom) && form.allowFrom.length) entry.allowFrom = form.allowFrom } else if (storageKey === 'discord') { entry.token = form.token + if (form.applicationId) entry.applicationId = form.applicationId entry.dmPolicy = form.dmPolicy entry.groupPolicy = form.groupPolicy if (Array.isArray(form.allowFrom) && form.allowFrom.length) entry.allowFrom = form.allowFrom @@ -4597,6 +4599,7 @@ const handlers = { if (Array.isArray(form.allowFrom) && form.allowFrom.length) entry.allowFrom = form.allowFrom } else if (platform === 'discord') { entry.token = form.token + if (form.applicationId) entry.applicationId = form.applicationId entry.dmPolicy = form.dmPolicy entry.groupPolicy = form.groupPolicy if (Array.isArray(form.allowFrom) && form.allowFrom.length) entry.allowFrom = form.allowFrom diff --git a/src-tauri/src/commands/messaging.rs b/src-tauri/src/commands/messaging.rs index f364bd5..bc4a6c5 100644 --- a/src-tauri/src/commands/messaging.rs +++ b/src-tauri/src/commands/messaging.rs @@ -731,6 +731,7 @@ pub async fn read_platform_config( // Discord 配置在 openclaw.json 中是展开的 guilds 结构 // 需要反向提取成表单字段:token, guildId, channelId insert_secret_aware_form_value(&mut form, &saved, "token"); + insert_string_if_present(&mut form, &saved, "applicationId"); insert_access_policy_form_values(&mut form, &saved, false, false); if let Some(guilds) = saved.get("guilds").and_then(|v| v.as_object()) { if let Some(gid) = guilds.keys().next() { @@ -1083,6 +1084,11 @@ pub async fn save_messaging_platform( if let Some(t) = form_obj.get("token").and_then(|v| v.as_str()) { entry.insert("token".into(), Value::String(t.trim().into())); } + put_string( + &mut entry, + "applicationId", + form_string(form_obj, "applicationId"), + ); entry.insert("enabled".into(), Value::Bool(true)); put_string(&mut entry, "dmPolicy", form_string(form_obj, "dmPolicy")); put_string( diff --git a/src/pages/channels.js b/src/pages/channels.js index d28d84f..4894b4c 100644 --- a/src/pages/channels.js +++ b/src/pages/channels.js @@ -143,6 +143,7 @@ const PLATFORM_REGISTRY = { guideFooter: t('channels.discordGuideFooter'), fields: [ { key: 'token', label: 'Bot Token', placeholder: 'MTExxxxxxxxx.Gxxxxxx.xxxxxxxx', secret: true, required: true }, + { key: 'applicationId', label: 'Application ID', placeholder: '123456789012345678', required: false }, { key: 'dmPolicy', label: t('channels.dmPolicy'), type: 'select', options: DM_POLICY_OPTIONS, required: false }, { key: 'groupPolicy', label: t('channels.groupPolicy'), type: 'select', options: GROUP_POLICY_OPTIONS(t('channels.groupAllChannels')), required: false }, { key: 'allowFrom', label: 'Allow From', placeholder: t('channels.allowFromPh'), required: false, hint: t('channels.allowFromHint') }, diff --git a/tests/channel-config-normalization.test.js b/tests/channel-config-normalization.test.js index 95bbbec..a641f9b 100644 --- a/tests/channel-config-normalization.test.js +++ b/tests/channel-config-normalization.test.js @@ -151,6 +151,16 @@ test('渠道读取会把 open + requireMention 反向回显为仅提及时策略 assert.equal(values.requireMention, 'true') }) +test('Discord 渠道读取会回显 applicationId', () => { + const values = buildMessagingPlatformFormValues('discord', { + token: 'discord-token', + applicationId: '123456789012345678', + }) + + assert.equal(values.token, 'discord-token') + assert.equal(values.applicationId, '123456789012345678') +}) + test('渠道保存会在用户改回所有群组时显式清除仅提及开关', () => { const form = normalizeMessagingPlatformForm('slack', { mode: 'socket', @@ -276,6 +286,21 @@ test('OpenClaw 渠道保存带账号标识时会写入 accounts 而不是覆盖 assert.equal(cfg.channels.slack.accounts['team-a'].appToken, 'team-app') }) +test('Discord 渠道保存会保留运行时需要的 applicationId', () => { + const cfg = { channels: {} } + + mergeOpenClawMessagingPlatformConfig(cfg, { + platform: 'discord', + form: { + token: 'discord-token', + applicationId: '123456789012345678', + }, + }) + + assert.equal(cfg.channels.discord.token, 'discord-token') + assert.equal(cfg.channels.discord.applicationId, '123456789012345678') +}) + test('OpenClaw 渠道保存第一个命名账号时会固定 defaultAccount', () => { const cfg = { channels: {} }