refactor!: rename chat providers to channels

This commit is contained in:
Peter Steinberger
2026-01-13 06:16:43 +00:00
parent 0cd632ba84
commit 90342a4f3a
393 changed files with 8004 additions and 6737 deletions

View 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 },
},
}),
};