import { describe, expect, test } from "bun:test" import type { AgentListOutput, ModelDefaultOutput, ModelListOutput, ProviderListOutput, } from "@opencode-ai/client/promise" import { directoryKey, normalizeAgentList, normalizePermissionRequest, normalizeProviderList } from "./utils" describe("normalizeAgentList", () => { test("adapts current agents to the app agent shape", () => { const result = normalizeAgentList([ { id: "build", name: "Build", mode: "primary", hidden: false, color: "primary", model: { id: "gpt-5", providerID: "openai", variant: "high" }, request: { settings: { temperature: 0.2, topP: 0.9 }, headers: {}, body: {} }, system: "Build software", permissions: [{ action: "read", resource: "*", effect: "allow" }], }, ] as AgentListOutput["data"]) expect(result).toEqual([ { name: "build", description: undefined, mode: "primary", hidden: false, temperature: 0.2, topP: 0.9, color: "primary", permission: [{ permission: "read", pattern: "*", action: "allow" }], model: { providerID: "openai", modelID: "gpt-5" }, variant: "high", prompt: "Build software", options: { temperature: 0.2, topP: 0.9 }, steps: undefined, }, ]) }) }) describe("normalizePermissionRequest", () => { test("adapts the current permission request to app state", () => { expect( normalizePermissionRequest({ id: "permission-1", sessionID: "session-1", action: "read", resources: ["README.md"], save: ["*.md"], metadata: { path: "README.md" }, source: { type: "tool", messageID: "message-1", callID: "call-1" }, }), ).toEqual({ id: "permission-1", sessionID: "session-1", permission: "read", patterns: ["README.md"], always: ["*.md"], metadata: { path: "README.md" }, tool: { messageID: "message-1", callID: "call-1" }, }) }) }) describe("normalizeProviderList", () => { test("groups current models into the app provider catalog", () => { const result = normalizeProviderList( [{ id: "openai", name: "OpenAI", package: "@ai-sdk/openai" }] as ProviderListOutput["data"], [ { id: "gpt-5", modelID: "gpt-5", providerID: "openai", name: "GPT-5", capabilities: { tools: true, input: ["text", "image"], output: ["text"] }, variants: [{ id: "high" }], time: { released: 1 }, cost: [{ input: 1, output: 2, cache: { read: 0.1, write: 0.2 } }], status: "active", enabled: true, limit: { context: 128_000, output: 8_192 }, }, { id: "gpt-old", modelID: "gpt-old", providerID: "openai", name: "GPT Old", capabilities: { tools: false, input: ["text"], output: ["text"] }, variants: [], time: { released: 0 }, cost: [], status: "deprecated", enabled: true, limit: { context: 1, output: 1 }, }, ] as ModelListOutput["data"], { id: "gpt-5", providerID: "openai" } as ModelDefaultOutput["data"], ) expect(result.connected).toEqual(["openai"]) expect(result.defaultModel).toEqual({ providerID: "openai", modelID: "gpt-5" }) expect(result.default).toEqual({ openai: "gpt-5" }) expect(result.all.get("openai")?.models["gpt-old"]).toBeUndefined() expect(result.all.get("openai")?.models["gpt-5"]).toMatchObject({ id: "gpt-5", providerID: "openai", capabilities: { toolcall: true, attachment: true }, cost: { input: 1, output: 2 }, variants: { high: {} }, }) }) test("preserves an empty current default", () => { expect(normalizeProviderList([] as ProviderListOutput["data"], [], null).defaultModel).toBeNull() }) }) describe("directoryKey", () => { test("normalizes slashes", () => { expect(String(directoryKey("C:\\Repos\\sst\\opencode"))).toBe("C:/Repos/sst/opencode") expect(String(directoryKey("C:/Repos/sst/opencode"))).toBe("C:/Repos/sst/opencode") }) test("preserves backslashes in posix paths", () => { expect(String(directoryKey("/tmp/foo\\bar"))).toBe("/tmp/foo\\bar") }) test("trims trailing slashes without breaking roots", () => { expect(String(directoryKey("C:/Repos/sst/opencode/"))).toBe("C:/Repos/sst/opencode") expect(String(directoryKey("C:/"))).toBe("C:/") expect(String(directoryKey("/"))).toBe("/") }) })