198 lines
6.0 KiB
TypeScript
198 lines
6.0 KiB
TypeScript
import type { ClawdbotConfig } from "../../../src/config/config.js";
|
|
import type { DmPolicy } from "../../../src/config/types.js";
|
|
import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js";
|
|
import { formatDocsLink } from "../../../src/terminal/links.js";
|
|
import type { WizardPrompter } from "../../../src/wizard/prompts.js";
|
|
import type {
|
|
ChannelOnboardingAdapter,
|
|
ChannelOnboardingDmPolicy,
|
|
} from "../../../src/channels/plugins/onboarding-types.js";
|
|
import { addWildcardAllowFrom } from "../../../src/channels/plugins/onboarding/helpers.js";
|
|
|
|
import { resolveMSTeamsCredentials } from "./token.js";
|
|
|
|
const channel = "msteams" as const;
|
|
|
|
function setMSTeamsDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy) {
|
|
const allowFrom =
|
|
dmPolicy === "open"
|
|
? addWildcardAllowFrom(cfg.channels?.msteams?.allowFrom)?.map((entry) => String(entry))
|
|
: undefined;
|
|
return {
|
|
...cfg,
|
|
channels: {
|
|
...cfg.channels,
|
|
msteams: {
|
|
...cfg.channels?.msteams,
|
|
dmPolicy,
|
|
...(allowFrom ? { allowFrom } : {}),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
async function noteMSTeamsCredentialHelp(prompter: WizardPrompter): Promise<void> {
|
|
await prompter.note(
|
|
[
|
|
"1) Azure Bot registration → get App ID + Tenant ID",
|
|
"2) Add a client secret (App Password)",
|
|
"3) Set webhook URL + messaging endpoint",
|
|
"Tip: you can also set MSTEAMS_APP_ID / MSTEAMS_APP_PASSWORD / MSTEAMS_TENANT_ID.",
|
|
`Docs: ${formatDocsLink("/channels/msteams", "msteams")}`,
|
|
].join("\n"),
|
|
"MS Teams credentials",
|
|
);
|
|
}
|
|
|
|
const dmPolicy: ChannelOnboardingDmPolicy = {
|
|
label: "MS Teams",
|
|
channel,
|
|
policyKey: "channels.msteams.dmPolicy",
|
|
allowFromKey: "channels.msteams.allowFrom",
|
|
getCurrent: (cfg) => cfg.channels?.msteams?.dmPolicy ?? "pairing",
|
|
setPolicy: (cfg, policy) => setMSTeamsDmPolicy(cfg, policy),
|
|
};
|
|
|
|
export const msteamsOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
channel,
|
|
getStatus: async ({ cfg }) => {
|
|
const configured = Boolean(resolveMSTeamsCredentials(cfg.channels?.msteams));
|
|
return {
|
|
channel,
|
|
configured,
|
|
statusLines: [`MS Teams: ${configured ? "configured" : "needs app credentials"}`],
|
|
selectionHint: configured ? "configured" : "needs app creds",
|
|
quickstartScore: configured ? 2 : 0,
|
|
};
|
|
},
|
|
configure: async ({ cfg, prompter }) => {
|
|
const resolved = resolveMSTeamsCredentials(cfg.channels?.msteams);
|
|
const hasConfigCreds = Boolean(
|
|
cfg.channels?.msteams?.appId?.trim() &&
|
|
cfg.channels?.msteams?.appPassword?.trim() &&
|
|
cfg.channels?.msteams?.tenantId?.trim(),
|
|
);
|
|
const canUseEnv = Boolean(
|
|
!hasConfigCreds &&
|
|
process.env.MSTEAMS_APP_ID?.trim() &&
|
|
process.env.MSTEAMS_APP_PASSWORD?.trim() &&
|
|
process.env.MSTEAMS_TENANT_ID?.trim(),
|
|
);
|
|
|
|
let next = cfg;
|
|
let appId: string | null = null;
|
|
let appPassword: string | null = null;
|
|
let tenantId: string | null = null;
|
|
|
|
if (!resolved) {
|
|
await noteMSTeamsCredentialHelp(prompter);
|
|
}
|
|
|
|
if (canUseEnv) {
|
|
const keepEnv = await prompter.confirm({
|
|
message:
|
|
"MSTEAMS_APP_ID + MSTEAMS_APP_PASSWORD + MSTEAMS_TENANT_ID detected. Use env vars?",
|
|
initialValue: true,
|
|
});
|
|
if (keepEnv) {
|
|
next = {
|
|
...next,
|
|
channels: {
|
|
...next.channels,
|
|
msteams: { ...next.channels?.msteams, enabled: true },
|
|
},
|
|
};
|
|
} else {
|
|
appId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
appPassword = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App Password",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
tenantId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams Tenant ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
}
|
|
} else if (hasConfigCreds) {
|
|
const keep = await prompter.confirm({
|
|
message: "MS Teams credentials already configured. Keep them?",
|
|
initialValue: true,
|
|
});
|
|
if (!keep) {
|
|
appId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
appPassword = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App Password",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
tenantId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams Tenant ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
}
|
|
} else {
|
|
appId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
appPassword = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams App Password",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
tenantId = String(
|
|
await prompter.text({
|
|
message: "Enter MS Teams Tenant ID",
|
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
}),
|
|
).trim();
|
|
}
|
|
|
|
if (appId && appPassword && tenantId) {
|
|
next = {
|
|
...next,
|
|
channels: {
|
|
...next.channels,
|
|
msteams: {
|
|
...next.channels?.msteams,
|
|
enabled: true,
|
|
appId,
|
|
appPassword,
|
|
tenantId,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
return { cfg: next, accountId: DEFAULT_ACCOUNT_ID };
|
|
},
|
|
dmPolicy,
|
|
disable: (cfg) => ({
|
|
...cfg,
|
|
channels: {
|
|
...cfg.channels,
|
|
msteams: { ...cfg.channels?.msteams, enabled: false },
|
|
},
|
|
}),
|
|
};
|