|
|
|
@@ -1,3 +1,4 @@
|
|
|
|
|
|
|
|
import crypto from "node:crypto";
|
|
|
|
import fs from "node:fs";
|
|
|
|
import fs from "node:fs";
|
|
|
|
import type { ClawdbotConfig } from "../../config/config.js";
|
|
|
|
import type { ClawdbotConfig } from "../../config/config.js";
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
@@ -66,7 +67,28 @@ function existsSyncMaybe(p: string | undefined): boolean | null {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
function sha256HexPrefix(value: string, len = 8): string {
|
|
|
|
|
|
|
|
return crypto.createHash("sha256").update(value).digest("hex").slice(0, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function formatTokenHint(
|
|
|
|
|
|
|
|
token: string,
|
|
|
|
|
|
|
|
opts: { showSecrets: boolean },
|
|
|
|
|
|
|
|
): string {
|
|
|
|
|
|
|
|
const t = token.trim();
|
|
|
|
|
|
|
|
if (!t) return "empty";
|
|
|
|
|
|
|
|
if (!opts.showSecrets)
|
|
|
|
|
|
|
|
return `sha256:${sha256HexPrefix(t)} · len ${t.length}`;
|
|
|
|
|
|
|
|
const head = t.slice(0, 4);
|
|
|
|
|
|
|
|
const tail = t.slice(-4);
|
|
|
|
|
|
|
|
if (t.length <= 10) return `${t} · len ${t.length}`;
|
|
|
|
|
|
|
|
return `${head}…${tail} · len ${t.length}`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function buildProvidersTable(
|
|
|
|
|
|
|
|
cfg: ClawdbotConfig,
|
|
|
|
|
|
|
|
opts?: { showSecrets?: boolean },
|
|
|
|
|
|
|
|
): Promise<{
|
|
|
|
rows: ProviderRow[];
|
|
|
|
rows: ProviderRow[];
|
|
|
|
details: Array<{
|
|
|
|
details: Array<{
|
|
|
|
title: string;
|
|
|
|
title: string;
|
|
|
|
@@ -74,6 +96,7 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
rows: Array<Record<string, string>>;
|
|
|
|
rows: Array<Record<string, string>>;
|
|
|
|
}>;
|
|
|
|
}>;
|
|
|
|
}> {
|
|
|
|
}> {
|
|
|
|
|
|
|
|
const showSecrets = opts?.showSecrets === true;
|
|
|
|
const rows: ProviderRow[] = [];
|
|
|
|
const rows: ProviderRow[] = [];
|
|
|
|
const details: Array<{
|
|
|
|
const details: Array<{
|
|
|
|
title: string;
|
|
|
|
title: string;
|
|
|
|
@@ -138,6 +161,10 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
const tgEnabledAccounts = tgAccounts.filter((a) => a.enabled);
|
|
|
|
const tgEnabledAccounts = tgAccounts.filter((a) => a.enabled);
|
|
|
|
const tgTokenAccounts = tgEnabledAccounts.filter((a) => a.token?.trim());
|
|
|
|
const tgTokenAccounts = tgEnabledAccounts.filter((a) => a.token?.trim());
|
|
|
|
const tgSources = summarizeSources(tgTokenAccounts.map((a) => a.tokenSource));
|
|
|
|
const tgSources = summarizeSources(tgTokenAccounts.map((a) => a.tokenSource));
|
|
|
|
|
|
|
|
const tgSampleToken = tgTokenAccounts[0]?.token?.trim() || "";
|
|
|
|
|
|
|
|
const tgTokenHint = tgSampleToken
|
|
|
|
|
|
|
|
? formatTokenHint(tgSampleToken, { showSecrets })
|
|
|
|
|
|
|
|
: "";
|
|
|
|
const tgMissingFiles: string[] = [];
|
|
|
|
const tgMissingFiles: string[] = [];
|
|
|
|
const tgGlobalTokenFileExists = existsSyncMaybe(cfg.telegram?.tokenFile);
|
|
|
|
const tgGlobalTokenFileExists = existsSyncMaybe(cfg.telegram?.tokenFile);
|
|
|
|
if (
|
|
|
|
if (
|
|
|
|
@@ -170,7 +197,7 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
? tgMisconfigured
|
|
|
|
? tgMisconfigured
|
|
|
|
? `token file missing (${tgMissingFiles[0]})`
|
|
|
|
? `token file missing (${tgMissingFiles[0]})`
|
|
|
|
: tgTokenAccounts.length > 0
|
|
|
|
: tgTokenAccounts.length > 0
|
|
|
|
? `bot token ${tgSources.label} · accounts ${tgTokenAccounts.length}/${tgEnabledAccounts.length || 1}`
|
|
|
|
? `bot token ${tgSources.label}${tgTokenHint ? ` (${tgTokenHint})` : ""} · accounts ${tgTokenAccounts.length}/${tgEnabledAccounts.length || 1}`
|
|
|
|
: "no bot token (TELEGRAM_BOT_TOKEN / telegram.botToken)"
|
|
|
|
: "no bot token (TELEGRAM_BOT_TOKEN / telegram.botToken)"
|
|
|
|
: "disabled",
|
|
|
|
: "disabled",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@@ -183,13 +210,17 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
const dcEnabledAccounts = dcAccounts.filter((a) => a.enabled);
|
|
|
|
const dcEnabledAccounts = dcAccounts.filter((a) => a.enabled);
|
|
|
|
const dcTokenAccounts = dcEnabledAccounts.filter((a) => a.token?.trim());
|
|
|
|
const dcTokenAccounts = dcEnabledAccounts.filter((a) => a.token?.trim());
|
|
|
|
const dcSources = summarizeSources(dcTokenAccounts.map((a) => a.tokenSource));
|
|
|
|
const dcSources = summarizeSources(dcTokenAccounts.map((a) => a.tokenSource));
|
|
|
|
|
|
|
|
const dcSampleToken = dcTokenAccounts[0]?.token?.trim() || "";
|
|
|
|
|
|
|
|
const dcTokenHint = dcSampleToken
|
|
|
|
|
|
|
|
? formatTokenHint(dcSampleToken, { showSecrets })
|
|
|
|
|
|
|
|
: "";
|
|
|
|
rows.push({
|
|
|
|
rows.push({
|
|
|
|
provider: "Discord",
|
|
|
|
provider: "Discord",
|
|
|
|
enabled: dcEnabled,
|
|
|
|
enabled: dcEnabled,
|
|
|
|
state: !dcEnabled ? "off" : dcTokenAccounts.length > 0 ? "ok" : "setup",
|
|
|
|
state: !dcEnabled ? "off" : dcTokenAccounts.length > 0 ? "ok" : "setup",
|
|
|
|
detail: dcEnabled
|
|
|
|
detail: dcEnabled
|
|
|
|
? dcTokenAccounts.length > 0
|
|
|
|
? dcTokenAccounts.length > 0
|
|
|
|
? `bot token ${dcSources.label} · accounts ${dcTokenAccounts.length}/${dcEnabledAccounts.length || 1}`
|
|
|
|
? `bot token ${dcSources.label}${dcTokenHint ? ` (${dcTokenHint})` : ""} · accounts ${dcTokenAccounts.length}/${dcEnabledAccounts.length || 1}`
|
|
|
|
: "no bot token (DISCORD_BOT_TOKEN / discord.token)"
|
|
|
|
: "no bot token (DISCORD_BOT_TOKEN / discord.token)"
|
|
|
|
: "disabled",
|
|
|
|
: "disabled",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
@@ -217,6 +248,15 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
const slAppSources = summarizeSources(
|
|
|
|
const slAppSources = summarizeSources(
|
|
|
|
slReady.map((a) => a.appTokenSource ?? "none"),
|
|
|
|
slReady.map((a) => a.appTokenSource ?? "none"),
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
const slSample = slReady[0] ?? null;
|
|
|
|
|
|
|
|
const slBotHint =
|
|
|
|
|
|
|
|
slSample?.botToken?.trim() && slSample.botTokenSource !== "none"
|
|
|
|
|
|
|
|
? formatTokenHint(slSample.botToken, { showSecrets })
|
|
|
|
|
|
|
|
: "";
|
|
|
|
|
|
|
|
const slAppHint =
|
|
|
|
|
|
|
|
slSample?.appToken?.trim() && slSample.appTokenSource !== "none"
|
|
|
|
|
|
|
|
? formatTokenHint(slSample.appToken, { showSecrets })
|
|
|
|
|
|
|
|
: "";
|
|
|
|
rows.push({
|
|
|
|
rows.push({
|
|
|
|
provider: "Slack",
|
|
|
|
provider: "Slack",
|
|
|
|
enabled: slEnabled,
|
|
|
|
enabled: slEnabled,
|
|
|
|
@@ -231,7 +271,7 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
? slPartial.length > 0
|
|
|
|
? slPartial.length > 0
|
|
|
|
? `partial tokens (need bot+app) · accounts ${slPartial.length}`
|
|
|
|
? `partial tokens (need bot+app) · accounts ${slPartial.length}`
|
|
|
|
: slReady.length > 0
|
|
|
|
: slReady.length > 0
|
|
|
|
? `tokens ok (bot ${slBotSources.label}, app ${slAppSources.label}) · accounts ${slReady.length}/${slEnabledAccounts.length || 1}`
|
|
|
|
? `tokens ok (bot ${slBotSources.label}${slBotHint ? ` ${slBotHint}` : ""}, app ${slAppSources.label}${slAppHint ? ` ${slAppHint}` : ""}) · accounts ${slReady.length}/${slEnabledAccounts.length || 1}`
|
|
|
|
: slHasAnyToken
|
|
|
|
: slHasAnyToken
|
|
|
|
? "tokens incomplete (need bot+app)"
|
|
|
|
? "tokens incomplete (need bot+app)"
|
|
|
|
: "no tokens (SLACK_BOT_TOKEN + SLACK_APP_TOKEN)"
|
|
|
|
: "no tokens (SLACK_BOT_TOKEN + SLACK_APP_TOKEN)"
|
|
|
|
@@ -298,6 +338,9 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
!msTenantId ? "tenantId" : null,
|
|
|
|
!msTenantId ? "tenantId" : null,
|
|
|
|
].filter(Boolean) as string[];
|
|
|
|
].filter(Boolean) as string[];
|
|
|
|
const msAnyPresent = Boolean(msAppId || msAppPassword || msTenantId);
|
|
|
|
const msAnyPresent = Boolean(msAppId || msAppPassword || msTenantId);
|
|
|
|
|
|
|
|
const msPasswordHint = msAppPassword
|
|
|
|
|
|
|
|
? formatTokenHint(msAppPassword, { showSecrets })
|
|
|
|
|
|
|
|
: "";
|
|
|
|
rows.push({
|
|
|
|
rows.push({
|
|
|
|
provider: "MS Teams",
|
|
|
|
provider: "MS Teams",
|
|
|
|
enabled: msEnabled,
|
|
|
|
enabled: msEnabled,
|
|
|
|
@@ -310,7 +353,7 @@ export async function buildProvidersTable(cfg: ClawdbotConfig): Promise<{
|
|
|
|
: "setup",
|
|
|
|
: "setup",
|
|
|
|
detail: msEnabled
|
|
|
|
detail: msEnabled
|
|
|
|
? msCreds
|
|
|
|
? msCreds
|
|
|
|
? "credentials set"
|
|
|
|
? `credentials set${msPasswordHint ? ` (password ${msPasswordHint})` : ""}`
|
|
|
|
: msAnyPresent
|
|
|
|
: msAnyPresent
|
|
|
|
? `credentials incomplete (missing ${msMissing.join(", ")})`
|
|
|
|
? `credentials incomplete (missing ${msMissing.join(", ")})`
|
|
|
|
: "no credentials (MSTEAMS_APP_ID / _PASSWORD / _TENANT_ID)"
|
|
|
|
: "no credentials (MSTEAMS_APP_ID / _PASSWORD / _TENANT_ID)"
|
|
|
|
|