



















@@ -2,6 +2,7 @@ import fs from "node:fs";
22import path from "node:path";
33import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
44import { createSuiteTempRootTracker } from "../test-helpers/temp-dir.js";
5+import { readSessionStoreCache, writeSessionStoreCache } from "./sessions/store-cache.js";
56import {
67clearSessionStoreCacheForTest,
78loadSessionStore,
@@ -107,6 +108,121 @@ describe("Session Store Cache", () => {
107108expect(loaded2["session:1"].skillsSnapshot?.skills?.[0]?.name).toBe("alpha");
108109});
109110111+it("does not cache pre-migration or pre-normalization disk JSON", () => {
112+fs.writeFileSync(
113+storePath,
114+JSON.stringify({
115+"session:1": {
116+sessionId: "id-1",
117+updatedAt: Date.now(),
118+provider: "telegram",
119+room: "room-1",
120+modelProvider: " openai ",
121+model: " gpt-5.4 ",
122+},
123+}),
124+);
125+126+const loaded1 = loadSessionStore(storePath);
127+const entry1 = loaded1["session:1"] as SessionEntry & { provider?: string; room?: string };
128+expect(entry1.channel).toBe("telegram");
129+expect(entry1.groupChannel).toBe("room-1");
130+expect(entry1.provider).toBeUndefined();
131+expect(entry1.room).toBeUndefined();
132+expect(entry1.modelProvider).toBe("openai");
133+expect(entry1.model).toBe("gpt-5.4");
134+135+const loaded2 = loadSessionStore(storePath);
136+const entry2 = loaded2["session:1"] as SessionEntry & { provider?: string; room?: string };
137+expect(entry2.channel).toBe("telegram");
138+expect(entry2.groupChannel).toBe("room-1");
139+expect(entry2.provider).toBeUndefined();
140+expect(entry2.room).toBeUndefined();
141+expect(entry2.modelProvider).toBe("openai");
142+expect(entry2.model).toBe("gpt-5.4");
143+});
144+145+it("isolates cached session stores without structuredClone", async () => {
146+const structuredCloneSpy = vi.spyOn(globalThis, "structuredClone");
147+const testStore = createSingleSessionStore(
148+createSessionEntry({
149+origin: { provider: "openai" },
150+skillsSnapshot: {
151+prompt: "skills",
152+skills: [{ name: "alpha" }],
153+},
154+}),
155+);
156+157+await saveSessionStore(storePath, testStore);
158+159+const loaded1 = loadSessionStore(storePath);
160+loaded1["session:1"].origin = { provider: "mutated" };
161+if (loaded1["session:1"].skillsSnapshot?.skills?.length) {
162+loaded1["session:1"].skillsSnapshot.skills[0].name = "mutated";
163+}
164+165+const loaded2 = loadSessionStore(storePath);
166+expect(loaded2["session:1"].origin?.provider).toBe("openai");
167+expect(loaded2["session:1"].skillsSnapshot?.skills?.[0]?.name).toBe("alpha");
168+expect(structuredCloneSpy).not.toHaveBeenCalled();
169+170+structuredCloneSpy.mockRestore();
171+});
172+173+it("does not parse serialized stores when writing the cache", () => {
174+const testStore = createSingleSessionStore(
175+createSessionEntry({
176+origin: { provider: "openai" },
177+}),
178+);
179+const serialized = JSON.stringify(testStore);
180+const parseSpy = vi.spyOn(JSON, "parse");
181+182+writeSessionStoreCache({ storePath, store: testStore, serialized });
183+184+expect(parseSpy).not.toHaveBeenCalled();
185+186+testStore["session:1"].origin = { provider: "mutated" };
187+const cached = readSessionStoreCache({ storePath });
188+189+expect(cached?.["session:1"].origin?.provider).toBe("openai");
190+expect(parseSpy).toHaveBeenCalledTimes(1);
191+192+parseSpy.mockRestore();
193+});
194+195+it("clones disk-loaded stores from the raw serialized JSON", () => {
196+const testStore = createSingleSessionStore(
197+createSessionEntry({
198+origin: { provider: "openai" },
199+skillsSnapshot: {
200+prompt: "skills",
201+skills: [{ name: "alpha" }],
202+},
203+}),
204+);
205+const serialized = JSON.stringify(testStore);
206+fs.writeFileSync(storePath, serialized);
207+208+const stringifySpy = vi.spyOn(JSON, "stringify");
209+const loaded = loadSessionStore(storePath, { skipCache: true });
210+211+expect(loaded).toEqual(testStore);
212+expect(stringifySpy).not.toHaveBeenCalled();
213+214+loaded["session:1"].origin = { provider: "mutated" };
215+if (loaded["session:1"].skillsSnapshot?.skills?.length) {
216+loaded["session:1"].skillsSnapshot.skills[0].name = "mutated";
217+}
218+219+const reloaded = loadSessionStore(storePath, { skipCache: true });
220+expect(reloaded["session:1"].origin?.provider).toBe("openai");
221+expect(reloaded["session:1"].skillsSnapshot?.skills?.[0]?.name).toBe("alpha");
222+223+stringifySpy.mockRestore();
224+});
225+110226it("should refresh cache when store file changes on disk", async () => {
111227const testStore = createSingleSessionStore();
112228此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。