mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 15:45:01 +00:00
refactor!: rename chat providers to channels
This commit is contained in:
219
src/channels/plugins/onboarding/signal.ts
Normal file
219
src/channels/plugins/onboarding/signal.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import { detectBinary } from "../../../commands/onboard-helpers.js";
|
||||
import { installSignalCli } from "../../../commands/signal-install.js";
|
||||
import type { ClawdbotConfig } from "../../../config/config.js";
|
||||
import type { DmPolicy } from "../../../config/types.js";
|
||||
import {
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
normalizeAccountId,
|
||||
} from "../../../routing/session-key.js";
|
||||
import {
|
||||
listSignalAccountIds,
|
||||
resolveDefaultSignalAccountId,
|
||||
resolveSignalAccount,
|
||||
} from "../../../signal/accounts.js";
|
||||
import { formatDocsLink } from "../../../terminal/links.js";
|
||||
import type {
|
||||
ChannelOnboardingAdapter,
|
||||
ChannelOnboardingDmPolicy,
|
||||
} from "../onboarding-types.js";
|
||||
import { addWildcardAllowFrom, promptAccountId } from "./helpers.js";
|
||||
|
||||
const channel = "signal" as const;
|
||||
|
||||
function setSignalDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy) {
|
||||
const allowFrom =
|
||||
dmPolicy === "open"
|
||||
? addWildcardAllowFrom(cfg.channels?.signal?.allowFrom)
|
||||
: undefined;
|
||||
return {
|
||||
...cfg,
|
||||
channels: {
|
||||
...cfg.channels,
|
||||
signal: {
|
||||
...cfg.channels?.signal,
|
||||
dmPolicy,
|
||||
...(allowFrom ? { allowFrom } : {}),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const dmPolicy: ChannelOnboardingDmPolicy = {
|
||||
label: "Signal",
|
||||
channel,
|
||||
policyKey: "channels.signal.dmPolicy",
|
||||
allowFromKey: "channels.signal.allowFrom",
|
||||
getCurrent: (cfg) => cfg.channels?.signal?.dmPolicy ?? "pairing",
|
||||
setPolicy: (cfg, policy) => setSignalDmPolicy(cfg, policy),
|
||||
};
|
||||
|
||||
export const signalOnboardingAdapter: ChannelOnboardingAdapter = {
|
||||
channel,
|
||||
getStatus: async ({ cfg }) => {
|
||||
const configured = listSignalAccountIds(cfg).some(
|
||||
(accountId) => resolveSignalAccount({ cfg, accountId }).configured,
|
||||
);
|
||||
const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli";
|
||||
const signalCliDetected = await detectBinary(signalCliPath);
|
||||
return {
|
||||
channel,
|
||||
configured,
|
||||
statusLines: [
|
||||
`Signal: ${configured ? "configured" : "needs setup"}`,
|
||||
`signal-cli: ${signalCliDetected ? "found" : "missing"} (${signalCliPath})`,
|
||||
],
|
||||
selectionHint: signalCliDetected
|
||||
? "signal-cli found"
|
||||
: "signal-cli missing",
|
||||
quickstartScore: signalCliDetected ? 1 : 0,
|
||||
};
|
||||
},
|
||||
configure: async ({
|
||||
cfg,
|
||||
runtime,
|
||||
prompter,
|
||||
accountOverrides,
|
||||
shouldPromptAccountIds,
|
||||
options,
|
||||
}) => {
|
||||
const signalOverride = accountOverrides.signal?.trim();
|
||||
const defaultSignalAccountId = resolveDefaultSignalAccountId(cfg);
|
||||
let signalAccountId = signalOverride
|
||||
? normalizeAccountId(signalOverride)
|
||||
: defaultSignalAccountId;
|
||||
if (shouldPromptAccountIds && !signalOverride) {
|
||||
signalAccountId = await promptAccountId({
|
||||
cfg,
|
||||
prompter,
|
||||
label: "Signal",
|
||||
currentId: signalAccountId,
|
||||
listAccountIds: listSignalAccountIds,
|
||||
defaultAccountId: defaultSignalAccountId,
|
||||
});
|
||||
}
|
||||
|
||||
let next = cfg;
|
||||
const resolvedAccount = resolveSignalAccount({
|
||||
cfg: next,
|
||||
accountId: signalAccountId,
|
||||
});
|
||||
const accountConfig = resolvedAccount.config;
|
||||
let resolvedCliPath = accountConfig.cliPath ?? "signal-cli";
|
||||
let cliDetected = await detectBinary(resolvedCliPath);
|
||||
if (options?.allowSignalInstall) {
|
||||
const wantsInstall = await prompter.confirm({
|
||||
message: cliDetected
|
||||
? "signal-cli detected. Reinstall/update now?"
|
||||
: "signal-cli not found. Install now?",
|
||||
initialValue: !cliDetected,
|
||||
});
|
||||
if (wantsInstall) {
|
||||
try {
|
||||
const result = await installSignalCli(runtime);
|
||||
if (result.ok && result.cliPath) {
|
||||
cliDetected = true;
|
||||
resolvedCliPath = result.cliPath;
|
||||
await prompter.note(
|
||||
`Installed signal-cli at ${result.cliPath}`,
|
||||
"Signal",
|
||||
);
|
||||
} else if (!result.ok) {
|
||||
await prompter.note(
|
||||
result.error ?? "signal-cli install failed.",
|
||||
"Signal",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
await prompter.note(
|
||||
`signal-cli install failed: ${String(err)}`,
|
||||
"Signal",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cliDetected) {
|
||||
await prompter.note(
|
||||
"signal-cli not found. Install it, then rerun this step or set channels.signal.cliPath.",
|
||||
"Signal",
|
||||
);
|
||||
}
|
||||
|
||||
let account = accountConfig.account ?? "";
|
||||
if (account) {
|
||||
const keep = await prompter.confirm({
|
||||
message: `Signal account set (${account}). Keep it?`,
|
||||
initialValue: true,
|
||||
});
|
||||
if (!keep) account = "";
|
||||
}
|
||||
|
||||
if (!account) {
|
||||
account = String(
|
||||
await prompter.text({
|
||||
message: "Signal bot number (E.164)",
|
||||
validate: (value) => (value?.trim() ? undefined : "Required"),
|
||||
}),
|
||||
).trim();
|
||||
}
|
||||
|
||||
if (account) {
|
||||
if (signalAccountId === DEFAULT_ACCOUNT_ID) {
|
||||
next = {
|
||||
...next,
|
||||
channels: {
|
||||
...next.channels,
|
||||
signal: {
|
||||
...next.channels?.signal,
|
||||
enabled: true,
|
||||
account,
|
||||
cliPath: resolvedCliPath ?? "signal-cli",
|
||||
},
|
||||
},
|
||||
};
|
||||
} else {
|
||||
next = {
|
||||
...next,
|
||||
channels: {
|
||||
...next.channels,
|
||||
signal: {
|
||||
...next.channels?.signal,
|
||||
enabled: true,
|
||||
accounts: {
|
||||
...next.channels?.signal?.accounts,
|
||||
[signalAccountId]: {
|
||||
...next.channels?.signal?.accounts?.[signalAccountId],
|
||||
enabled:
|
||||
next.channels?.signal?.accounts?.[signalAccountId]
|
||||
?.enabled ?? true,
|
||||
account,
|
||||
cliPath: resolvedCliPath ?? "signal-cli",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
await prompter.note(
|
||||
[
|
||||
'Link device with: signal-cli link -n "Clawdbot"',
|
||||
"Scan QR in Signal → Linked Devices",
|
||||
"Then run: clawdbot gateway call channels.status --params '{\"probe\":true}'",
|
||||
`Docs: ${formatDocsLink("/signal", "signal")}`,
|
||||
].join("\n"),
|
||||
"Signal next steps",
|
||||
);
|
||||
|
||||
return { cfg: next, accountId: signalAccountId };
|
||||
},
|
||||
dmPolicy,
|
||||
disable: (cfg) => ({
|
||||
...cfg,
|
||||
channels: {
|
||||
...cfg.channels,
|
||||
signal: { ...cfg.channels?.signal, enabled: false },
|
||||
},
|
||||
}),
|
||||
};
|
||||
Reference in New Issue
Block a user