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.", }); }), );});
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.",
});
}),
);
});