Skip to content

Commit 5682ec3

Browse files
authored
refactor: move Discord channel implementation to extensions/ (openclaw#45660)
* refactor: move Discord channel implementation to extensions/discord/src/ Move all Discord source files from src/discord/ to extensions/discord/src/, following the extension migration pattern. Source files in src/discord/ are replaced with re-export shims. Channel-plugin files from src/channels/plugins/*/discord* are similarly moved and shimmed. - Copy all .ts source files preserving subdirectory structure (monitor/, voice/) - Move channel-plugin files (actions, normalize, onboarding, outbound, status-issues) - Fix all relative imports to use correct paths from new location - Create re-export shims at original locations for backward compatibility - Delete test files from shim locations (tests live in extension now) - Update tsconfig.plugin-sdk.dts.json rootDir from "src" to "." to accommodate extension files outside src/ - Update write-plugin-sdk-entry-dts.ts to match new declaration output paths * fix: add importOriginal to thread-bindings session-meta mock for extensions test * style: fix formatting in thread-bindings lifecycle test
1 parent e5bca08 commit 5682ec3

File tree

283 files changed

+26180
-26016
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

283 files changed

+26180
-26016
lines changed

src/discord/account-inspect.test.ts renamed to extensions/discord/src/account-inspect.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import type { OpenClawConfig } from "../config/config.js";
2+
import type { OpenClawConfig } from "../../../src/config/config.js";
33
import { inspectDiscordAccount } from "./account-inspect.js";
44

55
function asConfig(value: unknown): OpenClawConfig {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import type { OpenClawConfig } from "../../../src/config/config.js";
2+
import type { DiscordAccountConfig } from "../../../src/config/types.discord.js";
3+
import {
4+
hasConfiguredSecretInput,
5+
normalizeSecretInputString,
6+
} from "../../../src/config/types.secrets.js";
7+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
8+
import {
9+
mergeDiscordAccountConfig,
10+
resolveDefaultDiscordAccountId,
11+
resolveDiscordAccountConfig,
12+
} from "./accounts.js";
13+
14+
export type DiscordCredentialStatus = "available" | "configured_unavailable" | "missing";
15+
16+
export type InspectedDiscordAccount = {
17+
accountId: string;
18+
enabled: boolean;
19+
name?: string;
20+
token: string;
21+
tokenSource: "env" | "config" | "none";
22+
tokenStatus: DiscordCredentialStatus;
23+
configured: boolean;
24+
config: DiscordAccountConfig;
25+
};
26+
27+
function inspectDiscordTokenValue(value: unknown): {
28+
token: string;
29+
tokenSource: "config";
30+
tokenStatus: Exclude<DiscordCredentialStatus, "missing">;
31+
} | null {
32+
const normalized = normalizeSecretInputString(value);
33+
if (normalized) {
34+
return {
35+
token: normalized.replace(/^Bot\s+/i, ""),
36+
tokenSource: "config",
37+
tokenStatus: "available",
38+
};
39+
}
40+
if (hasConfiguredSecretInput(value)) {
41+
return {
42+
token: "",
43+
tokenSource: "config",
44+
tokenStatus: "configured_unavailable",
45+
};
46+
}
47+
return null;
48+
}
49+
50+
export function inspectDiscordAccount(params: {
51+
cfg: OpenClawConfig;
52+
accountId?: string | null;
53+
envToken?: string | null;
54+
}): InspectedDiscordAccount {
55+
const accountId = normalizeAccountId(
56+
params.accountId ?? resolveDefaultDiscordAccountId(params.cfg),
57+
);
58+
const merged = mergeDiscordAccountConfig(params.cfg, accountId);
59+
const enabled = params.cfg.channels?.discord?.enabled !== false && merged.enabled !== false;
60+
const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
61+
const hasAccountToken = Boolean(
62+
accountConfig &&
63+
Object.prototype.hasOwnProperty.call(accountConfig as Record<string, unknown>, "token"),
64+
);
65+
const accountToken = inspectDiscordTokenValue(accountConfig?.token);
66+
if (accountToken) {
67+
return {
68+
accountId,
69+
enabled,
70+
name: merged.name?.trim() || undefined,
71+
token: accountToken.token,
72+
tokenSource: accountToken.tokenSource,
73+
tokenStatus: accountToken.tokenStatus,
74+
configured: true,
75+
config: merged,
76+
};
77+
}
78+
if (hasAccountToken) {
79+
return {
80+
accountId,
81+
enabled,
82+
name: merged.name?.trim() || undefined,
83+
token: "",
84+
tokenSource: "none",
85+
tokenStatus: "missing",
86+
configured: false,
87+
config: merged,
88+
};
89+
}
90+
91+
const channelToken = inspectDiscordTokenValue(params.cfg.channels?.discord?.token);
92+
if (channelToken) {
93+
return {
94+
accountId,
95+
enabled,
96+
name: merged.name?.trim() || undefined,
97+
token: channelToken.token,
98+
tokenSource: channelToken.tokenSource,
99+
tokenStatus: channelToken.tokenStatus,
100+
configured: true,
101+
config: merged,
102+
};
103+
}
104+
105+
const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
106+
const envToken = allowEnv
107+
? normalizeSecretInputString(params.envToken ?? process.env.DISCORD_BOT_TOKEN)
108+
: undefined;
109+
if (envToken) {
110+
return {
111+
accountId,
112+
enabled,
113+
name: merged.name?.trim() || undefined,
114+
token: envToken.replace(/^Bot\s+/i, ""),
115+
tokenSource: "env",
116+
tokenStatus: "available",
117+
configured: true,
118+
config: merged,
119+
};
120+
}
121+
122+
return {
123+
accountId,
124+
enabled,
125+
name: merged.name?.trim() || undefined,
126+
token: "",
127+
tokenSource: "none",
128+
tokenStatus: "missing",
129+
configured: false,
130+
config: merged,
131+
};
132+
}

extensions/discord/src/accounts.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { createAccountActionGate } from "../../../src/channels/plugins/account-action-gate.js";
2+
import { createAccountListHelpers } from "../../../src/channels/plugins/account-helpers.js";
3+
import type { OpenClawConfig } from "../../../src/config/config.js";
4+
import type { DiscordAccountConfig, DiscordActionConfig } from "../../../src/config/types.js";
5+
import { resolveAccountEntry } from "../../../src/routing/account-lookup.js";
6+
import { normalizeAccountId } from "../../../src/routing/session-key.js";
7+
import { resolveDiscordToken } from "./token.js";
8+
9+
export type ResolvedDiscordAccount = {
10+
accountId: string;
11+
enabled: boolean;
12+
name?: string;
13+
token: string;
14+
tokenSource: "env" | "config" | "none";
15+
config: DiscordAccountConfig;
16+
};
17+
18+
const { listAccountIds, resolveDefaultAccountId } = createAccountListHelpers("discord");
19+
export const listDiscordAccountIds = listAccountIds;
20+
export const resolveDefaultDiscordAccountId = resolveDefaultAccountId;
21+
22+
export function resolveDiscordAccountConfig(
23+
cfg: OpenClawConfig,
24+
accountId: string,
25+
): DiscordAccountConfig | undefined {
26+
return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
27+
}
28+
29+
export function mergeDiscordAccountConfig(
30+
cfg: OpenClawConfig,
31+
accountId: string,
32+
): DiscordAccountConfig {
33+
const { accounts: _ignored, ...base } = (cfg.channels?.discord ?? {}) as DiscordAccountConfig & {
34+
accounts?: unknown;
35+
};
36+
const account = resolveDiscordAccountConfig(cfg, accountId) ?? {};
37+
return { ...base, ...account };
38+
}
39+
40+
export function createDiscordActionGate(params: {
41+
cfg: OpenClawConfig;
42+
accountId?: string | null;
43+
}): (key: keyof DiscordActionConfig, defaultValue?: boolean) => boolean {
44+
const accountId = normalizeAccountId(params.accountId);
45+
return createAccountActionGate({
46+
baseActions: params.cfg.channels?.discord?.actions,
47+
accountActions: resolveDiscordAccountConfig(params.cfg, accountId)?.actions,
48+
});
49+
}
50+
51+
export function resolveDiscordAccount(params: {
52+
cfg: OpenClawConfig;
53+
accountId?: string | null;
54+
}): ResolvedDiscordAccount {
55+
const accountId = normalizeAccountId(params.accountId);
56+
const baseEnabled = params.cfg.channels?.discord?.enabled !== false;
57+
const merged = mergeDiscordAccountConfig(params.cfg, accountId);
58+
const accountEnabled = merged.enabled !== false;
59+
const enabled = baseEnabled && accountEnabled;
60+
const tokenResolution = resolveDiscordToken(params.cfg, { accountId });
61+
return {
62+
accountId,
63+
enabled,
64+
name: merged.name?.trim() || undefined,
65+
token: tokenResolution.token,
66+
tokenSource: tokenResolution.source,
67+
config: merged,
68+
};
69+
}
70+
71+
export function resolveDiscordMaxLinesPerMessage(params: {
72+
cfg: OpenClawConfig;
73+
discordConfig?: DiscordAccountConfig | null;
74+
accountId?: string | null;
75+
}): number | undefined {
76+
if (typeof params.discordConfig?.maxLinesPerMessage === "number") {
77+
return params.discordConfig.maxLinesPerMessage;
78+
}
79+
return resolveDiscordAccount({
80+
cfg: params.cfg,
81+
accountId: params.accountId,
82+
}).config.maxLinesPerMessage;
83+
}
84+
85+
export function listEnabledDiscordAccounts(cfg: OpenClawConfig): ResolvedDiscordAccount[] {
86+
return listDiscordAccountIds(cfg)
87+
.map((accountId) => resolveDiscordAccount({ cfg, accountId }))
88+
.filter((account) => account.enabled);
89+
}

0 commit comments

Comments
 (0)