import { DEFAULT_ACCOUNT_ID } from
"openclaw/plugin-sdk/routing" ;
import { hasConfiguredSecretInput } from
"openclaw/plugin-sdk/secret-input" ;
import {
createStandardChannelSetupStatus,
formatDocsLink,
setSetupChannelEnabled,
type ChannelSetupWizard,
} from
"openclaw/plugin-sdk/setup" ;
import { normalizeOptionalString } from
"openclaw/plugin-sdk/text-runtime" ;
import { resolveNextcloudTalkAccount } from
"./accounts.js" ;
import {
clearNextcloudTalkAccountFields,
nextcloudTalkDmPolicy,
nextcloudTalkSetupAdapter,
normalizeNextcloudTalkBaseUrl,
setNextcloudTalkAccountConfig,
validateNextcloudTalkBaseUrl,
} from
"./setup-core.js" ;
import type { CoreConfig } from
"./types.js" ;
const channel =
"nextcloud-talk" as
const ;
const CONFIGURE_API_FLAG =
"__nextcloudTalkConfigureApiCredentials" ;
export
const nextcloudTalkSetupWizard: ChannelSetupWizard = {
channel,
stepOrder:
"text-first" ,
status: createStandardChannelSetupStatus({
channelLabel:
"Nextcloud Talk" ,
configuredLabel:
"configured" ,
unconfiguredLabel:
"needs setup" ,
configuredHint:
"configured" ,
unconfiguredHint:
"self-hosted chat" ,
configuredScore:
1 ,
unconfiguredScore:
5 ,
resolveConfigured: ({ cfg, accountId }) => {
const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
return Boolean (account.secret && account.baseUrl);
},
}),
introNote: {
title:
"Nextcloud Talk bot setup" ,
lines: [
"1) SSH into your Nextcloud server" ,
'2) Run: ./occ talk:bot:install "OpenClaw" "<shared-secret>" "<webhook-url>" --feature reaction' ,
"3) Copy the shared secret you used in the command" ,
"4) Enable the bot in your Nextcloud Talk room settings" ,
"Tip: you can also set NEXTCLOUD_TALK_BOT_SECRET in your env." ,
`Docs: ${formatDocsLink(
"/channels/nextcloud-talk" ,
"channels/nextcloud-talk" )}`,
],
shouldShow: ({ cfg, accountId }) => {
const account = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
return !account.secret || !account.baseUrl;
},
},
prepare: async ({ cfg, accountId, credentialValues, prompter }) => {
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }
);
const hasApiCredentials = Boolean (
resolvedAccount.config.apiUser?.trim() &&
(hasConfiguredSecretInput(resolvedAccount.config.apiPassword) ||
resolvedAccount.config.apiPasswordFile),
);
const configureApiCredentials = await prompter.confirm({
message: "Configure optional Nextcloud Talk API credentials for room lookups?" ,
initialValue: hasApiCredentials,
});
if (!configureApiCredentials) {
return undefined;
}
return {
credentialValues: {
...credentialValues,
[CONFIGURE_API_FLAG]: "1" ,
},
};
},
credentials: [
{
inputKey: "token" ,
providerHint: channel,
credentialLabel: "bot secret" ,
preferredEnvVar: "NEXTCLOUD_TALK_BOT_SECRET" ,
envPrompt: "NEXTCLOUD_TALK_BOT_SECRET detected. Use env var?" ,
keepPrompt: "Nextcloud Talk bot secret already configured. Keep it?" ,
inputPrompt: "Enter Nextcloud Talk bot secret" ,
allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID,
inspect: ({ cfg, accountId }) => {
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
return {
accountConfigured: Boolean (resolvedAccount.secret && resolvedAccount.baseUrl),
hasConfiguredValue: Boolean (
hasConfiguredSecretInput(resolvedAccount.config.botSecret) ||
resolvedAccount.config.botSecretFile,
),
resolvedValue: resolvedAccount.secret || undefined,
envValue:
accountId === DEFAULT_ACCOUNT_ID
? normalizeOptionalString(process.env.NEXTCLOUD_TALK_BOT_SECRET)
: undefined,
};
},
applyUseEnv: async (params) => {
const resolvedAccount = resolveNextcloudTalkAccount({
cfg: params.cfg as CoreConfig,
accountId: params.accountId,
});
const cleared = clearNextcloudTalkAccountFields(
params.cfg as CoreConfig,
params.accountId,
["botSecret" , "botSecretFile" ],
);
return setNextcloudTalkAccountConfig(cleared, params.accountId, {
baseUrl: resolvedAccount.baseUrl,
});
},
applySet: async (params) =>
setNextcloudTalkAccountConfig(
clearNextcloudTalkAccountFields(params.cfg as CoreConfig, params.accountId, [
"botSecret" ,
"botSecretFile" ,
]),
params.accountId,
{
botSecret: params.value,
},
),
},
{
inputKey: "password" ,
providerHint: "nextcloud-talk-api" ,
credentialLabel: "API password" ,
preferredEnvVar: "NEXTCLOUD_TALK_API_PASSWORD" ,
envPrompt: "" ,
keepPrompt: "Nextcloud Talk API password already configured. Keep it?" ,
inputPrompt: "Enter Nextcloud Talk API password" ,
inspect: ({ cfg, accountId }) => {
const resolvedAccount = resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId });
const apiUser = resolvedAccount.config.apiUser?.trim();
const apiPasswordConfigured = Boolean (
hasConfiguredSecretInput(resolvedAccount.config.apiPassword) ||
resolvedAccount.config.apiPasswordFile,
);
return {
accountConfigured: Boolean (apiUser && apiPasswordConfigured),
hasConfiguredValue: apiPasswordConfigured,
};
},
shouldPrompt: ({ credentialValues }) => credentialValues[CONFIGURE_API_FLAG] === "1" ,
applySet: async (params) =>
setNextcloudTalkAccountConfig(
clearNextcloudTalkAccountFields(params.cfg as CoreConfig, params.accountId, [
"apiPassword" ,
"apiPasswordFile" ,
]),
params.accountId,
{
apiPassword: params.value,
},
),
},
],
textInputs: [
{
inputKey: "httpUrl" ,
message: "Enter Nextcloud instance URL (e.g., https://cloud.example.com) ",
currentValue: ({ cfg, accountId }) =>
resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }).baseUrl || undefined,
shouldPrompt: ({ currentValue }) => !currentValue,
validate: ({ value }) => validateNextcloudTalkBaseUrl(value),
normalizeValue: ({ value }) => normalizeNextcloudTalkBaseUrl(value),
applySet: async (params) =>
setNextcloudTalkAccountConfig(params.cfg as CoreConfig, params.accountId, {
baseUrl: params.value,
}),
},
{
inputKey: "userId" ,
message: "Nextcloud Talk API user" ,
currentValue: ({ cfg, accountId }) =>
resolveNextcloudTalkAccount({ cfg: cfg as CoreConfig, accountId }).config.apiUser?.trim() ||
undefined,
shouldPrompt: ({ credentialValues }) => credentialValues[CONFIGURE_API_FLAG] === "1" ,
validate: ({ value }) => (value ? undefined : "Required" ),
applySet: async (params) =>
setNextcloudTalkAccountConfig(params.cfg as CoreConfig, params.accountId, {
apiUser: params.value,
}),
},
],
dmPolicy: nextcloudTalkDmPolicy,
disable: (cfg) => setSetupChannelEnabled(cfg, channel, false ),
};
export { nextcloudTalkSetupAdapter };
Messung V0.5 in Prozent C=98 H=99 G=98
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland