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" }], }); }); it("defaults to an empty record so legacy configs without the key still decode", () => { expect(DEFAULT_SERVER_SETTINGS.providerInstances).toEqual({}); }); it("decodes a fully empty config (legacy on-disk shape) without complaint", () => { const decoded = decodeServerSettings({}); expect(decoded.providerInstances).toEqual({}); // Legacy `providers` struct is still hydrated with its per-driver defaults // so existing call sites keep working through the migration. expect(decoded.providers.codex.enabled).toBe(true); }); it("decodes a multi-instance map mixing first-party and fork drivers", () => { const decoded = decodeServerSettings({ providerInstances: { codex_personal: { driver: "codex", displayName: "Codex (personal)", config: { homePath: "~/.codex_personal" }, }, codex_work: { driver: "codex", config: { homePath: "~/.codex_work" }, }, ollama_local: { driver: "ollama", displayName: "Ollama (local)", config: { endpoint: "http://localhost:11434" }, }, }, }); const personalId = ProviderInstanceId.make("codex_personal"); const workId = ProviderInstanceId.make("codex_work"); const ollamaId = ProviderInstanceId.make("ollama_local"); expect(decoded.providerInstances[personalId]?.driver).toBe("codex"); expect(decoded.providerInstances[workId]?.config).toEqual({ homePath: "~/.codex_work" }); // Critical: a config naming a driver this build does not know about // (`ollama` is not in `ProviderDriverKind`) must round-trip without loss. // The runtime handles "driver not installed" — the schema must not. expect(decoded.providerInstances[ollamaId]?.driver).toBe("ollama"); expect(decoded.providerInstances[ollamaId]?.config).toEqual({ endpoint: "http://localhost:11434", }); }); it("rejects instance keys that violate the slug pattern", () => { expect(() => decodeServerSettings({ providerInstances: { "1bad": { driver: "codex" } }, }), ).toThrow(); }); }); describe("provider enabled defaults", () => { it("enables only the stable bindings by default", () => { const decoded = decodeServerSettings({}); expect(decoded.providers.codex.enabled).toBe(true); expect(decoded.providers.claudeAgent.enabled).toBe(true); expect(decoded.providers.cursor.enabled).toBe(false); expect(decoded.providers.grok.enabled).toBe(false); expect(decoded.providers.opencode.enabled).toBe(false); }); it("keeps Cursor enabled when an existing user explicitly opted in", () => { const cursor = ProviderDriverKind.make("cursor"); const cursorId = ProviderInstanceId.make("cursor"); const decoded = decodeServerSettings({ providers: { cursor: { enabled: true } }, providerInstances: { [cursorId]: { driver: cursor, enabled: true, config: {} }, }, }); expect(decoded.providers.cursor.enabled).toBe(true); expect(resolveProviderInstanceEnabled(decoded.providerInstances[cursorId]!)).toBe(true); }); it("resolves instance enabled state with explicit false winning", () => { const grok = ProviderDriverKind.make("grok"); const codex = ProviderDriverKind.make("codex"); // No flags anywhere: driver default applies. expect(resolveProviderInstanceEnabled({ driver: grok, config: {} })).toBe(false); expect(resolveProviderInstanceEnabled({ driver: codex, config: {} })).toBe(true); // Unknown fork drivers stay enabled. expect( resolveProviderInstanceEnabled({ driver: ProviderDriverKind.make("ollama"), config: {} }), ).toBe(true); // Envelope flag wins over the driver default. expect(resolveProviderInstanceEnabled({ driver: grok, enabled: true, config: {} })).toBe(true); expect(resolveProviderInstanceEnabled({ driver: codex, enabled: false, config: {} })).toBe( false, ); // Legacy in-config flag fills in when the envelope is silent. expect(resolveProviderInstanceEnabled({ driver: grok, config: { enabled: true } })).toBe(true); // Conflicting flags: the explicit false wins, whichever side it is on. expect( resolveProviderInstanceEnabled({ driver: grok, enabled: true, config: { enabled: false } }), ).toBe(false); expect( resolveProviderInstanceEnabled({ driver: codex, enabled: false, config: { enabled: true } }), ).toBe(false); }); }); describe("ServerSettings worktree defaults", () => { it("defaults start-from-origin on for legacy configs", () => { expect(decodeServerSettings({}).newWorktreesStartFromOrigin).toBe(true); }); it("accepts start-from-origin updates", () => { expect( decodeServerSettingsPatch({ newWorktreesStartFromOrigin: false }).newWorktreesStartFromOrigin, ).toBe(false); }); }); describe("ServerSettings.sourceControlWritingStyle", () => { it("defaults all style settings for legacy configs", () => { const settings = decodeServerSettings({}); expect(settings.sourceControlWritingStyle).toEqual({ mode: "repo_conventions", customInstructions: "", followChangeRequestTemplates: true, }); expect(settings.sourceControlWriterModelSelection).toBeNull(); }); it("trims partial style updates", () => { const patch = decodeServerSettingsPatch({ sourceControlWritingStyle: { mode: "custom", customInstructions: " Prefer concise wording. ", }, }); expect(patch.sourceControlWritingStyle).toEqual({ mode: "custom", customInstructions: "Prefer concise wording.", }); }); }); describe("ServerSettingsPatch.providerInstances", () => { it("treats providerInstances as an optional whole-map replacement", () => { const patch = decodeServerSettingsPatch({}); expect(patch.providerInstances).toBeUndefined(); const replacement = decodeServerSettingsPatch({ providerInstances: { codex_personal: { driver: "codex", config: { homePath: "~/.codex" } }, }, }); expect(replacement.providerInstances).toBeDefined(); expect(replacement.providerInstances?.[ProviderInstanceId.make("codex_personal")]?.driver).toBe( "codex", ); }); it("preserves a fork-defined driver entry through patch decoding", () => { const patch = decodeServerSettingsPatch({ providerInstances: { ollama_local: { driver: "ollama", config: { endpoint: "http://localhost:11434" }, }, }, }); const ollamaId = ProviderInstanceId.make("ollama_local"); expect(patch.providerInstances?.[ollamaId]?.driver).toBe("ollama"); }); }); describe("ServerSettingsPatch string normalization", () => { it("trims string settings while decoding patches", () => { const patch = decodeServerSettingsPatch({ addProjectBaseDirectory: " ~/Development ", textGenerationModelSelection: { model: " gpt-5.4-mini " }, observability: { otlpTracesUrl: " http://localhost:4318/v1/traces ", }, providers: { codex: { binaryPath: " /opt/homebrew/bin/codex ", homePath: " ~/.codex ", launchArgs: " --strict-config --enable foo ", }, }, providerInstances: { codex_personal: { driver: " codex ", displayName: " Codex Personal ", config: { homePath: " ~/.codex-personal " }, }, }, }); expect(patch.addProjectBaseDirectory).toBe("~/Development"); expect(patch.textGenerationModelSelection?.model).toBe("gpt-5.4-mini"); expect(patch.observability?.otlpTracesUrl).toBe("http://localhost:4318/v1/traces"); expect(patch.providers?.codex?.binaryPath).toBe("/opt/homebrew/bin/codex"); expect(patch.providers?.codex?.homePath).toBe("~/.codex"); expect(patch.providers?.codex?.launchArgs).toBe("--strict-config --enable foo"); expect(patch.providerInstances?.[ProviderInstanceId.make("codex_personal")]?.driver).toBe( "codex", ); expect(patch.providerInstances?.[ProviderInstanceId.make("codex_personal")]?.displayName).toBe( "Codex Personal", ); expect(patch.providerInstances?.[ProviderInstanceId.make("codex_personal")]?.config).toEqual({ homePath: " ~/.codex-personal ", }); }); it("trims encoded server settings values before validation", () => { const defaultSettings = decodeServerSettings({}); const encoded = encodeServerSettings({ ...defaultSettings, addProjectBaseDirectory: " ~/Development ", providers: { ...defaultSettings.providers, codex: { ...defaultSettings.providers.codex, binaryPath: " /opt/homebrew/bin/codex ", launchArgs: " --strict-config ", }, }, }); expect(encoded.addProjectBaseDirectory).toBe("~/Development"); expect(encoded.providers?.codex?.binaryPath).toBe("/opt/homebrew/bin/codex"); expect(encoded.providers?.codex?.launchArgs).toBe("--strict-config"); }); }); describe("ServerSettings environment icon", () => { it("defaults to null", () => { expect(decodeServerSettings({}).environmentIcon).toBeNull(); }); it("keeps a kind this build knows", () => { expect(decodeServerSettings({ environmentIcon: "mac-mini" }).environmentIcon).toBe("mac-mini"); expect(decodeServerSettings({ environmentIcon: "linux" }).environmentIcon).toBe("linux"); }); it("decodes a kind from a newer server as null instead of failing the snapshot", () => { expect(decodeServerSettings({ environmentIcon: "toaster" }).environmentIcon).toBeNull(); }); it("round-trips through encode", () => { const settings = decodeServerSettings({ environmentIcon: "laptop" }); expect(encodeServerSettings(settings).environmentIcon).toBe("laptop"); const linuxSettings = decodeServerSettings({ environmentIcon: "linux" }); expect(encodeServerSettings(linuxSettings).environmentIcon).toBe("linux"); }); }); const decodeDeviceHostSettings = Schema.decodeSync(ServerSettings); it("validates remote device hosts and rejects ambiguous host ids", () => { const host = { id: "mini", label: "Mac mini", target: "user@mini", port: 2222 }; expect(decodeDeviceHostSettings({ deviceHosts: [host] }).deviceHosts).toEqual([host]); expect(() => decodeDeviceHostSettings({ deviceHosts: [host, host] })).toThrow(); expect(() => decodeDeviceHostSettings({ deviceHosts: [{ ...host, id: "local" }] })).toThrow(); expect(() => decodeDeviceHostSettings({ deviceHosts: [{ ...host, target: "-oProxyCommand=bad" }] }), ).toThrow(); expect(() => decodeDeviceHostSettings({ deviceHosts: [{ ...host, port: 0 }] })).toThrow(); });