import { describe, expect, it } from "vite-plus/test"; import { CursorListAvailableModelsResponse, extractAskQuestions, extractPlanMarkdown, extractTodosAsPlan,} from "./CursorAcpExtension.ts"; describe("CursorAcpExtension", () => { it("extracts ask-question prompts from the real Cursor ACP payload shape", () => { const questions = extractAskQuestions({ toolCallId: "ask-1", title: "Need input", questions: [ { id: "language", prompt: "Which language should I use?", options: [ { id: "ts", label: "TypeScript" }, { id: "rs", label: "Rust" }, ], allowMultiple: false, }, ], }); expect(questions).toEqual([ { id: "language", header: "Question", question: "Which language should I use?", multiSelect: false, options: [ { label: "TypeScript", description: "TypeScript" }, { label: "Rust", description: "Rust" }, ], }, ]); }); it("defaults ask-question multi-select to false when Cursor omits allowMultiple", () => { const questions = extractAskQuestions({ toolCallId: "ask-2", questions: [ { id: "mode", prompt: "Which mode should I use?", options: [ { id: "agent", label: "Agent" }, { id: "plan", label: "Plan" }, ], }, ], }); expect(questions).toEqual([ { id: "mode", header: "Question", question: "Which mode should I use?", multiSelect: false, options: [ { label: "Agent", description: "Agent" }, { label: "Plan", description: "Plan" }, ], }, ]); }); it("extracts plan markdown from the real Cursor create-plan payload shape", () => { const planMarkdown = extractPlanMarkdown({ toolCallId: "plan-1", name: "Refactor parser", overview: "Tighten ACP parsing", plan: "# Plan\n\n1. Add schemas\n2. Remove casts", todos: [ { id: "t1", content: "Add schemas", status: "in_progress" }, { id: "t2", content: "Remove casts", status: "pending" }, ], isProject: false, }); expect(planMarkdown).toBe("# Plan\n\n1. Add schemas\n2. Remove casts"); }); it("projects todo updates into a plan shape and drops invalid entries", () => { expect( extractTodosAsPlan({ toolCallId: "todos-1", todos: [ { id: "1", content: "Inspect state", status: "completed" }, { id: "2", content: " Apply fix ", status: "in_progress" }, { id: "3", title: "Fallback title", status: "pending" }, { id: "4", content: "Unknown status", status: "weird_status" }, { id: "5", content: " " }, ], merge: true, }), ).toEqual({ plan: [ { step: "Inspect state", status: "completed" }, { step: "Apply fix", status: "inProgress" }, { step: "Fallback title", status: "pending" }, { step: "Unknown status", status: "pending" }, ], }); }); it("decodes Cursor list_available_models responses with per-model config options", () => { const decoded = CursorListAvailableModelsResponse.make({ models: [ { value: "gpt-5.4", name: "GPT-5.4", configOptions: [ { id: "reasoning", name: "Reasoning", category: "thought_level", type: "select", currentValue: "medium", options: [ { value: "low", name: "Low" }, { value: "medium", name: "Medium" }, ], }, ], }, ], }); expect(decoded.models[0]?.configOptions?.[0]?.id).toBe("reasoning"); });});
import { describe, expect, it } from "vite-plus/test";
import {
CursorListAvailableModelsResponse,
extractAskQuestions,
extractPlanMarkdown,
extractTodosAsPlan,
} from "./CursorAcpExtension.ts";
describe("CursorAcpExtension", () => {
it("extracts ask-question prompts from the real Cursor ACP payload shape", () => {
const questions = extractAskQuestions({
toolCallId: "ask-1",
title: "Need input",
questions: [
{
id: "language",
prompt: "Which language should I use?",
options: [
{ id: "ts", label: "TypeScript" },
{ id: "rs", label: "Rust" },
],
allowMultiple: false,
},
],
});
expect(questions).toEqual([
{
id: "language",
header: "Question",
question: "Which language should I use?",
multiSelect: false,
options: [
{ label: "TypeScript", description: "TypeScript" },
{ label: "Rust", description: "Rust" },
],
},
]);
});
it("defaults ask-question multi-select to false when Cursor omits allowMultiple", () => {
const questions = extractAskQuestions({
toolCallId: "ask-2",
questions: [
{
id: "mode",
prompt: "Which mode should I use?",
options: [
{ id: "agent", label: "Agent" },
{ id: "plan", label: "Plan" },
],
},
],
});
expect(questions).toEqual([
{
id: "mode",
header: "Question",
question: "Which mode should I use?",
multiSelect: false,
options: [
{ label: "Agent", description: "Agent" },
{ label: "Plan", description: "Plan" },
],
},
]);
});
it("extracts plan markdown from the real Cursor create-plan payload shape", () => {
const planMarkdown = extractPlanMarkdown({
toolCallId: "plan-1",
name: "Refactor parser",
overview: "Tighten ACP parsing",
plan: "# Plan\n\n1. Add schemas\n2. Remove casts",
todos: [
{ id: "t1", content: "Add schemas", status: "in_progress" },
{ id: "t2", content: "Remove casts", status: "pending" },
],
isProject: false,
});
expect(planMarkdown).toBe("# Plan\n\n1. Add schemas\n2. Remove casts");
});
it("projects todo updates into a plan shape and drops invalid entries", () => {
expect(
extractTodosAsPlan({
toolCallId: "todos-1",
todos: [
{ id: "1", content: "Inspect state", status: "completed" },
{ id: "2", content: " Apply fix ", status: "in_progress" },
{ id: "3", title: "Fallback title", status: "pending" },
{ id: "4", content: "Unknown status", status: "weird_status" },
{ id: "5", content: " " },
],
merge: true,
}),
).toEqual({
plan: [
{ step: "Inspect state", status: "completed" },
{ step: "Apply fix", status: "inProgress" },
{ step: "Fallback title", status: "pending" },
{ step: "Unknown status", status: "pending" },
],
});
});
it("decodes Cursor list_available_models responses with per-model config options", () => {
const decoded = CursorListAvailableModelsResponse.make({
models: [
{
value: "gpt-5.4",
name: "GPT-5.4",
configOptions: [
{
id: "reasoning",
name: "Reasoning",
category: "thought_level",
type: "select",
currentValue: "medium",
options: [
{ value: "low", name: "Low" },
{ value: "medium", name: "Medium" },
],
},
],
},
],
});
expect(decoded.models[0]?.configOptions?.[0]?.id).toBe("reasoning");
});
});