@gakr-gakr/discord 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/account-inspect-api.ts +6 -0
- package/action-runtime-api.ts +1 -0
- package/api.ts +130 -0
- package/autobot.plugin.json +15 -0
- package/channel-config-api.ts +1 -0
- package/channel-plugin-api.ts +3 -0
- package/config-api.ts +4 -0
- package/configured-state.ts +6 -0
- package/contract-api.ts +21 -0
- package/directory-contract-api.ts +4 -0
- package/doctor-contract-api.ts +1 -0
- package/index.ts +24 -0
- package/package.json +79 -0
- package/runtime-api.actions.ts +15 -0
- package/runtime-api.lookup.ts +22 -0
- package/runtime-api.monitor.ts +50 -0
- package/runtime-api.send.ts +79 -0
- package/runtime-api.threads.ts +31 -0
- package/runtime-api.ts +181 -0
- package/runtime-setter-api.ts +3 -0
- package/secret-contract-api.ts +4 -0
- package/security-audit-contract-api.ts +1 -0
- package/security-contract-api.ts +4 -0
- package/session-key-api.ts +1 -0
- package/setup-entry.ts +9 -0
- package/setup-plugin-api.ts +3 -0
- package/src/account-inspect.ts +131 -0
- package/src/accounts.ts +205 -0
- package/src/actions/handle-action.guild-admin.ts +421 -0
- package/src/actions/handle-action.ts +402 -0
- package/src/actions/runtime.guild.ts +446 -0
- package/src/actions/runtime.messaging.messages.ts +226 -0
- package/src/actions/runtime.messaging.reactions.ts +67 -0
- package/src/actions/runtime.messaging.runtime.ts +73 -0
- package/src/actions/runtime.messaging.send.ts +336 -0
- package/src/actions/runtime.messaging.shared.ts +97 -0
- package/src/actions/runtime.messaging.ts +37 -0
- package/src/actions/runtime.moderation-shared.ts +48 -0
- package/src/actions/runtime.moderation.ts +116 -0
- package/src/actions/runtime.presence.ts +117 -0
- package/src/actions/runtime.shared.ts +86 -0
- package/src/actions/runtime.ts +87 -0
- package/src/api.ts +219 -0
- package/src/approval-handler.runtime.ts +636 -0
- package/src/approval-native.ts +219 -0
- package/src/approval-runtime.ts +14 -0
- package/src/approval-shared.ts +56 -0
- package/src/audit-core.ts +178 -0
- package/src/audit.ts +32 -0
- package/src/channel-actions.runtime.ts +1 -0
- package/src/channel-actions.ts +254 -0
- package/src/channel-api.ts +29 -0
- package/src/channel.conversation.ts +159 -0
- package/src/channel.loaders.ts +50 -0
- package/src/channel.runtime.ts +1 -0
- package/src/channel.setup.ts +12 -0
- package/src/channel.ts +728 -0
- package/src/chunk.ts +321 -0
- package/src/client.ts +143 -0
- package/src/component-custom-id.ts +72 -0
- package/src/components-registry.ts +356 -0
- package/src/components.builders.ts +410 -0
- package/src/components.modal.ts +124 -0
- package/src/components.parse.ts +407 -0
- package/src/components.ts +54 -0
- package/src/components.types.ts +187 -0
- package/src/config-schema.ts +6 -0
- package/src/config-ui-hints.ts +354 -0
- package/src/conversation-identity.ts +58 -0
- package/src/delivery-retry.ts +56 -0
- package/src/directory-cache.ts +116 -0
- package/src/directory-config.ts +58 -0
- package/src/directory-live.ts +135 -0
- package/src/doctor-contract.ts +477 -0
- package/src/doctor-shared.ts +5 -0
- package/src/doctor.ts +340 -0
- package/src/draft-chunking.ts +43 -0
- package/src/draft-stream.ts +162 -0
- package/src/error-body.ts +38 -0
- package/src/exec-approvals.ts +110 -0
- package/src/gateway-logging.ts +67 -0
- package/src/group-policy.ts +113 -0
- package/src/guilds.ts +29 -0
- package/src/inbound-event-delivery.ts +135 -0
- package/src/interactive-dispatch.ts +104 -0
- package/src/internal/api.commands.ts +51 -0
- package/src/internal/api.guild.ts +164 -0
- package/src/internal/api.interactions.ts +53 -0
- package/src/internal/api.messages.ts +113 -0
- package/src/internal/api.reactions.ts +38 -0
- package/src/internal/api.ts +61 -0
- package/src/internal/api.users.ts +19 -0
- package/src/internal/api.webhooks.ts +13 -0
- package/src/internal/client.ts +310 -0
- package/src/internal/command-deploy.ts +352 -0
- package/src/internal/commands.ts +188 -0
- package/src/internal/components.base.ts +65 -0
- package/src/internal/components.message.ts +279 -0
- package/src/internal/components.modal.ts +95 -0
- package/src/internal/components.ts +31 -0
- package/src/internal/discord.ts +11 -0
- package/src/internal/embeds.ts +35 -0
- package/src/internal/entity-cache.ts +98 -0
- package/src/internal/event-queue.ts +185 -0
- package/src/internal/gateway-close-codes.ts +25 -0
- package/src/internal/gateway-dispatch.ts +96 -0
- package/src/internal/gateway-identify-limiter.ts +26 -0
- package/src/internal/gateway-lifecycle.ts +75 -0
- package/src/internal/gateway-rate-limit.ts +104 -0
- package/src/internal/gateway.ts +479 -0
- package/src/internal/interaction-dispatch.ts +162 -0
- package/src/internal/interaction-options.ts +98 -0
- package/src/internal/interaction-response.ts +53 -0
- package/src/internal/interactions.ts +378 -0
- package/src/internal/listeners.ts +91 -0
- package/src/internal/modal-fields.ts +95 -0
- package/src/internal/payload.ts +69 -0
- package/src/internal/rest-body.ts +115 -0
- package/src/internal/rest-errors.ts +88 -0
- package/src/internal/rest-routes.ts +50 -0
- package/src/internal/rest-scheduler.ts +557 -0
- package/src/internal/rest.ts +322 -0
- package/src/internal/schemas.ts +36 -0
- package/src/internal/structures.ts +280 -0
- package/src/internal/test-builders.test-support.ts +167 -0
- package/src/internal/voice.ts +49 -0
- package/src/media-detection.ts +28 -0
- package/src/mentions.ts +147 -0
- package/src/monitor/ack-reactions.ts +70 -0
- package/src/monitor/agent-components-auth.ts +7 -0
- package/src/monitor/agent-components-context.ts +154 -0
- package/src/monitor/agent-components-data.ts +224 -0
- package/src/monitor/agent-components-dm-auth.ts +177 -0
- package/src/monitor/agent-components-guild-auth.ts +322 -0
- package/src/monitor/agent-components-helpers.runtime.ts +3 -0
- package/src/monitor/agent-components-helpers.ts +34 -0
- package/src/monitor/agent-components-reply.ts +10 -0
- package/src/monitor/agent-components.deps.runtime.ts +2 -0
- package/src/monitor/agent-components.dispatch.ts +359 -0
- package/src/monitor/agent-components.handlers.ts +303 -0
- package/src/monitor/agent-components.modal.ts +160 -0
- package/src/monitor/agent-components.plugin-interactive.ts +187 -0
- package/src/monitor/agent-components.runtime.ts +14 -0
- package/src/monitor/agent-components.system-controls.ts +215 -0
- package/src/monitor/agent-components.ts +70 -0
- package/src/monitor/agent-components.types.ts +58 -0
- package/src/monitor/agent-components.wildcard-controls.ts +171 -0
- package/src/monitor/allow-list.ts +631 -0
- package/src/monitor/auto-presence.ts +356 -0
- package/src/monitor/channel-access.ts +102 -0
- package/src/monitor/commands.ts +9 -0
- package/src/monitor/dm-command-auth.ts +259 -0
- package/src/monitor/dm-command-decision.ts +49 -0
- package/src/monitor/exec-approvals.ts +161 -0
- package/src/monitor/format.ts +45 -0
- package/src/monitor/gateway-handle.ts +34 -0
- package/src/monitor/gateway-metadata.ts +298 -0
- package/src/monitor/gateway-plugin.ts +302 -0
- package/src/monitor/gateway-registry.ts +37 -0
- package/src/monitor/gateway-supervisor.ts +206 -0
- package/src/monitor/inbound-context.ts +95 -0
- package/src/monitor/inbound-dedupe.ts +79 -0
- package/src/monitor/inbound-job.ts +118 -0
- package/src/monitor/listeners.queue.ts +91 -0
- package/src/monitor/listeners.reactions.ts +594 -0
- package/src/monitor/listeners.ts +150 -0
- package/src/monitor/message-channel-info.ts +96 -0
- package/src/monitor/message-forwarded.ts +114 -0
- package/src/monitor/message-handler.batch-gate.ts +19 -0
- package/src/monitor/message-handler.context.ts +492 -0
- package/src/monitor/message-handler.dm-preflight.ts +119 -0
- package/src/monitor/message-handler.draft-preview.ts +436 -0
- package/src/monitor/message-handler.hydration.ts +198 -0
- package/src/monitor/message-handler.module-test-helpers.ts +31 -0
- package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
- package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
- package/src/monitor/message-handler.preflight-context.ts +54 -0
- package/src/monitor/message-handler.preflight-helpers.ts +164 -0
- package/src/monitor/message-handler.preflight-history.ts +23 -0
- package/src/monitor/message-handler.preflight-logging.ts +36 -0
- package/src/monitor/message-handler.preflight-pluralkit.ts +28 -0
- package/src/monitor/message-handler.preflight-runtime.ts +28 -0
- package/src/monitor/message-handler.preflight-thread.ts +49 -0
- package/src/monitor/message-handler.preflight.ts +822 -0
- package/src/monitor/message-handler.preflight.types.ts +115 -0
- package/src/monitor/message-handler.process.ts +1033 -0
- package/src/monitor/message-handler.routing-preflight.ts +112 -0
- package/src/monitor/message-handler.ts +309 -0
- package/src/monitor/message-media.ts +536 -0
- package/src/monitor/message-run-queue.ts +101 -0
- package/src/monitor/message-text.ts +171 -0
- package/src/monitor/message-utils.ts +34 -0
- package/src/monitor/model-picker-preferences.ts +184 -0
- package/src/monitor/model-picker.state.ts +364 -0
- package/src/monitor/model-picker.test-utils.ts +26 -0
- package/src/monitor/model-picker.ts +38 -0
- package/src/monitor/model-picker.view.ts +722 -0
- package/src/monitor/native-command-agent-reply.ts +125 -0
- package/src/monitor/native-command-arg-ui.ts +233 -0
- package/src/monitor/native-command-auth.ts +309 -0
- package/src/monitor/native-command-bypass.ts +13 -0
- package/src/monitor/native-command-context.ts +109 -0
- package/src/monitor/native-command-dispatch.ts +35 -0
- package/src/monitor/native-command-model-picker-apply.ts +209 -0
- package/src/monitor/native-command-model-picker-interaction.ts +516 -0
- package/src/monitor/native-command-model-picker-ui.ts +357 -0
- package/src/monitor/native-command-reply.ts +185 -0
- package/src/monitor/native-command-route.ts +91 -0
- package/src/monitor/native-command-status.ts +76 -0
- package/src/monitor/native-command-ui.ts +26 -0
- package/src/monitor/native-command-ui.types.ts +20 -0
- package/src/monitor/native-command.args.ts +45 -0
- package/src/monitor/native-command.options.ts +153 -0
- package/src/monitor/native-command.runtime.ts +51 -0
- package/src/monitor/native-command.ts +747 -0
- package/src/monitor/native-command.types.ts +9 -0
- package/src/monitor/native-interaction-channel-context.ts +50 -0
- package/src/monitor/preflight-audio.runtime.ts +9 -0
- package/src/monitor/preflight-audio.ts +130 -0
- package/src/monitor/presence-cache.ts +61 -0
- package/src/monitor/presence.ts +50 -0
- package/src/monitor/provider-session.runtime.ts +12 -0
- package/src/monitor/provider.acp.ts +89 -0
- package/src/monitor/provider.allowlist.ts +398 -0
- package/src/monitor/provider.cleanup.ts +41 -0
- package/src/monitor/provider.commands.ts +129 -0
- package/src/monitor/provider.config-log.ts +45 -0
- package/src/monitor/provider.deploy-errors.ts +362 -0
- package/src/monitor/provider.deploy.ts +221 -0
- package/src/monitor/provider.interactions.ts +160 -0
- package/src/monitor/provider.lifecycle.ts +562 -0
- package/src/monitor/provider.runtime.ts +1 -0
- package/src/monitor/provider.startup-log.ts +32 -0
- package/src/monitor/provider.startup.ts +323 -0
- package/src/monitor/provider.ts +688 -0
- package/src/monitor/reply-context.ts +64 -0
- package/src/monitor/reply-delivery.ts +216 -0
- package/src/monitor/reply-safety.ts +96 -0
- package/src/monitor/rest-fetch.ts +97 -0
- package/src/monitor/route-resolution.ts +140 -0
- package/src/monitor/sender-identity.ts +81 -0
- package/src/monitor/startup-status.ts +10 -0
- package/src/monitor/status.ts +22 -0
- package/src/monitor/system-events.ts +55 -0
- package/src/monitor/thread-bindings.config.ts +35 -0
- package/src/monitor/thread-bindings.discord-api.ts +310 -0
- package/src/monitor/thread-bindings.lifecycle.ts +354 -0
- package/src/monitor/thread-bindings.manager.ts +554 -0
- package/src/monitor/thread-bindings.messages.ts +6 -0
- package/src/monitor/thread-bindings.persona.ts +25 -0
- package/src/monitor/thread-bindings.session-adapter.ts +229 -0
- package/src/monitor/thread-bindings.session-shared.ts +59 -0
- package/src/monitor/thread-bindings.session-updates.ts +35 -0
- package/src/monitor/thread-bindings.state.ts +540 -0
- package/src/monitor/thread-bindings.ts +48 -0
- package/src/monitor/thread-bindings.types.ts +83 -0
- package/src/monitor/thread-channel-context.ts +112 -0
- package/src/monitor/thread-session-close.ts +63 -0
- package/src/monitor/thread-title.ts +181 -0
- package/src/monitor/threading.auto-thread.ts +287 -0
- package/src/monitor/threading.cache.ts +45 -0
- package/src/monitor/threading.starter.ts +288 -0
- package/src/monitor/threading.ts +20 -0
- package/src/monitor/threading.types.ts +102 -0
- package/src/monitor/timeouts.ts +84 -0
- package/src/monitor/typing.ts +17 -0
- package/src/monitor.gateway.ts +75 -0
- package/src/monitor.ts +28 -0
- package/src/network-config.ts +79 -0
- package/src/normalize.ts +86 -0
- package/src/outbound-adapter.ts +327 -0
- package/src/outbound-approval.ts +29 -0
- package/src/outbound-components.ts +86 -0
- package/src/outbound-payload.ts +208 -0
- package/src/outbound-send-context.ts +92 -0
- package/src/outbound-session-route.ts +72 -0
- package/src/pluralkit.ts +58 -0
- package/src/preview-streaming.ts +18 -0
- package/src/probe.runtime.ts +1 -0
- package/src/probe.ts +237 -0
- package/src/proxy-fetch.ts +92 -0
- package/src/proxy-request-client.ts +21 -0
- package/src/recipient-resolution.ts +39 -0
- package/src/resolve-allowlist-common.ts +39 -0
- package/src/resolve-channels.ts +369 -0
- package/src/resolve-users.ts +184 -0
- package/src/retry.ts +98 -0
- package/src/runtime-api.ts +64 -0
- package/src/runtime-config.ts +16 -0
- package/src/runtime.ts +23 -0
- package/src/secret-config-contract.ts +140 -0
- package/src/security-audit.runtime.ts +1 -0
- package/src/security-audit.ts +208 -0
- package/src/security-contract.ts +47 -0
- package/src/security-doctor.ts +20 -0
- package/src/security.ts +60 -0
- package/src/send-target-parsing.ts +14 -0
- package/src/send.channels.ts +139 -0
- package/src/send.components.ts +391 -0
- package/src/send.emojis-stickers.ts +57 -0
- package/src/send.guild.ts +170 -0
- package/src/send.message-request.ts +112 -0
- package/src/send.messages.ts +229 -0
- package/src/send.outbound.ts +459 -0
- package/src/send.permissions.ts +283 -0
- package/src/send.reactions.ts +155 -0
- package/src/send.receipt.ts +69 -0
- package/src/send.shared.ts +469 -0
- package/src/send.ts +82 -0
- package/src/send.types.ts +191 -0
- package/src/send.typing.ts +9 -0
- package/src/send.voice.ts +140 -0
- package/src/send.webhook.ts +137 -0
- package/src/session-contract.ts +3 -0
- package/src/session-key-normalization.ts +47 -0
- package/src/setup-account-state.ts +144 -0
- package/src/setup-adapter.ts +14 -0
- package/src/setup-core.ts +215 -0
- package/src/setup-runtime-helpers.ts +10 -0
- package/src/setup-surface.ts +132 -0
- package/src/shared-interactive.ts +167 -0
- package/src/shared.ts +197 -0
- package/src/status-issues.ts +201 -0
- package/src/subagent-hooks.ts +232 -0
- package/src/target-parsing.ts +70 -0
- package/src/target-resolver.ts +129 -0
- package/src/targets.ts +12 -0
- package/src/token.ts +107 -0
- package/src/ui-colors.ts +27 -0
- package/src/ui.ts +20 -0
- package/src/voice/access.ts +126 -0
- package/src/voice/audio.ts +249 -0
- package/src/voice/capture-state.ts +120 -0
- package/src/voice/command.ts +284 -0
- package/src/voice/config.ts +8 -0
- package/src/voice/ingress.ts +164 -0
- package/src/voice/manager.runtime.ts +14 -0
- package/src/voice/manager.ts +1155 -0
- package/src/voice/prompt.ts +22 -0
- package/src/voice/realtime.ts +1370 -0
- package/src/voice/receive-recovery.ts +159 -0
- package/src/voice/sanitize.ts +29 -0
- package/src/voice/sdk-runtime.ts +14 -0
- package/src/voice/segment.ts +160 -0
- package/src/voice/session.ts +81 -0
- package/src/voice/speaker-context.ts +127 -0
- package/src/voice/tts.ts +151 -0
- package/src/voice-message.ts +474 -0
- package/subagent-hooks-api.ts +27 -0
- package/test-api.ts +4 -0
- package/thread-binding-api.ts +1 -0
- package/timeouts.ts +6 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChannelDirectoryEntry,
|
|
3
|
+
DirectoryConfigParams,
|
|
4
|
+
} from "autobot/plugin-sdk/directory-runtime";
|
|
5
|
+
import { normalizeOptionalLowercaseString } from "autobot/plugin-sdk/string-coerce-runtime";
|
|
6
|
+
import { resolveDiscordAccount } from "./accounts.js";
|
|
7
|
+
import { fetchDiscord } from "./api.js";
|
|
8
|
+
import { rememberDiscordDirectoryUser } from "./directory-cache.js";
|
|
9
|
+
import { normalizeDiscordSlug } from "./monitor/allow-list.js";
|
|
10
|
+
import { normalizeDiscordToken } from "./token.js";
|
|
11
|
+
|
|
12
|
+
type DiscordGuild = { id: string; name: string };
|
|
13
|
+
type DiscordUser = { id: string; username: string; global_name?: string; bot?: boolean };
|
|
14
|
+
type DiscordMember = { user: DiscordUser; nick?: string | null };
|
|
15
|
+
type DiscordChannel = { id: string; name?: string | null };
|
|
16
|
+
type DiscordDirectoryAccess = { token: string; query: string; accountId: string };
|
|
17
|
+
|
|
18
|
+
function normalizeQuery(value?: string | null): string {
|
|
19
|
+
return normalizeOptionalLowercaseString(value) ?? "";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildUserRank(user: DiscordUser): number {
|
|
23
|
+
return user.bot ? 0 : 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function resolveDiscordDirectoryAccess(
|
|
27
|
+
params: DirectoryConfigParams,
|
|
28
|
+
): DiscordDirectoryAccess | null {
|
|
29
|
+
const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId });
|
|
30
|
+
const token = normalizeDiscordToken(account.token, "channels.discord.token");
|
|
31
|
+
if (!token) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return { token, query: normalizeQuery(params.query), accountId: account.accountId };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function listDiscordGuilds(token: string): Promise<DiscordGuild[]> {
|
|
38
|
+
const rawGuilds = await fetchDiscord<DiscordGuild[]>("/users/@me/guilds", token);
|
|
39
|
+
return rawGuilds.filter((guild) => guild.id && guild.name);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function listDiscordDirectoryGroupsLive(
|
|
43
|
+
params: DirectoryConfigParams,
|
|
44
|
+
): Promise<ChannelDirectoryEntry[]> {
|
|
45
|
+
const access = resolveDiscordDirectoryAccess(params);
|
|
46
|
+
if (!access) {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const { token, query } = access;
|
|
50
|
+
const guilds = await listDiscordGuilds(token);
|
|
51
|
+
const rows: ChannelDirectoryEntry[] = [];
|
|
52
|
+
|
|
53
|
+
for (const guild of guilds) {
|
|
54
|
+
const channels = await fetchDiscord<DiscordChannel[]>(`/guilds/${guild.id}/channels`, token);
|
|
55
|
+
for (const channel of channels) {
|
|
56
|
+
const name = channel.name?.trim();
|
|
57
|
+
if (!name) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (query && !normalizeDiscordSlug(name).includes(normalizeDiscordSlug(query))) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
rows.push({
|
|
64
|
+
kind: "group",
|
|
65
|
+
id: `channel:${channel.id}`,
|
|
66
|
+
name,
|
|
67
|
+
handle: `#${name}`,
|
|
68
|
+
raw: channel,
|
|
69
|
+
});
|
|
70
|
+
if (typeof params.limit === "number" && params.limit > 0 && rows.length >= params.limit) {
|
|
71
|
+
return rows;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return rows;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function listDiscordDirectoryPeersLive(
|
|
80
|
+
params: DirectoryConfigParams,
|
|
81
|
+
): Promise<ChannelDirectoryEntry[]> {
|
|
82
|
+
const access = resolveDiscordDirectoryAccess(params);
|
|
83
|
+
if (!access) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const { token, query, accountId } = access;
|
|
87
|
+
if (!query) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const guilds = await listDiscordGuilds(token);
|
|
92
|
+
const rows: ChannelDirectoryEntry[] = [];
|
|
93
|
+
const limit = typeof params.limit === "number" && params.limit > 0 ? params.limit : 25;
|
|
94
|
+
|
|
95
|
+
for (const guild of guilds) {
|
|
96
|
+
const paramsObj = new URLSearchParams({
|
|
97
|
+
query,
|
|
98
|
+
limit: String(Math.min(limit, 100)),
|
|
99
|
+
});
|
|
100
|
+
const members = await fetchDiscord<DiscordMember[]>(
|
|
101
|
+
`/guilds/${guild.id}/members/search?${paramsObj.toString()}`,
|
|
102
|
+
token,
|
|
103
|
+
);
|
|
104
|
+
for (const member of members) {
|
|
105
|
+
const user = member.user;
|
|
106
|
+
if (!user?.id) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
rememberDiscordDirectoryUser({
|
|
110
|
+
accountId,
|
|
111
|
+
userId: user.id,
|
|
112
|
+
handles: [
|
|
113
|
+
user.username,
|
|
114
|
+
user.global_name,
|
|
115
|
+
member.nick,
|
|
116
|
+
user.username ? `@${user.username}` : null,
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
const name = member.nick?.trim() || user.global_name?.trim() || user.username?.trim();
|
|
120
|
+
rows.push({
|
|
121
|
+
kind: "user",
|
|
122
|
+
id: `user:${user.id}`,
|
|
123
|
+
name: name || undefined,
|
|
124
|
+
handle: user.username ? `@${user.username}` : undefined,
|
|
125
|
+
rank: buildUserRank(user),
|
|
126
|
+
raw: member,
|
|
127
|
+
});
|
|
128
|
+
if (rows.length >= limit) {
|
|
129
|
+
return rows;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return rows;
|
|
135
|
+
}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ChannelDoctorConfigMutation,
|
|
3
|
+
ChannelDoctorLegacyConfigRule,
|
|
4
|
+
} from "autobot/plugin-sdk/channel-contract";
|
|
5
|
+
import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
|
|
6
|
+
import { asObjectRecord, normalizeLegacyChannelAliases } from "autobot/plugin-sdk/runtime-doctor";
|
|
7
|
+
import { resolveDiscordPreviewStreamMode } from "./preview-streaming.js";
|
|
8
|
+
|
|
9
|
+
const LEGACY_TTS_PROVIDER_KEYS = ["openai", "elevenlabs", "microsoft", "edge"] as const;
|
|
10
|
+
type AgentBindingConfig = NonNullable<AutoBotConfig["bindings"]>[number];
|
|
11
|
+
|
|
12
|
+
function hasLegacyTtsProviderKeys(value: unknown): boolean {
|
|
13
|
+
const tts = asObjectRecord(value);
|
|
14
|
+
if (!tts) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return LEGACY_TTS_PROVIDER_KEYS.some((key) => Object.prototype.hasOwnProperty.call(tts, key));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function hasLegacyDiscordAccountTtsProviderKeys(value: unknown): boolean {
|
|
21
|
+
const accounts = asObjectRecord(value);
|
|
22
|
+
if (!accounts) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return Object.values(accounts).some((accountValue) => {
|
|
26
|
+
const account = asObjectRecord(accountValue);
|
|
27
|
+
const voice = asObjectRecord(account?.voice);
|
|
28
|
+
return hasLegacyTtsProviderKeys(voice?.tts);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function hasLegacyDiscordGuildChannelAllowAlias(value: unknown): boolean {
|
|
33
|
+
const guilds = asObjectRecord(asObjectRecord(value)?.guilds);
|
|
34
|
+
if (!guilds) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return Object.values(guilds).some((guildValue) => {
|
|
38
|
+
const channels = asObjectRecord(asObjectRecord(guildValue)?.channels);
|
|
39
|
+
if (!channels) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return Object.values(channels).some((channel) =>
|
|
43
|
+
Object.prototype.hasOwnProperty.call(asObjectRecord(channel) ?? {}, "allow"),
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function hasLegacyDiscordGuildChannelAgentId(value: unknown): boolean {
|
|
49
|
+
const guilds = asObjectRecord(asObjectRecord(value)?.guilds);
|
|
50
|
+
if (!guilds) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return Object.values(guilds).some((guildValue) => {
|
|
54
|
+
const channels = asObjectRecord(asObjectRecord(guildValue)?.channels);
|
|
55
|
+
if (!channels) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return Object.values(channels).some((channel) =>
|
|
59
|
+
Object.prototype.hasOwnProperty.call(asObjectRecord(channel) ?? {}, "agentId"),
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hasLegacyDiscordAccountGuildChannelAllowAlias(value: unknown): boolean {
|
|
65
|
+
const accounts = asObjectRecord(value);
|
|
66
|
+
if (!accounts) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return Object.values(accounts).some((account) => hasLegacyDiscordGuildChannelAllowAlias(account));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function hasLegacyDiscordAccountGuildChannelAgentId(value: unknown): boolean {
|
|
73
|
+
const accounts = asObjectRecord(value);
|
|
74
|
+
if (!accounts) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return Object.values(accounts).some((account) => hasLegacyDiscordGuildChannelAgentId(account));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function mergeMissing(target: Record<string, unknown>, source: Record<string, unknown>) {
|
|
81
|
+
for (const [key, value] of Object.entries(source)) {
|
|
82
|
+
if (value === undefined) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const existing = target[key];
|
|
86
|
+
if (existing === undefined) {
|
|
87
|
+
target[key] = value;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (
|
|
91
|
+
existing &&
|
|
92
|
+
typeof existing === "object" &&
|
|
93
|
+
!Array.isArray(existing) &&
|
|
94
|
+
value &&
|
|
95
|
+
typeof value === "object" &&
|
|
96
|
+
!Array.isArray(value)
|
|
97
|
+
) {
|
|
98
|
+
mergeMissing(existing as Record<string, unknown>, value as Record<string, unknown>);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getOrCreateTtsProviders(tts: Record<string, unknown>): Record<string, unknown> {
|
|
104
|
+
const providers = asObjectRecord(tts.providers) ?? {};
|
|
105
|
+
tts.providers = providers;
|
|
106
|
+
return providers;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function mergeLegacyTtsProviderConfig(
|
|
110
|
+
tts: Record<string, unknown>,
|
|
111
|
+
legacyKey: string,
|
|
112
|
+
providerId: string,
|
|
113
|
+
): boolean {
|
|
114
|
+
const legacyValue = asObjectRecord(tts[legacyKey]);
|
|
115
|
+
if (!legacyValue) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
const providers = getOrCreateTtsProviders(tts);
|
|
119
|
+
const existing = asObjectRecord(providers[providerId]) ?? {};
|
|
120
|
+
const merged = structuredClone(existing);
|
|
121
|
+
mergeMissing(merged, legacyValue);
|
|
122
|
+
providers[providerId] = merged;
|
|
123
|
+
delete tts[legacyKey];
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function migrateLegacyTtsConfig(
|
|
128
|
+
tts: Record<string, unknown> | null,
|
|
129
|
+
pathLabel: string,
|
|
130
|
+
changes: string[],
|
|
131
|
+
): boolean {
|
|
132
|
+
if (!tts) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
let changed = false;
|
|
136
|
+
if (mergeLegacyTtsProviderConfig(tts, "openai", "openai")) {
|
|
137
|
+
changes.push(`Moved ${pathLabel}.openai → ${pathLabel}.providers.openai.`);
|
|
138
|
+
changed = true;
|
|
139
|
+
}
|
|
140
|
+
if (mergeLegacyTtsProviderConfig(tts, "elevenlabs", "elevenlabs")) {
|
|
141
|
+
changes.push(`Moved ${pathLabel}.elevenlabs → ${pathLabel}.providers.elevenlabs.`);
|
|
142
|
+
changed = true;
|
|
143
|
+
}
|
|
144
|
+
if (mergeLegacyTtsProviderConfig(tts, "microsoft", "microsoft")) {
|
|
145
|
+
changes.push(`Moved ${pathLabel}.microsoft → ${pathLabel}.providers.microsoft.`);
|
|
146
|
+
changed = true;
|
|
147
|
+
}
|
|
148
|
+
if (mergeLegacyTtsProviderConfig(tts, "edge", "microsoft")) {
|
|
149
|
+
changes.push(`Moved ${pathLabel}.edge → ${pathLabel}.providers.microsoft.`);
|
|
150
|
+
changed = true;
|
|
151
|
+
}
|
|
152
|
+
return changed;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function normalizeDiscordGuildChannelAllowAliases(params: {
|
|
156
|
+
entry: Record<string, unknown>;
|
|
157
|
+
pathPrefix: string;
|
|
158
|
+
changes: string[];
|
|
159
|
+
}): { entry: Record<string, unknown>; changed: boolean } {
|
|
160
|
+
const guilds = asObjectRecord(params.entry.guilds);
|
|
161
|
+
if (!guilds) {
|
|
162
|
+
return { entry: params.entry, changed: false };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let changed = false;
|
|
166
|
+
const nextGuilds = { ...guilds };
|
|
167
|
+
for (const [guildId, guildValue] of Object.entries(guilds)) {
|
|
168
|
+
const guild = asObjectRecord(guildValue);
|
|
169
|
+
const channels = asObjectRecord(guild?.channels);
|
|
170
|
+
if (!guild || !channels) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
let channelsChanged = false;
|
|
174
|
+
const nextChannels = { ...channels };
|
|
175
|
+
for (const [channelId, channelValue] of Object.entries(channels)) {
|
|
176
|
+
const channel = asObjectRecord(channelValue);
|
|
177
|
+
if (!channel || !Object.prototype.hasOwnProperty.call(channel, "allow")) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const nextChannel = { ...channel };
|
|
181
|
+
if (nextChannel.enabled === undefined) {
|
|
182
|
+
nextChannel.enabled = channel.allow;
|
|
183
|
+
params.changes.push(
|
|
184
|
+
`Moved ${params.pathPrefix}.guilds.${guildId}.channels.${channelId}.allow → ${params.pathPrefix}.guilds.${guildId}.channels.${channelId}.enabled.`,
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
params.changes.push(
|
|
188
|
+
`Removed ${params.pathPrefix}.guilds.${guildId}.channels.${channelId}.allow (${params.pathPrefix}.guilds.${guildId}.channels.${channelId}.enabled already set).`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
delete nextChannel.allow;
|
|
192
|
+
nextChannels[channelId] = nextChannel;
|
|
193
|
+
channelsChanged = true;
|
|
194
|
+
}
|
|
195
|
+
if (!channelsChanged) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
nextGuilds[guildId] = { ...guild, channels: nextChannels };
|
|
199
|
+
changed = true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return changed
|
|
203
|
+
? { entry: { ...params.entry, guilds: nextGuilds }, changed: true }
|
|
204
|
+
: { entry: params.entry, changed: false };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function isDiscordChannelAgentBinding(
|
|
208
|
+
value: unknown,
|
|
209
|
+
match: { accountId?: string; guildId: string; channelId: string },
|
|
210
|
+
): value is Record<string, unknown> {
|
|
211
|
+
const binding = asObjectRecord(value);
|
|
212
|
+
const bindingMatch = asObjectRecord(binding?.match);
|
|
213
|
+
const peer = asObjectRecord(bindingMatch?.peer);
|
|
214
|
+
if (!binding || !bindingMatch || !peer) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
return (
|
|
218
|
+
bindingMatch.channel === "discord" &&
|
|
219
|
+
bindingMatch.guildId === match.guildId &&
|
|
220
|
+
(match.accountId === undefined || bindingMatch.accountId === match.accountId) &&
|
|
221
|
+
peer.kind === "channel" &&
|
|
222
|
+
peer.id === match.channelId
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function normalizeDiscordGuildChannelAgentIds(params: {
|
|
227
|
+
cfg: AutoBotConfig;
|
|
228
|
+
entry: Record<string, unknown>;
|
|
229
|
+
pathPrefix: string;
|
|
230
|
+
accountId?: string;
|
|
231
|
+
changes: string[];
|
|
232
|
+
bindingsToAdd: AgentBindingConfig[];
|
|
233
|
+
}): { entry: Record<string, unknown>; changed: boolean } {
|
|
234
|
+
const guilds = asObjectRecord(params.entry.guilds);
|
|
235
|
+
if (!guilds) {
|
|
236
|
+
return { entry: params.entry, changed: false };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const existingBindings = Array.isArray(params.cfg.bindings) ? params.cfg.bindings : [];
|
|
240
|
+
let changed = false;
|
|
241
|
+
const nextGuilds = { ...guilds };
|
|
242
|
+
for (const [guildId, guildValue] of Object.entries(guilds)) {
|
|
243
|
+
const guild = asObjectRecord(guildValue);
|
|
244
|
+
const channels = asObjectRecord(guild?.channels);
|
|
245
|
+
if (!guild || !channels) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
let channelsChanged = false;
|
|
249
|
+
const nextChannels = { ...channels };
|
|
250
|
+
for (const [channelId, channelValue] of Object.entries(channels)) {
|
|
251
|
+
const channel = asObjectRecord(channelValue);
|
|
252
|
+
if (!channel || !Object.prototype.hasOwnProperty.call(channel, "agentId")) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const nextChannel = { ...channel };
|
|
256
|
+
const rawAgentId = nextChannel.agentId;
|
|
257
|
+
delete nextChannel.agentId;
|
|
258
|
+
nextChannels[channelId] = nextChannel;
|
|
259
|
+
channelsChanged = true;
|
|
260
|
+
|
|
261
|
+
const path = `${params.pathPrefix}.guilds.${guildId}.channels.${channelId}.agentId`;
|
|
262
|
+
const agentId = typeof rawAgentId === "string" ? rawAgentId.trim() : "";
|
|
263
|
+
if (!agentId) {
|
|
264
|
+
params.changes.push(
|
|
265
|
+
`Removed ${path}; configure top-level bindings[] for per-channel Discord agent routing.`,
|
|
266
|
+
);
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const match = { accountId: params.accountId, guildId, channelId };
|
|
271
|
+
const existingBinding = existingBindings.find((binding) =>
|
|
272
|
+
isDiscordChannelAgentBinding(binding, match),
|
|
273
|
+
);
|
|
274
|
+
if (existingBinding) {
|
|
275
|
+
params.changes.push(
|
|
276
|
+
`Removed ${path}; a matching top-level bindings[] route already exists for Discord channel ${channelId}.`,
|
|
277
|
+
);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const bindingMatch: AgentBindingConfig["match"] = {
|
|
282
|
+
channel: "discord",
|
|
283
|
+
guildId,
|
|
284
|
+
peer: { kind: "channel", id: channelId },
|
|
285
|
+
};
|
|
286
|
+
if (params.accountId) {
|
|
287
|
+
bindingMatch.accountId = params.accountId;
|
|
288
|
+
}
|
|
289
|
+
params.bindingsToAdd.push({
|
|
290
|
+
agentId,
|
|
291
|
+
match: bindingMatch,
|
|
292
|
+
});
|
|
293
|
+
params.changes.push(
|
|
294
|
+
`Moved ${path} → top-level bindings[] route for Discord channel ${channelId}.`,
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
if (!channelsChanged) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
nextGuilds[guildId] = { ...guild, channels: nextChannels };
|
|
301
|
+
changed = true;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return changed
|
|
305
|
+
? { entry: { ...params.entry, guilds: nextGuilds }, changed: true }
|
|
306
|
+
: { entry: params.entry, changed: false };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export const legacyConfigRules: ChannelDoctorLegacyConfigRule[] = [
|
|
310
|
+
{
|
|
311
|
+
path: ["channels", "discord", "voice", "tts"],
|
|
312
|
+
message:
|
|
313
|
+
'channels.discord.voice.tts.<provider> keys (openai/elevenlabs/microsoft/edge) are legacy; use channels.discord.voice.tts.providers.<provider>. Run "autobot doctor --fix".',
|
|
314
|
+
match: hasLegacyTtsProviderKeys,
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
path: ["channels", "discord", "accounts"],
|
|
318
|
+
message:
|
|
319
|
+
'channels.discord.accounts.<id>.voice.tts.<provider> keys (openai/elevenlabs/microsoft/edge) are legacy; use channels.discord.accounts.<id>.voice.tts.providers.<provider>. Run "autobot doctor --fix".',
|
|
320
|
+
match: hasLegacyDiscordAccountTtsProviderKeys,
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
path: ["channels", "discord"],
|
|
324
|
+
message:
|
|
325
|
+
'channels.discord.guilds.<id>.channels.<id>.allow is legacy; use channels.discord.guilds.<id>.channels.<id>.enabled instead. Run "autobot doctor --fix".',
|
|
326
|
+
match: hasLegacyDiscordGuildChannelAllowAlias,
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
path: ["channels", "discord", "accounts"],
|
|
330
|
+
message:
|
|
331
|
+
'channels.discord.accounts.<id>.guilds.<id>.channels.<id>.allow is legacy; use channels.discord.accounts.<id>.guilds.<id>.channels.<id>.enabled instead. Run "autobot doctor --fix".',
|
|
332
|
+
match: hasLegacyDiscordAccountGuildChannelAllowAlias,
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
path: ["channels", "discord"],
|
|
336
|
+
message:
|
|
337
|
+
'channels.discord.guilds.<id>.channels.<id>.agentId is legacy; use top-level bindings[] for per-channel Discord agent routing. Run "autobot doctor --fix".',
|
|
338
|
+
match: hasLegacyDiscordGuildChannelAgentId,
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
path: ["channels", "discord", "accounts"],
|
|
342
|
+
message:
|
|
343
|
+
'channels.discord.accounts.<id>.guilds.<id>.channels.<id>.agentId is legacy; use top-level bindings[] with match.accountId for per-channel Discord agent routing. Run "autobot doctor --fix".',
|
|
344
|
+
match: hasLegacyDiscordAccountGuildChannelAgentId,
|
|
345
|
+
},
|
|
346
|
+
];
|
|
347
|
+
|
|
348
|
+
export function normalizeCompatibilityConfig({
|
|
349
|
+
cfg,
|
|
350
|
+
}: {
|
|
351
|
+
cfg: AutoBotConfig;
|
|
352
|
+
}): ChannelDoctorConfigMutation {
|
|
353
|
+
const rawEntry = asObjectRecord((cfg.channels as Record<string, unknown> | undefined)?.discord);
|
|
354
|
+
if (!rawEntry) {
|
|
355
|
+
return { config: cfg, changes: [] };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const changes: string[] = [];
|
|
359
|
+
let updated = rawEntry;
|
|
360
|
+
let changed = false;
|
|
361
|
+
const bindingsToAdd: AgentBindingConfig[] = [];
|
|
362
|
+
|
|
363
|
+
const aliases = normalizeLegacyChannelAliases({
|
|
364
|
+
entry: rawEntry,
|
|
365
|
+
pathPrefix: "channels.discord",
|
|
366
|
+
changes,
|
|
367
|
+
normalizeDm: true,
|
|
368
|
+
normalizeAccountDm: true,
|
|
369
|
+
resolveStreamingOptions: (entry) => ({
|
|
370
|
+
resolvedMode: resolveDiscordPreviewStreamMode(entry),
|
|
371
|
+
includePreviewChunk: true,
|
|
372
|
+
}),
|
|
373
|
+
normalizeAccountExtra: ({ account, pathPrefix }) => {
|
|
374
|
+
const accountVoice = asObjectRecord(account.voice);
|
|
375
|
+
if (
|
|
376
|
+
!accountVoice ||
|
|
377
|
+
!migrateLegacyTtsConfig(
|
|
378
|
+
asObjectRecord(accountVoice.tts),
|
|
379
|
+
`${pathPrefix}.voice.tts`,
|
|
380
|
+
changes,
|
|
381
|
+
)
|
|
382
|
+
) {
|
|
383
|
+
return { entry: account, changed: false };
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
entry: {
|
|
387
|
+
...account,
|
|
388
|
+
voice: accountVoice,
|
|
389
|
+
},
|
|
390
|
+
changed: true,
|
|
391
|
+
};
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
updated = aliases.entry;
|
|
395
|
+
changed = aliases.changed;
|
|
396
|
+
|
|
397
|
+
const guildAliases = normalizeDiscordGuildChannelAllowAliases({
|
|
398
|
+
entry: updated,
|
|
399
|
+
pathPrefix: "channels.discord",
|
|
400
|
+
changes,
|
|
401
|
+
});
|
|
402
|
+
updated = guildAliases.entry;
|
|
403
|
+
changed = changed || guildAliases.changed;
|
|
404
|
+
|
|
405
|
+
const channelAgentIds = normalizeDiscordGuildChannelAgentIds({
|
|
406
|
+
cfg,
|
|
407
|
+
entry: updated,
|
|
408
|
+
pathPrefix: "channels.discord",
|
|
409
|
+
changes,
|
|
410
|
+
bindingsToAdd,
|
|
411
|
+
});
|
|
412
|
+
updated = channelAgentIds.entry;
|
|
413
|
+
changed = changed || channelAgentIds.changed;
|
|
414
|
+
|
|
415
|
+
const accounts = asObjectRecord(updated.accounts);
|
|
416
|
+
if (accounts) {
|
|
417
|
+
let accountsChanged = false;
|
|
418
|
+
const nextAccounts = { ...accounts };
|
|
419
|
+
for (const [accountId, accountValue] of Object.entries(accounts)) {
|
|
420
|
+
const account = asObjectRecord(accountValue);
|
|
421
|
+
if (!account) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const normalized = normalizeDiscordGuildChannelAllowAliases({
|
|
425
|
+
entry: account,
|
|
426
|
+
pathPrefix: `channels.discord.accounts.${accountId}`,
|
|
427
|
+
changes,
|
|
428
|
+
});
|
|
429
|
+
let nextAccount = normalized.entry;
|
|
430
|
+
let accountChanged = normalized.changed;
|
|
431
|
+
const normalizedAgentIds = normalizeDiscordGuildChannelAgentIds({
|
|
432
|
+
cfg,
|
|
433
|
+
entry: nextAccount,
|
|
434
|
+
pathPrefix: `channels.discord.accounts.${accountId}`,
|
|
435
|
+
accountId,
|
|
436
|
+
changes,
|
|
437
|
+
bindingsToAdd,
|
|
438
|
+
});
|
|
439
|
+
nextAccount = normalizedAgentIds.entry;
|
|
440
|
+
accountChanged = accountChanged || normalizedAgentIds.changed;
|
|
441
|
+
if (!accountChanged) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
nextAccounts[accountId] = nextAccount;
|
|
445
|
+
accountsChanged = true;
|
|
446
|
+
}
|
|
447
|
+
if (accountsChanged) {
|
|
448
|
+
updated = { ...updated, accounts: nextAccounts };
|
|
449
|
+
changed = true;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const voice = asObjectRecord(updated.voice);
|
|
454
|
+
if (
|
|
455
|
+
voice &&
|
|
456
|
+
migrateLegacyTtsConfig(asObjectRecord(voice.tts), "channels.discord.voice.tts", changes)
|
|
457
|
+
) {
|
|
458
|
+
updated = { ...updated, voice };
|
|
459
|
+
changed = true;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (!changed) {
|
|
463
|
+
return { config: cfg, changes: [] };
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
config: {
|
|
467
|
+
...cfg,
|
|
468
|
+
channels: {
|
|
469
|
+
...cfg.channels,
|
|
470
|
+
discord: updated,
|
|
471
|
+
} as AutoBotConfig["channels"],
|
|
472
|
+
bindings:
|
|
473
|
+
bindingsToAdd.length > 0 ? [...(cfg.bindings ?? []), ...bindingsToAdd] : cfg.bindings,
|
|
474
|
+
},
|
|
475
|
+
changes,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ChannelDoctorLegacyConfigRule } from "autobot/plugin-sdk/channel-contract";
|
|
2
|
+
|
|
3
|
+
// Runtime config loading already normalizes these aliases without rewriting the
|
|
4
|
+
// source file. Keep doctor non-destructive so downgrade paths remain recoverable.
|
|
5
|
+
export const DISCORD_LEGACY_CONFIG_RULES: ChannelDoctorLegacyConfigRule[] = [];
|