feat: pin sessions to workspace revisions

This commit is contained in:
2026-08-04 05:05:20 +02:00
parent 90894176b6
commit 301db4bd85
14 changed files with 288 additions and 54 deletions
@@ -0,0 +1,15 @@
import { expect, test } from "vitest";
import { workspacePreferences } from "./preferences";
test("migrates legacy selections once and keeps later browser choices", () => {
localStorage.clear();
expect(workspacePreferences.migrate({
workspaceId: "psd-clinical", provider: "zai", model: "glm-5.2", thinking: "medium",
})).toMatchObject({ workspaceId: "psd-clinical", model: "glm-5.2" });
workspacePreferences.save({ workspaceId: "research", provider: "deepseek", model: "deepseek-v4-pro", thinking: "high" });
expect(workspacePreferences.migrate({ workspaceId: "legacy" })).toMatchObject({
workspaceId: "research", provider: "deepseek", model: "deepseek-v4-pro", thinking: "high",
});
});
+40
View File
@@ -0,0 +1,40 @@
export interface WorkspacePreference {
workspaceId?: string;
provider?: string;
model?: string;
thinking?: string;
}
const STORAGE_KEY = "thothii.workspace-registry.v1.preferences";
function storage(): Storage | undefined {
try { return window.localStorage; } catch { return undefined; }
}
function parse(raw: string | null): WorkspacePreference | undefined {
if (raw === null) return undefined;
try {
const value = JSON.parse(raw);
return value && typeof value === "object" && !Array.isArray(value) ? value as WorkspacePreference : undefined;
} catch {
return undefined;
}
}
/** Anonymous, non-secret browser choices for the workspace session composer. */
export const workspacePreferences = {
load(): WorkspacePreference {
return parse(storage()?.getItem(STORAGE_KEY) ?? null) ?? {};
},
save(value: WorkspacePreference): WorkspacePreference {
try { storage()?.setItem(STORAGE_KEY, JSON.stringify(value)); } catch { /* storage is optional */ }
return value;
},
/** Copy the pre-local-storage server values only when this browser has no saved choice. */
migrate(legacy: WorkspacePreference): WorkspacePreference {
const current = storage()?.getItem(STORAGE_KEY);
return current === null || current === undefined ? this.save(legacy) : this.load();
},
};