From 56f7a5baae63bd6f8ec499cf4c36ce5060bbd4b5 Mon Sep 17 00:00:00 2001 From: Hdsje Date: Mon, 13 Apr 2026 19:10:27 +0300 Subject: [PATCH] fix: community patches for production stability (OAuth, DB safety, burst-limit, CLI tools) (#1213) Integrated into release/v3.6.5 --- open-sse/executors/antigravity.ts | 7 +++- src/app/api/cli-tools/status/route.ts | 48 +++++++++++++++++++++++---- src/lib/db/core.ts | 8 +++-- src/lib/oauth/utils/server.ts | 2 +- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/open-sse/executors/antigravity.ts b/open-sse/executors/antigravity.ts index e6115f0fcb..ffbeaff31b 100644 --- a/open-sse/executors/antigravity.ts +++ b/open-sse/executors/antigravity.ts @@ -253,7 +253,12 @@ export class AntigravityExecutor extends BaseExecutor { if (match[2]) totalMs += parseInt(match[2]) * 60 * 1000; // minutes if (match[3]) totalMs += parseInt(match[3]) * 1000; // seconds - return totalMs > 0 ? totalMs : null; + // "reset after 0s" = burst/RPM limit, not quota exhaustion. + // Return a minimum backoff so the auto-retry loop handles it + // instead of falling through to the 24h exhaustion classifier. + if (totalMs === 0) return 2_000; // 2s minimum burst-limit backoff + + return totalMs; } /** diff --git a/src/app/api/cli-tools/status/route.ts b/src/app/api/cli-tools/status/route.ts index 2d8108aaf4..ebcb7067be 100644 --- a/src/app/api/cli-tools/status/route.ts +++ b/src/app/api/cli-tools/status/route.ts @@ -20,28 +20,62 @@ async function checkToolConfigStatus(toolId: string): Promise { if (!configPath) return "unknown"; const content = await fs.readFile(configPath, "utf-8"); + + // Codex uses TOML config — parse as raw text, not JSON + if (toolId === "codex") { + const lower = content.toLowerCase(); + const hasOmniRoute = + lower.includes("omniroute") || + lower.includes(`localhost:${apiPort}`) || + lower.includes(`127.0.0.1:${apiPort}`); + if (!hasOmniRoute) return "not_configured"; + + // Also verify auth.json has an API key (not masked/empty) + try { + const authPath = configPath.replace(/config\.toml$/, "auth.json"); + const authContent = await fs.readFile(authPath, "utf-8"); + const auth = JSON.parse(authContent); + const apiKey = auth?.OPENAI_API_KEY || ""; + if (!apiKey || apiKey.includes("****") || apiKey.length < 20) { + return "not_configured"; + } + } catch { + return "not_configured"; + } + + return "configured"; + } + const config = JSON.parse(content); // Each tool stores OmniRoute config differently switch (toolId) { case "claude": return config?.env?.ANTHROPIC_BASE_URL ? "configured" : "not_configured"; - case "codex": - return config?.providers?.omniroute || config?.providers?.["openai-compatible"] - ? "configured" - : "not_configured"; case "droid": case "openclaw": case "cline": case "kilo": // Generic check: look for OmniRoute-specific markers in the config const configStr = JSON.stringify(config).toLowerCase(); - return configStr.includes("omniroute") || + if ( + configStr.includes("omniroute") || configStr.includes("sk_omniroute") || configStr.includes(`localhost:${apiPort}`) || configStr.includes(`127.0.0.1:${apiPort}`) - ? "configured" - : "not_configured"; + ) { + return "configured"; + } + // Also accept openai-compatible provider with any non-empty baseUrl + // (user may configure an external domain instead of localhost) + if ( + toolId === "cline" && + (config.actModeApiProvider === "openai" || config.planModeApiProvider === "openai") && + (config.openAiBaseUrl || "").trim().length > 0 + ) { + return "configured"; + } + return "not_configured"; default: return "unknown"; } diff --git a/src/lib/db/core.ts b/src/lib/db/core.ts index e906c364a7..1d80647695 100644 --- a/src/lib/db/core.ts +++ b/src/lib/db/core.ts @@ -532,9 +532,13 @@ export function getDbInstance(): SqliteDatabase { } } catch (e: unknown) { const message = e instanceof Error ? e.message : String(e); - console.warn("[DB] Could not probe existing DB, will create fresh:", message); + console.warn("[DB] Could not probe existing DB:", message); + // SAFETY: Never delete the database — rename to backup so data can be recovered. + // The old code would silently destroy all user data on any probe failure. + const failedPath = sqliteFile + `.probe-failed-${Date.now()}`; try { - fs.unlinkSync(sqliteFile); + fs.renameSync(sqliteFile, failedPath); + console.warn(`[DB] Renamed corrupt DB to ${path.basename(failedPath)}`); } catch { /* ok */ } diff --git a/src/lib/oauth/utils/server.ts b/src/lib/oauth/utils/server.ts index e8d2ccc547..2e6491b15f 100644 --- a/src/lib/oauth/utils/server.ts +++ b/src/lib/oauth/utils/server.ts @@ -69,7 +69,7 @@ export function startLocalServer( // Listen on fixed port or find available port const portToUse = fixedPort || 0; - server.listen(portToUse, "127.0.0.1", () => { + server.listen(portToUse, "0.0.0.0", () => { const addr = server.address() as { port: number }; resolve({ server,