F4: document propose/accept — manual smoke, README, playground loop (#12)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,8 @@ catalog (a pure, key-free SDK call) in a notification and the
|
|||||||
"Cowriting (Cline SDK)" output channel.
|
"Cowriting (Cline SDK)" output channel.
|
||||||
|
|
||||||
Features shipped so far: F2 region-anchored threads (Feature #4), F3 live
|
Features shipped so far: F2 region-anchored threads (Feature #4), F3 live
|
||||||
human/Claude attribution (Feature #6).
|
human/Claude attribution (Feature #6), F4 propose/accept diff flow
|
||||||
|
(Feature #12).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -67,13 +68,36 @@ Attribution" output channel) rather than silently moved or discarded.
|
|||||||
- **`Cowriting: Ask Claude to Edit Selection`** — select text → enter an
|
- **`Cowriting: Ask Claude to Edit Selection`** — select text → enter an
|
||||||
instruction → a live `@cline/sdk` turn runs on the built-in `claude-code`
|
instruction → a live `@cline/sdk` turn runs on the built-in `claude-code`
|
||||||
provider (rides your local Claude Code Pro/Max login; the extension stores no
|
provider (rides your local Claude Code Pro/Max login; the extension stores no
|
||||||
credentials). The replacement lands in the buffer as a Claude-attributed span.
|
credentials). As of F4 the turn ends in a **proposal** (see below); accepted
|
||||||
|
text lands as a Claude-attributed span.
|
||||||
- **`Cowriting: Toggle Attribution`** — show/hide attribution decorations.
|
- **`Cowriting: Toggle Attribution`** — show/hide attribution decorations.
|
||||||
- `cowriting.applyAgentEdit` _(palette-hidden)_ — the single machine-edit
|
- `cowriting.applyAgentEdit` _(palette-hidden)_ — the single machine-edit
|
||||||
ingress seam. Tests drive this directly so CI requires no LLM.
|
ingress seam. Tests drive this directly so CI requires no LLM.
|
||||||
|
|
||||||
Design: `vscode-cowriting-plugin-content/specs/coauthoring-attribution.md`.
|
Design: `vscode-cowriting-plugin-content/specs/coauthoring-attribution.md`.
|
||||||
|
|
||||||
|
## F4 — Propose/accept diff flow (Feature #12)
|
||||||
|
|
||||||
|
Claude's edits arrive as **pending proposals** — propose-by-default, the
|
||||||
|
document never changes without your say-so. A proposal renders two ways at
|
||||||
|
once: an **amber tint** on the target range, and a "Claude proposes" comment
|
||||||
|
thread showing a fenced `diff` of current → proposed text with two actions:
|
||||||
|
|
||||||
|
- **✓ Accept Proposal** — applies the replacement through the `applyAgentEdit`
|
||||||
|
seam, so it lands Claude-attributed (F3) — and the proposal disappears.
|
||||||
|
- **✗ Reject Proposal** — the document is untouched; the proposal disappears.
|
||||||
|
|
||||||
|
Pending proposals persist git-natively in the same sidecar (`proposals[]`,
|
||||||
|
sharing the F2/F3 `anchors` fingerprints), survive reload, and re-anchor as
|
||||||
|
surrounding text changes. If the **target text itself** changes, the proposal
|
||||||
|
goes **stale** (status-bar count, accept disabled — never applied by guess);
|
||||||
|
undo the change and it becomes decidable again. `cowriting.proposeAgentEdit`
|
||||||
|
_(palette-hidden)_ is the programmatic propose ingress E2E drives — no LLM in
|
||||||
|
CI.
|
||||||
|
|
||||||
|
Design: `vscode-cowriting-plugin-content/specs/coauthoring-propose-accept.md`.
|
||||||
|
Live smoke: [`docs/MANUAL-SMOKE-F4.md`](docs/MANUAL-SMOKE-F4.md).
|
||||||
|
|
||||||
## Develop
|
## Develop
|
||||||
|
|
||||||
- `npm run watch` — rebuild on change.
|
- `npm run watch` — rebuild on change.
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
# F3 manual smoke — live `claude-code` turn (spec §6.8)
|
# F3 manual smoke — live `claude-code` turn (spec §6.8)
|
||||||
|
|
||||||
|
> **As of F4 (#12)** the edit-selection turn ends in a **proposal** — the
|
||||||
|
> direct-apply behavior in §2 step 4 now happens on **✓ Accept Proposal**. The
|
||||||
|
> full propose→accept smoke is [`MANUAL-SMOKE-F4.md`](./MANUAL-SMOKE-F4.md);
|
||||||
|
> §1's scripted smoke is unchanged (it drives the SDK turn only, no editor).
|
||||||
|
|
||||||
The live turn is deliberately NOT in CI (unit + host E2E drive the seam). It
|
The live turn is deliberately NOT in CI (unit + host E2E drive the seam). It
|
||||||
gets this documented smoke, run once per machine that has Claude Code
|
gets this documented smoke, run once per machine that has Claude Code
|
||||||
installed and signed in (Pro/Max). The extension itself holds no credentials
|
installed and signed in (Pro/Max). The extension itself holds no credentials
|
||||||
@@ -37,9 +42,9 @@ the model id, a non-empty `sessionId`, and exits 0.
|
|||||||
with a clear error (`runEditTurn` throws on any non-`completed` run
|
with a clear error (`runEditTurn` throws on any non-`completed` run
|
||||||
status); in-editor, the command shows an error notification and NO edit is
|
status); in-editor, the command shows an error notification and NO edit is
|
||||||
applied.
|
applied.
|
||||||
- Buffer edited mid-turn: start an edit-selection turn, type elsewhere in the
|
- Buffer edited mid-turn: superseded by F4 — the turn ends in a proposal, so a
|
||||||
document before it completes → warning notification "document changed", no
|
mid-turn edit can't race an application; the proposal simply renders where
|
||||||
partial application (stale `expectedVersion`, spec §6.9).
|
its target re-resolves (or stale if the target itself changed — F4 INV-11).
|
||||||
|
|
||||||
## Smoke log
|
## Smoke log
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Manual smoke — F4 propose/accept (live turn)
|
||||||
|
|
||||||
|
Pre-req: Claude Code installed + signed in (the `claude-code` provider rides
|
||||||
|
that login — the extension holds no credentials, INV-8). Run on a real machine,
|
||||||
|
not CI.
|
||||||
|
|
||||||
|
1. `npm run build`, then F5 (the EDH opens the committed `sandbox/` playground).
|
||||||
|
2. Open `playground.md`, select a sentence → right-click → **Ask Claude to Edit
|
||||||
|
Selection** → give an instruction.
|
||||||
|
3. ✅ A **proposal** appears: the selection gets an amber tint and a "Claude
|
||||||
|
proposes" comment thread shows a `diff` of current → proposed. **The document
|
||||||
|
text is unchanged** (INV-10).
|
||||||
|
4. Click **✓ Accept Proposal** in the thread title. ✅ The replacement lands and
|
||||||
|
renders Claude-tinted (the F3 attribution substrate); the proposal disappears.
|
||||||
|
5. Repeat with another selection and click **✗ Reject Proposal**. ✅ The document
|
||||||
|
is untouched; the proposal disappears.
|
||||||
|
6. Propose again, then save and reload the window. ✅ The pending proposal is
|
||||||
|
restored at its re-resolved range.
|
||||||
|
7. Failure path: edit the proposed-on text, then try Accept. ✅ Refused with a
|
||||||
|
warning ("target text changed"); undo your edit → Accept works.
|
||||||
@@ -8,8 +8,10 @@ open in your dev window (#8).
|
|||||||
Play here:
|
Play here:
|
||||||
|
|
||||||
1. Type a sentence below — it renders with the human left-border as you type.
|
1. Type a sentence below — it renders with the human left-border as you type.
|
||||||
2. Highlight it → right-click → **Ask Claude to Edit Selection** — the
|
2. Highlight it → right-click → **Ask Claude to Edit Selection** — Claude
|
||||||
replacement lands Claude-tinted.
|
**proposes** a diff (amber tint + a "Claude proposes" thread); click
|
||||||
|
**✓ Accept Proposal** and it lands Claude-tinted, or **✗ Reject Proposal**
|
||||||
|
to discard.
|
||||||
3. Edit inside the tinted span — it splits character-precisely.
|
3. Edit inside the tinted span — it splits character-precisely.
|
||||||
4. Save, then peek at `sandbox/.threads/playground.md.json` — the git-native
|
4. Save, then peek at `sandbox/.threads/playground.md.json` — the git-native
|
||||||
attribution record. Reopen the file: spans re-resolve.
|
attribution record. Reopen the file: spans re-resolve.
|
||||||
|
|||||||
Reference in New Issue
Block a user