Files
openclaw/extensions/slack/src/accounts.ts
scoootscooob 8746362f5e refactor(slack): move Slack channel code to extensions/slack/src/ (#45621)
Move all Slack channel implementation files from src/slack/ to
extensions/slack/src/ and replace originals with shim re-exports.
This follows the extension migration pattern for channel plugins.

- Copy all .ts files to extensions/slack/src/ (preserving directory
  structure: monitor/, http/, monitor/events/, monitor/message-handler/)
- Transform import paths: external src/ imports use relative paths
  back to src/, internal slack imports stay relative within extension
- Replace all src/slack/ files with shim re-exports pointing to
  the extension copies
- Update tsconfig.plugin-sdk.dts.json rootDir from "src" to "." so
  the DTS build can follow shim chains into extensions/
- Update write-plugin-sdk-entry-dts.ts re-export path accordingly
- Preserve extensions/slack/index.ts, package.json, openclaw.plugin.json,
  src/channel.ts, src/runtime.ts, src/channel.test.ts (untouched)
2026-03-14 02:47:04 -07:00

123 lines
4.5 KiB
TypeScript

import { normalizeChatType } from "../../../src/channels/chat-type.js";
import { createAccountListHelpers } from "../../../src/channels/plugins/account-helpers.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { SlackAccountConfig } from "../../../src/config/types.js";
import { resolveAccountEntry } from "../../../src/routing/account-lookup.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
import type { SlackAccountSurfaceFields } from "./account-surface-fields.js";
import { resolveSlackAppToken, resolveSlackBotToken, resolveSlackUserToken } from "./token.js";
export type SlackTokenSource = "env" | "config" | "none";
export type ResolvedSlackAccount = {
accountId: string;
enabled: boolean;
name?: string;
botToken?: string;
appToken?: string;
userToken?: string;
botTokenSource: SlackTokenSource;
appTokenSource: SlackTokenSource;
userTokenSource: SlackTokenSource;
config: SlackAccountConfig;
} & SlackAccountSurfaceFields;
const { listAccountIds, resolveDefaultAccountId } = createAccountListHelpers("slack");
export const listSlackAccountIds = listAccountIds;
export const resolveDefaultSlackAccountId = resolveDefaultAccountId;
function resolveAccountConfig(
cfg: OpenClawConfig,
accountId: string,
): SlackAccountConfig | undefined {
return resolveAccountEntry(cfg.channels?.slack?.accounts, accountId);
}
export function mergeSlackAccountConfig(
cfg: OpenClawConfig,
accountId: string,
): SlackAccountConfig {
const { accounts: _ignored, ...base } = (cfg.channels?.slack ?? {}) as SlackAccountConfig & {
accounts?: unknown;
};
const account = resolveAccountConfig(cfg, accountId) ?? {};
return { ...base, ...account };
}
export function resolveSlackAccount(params: {
cfg: OpenClawConfig;
accountId?: string | null;
}): ResolvedSlackAccount {
const accountId = normalizeAccountId(params.accountId);
const baseEnabled = params.cfg.channels?.slack?.enabled !== false;
const merged = mergeSlackAccountConfig(params.cfg, accountId);
const accountEnabled = merged.enabled !== false;
const enabled = baseEnabled && accountEnabled;
const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
const envBot = allowEnv ? resolveSlackBotToken(process.env.SLACK_BOT_TOKEN) : undefined;
const envApp = allowEnv ? resolveSlackAppToken(process.env.SLACK_APP_TOKEN) : undefined;
const envUser = allowEnv ? resolveSlackUserToken(process.env.SLACK_USER_TOKEN) : undefined;
const configBot = resolveSlackBotToken(
merged.botToken,
`channels.slack.accounts.${accountId}.botToken`,
);
const configApp = resolveSlackAppToken(
merged.appToken,
`channels.slack.accounts.${accountId}.appToken`,
);
const configUser = resolveSlackUserToken(
merged.userToken,
`channels.slack.accounts.${accountId}.userToken`,
);
const botToken = configBot ?? envBot;
const appToken = configApp ?? envApp;
const userToken = configUser ?? envUser;
const botTokenSource: SlackTokenSource = configBot ? "config" : envBot ? "env" : "none";
const appTokenSource: SlackTokenSource = configApp ? "config" : envApp ? "env" : "none";
const userTokenSource: SlackTokenSource = configUser ? "config" : envUser ? "env" : "none";
return {
accountId,
enabled,
name: merged.name?.trim() || undefined,
botToken,
appToken,
userToken,
botTokenSource,
appTokenSource,
userTokenSource,
config: merged,
groupPolicy: merged.groupPolicy,
textChunkLimit: merged.textChunkLimit,
mediaMaxMb: merged.mediaMaxMb,
reactionNotifications: merged.reactionNotifications,
reactionAllowlist: merged.reactionAllowlist,
replyToMode: merged.replyToMode,
replyToModeByChatType: merged.replyToModeByChatType,
actions: merged.actions,
slashCommand: merged.slashCommand,
dm: merged.dm,
channels: merged.channels,
};
}
export function listEnabledSlackAccounts(cfg: OpenClawConfig): ResolvedSlackAccount[] {
return listSlackAccountIds(cfg)
.map((accountId) => resolveSlackAccount({ cfg, accountId }))
.filter((account) => account.enabled);
}
export function resolveSlackReplyToMode(
account: ResolvedSlackAccount,
chatType?: string | null,
): "off" | "first" | "all" {
const normalized = normalizeChatType(chatType ?? undefined);
if (normalized && account.replyToModeByChatType?.[normalized] !== undefined) {
return account.replyToModeByChatType[normalized] ?? "off";
}
if (normalized === "direct" && account.dm?.replyToMode !== undefined) {
return account.dm.replyToMode;
}
return account.replyToMode ?? "off";
}