import type { SDKModel } from "@cursor/sdk"; import { describe, expect, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Schema from "effect/Schema"; import type { CursorSettings } from "@t3tools/contracts"; import { CursorSettings as CursorSettingsSchema } from "@t3tools/contracts"; import { createModelCapabilities } from "@t3tools/shared/model"; import { buildCursorCapabilitiesFromSdkModel, buildCursorDiscoveredModelsFromSdk, buildCursorProviderSnapshot, buildInitialCursorProviderSnapshot, checkCursorProviderStatus, getCursorFallbackModels, } from "./CursorProvider.ts"; import { CursorSdkCatalogError, makeCursorSdkCatalogTestLayer } from "./CursorSdkCatalog.ts"; const decodeCursorSettings = Schema.decodeSync(CursorSettingsSchema); function selectDescriptor( id: string, label: string, options: ReadonlyArray<{ id: string; label: string; isDefault?: boolean }>, ) { return { id, label, type: "select" as const, options: [...options], ...(options.find((option) => option.isDefault)?.id ? { currentValue: options.find((option) => option.isDefault)?.id } : {}), }; } function booleanDescriptor(id: string, label: string, currentValue?: boolean) { return { id, label, type: "boolean" as const, ...(typeof currentValue === "boolean" ? { currentValue } : {}), }; } const baseCursorSettings: CursorSettings = decodeCursorSettings({ enabled: true, customModels: [], }); const sdkParameterizedModel = { id: "claude-opus-4-8", displayName: "Opus 4.8", parameters: [ { id: "thinking", displayName: "Thinking", values: [{ value: "false" }, { value: "true" }], }, { id: "context", displayName: "Context", values: [ { value: "300k", displayName: "300K" }, { value: "1m", displayName: "1M" }, ], }, { id: "effort", displayName: "Effort", values: [ { value: "low", displayName: "Low" }, { value: "high", displayName: "High" }, ], }, { id: "fast", displayName: "Fast", values: [{ value: "false" }, { value: "true", displayName: "Fast" }], }, ], variants: [ { displayName: "Opus 4.8", isDefault: true, params: [ { id: "thinking", value: "true" }, { id: "context", value: "1m" }, { id: "effort", value: "high" }, { id: "fast", value: "false" }, ], }, ], } satisfies SDKModel; describe("getCursorFallbackModels", () => { it("does not publish any built-in cursor models before SDK discovery", () => { expect( getCursorFallbackModels({ customModels: ["internal/cursor-model"], }).map((model) => model.slug), ).toEqual(["internal/cursor-model"]); }); }); describe("buildInitialCursorProviderSnapshot", () => { it.effect("uses SDK-specific pending status copy", () => Effect.gen(function* () { const provider = yield* buildInitialCursorProviderSnapshot(baseCursorSettings); expect(provider).toMatchObject({ status: "warning", message: "Checking Cursor SDK availability...", }); }), ); }); describe("buildCursorProviderSnapshot", () => { it("downgrades ready status to warning when SDK model discovery returns no models", () => { expect( buildCursorProviderSnapshot({ checkedAt: "2026-01-01T00:00:00.000Z", cursorSettings: baseCursorSettings, parsed: { version: null, status: "ready", auth: { status: "authenticated", type: "api-key", label: "Cursor API key" }, }, discoveryWarning: "Cursor SDK model discovery returned no built-in models.", }), ).toMatchObject({ status: "warning", message: "Cursor SDK model discovery returned no built-in models.", models: [], }); }); }); describe("Cursor SDK model discovery", () => { it("maps native SDK parameter ids and default variant values to model capabilities", () => { expect(buildCursorCapabilitiesFromSdkModel(sdkParameterizedModel)).toEqual( createModelCapabilities({ optionDescriptors: [ selectDescriptor("effort", "Effort", [ { id: "low", label: "Low" }, { id: "high", label: "High", isDefault: true }, ]), selectDescriptor("contextWindow", "Context", [ { id: "300k", label: "300K" }, { id: "1m", label: "1M", isDefault: true }, ]), booleanDescriptor("fastMode", "Fast", false), booleanDescriptor("thinking", "Thinking", true), ], }), ); }); it("filters invalid and duplicate SDK model entries", () => { expect( buildCursorDiscoveredModelsFromSdk([ sdkParameterizedModel, { ...sdkParameterizedModel, displayName: "Duplicate" }, { id: "", displayName: "Invalid" }, ]), ).toEqual([ { slug: "claude-opus-4-8", name: "Opus 4.8", isCustom: false, capabilities: buildCursorCapabilitiesFromSdkModel(sdkParameterizedModel), }, ]); }); }); describe("checkCursorProviderStatus", () => { it.effect("uses the SDK catalog when CURSOR_API_KEY is configured", () => Effect.gen(function* () { const provider = yield* checkCursorProviderStatus( { ...baseCursorSettings, customModels: ["internal/cursor-model"], }, { CURSOR_API_KEY: "test-cursor-key" }, ).pipe( Effect.provide( makeCursorSdkCatalogTestLayer((apiKey) => { expect(apiKey).toBe("test-cursor-key"); return Effect.succeed({ user: { apiKeyName: "test-key", userEmail: "cursor@example.com", createdAt: "2026-01-01T00:00:00.000Z", }, models: [sdkParameterizedModel], }); }), ), ); expect(provider).toMatchObject({ status: "ready", auth: { status: "authenticated", type: "api-key", label: "Cursor API key (test-key)", email: "cursor@example.com", }, models: [ { slug: "claude-opus-4-8", isCustom: false }, { slug: "internal/cursor-model", isCustom: true }, ], }); }), ); it.effect("surfaces SDK authentication failures", () => Effect.gen(function* () { const provider = yield* checkCursorProviderStatus(baseCursorSettings, { CURSOR_API_KEY: "invalid-test-key", }).pipe( Effect.provide( makeCursorSdkCatalogTestLayer(() => Effect.fail( new CursorSdkCatalogError({ authenticationFailure: true, cause: new Error("unauthorized"), }), ), ), ), ); expect(provider).toMatchObject({ status: "error", auth: { status: "unauthenticated" }, message: "Cursor SDK authentication failed. Check CURSOR_API_KEY.", }); }), ); it.effect("requires a Cursor API key without probing any external Cursor binary", () => Effect.gen(function* () { const provider = yield* checkCursorProviderStatus(baseCursorSettings).pipe( Effect.provide( makeCursorSdkCatalogTestLayer(() => Effect.die("SDK catalog must not be used without CURSOR_API_KEY"), ), ), ); expect(provider).toMatchObject({ installed: true, status: "error", auth: { status: "unauthenticated" }, message: "Cursor API key is required. Add CURSOR_API_KEY in provider settings.", }); }), ); });