Native surfaces migration — evolve the extension onto VS Code's native review surfaces (9-task plan, spec v0.2.1) (#72)

This commit was merged in pull request #72.
This commit is contained in:
2026-07-02 23:09:37 +00:00
parent 93eeaf13b8
commit 935fcc35ee
54 changed files with 3689 additions and 1995 deletions
+43 -23
View File
@@ -15,6 +15,16 @@ async function openDoc(): Promise<vscode.TextDocument> {
await vscode.window.showTextDocument(doc);
return doc;
}
/** Open the doc AND enter coediting (INV-10) — baselines are established only
* on entry (Task 2). Idempotent across tests: re-entering an already-coedited
* doc is a no-op, so the once-captured baseline survives (order-dependent
* suite, same as before). */
async function openAndCoedit(): Promise<vscode.TextDocument> {
const doc = await openDoc();
await vscode.commands.executeCommand("cowriting.coeditDocument");
await settle();
return doc;
}
async function getApi(): Promise<CowritingApi> {
const ext = vscode.extensions.getExtension("benstull.vscode-cowriting-plugin")!;
const api = (await ext.activate()) as CowritingApi;
@@ -29,22 +39,29 @@ const settle = () => new Promise((r) => setTimeout(r, 300));
// later tests consume earlier state. Owns docs/diffview.md exclusively. The
// baseline works on ANY file (#19), so the last two tests use an out-of-workspace
// file and an untitled buffer.
//
// Native-surfaces migration (Task 2, spec §6.4/INV-7): a baseline is now
// established only once a document ENTERS coediting (not merely opened), and
// the fixture workspace is NOT a git repo, so every doc here resolves to
// SNAPSHOT mode. The shipped machine-landing baseline advance (#48/INV-18) is
// retired — an accepted proposal now stays a visible change-since-baseline
// until "Mark Changes as Reviewed" (D21).
suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress, no LLM)", () => {
const TARGET = "A target sentence Claude will rewrite via the seam.";
const REPLACEMENT = "A SENTENCE CLAUDE REWROTE via the seam.";
test("opening a tracked doc captures an `opened` baseline equal to the buffer (INV-18)", async () => {
const doc = await openDoc();
await getApi();
test("entering coediting on a snapshot-mode doc captures an `entered` baseline equal to the buffer (INV-7)", async () => {
const doc = await openAndCoedit();
const api = await getApi();
assert.strictEqual(api.diffViewController.modeOf(docUri()), "snapshot", "no git repo → snapshot mode");
const baseline = api.diffViewController.getBaseline(docUri());
assert.ok(baseline, "baseline captured on first sight");
assert.strictEqual(baseline!.reason, "opened");
assert.strictEqual(baseline!.text, doc.getText(), "baseline = open-time buffer");
assert.ok(baseline, "baseline captured on coediting entry");
assert.strictEqual(baseline!.reason, "entered");
assert.strictEqual(baseline!.text, doc.getText(), "baseline = entry-time buffer");
});
test("typing leaves the baseline unchanged while the buffer diverges", async () => {
const doc = await openDoc();
const doc = await openAndCoedit();
const api = await getApi();
const before = api.diffViewController.getBaseline(docUri())!.text;
const edit = new vscode.WorkspaceEdit();
@@ -55,9 +72,10 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
assert.notStrictEqual(doc.getText(), before, "buffer diverged");
});
test("accepting a proposal advances the baseline past the landed text (PUC-2, INV-18)", async () => {
const doc = await openDoc();
test("accepting a proposal does NOT advance the baseline the landed text stays a change (INV-7/D21, #48 retired)", async () => {
const doc = await openAndCoedit();
const api = await getApi();
const before = api.diffViewController.getBaseline(docUri())!;
const start = doc.getText().indexOf(TARGET);
assert.ok(start >= 0, "fixture contains the target");
const id = await vscode.commands.executeCommand<string>("cowriting.proposeAgentEdit", {
@@ -73,14 +91,14 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
assert.ok(await api.proposalController.acceptById(DOC_REL, id!), "accept applies via the seam");
await settle();
const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "machine-landing", "baseline advanced on the landing");
assert.ok(baseline.text.includes(REPLACEMENT), "landed text is in the baseline (won't show as a change)");
assert.ok(!baseline.text.includes(TARGET), "old target gone from the baseline too");
assert.strictEqual(baseline.text, doc.getText(), "baseline == buffer right after the landing");
assert.strictEqual(baseline.reason, before.reason, "baseline reason untouched by the landing");
assert.strictEqual(baseline.text, before.text, "baseline text untouched by the landing");
assert.ok(!baseline.text.includes(REPLACEMENT), "landed text is NOT folded into the baseline");
assert.notStrictEqual(baseline.text, doc.getText(), "baseline != buffer the landing reads as a change");
});
test("an operator edit after the landing makes baseline ≠ buffer (the operator delta)", async () => {
const doc = await openDoc();
test("an operator edit after the landing keeps baseline ≠ buffer (the operator delta)", async () => {
const doc = await openAndCoedit();
const api = await getApi();
const edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, new vscode.Position(0, 0), "POST-LANDING OPERATOR LINE\n");
@@ -89,14 +107,14 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
assert.notStrictEqual(
api.diffViewController.getBaseline(docUri())!.text,
doc.getText(),
"operator changes show against the advanced baseline",
"operator changes show against the untouched baseline",
);
});
test("pin resets the baseline to now: baseline == buffer, reason pinned", async () => {
const doc = await openDoc();
test("markReviewed resets the baseline to now: baseline == buffer, reason pinned", async () => {
const doc = await openAndCoedit();
const api = await getApi();
await vscode.commands.executeCommand("cowriting.pinDiffBaseline");
await vscode.commands.executeCommand("cowriting.markReviewed");
await settle();
const baseline = api.diffViewController.getBaseline(docUri())!;
assert.strictEqual(baseline.reason, "pinned");
@@ -104,14 +122,14 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
});
test("the baseline is persisted in GLOBAL storage, never the repo (INV-19)", async () => {
await openDoc();
await openAndCoedit();
const api = await getApi();
const p = api.diffViewController.baselineFilePath(docUri());
assert.ok(p, "storage-backed baseline path is available for a file: doc");
assert.ok(fs.existsSync(p!), `baseline file exists at ${p}`);
const onDisk = JSON.parse(fs.readFileSync(p!, "utf8"));
assert.strictEqual(onDisk.uri, docUri(), "baseline records the document URI");
assert.strictEqual(onDisk.reason, "pinned", "last epoch (pin) persisted");
assert.strictEqual(onDisk.reason, "pinned", "last epoch (markReviewed) persisted");
assert.strictEqual(onDisk.text, api.diffViewController.getBaseline(docUri())!.text, "on-disk == in-memory");
// INV-19: baseline lives under the extension's storage dir, not the repo.
assert.ok(!p!.includes(`${path.sep}.threads${path.sep}`), "baseline is NOT in the sidecar tree");
@@ -127,11 +145,12 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
const outsideUri = vscode.Uri.file(outsidePath);
const doc = await vscode.workspace.openTextDocument(outsideUri);
await vscode.window.showTextDocument(doc);
await vscode.commands.executeCommand("cowriting.coeditDocument");
await settle();
// Captured on open even though it is NOT under the workspace folder.
// Captured on coediting entry even though it is NOT under the workspace folder.
const baseline = api.diffViewController.getBaseline(outsideUri.toString());
assert.ok(baseline, "baseline captured for an out-of-folder file");
assert.strictEqual(baseline!.reason, "opened");
assert.strictEqual(baseline!.reason, "entered");
const fp = api.diffViewController.baselineFilePath(outsideUri.toString());
assert.ok(fp && fs.existsSync(fp), "outside-file baseline persisted in global storage");
assert.ok(!fp!.startsWith(WS + path.sep), "not under the workspace folder");
@@ -143,6 +162,7 @@ suite("F6 baseline data layer (host E2E — any file, programmatic seam ingress,
const api = await getApi();
const untitled = await vscode.workspace.openTextDocument({ content: "scratch line\n", language: "markdown" });
await vscode.window.showTextDocument(untitled);
await vscode.commands.executeCommand("cowriting.coeditDocument");
await settle();
const key = untitled.uri.toString();
assert.strictEqual(untitled.uri.scheme, "untitled", "it really is an untitled buffer");