tandem-editor 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "tandem-editor",
3
+ "owner": {
4
+ "name": "Tandem"
5
+ },
6
+ "metadata": {
7
+ "description": "Tandem — collaborative AI-human document editor"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "tandem",
12
+ "source": {
13
+ "source": "github",
14
+ "repo": "bloknayrb/tandem"
15
+ },
16
+ "description": "Edit and iterate on documents with Claude — no copy-paste, real-time push via plugin monitor"
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "tandem",
3
+ "version": "0.6.0",
4
+ "description": "Edit and iterate on documents with Claude — no copy-paste, real-time push via plugin monitor",
5
+ "author": {
6
+ "name": "Tandem"
7
+ },
8
+ "repository": "https://github.com/bloknayrb/tandem",
9
+ "license": "MIT",
10
+ "keywords": ["editor", "collaborative", "mcp", "claude"],
11
+ "mcpServers": {
12
+ "tandem": {
13
+ "command": "npx",
14
+ "args": ["-y", "tandem-editor", "mcp-stdio"],
15
+ "env": {
16
+ "TANDEM_URL": "http://localhost:3479"
17
+ }
18
+ },
19
+ "tandem-channel": {
20
+ "command": "npx",
21
+ "args": ["-y", "tandem-editor", "channel"],
22
+ "env": {
23
+ "TANDEM_URL": "http://localhost:3479"
24
+ }
25
+ }
26
+ }
27
+ }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,86 @@ All notable changes to Tandem will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [0.6.0] - 2026-04-15
11
+
12
+ ### Added
13
+
14
+ - **Plugin bridge to Cowork** — new `tandem mcp-stdio` subcommand is a stdio ↔ HTTP JSON-RPC proxy so Claude Desktop's plugin loader surfaces the full `tandem_*` tool surface into Cowork VM sessions. Verified empirically that plugin-loaded HTTP MCP entries don't bridge to Cowork but plugin-loaded stdio entries do. The plugin's `.claude-plugin/plugin.json` now declares stdio entries for both `tandem` (proxy) and `tandem-channel` (existing shim re-exposed as `tandem channel` subcommand), invoked via `npx -y tandem-editor …` so the plugin cache never needs dev dependencies. Both subcommands share a strict preflight in `src/cli/preflight.ts` that fails fast with a single clear message when the Tandem server isn't running on `localhost:3479`.
15
+ - `tandem channel` CLI subcommand — npm-delivered entry for the plugin's `tandem-channel` MCP server; shares runtime with the standalone `src/channel/index.ts` binary via the new `src/channel/run.ts` extraction.
16
+ - **Settings expansion** — Settings popover grows from layout/dwell/authorship into a fuller preferences surface:
17
+ - Ctrl+, / Cmd+, hotkey (AZERTY/QWERTZ/IME-safe, survives non-QWERTY layouts)
18
+ - Display Name field, synced live with the StatusBar via a shared `useUserName` hook
19
+ - Reduce Motion toggle (JS-gates all autoscroll paths; defaults to `prefers-reduced-motion`)
20
+ - Text Size S/M/L for editor reading density (browser zoom remains the WCAG 1.4.4 path)
21
+ - Theme Light/Dark/System (CSS custom-property token system on `<html data-theme>` with `forced-colors` support for Windows High Contrast)
22
+ - Tier 0 accessibility prerequisites on SettingsPopover: `role="dialog"` + `aria-modal`, focus trap, Escape-to-close, pointerdown outside-dismiss, radiogroup semantics, 24×24 hit targets, focus-return on close
23
+
24
+ ### Changed
25
+
26
+ - Repo's project-level `.mcp.json` renamed to `.mcp.json.example` and gitignored so it no longer ships inside plugin installs. The plugin's own `.claude-plugin/plugin.json` is authoritative for MCP wiring. Developers who clone the repo should copy the example to `.mcp.json` (gitignored) if they want Claude Code to auto-connect locally.
27
+ - Settings heading renamed "Layout Settings" → "Settings"
28
+ - Settings popover hardcoded hex values swapped to CSS tokens (remaining components will migrate in a follow-up)
29
+ - `shutdownForTests` renamed to `shutdownMonitor` (test-only alias kept for backward compatibility)
30
+ - `refreshMode` IIFE now wrapped in an outer `.catch` to keep future synchronous throws off the hot path
31
+
32
+ ### Fixed
33
+
34
+ - **Monitor preserves last-known `documentId`** — doc-less events (e.g. `chat:message`) no longer blank out the tracked document, so the shutdown awareness clear always targets a valid document.
35
+ - **Monitor exits 1 on shutdown awareness failure** — if the final `clearAwareness` POST fails during SIGINT/SIGTERM, the monitor exits with a non-zero status rather than silently succeeding.
36
+ - **`/api/setup` returns accurate status codes** — 207 on partial failure (some targets configured, some failed) and 500 on total failure, instead of always returning 200.
37
+ - **Checkpoint after stdout write** — `lastEventId` is only advanced after `process.stdout.write` returns, so EPIPE on a closed pipe no longer silently skips an event on reconnect.
38
+ - **Async EPIPE surfaces as exit(1)** — `process.stdout.on('error')` listener now catches asynchronous EPIPE (plugin host closes pipe mid-stream); monitor exits 1 instead of silently advancing `lastEventId` past lost events.
39
+ - **Defensive exit on monitor fallthrough** — the retry loop exits 1 if it ever terminates without hitting the explicit exhaustion path.
40
+
41
+ ## [0.5.1] - 2026-04-13
42
+
43
+ ### Added
44
+
45
+ - **Claude Code plugin support** — monitor-based event push (`src/monitor/index.ts`) gives real-time notifications without polling or the channel shim. Install via `claude plugin marketplace add bloknayrb/tandem`.
46
+ - **`--with-channel-shim` opt-in** — `tandem setup --with-channel-shim` writes the legacy `tandem-channel` MCP entry for setups that can't install the plugin.
47
+
48
+ ### Changed
49
+
50
+ - `tandem setup` no longer writes the `tandem-channel` MCP entry by default — running the plugin and the shim simultaneously produces duplicate event notifications. The shim is now opt-in only via `--with-channel-shim`.
51
+
52
+ ### Fixed
53
+
54
+ - **Windows update failure** — sidecar is now killed before the NSIS installer runs, preventing "Error opening file for writing: node-sidecar.exe" during updates
55
+ - **Mode check fails closed** — `/api/mode` errors now fall back to "solo" at startup (privacy signal, not a permissive default) while the hot-path background refresh keeps the last known good value to avoid mid-session suppression.
56
+ - **Retry counter resets on stable uptime** — retry count now resets only after 60s of continuous uptime, not on every delivered event; prevents infinite reconnect loops when the server crashes after each event.
57
+ - **Exponential backoff on reconnect** — monitor reconnects use 2s/4s/8s/16s/30s backoff instead of a fixed 2s delay.
58
+ - **SIGINT/SIGTERM clears awareness** — monitor posts a final `clearAwareness` before exit so the "Claude is active" indicator doesn't hang in the browser.
59
+ - **Per-route fetch timeouts** — `AbortSignal.timeout` enforces budgets per route (connect 10s, mode 2s, awareness 5s, error report 3s) to prevent hung SSE connects or mode lookups from stalling the monitor.
60
+ - **SSE parse errors don't advance `lastEventId`** — JSON parse failures and schema validation errors are logged with event ID + frame tail but do not advance `lastEventId`, so bad events are re-delivered on reconnect rather than silently dropped.
61
+ - **SKILL.md corrected** — `question` annotation guidance now uses `type === 'comment' && directedAt === 'claude' && author === 'user'`; all 5 highlight colors listed (yellow, red, green, blue, purple).
62
+
63
+ ## [0.5.0] - 2026-04-13
64
+
65
+ ### Added
66
+
67
+ - **Authorship tracking** — Y.Map overlay marks text as user-written or Claude-written, with text-color styling (blue for user, orange for Claude) (#190)
68
+ - **Threaded annotation replies** — reply to annotations with back-and-forth conversation threads (#187)
69
+ - **Claude cursor decoration** — character-level cursor shows where Claude is editing in real time (#209)
70
+ - **Auto-save** — documents save automatically on change; Ctrl+S triggers immediate manual save (#272)
71
+ - **Text zoom** — keyboard shortcuts (Ctrl+=/Ctrl+-) for adjusting text size in the Tauri desktop app (#273)
72
+ - **Three-panel default layout** — editor, side panel, and chat visible by default (#264)
73
+ - **Selection event suppression** — selection events only fire after a chat message is sent, reducing noise (#270)
74
+ - V1.0 release plan added to roadmap (#279)
75
+
76
+ ### Fixed
77
+
78
+ - Session persistence, tab bar horizontal scrollbar, and tab cycling keyboard shortcuts (#278)
79
+ - Authorship styling uses text color instead of background highlight; reopen sync corrected
80
+ - Annotation replies renamed from Acknowledge/Dismiss to Accept/Reject for clarity
81
+
82
+ ### Changed
83
+
84
+ - Pinned Hocuspocus and Y.js dependency versions to prevent upstream breakage (#271)
85
+ - EOL normalizer added to lint-staged for .yml and .md files (#263)
86
+ - Lessons learned applied to codebase and tooling (#280)
87
+
8
88
  ## [0.4.0] - 2026-04-12
9
89
 
10
90
  ### Added
package/README.md CHANGED
@@ -2,18 +2,29 @@
2
2
  <img src="docs/assets/banner.png" alt="Tandem — Collaborative AI-Human Document Editor" width="800">
3
3
  </p>
4
4
 
5
- Have you ever been working on a document (or any multi-paragraph piece of text) with Claude and wondered aloud, "Why isn't there an easier way to do this?" Well look no further, because now there is! My goal with this was to try to create an experience kind of similar to editing a Google doc with another person except that that other person is Claude Code.
5
+ Have you ever been working on a piece of writing with an LLM and caught yourself copy-pasting the same paragraph into the chat for the fifth time just so the model knows what you're talking about? That's the friction Tandem eliminates. Open a file directly, or just tell Claude "let's work on my draft in tandem" the document appears in the editor, and from that point on you highlight text and Claude sees it directly. No pasting, no "here's the paragraph I mean," no losing your place.
6
+
7
+ And because Tandem hooks into Claude as an MCP server, you're not stuck in some stripped-down document-editing silo. It's the full Claude — with all its knowledge, your conversation context, and every tool it has access to — just now it can also see and edit your document.
6
8
 
7
9
  ![Tandem editor showing a document with annotations, side panel, and Claude's presence](docs/screenshots/01-editor-overview.png)
8
10
 
11
+ ## Why Tandem?
12
+
13
+ - **No more copy-paste ping-pong.** Select text in the editor, and Claude reads your selection directly. Ask "what do you think of this?" or "make this more concise" — Claude knows exactly which text you mean.
14
+ - **Your full LLM, not a toy editor.** Tandem connects via MCP, so Claude keeps all its knowledge, all its tools, and your full conversation context. Need it to cross-reference your document against a codebase, a URL, or another file? It can — it's still Claude.
15
+ - **Iterate in place.** Claude can suggest rewrites, leave comments, flag issues, and edit text — all appearing as annotations you accept, dismiss, or tweak right in the document.
16
+
9
17
  ## Quick Start
10
18
 
11
- ### Prerequisites
19
+ ### Option A: Desktop App
20
+
21
+ Download the installer for your platform from the [latest release](https://github.com/bloknayrb/tandem/releases/latest).
22
+
23
+ The desktop app bundles everything — no Node.js required. It auto-configures Claude Code on launch, manages the server as a background process, and updates itself automatically. Just install and open.
12
24
 
13
- - **Node.js 22+** ([download](https://nodejs.org))
14
- - **Claude Code** (`irm https://claude.ai/install.ps1 | iex`)
25
+ ### Option B: npm Global Install
15
26
 
16
- ### Install and Run
27
+ Requires **Node.js 22+** ([download](https://nodejs.org)) and **Claude Code** (`npm install -g @anthropic-ai/claude-code`).
17
28
 
18
29
  ```bash
19
30
  npm install -g tandem-editor
@@ -23,10 +34,39 @@ tandem # starts server + opens browser
23
34
 
24
35
  `tandem setup` auto-detects Claude Code and Claude Desktop, writes MCP configuration, and installs a skill (`~/.claude/skills/tandem/SKILL.md`) that teaches Claude how to use Tandem's tools effectively. Re-run after upgrading (`npm update -g tandem-editor && tandem setup`).
25
36
 
37
+ ### Quickstart: Claude Code plugin (recommended)
38
+
39
+ Install the plugin to expose Tandem's tools and real-time event stream into Claude Desktop chats **and** Cowork VM sessions:
40
+
41
+ ```bash
42
+ claude plugin marketplace add bloknayrb/tandem
43
+ claude plugin install tandem@tandem-editor
44
+ ```
45
+
46
+ **Tandem must be running on the host before the plugin can do anything.** The plugin spawns two stdio MCP processes (`tandem mcp-stdio` and `tandem channel`) that proxy to `http://localhost:3479`. If the server isn't up they fail fast and log "Tandem server not reachable at …". Start the Tauri desktop app or run `tandem start` on the host first, then open Claude.
47
+
48
+ ### Legacy stdio channel shim
49
+
50
+ If you can't install the plugin, use the older channel shim:
51
+
52
+ ```bash
53
+ tandem setup --with-channel-shim
54
+ ```
55
+
56
+ This writes a `tandem-channel` entry to your Claude Code MCP config. Start Claude Code with:
57
+
58
+ ```bash
59
+ claude --dangerously-load-development-channels server:tandem-channel
60
+ ```
61
+
62
+ Don't combine this with the plugin — both subscribe to `/api/events` and you'll get duplicate notifications for every event.
63
+
26
64
  ### Connect Claude Code
27
65
 
28
66
  For the full Tandem experience, start Claude Code with the **channel push** flag:
29
67
 
68
+ > **Desktop app users:** Claude Code is configured automatically on every launch — skip `tandem setup` and just start Claude Code. The `tandem_*` tools will be available immediately.
69
+
30
70
  ```bash
31
71
  claude --dangerously-load-development-channels server:tandem-channel
32
72
  ```
@@ -79,7 +119,7 @@ Or check the raw health endpoint:
79
119
 
80
120
  ```bash
81
121
  curl http://localhost:3479/health
82
- # → {"status":"ok","version":"0.3.0","transport":"http","hasSession":false}
122
+ # → {"status":"ok","version":"0.4.0","transport":"http","hasSession":false}
83
123
  ```
84
124
 
85
125
  `hasSession` becomes `true` once Claude Code connects.
@@ -100,27 +140,29 @@ Open http://localhost:5173 — you'll see `sample/welcome.md` loaded automatical
100
140
 
101
141
  ## Using Tandem
102
142
 
103
- A one-minute mental model of the daily loop:
143
+ You point at text, Claude sees it. Here's how that plays out day-to-day:
104
144
 
105
- - **Open a document.** Ask Claude (`"open notes.md"`), drag a file onto the browser, or click the **+** in the tab bar. `.md`, `.txt`, `.html`, and `.docx` (review-only) are supported.
106
- - **Talk about specific text.** Select it in the browser editor, then ask Claude about "this paragraph" in the terminal. Claude reads your selection from `tandem_checkInbox` — no copy/paste. Hold the selection still for about a second so it registers (dwell-time gating filters out incidental clicks).
107
- - **Review what Claude suggests.** Annotations appear in the side panel. Press **Ctrl+Shift+R** to enter keyboard review mode: **Tab** to navigate, **Y** accept, **N** dismiss, **E** edit, **Z** undo within a 10-second window.
145
+ - **Open a document.** Ask Claude (`"let's work on notes.md in tandem"`), drag a file onto the browser, or click the **+** in the tab bar. `.md`, `.txt`, `.html`, and `.docx` (review-only) are supported.
146
+ - **Point at what you mean.** Select text in the editor and ask Claude about "this paragraph" in the terminal — or just wait for Claude to react if you have channels on. Claude reads your selection directly, no copy-paste needed. Hold the selection for about a second so it registers (dwell-time gating filters out incidental clicks).
147
+ - **Iterate on Claude's response.** Claude's suggestions appear as annotations in the side panel — accept, dismiss, edit, or ask follow-up questions. Each round refines the text without you ever leaving the document. Press **Ctrl+Shift+R** for keyboard review mode: **Tab** to navigate, **Y** accept, **N** dismiss, **E** edit, **Z** undo within a 10-second window.
108
148
  - **Heads-down vs collaborative.** Toggle **Solo** mode when you want to write without interruptions — Tandem queues non-urgent annotations until you flip back to **Tandem** mode. Both `tandem_status` and `tandem_checkInbox` return the current mode so Claude adapts its behavior automatically.
109
149
  - **Save.** Ask Claude ("save the file"), press the save button, or let session auto-persistence take over — your documents and annotations survive server restarts either way.
110
150
 
111
151
  ## Features
112
152
 
113
- ### Annotations
114
-
115
- ![Side panel showing annotation cards with filtering, bulk actions, and text previews](docs/screenshots/03-side-panel.png)
116
-
117
- Claude adds highlights, comments, suggestions, and flags directly in the document. Suggestion cards show a visual diff — original text in red strikethrough, replacement in green. The side panel lists all annotations with filtering by type, author, and status. Accept, dismiss, or edit each one individually — or use bulk actions to process them in batches.
153
+ Everything in Tandem is built around one idea: you work in the document, Claude works alongside you, and neither of you has to leave your surface to stay in sync.
118
154
 
119
155
  ### Chat
120
156
 
121
157
  ![Chat sidebar showing messages, typing indicator, and panel toggle](docs/screenshots/02-chat-sidebar.png)
122
158
 
123
- Send freeform messages to Claude alongside annotation review. Select text before sending to attach it as a clickable anchor clicking it later scrolls back to that passage.
159
+ Send messages to Claude alongside your document. Select text before sending to attach it as context Claude sees exactly what you mean. Clicking an anchored selection later scrolls back to that passage.
160
+
161
+ ### Annotations
162
+
163
+ ![Side panel showing annotation cards with filtering, bulk actions, and text previews](docs/screenshots/03-side-panel.png)
164
+
165
+ This is how Claude's feedback shows up in the document. Claude adds highlights, comments, suggestions, and flags directly on the text. Suggestion cards show a visual diff — original text in red strikethrough, replacement in green. The side panel lists all annotations with filtering by type, author, and status. Accept, dismiss, or edit each one individually — or use bulk actions to process them in batches.
124
166
 
125
167
  ### Review Mode
126
168
 
@@ -130,11 +172,11 @@ Press **Ctrl+Shift+R** to enter keyboard review mode. Navigate with **Tab**, acc
130
172
 
131
173
  ### More
132
174
 
175
+ - **Full LLM via MCP** — Claude connects through MCP tools, so it retains all its knowledge, conversation context, and tool access while working on your document
133
176
  - **Multi-document tabs** — open `.md`, `.txt`, `.html`, `.docx` files side by side; drag to reorder
134
177
  - **.docx review-only mode** — open Word documents for annotation; imported Word comments appear alongside Claude's
135
178
  - **Session persistence** — documents and annotations survive server restarts
136
179
  - **Solo / Tandem mode** — flip to Solo when you want to write heads-down; Tandem queues non-urgent annotations until you're ready
137
- - **Selection-aware chat** — highlight text in the browser, ask Claude about "this" in the terminal; Claude reads your selection directly, no copy/paste
138
180
  - **Real-time channel push** *(recommended)* — with the `--dangerously-load-development-channels` Claude Code flag, selections, annotations, and chat push to Claude instantly, making Tandem feel like a live collaborator watching over your shoulder
139
181
  - **Keyboard shortcuts** — press `?` for the full reference
140
182
  - **Unsaved-changes indicator** — dot on tab title when a document has pending edits
@@ -144,9 +186,8 @@ Press **Ctrl+Shift+R** to enter keyboard review mode. Navigate with **Tab**, acc
144
186
 
145
187
  ## Where Tandem is headed
146
188
 
147
- Tandem v1 covers the core loop well single user editing prose with Claude, with `.md`/`.txt`/`.html` round-trip and `.docx` review. A few directions on the radar for later releases:
189
+ Tandem v0.4.0 ships a native desktop app (macOS, Linux, Windows) alongside the existing npm CLI. A few directions on the radar for later releases:
148
190
 
149
- - **Progressive Web App** — install Tandem from the browser for a real app window, taskbar icon, and offline-capable shell.
150
191
  - **High-fidelity .docx round-trip** — current `.docx` support is review-only; LibreOffice-headless-based production export is planned so you can stay in Tandem through the final draft.
151
192
  - **Claude Desktop parity** — the MCP server already works with Claude Desktop; polish and documentation for a first-class experience there is in the works.
152
193
  - **Exportable annotated documents** — PDF (and eventually `.docx`) with annotations baked in, so you can share reviewed drafts outside Tandem.
@@ -158,12 +199,12 @@ See the full [Roadmap](docs/roadmap.md) and [Known Limitations](docs/roadmap.md#
158
199
  ## Documentation
159
200
 
160
201
  - **[User Guide](docs/user-guide.md)** — How to use Tandem: browser UI, annotations, chat, review mode, keyboard shortcuts
161
- - [MCP Tool Reference](docs/mcp-tools.md) — 30 MCP tools + channel API endpoints
202
+ - [MCP Tool Reference](docs/mcp-tools.md) — 31 MCP tools + channel API endpoints
162
203
  - [Architecture](docs/architecture.md) — System design, data flows, coordinate systems, channel push
163
- - [Workflows](docs/workflows.md) — Claude Code usage patterns: document review, cross-referencing, multi-model
204
+ - [Workflows](docs/workflows.md) — Claude Code usage patterns: text iteration, cross-referencing, multi-model
164
205
  - [Roadmap](docs/roadmap.md) — Phase 2+ roadmap, known issues, future extensions
165
- - [Design Decisions](docs/decisions.md) — ADR-001 through ADR-021
166
- - [Lessons Learned](docs/lessons-learned.md) — 31 implementation lessons
206
+ - [Design Decisions](docs/decisions.md) — ADR-001 through ADR-022
207
+ - [Lessons Learned](docs/lessons-learned.md) — 37 implementation lessons
167
208
 
168
209
  ## CLI Commands
169
210
 
@@ -246,5 +287,9 @@ On first run, `sample/welcome.md` auto-opens. If you've cleared sessions or dele
246
287
  | `npm test` | Run vitest (unit tests) |
247
288
  | `npm run test:e2e` | Run Playwright E2E tests |
248
289
  | `npm run test:e2e:ui` | Playwright UI mode |
290
+ | `cargo tauri dev` | Tauri desktop app (dev mode with hot-reload) |
291
+ | `cargo tauri build` | Tauri production build (installer output) |
292
+
293
+ **Tauri development** requires the [Rust toolchain](https://www.rust-lang.org/tools/install) and [Tauri CLI](https://v2.tauri.app/start/prerequisites/). Web-only development (`npm run dev:standalone`) does not require Rust.
249
294
 
250
295
  **Tech Stack:** React 19, Tiptap, Vite, TypeScript | Node.js, Hocuspocus (Yjs WebSocket), MCP SDK, Express | Yjs (CRDT), y-prosemirror | mammoth.js (.docx), unified/remark (.md)