diff --git a/open-sse/services/antigravityCredits.ts b/open-sse/services/antigravityCredits.ts index 31cd744983..b56bcb7eed 100644 --- a/open-sse/services/antigravityCredits.ts +++ b/open-sse/services/antigravityCredits.ts @@ -40,3 +40,29 @@ export function shouldRetryWithCredits(authKey: string, creditsEnabled: boolean) export function handleCreditsFailure(authKey: string): boolean { return recordCreditsFailure(authKey); } + +/** + * Read the ANTIGRAVITY_CREDITS env var to determine the credits injection strategy. + * + * - "off" — never inject credits (default if env var is missing) + * - "retry" — inject credits only as a 429 fallback + * - "always" — inject credits on every request (skip normal quota path) + */ +export type CreditsMode = "off" | "retry" | "always"; + +export function getCreditsMode(): CreditsMode { + const raw = (process.env.ANTIGRAVITY_CREDITS || "").trim().toLowerCase(); + if (raw === "always" || raw === "retry") return raw; + return "off"; +} + +/** + * Determine if the executor should inject credits on the *first* request + * (credits-first mode). Returns true only when creditsMode === "always" + * and the auth key hasn't been disabled by repeated failures. + */ +export function shouldUseCreditsFirst(authKey: string, creditsMode: CreditsMode | string): boolean { + if (creditsMode !== "always") return false; + if (isCreditsDisabled(authKey)) return false; + return true; +} diff --git a/src/lib/db/core.ts b/src/lib/db/core.ts index 00d9c6c1d1..715d5f6b3d 100644 --- a/src/lib/db/core.ts +++ b/src/lib/db/core.ts @@ -791,7 +791,9 @@ export function getDbInstance(): SqliteDatabase { .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='key_value'") .get(); if (hasKv) { - const rowCount = (kvProbe.prepare("SELECT COUNT(*) AS c FROM key_value").get() as { c: number }).c; + const rowCount = ( + kvProbe.prepare("SELECT COUNT(*) AS c FROM key_value").get() as { c: number } + ).c; if (rowCount > KEY_VALUE_PRESERVE_LIMIT) { console.warn( `[DB] key_value has ${rowCount} rows (limit ${KEY_VALUE_PRESERVE_LIMIT}), skipping preservation` @@ -819,6 +821,12 @@ export function getDbInstance(): SqliteDatabase { } } + // Track whether the DB file is brand new (fresh DATA_DIR / Docker volume). + // This is needed so the migration runner skips the mass-migration safety abort + // that would otherwise trigger because heuristic seeding marks some migrations + // as applied, making the fresh DB look like a wiped existing DB (#1328). + const isNewDb = !fs.existsSync(sqliteFile); + // Detect and handle old schema format — preserve data when possible (#146) // Uses a single probe connection that becomes the real connection when possible. if (fs.existsSync(sqliteFile)) { @@ -983,7 +991,7 @@ export function getDbInstance(): SqliteDatabase { "call_logs_summary_storage" ); } - runMigrations(db); + runMigrations(db, { isNewDb }); offloadLegacyCallLogDetails(db); // Auto-migrate from db.json if exists diff --git a/src/lib/db/migrationRunner.ts b/src/lib/db/migrationRunner.ts index 06f3a9983a..8e5517dcad 100644 --- a/src/lib/db/migrationRunner.ts +++ b/src/lib/db/migrationRunner.ts @@ -150,12 +150,10 @@ function reconcileRenumberedMigrations( for (const compatibility of RENAMED_MIGRATION_COMPATIBILITY) { const hasTargetFile = files.some( - (file) => - file.version === compatibility.toVersion && file.name === compatibility.toName + (file) => file.version === compatibility.toVersion && file.name === compatibility.toName ); const hasSourceFile = files.some( - (file) => - file.version === compatibility.fromVersion && file.name !== compatibility.fromName + (file) => file.version === compatibility.fromVersion && file.name !== compatibility.fromName ); if (!hasTargetFile || !hasSourceFile) { @@ -241,7 +239,8 @@ function createPreMigrationBackup(db: Database.Database): string | null { * 2. Aborts if too many pending migrations on an existing DB (likely wipe) * 3. Creates automatic backup before running any migrations */ -export function runMigrations(db: Database.Database): number { +export function runMigrations(db: Database.Database, options?: { isNewDb?: boolean }): number { + const isNewDb = options?.isNewDb === true; ensureMigrationsTable(db); const files = getMigrationFiles(); @@ -284,6 +283,7 @@ export function runMigrations(db: Database.Database): number { if ( !isTestEnvironment && + !isNewDb && process.env.DISABLE_SQLITE_AUTO_BACKUP !== "true" && MAX_PENDING_MIGRATIONS_ON_EXISTING_DB > 0 && applied.size > 0 &&