diff --git a/sdk/packages/core/src/services/global-settings.test.ts b/sdk/packages/core/src/services/global-settings.test.ts index 9860525641..84cefe51c2 100644 --- a/sdk/packages/core/src/services/global-settings.test.ts +++ b/sdk/packages/core/src/services/global-settings.test.ts @@ -6,6 +6,7 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { GlobalSettingsSchema, isAgentPluginDisabledGlobally, + isKeepChangesInProjectEnabledGlobally, isModelToolEnabledGlobally, readCompactionModeGlobally, readCompactionStrategyGlobally, @@ -19,6 +20,7 @@ import { setDisabledAgentPlugin, setDisabledPlugin, setDisabledTools, + setKeepChangesInProjectGlobally, setModelToolEnabledGlobally, setPlanActModeGlobally, setTelemetryOptOutGlobally, @@ -216,6 +218,24 @@ describe("global-settings", () => { } }); + it("keeps project edit protection on when the settings file is unreadable", async () => { + const root = await mkdtemp(join(tmpdir(), "core-global-settings-")); + try { + const settingsPath = join(root, "global-settings.json"); + process.env.CLINE_GLOBAL_SETTINGS_PATH = settingsPath; + setKeepChangesInProjectGlobally(true); + expect(isKeepChangesInProjectEnabledGlobally()).toBe(true); + + await writeFile(settingsPath, "{torn write"); + expect(isKeepChangesInProjectEnabledGlobally()).toBe(true); + + setKeepChangesInProjectGlobally(false); + expect(isKeepChangesInProjectEnabledGlobally()).toBe(false); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + it("records telemetry opt-out once when the setting changes to true", async () => { const root = await mkdtemp(join(tmpdir(), "core-global-settings-")); try { diff --git a/sdk/packages/core/src/services/global-settings.ts b/sdk/packages/core/src/services/global-settings.ts index 52cb9a016d..b7c4b25a6b 100644 --- a/sdk/packages/core/src/services/global-settings.ts +++ b/sdk/packages/core/src/services/global-settings.ts @@ -343,9 +343,18 @@ export function setToolAutoApproveGlobally(toolAutoApprove: boolean): void { * project, and file edits outside the project are refused. */ export function isKeepChangesInProjectEnabledGlobally(): boolean { - return readGlobalSettings().keepChangesInProject === true; + const cached = getCachedSettings(); + // A torn or corrupt read (e.g. another app mid-write) falls back to + // defaults; keep the last value actually read so protection does not + // silently switch off. + if (!cached.loadFailed) { + lastReadKeepChangesInProject = cached.value.keepChangesInProject === true; + } + return lastReadKeepChangesInProject; } +let lastReadKeepChangesInProject = false; + export function setKeepChangesInProjectGlobally( keepChangesInProject: boolean, ): void {