Commit Graph

323 Commits

Author SHA1 Message Date
Ben Stull 5a02e793dd claim vscode-cowriting-plugin session 0052 (placeholder) + sessions.json entry 2026-06-15 08:33:55 -07:00
Ben Stull faf0810a6c add sessions/0051/SESSION-0051.0-TRANSCRIPT-2026-06-13T17-49--2026-06-13T17-58.md + replace placeholder/variant SESSION-0051.0-TRANSCRIPT-2026-06-13T17-49--INPROGRESS.md 2026-06-15 03:28:01 -07:00
Ben Stull d597c1c362 claim vscode-cowriting-plugin session 0051 (placeholder) + sessions.json entry 2026-06-13 17:49:33 -07:00
Ben Stull 790d88c827 add sessions/0050/SESSION-0050.0-TRANSCRIPT-2026-06-13T17-43--2026-06-13T17-52.md + replace placeholder/variant SESSION-0050.0-TRANSCRIPT-2026-06-13T17-43--INPROGRESS.md 2026-06-13 17:48:52 -07:00
Ben Stull 37953cfcad claim vscode-cowriting-plugin session 0050 (placeholder) + sessions.json entry 2026-06-13 17:43:55 -07:00
Ben Stull 24e329e25d add sessions/0049/SESSION-0049.0-TRANSCRIPT-2026-06-13T09-19--2026-06-13T09-24.md + replace placeholder/variant SESSION-0049.0-TRANSCRIPT-2026-06-13T09-19--INPROGRESS.md 2026-06-13 09:22:49 -07:00
benstull 96a689aedf Merge pull request '#54 follow-up: pretest:e2e cleans out/test (stop stale cross-branch compiled tests running)' (#56) from s54-pretest-clean into main 2026-06-13 16:21:57 +00:00
Ben Stull 911ed21671 #54 follow-up: pretest:e2e cleans out/test before recompiling
`tsc -p tsconfig.e2e.json` emits to `out/` but never removes outputs for test
sources absent on the current branch, so stale compiled
`out/test/e2e/suite/*.test.js` from other branches were picked up and run by the
suite glob (`**/*.test.js`) — this caused real cross-branch test confusion in
session 0048 (a deleted probe + another branch's tests ran on an unrelated branch).

Add a `clean:e2e` script (`fs.rmSync('out/test', {recursive, force})` via node, so
no shell `rm` dependency) and run it between `build` and `tsc` in `pretest:e2e`.
Cleans ONLY `out/test` — never `out/`, which holds the just-built esbuild bundle
(`out/extension.cjs`, `out/media`).

Verified: planting a stale `out/test/.../zz.test.js` then running `pretest:e2e`
removes it, and the E2E suite stays green (73 passing + 1 pending, both passes
exit 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 09:21:31 -07:00
Ben Stull 2ca0fc8c51 claim vscode-cowriting-plugin session 0049 (placeholder) + sessions.json entry 2026-06-13 09:19:26 -07:00
benstull 3d9270ecc4 Merge pull request '#54: resilient undo E2E (preflight skip-guard) — fixes main E2E red' (#55) from s54-undo-e2e-resilience into main 2026-06-13 16:17:02 +00:00
Ben Stull e53f0c30ad #54: make undo-dependent E2E resilient to environments where undo is broken
`executeCommand("undo")` is non-functional in some headless `.vscode-test`
instances (it does not restore the buffer — see #54's diagnosis), which
false-fails every undo-dependent host E2E and turns `main`'s E2E red there even
though the product code is fine.

Add a RUNTIME preflight probe (`undoCapable.ts`): edit a scratch buffer, undo,
and report whether the buffer was actually restored (memoized per run). The #38
undoMarks suite gates on it via `suiteSetup` — running normally where undo works
(full coverage preserved, real regressions still caught) and skipping with a LOUD
console warning where it doesn't (no false red, no silent loss — the skip is
logged and shows as `pending`).

This fixes the "main E2E red" symptom. The underlying headless-undo limitation is
documented in #54; #40's undo-behavior coverage runs wherever undo works.

Test-infra only — no product code changed. Verified: with undo broken locally the
#38 suite skips (1 pending) and both E2E passes exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 09:16:40 -07:00
Ben Stull ad6cbe10c7 add sessions/0048/SESSION-0048.0-TRANSCRIPT-2026-06-13T08-45--2026-06-13T08-58.md + replace placeholder/variant SESSION-0048.0-TRANSCRIPT-2026-06-13T08-45--INPROGRESS.md 2026-06-13 08:58:11 -07:00
Ben Stull 64c7d7bad2 claim vscode-cowriting-plugin session 0048 (placeholder) + sessions.json entry 2026-06-13 08:45:48 -07:00
Ben Stull ab00cbefcc add sessions/0047/SESSION-0047.0-TRANSCRIPT-2026-06-13T08-34--2026-06-13T08-44.md + replace placeholder/variant SESSION-0047.0-TRANSCRIPT-2026-06-13T08-34--INPROGRESS.md 2026-06-13 08:43:50 -07:00
benstull c67749a53c Merge pull request '#33: harden author-coloring PUA sentinels against intra-emphasis markdown' (#53) from s33-sentinel-hardening into main 2026-06-13 15:42:04 +00:00
Ben Stull ba7623f813 #33: harden author-coloring PUA sentinels against intra-emphasis markdown
The F9/F10 author-coloring technique injects paired PUA sentinels into prose
source at span offsets, renders, then maps sentinels → cw-by-* spans. Two failure
modes when a span boundary met emphasis markup (characterized in session 0032):
- CASE1: a boundary strictly inside a delimiter run (a**b**c, between the two *)
  split `**`, breaking markdown-it's delimiter pairing (stray <em></em>, raw **).
- CASE3: a boundary inside an emphasis run (**bold** span covering **bo) rendered
  the emphasis but MISNESTED span/element (<strong>bo</span>ld</strong>).

Token-aware fix (both, per the issue #33 comment):
- injectSentinels: clamp any sentinel offset that lands strictly inside a
  delimiter run (* _ ~ `) to the run's start, so a sentinel never splits a run
  (CASE1). Delimiters are invisible once rendered, so this only shifts the colored
  boundary across markup. Drop spans that clamp to empty.
- sentinelsToSpans: replace the naive global split/join with a walker over the
  rendered HTML that emits the cw-by-* span only around TEXT runs — closing it
  before any <tag> and reopening after — so a span is always well-nested within
  inline elements (one span segment per text run, CASE3). Tags are copied
  verbatim with any stray sentinel stripped (no Private-Use-Area char leaks).

Pure, vscode-free, deterministic (INV-33). No regression: existing colorByAuthor /
renderReview cases stay green; the common no-emphasis case is byte-identical.

222 unit + 74/5 host E2E green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 08:41:31 -07:00
Ben Stull 9e9fcb8057 claim vscode-cowriting-plugin session 0047 (placeholder) + sessions.json entry 2026-06-13 08:34:03 -07:00
Ben Stull 1381eab11e add sessions/0046/SESSION-0046.0-TRANSCRIPT-2026-06-13T08-19--2026-06-13T08-31.md + replace placeholder/variant SESSION-0046.0-TRANSCRIPT-2026-06-13T08-19--INPROGRESS.md 2026-06-13 08:32:25 -07:00
benstull 54846da1ea Merge pull request '#48: pinning the baseline leaves the review panel fully un-annotated' (#52) from s48-pin-clean-panel into main 2026-06-13 15:30:55 +00:00
Ben Stull fdd743490d #48: pinning the baseline leaves the review panel fully un-annotated
A pinned baseline with no changes since should read as a clean starting point,
but the F10 on-render still author-colored every block (colorByAuthor), painting
the whole document green/blue right after a pin. Now, when the baseline reason is
"pinned" and there are zero changes since (every diffBlocks op unchanged), the
on-render is fully clean — no change marks and no authorship coloring — while the
data-src block mapping (INV-36) and any pending proposals (review actions, not
annotations) are kept.

Scoped to the PIN specifically, not all zero-diff: a baseline advanced by a
machine-landing (accept) is also zero-diff but keeps its authorship coloring so
accepted Claude text stays blue (F10 INV-33). renderReview takes a `pinned`
option; the controller passes baseline.reason === "pinned" from both refresh and
the renderHtmlFor test seam.

- trackChangesModel.ts: renderReview gains the `pinned` RenderOption; when pinned
  + zero-diff, blocks render plain (no colorByAuthor).
- trackChangesPreview.ts: pass { pinned } through refresh + renderHtmlFor.
- unit: pinned+zero-diff → no cw-by-*; pinned+zero-diff still shows proposals;
  zero-diff WITHOUT pin (machine-landing) keeps coloring (INV-33); real changes
  after a pin re-color.
- s48PinClean host E2E: type → colored; pin → clean; edit → annotations return.

218 unit + 74/5 host E2E green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 08:28:52 -07:00
Ben Stull 4584e06679 claim vscode-cowriting-plugin session 0046 (placeholder) + sessions.json entry 2026-06-13 08:19:43 -07:00
Ben Stull ef07acfdc1 add sessions/0045/SESSION-0045.0-TRANSCRIPT-2026-06-13T08-04--2026-06-13T08-17.md + replace placeholder/variant SESSION-0045.0-TRANSCRIPT-2026-06-13T08-04--INPROGRESS.md 2026-06-13 08:18:17 -07:00
benstull 83c4a80d8b Merge pull request '#46 (SLICE-3, accept): Accept all pending proposals in one gesture' (#51) from f12-slice3-accept-all into main 2026-06-13 15:16:18 +00:00
Ben Stull c94b9ccfe7 #46 (SLICE-3, accept): Accept all pending proposals in one gesture
Document-edit flow SLICE-3 — completes reach→review→accept
(specs/coauthoring-document-edit-flow.md §7.2, INV-42). A single "Accept all"
gesture applies every pending proposal on the current document through the
existing F4 acceptById seam (block proposals take the INV-40 word-precise path
automatically), in descending anchor order so an earlier accept never invalidates
a later one, skipping (never force-applying) proposals that can't anchor and
reporting applied-vs-skipped. Batched application of the existing accept path — no
new mechanism; the webview posts intent only (INV-35). No confirmation dialog
(undo restores).

- proposalController.ts: acceptAllProposals(document) → {applied, skipped}
  (descending order, orphan-skip); accept/acceptById gain a silent opt so the
  batch suppresses N per-proposal orphan warnings in favour of one report.
- trackChangesPreview.ts: ToolbarMsg += {type:"acceptAll"}; handleWebviewMessage
  routes it to a public acceptAll(document) that batches + reports.
- extension.ts + package.json: cowriting.acceptAllProposals command (active doc,
  markdown-gated palette entry) for the non-webview path.
- media/preview.ts + shellHtml: "✓✓ Accept all" toolbar button, posting the
  intent, shown only with ≥2 pending proposals (authorable, on-state).
- trackChangesModel.ts: diffToBlockHunks now emits one block-aligned hunk per
  CHANGED block even when changed blocks are ADJACENT (treats changed blocks as
  1:1 anchors alongside unchanged ones; gap-spans only cover add/remove runs
  between anchors) — fixes adjacent changed blocks collapsing into one proposal.
- f12Accept host E2E (apply-all reconstructs; orphan skip + report; single
  proposal; command registered/gated); MANUAL-SMOKE-F12 §3.

214 unit + 73/5 host E2E green. Completes the document-edit-flow cluster
(#42 reach + #47 review + #46 accept).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 08:15:55 -07:00
Ben Stull 6fd7555183 claim vscode-cowriting-plugin session 0045 (placeholder) + sessions.json entry 2026-06-13 08:05:04 -07:00
Ben Stull f7788c5585 add sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--2026-06-13T08-04.md + replace placeholder/variant SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md 2026-06-13 08:04:35 -07:00
Ben Stull b69d0f7d15 update sessions/0044/SESSION-0044.0-TRANSCRIPT-2026-06-13T07-40--INPROGRESS.md 2026-06-13 08:03:06 -07:00
benstull dc38b55c57 Merge pull request '#47 (SLICE-2, review): per-block document proposals + word-precise accept' (#50) from f12-slice2-block-proposals into main 2026-06-13 15:01:55 +00:00
Ben Stull 2f6008ba2b #47 (SLICE-2, review): per-block document proposals + word-precise accept
Document-edit flow SLICE-2 (specs/coauthoring-document-edit-flow.md §7.2,
INV-39/40/41 — P1 "too much to review"). A whole-document rewrite now proposes
ONE F4 proposal per CHANGED BLOCK (the unit a human reviews), but accepting a
block reconciles attribution at WORD granularity (the unit F3 records). Block =
decision unit; word = attribution unit. Supersedes INV-37's per-word cut for
document edits; selection edits unchanged.

- trackChangesModel.ts: new pure diffToBlockHunks(current, rewritten) — block-key
  alignment (reusing diffArrays/diffBlocks keying): an isolated changed block →
  one block-aligned hunk → the rewritten block raw (a code/mermaid fence is one
  atomic whole-fence hunk, INV-23); insert/delete runs → one gap-span hunk over
  the inter-anchor region (separators included) so reconstruction stays exact; a
  zero-width gap-span is anchored (INV-41). Also split diffToHunks into the raw,
  un-anchored wordEditHunks + the anchoring wrapper (the anchoring could grow an
  insertion to overlap an adjacent hunk, corrupting a batch apply — a latent bug
  that only surfaced once hunks are applied as a batch).
- trackChangesPreview.ts: runEditAndPropose document branch uses diffToBlockHunks
  and tags each proposal granularity:"block".
- model.ts / proposalModel.ts: additive optional Proposal.granularity
  ("block"|"single"; absent ⇒ single, back-compat — no migration).
- proposalController.ts: accept of a block proposal runs an intra-block word
  sub-diff (wordEditHunks, disjoint) and applies one applyAgentEdit per changed
  run, descending offset — only the words Claude changed land Claude-attributed;
  unchanged spans keep prior authorship (INV-40).
- Tests: diffToBlockHunks unit (reconstruction + fence atomic + add/remove);
  f12Review host E2E (M blocks→M proposals, unchanged→none, fence atomic, INV-40
  attribution, INV-41 insertion accept); updated the f11 document-path E2E to
  per-block (INV-39 supersedes INV-37); MANUAL-SMOKE-F12 §2.

Seam note: pendingEdits.matchEvent resolves one registration per change event, so
INV-40's per-run attribution is sequential applyAgentEdit calls (N undo steps),
not one multi-replace WorkspaceEdit — see transcript Deferred decisions.

214 unit + 69/5 host E2E green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 08:01:16 -07:00
Ben Stull 6e944ab4cc claim vscode-cowriting-plugin session 0044 (placeholder) + sessions.json entry 2026-06-13 07:40:13 -07:00
Ben Stull 2175efb5e5 add sessions/0043/SESSION-0043.0-TRANSCRIPT-2026-06-13T07-18--2026-06-13T07-38.md + replace placeholder/variant SESSION-0043.0-TRANSCRIPT-2026-06-13T07-18--INPROGRESS.md 2026-06-13 07:39:13 -07:00
Ben Stull 5dc7d19419 update sessions/0043/SESSION-0043.0-TRANSCRIPT-2026-06-13T07-18--INPROGRESS.md 2026-06-13 07:29:04 -07:00
benstull e804c46ba0 Merge pull request '#42 (SLICE-1, reach): selection-aware Ask-Claude from editor body + tab' (#49) from f12-slice1-ask-claude-menus into main 2026-06-13 14:27:09 +00:00
Ben Stull 9c3770d26a #42 (SLICE-1, reach): selection-aware Ask-Claude from editor body + tab
Document-edit flow SLICE-1 (specs/coauthoring-document-edit-flow.md §7.2,
INV-38): make "Ask Claude to Edit" reachable from the editor body AND the
editor tab, selection-aware — a selection routes to editSelection, no
selection to editDocument — both gated to markdown/authorable docs, both
flowing through the single runEditAndPropose path (no divergent edit code).

- package.json: add editSelection + editDocument to editor/context (selection-
  aware, markdown + file/untitled) and editor/title/context (selection-aware,
  resourceLangId == markdown). Markdown-gate the existing editor/context
  editSelection entry to match (its command handler is unchanged; the palette
  still reaches any authorable doc — see transcript Deferred decisions).
- trackChangesPreview.ts: cowriting.editDocument accepts the clicked tab's
  resource Uri (editor/title/context), targeting THAT document (opening it if
  needed) and falling back to the active editor when invoked with no arg —
  mirroring showTrackChangesPreview's #41 clicked-doc resolution.
- E2E (test/e2e/suite/f12Reach.test.ts): menu entries present, selection-aware,
  markdown-gated; editDocument(uri) targets the tab doc not the active editor;
  no-arg falls back to the active editor.
- docs/MANUAL-SMOKE-F12.md: SLICE-1 reach smoke steps.

208 unit + 65/5 host E2E green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 07:26:14 -07:00
Ben Stull 60a396c09e claim vscode-cowriting-plugin session 0043 (placeholder) + sessions.json entry 2026-06-13 07:19:03 -07:00
Ben Stull 9ec0862353 add sessions/0042/SESSION-0042.0-TRANSCRIPT-2026-06-12T21-04--2026-06-13T07-16.md + replace placeholder/variant SESSION-0042.0-TRANSCRIPT-2026-06-12T21-04--INPROGRESS.md 2026-06-13 07:17:25 -07:00
Ben Stull d5ef6dc90f add sessions/0041/SESSION-0041.0-TRANSCRIPT-2026-06-12T18-17--2026-06-13T07-16.md + replace placeholder/variant SESSION-0041.0-TRANSCRIPT-2026-06-12T18-17--INPROGRESS.md 2026-06-13 07:17:16 -07:00
Ben Stull 261f0de240 claim vscode-cowriting-plugin session 0042 (placeholder) + sessions.json entry 2026-06-12 21:05:02 -07:00
Ben Stull 46f74c8247 claim vscode-cowriting-plugin session 0041 (placeholder) + sessions.json entry 2026-06-12 18:17:58 -07:00
Ben Stull cc3d778da9 add sessions/0040/SESSION-0040.0-TRANSCRIPT-2026-06-12T17-03--2026-06-12T17-21.md + replace placeholder/variant SESSION-0040.0-TRANSCRIPT-2026-06-12T17-03--INPROGRESS.md 2026-06-12 17:22:23 -07:00
Ben Stull 981640f3d5 claim vscode-cowriting-plugin session 0040 (placeholder) + sessions.json entry 2026-06-12 17:03:31 -07:00
Ben Stull 2978663c14 add sessions/0039/SESSION-0039.0-TRANSCRIPT-2026-06-12T16-07--2026-06-12T17-02.md + replace placeholder/variant SESSION-0039.0-TRANSCRIPT-2026-06-12T16-07--INPROGRESS.md 2026-06-12 17:02:44 -07:00
Ben Stull 5eb13deca3 claim vscode-cowriting-plugin session 0039 (placeholder) + sessions.json entry 2026-06-12 16:07:27 -07:00
Ben Stull 91c55870f2 add sessions/0038/SESSION-0038.0-TRANSCRIPT-2026-06-12T15-55--2026-06-12T16-06.md + replace placeholder/variant SESSION-0038.0-TRANSCRIPT-2026-06-12T15-55--INPROGRESS.md 2026-06-12 16:06:50 -07:00
benstull eea4145904 Merge pull request 'feat(#41): Open Cowriting Review Panel from markdown file/tab right-click' (#45) from 41-review-panel-right-click into main 2026-06-12 23:04:48 +00:00
Ben Stull 695b51f903 feat(#41): Open Cowriting Review Panel from markdown file/tab right-click
The review preview (`cowriting.showTrackChangesPreview`) was only reachable from
the command palette and `ctrl+alt+r` — neither where a writer's hand naturally
goes. Add the obvious right-click entry points to the plugin's central surface:

- `explorer/context` + `editor/title/context` menu items gated on
  `resourceLangId == markdown`, both invoking `showTrackChangesPreview`.
- The command now resolves the *clicked* document: it opens the passed Uri if
  it isn't already an open document (the Explorer case), instead of falling back
  to the active editor. No-arg invocation (palette / keybinding) is unchanged.
- Retitle the command to "Open Cowriting Review Panel" so the menus read the
  operator's wording (palette shows "Cowriting: Open Cowriting Review Panel").

E2E: clicked-doc resolution (open + not-yet-open + no-arg fallback), both menu
contributions present + markdown-gated, title, and keybinding unchanged.

Closes #41.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 16:04:02 -07:00
Ben Stull de53305a08 claim vscode-cowriting-plugin session 0038 (placeholder) + sessions.json entry 2026-06-12 15:55:41 -07:00
Ben Stull 21df67022f add sessions/0037/SESSION-0037.0-TRANSCRIPT-2026-06-12T13-33--2026-06-12T14-22.md + replace placeholder/variant SESSION-0037.0-TRANSCRIPT-2026-06-12T13-33--INPROGRESS.md 2026-06-12 14:21:49 -07:00
benstull 62a2229c25 Merge pull request 'F11 — Preview toolbar as the primary interaction surface (#43)' (#44) from f11-preview-toolbar into main 2026-06-12 21:18:54 +00:00
Ben Stull 47cc733026 fix(f11): address code review — insertion anchoring, turnId, accept-all coverage (#43)
Code-review follow-up on the F11 branch (5966907..1564ef5). Three real findings:

- CRITICAL — pure-insertion hunks were born-orphaned. A document rewrite that
  INSERTS text produced a zero-width hunk (start==end) → buildFingerprint yields
  empty fp.text → anchorer.resolve orphans an empty needle → the proposal could
  never be accepted (silently). diffToHunks now anchors every zero-width
  insertion to an adjacent source token (anchorInsertion): the range absorbs the
  token and the replacement keeps it, so net text is identical but fp.text is
  non-empty and resolvable. New unit tests: applying hunks always reconstructs
  the rewrite (substitute/delete/insert/multi); insertions are never zero-width.
  New host E2E ACCEPTS a rewrite-with-insertion end to end and asserts accept-all
  reconstructs the intended document (also covers sequential multi-hunk accept).

- IMPORTANT — renderPlain cross-block fidelity. The per-block off-mode rendering
  (SLICE-2) can't resolve a reference-link definition in a separate block.
  Documented as a conscious tradeoff of the operator-locked block-level mapping
  (§6.7) — renderReview already rendered per-block, so this keeps both modes
  consistent — with a characterization test + a docstring note.

- MINOR — F11 proposals now carry a turnId (one per Ask-Claude gesture, shared
  across a document rewrite's N hunks), matching the editor-menu editSelection
  path so a rewrite groups as one agent turn.

208 unit + 9/9 F11 host E2E green. (The lone red E2E is a pre-existing,
F11-independent undoMarks timing flake — proven by isolation: it fails
identically with all F11 tests removed.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 14:16:49 -07:00