mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 12:31:23 +00:00
chore: Enable more lint rules, disable some that trigger a lot. Will clean up later.
This commit is contained in:
@@ -150,7 +150,7 @@ describe("agentCommand", () => {
|
||||
if (evt.stream !== "assistant") return;
|
||||
assistantEvents.push({
|
||||
runId: evt.runId,
|
||||
text: typeof evt.data?.text === "string" ? (evt.data.text as string) : undefined,
|
||||
text: typeof evt.data?.text === "string" ? evt.data.text : undefined,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function agentsListCommand(
|
||||
for (const binding of cfg.bindings ?? []) {
|
||||
const agentId = normalizeAgentId(binding.agentId);
|
||||
const list = bindingMap.get(agentId) ?? [];
|
||||
list.push(binding as AgentBinding);
|
||||
list.push(binding);
|
||||
bindingMap.set(agentId, list);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ export async function promptAuthChoiceGrouped(params: {
|
||||
continue;
|
||||
}
|
||||
|
||||
const methodSelection = (await params.prompter.select({
|
||||
const methodSelection = await params.prompter.select({
|
||||
message: `${group.label} auth method`,
|
||||
options: [...group.options, { value: BACK_VALUE, label: "Back" }],
|
||||
})) as string;
|
||||
});
|
||||
|
||||
if (methodSelection === BACK_VALUE) {
|
||||
continue;
|
||||
|
||||
@@ -108,7 +108,7 @@ export async function channelsAddCommand(
|
||||
if (wantsNames) {
|
||||
for (const channel of selection) {
|
||||
const accountId = accountIds[channel] ?? DEFAULT_ACCOUNT_ID;
|
||||
const plugin = getChannelPlugin(channel as ChannelId);
|
||||
const plugin = getChannelPlugin(channel);
|
||||
const account = plugin?.config.resolveAccount(nextConfig, accountId) as
|
||||
| { name?: string }
|
||||
| undefined;
|
||||
|
||||
@@ -38,25 +38,25 @@ export async function channelsRemoveCommand(
|
||||
|
||||
if (useWizard && prompter) {
|
||||
await prompter.intro("Remove channel account");
|
||||
const selectedChannel = (await prompter.select({
|
||||
const selectedChannel = await prompter.select({
|
||||
message: "Channel",
|
||||
options: listChannelPlugins().map((plugin) => ({
|
||||
value: plugin.id,
|
||||
label: plugin.meta.label,
|
||||
})),
|
||||
})) as ChatChannel;
|
||||
});
|
||||
channel = selectedChannel;
|
||||
|
||||
accountId = await (async () => {
|
||||
const ids = listAccountIds(cfg, selectedChannel);
|
||||
const choice = (await prompter.select({
|
||||
const choice = await prompter.select({
|
||||
message: "Account",
|
||||
options: ids.map((id) => ({
|
||||
value: id,
|
||||
label: id === DEFAULT_ACCOUNT_ID ? "default (primary)" : id,
|
||||
})),
|
||||
initialValue: ids[0] ?? DEFAULT_ACCOUNT_ID,
|
||||
})) as string;
|
||||
});
|
||||
return normalizeAccountId(choice);
|
||||
})();
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ export function formatGatewayChannelsStatusLines(payload: Record<string, unknown
|
||||
for (const plugin of plugins) {
|
||||
const accounts = accountPayloads[plugin.id];
|
||||
if (accounts && accounts.length > 0) {
|
||||
lines.push(...accountLines(plugin.id as ChatChannel, accounts));
|
||||
lines.push(...accountLines(plugin.id, accounts));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ async function formatConfigChannelsStatusLines(
|
||||
snapshots.push(snapshot);
|
||||
}
|
||||
if (snapshots.length > 0) {
|
||||
lines.push(...accountLines(plugin.id as ChatChannel, snapshots));
|
||||
lines.push(...accountLines(plugin.id, snapshots));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ export async function removeChannelConfigWizard(
|
||||
],
|
||||
}),
|
||||
runtime,
|
||||
) as string;
|
||||
);
|
||||
|
||||
if (channel === "done") return next;
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ export async function maybeInstallDaemon(params: {
|
||||
await ensureSystemdUserLingerInteractive({
|
||||
runtime: params.runtime,
|
||||
prompter: {
|
||||
confirm: async (p) => guardCancel(await confirm(p), params.runtime) === true,
|
||||
confirm: async (p) => guardCancel(await confirm(p), params.runtime),
|
||||
note,
|
||||
},
|
||||
reason:
|
||||
|
||||
@@ -59,7 +59,7 @@ export async function promptGatewayConfig(
|
||||
],
|
||||
}),
|
||||
runtime,
|
||||
) as "auto" | "lan" | "loopback" | "custom" | "tailnet";
|
||||
);
|
||||
|
||||
let customBindHost: string | undefined;
|
||||
if (bind === "custom") {
|
||||
@@ -117,7 +117,7 @@ export async function promptGatewayConfig(
|
||||
],
|
||||
}),
|
||||
runtime,
|
||||
) as "off" | "serve" | "funnel";
|
||||
);
|
||||
|
||||
// Detect Tailscale binary before proceeding with serve/funnel setup.
|
||||
if (tailscaleMode !== "off") {
|
||||
|
||||
@@ -240,7 +240,7 @@ export async function runConfigureWizard(
|
||||
],
|
||||
}),
|
||||
runtime,
|
||||
) as "local" | "remote";
|
||||
);
|
||||
|
||||
if (mode === "remote") {
|
||||
let remoteConfig = await promptRemoteGatewayConfig(baseConfig, prompter);
|
||||
|
||||
@@ -74,7 +74,7 @@ function stripUnknownConfigKeys(config: OpenClawConfig): {
|
||||
return { config, removed: [] };
|
||||
}
|
||||
|
||||
const next = structuredClone(config) as OpenClawConfig;
|
||||
const next = structuredClone(config);
|
||||
const removed: string[] = [];
|
||||
for (const issue of parsed.error.issues) {
|
||||
if (!isUnrecognizedKeysIssue(issue)) continue;
|
||||
@@ -186,7 +186,7 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
|
||||
let snapshot = await readConfigFileSnapshot();
|
||||
const baseCfg = snapshot.config ?? {};
|
||||
let cfg: OpenClawConfig = baseCfg;
|
||||
let candidate = structuredClone(baseCfg) as OpenClawConfig;
|
||||
let candidate = structuredClone(baseCfg);
|
||||
let pendingChanges = false;
|
||||
let shouldWriteConfig = false;
|
||||
const fixHints: string[] = [];
|
||||
|
||||
@@ -40,14 +40,12 @@ export function createDoctorPrompter(params: {
|
||||
if (nonInteractive) return false;
|
||||
if (shouldRepair) return true;
|
||||
if (!canPrompt) return Boolean(p.initialValue ?? false);
|
||||
return (
|
||||
guardCancel(
|
||||
await confirm({
|
||||
...p,
|
||||
message: stylePromptMessage(p.message),
|
||||
}),
|
||||
params.runtime,
|
||||
) === true
|
||||
return guardCancel(
|
||||
await confirm({
|
||||
...p,
|
||||
message: stylePromptMessage(p.message),
|
||||
}),
|
||||
params.runtime,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -62,14 +60,12 @@ export function createDoctorPrompter(params: {
|
||||
if (shouldRepair && shouldForce) return true;
|
||||
if (shouldRepair && !shouldForce) return false;
|
||||
if (!canPrompt) return Boolean(p.initialValue ?? false);
|
||||
return (
|
||||
guardCancel(
|
||||
await confirm({
|
||||
...p,
|
||||
message: stylePromptMessage(p.message),
|
||||
}),
|
||||
params.runtime,
|
||||
) === true
|
||||
return guardCancel(
|
||||
await confirm({
|
||||
...p,
|
||||
message: stylePromptMessage(p.message),
|
||||
}),
|
||||
params.runtime,
|
||||
);
|
||||
},
|
||||
confirmSkipInNonInteractive: async (p) => {
|
||||
|
||||
@@ -302,7 +302,7 @@ export async function noteStateIntegrity(
|
||||
if (entries.length > 0) {
|
||||
const recent = entries
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
.toSorted((a, b) => {
|
||||
const aUpdated = typeof a[1].updatedAt === "number" ? a[1].updatedAt : 0;
|
||||
const bUpdated = typeof b[1].updatedAt === "number" ? b[1].updatedAt : 0;
|
||||
return bUpdated - aUpdated;
|
||||
|
||||
@@ -135,7 +135,7 @@ const buildSessionSummary = (storePath: string) => {
|
||||
const sessions = Object.entries(store)
|
||||
.filter(([key]) => key !== "global" && key !== "unknown")
|
||||
.map(([key, entry]) => ({ key, updatedAt: entry?.updatedAt ?? 0 }))
|
||||
.sort((a, b) => b.updatedAt - a.updatedAt);
|
||||
.toSorted((a, b) => b.updatedAt - a.updatedAt);
|
||||
const recent = sessions.slice(0, 5).map((s) => ({
|
||||
key: s.key,
|
||||
updatedAt: s.updatedAt || null,
|
||||
|
||||
@@ -185,7 +185,7 @@ function renderReactions(payload: unknown, opts: FormatOpts): string[] | null {
|
||||
const emoji =
|
||||
(typeof emojiObj?.raw === "string" && emojiObj.raw) ||
|
||||
(typeof entry.name === "string" && entry.name) ||
|
||||
(typeof entry.emoji === "string" && (entry.emoji as string)) ||
|
||||
(typeof entry.emoji === "string" && entry.emoji) ||
|
||||
"";
|
||||
const count = typeof entry.count === "number" ? String(entry.count) : "";
|
||||
const userList = Array.isArray(entry.users)
|
||||
|
||||
@@ -140,7 +140,7 @@ export async function promptDefaultModel(
|
||||
});
|
||||
}
|
||||
|
||||
const providers = Array.from(new Set(models.map((entry) => entry.provider))).sort((a, b) =>
|
||||
const providers = Array.from(new Set(models.map((entry) => entry.provider))).toSorted((a, b) =>
|
||||
a.localeCompare(b),
|
||||
);
|
||||
|
||||
@@ -183,7 +183,7 @@ export async function promptDefaultModel(
|
||||
return value;
|
||||
};
|
||||
|
||||
const options: WizardSelectOption<string>[] = [];
|
||||
const options: WizardSelectOption[] = [];
|
||||
if (allowKeep) {
|
||||
options.push({
|
||||
value: KEEP_VALUE,
|
||||
@@ -325,7 +325,7 @@ export async function promptModelAllowlist(params: {
|
||||
return value;
|
||||
};
|
||||
|
||||
const options: WizardSelectOption<string>[] = [];
|
||||
const options: WizardSelectOption[] = [];
|
||||
const seen = new Set<string>();
|
||||
const addModelOption = (entry: {
|
||||
provider: string;
|
||||
|
||||
@@ -64,7 +64,7 @@ export async function modelsListCommand(
|
||||
};
|
||||
|
||||
if (opts.all) {
|
||||
const sorted = [...models].sort((a, b) => {
|
||||
const sorted = [...models].toSorted((a, b) => {
|
||||
const p = a.provider.localeCompare(b.provider);
|
||||
if (p !== 0) return p;
|
||||
return a.id.localeCompare(b.id);
|
||||
|
||||
@@ -445,7 +445,7 @@ export function groupProbeResults(results: AuthProbeResult[]): Map<string, AuthP
|
||||
}
|
||||
|
||||
export function sortProbeResults(results: AuthProbeResult[]): AuthProbeResult[] {
|
||||
return results.slice().sort((a, b) => {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const provider = a.provider.localeCompare(b.provider);
|
||||
if (provider !== 0) return provider;
|
||||
const aLabel = a.label || a.profileId || "";
|
||||
|
||||
@@ -43,8 +43,8 @@ export async function loadModelRegistry(cfg: OpenClawConfig) {
|
||||
const agentDir = resolveOpenClawAgentDir();
|
||||
const authStorage = discoverAuthStorage(agentDir);
|
||||
const registry = discoverModels(authStorage, agentDir);
|
||||
const models = registry.getAll() as Model<Api>[];
|
||||
const availableModels = registry.getAvailable() as Model<Api>[];
|
||||
const models = registry.getAll();
|
||||
const availableModels = registry.getAvailable();
|
||||
const availableKeys = new Set(availableModels.map((model) => modelKey(model.provider, model.id)));
|
||||
return { registry, models, availableKeys };
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ export async function modelsStatusCommand(
|
||||
)
|
||||
.map((p) => p.trim())
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
.toSorted((a, b) => a.localeCompare(b));
|
||||
|
||||
const applied = getShellEnvAppliedKeys();
|
||||
const shellFallbackEnabled =
|
||||
@@ -185,7 +185,7 @@ export async function modelsStatusCommand(
|
||||
const providerAuthMap = new Map(providerAuth.map((entry) => [entry.provider, entry]));
|
||||
const missingProvidersInUse = Array.from(providersInUse)
|
||||
.filter((provider) => !providerAuthMap.has(provider))
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
.toSorted((a, b) => a.localeCompare(b));
|
||||
|
||||
const probeProfileIds = (() => {
|
||||
if (!opts.probeProfile) return [];
|
||||
@@ -298,7 +298,7 @@ export async function modelsStatusCommand(
|
||||
remainingMs: unusableUntil - now,
|
||||
});
|
||||
}
|
||||
return out.sort((a, b) => a.remainingMs - b.remainingMs);
|
||||
return out.toSorted((a, b) => a.remainingMs - b.remainingMs);
|
||||
})();
|
||||
|
||||
const checkStatus = (() => {
|
||||
|
||||
@@ -33,7 +33,7 @@ const truncate = (value: string, max: number) => {
|
||||
};
|
||||
|
||||
function sortScanResults(results: ModelScanResult[]): ModelScanResult[] {
|
||||
return results.slice().sort((a, b) => {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const aImage = a.image.ok ? 1 : 0;
|
||||
const bImage = b.image.ok ? 1 : 0;
|
||||
if (aImage !== bImage) return bImage - aImage;
|
||||
@@ -55,7 +55,7 @@ function sortScanResults(results: ModelScanResult[]): ModelScanResult[] {
|
||||
}
|
||||
|
||||
function sortImageResults(results: ModelScanResult[]): ModelScanResult[] {
|
||||
return results.slice().sort((a, b) => {
|
||||
return results.slice().toSorted((a, b) => {
|
||||
const aLatency = a.image.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
const bLatency = b.image.latencyMs ?? Number.POSITIVE_INFINITY;
|
||||
if (aLatency !== bLatency) return aLatency - bLatency;
|
||||
@@ -255,7 +255,7 @@ export async function modelsScanCommand(
|
||||
runtime.exit(0);
|
||||
}
|
||||
|
||||
selected = selection as string[];
|
||||
selected = selection;
|
||||
if (imageSorted.length > 0) {
|
||||
const imageSelection = await multiselect({
|
||||
message: "Select image fallback models (ordered)",
|
||||
@@ -272,7 +272,7 @@ export async function modelsScanCommand(
|
||||
runtime.exit(0);
|
||||
}
|
||||
|
||||
selectedImages = imageSelection as string[];
|
||||
selectedImages = imageSelection;
|
||||
}
|
||||
} else if (!process.stdin.isTTY && !opts.yes && !noInput && !opts.json) {
|
||||
throw new Error("Non-interactive scan: pass --yes to apply defaults.");
|
||||
|
||||
@@ -74,11 +74,11 @@ async function promptConfiguredAction(params: {
|
||||
...(supportsDelete ? [deleteOption] : []),
|
||||
skipOption,
|
||||
];
|
||||
return (await prompter.select({
|
||||
return await prompter.select({
|
||||
message: `${label} already configured. What do you want to do?`,
|
||||
options,
|
||||
initialValue: "update",
|
||||
})) as ConfiguredChannelAction;
|
||||
});
|
||||
}
|
||||
|
||||
async function promptRemovalAccountId(params: {
|
||||
@@ -93,14 +93,14 @@ async function promptRemovalAccountId(params: {
|
||||
const accountIds = plugin.config.listAccountIds(cfg).filter(Boolean);
|
||||
const defaultAccountId = resolveChannelDefaultAccountId({ plugin, cfg, accountIds });
|
||||
if (accountIds.length <= 1) return defaultAccountId;
|
||||
const selected = (await prompter.select({
|
||||
const selected = await prompter.select({
|
||||
message: `${label} account`,
|
||||
options: accountIds.map((accountId) => ({
|
||||
value: accountId,
|
||||
label: formatAccountLabel(accountId),
|
||||
})),
|
||||
initialValue: defaultAccountId,
|
||||
})) as string;
|
||||
});
|
||||
return normalizeAccountId(selected) ?? defaultAccountId;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ export async function setupChannels(
|
||||
if (!shouldConfigure) return cfg;
|
||||
|
||||
const corePrimer = listChatChannels().map((meta) => ({
|
||||
id: meta.id as ChannelChoice,
|
||||
id: meta.id,
|
||||
label: meta.label,
|
||||
blurb: meta.blurb,
|
||||
}));
|
||||
@@ -312,9 +312,9 @@ export async function setupChannels(
|
||||
const primerChannels = [
|
||||
...corePrimer,
|
||||
...installedPlugins
|
||||
.filter((plugin) => !coreIds.has(plugin.id as ChannelChoice))
|
||||
.filter((plugin) => !coreIds.has(plugin.id))
|
||||
.map((plugin) => ({
|
||||
id: plugin.id as ChannelChoice,
|
||||
id: plugin.id,
|
||||
label: plugin.meta.label,
|
||||
blurb: plugin.meta.blurb,
|
||||
})),
|
||||
|
||||
@@ -33,7 +33,7 @@ export function guardCancel<T>(value: T | symbol, runtime: RuntimeEnv): T {
|
||||
cancel(stylePromptTitle("Setup cancelled.") ?? "Setup cancelled.");
|
||||
runtime.exit(0);
|
||||
}
|
||||
return value as T;
|
||||
return value;
|
||||
}
|
||||
|
||||
export function summarizeExistingConfig(config: OpenClawConfig): string {
|
||||
|
||||
@@ -227,7 +227,7 @@ describe("onboard (non-interactive): gateway and remote auth", () => {
|
||||
// otherwise sees a mocked writeConfigFile and the config never lands on disk).
|
||||
vi.resetModules();
|
||||
vi.doMock("../config/config.js", async () => {
|
||||
return (await vi.importActual("../config/config.js")) as typeof import("../config/config.js");
|
||||
return await vi.importActual("../config/config.js");
|
||||
});
|
||||
|
||||
const { runNonInteractiveOnboarding } = await import("./onboard-non-interactive.js");
|
||||
|
||||
@@ -118,13 +118,13 @@ export async function promptRemoteGatewayConfig(
|
||||
});
|
||||
const url = ensureWsUrl(String(urlInput));
|
||||
|
||||
const authChoice = (await prompter.select({
|
||||
const authChoice = await prompter.select({
|
||||
message: "Gateway auth",
|
||||
options: [
|
||||
{ value: "token", label: "Token (recommended)" },
|
||||
{ value: "off", label: "No auth" },
|
||||
],
|
||||
})) as "token" | "off";
|
||||
});
|
||||
|
||||
let token = cfg.gateway?.remote?.token ?? "";
|
||||
if (authChoice === "token") {
|
||||
|
||||
@@ -132,7 +132,7 @@ export async function setupSkills(
|
||||
],
|
||||
});
|
||||
|
||||
const selected = (toInstall as string[]).filter((name) => name !== "__skip__");
|
||||
const selected = toInstall.filter((name) => name !== "__skip__");
|
||||
for (const name of selected) {
|
||||
const target = installable.find((s) => s.name === name);
|
||||
if (!target || target.install.length === 0) continue;
|
||||
|
||||
@@ -5,9 +5,7 @@ import type { ChannelOnboardingAdapter } from "./types.js";
|
||||
const CHANNEL_ONBOARDING_ADAPTERS = () =>
|
||||
new Map<ChannelChoice, ChannelOnboardingAdapter>(
|
||||
listChannelPlugins()
|
||||
.map((plugin) =>
|
||||
plugin.onboarding ? ([plugin.id as ChannelChoice, plugin.onboarding] as const) : null,
|
||||
)
|
||||
.map((plugin) => (plugin.onboarding ? ([plugin.id, plugin.onboarding] as const) : null))
|
||||
.filter((entry): entry is readonly [ChannelChoice, ChannelOnboardingAdapter] =>
|
||||
Boolean(entry),
|
||||
),
|
||||
|
||||
@@ -144,7 +144,7 @@ function toRows(store: Record<string, SessionEntry>): SessionRow[] {
|
||||
contextTokens: entry?.contextTokens,
|
||||
} satisfies SessionRow;
|
||||
})
|
||||
.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
||||
.toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
||||
}
|
||||
|
||||
export async function sessionsCommand(
|
||||
|
||||
@@ -220,7 +220,7 @@ export async function statusAllCommand(
|
||||
|
||||
progress.setLabel("Querying gateway…");
|
||||
const health = gatewayReachable
|
||||
? await callGateway<unknown>({
|
||||
? await callGateway({
|
||||
method: "health",
|
||||
timeoutMs: Math.min(8000, opts?.timeoutMs ?? 10_000),
|
||||
...callOverrides,
|
||||
@@ -379,19 +379,17 @@ export async function statusAllCommand(
|
||||
daemon
|
||||
? {
|
||||
Item: "Gateway service",
|
||||
Value:
|
||||
daemon.installed === false
|
||||
? `${daemon.label} not installed`
|
||||
: `${daemon.label} ${daemon.installed ? "installed · " : ""}${daemon.loadedText}${daemon.runtime?.status ? ` · ${daemon.runtime.status}` : ""}${daemon.runtime?.pid ? ` (pid ${daemon.runtime.pid})` : ""}`,
|
||||
Value: !daemon.installed
|
||||
? `${daemon.label} not installed`
|
||||
: `${daemon.label} ${daemon.installed ? "installed · " : ""}${daemon.loadedText}${daemon.runtime?.status ? ` · ${daemon.runtime.status}` : ""}${daemon.runtime?.pid ? ` (pid ${daemon.runtime.pid})` : ""}`,
|
||||
}
|
||||
: { Item: "Gateway service", Value: "unknown" },
|
||||
nodeService
|
||||
? {
|
||||
Item: "Node service",
|
||||
Value:
|
||||
nodeService.installed === false
|
||||
? `${nodeService.label} not installed`
|
||||
: `${nodeService.label} ${nodeService.installed ? "installed · " : ""}${nodeService.loadedText}${nodeService.runtime?.status ? ` · ${nodeService.runtime.status}` : ""}${nodeService.runtime?.pid ? ` (pid ${nodeService.runtime.pid})` : ""}`,
|
||||
Value: !nodeService.installed
|
||||
? `${nodeService.label} not installed`
|
||||
: `${nodeService.label} ${nodeService.installed ? "installed · " : ""}${nodeService.loadedText}${nodeService.runtime?.status ? ` · ${nodeService.runtime.status}` : ""}${nodeService.runtime?.pid ? ` (pid ${nodeService.runtime.pid})` : ""}`,
|
||||
}
|
||||
: { Item: "Node service", Value: "unknown" },
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ function summarizeSources(sources: Array<string | undefined>): {
|
||||
counts.set(key, (counts.get(key) ?? 0) + 1);
|
||||
}
|
||||
const parts = [...counts.entries()]
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.toSorted((a, b) => b[1] - a[1])
|
||||
.map(([key, n]) => `${key}${n > 1 ? `×${n}` : ""}`);
|
||||
const label = parts.length > 0 ? parts.join("+") : "unknown";
|
||||
return { label, parts };
|
||||
@@ -430,7 +430,7 @@ export async function buildChannelsTable(
|
||||
accountId: entry.accountId,
|
||||
name: entry.snapshot.name,
|
||||
}),
|
||||
Status: entry.enabled !== false ? "OK" : "WARN",
|
||||
Status: entry.enabled ? "OK" : "WARN",
|
||||
Notes: notes.join(" · "),
|
||||
};
|
||||
}),
|
||||
|
||||
@@ -401,7 +401,9 @@ export async function statusCommand(
|
||||
};
|
||||
const sevRank = (sev: "critical" | "warn" | "info") =>
|
||||
sev === "critical" ? 0 : sev === "warn" ? 1 : 2;
|
||||
const sorted = [...importantFindings].sort((a, b) => sevRank(a.severity) - sevRank(b.severity));
|
||||
const sorted = [...importantFindings].toSorted(
|
||||
(a, b) => sevRank(a.severity) - sevRank(b.severity),
|
||||
);
|
||||
const shown = sorted.slice(0, 6);
|
||||
for (const f of shown) {
|
||||
runtime.log(` ${severityLabel(f.severity)} ${f.title}`);
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function resolveLinkChannelContext(
|
||||
snapshot,
|
||||
})
|
||||
: undefined;
|
||||
const summaryRecord = summary as Record<string, unknown> | undefined;
|
||||
const summaryRecord = summary;
|
||||
const linked =
|
||||
summaryRecord && typeof summaryRecord.linked === "boolean" ? summaryRecord.linked : null;
|
||||
if (linked === null) continue;
|
||||
|
||||
@@ -150,7 +150,7 @@ export async function getStatusSummary(): Promise<StatusSummary> {
|
||||
|
||||
const allSessions = Array.from(paths)
|
||||
.flatMap((storePath) => buildSessionRows(loadStore(storePath)))
|
||||
.sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
||||
.toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
||||
const recent = allSessions.slice(0, 10);
|
||||
const totalSessions = allSessions.length;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user