tandem-editor 0.6.3 → 0.7.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.
- package/CHANGELOG.md +389 -32
- package/dist/channel/index.js +41 -7
- package/dist/channel/index.js.map +1 -1
- package/dist/cli/index.js +334 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/monitor/index.js +23 -2
- package/dist/monitor/index.js.map +1 -1
- package/dist/server/index.js +787 -392
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,22 +5,379 @@ 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]
|
|
8
|
+
## \[Unreleased]
|
|
9
9
|
|
|
10
|
-
## [0.
|
|
10
|
+
## \[0.7.0] - 2026-04-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Auth token storage** — on first boot the server generates a 32-byte base64url token and persists it to the platform data directory (`%LOCALAPPDATA%\tandem\Data\auth-token` on Windows, `~/.local/share/tandem/auth-token` on Linux, `~/Library/Application Support/tandem/auth-token` on macOS). Subsequent boots reuse the token. First-boot race is protected by `O_EXCL` file creation. Tauri mode receives the token via `TANDEM_AUTH_TOKEN` env before sidecar spawn and never regenerates.
|
|
15
|
+
- **Auth middleware** — non-loopback MCP and API requests require `Authorization: Bearer <token>`. Loopback connections (`127.0.0.1`, `::1`, `::ffff:127.0.0.1`) remain exempt, preserving zero-config Claude Code usage. Token comparison uses SHA-256 on both sides before `crypto.timingSafeEqual` to eliminate the length oracle. Rate-limiting (5 attempts / 60 s) keyed by IPv4 address or IPv6 `/64` prefix with LRU eviction; Authorization headers are redacted from all rejection logs.
|
|
16
|
+
- **`TANDEM_BIND_HOST` bind-mode selection** — MCP HTTP server binds to `127.0.0.1` by default; set `TANDEM_BIND_HOST=0.0.0.0` (or a specific LAN IP) to expose Tandem on the local network. Hocuspocus WebSocket always stays loopback. Non-loopback bind without a token file exits 1 with guidance; `TANDEM_ALLOW_UNAUTHENTICATED_LAN=1` is the escape hatch. Multi-homed machines require `TANDEM_LAN_IP` to be set explicitly.
|
|
17
|
+
- **`tandem rotate-token`** — new CLI subcommand that atomically regenerates the auth token, notifies the running server to open a 60-second grace window for in-flight sessions, and re-runs `tandem setup` across all detected MCP config files. Prints old and new token fingerprints (first 8 hex chars of SHA-256). Refuses rotation when `TANDEM_AUTH_TOKEN` is set in the environment (Tauri mode).
|
|
18
|
+
- **Token forwarding in stdio bridge, monitor, and channel sidecars** — `tandem mcp-stdio`, `tandem monitor`, and the channel sidecar now forward `TANDEM_AUTH_TOKEN` as `Authorization: Bearer` on upstream HTTP calls. Malformed tokens (empty, `Bearer`-prefixed, < 32 chars, non-URL-safe) exit 1 with a specific message.
|
|
19
|
+
- **OAuth protected-resource metadata** — `/.well-known/oauth-protected-resource/mcp` now declares `bearer_methods_supported: ["header"]` and a literal-`localhost` `resource` field per RFC 9728.
|
|
20
|
+
- **`/health` session-presence guard** — `hasSession` is omitted from `/health` responses on non-loopback requests, preventing session-presence leakage on LAN binds.
|
|
21
|
+
|
|
22
|
+
### Security
|
|
23
|
+
|
|
24
|
+
- Loopback detection keys off `req.socket.remoteAddress` exclusively — `Host` header is never trusted for the loopback bypass decision.
|
|
25
|
+
- Fail-closed on LAN bind: `TANDEM_BIND_HOST=0.0.0.0` without a token file exits 1; the server never auto-generates a token and proceeds silently.
|
|
26
|
+
- `crypto.randomBytes` failure or non-writable data directory → server exits 1; no silent fallback.
|
|
27
|
+
|
|
28
|
+
## \[0.6.4] - 2026-04-20
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **Flaky layout-switch E2E test (#281)** — `toHaveCount` assertions on resize-handle locators lacked explicit timeouts, causing intermittent CI failures under load when React re-renders were slower than the default 5 s expectation. All 8 assertions now carry `{ timeout: 10_000 }`, and the missing `right-panel-resize-handle` absence assertion in the tabbed-layout block has been added.
|
|
33
|
+
- **Silent crashes in CLI entry points (#336)** — `src/cli/index.ts` and `src/channel/index.ts` lacked `process.once("uncaughtException")` / `process.once("unhandledRejection")` handlers. Uncaught throws in `tandem start`, `tandem setup`, and the Tauri channel sidecar exited silently with code 0, surfacing as "tools never appear" with no diagnostics. Both entries now write a labelled message to stderr and exit 1. The `uncaughtException` handler uses `err: unknown` with an `instanceof Error` guard so non-Error throws (strings, plain objects) produce the actual thrown value rather than `"undefined"`.
|
|
34
|
+
|
|
35
|
+
## \[0.6.3] - 2026-04-19
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **Annotation GC race on startup (#334)** — `cleanupOrphanedAnnotationFiles` previously ran as a `.then()` chain during boot, racing the boot-path doc opens. On upgrade paths where `sample/welcome.md` or `CHANGELOG.md` hadn't been opened in 30+ days, the GC could unlink the annotation file between read intent and the actual read, silently returning an empty doc. Now `await`-ed before all boot-path opens.
|
|
40
|
+
- **Settings Popover extends out of view (#306)** — centered the popover in the viewport with `transform: translate(-50%, -50%)` and added `maxHeight: calc(100vh - 32px)` + `overflowY: auto` so it is always fully visible and internally scrollable on short screens.
|
|
41
|
+
- **Dark-mode ****\*-bg**** tokens inconsistent (#307)** — `--tandem-success-bg` and `--tandem-warning-bg` in dark mode were hand-coded hex while `--tandem-error-bg` used `color-mix`. All three now use `color-mix(in srgb, var(--tandem-<semantic>) 15%, var(--tandem-surface))` for consistency with light-mode behavior.
|
|
42
|
+
- **stdio bridge silent-failure paths (#336 partial)** — three paths in `src/cli/mcp-stdio.ts` (preflight exit, `http.onclose`, `http.start()` TOCTOU) previously closed stdio without writing a JSON-RPC error, producing "tools never appear in Cowork" with no diagnostics. All three now synthesize `-32000` for any in-flight request ID before exit. Remaining #336 items (channel-shim tests, Windows npx smoke, nits) carry to v0.7.0.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- **Annotation module internals** — extracted `mergeMap<T>` helper (#324), promoted `UPLOAD_PREFIX` to shared constants (#327), centralized app-data dir resolution in `platform.ts` (#328), extracted `ReplyAuthorSchema`, trimmed module headers, and dropped unused `docContexts` map (#332). No user-facing behavior changes.
|
|
47
|
+
- **Annotation serialization upgrades legacy ****type**** values on write** (#329) — records with non-canonical `type` (`"suggestion"` / `"question"` / anything outside `highlight` / `comment` / `flag`) are now routed through `sanitizeAnnotation` during snapshot serialization, which rewrites them to `"comment"`. **One-way lossy migration:** users with legacy-type annotations will see `type` flip to `"comment"` on the next durable write for that document — the original distinction between `suggestion` and `question` is not recoverable.
|
|
48
|
+
- **migrateToV1**** reports drop counts** (#330) — `migrateToV1(raw)` now returns `{ doc, droppedAnnotations, droppedReplies }` so future production callers can surface lossy upgrades to users rather than silently discarding malformed records. No production caller exists yet; a follow-up will wire drop counts to `npm run doctor` or a toast when the first caller lands.
|
|
49
|
+
|
|
50
|
+
### Internal
|
|
51
|
+
|
|
52
|
+
- Test coverage: `pickWinner`, `SerializedRelPos` edges, UNC paths, upload-path edges (#331); `wireAnnotationStore` perf baseline at 500/1000/5000 annotations (#335).
|
|
53
|
+
- Test sweep: stale hex color refs cleaned up post-PR #303 (#309).
|
|
54
|
+
- Accessibility: forced-colors fallback audit on PR #303 annotation surfaces (#311).
|
|
55
|
+
- CI: typecheck / lint / tests now gate on all PRs regardless of base branch; dropped unused `baseUrl` from `tsconfig.server.json` (#310).
|
|
56
|
+
|
|
57
|
+
## \[0.6.2] - 2026-04-16
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **Plugin stdio entries crash-loop on Windows** — `tandem-editor@0.6.1`'s published `package.json` shipped `"workspaces": ["packages/*"]`, a dev-only field for the vestigial `packages/tandem-doc/` alias stub. On Windows with Node 24 + npm 11, the presence of `workspaces` in an installed consumer package caused `npx -y tandem-editor …` to fail with `ERR_UNSUPPORTED_ESM_URL_SCHEME` (the bin path was handed to the ESM loader as a raw `c:\…` string instead of a `file://` URL). Claude Desktop's plugin loader spawns the stdio entries via `npx -y`, so both `tandem` and `tandem-channel` crash-exited before any user code ran, manifesting in Cowork sessions as entries that flapped "connecting → gone" and never surfaced `tandem_*` tools. Removed the unused `packages/tandem-doc/` directory and the `workspaces` field; direct `node dist/cli/index.js` invocation was never affected, so the Tauri desktop app's bundled sidecar was fine and only the npm-tarball/`npx` path needed the fix.
|
|
62
|
+
|
|
63
|
+
## \[0.6.1] - 2026-04-15
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- **Tauri desktop app fails to start** — `src/cli/skill-content.ts` reads `skills/tandem/SKILL.md` at module-init via `readFileSync`, and `src/server/mcp/api-routes.ts` transitively imports it, so the bundled sidecar server crashed on startup with `ENOENT: skills/tandem/SKILL.md`. The `skills/` directory was never declared in `src-tauri/tauri.conf.json` bundle resources (latent since the v0.5.1 refactor to read SKILL.md at runtime). Add `"../skills/": "skills/"` so the sidecar's relative path resolution matches the npm-install layout. npm-published 0.6.0 was unaffected because `skills/` ships in the npm tarball via `package.json` `files`.
|
|
68
|
+
|
|
69
|
+
## \[0.6.0] - 2026-04-15
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **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`.
|
|
74
|
+
- `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.
|
|
75
|
+
- **Settings expansion** — Settings popover grows from layout/dwell/authorship into a fuller preferences surface:
|
|
76
|
+
- Ctrl+, / Cmd+, hotkey (AZERTY/QWERTZ/IME-safe, survives non-QWERTY layouts)
|
|
77
|
+
- Display Name field, synced live with the StatusBar via a shared `useUserName` hook
|
|
78
|
+
- Reduce Motion toggle (JS-gates all autoscroll paths; defaults to `prefers-reduced-motion`)
|
|
79
|
+
- Text Size S/M/L for editor reading density (browser zoom remains the WCAG 1.4.4 path)
|
|
80
|
+
- Theme Light/Dark/System (CSS custom-property token system on `<html data-theme>` with `forced-colors` support for Windows High Contrast)
|
|
81
|
+
- 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
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- 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.
|
|
86
|
+
- Settings heading renamed "Layout Settings" → "Settings"
|
|
87
|
+
- Settings popover hardcoded hex values swapped to CSS tokens (remaining components will migrate in a follow-up)
|
|
88
|
+
- `shutdownForTests` renamed to `shutdownMonitor` (test-only alias kept for backward compatibility)
|
|
89
|
+
- `refreshMode` IIFE now wrapped in an outer `.catch` to keep future synchronous throws off the hot path
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
- **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.
|
|
94
|
+
- **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.
|
|
95
|
+
- **/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.
|
|
96
|
+
- **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.
|
|
97
|
+
- **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.
|
|
98
|
+
- **Defensive exit on monitor fallthrough** — the retry loop exits 1 if it ever terminates without hitting the explicit exhaustion path.
|
|
99
|
+
|
|
100
|
+
## \[0.5.1] - 2026-04-13
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- **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`.
|
|
105
|
+
- **--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.
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- `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`.
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- **Windows update failure** — sidecar is now killed before the NSIS installer runs, preventing "Error opening file for writing: node-sidecar.exe" during updates
|
|
114
|
+
- **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.
|
|
115
|
+
- **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.
|
|
116
|
+
- **Exponential backoff on reconnect** — monitor reconnects use 2s/4s/8s/16s/30s backoff instead of a fixed 2s delay.
|
|
117
|
+
- **SIGINT/SIGTERM clears awareness** — monitor posts a final `clearAwareness` before exit so the "Claude is active" indicator doesn't hang in the browser.
|
|
118
|
+
- **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.
|
|
119
|
+
- **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.
|
|
120
|
+
- **SKILL.md corrected** — `question` annotation guidance now uses `type === 'comment' && directedAt === 'claude' && author === 'user'`; all 5 highlight colors listed (yellow, red, green, blue, purple).
|
|
121
|
+
|
|
122
|
+
## \[0.5.0] - 2026-04-13
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
|
|
126
|
+
- **Authorship tracking** — Y.Map overlay marks text as user-written or Claude-written, with text-color styling (blue for user, orange for Claude) (#190)
|
|
127
|
+
- **Threaded annotation replies** — reply to annotations with back-and-forth conversation threads (#187)
|
|
128
|
+
- **Claude cursor decoration** — character-level cursor shows where Claude is editing in real time (#209)
|
|
129
|
+
- **Auto-save** — documents save automatically on change; Ctrl+S triggers immediate manual save (#272)
|
|
130
|
+
- **Text zoom** — keyboard shortcuts (Ctrl+=/Ctrl+-) for adjusting text size in the Tauri desktop app (#273)
|
|
131
|
+
- **Three-panel default layout** — editor, side panel, and chat visible by default (#264)
|
|
132
|
+
- **Selection event suppression** — selection events only fire after a chat message is sent, reducing noise (#270)
|
|
133
|
+
- V1.0 release plan added to roadmap (#279)
|
|
134
|
+
|
|
135
|
+
### Fixed
|
|
136
|
+
|
|
137
|
+
- Session persistence, tab bar horizontal scrollbar, and tab cycling keyboard shortcuts (#278)
|
|
138
|
+
- Authorship styling uses text color instead of background highlight; reopen sync corrected
|
|
139
|
+
- Annotation replies renamed from Acknowledge/Dismiss to Accept/Reject for clarity
|
|
140
|
+
|
|
141
|
+
### Changed
|
|
142
|
+
|
|
143
|
+
- Pinned Hocuspocus and Y.js dependency versions to prevent upstream breakage (#271)
|
|
144
|
+
- EOL normalizer added to lint-staged for .yml and .md files (#263)
|
|
145
|
+
- Lessons learned applied to codebase and tooling (#280)
|
|
146
|
+
|
|
147
|
+
## \[0.4.0] - 2026-04-12
|
|
148
|
+
|
|
149
|
+
### Added
|
|
150
|
+
|
|
151
|
+
- Tauri v2 desktop app wrapping the existing web editor (macOS, Linux, Windows)
|
|
152
|
+
- System tray with menu: Open Editor, Setup Claude, Check for Updates, About, Quit
|
|
153
|
+
- Single-instance detection — second launch focuses the existing window instead of opening a duplicate
|
|
154
|
+
- Node.js sidecar lifecycle: auto-spawn on startup, health polling, crash restart with exponential backoff
|
|
155
|
+
- Auto-updater checks on launch and every 8h; manual check available via tray menu "Check for Updates"
|
|
156
|
+
- Cross-platform CI release workflow (macOS arm64/x64, Linux x64, Windows x64) with GitHub Releases
|
|
157
|
+
- Window state persistence — position and size remembered across sessions
|
|
158
|
+
- Sample file copied to writable data directory on first run (supports read-only app bundles)
|
|
159
|
+
- Self-signed code signing for Windows builds in CI
|
|
160
|
+
- MCP setup auto-configuration on launch — writes Claude Code/Desktop config without manual `tandem setup`
|
|
161
|
+
|
|
162
|
+
### Fixed
|
|
163
|
+
|
|
164
|
+
- Accept `tauri.localhost` origin in WebSocket and CORS checks so the production WebView can connect
|
|
165
|
+
- Strip Windows `\\?\` extended-length path prefix returned by Tauri path APIs before passing to Node
|
|
166
|
+
- Sidecar binary name resolution corrected for Tauri's platform-specific naming convention
|
|
167
|
+
- Self-contained JS bundles via tsup `noExternal` so Tauri doesn't require `node_modules` at runtime
|
|
168
|
+
- Poll for port release before restarting after update install, preventing a startup race condition
|
|
169
|
+
- Surface last HTTP error in health-poll timeout diagnostics for easier debugging
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
|
|
173
|
+
- Updater-unavailable log downgraded from error to debug (reduces noise in dev builds without updater keys)
|
|
174
|
+
- Unhandled sidecar events are now logged instead of silently dropped
|
|
175
|
+
- Warn when `sample/` directory is missing in release builds
|
|
176
|
+
- CI: fail build when updater signing key secret is absent
|
|
177
|
+
- CI: summary job catches partial platform build failures rather than reporting false success
|
|
178
|
+
|
|
179
|
+
## \[0.3.2] - 2026-04-12
|
|
180
|
+
|
|
181
|
+
### Changed
|
|
182
|
+
|
|
183
|
+
- **Annotation type unification:** Three semantically identical types (`comment`, `suggestion`, `question`) collapsed into a single `comment` type with optional `suggestedText` and `directedAt` fields. `AnnotationTypeSchema` reduced from 5 values to 3: `highlight`, `comment`, `flag`. (#193, #245, #255)
|
|
184
|
+
- **Toolbar:** Three annotation buttons (Comment, Suggest, Ask Claude) replaced with a single Comment button with "Replace" and "@Claude" toggles (#193)
|
|
185
|
+
- **Side panel filters:** "Suggestions" → "With replacement", "Questions" → "For Claude" (#193)
|
|
186
|
+
- **sanitizeAnnotation()**** moved to ****src/shared/sanitize.ts** — now available to both server and client code. Client-side Y.Map reads are sanitized to handle legacy session data. (#255)
|
|
187
|
+
|
|
188
|
+
### Added
|
|
189
|
+
|
|
190
|
+
- Link (Ctrl+K), Horizontal Rule, and Code Block buttons in the formatting toolbar (#204)
|
|
191
|
+
- Replacement cards show a visual diff — original text in red strikethrough → replacement in green (#195)
|
|
192
|
+
- Undo countdown progress bar — a shrinking indicator shows the 10-second undo window (#196)
|
|
193
|
+
- Review mode shortcut hints (Y / N / ↑↓ / Z) shown below the Review button (#200)
|
|
194
|
+
- Chat anchor previews expand on hover to show full text (#198)
|
|
195
|
+
- `disabledTitle` prop on toolbar buttons — annotation buttons show "Select text first" when no text is selected (#197)
|
|
196
|
+
- Explicit ✕ close button on the highlight color picker (#203)
|
|
197
|
+
- `tandem_comment` now accepts optional `suggestedText` and `directedAt` parameters (#193)
|
|
198
|
+
- `sanitizeAnnotation()` normalizes legacy `suggestion`/`question` entries at read boundaries — permanent migration for historical session data (#193)
|
|
199
|
+
- Exhaustive type switch in `buildDecorations` catches unhandled annotation types at compile time (#255)
|
|
200
|
+
- 8 new tests covering MCP tool params, sanitization edge cases, and legacy migration paths (#255)
|
|
201
|
+
|
|
202
|
+
### Fixed
|
|
203
|
+
|
|
204
|
+
- Toolbar wraps to a second row on narrow windows instead of overflowing; inline inputs shrink responsively (#192)
|
|
205
|
+
- Edit button on annotation cards now shows a visible "✎ Edit" label instead of icon-only (#201)
|
|
206
|
+
- Client-side legacy annotations (from pre-0.3.2 sessions) no longer render as invisible decorations or display raw JSON (#255)
|
|
207
|
+
- `sanitizeAnnotation` no longer drops `textSnapshot: ""` or `editedAt: 0` via falsy-check bug (#255)
|
|
208
|
+
- Event queue observer no longer silently dies if `sanitizeAnnotation` throws (#255)
|
|
209
|
+
- `handleEdit` catch-block no longer corrupts annotation data on JSON parse failure (#255)
|
|
210
|
+
|
|
211
|
+
### Deprecated
|
|
212
|
+
|
|
213
|
+
- `tandem_suggest` MCP tool — use `tandem_comment` with `suggestedText` parameter instead (#193)
|
|
214
|
+
|
|
215
|
+
### Removed
|
|
216
|
+
|
|
217
|
+
- **MCP wire change:** Removed unused `"overlay"` annotation kind from `AnnotationTypeSchema`. External clients sending `type: "overlay"` will now receive a Zod validation error. (#249)
|
|
218
|
+
- **MCP wire change:** `suggestion` and `question` annotation types removed from `AnnotationTypeSchema`. Use `comment` with `suggestedText` or `directedAt` fields. Legacy data is migrated automatically via `sanitizeAnnotation()`. (#193)
|
|
219
|
+
|
|
220
|
+
## \[0.3.0] - 2026-04-07
|
|
221
|
+
|
|
222
|
+
### Wave 4: Notification & Interruption Redesign
|
|
223
|
+
|
|
224
|
+
- **Solo/Tandem mode** replaces All/Urgent/Paused interruption controls (#207, #226)
|
|
225
|
+
- **Dwell-time selection events** — selections fire after 1s hold (#188)
|
|
226
|
+
- **Configurable layout** — tabbed or three-panel, with settings popover (#206)
|
|
227
|
+
- **Click-to-navigate** — click annotated text to jump to annotation card
|
|
228
|
+
- **Tab badges** — notification counts on inactive panel tabs
|
|
229
|
+
- **Skill-directed response routing** — Claude responds in chat panel, not terminal
|
|
230
|
+
- Review banner replaced with per-annotation toasts (#208, landed earlier)
|
|
231
|
+
- `Y_MAP_MODE` constant, Zod validation for mode reads, error logging in channel event bridge
|
|
232
|
+
- 894 tests passing
|
|
233
|
+
|
|
234
|
+
## \[0.2.12] - 2026-04-06
|
|
235
|
+
|
|
236
|
+
### Added
|
|
237
|
+
|
|
238
|
+
- Undo/redo toolbar buttons powered by Y.js UndoManager — tracks document edits with proper CRDT-aware undo scoping (#189, #210)
|
|
239
|
+
- Adjustable editor content width toggle — switch between comfortable and full-width layouts, preference persists in localStorage (#185, #205)
|
|
240
|
+
- SVG icons for unordered list, ordered list, and blockquote toolbar buttons, replacing plain text labels (#194)
|
|
241
|
+
- Automated npm publishing via GitHub Actions with OIDC trusted publisher (tokenless)
|
|
242
|
+
|
|
243
|
+
### Fixed
|
|
244
|
+
|
|
245
|
+
- Guard all localStorage access with try-catch for private/disabled browser storage modes; reset scroll position on annotation filter clear (#212, #202)
|
|
246
|
+
|
|
247
|
+
## \[0.2.11] - 2026-04-06
|
|
248
|
+
|
|
249
|
+
### Added
|
|
250
|
+
|
|
251
|
+
- Auto-reload documents when files change on disk — Tandem detects external edits (e.g., Claude's Edit tool) via `fs.watch`, reloads content, and preserves existing annotations (#175)
|
|
252
|
+
- File watcher module with 500ms debounce and self-write suppression (prevents reload loops when Tandem saves)
|
|
253
|
+
- Toast notification when a document is reloaded from disk
|
|
254
|
+
- Runtime warning when `onDocSwapped` callback is missing during Hocuspocus doc swap (defensive guard for #178 audit)
|
|
255
|
+
- 28 new tests: observer reattachment, CTRL\_ROOM lifecycle, buffer cap, file watcher debounce/suppress, annotation-preserving reload
|
|
256
|
+
|
|
257
|
+
### Fixed
|
|
258
|
+
|
|
259
|
+
- Dead CRDT `relRange` handling — `refreshRange` now strips broken CRDT anchors and re-anchors from flat offsets instead of leaving annotations permanently stuck with non-functional RelativePositions (#175)
|
|
260
|
+
- Buffer cap test was previously a no-op (empty loop body) — now actually exercises the event queue buffer (#178)
|
|
261
|
+
|
|
262
|
+
### Changed
|
|
263
|
+
|
|
264
|
+
- CLAUDE.md gotcha for Hocuspocus doc replacement updated to document the automatic `onDocSwapped` callback lifecycle (#178)
|
|
265
|
+
|
|
266
|
+
## \[0.2.10] - 2026-04-05
|
|
267
|
+
|
|
268
|
+
### Added
|
|
269
|
+
|
|
270
|
+
- Resizable side panel — drag to resize between 200–600px, width persists in localStorage
|
|
271
|
+
- Accessibility: ARIA labels on annotation highlights (type-specific), annotation cards (`role="listitem"`, `aria-current`), annotation list (`role="list"`), review mode button (`aria-pressed`), live region for pending count and review progress
|
|
272
|
+
|
|
273
|
+
### Fixed
|
|
274
|
+
|
|
275
|
+
- Flaky session tests — each test file now uses an isolated temp directory via `vi.mock`, eliminating cross-file race conditions (#177)
|
|
276
|
+
- Session file writes use atomic rename with retry on Windows EPERM/EACCES (#173)
|
|
277
|
+
|
|
278
|
+
### Changed
|
|
279
|
+
|
|
280
|
+
- `atomicWrite()` extracted as shared helper in session manager — consolidates duplicate write-tmp-rename logic with exponential backoff retry
|
|
281
|
+
|
|
282
|
+
## \[0.2.9] - 2026-04-05
|
|
283
|
+
|
|
284
|
+
### Fixed
|
|
285
|
+
|
|
286
|
+
- Changelog tab no longer disappears after upgrade — version check and sample/welcome.md now open before servers start, preventing CRDT merge races with stale browser tabs
|
|
287
|
+
- Tutorial annotation injection errors now get their own log message instead of being misattributed as file-open failures
|
|
288
|
+
|
|
289
|
+
## \[0.2.8] - 2026-04-05
|
|
290
|
+
|
|
291
|
+
### Added
|
|
292
|
+
|
|
293
|
+
- CHANGELOG.md opens as the active tab on first startup after an npm update
|
|
294
|
+
- `checkVersionChange` helper tracks version transitions via `last-seen-version` file
|
|
295
|
+
- CHANGELOG.md now ships in the npm package
|
|
296
|
+
|
|
297
|
+
## \[0.2.7] - 2026-04-05
|
|
298
|
+
|
|
299
|
+
### Fixed
|
|
300
|
+
|
|
301
|
+
- Force-reload (`tandem_open` with `force: true`) now clears Y.Doc in-place instead of destroying the Hocuspocus room — sidebar, observers, and connections survive
|
|
302
|
+
- TOCTOU fix: session deletion moved after successful reload transaction
|
|
303
|
+
- Observer ownership table corrected in architecture docs
|
|
304
|
+
|
|
305
|
+
### Added
|
|
306
|
+
|
|
307
|
+
- 4 new tests for force-reload (annotation clearing, awareness clearing, .txt reload, metadata)
|
|
308
|
+
|
|
309
|
+
## \[0.2.6] - 2026-04-05
|
|
310
|
+
|
|
311
|
+
### Fixed
|
|
312
|
+
|
|
313
|
+
- Demo script rewritten to be self-referential for recording
|
|
314
|
+
- Observer ownership documentation added to architecture.md
|
|
315
|
+
|
|
316
|
+
## \[0.2.5] - 2026-04-05
|
|
317
|
+
|
|
318
|
+
### Fixed
|
|
319
|
+
|
|
320
|
+
- `tandem setup` Claude Code MCP config path updated
|
|
321
|
+
|
|
322
|
+
## \[0.2.4] - 2026-04-05
|
|
323
|
+
|
|
324
|
+
### Fixed
|
|
325
|
+
|
|
326
|
+
- Security audit findings (DNS rebinding, CORS, input validation)
|
|
327
|
+
|
|
328
|
+
## \[0.2.3] - 2026-04-05
|
|
329
|
+
|
|
330
|
+
### Fixed
|
|
331
|
+
|
|
332
|
+
- `tandem setup` now writes Claude Code MCP config to `~/.claude.json` instead of `~/.claude/mcp_settings.json`, which Claude Code no longer reads
|
|
333
|
+
|
|
334
|
+
## \[0.2.2] - 2025-04-05
|
|
335
|
+
|
|
336
|
+
### Fixed
|
|
337
|
+
|
|
338
|
+
- Silent failure review findings
|
|
339
|
+
|
|
340
|
+
## \[0.2.1] - 2025-04-05
|
|
341
|
+
|
|
342
|
+
### Fixed
|
|
343
|
+
|
|
344
|
+
- Full security audit — 25 findings across 7 categories (#172)
|
|
345
|
+
|
|
346
|
+
## \[0.2.0] - 2025-04-04
|
|
347
|
+
|
|
348
|
+
### Added
|
|
349
|
+
|
|
350
|
+
- Initial public release on npm as `tandem-editor`
|
|
351
|
+
- 30 MCP tools for collaborative document editing
|
|
352
|
+
- Multi-document tabs with CRDT-anchored annotations
|
|
353
|
+
- Chat sidebar with real-time channel push
|
|
354
|
+
- Support for .md, .docx, .txt, .html files
|
|
355
|
+
- `tandem` CLI with `setup` and `start` commands
|
|
356
|
+
- Claude Code skill auto-installation
|
|
357
|
+
|
|
358
|
+
# Changelog
|
|
359
|
+
|
|
360
|
+
All notable changes to Tandem will be documented in this file.
|
|
361
|
+
|
|
362
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
363
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
364
|
+
|
|
365
|
+
## \[Unreleased]
|
|
366
|
+
|
|
367
|
+
## \[0.6.3] - 2026-04-19
|
|
11
368
|
|
|
12
369
|
### Fixed
|
|
13
370
|
|
|
14
371
|
- **Annotation GC race on startup (#334)** — `cleanupOrphanedAnnotationFiles` previously ran as a `.then()` chain during boot, racing the boot-path doc opens. On upgrade paths where `sample/welcome.md` or `CHANGELOG.md` hadn't been opened in 30+ days, the GC could unlink the annotation file between read intent and the actual read, silently returning an empty doc. Now `await`-ed before all boot-path opens.
|
|
15
372
|
- **Settings Popover extends out of view (#306)** — centered the popover in the viewport with `transform: translate(-50%, -50%)` and added `maxHeight: calc(100vh - 32px)` + `overflowY: auto` so it is always fully visible and internally scrollable on short screens.
|
|
16
|
-
- **Dark-mode
|
|
373
|
+
- **Dark-mode ****\*-bg**** tokens inconsistent (#307)** — `--tandem-success-bg` and `--tandem-warning-bg` in dark mode were hand-coded hex while `--tandem-error-bg` used `color-mix`. All three now use `color-mix(in srgb, var(--tandem-<semantic>) 15%, var(--tandem-surface))` for consistency with light-mode behavior.
|
|
17
374
|
- **stdio bridge silent-failure paths (#336 partial)** — three paths in `src/cli/mcp-stdio.ts` (preflight exit, `http.onclose`, `http.start()` TOCTOU) previously closed stdio without writing a JSON-RPC error, producing "tools never appear in Cowork" with no diagnostics. All three now synthesize `-32000` for any in-flight request ID before exit. Remaining #336 items (channel-shim tests, Windows npx smoke, nits) carry to v0.7.0.
|
|
18
375
|
|
|
19
376
|
### Changed
|
|
20
377
|
|
|
21
378
|
- **Annotation module internals** — extracted `mergeMap<T>` helper (#324), promoted `UPLOAD_PREFIX` to shared constants (#327), centralized app-data dir resolution in `platform.ts` (#328), extracted `ReplyAuthorSchema`, trimmed module headers, and dropped unused `docContexts` map (#332). No user-facing behavior changes.
|
|
22
|
-
- **Annotation serialization upgrades legacy
|
|
23
|
-
-
|
|
379
|
+
- **Annotation serialization upgrades legacy ****type**** values on write** (#329) — records with non-canonical `type` (`"suggestion"` / `"question"` / anything outside `highlight` / `comment` / `flag`) are now routed through `sanitizeAnnotation` during snapshot serialization, which rewrites them to `"comment"`. **One-way lossy migration:** users with legacy-type annotations will see `type` flip to `"comment"` on the next durable write for that document — the original distinction between `suggestion` and `question` is not recoverable.
|
|
380
|
+
- **migrateToV1**** reports drop counts** (#330) — `migrateToV1(raw)` now returns `{ doc, droppedAnnotations, droppedReplies }` so future production callers can surface lossy upgrades to users rather than silently discarding malformed records. No production caller exists yet; a follow-up will wire drop counts to `npm run doctor` or a toast when the first caller lands.
|
|
24
381
|
|
|
25
382
|
### Internal
|
|
26
383
|
|
|
@@ -29,19 +386,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
29
386
|
- Accessibility: forced-colors fallback audit on PR #303 annotation surfaces (#311).
|
|
30
387
|
- CI: typecheck / lint / tests now gate on all PRs regardless of base branch; dropped unused `baseUrl` from `tsconfig.server.json` (#310).
|
|
31
388
|
|
|
32
|
-
## [0.6.2] - 2026-04-16
|
|
389
|
+
## \[0.6.2] - 2026-04-16
|
|
33
390
|
|
|
34
391
|
### Fixed
|
|
35
392
|
|
|
36
393
|
- **Plugin stdio entries crash-loop on Windows** — `tandem-editor@0.6.1`'s published `package.json` shipped `"workspaces": ["packages/*"]`, a dev-only field for the vestigial `packages/tandem-doc/` alias stub. On Windows with Node 24 + npm 11, the presence of `workspaces` in an installed consumer package caused `npx -y tandem-editor …` to fail with `ERR_UNSUPPORTED_ESM_URL_SCHEME` (the bin path was handed to the ESM loader as a raw `c:\…` string instead of a `file://` URL). Claude Desktop's plugin loader spawns the stdio entries via `npx -y`, so both `tandem` and `tandem-channel` crash-exited before any user code ran, manifesting in Cowork sessions as entries that flapped "connecting → gone" and never surfaced `tandem_*` tools. Removed the unused `packages/tandem-doc/` directory and the `workspaces` field; direct `node dist/cli/index.js` invocation was never affected, so the Tauri desktop app's bundled sidecar was fine and only the npm-tarball/`npx` path needed the fix.
|
|
37
394
|
|
|
38
|
-
## [0.6.1] - 2026-04-15
|
|
395
|
+
## \[0.6.1] - 2026-04-15
|
|
39
396
|
|
|
40
397
|
### Fixed
|
|
41
398
|
|
|
42
399
|
- **Tauri desktop app fails to start** — `src/cli/skill-content.ts` reads `skills/tandem/SKILL.md` at module-init via `readFileSync`, and `src/server/mcp/api-routes.ts` transitively imports it, so the bundled sidecar server crashed on startup with `ENOENT: skills/tandem/SKILL.md`. The `skills/` directory was never declared in `src-tauri/tauri.conf.json` bundle resources (latent since the v0.5.1 refactor to read SKILL.md at runtime). Add `"../skills/": "skills/"` so the sidecar's relative path resolution matches the npm-install layout. npm-published 0.6.0 was unaffected because `skills/` ships in the npm tarball via `package.json` `files`.
|
|
43
400
|
|
|
44
|
-
## [0.6.0] - 2026-04-15
|
|
401
|
+
## \[0.6.0] - 2026-04-15
|
|
45
402
|
|
|
46
403
|
### Added
|
|
47
404
|
|
|
@@ -65,19 +422,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
65
422
|
|
|
66
423
|
### Fixed
|
|
67
424
|
|
|
68
|
-
- **Monitor preserves last-known
|
|
425
|
+
- **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.
|
|
69
426
|
- **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.
|
|
70
|
-
-
|
|
427
|
+
- **/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.
|
|
71
428
|
- **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.
|
|
72
429
|
- **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.
|
|
73
430
|
- **Defensive exit on monitor fallthrough** — the retry loop exits 1 if it ever terminates without hitting the explicit exhaustion path.
|
|
74
431
|
|
|
75
|
-
## [0.5.1] - 2026-04-13
|
|
432
|
+
## \[0.5.1] - 2026-04-13
|
|
76
433
|
|
|
77
434
|
### Added
|
|
78
435
|
|
|
79
436
|
- **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`.
|
|
80
|
-
-
|
|
437
|
+
- **--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.
|
|
81
438
|
|
|
82
439
|
### Changed
|
|
83
440
|
|
|
@@ -91,10 +448,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
91
448
|
- **Exponential backoff on reconnect** — monitor reconnects use 2s/4s/8s/16s/30s backoff instead of a fixed 2s delay.
|
|
92
449
|
- **SIGINT/SIGTERM clears awareness** — monitor posts a final `clearAwareness` before exit so the "Claude is active" indicator doesn't hang in the browser.
|
|
93
450
|
- **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.
|
|
94
|
-
- **SSE parse errors don't advance
|
|
451
|
+
- **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.
|
|
95
452
|
- **SKILL.md corrected** — `question` annotation guidance now uses `type === 'comment' && directedAt === 'claude' && author === 'user'`; all 5 highlight colors listed (yellow, red, green, blue, purple).
|
|
96
453
|
|
|
97
|
-
## [0.5.0] - 2026-04-13
|
|
454
|
+
## \[0.5.0] - 2026-04-13
|
|
98
455
|
|
|
99
456
|
### Added
|
|
100
457
|
|
|
@@ -119,7 +476,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
119
476
|
- EOL normalizer added to lint-staged for .yml and .md files (#263)
|
|
120
477
|
- Lessons learned applied to codebase and tooling (#280)
|
|
121
478
|
|
|
122
|
-
## [0.4.0] - 2026-04-12
|
|
479
|
+
## \[0.4.0] - 2026-04-12
|
|
123
480
|
|
|
124
481
|
### Added
|
|
125
482
|
|
|
@@ -151,14 +508,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
151
508
|
- CI: fail build when updater signing key secret is absent
|
|
152
509
|
- CI: summary job catches partial platform build failures rather than reporting false success
|
|
153
510
|
|
|
154
|
-
## [0.3.2] - 2026-04-12
|
|
511
|
+
## \[0.3.2] - 2026-04-12
|
|
155
512
|
|
|
156
513
|
### Changed
|
|
157
514
|
|
|
158
515
|
- **Annotation type unification:** Three semantically identical types (`comment`, `suggestion`, `question`) collapsed into a single `comment` type with optional `suggestedText` and `directedAt` fields. `AnnotationTypeSchema` reduced from 5 values to 3: `highlight`, `comment`, `flag`. (#193, #245, #255)
|
|
159
516
|
- **Toolbar:** Three annotation buttons (Comment, Suggest, Ask Claude) replaced with a single Comment button with "Replace" and "@Claude" toggles (#193)
|
|
160
517
|
- **Side panel filters:** "Suggestions" → "With replacement", "Questions" → "For Claude" (#193)
|
|
161
|
-
-
|
|
518
|
+
- **sanitizeAnnotation()**** moved to ****src/shared/sanitize.ts** — now available to both server and client code. Client-side Y.Map reads are sanitized to handle legacy session data. (#255)
|
|
162
519
|
|
|
163
520
|
### Added
|
|
164
521
|
|
|
@@ -192,7 +549,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
192
549
|
- **MCP wire change:** Removed unused `"overlay"` annotation kind from `AnnotationTypeSchema`. External clients sending `type: "overlay"` will now receive a Zod validation error. (#249)
|
|
193
550
|
- **MCP wire change:** `suggestion` and `question` annotation types removed from `AnnotationTypeSchema`. Use `comment` with `suggestedText` or `directedAt` fields. Legacy data is migrated automatically via `sanitizeAnnotation()`. (#193)
|
|
194
551
|
|
|
195
|
-
## [0.3.0] - 2026-04-07
|
|
552
|
+
## \[0.3.0] - 2026-04-07
|
|
196
553
|
|
|
197
554
|
### Wave 4: Notification & Interruption Redesign
|
|
198
555
|
|
|
@@ -206,7 +563,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
206
563
|
- `Y_MAP_MODE` constant, Zod validation for mode reads, error logging in channel event bridge
|
|
207
564
|
- 894 tests passing
|
|
208
565
|
|
|
209
|
-
## [0.2.12] - 2026-04-06
|
|
566
|
+
## \[0.2.12] - 2026-04-06
|
|
210
567
|
|
|
211
568
|
### Added
|
|
212
569
|
|
|
@@ -219,7 +576,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
219
576
|
|
|
220
577
|
- Guard all localStorage access with try-catch for private/disabled browser storage modes; reset scroll position on annotation filter clear (#212, #202)
|
|
221
578
|
|
|
222
|
-
## [0.2.11] - 2026-04-06
|
|
579
|
+
## \[0.2.11] - 2026-04-06
|
|
223
580
|
|
|
224
581
|
### Added
|
|
225
582
|
|
|
@@ -227,7 +584,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
227
584
|
- File watcher module with 500ms debounce and self-write suppression (prevents reload loops when Tandem saves)
|
|
228
585
|
- Toast notification when a document is reloaded from disk
|
|
229
586
|
- Runtime warning when `onDocSwapped` callback is missing during Hocuspocus doc swap (defensive guard for #178 audit)
|
|
230
|
-
- 28 new tests: observer reattachment,
|
|
587
|
+
- 28 new tests: observer reattachment, CTRL\_ROOM lifecycle, buffer cap, file watcher debounce/suppress, annotation-preserving reload
|
|
231
588
|
|
|
232
589
|
### Fixed
|
|
233
590
|
|
|
@@ -238,7 +595,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
238
595
|
|
|
239
596
|
- CLAUDE.md gotcha for Hocuspocus doc replacement updated to document the automatic `onDocSwapped` callback lifecycle (#178)
|
|
240
597
|
|
|
241
|
-
## [0.2.10] - 2026-04-05
|
|
598
|
+
## \[0.2.10] - 2026-04-05
|
|
242
599
|
|
|
243
600
|
### Added
|
|
244
601
|
|
|
@@ -254,14 +611,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
254
611
|
|
|
255
612
|
- `atomicWrite()` extracted as shared helper in session manager — consolidates duplicate write-tmp-rename logic with exponential backoff retry
|
|
256
613
|
|
|
257
|
-
## [0.2.9] - 2026-04-05
|
|
614
|
+
## \[0.2.9] - 2026-04-05
|
|
258
615
|
|
|
259
616
|
### Fixed
|
|
260
617
|
|
|
261
618
|
- Changelog tab no longer disappears after upgrade — version check and sample/welcome.md now open before servers start, preventing CRDT merge races with stale browser tabs
|
|
262
619
|
- Tutorial annotation injection errors now get their own log message instead of being misattributed as file-open failures
|
|
263
620
|
|
|
264
|
-
## [0.2.8] - 2026-04-05
|
|
621
|
+
## \[0.2.8] - 2026-04-05
|
|
265
622
|
|
|
266
623
|
### Added
|
|
267
624
|
|
|
@@ -269,7 +626,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
269
626
|
- `checkVersionChange` helper tracks version transitions via `last-seen-version` file
|
|
270
627
|
- CHANGELOG.md now ships in the npm package
|
|
271
628
|
|
|
272
|
-
## [0.2.7] - 2026-04-05
|
|
629
|
+
## \[0.2.7] - 2026-04-05
|
|
273
630
|
|
|
274
631
|
### Fixed
|
|
275
632
|
|
|
@@ -281,44 +638,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
281
638
|
|
|
282
639
|
- 4 new tests for force-reload (annotation clearing, awareness clearing, .txt reload, metadata)
|
|
283
640
|
|
|
284
|
-
## [0.2.6] - 2026-04-05
|
|
641
|
+
## \[0.2.6] - 2026-04-05
|
|
285
642
|
|
|
286
643
|
### Fixed
|
|
287
644
|
|
|
288
645
|
- Demo script rewritten to be self-referential for recording
|
|
289
646
|
- Observer ownership documentation added to architecture.md
|
|
290
647
|
|
|
291
|
-
## [0.2.5] - 2026-04-05
|
|
648
|
+
## \[0.2.5] - 2026-04-05
|
|
292
649
|
|
|
293
650
|
### Fixed
|
|
294
651
|
|
|
295
652
|
- `tandem setup` Claude Code MCP config path updated
|
|
296
653
|
|
|
297
|
-
## [0.2.4] - 2026-04-05
|
|
654
|
+
## \[0.2.4] - 2026-04-05
|
|
298
655
|
|
|
299
656
|
### Fixed
|
|
300
657
|
|
|
301
658
|
- Security audit findings (DNS rebinding, CORS, input validation)
|
|
302
659
|
|
|
303
|
-
## [0.2.3] - 2026-04-05
|
|
660
|
+
## \[0.2.3] - 2026-04-05
|
|
304
661
|
|
|
305
662
|
### Fixed
|
|
306
663
|
|
|
307
664
|
- `tandem setup` now writes Claude Code MCP config to `~/.claude.json` instead of `~/.claude/mcp_settings.json`, which Claude Code no longer reads
|
|
308
665
|
|
|
309
|
-
## [0.2.2] - 2025-04-05
|
|
666
|
+
## \[0.2.2] - 2025-04-05
|
|
310
667
|
|
|
311
668
|
### Fixed
|
|
312
669
|
|
|
313
670
|
- Silent failure review findings
|
|
314
671
|
|
|
315
|
-
## [0.2.1] - 2025-04-05
|
|
672
|
+
## \[0.2.1] - 2025-04-05
|
|
316
673
|
|
|
317
674
|
### Fixed
|
|
318
675
|
|
|
319
676
|
- Full security audit — 25 findings across 7 categories (#172)
|
|
320
677
|
|
|
321
|
-
## [0.2.0] - 2025-04-04
|
|
678
|
+
## \[0.2.0] - 2025-04-04
|
|
322
679
|
|
|
323
680
|
### Added
|
|
324
681
|
|