feat(f11): SLICE-3 — Edit Document button + per-hunk proposal path (#43, INV-37)

A whole-document Ask-Claude rewrite is diffed into hunks and surfaced as N
independent F4 proposals (one per changed hunk) — reusing the F4 single-range
model N times, no new model. Per spec §6.4/§7.2 SLICE-3.

- trackChangesModel: pure `diffToHunks(currentText, rewrittenText)` →
  EditHunk[] (vscode-free, deterministic; diffWordsWithSpace, coalescing
  adjacent add/remove runs; offsets index currentText).
- trackChangesPreview: `runEditAndPropose(document, target, instruction)` — the
  shared host routine (selection → one single-range propose; document → diff →
  one propose per hunk; never mutates the doc, INV-10); `askClaude` UI wrapper
  (host showInputBox keeps LLM/secrets out of the sealed webview, INV-8/35);
  injectable `editTurn` + `setEditTurnForTest` seam (no LLM in CI); the
  `askClaude` inbound message branch; `cowriting.editDocument` command for #42
  reuse.
- package.json: register cowriting.editDocument, palette-guarded on markdown.
- webview: ✦ Ask Claude to Edit Document button → { askClaude, scope:"document" }.
- unit: diffToHunks fixtures (zero/one/multi-hunk, wholesale, determinism).
- host E2E: stubbed multi-hunk rewrite → N matching proposals, doc untouched;
  editDocument command registered + markdown-guarded.

205 unit + 49 host E2E green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-06-12 13:51:07 -07:00
parent 1ef9451e89
commit 0d1a5635cb
6 changed files with 254 additions and 4 deletions
+9
View File
@@ -78,6 +78,11 @@
"command": "cowriting.showTrackChangesPreview",
"title": "Cowriting: Open Review Preview",
"category": "Cowriting"
},
{
"command": "cowriting.editDocument",
"title": "Ask Claude to Edit Document",
"category": "Cowriting"
}
],
"menus": {
@@ -101,6 +106,10 @@
{
"command": "cowriting.pinDiffBaseline",
"when": "editorLangId == markdown"
},
{
"command": "cowriting.editDocument",
"when": "editorLangId == markdown"
}
],
"editor/context": [