import type { RemoteClawConfig } from "../../../src/config/config.js"; import { hasConfiguredSecretInput, normalizeSecretInputString, } from "../../../src/config/types.secrets.js"; import type { SlackAccountConfig } from "../../../src/config/types.slack.js"; import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js"; import type { SlackAccountSurfaceFields } from "./account-surface-fields.js"; import { mergeSlackAccountConfig, resolveDefaultSlackAccountId, type SlackTokenSource, } from "./accounts.js"; export type SlackCredentialStatus = "available" | "configured_unavailable" | "missing"; export type InspectedSlackAccount = { accountId: string; enabled: boolean; name?: string; mode?: SlackAccountConfig["mode"]; botToken?: string; appToken?: string; signingSecret?: string; userToken?: string; botTokenSource: SlackTokenSource; appTokenSource: SlackTokenSource; signingSecretSource?: SlackTokenSource; userTokenSource: SlackTokenSource; botTokenStatus: SlackCredentialStatus; appTokenStatus: SlackCredentialStatus; signingSecretStatus?: SlackCredentialStatus; userTokenStatus: SlackCredentialStatus; configured: boolean; config: SlackAccountConfig; } & SlackAccountSurfaceFields; function inspectSlackToken(value: unknown): { token?: string; source: Exclude; status: SlackCredentialStatus; } { const token = normalizeSecretInputString(value); if (token) { return { token, source: "config", status: "available", }; } if (hasConfiguredSecretInput(value)) { return { source: "config", status: "configured_unavailable", }; } return { source: "none", status: "missing", }; } export function inspectSlackAccount(params: { cfg: RemoteClawConfig; accountId?: string | null; envBotToken?: string | null; envAppToken?: string | null; envUserToken?: string | null; }): InspectedSlackAccount { const accountId = normalizeAccountId( params.accountId ?? resolveDefaultSlackAccountId(params.cfg), ); const merged = mergeSlackAccountConfig(params.cfg, accountId); const enabled = params.cfg.channels?.slack?.enabled !== false && merged.enabled !== false; const allowEnv = accountId === DEFAULT_ACCOUNT_ID; const mode = merged.mode ?? "socket"; const isHttpMode = mode === "http"; const configBot = inspectSlackToken(merged.botToken); const configApp = inspectSlackToken(merged.appToken); const configSigningSecret = inspectSlackToken(merged.signingSecret); const configUser = inspectSlackToken(merged.userToken); const envBot = allowEnv ? normalizeSecretInputString(params.envBotToken ?? process.env.SLACK_BOT_TOKEN) : undefined; const envApp = allowEnv ? normalizeSecretInputString(params.envAppToken ?? process.env.SLACK_APP_TOKEN) : undefined; const envUser = allowEnv ? normalizeSecretInputString(params.envUserToken ?? process.env.SLACK_USER_TOKEN) : undefined; const botToken = configBot.token ?? envBot; const appToken = configApp.token ?? envApp; const signingSecret = configSigningSecret.token; const userToken = configUser.token ?? envUser; const botTokenSource: SlackTokenSource = configBot.token ? "config" : configBot.status === "configured_unavailable" ? "config" : envBot ? "env" : "none"; const appTokenSource: SlackTokenSource = configApp.token ? "config" : configApp.status === "configured_unavailable" ? "config" : envApp ? "env" : "none"; const signingSecretSource: SlackTokenSource = configSigningSecret.token ? "config" : configSigningSecret.status === "configured_unavailable" ? "config" : "none"; const userTokenSource: SlackTokenSource = configUser.token ? "config" : configUser.status === "configured_unavailable" ? "config" : envUser ? "env" : "none"; return { accountId, enabled, name: merged.name?.trim() || undefined, mode, botToken, appToken, ...(isHttpMode ? { signingSecret } : {}), userToken, botTokenSource, appTokenSource, ...(isHttpMode ? { signingSecretSource } : {}), userTokenSource, botTokenStatus: configBot.token ? "available" : configBot.status === "configured_unavailable" ? "configured_unavailable" : envBot ? "available" : "missing", appTokenStatus: configApp.token ? "available" : configApp.status === "configured_unavailable" ? "configured_unavailable" : envApp ? "available" : "missing", ...(isHttpMode ? { signingSecretStatus: configSigningSecret.token ? "available" : configSigningSecret.status === "configured_unavailable" ? "configured_unavailable" : "missing", } : {}), userTokenStatus: configUser.token ? "available" : configUser.status === "configured_unavailable" ? "configured_unavailable" : envUser ? "available" : "missing", configured: isHttpMode ? (configBot.status !== "missing" || Boolean(envBot)) && configSigningSecret.status !== "missing" : (configBot.status !== "missing" || Boolean(envBot)) && (configApp.status !== "missing" || Boolean(envApp)), 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, }; }