F12: inline editable proposed-change diff in the Markdown editor + Accept/Reject control parity (#64) #66
@@ -97,6 +97,14 @@ export interface Proposal {
|
|||||||
* back-compat with older sidecars) ⇒ a single-range proposal accepted whole.
|
* back-compat with older sidecars) ⇒ a single-range proposal accepted whole.
|
||||||
*/
|
*/
|
||||||
granularity?: "block" | "single";
|
granularity?: "block" | "single";
|
||||||
|
/**
|
||||||
|
* F12/#64 (INV-48): the pre-apply text, captured when a proposal is
|
||||||
|
* optimistically applied to the buffer. `replacement` is now in the buffer and
|
||||||
|
* `fp.text` re-anchors to it, so `original` is the only record of what to revert
|
||||||
|
* to (revert-in-place) and what to show struck in the `<del>` half. Absent on a
|
||||||
|
* proposal created but not yet optimistically applied (or older sidecars).
|
||||||
|
*/
|
||||||
|
original?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Artifact {
|
export interface Artifact {
|
||||||
@@ -252,6 +260,8 @@ export function serializeArtifact(a: Artifact): string {
|
|||||||
createdAt: p.createdAt,
|
createdAt: p.createdAt,
|
||||||
...(p.turnId !== undefined ? { turnId: p.turnId } : {}),
|
...(p.turnId !== undefined ? { turnId: p.turnId } : {}),
|
||||||
...(p.instruction !== undefined ? { instruction: p.instruction } : {}),
|
...(p.instruction !== undefined ? { instruction: p.instruction } : {}),
|
||||||
|
...(p.original !== undefined ? { original: p.original } : {}),
|
||||||
|
...(p.granularity !== undefined ? { granularity: p.granularity } : {}),
|
||||||
},
|
},
|
||||||
p,
|
p,
|
||||||
),
|
),
|
||||||
|
|||||||
+15
-1
@@ -1,4 +1,5 @@
|
|||||||
import { describe, it, expect } from "vitest";
|
import assert from "node:assert";
|
||||||
|
import { describe, it, test, expect } from "vitest";
|
||||||
import {
|
import {
|
||||||
SCHEMA_VERSION,
|
SCHEMA_VERSION,
|
||||||
emptyArtifact,
|
emptyArtifact,
|
||||||
@@ -179,6 +180,19 @@ describe("unknown-field preservation (F5 SLICE-2, INV-15)", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("serializeArtifact round-trips Proposal.original", () => {
|
||||||
|
const a = emptyArtifact("doc.md");
|
||||||
|
a.anchors["a_1"] = { fingerprint: { text: "new", before: "", after: "", lineHint: 0 } };
|
||||||
|
a.proposals.push({
|
||||||
|
id: "pr_1", anchorId: "a_1", replacement: "new",
|
||||||
|
author: { kind: "agent", id: "claude", agent: { sdk: "@cline/sdk", model: "sonnet", sessionId: "s" } },
|
||||||
|
createdAt: "2026-06-26T00:00:00.000Z", original: "old", granularity: "block",
|
||||||
|
});
|
||||||
|
const json = serializeArtifact(a);
|
||||||
|
assert.match(json, /"original": "old"/);
|
||||||
|
assert.match(json, /"granularity": "block"/);
|
||||||
|
});
|
||||||
|
|
||||||
describe("attributions[] (F3 SLICE-1)", () => {
|
describe("attributions[] (F3 SLICE-1)", () => {
|
||||||
it("round-trips an attribution record through serialize → parse", () => {
|
it("round-trips an attribution record through serialize → parse", () => {
|
||||||
const a = emptyArtifact("docs/x.md");
|
const a = emptyArtifact("docs/x.md");
|
||||||
|
|||||||
Reference in New Issue
Block a user