import { describe, expect, it } from "vite-plus/test";import * as Schema from "effect/Schema"; import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts";import { ClientSettingsSchema, ClientSettingsPatch, ClaudeSettings, DEFAULT_SERVER_SETTINGS, resolveProviderInstanceEnabled, ServerSettings, ServerSettingsPatch,} from "./settings.ts"; const decodeClientSettings = Schema.decodeUnknownSync(ClientSettingsSchema);const decodeClientSettingsPatch = Schema.decodeUnknownSync(ClientSettingsPatch);const encodeClientSettings = Schema.encodeSync(ClientSettingsSchema);const decodeServerSettings = Schema.decodeUnknownSync(ServerSettings);const decodeServerSettingsPatch = Schema.decodeUnknownSync(ServerSettingsPatch);const encodeServerSettings = Schema.encodeSync(ServerSettings);const decodeClaudeSettings = Schema.decodeUnknownSync(ClaudeSettings); describe("ServerSettings usage price overrides", () => { const prices = { inputCostPerMillionTokens: 2, outputCostPerMillionTokens: 8 }; it("defaults to automatic pricing and round-trips arbitrary model IDs", () => { expect(decodeServerSettings({}).usagePriceOverrides).toEqual({}); const settings = decodeServerSettings({ usagePriceOverrides: { " vendor/example-model ": prices }, }); expect(encodeServerSettings(settings).usagePriceOverrides).toEqual({ "vendor/example-model": prices, }); }); it("accepts zero rates, optional cache rates, and per-model deletion", () => { const overrides = { "example-model": { inputCostPerMillionTokens: 0, outputCostPerMillionTokens: 0, cacheReadCostPerMillionTokens: 0.5, cacheWriteCostPerMillionTokens: 3, }, "removed-model": null, }; expect( decodeServerSettingsPatch({ usagePriceOverrides: overrides }).usagePriceOverrides, ).toEqual(overrides); }); it.each([ "inputCostPerMillionTokens", "outputCostPerMillionTokens", "cacheReadCostPerMillionTokens", "cacheWriteCostPerMillionTokens", ])("rejects invalid %s rates at the settings boundary", (field) => { for (const value of [-1, Number.NaN, Number.POSITIVE_INFINITY, "2"]) { const usagePriceOverrides = { "example-model": { ...prices, [field]: value } }; expect(() => decodeServerSettings({ usagePriceOverrides })).toThrow(); expect(() => decodeServerSettingsPatch({ usagePriceOverrides })).toThrow(); } }); it("rejects empty model IDs and incomplete input/output pricing", () => { for (const usagePriceOverrides of [ { " ": prices }, { "example-model": { inputCostPerMillionTokens: 2 } }, { "example-model": { outputCostPerMillionTokens: 8 } }, ]) { expect(() => decodeServerSettingsPatch({ usagePriceOverrides })).toThrow(); } });}); describe("custom model settings", () => { const capabilities = { optionDescriptors: [ { id: "effort", label: "Reasoning", type: "select", options: [{ id: "high", label: "High", isDefault: true }], }, ], }; it("accepts legacy bare slugs alongside full entries", () => { const decoded = decodeClaudeSettings({ customModels: ["bare-slug", { slug: "named", name: "Named", capabilities }], }); expect(decoded.customModels).toEqual([ "bare-slug", { slug: "named", name: "Named", capabilities }, ]); }); it("accepts entries at the settings patch boundary", () => { expect( decodeServerSettingsPatch({ providers: { codex: { customModels: [{ slug: "x", capabilities }] } }, }).providers?.codex?.customModels, ).toEqual([{ slug: "x", capabilities }]); expect(() => decodeServerSettingsPatch({ providers: { codex: { customModels: [{ name: "no slug" }] } } }), ).toThrow(); });}); describe("ClaudeSettings auto-compaction", () => { it("uses Claude's default threshold when no override is configured", () => { expect(decodeClaudeSettings({}).autoCompactWindow).toBe(""); }); it.each(["100000", "300000", "1000000"])( "accepts a supported auto-compaction threshold: %s", (value) => { expect(decodeClaudeSettings({ autoCompactWindow: value }).autoCompactWindow).toBe(value); }, ); it.each(["99999", "1000001", "300k", "invalid"])( "rejects an unsupported auto-compaction threshold: %s", (value) => { expect(() => decodeClaudeSettings({ autoCompactWindow: value })).toThrow(); }, ); it("rejects an unsupported threshold at the settings patch boundary", () => { expect(() => decodeServerSettingsPatch({ providers: { claudeAgent: { autoCompactWindow: "300k" } } }), ).toThrow(); expect( decodeServerSettingsPatch({ providers: { claudeAgent: { autoCompactWindow: "300000" } } }), ).toBeDefined(); });}); describe("ClientSettings diff colors", () => { it("keeps red and green for existing settings without a saved palette", () => { expect(decodeClientSettings({}).diffColorScheme).toBe("red-green"); }); it.each(["red-green", "blue-orange"])("round-trips the %s palette", (diffColorScheme) => { const settings = decodeClientSettings({ diffColorScheme }); expect(encodeClientSettings(settings).diffColorScheme).toBe(diffColorScheme); expect(decodeClientSettingsPatch({ diffColorScheme }).diffColorScheme).toBe(diffColorScheme); }); it("rejects unsupported palettes", () => { expect(() => decodeClientSettings({ diffColorScheme: "purple-yellow" })).toThrow(); expect(() => decodeClientSettingsPatch({ diffColorScheme: "purple-yellow" })).toThrow(); });}); describe("ClientSettings load balancing", () => { it("requires opt-in when settings are new or omit load balancing", () => { expect(decodeClientSettings({}).loadBalancingEnabled).toBe(false); expect(decodeClientSettings({ loadBalancingWeights: {} }).loadBalancingEnabled).toBe(false); }); it.each([true, false])("preserves a saved choice of %s", (loadBalancingEnabled) => { const settings = decodeClientSettings({ loadBalancingEnabled }); expect(encodeClientSettings(settings).loadBalancingEnabled).toBe(loadBalancingEnabled); expect(decodeClientSettingsPatch({ loadBalancingEnabled }).loadBalancingEnabled).toBe( loadBalancingEnabled, ); });}); describe("ClientSettings word wrap", () => { it("defaults word wrap on", () => { expect(decodeClientSettings({}).wordWrap).toBe(true); }); it("ignores obsolete wrapping preferences", () => { const decoded = decodeClientSettings({ chatWordWrap: false, diffWordWrap: false, }); expect(decoded.wordWrap).toBe(true); expect(decoded).not.toHaveProperty("chatWordWrap"); expect(decoded).not.toHaveProperty("diffWordWrap"); });}); describe("ClientSettings window capture", () => { it("defaults capture off while keeping its feedback enabled", () => { const settings = decodeClientSettings({}); expect(settings.snapShotEnabled).toBe(false); expect(settings.snapShotIncludeAccessibility).toBe(true); expect(settings.snapShotShortcut).toEqual({ kind: "both-shift-keys" }); expect(settings.snapShotPlaySound).toBe(true); expect(settings.snapShotSound).toBe("soft-pop"); expect(settings.snapShotFlash).toBe(true); expect(settings.snapShotAnimations).toBe(true); }); it("accepts capture preference updates", () => { expect( decodeClientSettingsPatch({ snapShotEnabled: true, snapShotIncludeAccessibility: false, snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: true, altKey: true, modKey: false, }, snapShotPlaySound: false, snapShotSound: "camera-shutter", snapShotFlash: false, snapShotAnimations: false, }), ).toEqual({ snapShotEnabled: true, snapShotIncludeAccessibility: false, snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: true, altKey: true, modKey: false, }, snapShotPlaySound: false, snapShotSound: "camera-shutter", snapShotFlash: false, snapShotAnimations: false, }); }); it("rejects unknown capture sounds", () => { expect(() => decodeClientSettingsPatch({ snapShotSound: "doorbell" })).toThrow(); }); it("accepts modifier pair shortcuts", () => { expect( decodeClientSettingsPatch({ snapShotShortcut: { kind: "modifier-pair", modifier: "meta" }, }), ).toEqual({ snapShotShortcut: { kind: "modifier-pair", modifier: "meta" }, }); expect(() => decodeClientSettingsPatch({ snapShotShortcut: { kind: "modifier-pair", modifier: "hyper" }, }), ).toThrow(); }); it("rejects a capture shortcut with no modifier", () => { expect(() => decodeClientSettingsPatch({ snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: false, altKey: false, modKey: false, }, }), ).toThrow(); });}); describe("ClientSettings proactive panels", () => { it("is opt-in and accepts client-local updates", () => { expect(decodeClientSettings({}).proactivePanelsEnabled).toBe(false); expect(decodeClientSettingsPatch({ proactivePanelsEnabled: true }).proactivePanelsEnabled).toBe( true, ); });}); describe("ClientSettings quit confirmation", () => { it("defaults to hold", () => { expect(decodeClientSettings({}).confirmQuit).toBe("hold"); }); it.each(["direct", "hold", "double-click"] as const)("accepts the %s mode", (mode) => { expect(decodeClientSettings({ confirmQuit: mode }).confirmQuit).toBe(mode); expect(decodeClientSettingsPatch({ confirmQuit: mode }).confirmQuit).toBe(mode); }); it.each([ [true, "hold"], [false, "direct"], ] as const)("migrates the legacy %s value to %s", (legacyValue, mode) => { const settings = decodeClientSettings({ confirmQuit: legacyValue }); expect(settings.confirmQuit).toBe(mode); expect(encodeClientSettings(settings).confirmQuit).toBe(mode); }); it("rejects legacy booleans at the patch boundary", () => { expect(() => decodeClientSettingsPatch({ confirmQuit: true })).toThrow(); });}); describe("ClientSettings browser recording frame rate", () => { it("defaults to 30 fps", () => { expect(decodeClientSettings({}).browserRecordingFrameRate).toBe(30); }); it.each([30, 60])("accepts a supported frame rate: %s", (frameRate) => { expect( decodeClientSettings({ browserRecordingFrameRate: frameRate }).browserRecordingFrameRate, ).toBe(frameRate); expect( decodeClientSettingsPatch({ browserRecordingFrameRate: frameRate }).browserRecordingFrameRate, ).toBe(frameRate); }); it.each([24, 59, 120])("rejects an unsupported frame rate: %s", (frameRate) => { expect(() => decodeClientSettings({ browserRecordingFrameRate: frameRate })).toThrow(); expect(() => decodeClientSettingsPatch({ browserRecordingFrameRate: frameRate })).toThrow(); });}); describe("ClientSettings glass opacity", () => { it("defaults to a readable translucent surface", () => { expect(decodeClientSettings({}).glassOpacity).toBe(80); }); it.each([39, 101, 72.5])("rejects an invalid glass opacity: %s", (value) => { expect(() => decodeClientSettings({ glassOpacity: value })).toThrow(); expect(() => decodeClientSettingsPatch({ glassOpacity: value })).toThrow(); }); it.each([40, 75, 100])("accepts a glass opacity within the supported range: %s", (value) => { expect(decodeClientSettings({ glassOpacity: value }).glassOpacity).toBe(value); expect(decodeClientSettingsPatch({ glassOpacity: value }).glassOpacity).toBe(value); });}); describe("ClientSettings appearance contrast", () => { it("defaults to the theme's original contrast", () => { expect(decodeClientSettings({}).appearanceContrast).toBe(100); }); it.each([49, 201, 92.5])("rejects an invalid appearance contrast: %s", (value) => { expect(() => decodeClientSettings({ appearanceContrast: value })).toThrow(); expect(() => decodeClientSettingsPatch({ appearanceContrast: value })).toThrow(); }); it.each([50, 100, 150, 200])("accepts an appearance contrast in range: %s", (value) => { expect(decodeClientSettings({ appearanceContrast: value }).appearanceContrast).toBe(value); expect(decodeClientSettingsPatch({ appearanceContrast: value }).appearanceContrast).toBe(value); });}); describe("ClientSettings panel animations", () => { it("defaults to instant changes", () => { expect(decodeClientSettings({}).panelAnimationDurationMs).toBe(0); }); it.each([0, 400])("accepts a panel animation duration: %s", (value) => { expect(decodeClientSettingsPatch({ panelAnimationDurationMs: value })).toEqual({ panelAnimationDurationMs: value, }); }); it.each([-1, 401, 150.5])("rejects an invalid panel animation duration: %s", (value) => { expect(() => decodeClientSettingsPatch({ panelAnimationDurationMs: value })).toThrow(); });}); describe("ClientSettings environment identification", () => { it("defaults to artwork and accepts each presentation mode", () => { expect(decodeClientSettings({}).environmentIdentificationMode).toBe("artwork"); for (const mode of ["artwork", "pill", "none"] as const) { expect( decodeClientSettingsPatch({ environmentIdentificationMode: mode }) .environmentIdentificationMode, ).toBe(mode); } }); it("rejects unsupported presentation modes", () => { expect(() => decodeClientSettings({ environmentIdentificationMode: "badge" })).toThrow(); expect(() => decodeClientSettingsPatch({ environmentIdentificationMode: "badge" })).toThrow(); });}); describe("ClientSettings sidebar", () => { it("defaults to the current sidebar", () => { expect(decodeClientSettings({}).legacySidebarEnabled).toBe(false); }); it("drops the retired sidebar v2 beta keys, resetting everyone to the default", () => { const decoded = decodeClientSettings({ sidebarV2Enabled: false, sidebarV2ConfiguredByUser: true, }); expect(decoded.legacySidebarEnabled).toBe(false); expect(decoded).not.toHaveProperty("sidebarV2Enabled"); expect(decoded).not.toHaveProperty("sidebarV2ConfiguredByUser"); }); it("preserves an explicit legacy sidebar opt-in", () => { expect(decodeClientSettings({ legacySidebarEnabled: true }).legacySidebarEnabled).toBe(true); expect(decodeClientSettingsPatch({ legacySidebarEnabled: true }).legacySidebarEnabled).toBe( true, ); }); it("keeps unpin confirmation opt-in and patchable", () => { expect(decodeClientSettings({}).confirmThreadUnpin).toBe(false); expect(decodeClientSettingsPatch({ confirmThreadUnpin: true }).confirmThreadUnpin).toBe(true); expect(() => decodeClientSettingsPatch({ confirmThreadUnpin: "yes" })).toThrow(); });}); describe("ClientSettings context window meter", () => { it("defaults off and preserves an explicit legacy opt-in", () => { expect(decodeClientSettings({}).contextWindowMeterEnabled).toBe(false); expect( decodeClientSettings({ contextWindowMeterEnabled: true }).contextWindowMeterEnabled, ).toBe(true); expect( decodeClientSettingsPatch({ contextWindowMeterEnabled: true }).contextWindowMeterEnabled, ).toBe(true); });}); describe("ClientSettings composer collapse", () => { it("collapses on scroll by default and accepts opting out", () => { expect(decodeClientSettings({}).composerCollapseOnScroll).toBe(true); expect( decodeClientSettingsPatch({ composerCollapseOnScroll: false }).composerCollapseOnScroll, ).toBe(false); }); it("drops the retired blur trigger key", () => { const decoded = decodeClientSettings({ composerCollapseOnBlur: false }); expect(decoded.composerCollapseOnScroll).toBe(true); expect(decoded).not.toHaveProperty("composerCollapseOnBlur"); });}); describe("ServerSettings thread settlement", () => { it("defaults merge settlement on and inactivity settlement to three days", () => { const settings = decodeServerSettings({}); expect(settings.sidebarAutoSettleAfterDays).toBe(3); expect(settings.sidebarAutoSettleOnMerge).toBe(true); }); it("allows both automatic rules to be disabled", () => { expect( decodeServerSettings({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false, }), ).toMatchObject({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false }); expect( decodeServerSettingsPatch({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false, }), ).toMatchObject({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false }); }); it.each([-1, 0, 91])("rejects an auto-settle threshold outside 1..90: %s", (value) => { expect(() => decodeServerSettings({ sidebarAutoSettleAfterDays: value })).toThrow(); expect(() => decodeServerSettingsPatch({ sidebarAutoSettleAfterDays: value })).toThrow(); });}); describe("ClientSettings pull request merge methods", () => { it("defaults to no project overrides and accepts supported methods", () => { expect(decodeClientSettings({}).pullRequestMergeMethodOverrides).toEqual({}); expect( decodeClientSettingsPatch({ pullRequestMergeMethodOverrides: { project: "squash" }, }).pullRequestMergeMethodOverrides, ).toEqual({ project: "squash" }); }); it("rejects unsupported project merge methods", () => { expect(() => decodeClientSettingsPatch({ pullRequestMergeMethodOverrides: { project: "fast-forward" }, }), ).toThrow(); });}); describe("ServerSettings.providerInstances (slice-2 invariant)", () => { it("defaults text generation to Luna at low reasoning effort", () => { expect(DEFAULT_SERVER_SETTINGS.textGenerationModelSelection).toEqual({ instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.6-luna", options: [{ id: "reasoningEffort", value: "low" }], });Lines 1–500 of 774. Load more
import { describe, expect, it } from "vite-plus/test"; import * as Schema from "effect/Schema"; import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts"; import { ClientSettingsSchema, ClientSettingsPatch, ClaudeSettings, DEFAULT_SERVER_SETTINGS, resolveProviderInstanceEnabled, ServerSettings, ServerSettingsPatch, } from "./settings.ts"; const decodeClientSettings = Schema.decodeUnknownSync(ClientSettingsSchema); const decodeClientSettingsPatch = Schema.decodeUnknownSync(ClientSettingsPatch); const encodeClientSettings = Schema.encodeSync(ClientSettingsSchema); const decodeServerSettings = Schema.decodeUnknownSync(ServerSettings); const decodeServerSettingsPatch = Schema.decodeUnknownSync(ServerSettingsPatch); const encodeServerSettings = Schema.encodeSync(ServerSettings); const decodeClaudeSettings = Schema.decodeUnknownSync(ClaudeSettings); describe("ServerSettings usage price overrides", () => { const prices = { inputCostPerMillionTokens: 2, outputCostPerMillionTokens: 8 }; it("defaults to automatic pricing and round-trips arbitrary model IDs", () => { expect(decodeServerSettings({}).usagePriceOverrides).toEqual({}); const settings = decodeServerSettings({ usagePriceOverrides: { " vendor/example-model ": prices }, }); expect(encodeServerSettings(settings).usagePriceOverrides).toEqual({ "vendor/example-model": prices, }); }); it("accepts zero rates, optional cache rates, and per-model deletion", () => { const overrides = { "example-model": { inputCostPerMillionTokens: 0, outputCostPerMillionTokens: 0, cacheReadCostPerMillionTokens: 0.5, cacheWriteCostPerMillionTokens: 3, }, "removed-model": null, }; expect( decodeServerSettingsPatch({ usagePriceOverrides: overrides }).usagePriceOverrides, ).toEqual(overrides); }); it.each([ "inputCostPerMillionTokens", "outputCostPerMillionTokens", "cacheReadCostPerMillionTokens", "cacheWriteCostPerMillionTokens", ])("rejects invalid %s rates at the settings boundary", (field) => { for (const value of [-1, Number.NaN, Number.POSITIVE_INFINITY, "2"]) { const usagePriceOverrides = { "example-model": { ...prices, [field]: value } }; expect(() => decodeServerSettings({ usagePriceOverrides })).toThrow(); expect(() => decodeServerSettingsPatch({ usagePriceOverrides })).toThrow(); } }); it("rejects empty model IDs and incomplete input/output pricing", () => { for (const usagePriceOverrides of [ { " ": prices }, { "example-model": { inputCostPerMillionTokens: 2 } }, { "example-model": { outputCostPerMillionTokens: 8 } }, ]) { expect(() => decodeServerSettingsPatch({ usagePriceOverrides })).toThrow(); } }); }); describe("custom model settings", () => { const capabilities = { optionDescriptors: [ { id: "effort", label: "Reasoning", type: "select", options: [{ id: "high", label: "High", isDefault: true }], }, ], }; it("accepts legacy bare slugs alongside full entries", () => { const decoded = decodeClaudeSettings({ customModels: ["bare-slug", { slug: "named", name: "Named", capabilities }], }); expect(decoded.customModels).toEqual([ "bare-slug", { slug: "named", name: "Named", capabilities }, ]); }); it("accepts entries at the settings patch boundary", () => { expect( decodeServerSettingsPatch({ providers: { codex: { customModels: [{ slug: "x", capabilities }] } }, }).providers?.codex?.customModels, ).toEqual([{ slug: "x", capabilities }]); expect(() => decodeServerSettingsPatch({ providers: { codex: { customModels: [{ name: "no slug" }] } } }), ).toThrow(); }); }); describe("ClaudeSettings auto-compaction", () => { it("uses Claude's default threshold when no override is configured", () => { expect(decodeClaudeSettings({}).autoCompactWindow).toBe(""); }); it.each(["100000", "300000", "1000000"])( "accepts a supported auto-compaction threshold: %s", (value) => { expect(decodeClaudeSettings({ autoCompactWindow: value }).autoCompactWindow).toBe(value); }, ); it.each(["99999", "1000001", "300k", "invalid"])( "rejects an unsupported auto-compaction threshold: %s", (value) => { expect(() => decodeClaudeSettings({ autoCompactWindow: value })).toThrow(); }, ); it("rejects an unsupported threshold at the settings patch boundary", () => { expect(() => decodeServerSettingsPatch({ providers: { claudeAgent: { autoCompactWindow: "300k" } } }), ).toThrow(); expect( decodeServerSettingsPatch({ providers: { claudeAgent: { autoCompactWindow: "300000" } } }), ).toBeDefined(); }); }); describe("ClientSettings diff colors", () => { it("keeps red and green for existing settings without a saved palette", () => { expect(decodeClientSettings({}).diffColorScheme).toBe("red-green"); }); it.each(["red-green", "blue-orange"])("round-trips the %s palette", (diffColorScheme) => { const settings = decodeClientSettings({ diffColorScheme }); expect(encodeClientSettings(settings).diffColorScheme).toBe(diffColorScheme); expect(decodeClientSettingsPatch({ diffColorScheme }).diffColorScheme).toBe(diffColorScheme); }); it("rejects unsupported palettes", () => { expect(() => decodeClientSettings({ diffColorScheme: "purple-yellow" })).toThrow(); expect(() => decodeClientSettingsPatch({ diffColorScheme: "purple-yellow" })).toThrow(); }); }); describe("ClientSettings load balancing", () => { it("requires opt-in when settings are new or omit load balancing", () => { expect(decodeClientSettings({}).loadBalancingEnabled).toBe(false); expect(decodeClientSettings({ loadBalancingWeights: {} }).loadBalancingEnabled).toBe(false); }); it.each([true, false])("preserves a saved choice of %s", (loadBalancingEnabled) => { const settings = decodeClientSettings({ loadBalancingEnabled }); expect(encodeClientSettings(settings).loadBalancingEnabled).toBe(loadBalancingEnabled); expect(decodeClientSettingsPatch({ loadBalancingEnabled }).loadBalancingEnabled).toBe( loadBalancingEnabled, ); }); }); describe("ClientSettings word wrap", () => { it("defaults word wrap on", () => { expect(decodeClientSettings({}).wordWrap).toBe(true); }); it("ignores obsolete wrapping preferences", () => { const decoded = decodeClientSettings({ chatWordWrap: false, diffWordWrap: false, }); expect(decoded.wordWrap).toBe(true); expect(decoded).not.toHaveProperty("chatWordWrap"); expect(decoded).not.toHaveProperty("diffWordWrap"); }); }); describe("ClientSettings window capture", () => { it("defaults capture off while keeping its feedback enabled", () => { const settings = decodeClientSettings({}); expect(settings.snapShotEnabled).toBe(false); expect(settings.snapShotIncludeAccessibility).toBe(true); expect(settings.snapShotShortcut).toEqual({ kind: "both-shift-keys" }); expect(settings.snapShotPlaySound).toBe(true); expect(settings.snapShotSound).toBe("soft-pop"); expect(settings.snapShotFlash).toBe(true); expect(settings.snapShotAnimations).toBe(true); }); it("accepts capture preference updates", () => { expect( decodeClientSettingsPatch({ snapShotEnabled: true, snapShotIncludeAccessibility: false, snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: true, altKey: true, modKey: false, }, snapShotPlaySound: false, snapShotSound: "camera-shutter", snapShotFlash: false, snapShotAnimations: false, }), ).toEqual({ snapShotEnabled: true, snapShotIncludeAccessibility: false, snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: true, altKey: true, modKey: false, }, snapShotPlaySound: false, snapShotSound: "camera-shutter", snapShotFlash: false, snapShotAnimations: false, }); }); it("rejects unknown capture sounds", () => { expect(() => decodeClientSettingsPatch({ snapShotSound: "doorbell" })).toThrow(); }); it("accepts modifier pair shortcuts", () => { expect( decodeClientSettingsPatch({ snapShotShortcut: { kind: "modifier-pair", modifier: "meta" }, }), ).toEqual({ snapShotShortcut: { kind: "modifier-pair", modifier: "meta" }, }); expect(() => decodeClientSettingsPatch({ snapShotShortcut: { kind: "modifier-pair", modifier: "hyper" }, }), ).toThrow(); }); it("rejects a capture shortcut with no modifier", () => { expect(() => decodeClientSettingsPatch({ snapShotShortcut: { key: "w", metaKey: false, ctrlKey: false, shiftKey: false, altKey: false, modKey: false, }, }), ).toThrow(); }); }); describe("ClientSettings proactive panels", () => { it("is opt-in and accepts client-local updates", () => { expect(decodeClientSettings({}).proactivePanelsEnabled).toBe(false); expect(decodeClientSettingsPatch({ proactivePanelsEnabled: true }).proactivePanelsEnabled).toBe( true, ); }); }); describe("ClientSettings quit confirmation", () => { it("defaults to hold", () => { expect(decodeClientSettings({}).confirmQuit).toBe("hold"); }); it.each(["direct", "hold", "double-click"] as const)("accepts the %s mode", (mode) => { expect(decodeClientSettings({ confirmQuit: mode }).confirmQuit).toBe(mode); expect(decodeClientSettingsPatch({ confirmQuit: mode }).confirmQuit).toBe(mode); }); it.each([ [true, "hold"], [false, "direct"], ] as const)("migrates the legacy %s value to %s", (legacyValue, mode) => { const settings = decodeClientSettings({ confirmQuit: legacyValue }); expect(settings.confirmQuit).toBe(mode); expect(encodeClientSettings(settings).confirmQuit).toBe(mode); }); it("rejects legacy booleans at the patch boundary", () => { expect(() => decodeClientSettingsPatch({ confirmQuit: true })).toThrow(); }); }); describe("ClientSettings browser recording frame rate", () => { it("defaults to 30 fps", () => { expect(decodeClientSettings({}).browserRecordingFrameRate).toBe(30); }); it.each([30, 60])("accepts a supported frame rate: %s", (frameRate) => { expect( decodeClientSettings({ browserRecordingFrameRate: frameRate }).browserRecordingFrameRate, ).toBe(frameRate); expect( decodeClientSettingsPatch({ browserRecordingFrameRate: frameRate }).browserRecordingFrameRate, ).toBe(frameRate); }); it.each([24, 59, 120])("rejects an unsupported frame rate: %s", (frameRate) => { expect(() => decodeClientSettings({ browserRecordingFrameRate: frameRate })).toThrow(); expect(() => decodeClientSettingsPatch({ browserRecordingFrameRate: frameRate })).toThrow(); }); }); describe("ClientSettings glass opacity", () => { it("defaults to a readable translucent surface", () => { expect(decodeClientSettings({}).glassOpacity).toBe(80); }); it.each([39, 101, 72.5])("rejects an invalid glass opacity: %s", (value) => { expect(() => decodeClientSettings({ glassOpacity: value })).toThrow(); expect(() => decodeClientSettingsPatch({ glassOpacity: value })).toThrow(); }); it.each([40, 75, 100])("accepts a glass opacity within the supported range: %s", (value) => { expect(decodeClientSettings({ glassOpacity: value }).glassOpacity).toBe(value); expect(decodeClientSettingsPatch({ glassOpacity: value }).glassOpacity).toBe(value); }); }); describe("ClientSettings appearance contrast", () => { it("defaults to the theme's original contrast", () => { expect(decodeClientSettings({}).appearanceContrast).toBe(100); }); it.each([49, 201, 92.5])("rejects an invalid appearance contrast: %s", (value) => { expect(() => decodeClientSettings({ appearanceContrast: value })).toThrow(); expect(() => decodeClientSettingsPatch({ appearanceContrast: value })).toThrow(); }); it.each([50, 100, 150, 200])("accepts an appearance contrast in range: %s", (value) => { expect(decodeClientSettings({ appearanceContrast: value }).appearanceContrast).toBe(value); expect(decodeClientSettingsPatch({ appearanceContrast: value }).appearanceContrast).toBe(value); }); }); describe("ClientSettings panel animations", () => { it("defaults to instant changes", () => { expect(decodeClientSettings({}).panelAnimationDurationMs).toBe(0); }); it.each([0, 400])("accepts a panel animation duration: %s", (value) => { expect(decodeClientSettingsPatch({ panelAnimationDurationMs: value })).toEqual({ panelAnimationDurationMs: value, }); }); it.each([-1, 401, 150.5])("rejects an invalid panel animation duration: %s", (value) => { expect(() => decodeClientSettingsPatch({ panelAnimationDurationMs: value })).toThrow(); }); }); describe("ClientSettings environment identification", () => { it("defaults to artwork and accepts each presentation mode", () => { expect(decodeClientSettings({}).environmentIdentificationMode).toBe("artwork"); for (const mode of ["artwork", "pill", "none"] as const) { expect( decodeClientSettingsPatch({ environmentIdentificationMode: mode }) .environmentIdentificationMode, ).toBe(mode); } }); it("rejects unsupported presentation modes", () => { expect(() => decodeClientSettings({ environmentIdentificationMode: "badge" })).toThrow(); expect(() => decodeClientSettingsPatch({ environmentIdentificationMode: "badge" })).toThrow(); }); }); describe("ClientSettings sidebar", () => { it("defaults to the current sidebar", () => { expect(decodeClientSettings({}).legacySidebarEnabled).toBe(false); }); it("drops the retired sidebar v2 beta keys, resetting everyone to the default", () => { const decoded = decodeClientSettings({ sidebarV2Enabled: false, sidebarV2ConfiguredByUser: true, }); expect(decoded.legacySidebarEnabled).toBe(false); expect(decoded).not.toHaveProperty("sidebarV2Enabled"); expect(decoded).not.toHaveProperty("sidebarV2ConfiguredByUser"); }); it("preserves an explicit legacy sidebar opt-in", () => { expect(decodeClientSettings({ legacySidebarEnabled: true }).legacySidebarEnabled).toBe(true); expect(decodeClientSettingsPatch({ legacySidebarEnabled: true }).legacySidebarEnabled).toBe( true, ); }); it("keeps unpin confirmation opt-in and patchable", () => { expect(decodeClientSettings({}).confirmThreadUnpin).toBe(false); expect(decodeClientSettingsPatch({ confirmThreadUnpin: true }).confirmThreadUnpin).toBe(true); expect(() => decodeClientSettingsPatch({ confirmThreadUnpin: "yes" })).toThrow(); }); }); describe("ClientSettings context window meter", () => { it("defaults off and preserves an explicit legacy opt-in", () => { expect(decodeClientSettings({}).contextWindowMeterEnabled).toBe(false); expect( decodeClientSettings({ contextWindowMeterEnabled: true }).contextWindowMeterEnabled, ).toBe(true); expect( decodeClientSettingsPatch({ contextWindowMeterEnabled: true }).contextWindowMeterEnabled, ).toBe(true); }); }); describe("ClientSettings composer collapse", () => { it("collapses on scroll by default and accepts opting out", () => { expect(decodeClientSettings({}).composerCollapseOnScroll).toBe(true); expect( decodeClientSettingsPatch({ composerCollapseOnScroll: false }).composerCollapseOnScroll, ).toBe(false); }); it("drops the retired blur trigger key", () => { const decoded = decodeClientSettings({ composerCollapseOnBlur: false }); expect(decoded.composerCollapseOnScroll).toBe(true); expect(decoded).not.toHaveProperty("composerCollapseOnBlur"); }); }); describe("ServerSettings thread settlement", () => { it("defaults merge settlement on and inactivity settlement to three days", () => { const settings = decodeServerSettings({}); expect(settings.sidebarAutoSettleAfterDays).toBe(3); expect(settings.sidebarAutoSettleOnMerge).toBe(true); }); it("allows both automatic rules to be disabled", () => { expect( decodeServerSettings({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false, }), ).toMatchObject({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false }); expect( decodeServerSettingsPatch({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false, }), ).toMatchObject({ sidebarAutoSettleAfterDays: null, sidebarAutoSettleOnMerge: false }); }); it.each([-1, 0, 91])("rejects an auto-settle threshold outside 1..90: %s", (value) => { expect(() => decodeServerSettings({ sidebarAutoSettleAfterDays: value })).toThrow(); expect(() => decodeServerSettingsPatch({ sidebarAutoSettleAfterDays: value })).toThrow(); }); }); describe("ClientSettings pull request merge methods", () => { it("defaults to no project overrides and accepts supported methods", () => { expect(decodeClientSettings({}).pullRequestMergeMethodOverrides).toEqual({}); expect( decodeClientSettingsPatch({ pullRequestMergeMethodOverrides: { project: "squash" }, }).pullRequestMergeMethodOverrides, ).toEqual({ project: "squash" }); }); it("rejects unsupported project merge methods", () => { expect(() => decodeClientSettingsPatch({ pullRequestMergeMethodOverrides: { project: "fast-forward" }, }), ).toThrow(); }); }); describe("ServerSettings.providerInstances (slice-2 invariant)", () => { it("defaults text generation to Luna at low reasoning effort", () => { expect(DEFAULT_SERVER_SETTINGS.textGenerationModelSelection).toEqual({ instanceId: ProviderInstanceId.make("codex"), model: "gpt-5.6-luna", options: [{ id: "reasoningEffort", value: "low" }], });