chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
@@ -28,9 +28,7 @@ export async function getAgentLocalStatuses(cfg: ClawdbotConfig) {
|
||||
}
|
||||
})();
|
||||
const bootstrapPending =
|
||||
workspaceDir != null
|
||||
? await fileExists(path.join(workspaceDir, "BOOTSTRAP.md"))
|
||||
: null;
|
||||
workspaceDir != null ? await fileExists(path.join(workspaceDir, "BOOTSTRAP.md")) : null;
|
||||
const sessionsPath = resolveStorePath(cfg.session?.store, {
|
||||
agentId: agent.id,
|
||||
});
|
||||
@@ -64,10 +62,7 @@ export async function getAgentLocalStatuses(cfg: ClawdbotConfig) {
|
||||
);
|
||||
|
||||
const totalSessions = agents.reduce((sum, a) => sum + a.sessionsCount, 0);
|
||||
const bootstrapPendingCount = agents.reduce(
|
||||
(sum, a) => sum + (a.bootstrapPending ? 1 : 0),
|
||||
0,
|
||||
);
|
||||
const bootstrapPendingCount = agents.reduce((sum, a) => sum + (a.bootstrapPending ? 1 : 0), 0);
|
||||
return {
|
||||
defaultId: agentList.defaultId,
|
||||
agents,
|
||||
|
||||
@@ -59,14 +59,10 @@ 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 {
|
||||
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}`;
|
||||
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}`;
|
||||
@@ -109,10 +105,7 @@ const buildAccountSnapshot = (params: {
|
||||
enabled: boolean;
|
||||
configured: boolean;
|
||||
}): ChannelAccountSnapshot => {
|
||||
const described = params.plugin.config.describeAccount?.(
|
||||
params.account,
|
||||
params.cfg,
|
||||
);
|
||||
const described = params.plugin.config.describeAccount?.(params.account, params.cfg);
|
||||
return {
|
||||
enabled: params.enabled,
|
||||
configured: params.configured,
|
||||
@@ -162,8 +155,7 @@ const buildAccountNotes = (params: {
|
||||
if (snapshot.dbPath) notes.push(`db:${snapshot.dbPath}`);
|
||||
|
||||
const allowFrom =
|
||||
plugin.config.resolveAllowFrom?.({ cfg, accountId: snapshot.accountId }) ??
|
||||
snapshot.allowFrom;
|
||||
plugin.config.resolveAllowFrom?.({ cfg, accountId: snapshot.accountId }) ?? snapshot.allowFrom;
|
||||
if (allowFrom?.length) {
|
||||
const formatted = formatAllowFrom({
|
||||
plugin,
|
||||
@@ -186,8 +178,7 @@ function resolveLinkFields(summary: unknown): {
|
||||
const linked = typeof rec.linked === "boolean" ? rec.linked : null;
|
||||
const authAgeMs = typeof rec.authAgeMs === "number" ? rec.authAgeMs : null;
|
||||
const self = asRecord(rec.self);
|
||||
const selfE164 =
|
||||
typeof self.e164 === "string" && self.e164.trim() ? self.e164.trim() : null;
|
||||
const selfE164 = typeof self.e164 === "string" && self.e164.trim() ? self.e164.trim() : null;
|
||||
return { linked, authAgeMs, selfE164 };
|
||||
}
|
||||
|
||||
@@ -205,8 +196,7 @@ function collectMissingPaths(accounts: ChannelAccountRow[]): string[] {
|
||||
"authDir",
|
||||
]) {
|
||||
const raw =
|
||||
(accountRec[key] as string | undefined) ??
|
||||
(snapshotRec[key] as string | undefined);
|
||||
(accountRec[key] as string | undefined) ?? (snapshotRec[key] as string | undefined);
|
||||
const ok = existsSyncMaybe(raw);
|
||||
if (ok === false) missing.push(String(raw));
|
||||
}
|
||||
@@ -224,9 +214,7 @@ function summarizeTokenConfig(params: {
|
||||
if (enabled.length === 0) return { state: null, detail: null };
|
||||
|
||||
const accountRecs = enabled.map((a) => asRecord(a.account));
|
||||
const hasBotOrAppTokenFields = accountRecs.some(
|
||||
(r) => "botToken" in r || "appToken" in r,
|
||||
);
|
||||
const hasBotOrAppTokenFields = accountRecs.some((r) => "botToken" in r || "appToken" in r);
|
||||
const hasTokenField = accountRecs.some((r) => "token" in r);
|
||||
|
||||
if (!hasBotOrAppTokenFields && !hasTokenField) {
|
||||
@@ -260,12 +248,8 @@ function summarizeTokenConfig(params: {
|
||||
return { state: "setup", detail: "no tokens (need bot+app)" };
|
||||
}
|
||||
|
||||
const botSources = summarizeSources(
|
||||
ready.map((a) => a.snapshot.botTokenSource ?? "none"),
|
||||
);
|
||||
const appSources = summarizeSources(
|
||||
ready.map((a) => a.snapshot.appTokenSource ?? "none"),
|
||||
);
|
||||
const botSources = summarizeSources(ready.map((a) => a.snapshot.botTokenSource ?? "none"));
|
||||
const appSources = summarizeSources(ready.map((a) => a.snapshot.appTokenSource ?? "none"));
|
||||
|
||||
const sample = ready[0]?.account ? asRecord(ready[0].account) : {};
|
||||
const botToken = typeof sample.botToken === "string" ? sample.botToken : "";
|
||||
@@ -277,10 +261,7 @@ function summarizeTokenConfig(params: {
|
||||
? formatTokenHint(appToken, { showSecrets: params.showSecrets })
|
||||
: "";
|
||||
|
||||
const hint =
|
||||
botHint || appHint
|
||||
? ` (bot ${botHint || "?"}, app ${appHint || "?"})`
|
||||
: "";
|
||||
const hint = botHint || appHint ? ` (bot ${botHint || "?"}, app ${appHint || "?"})` : "";
|
||||
return {
|
||||
state: "ok",
|
||||
detail: `tokens ok (bot ${botSources.label}, app ${appSources.label})${hint} · accounts ${ready.length}/${enabled.length || 1}`,
|
||||
@@ -335,8 +316,7 @@ export async function buildChannelsTable(
|
||||
cfg,
|
||||
accountIds,
|
||||
});
|
||||
const resolvedAccountIds =
|
||||
accountIds.length > 0 ? accountIds : [defaultAccountId];
|
||||
const resolvedAccountIds = accountIds.length > 0 ? accountIds : [defaultAccountId];
|
||||
|
||||
const accounts: ChannelAccountRow[] = [];
|
||||
for (const accountId of resolvedAccountIds) {
|
||||
@@ -357,8 +337,7 @@ export async function buildChannelsTable(
|
||||
const anyEnabled = accounts.some((a) => a.enabled);
|
||||
const enabledAccounts = accounts.filter((a) => a.enabled);
|
||||
const configuredAccounts = enabledAccounts.filter((a) => a.configured);
|
||||
const defaultEntry =
|
||||
accounts.find((a) => a.accountId === defaultAccountId) ?? accounts[0];
|
||||
const defaultEntry = accounts.find((a) => a.accountId === defaultAccountId) ?? accounts[0];
|
||||
|
||||
const summary = plugin.status?.buildChannelSummary
|
||||
? await plugin.status.buildChannelSummary({
|
||||
@@ -366,8 +345,7 @@ export async function buildChannelsTable(
|
||||
cfg,
|
||||
defaultAccountId,
|
||||
snapshot:
|
||||
defaultEntry?.snapshot ??
|
||||
({ accountId: defaultAccountId } as ChannelAccountSnapshot),
|
||||
defaultEntry?.snapshot ?? ({ accountId: defaultAccountId } as ChannelAccountSnapshot),
|
||||
})
|
||||
: undefined;
|
||||
|
||||
@@ -400,10 +378,7 @@ export async function buildChannelsTable(
|
||||
const detail = (() => {
|
||||
if (!anyEnabled) {
|
||||
if (!defaultEntry) return "disabled";
|
||||
return (
|
||||
plugin.config.disabledReason?.(defaultEntry.account, cfg) ??
|
||||
"disabled"
|
||||
);
|
||||
return plugin.config.disabledReason?.(defaultEntry.account, cfg) ?? "disabled";
|
||||
}
|
||||
if (missingPaths.length > 0) return `missing file (${missingPaths[0]})`;
|
||||
if (issues.length > 0) return issues[0]?.message ?? "misconfigured";
|
||||
@@ -425,8 +400,7 @@ export async function buildChannelsTable(
|
||||
|
||||
if (configuredAccounts.length > 0) {
|
||||
const head = "configured";
|
||||
if (accounts.length <= 1 && !plugin.meta.forceAccountBinding)
|
||||
return head;
|
||||
if (accounts.length <= 1 && !plugin.meta.forceAccountBinding) return head;
|
||||
return `${head} · accounts ${configuredAccounts.length}/${enabledAccounts.length || 1}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,14 +65,8 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
const { lines, muted, ok, warn, fail } = params;
|
||||
|
||||
const emitCheck = (label: string, status: "ok" | "warn" | "fail") => {
|
||||
const icon =
|
||||
status === "ok" ? ok("✓") : status === "warn" ? warn("!") : fail("✗");
|
||||
const colored =
|
||||
status === "ok"
|
||||
? ok(label)
|
||||
: status === "warn"
|
||||
? warn(label)
|
||||
: fail(label);
|
||||
const icon = status === "ok" ? ok("✓") : status === "warn" ? warn("!") : fail("✗");
|
||||
const colored = status === "ok" ? ok(label) : status === "warn" ? warn(label) : fail(label);
|
||||
lines.push(`${icon} ${colored}`);
|
||||
};
|
||||
|
||||
@@ -86,21 +80,12 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
|
||||
lines.push("");
|
||||
if (params.snap) {
|
||||
const status = !params.snap.exists
|
||||
? "fail"
|
||||
: params.snap.valid
|
||||
? "ok"
|
||||
: "warn";
|
||||
const status = !params.snap.exists ? "fail" : params.snap.valid ? "ok" : "warn";
|
||||
emitCheck(`Config: ${params.snap.path ?? "(unknown)"}`, status);
|
||||
const issues = [
|
||||
...(params.snap.legacyIssues ?? []),
|
||||
...(params.snap.issues ?? []),
|
||||
];
|
||||
const issues = [...(params.snap.legacyIssues ?? []), ...(params.snap.issues ?? [])];
|
||||
const uniqueIssues = issues.filter(
|
||||
(issue, index) =>
|
||||
issues.findIndex(
|
||||
(x) => x.path === issue.path && x.message === issue.message,
|
||||
) === index,
|
||||
issues.findIndex((x) => x.path === issue.path && x.message === issue.message) === index,
|
||||
);
|
||||
for (const issue of uniqueIssues.slice(0, 12)) {
|
||||
lines.push(` - ${issue.path}: ${issue.message}`);
|
||||
@@ -114,13 +99,8 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
|
||||
if (params.remoteUrlMissing) {
|
||||
lines.push("");
|
||||
emitCheck(
|
||||
"Gateway remote mode misconfigured (gateway.remote.url missing)",
|
||||
"warn",
|
||||
);
|
||||
lines.push(
|
||||
` ${muted("Fix: set gateway.remote.url, or set gateway.mode=local.")}`,
|
||||
);
|
||||
emitCheck("Gateway remote mode misconfigured (gateway.remote.url missing)", "warn");
|
||||
lines.push(` ${muted("Fix: set gateway.remote.url, or set gateway.mode=local.")}`);
|
||||
}
|
||||
|
||||
if (params.sentinel?.payload) {
|
||||
@@ -133,8 +113,7 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
}
|
||||
|
||||
const lastErrClean = params.lastErr?.trim() ?? "";
|
||||
const isTrivialLastErr =
|
||||
lastErrClean.length < 8 || lastErrClean === "}" || lastErrClean === "{";
|
||||
const isTrivialLastErr = lastErrClean.length < 8 || lastErrClean === "}" || lastErrClean === "{";
|
||||
if (lastErrClean && !isTrivialLastErr) {
|
||||
lines.push("");
|
||||
lines.push(`${muted("Gateway last log line:")}`);
|
||||
@@ -159,10 +138,7 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
params.tailscaleMode === "off"
|
||||
? `Tailscale: off · ${backend}${params.tailscale.dnsName ? ` · ${params.tailscale.dnsName}` : ""}`
|
||||
: `Tailscale: ${params.tailscaleMode} · ${backend}${params.tailscale.dnsName ? ` · ${params.tailscale.dnsName}` : ""}`;
|
||||
emitCheck(
|
||||
label,
|
||||
okBackend && (params.tailscaleMode === "off" || hasDns) ? "ok" : "warn",
|
||||
);
|
||||
emitCheck(label, okBackend && (params.tailscaleMode === "off" || hasDns) ? "ok" : "warn");
|
||||
if (params.tailscale.error) {
|
||||
lines.push(` ${muted(`error: ${params.tailscale.error}`)}`);
|
||||
}
|
||||
@@ -203,19 +179,13 @@ export async function appendStatusAllDiagnosis(params: {
|
||||
]);
|
||||
if (stderrTail.length > 0 || stdoutTail.length > 0) {
|
||||
lines.push("");
|
||||
lines.push(
|
||||
`${muted(`Gateway logs (tail, summarized): ${logPaths.logDir}`)}`,
|
||||
);
|
||||
lines.push(`${muted(`Gateway logs (tail, summarized): ${logPaths.logDir}`)}`);
|
||||
lines.push(` ${muted(`# stderr: ${logPaths.stderrPath}`)}`);
|
||||
for (const line of summarizeLogTail(stderrTail, { maxLines: 22 }).map(
|
||||
redactSecrets,
|
||||
)) {
|
||||
for (const line of summarizeLogTail(stderrTail, { maxLines: 22 }).map(redactSecrets)) {
|
||||
lines.push(` ${muted(line)}`);
|
||||
}
|
||||
lines.push(` ${muted(`# stdout: ${logPaths.stdoutPath}`)}`);
|
||||
for (const line of summarizeLogTail(stdoutTail, { maxLines: 22 }).map(
|
||||
redactSecrets,
|
||||
)) {
|
||||
for (const line of summarizeLogTail(stdoutTail, { maxLines: 22 }).map(redactSecrets)) {
|
||||
lines.push(` ${muted(line)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
export async function readFileTailLines(
|
||||
filePath: string,
|
||||
maxLines: number,
|
||||
): Promise<string[]> {
|
||||
export async function readFileTailLines(filePath: string, maxLines: number): Promise<string[]> {
|
||||
const raw = await fs.readFile(filePath, "utf8").catch(() => "");
|
||||
if (!raw.trim()) return [];
|
||||
const lines = raw.replace(/\r/g, "").split("\n");
|
||||
const out = lines.slice(Math.max(0, lines.length - maxLines));
|
||||
return out
|
||||
.map((line) => line.trimEnd())
|
||||
.filter((line) => line.trim().length > 0);
|
||||
return out.map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
|
||||
}
|
||||
|
||||
function countMatches(haystack: string, needle: string): number {
|
||||
@@ -42,8 +37,7 @@ function consumeJsonBlock(
|
||||
if (braceAt < 0) return null;
|
||||
|
||||
const parts: string[] = [startLine.slice(braceAt)];
|
||||
let depth =
|
||||
countMatches(parts[0] ?? "", "{") - countMatches(parts[0] ?? "", "}");
|
||||
let depth = countMatches(parts[0] ?? "", "{") - countMatches(parts[0] ?? "", "}");
|
||||
let i = startIndex;
|
||||
while (depth > 0 && i + 1 < lines.length) {
|
||||
i += 1;
|
||||
@@ -54,17 +48,11 @@ function consumeJsonBlock(
|
||||
return { json: parts.join("\n"), endIndex: i };
|
||||
}
|
||||
|
||||
export function summarizeLogTail(
|
||||
rawLines: string[],
|
||||
opts?: { maxLines?: number },
|
||||
): string[] {
|
||||
export function summarizeLogTail(rawLines: string[], opts?: { maxLines?: number }): string[] {
|
||||
const maxLines = Math.max(6, opts?.maxLines ?? 26);
|
||||
|
||||
const out: string[] = [];
|
||||
const groups = new Map<
|
||||
string,
|
||||
{ count: number; index: number; base: string }
|
||||
>();
|
||||
const groups = new Map<string, { count: number; index: number; base: string }>();
|
||||
|
||||
const addGroup = (key: string, base: string) => {
|
||||
const existing = groups.get(key);
|
||||
@@ -100,9 +88,7 @@ export function summarizeLogTail(
|
||||
}
|
||||
|
||||
// "[openai-codex] Token refresh failed: 401 { ...json... }"
|
||||
const tokenRefresh = line.match(
|
||||
/^\[([^\]]+)\]\s+Token refresh failed:\s*(\d+)\s*(\{)?\s*$/,
|
||||
);
|
||||
const tokenRefresh = line.match(/^\[([^\]]+)\]\s+Token refresh failed:\s*(\d+)\s*(\{)?\s*$/);
|
||||
if (tokenRefresh) {
|
||||
const tag = tokenRefresh[1] ?? "unknown";
|
||||
const status = tokenRefresh[2] ?? "unknown";
|
||||
@@ -126,10 +112,7 @@ export function summarizeLogTail(
|
||||
: shorten(msg, 52)
|
||||
: null;
|
||||
const base = `[${tag}] token refresh ${status}${code ? ` ${code}` : ""}${msgShort ? ` · ${msgShort}` : ""}`;
|
||||
addGroup(
|
||||
`token:${tag}:${status}:${code ?? ""}:${msgShort ?? ""}`,
|
||||
base,
|
||||
);
|
||||
addGroup(`token:${tag}:${status}:${code ?? ""}:${msgShort ?? ""}`, base);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -140,10 +123,7 @@ export function summarizeLogTail(
|
||||
);
|
||||
if (embedded) {
|
||||
const provider = embedded[1]?.trim() || "unknown";
|
||||
addGroup(
|
||||
`embedded:${provider}`,
|
||||
`Embedded agent: OAuth token refresh failed (${provider})`,
|
||||
);
|
||||
addGroup(`embedded:${provider}`, `Embedded agent: OAuth token refresh failed (${provider})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -192,8 +172,7 @@ export function pickGatewaySelfPresence(presence: unknown): {
|
||||
} | null {
|
||||
if (!Array.isArray(presence)) return null;
|
||||
const entries = presence as Array<Record<string, unknown>>;
|
||||
const self =
|
||||
entries.find((e) => e.mode === "gateway" && e.reason === "self") ?? null;
|
||||
const self = entries.find((e) => e.mode === "gateway" && e.reason === "self") ?? null;
|
||||
if (!self) return null;
|
||||
return {
|
||||
host: typeof self.host === "string" ? self.host : undefined,
|
||||
|
||||
@@ -46,13 +46,7 @@ export async function buildStatusAllReportLines(params: {
|
||||
connectionDetailsForReport: string;
|
||||
diagnosis: Omit<
|
||||
Parameters<typeof appendStatusAllDiagnosis>[0],
|
||||
| "lines"
|
||||
| "progress"
|
||||
| "muted"
|
||||
| "ok"
|
||||
| "warn"
|
||||
| "fail"
|
||||
| "connectionDetailsForReport"
|
||||
"lines" | "progress" | "muted" | "ok" | "warn" | "fail" | "connectionDetailsForReport"
|
||||
>;
|
||||
}) {
|
||||
const rich = isRich();
|
||||
@@ -129,8 +123,7 @@ export async function buildStatusAllReportLines(params: {
|
||||
? ok("OK")
|
||||
: "unknown",
|
||||
Sessions: String(a.sessionsCount),
|
||||
Active:
|
||||
a.lastActiveAgeMs != null ? formatAge(a.lastActiveAgeMs) : "unknown",
|
||||
Active: a.lastActiveAgeMs != null ? formatAge(a.lastActiveAgeMs) : "unknown",
|
||||
Store: a.sessionsPath,
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user