Files
PaperClipAI/tests/runner-e2e/cursor-native-cases.test.ts
T
DottaandPaperclip e2b89b6302 Integrate pinned Cursor ACP runtime and explicit public setup
Consolidate Cursor v10 onto current controller behavior, retain admission gates, and prepare native interaction and cleanup qualification. Add the public provisioner and ordinary provider-pack assets.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-03 13:33:15 -05:00

137 lines
11 KiB
TypeScript

import { parsePaperclipQuestionResponse } from "../../packages/paperclip-runner/src/contracts/question-set.js";
import { normalizeCursorPlanRequest } from "../../packages/paperclip-runner/src/drivers/acpx/cursor-extensions.js";
import { cursorNativePlanResponse, findCursorNativeRequest, hasCursorNativeCardBinding } from "./cursor-native-flow.js";
import { cursorDeniedCommand, type CursorToolNotice } from "./cursor-native-evidence.js";
import { describe, expect, it } from "vitest";
import { cursorNativeCaseDesigns, cursorNativePrompt, hasDeliveredCursorNativeRequest, hasCursorPlanDecision, hasCursorDenialBoundary, CURSOR_DENIAL_SAMPLE_PHASES, hasExactCursorNativeResponse } from "./cursor-native-cases.js";
const proof = (adapter = "acpx-runtime") => {
const wrap = (eventType: string, sourceSeq: number, payload: unknown) => ({ runId: "run", protocolSchemaVersion: 1, payload: { prpEvent: {
schema: "paperclip.prp.event.v1", schemaVersion: 1, runId: "run", turnId: "turn", eventType, sourceSeq, payload,
} } });
return [wrap("runtime_request.created", 1, { request: { requestId: "request", turnId: "turn", type: "input", status: "pending", origin: { adapter, provider: "cursor", method: "cursor/ask_question" } } }),
wrap("runtime_request.resolved", 2, { requestId: "request", turnId: "turn", action: "submit" })];
};
const grade = (events: unknown[]) => hasDeliveredCursorNativeRequest({ events, runId: "run", turnId: "turn", requestId: "request", method: "cursor/ask_question", action: "submit" });
describe("prepared Cursor native qualification", () => {
it("has four fixed native-only designs and bounded prompts", () => {
expect(cursorNativeCaseDesigns).toHaveLength(4);
for (const design of cursorNativeCaseDesigns) expect(cursorNativePrompt(design.id, "test-nonce")).toContain("Do not substitute");
expect(() => cursorNativePrompt("native-write-deny-reconnect", "../escape")).toThrow();
});
it("requires correlated native origin and response delivery evidence", () => { expect(grade(proof())).toBe(true); expect(grade([])).toBe(false); });
it("rejects semantic substitutions and permission fallbacks", () => {
for (const method of ["request_human_input", "session/request_permission", "cursor/create_plan"]) {
const rows = proof(); (rows[0]!.payload.prpEvent.payload as any).request.origin.method = method; expect(grade(rows)).toBe(false);
}
});
it("rejects missing, duplicated and expired delivery", () => {
const rows = proof(); expect(grade(rows.slice(0, 1))).toBe(false); expect(grade([...rows, rows[1]])).toBe(false);
rows[1]!.payload.prpEvent.eventType = "runtime_request.expired"; expect(grade(rows)).toBe(false);
});
it("rejects mismatched run, turn and event ordering", () => {
let rows = proof(); rows[1]!.runId = "foreign"; expect(grade(rows)).toBe(false);
rows = proof(); rows[1]!.payload.prpEvent.turnId = "stale"; expect(grade(rows)).toBe(false);
rows = proof(); rows[1]!.payload.prpEvent.sourceSeq = 0; expect(grade(rows)).toBe(false);
});
});
it("binds plan decisions to the full revision and rejects stale answers", () => {
const id = `plan-${"a".repeat(64)}`;
const questionSet = { questions: [{ id }] };
const answer = { schema: "paperclip.question_response.v1", answers: { [id]: { selectedOptionIds: ["accept"] } } };
expect(hasCursorPlanDecision(questionSet, answer, "accept")).toBe(true);
expect(hasCursorPlanDecision({ questions: [{ id: `plan-${"b".repeat(64)}` }] }, answer, "accept")).toBe(false);
expect(hasCursorPlanDecision(questionSet, answer, "reject")).toBe(false);
});
it.each(["acpx-runtime", "acpx-runtime-sidecar"])("requires supported denial choices, native IDs and complete no-effect boundaries via %s", adapter => {
const input = { request: { requestId: "request", turnId: "turn", type: "permission", status: "pending", details: { toolCallId: "tool" },
origin: { adapter, provider: "cursor", method: "session/request_permission" },
choices: [{ key: "accept" }, { key: "decline" }, { key: "cancel" }] }, expectedRequestId: "request", expectedToolCallId: "tool", path: "/fixture/denied.txt", runId: "run", turnId: "turn",
notices: ([{ stage: "tool", status: "pending" }, { stage: "permission_requested", requestId: "request", declineOffered: true }, { stage: "permission_delivered", requestId: "request", outcome: "reject_once" }, { stage: "tool", status: "failed" }].map((row, index) => ({ ...row, seq: index + 1, runId: "run", sessionId: "session", turnId: "turn", toolCallId: "tool", operation: "execute", commandSha256: cursorDeniedCommand("/fixture/denied.txt").commandSha256 })) as CursorToolNotice[]),
samples: CURSOR_DENIAL_SAMPLE_PHASES.map((phase, observedAt) => ({ phase, observedAt, absent: true, path: "/fixture/denied.txt" })) };
expect(hasCursorDenialBoundary(input)).toBe(true);
for (const origin of [{ ...input.request.origin, adapter: "semantic" }, { ...input.request.origin, provider: "pi" }, { ...input.request.origin, method: "request_human_input" }]) {
expect(hasCursorDenialBoundary({ ...input, request: { ...input.request, origin } })).toBe(false);
}
expect(hasCursorDenialBoundary({ ...input, samples: input.samples.slice(1) })).toBe(false);
expect(hasCursorDenialBoundary({ ...input, expectedToolCallId: "foreign" })).toBe(false);
input.samples[2]!.absent = false; expect(hasCursorDenialBoundary(input)).toBe(false); input.samples[2]!.absent = true;
input.request.choices.push({ key: "accept_for_session" }); expect(hasCursorDenialBoundary(input)).toBe(false);
});
it("requires exact delivered answer bytes rather than a saved or different answer", () => {
const rows = proof(); const response = { schema: "paperclip.question_response.v1", answers: { q: { selectedOptionIds: ["chosen"] } } };
(rows[1]!.payload.prpEvent.payload as any).response = response;
const input = { events: rows, runId: "run", turnId: "turn", requestId: "request", method: "cursor/ask_question" as const, action: "submit" as const, response };
expect(hasExactCursorNativeResponse(input)).toBe(true);
expect(hasExactCursorNativeResponse({ ...input, response: { ...response, answers: { q: { selectedOptionIds: ["other"] } } } })).toBe(false);
expect(hasExactCursorNativeResponse({ ...input, events: rows.slice(0, 1) })).toBe(false);
});
it.each(["accept", "cancel", "reject"] as const)("recognizes canonical delivered native plan %s without an empty optional answer", decision => {
const native = normalizeCursorPlanRequest({ toolCallId: "native-plan", plan: "Verify the revised plan.", todos: [] });
const planId = native.questionSet.questions[0]!.id;
const response = cursorNativePlanResponse(planId, decision, " Keep exact feedback 漢字\nSecond line ");
const delivered = parsePaperclipQuestionResponse(native.questionSet, response);
const rows = proof();
(rows[0]!.payload.prpEvent.payload as any).request.origin.method = "cursor/create_plan";
(rows[1]!.payload.prpEvent.payload as any).response = delivered;
const input = { events: rows, runId: "run", turnId: "turn", requestId: "request", method: "cursor/create_plan" as const, action: "submit" as const, response };
expect(hasCursorPlanDecision(native.questionSet, response, decision)).toBe(true);
expect(hasExactCursorNativeResponse(input)).toBe(true);
expect(native.resolve(delivered).outcome.outcome).toBe({ accept: "accepted", cancel: "cancelled", reject: "rejected" }[decision]);
if (decision === "reject") expect(delivered.answers.reason?.text).toBe(" Keep exact feedback 漢字\nSecond line ");
else {
expect(delivered.answers).not.toHaveProperty("reason");
expect(hasExactCursorNativeResponse({ ...input, response: { ...response, answers: { ...response.answers, reason: {} } } })).toBe(false);
}
});
// Retained paid sidecar plan callback exposed both origin and JSONB key-order drift.
it.each(["acpx-runtime", "acpx-runtime-sidecar"])("recognizes a native plan and its durable card via %s", adapter => {
const input = normalizeCursorPlanRequest({ toolCallId: "native-plan", name: "Fixture plan", plan: "Verify complete Markdown.", todos: [{ id: "first", content: "Read", status: "pending" }, { id: "second", content: "Check", status: "pending" }] }).questionSet;
const rows = proof(adapter);
const request = (rows[0]!.payload.prpEvent.payload as any).request;
request.origin.method = "cursor/create_plan";
request.input = input;
const event = findCursorNativeRequest(rows, "cursor/create_plan", "request")!;
expect(event).toBe(rows[0]!.payload.prpEvent);
expect(hasDeliveredCursorNativeRequest({ events: rows, runId: "run", turnId: "turn", requestId: "request", method: "cursor/create_plan", action: "submit" })).toBe(true);
const reorder = (value: any): any => Array.isArray(value) ? value.map(reorder) : value !== null && typeof value === "object"
? Object.fromEntries(Object.entries(value).reverse().map(([key, nested]) => [key, reorder(nested)])) : value;
const card = { sourceRunId: "run", continuationPolicy: "none", payload: { runtimeRequestId: "request", questionSet: reorder(input) } };
expect(JSON.stringify(card.payload.questionSet)).not.toBe(JSON.stringify(input));
expect(hasCursorNativeCardBinding(card, event, "run")).toBe(true);
expect(hasCursorNativeCardBinding(card, event, "other-run")).toBe(false);
expect(hasCursorNativeCardBinding({ ...card, continuationPolicy: "resume" }, event, "run")).toBe(false);
const changed = structuredClone(card);
changed.payload.questionSet.questions[0].options[0].label = "Changed choice";
expect(hasCursorNativeCardBinding(changed, event, "run")).toBe(false);
const reordered = structuredClone(card);
reordered.payload.questionSet.questions[0].options.reverse();
expect(hasCursorNativeCardBinding(reordered, event, "run")).toBe(false);
expect(findCursorNativeRequest(rows, "cursor/create_plan", "other-request")).toBeUndefined();
expect(findCursorNativeRequest(rows, "cursor/ask_question", "request")).toBeUndefined();
});
it.each(["acpx-runtime", "acpx-runtime-sidecar"])("rejects foreign native request identity or origin via %s", adapter => {
for (const patch of [{ adapter: "unknown" }, { adapter: "acpx-runtime-sidecar-unknown" }, { adapter: "semantic" }, { provider: "pi" }, { method: "request_human_input" }]) {
const rows = proof(adapter);
Object.assign((rows[0]!.payload.prpEvent.payload as any).request.origin, patch);
expect(grade(rows)).toBe(false);
expect(findCursorNativeRequest(rows, "cursor/ask_question", "request")).toBeUndefined();
}
for (const patch of [{ requestId: "foreign" }, { turnId: "stale" }]) {
const rows = proof(adapter);
Object.assign((rows[0]!.payload.prpEvent.payload as any).request, patch);
expect(grade(rows)).toBe(false);
}
const rows = proof(adapter);
expect(grade([...rows, rows[0]!])).toBe(false);
expect(grade([...rows, rows[1]!])).toBe(false);
rows[1]!.payload.prpEvent.turnId = "stale";
expect(grade(rows)).toBe(false);
});