import type { OpenClawConfig } from "openclaw/plugin-sdk";
import type { ChannelOnboardingAdapter } from "openclaw/plugin-sdk";
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
import type { DingTalkConfig } from "./types.js";
import {
listDingTalkAccountIds,
resolveDingTalkAccount,
} from "./accounts.js";
import { PLUGIN_ID } from "./constants.js";
const channel = PLUGIN_ID;
/**
* Display DingTalk credentials configuration help
*/
async function noteDingTalkCredentialsHelp(prompter: {
note: (message: string, title?: string) => Promise<void>;
}): Promise<void> {
await prompter.note(
[
"1) Log in to DingTalk Open Platform: https://open.dingtalk.com",
"2) Create an internal enterprise app -> Robot",
"3) Get AppKey (Client ID) and AppSecret (Client Secret)",
"4) Enable Stream mode in app configuration",
"Docs: https://open.dingtalk.com/document/",
].join("\n"),
"DingTalk bot setup"
);
}
/**
* DingTalk Onboarding Adapter(单账户模式)
*/
export const dingtalkOnboardingAdapter: ChannelOnboardingAdapter = {
channel,
getStatus: async ({ cfg }) => {
const configured = listDingTalkAccountIds(cfg).some((accountId) => {
const account = resolveDingTalkAccount({ cfg, accountId });
return Boolean(account.clientId?.trim() && account.clientSecret?.trim());
});
return {
channel,
configured,
statusLines: [`DingTalk: ${configured ? "configured" : "needs credentials"}`],
selectionHint: configured ? "configured" : "needs AppKey/AppSecret",
quickstartScore: configured ? 1 : 5,
};
},
configure: async ({
cfg,
prompter,
}) => {
let next = cfg;
const resolvedAccount = resolveDingTalkAccount({ cfg: next });
const accountConfigured = Boolean(
resolvedAccount.clientId?.trim() && resolvedAccount.clientSecret?.trim()
);
const dingtalkConfig = (next.channels?.[PLUGIN_ID] ?? {}) as DingTalkConfig;
const hasConfigCredentials = Boolean(dingtalkConfig.clientId);
let clientId: string | null = null;
let clientSecret: string | null = null;
if (!accountConfigured) {
await noteDingTalkCredentialsHelp(prompter);
}
if (hasConfigCredentials) {
const keep = await prompter.confirm({
message: "DingTalk credentials already configured. Keep them?",
initialValue: true,
});
if (!keep) {
clientId = String(
await prompter.text({
message: "Enter DingTalk AppKey (Client ID)",
validate: (value) => (value?.trim() ? undefined : "Required"),
})
).trim();
clientSecret = String(
await prompter.text({
message: "Enter DingTalk AppSecret (Client Secret)",
validate: (value) => (value?.trim() ? undefined : "Required"),
})
).trim();
}
} else {
clientId = String(
await prompter.text({
message: "Enter DingTalk AppKey (Client ID)",
validate: (value) => (value?.trim() ? undefined : "Required"),
})
).trim();
clientSecret = String(
await prompter.text({
message: "Enter DingTalk AppSecret (Client Secret)",
validate: (value) => (value?.trim() ? undefined : "Required"),
})
).trim();
}
if (clientId && clientSecret) {
const updatedDingtalkConfig = (next.channels?.[PLUGIN_ID] ?? {}) as DingTalkConfig;
next = {
...next,
channels: {
...next.channels,
[PLUGIN_ID]: {
...updatedDingtalkConfig,
enabled: true,
clientId,
clientSecret,
},
},
};
}
return { cfg: next, accountId: DEFAULT_ACCOUNT_ID };
},
disable: (cfg) => {
const dingtalkConfig = (cfg.channels?.[PLUGIN_ID] ?? {}) as DingTalkConfig;
return {
...cfg,
channels: {
...cfg.channels,
[PLUGIN_ID]: { ...dingtalkConfig, enabled: false },
},
};
},
};