diff --git a/apps/server/src/provider/Drivers/CodexHomeLayout.test.ts b/apps/server/src/provider/Drivers/CodexHomeLayout.test.ts index 2bbcea20faa91..fe1d4cfc25275 100644 --- a/apps/server/src/provider/Drivers/CodexHomeLayout.test.ts +++ b/apps/server/src/provider/Drivers/CodexHomeLayout.test.ts @@ -165,6 +165,66 @@ it.layer(NodeServices.layer)("CodexHomeLayout", (it) => { }), ); + it.effect.skipIf(!symlinksSupported)( + "keeps a shadow home's own cloud config bundle cache", + () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const sharedHome = yield* makeTempDir("t3code-codex-shared-"); + const shadowHome = yield* makeTempDir("t3code-codex-shadow-"); + const shadowCache = path.join(shadowHome, "cloud-config-bundle-cache.json"); + + yield* writeTextFile( + path.join(sharedHome, "cloud-config-bundle-cache.json"), + '{"account_id":"shared"}\n', + ); + yield* writeTextFile(shadowCache, '{"account_id":"shadow"}\n'); + const layout = yield* resolveCodexHomeLayout( + decodeCodexSettings({ homePath: sharedHome, shadowHomePath: shadowHome }), + ); + + yield* materializeCodexShadowHome(layout); + + expect(yield* fileSystem.readFileString(shadowCache)).toBe('{"account_id":"shadow"}\n'); + }), + ); + + it.effect.skipIf(!symlinksSupported)( + "does not share the cloud config bundle cache with shadow homes", + () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const sharedHome = yield* makeTempDir("t3code-codex-shared-"); + const freshShadowHome = yield* makeTempDir("t3code-codex-shadow-"); + const linkedShadowHome = yield* makeTempDir("t3code-codex-shadow-"); + const sharedCache = path.join(sharedHome, "cloud-config-bundle-cache.json"); + + yield* writeTextFile(sharedCache, '{"account_id":"shared"}\n'); + yield* fileSystem.symlink( + sharedCache, + path.join(linkedShadowHome, "cloud-config-bundle-cache.json"), + ); + + for (const shadowHome of [freshShadowHome, linkedShadowHome]) { + yield* materializeCodexShadowHome( + yield* resolveCodexHomeLayout( + decodeCodexSettings({ homePath: sharedHome, shadowHomePath: shadowHome }), + ), + ); + } + + expect( + yield* fileSystem.exists(path.join(freshShadowHome, "cloud-config-bundle-cache.json")), + ).toBe(false); + expect( + yield* fileSystem.exists(path.join(linkedShadowHome, "cloud-config-bundle-cache.json")), + ).toBe(false); + expect(yield* fileSystem.readFileString(sharedCache)).toBe('{"account_id":"shared"}\n'); + }), + ); + it.effect.skipIf(!symlinksSupported)( "replaces a Codex-created local sqlite maintenance lock with the shared lock", () => diff --git a/apps/server/src/provider/Drivers/CodexHomeLayout.ts b/apps/server/src/provider/Drivers/CodexHomeLayout.ts index f6d2ba9d44cf5..7cc7b94521da6 100644 --- a/apps/server/src/provider/Drivers/CodexHomeLayout.ts +++ b/apps/server/src/provider/Drivers/CodexHomeLayout.ts @@ -30,7 +30,12 @@ const KNOWN_SHARED_DIRECTORIES = [ ] as const; // auth.lock guards the shadow home's private auth.json. -const PRIVATE_ENTRY_NAMES = new Set(["auth.json", "auth.lock", "models_cache.json"]); +const PRIVATE_ENTRY_NAMES = new Set([ + "auth.json", + "auth.lock", + "models_cache.json", + "cloud-config-bundle-cache.json", +]); // Finder maintains metadata separately for each directory, including shadow homes. const SHADOW_LOCAL_ENTRY_NAMES = new Set(["log", "memories", "tmp", ".DS_Store"]); // Shadow homes may create local runtime locks first; replace them with shared links because they guard shared state.