fix(status): full-width tables + better diagnosis

This commit is contained in:
Peter Steinberger
2026-01-11 00:54:19 +01:00
parent f3882671c9
commit 5fa3ac1e01
9 changed files with 1063 additions and 885 deletions

View File

@@ -13,6 +13,177 @@ export async function readFileTailLines(
.filter((line) => line.trim().length > 0);
}
function countMatches(haystack: string, needle: string): number {
if (!haystack || !needle) return 0;
return haystack.split(needle).length - 1;
}
function shorten(message: string, maxLen: number): string {
const cleaned = message.replace(/\s+/g, " ").trim();
if (cleaned.length <= maxLen) return cleaned;
return `${cleaned.slice(0, Math.max(0, maxLen - 1))}`;
}
function normalizeGwsLine(line: string): string {
return line
.replace(/\s+runId=[^\s]+/g, "")
.replace(/\s+conn=[^\s]+/g, "")
.replace(/\s+id=[^\s]+/g, "")
.replace(/\s+error=Error:.*$/g, "")
.trim();
}
function consumeJsonBlock(
lines: string[],
startIndex: number,
): { json: string; endIndex: number } | null {
const startLine = lines[startIndex] ?? "";
const braceAt = startLine.indexOf("{");
if (braceAt < 0) return null;
const parts: string[] = [startLine.slice(braceAt)];
let depth =
countMatches(parts[0] ?? "", "{") - countMatches(parts[0] ?? "", "}");
let i = startIndex;
while (depth > 0 && i + 1 < lines.length) {
i += 1;
const next = lines[i] ?? "";
parts.push(next);
depth += countMatches(next, "{") - countMatches(next, "}");
}
return { json: parts.join("\n"), endIndex: i };
}
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 addGroup = (key: string, base: string) => {
const existing = groups.get(key);
if (existing) {
existing.count += 1;
return;
}
groups.set(key, { count: 1, index: out.length, base });
out.push(base);
};
const addLine = (line: string) => {
const trimmed = line.trimEnd();
if (!trimmed) return;
out.push(trimmed);
};
const lines = rawLines.map((line) => line.trimEnd()).filter(Boolean);
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i] ?? "";
const trimmedStart = line.trimStart();
if (
(trimmedStart.startsWith('"') ||
trimmedStart === "}" ||
trimmedStart === "{" ||
trimmedStart.startsWith("}") ||
trimmedStart.startsWith("{")) &&
!trimmedStart.startsWith("[") &&
!trimmedStart.startsWith("#")
) {
// Tail can cut in the middle of a JSON blob; drop orphaned JSON fragments.
continue;
}
// "[openai-codex] Token refresh failed: 401 { ...json... }"
const tokenRefresh = line.match(
/^\[([^\]]+)\]\s+Token refresh failed:\s*(\d+)\s*(\{)?\s*$/,
);
if (tokenRefresh) {
const tag = tokenRefresh[1] ?? "unknown";
const status = tokenRefresh[2] ?? "unknown";
const block = consumeJsonBlock(lines, i);
if (block) {
i = block.endIndex;
const parsed = (() => {
try {
return JSON.parse(block.json) as {
error?: { code?: string; message?: string };
};
} catch {
return null;
}
})();
const code = parsed?.error?.code?.trim() || null;
const msg = parsed?.error?.message?.trim() || null;
const msgShort = msg
? msg.toLowerCase().includes("signing in again")
? "re-auth required"
: shorten(msg, 52)
: null;
const base = `[${tag}] token refresh ${status}${code ? ` ${code}` : ""}${msgShort ? ` · ${msgShort}` : ""}`;
addGroup(
`token:${tag}:${status}:${code ?? ""}:${msgShort ?? ""}`,
base,
);
continue;
}
}
// "Embedded agent failed before reply: OAuth token refresh failed for openai-codex: ..."
const embedded = line.match(
/^Embedded agent failed before reply:\s+OAuth token refresh failed for ([^:]+):/,
);
if (embedded) {
const provider = embedded[1]?.trim() || "unknown";
addGroup(
`embedded:${provider}`,
`Embedded agent: OAuth token refresh failed (${provider})`,
);
continue;
}
// "[gws] ⇄ res ✗ agent ... errorCode=UNAVAILABLE errorMessage=Error: OAuth token refresh failed ... runId=..."
if (
line.startsWith("[gws]") &&
line.includes("errorCode=UNAVAILABLE") &&
line.includes("OAuth token refresh failed")
) {
const normalized = normalizeGwsLine(line);
addGroup(`gws:${normalized}`, normalized);
continue;
}
addLine(line);
}
for (const g of groups.values()) {
if (g.count <= 1) continue;
out[g.index] = `${g.base} ×${g.count}`;
}
const deduped: string[] = [];
for (const line of out) {
if (deduped[deduped.length - 1] === line) continue;
deduped.push(line);
}
if (deduped.length <= maxLines) return deduped;
const head = Math.min(6, Math.floor(maxLines / 3));
const tail = Math.max(1, maxLines - head - 1);
const kept = [
...deduped.slice(0, head),
`${deduped.length - head - tail} lines omitted …`,
...deduped.slice(-tail),
];
return kept;
}
export function pickGatewaySelfPresence(presence: unknown): {
host?: string;
ip?: string;