mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 02:26:12 +02:00
Fix canonical Cursor plan delivery expectations
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
1d5196c8e8
commit
0ccdd4f03f
2 files changed
+29
-1
No files matched your search
@@ -1,3 +1,6 @@
|
||||
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 } 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";
|
||||
@@ -62,3 +65,23 @@ it("requires exact delivered answer bytes rather than a saved or different answe
|
||||
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);
|
||||
}
|
||||
});
|
||||
@@ -14,6 +14,11 @@ import type { MatrixExecution } from "./types.js";
|
||||
type Row = Record<string, any>;
|
||||
type Check = { id: string; passed: boolean; detail: string };
|
||||
|
||||
/** Match canonical omission of an unanswered optional feedback field. */
|
||||
export function cursorNativePlanResponse(planId: string, decision: "accept" | "reject" | "cancel", feedback: string) {
|
||||
return { schema: "paperclip.question_response.v1", answers: { [planId]: { selectedOptionIds: [decision] }, ...(decision === "reject" ? { reason: { text: feedback } } : {}) } };
|
||||
}
|
||||
|
||||
/** Independent bounded snapshot; symlinks are rejected without following them. */
|
||||
export async function cursorNativeWorkspaceSnapshot(root: string): Promise<Record<string, string>> {
|
||||
const files: Record<string, string> = {}; let bytes = 0;
|
||||
@@ -183,7 +188,7 @@ export async function runCursorNativeFlow(input: {
|
||||
await page.getByRole("radio", { name: decision === "accept" ? "Accept plan" : decision === "reject" ? "Reject plan" : "Cancel plan request", exact: true }).last().click();
|
||||
await page.getByRole("button", { name: "Next", exact: true }).last().click();
|
||||
if (decision === "reject") await page.getByTestId("question-text-answer-composer").last().locator('[contenteditable="true"],textarea').first().fill(feedback);
|
||||
const response = { schema: "paperclip.question_response.v1", answers: { [plan.id]: { selectedOptionIds: [decision] }, reason: decision === "reject" ? { text: feedback } : {} } };
|
||||
const response = cursorNativePlanResponse(plan.id, decision, feedback);
|
||||
check("revision-bound-decision", hasCursorPlanDecision(set, response, decision), "Decision addresses precisely the displayed native plan revision");
|
||||
await page.getByRole("button", { name: set.submitLabel ?? "Submit answers", exact: true }).last().click();
|
||||
await delivery(card, event, response); seen.add(card.id); previousRevision = plan.id;
|
||||
|
||||
Reference in new issue
Block a user