tandem-editor 0.20.0 → 0.20.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tandem",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "Edit and iterate on documents with any MCP-capable AI. Claude is the default and best-supported client today.",
5
5
  "author": {
6
6
  "name": "Tandem"
@@ -11,14 +11,14 @@
11
11
  "mcpServers": {
12
12
  "tandem": {
13
13
  "command": "npx",
14
- "args": ["-y", "tandem-editor@0.20.0", "mcp-stdio"],
14
+ "args": ["-y", "tandem-editor@0.20.1", "mcp-stdio"],
15
15
  "env": {
16
16
  "TANDEM_URL": "http://127.0.0.1:3479"
17
17
  }
18
18
  },
19
19
  "tandem-channel": {
20
20
  "command": "npx",
21
- "args": ["-y", "tandem-editor@0.20.0", "channel"],
21
+ "args": ["-y", "tandem-editor@0.20.1", "channel"],
22
22
  "env": {
23
23
  "TANDEM_URL": "http://127.0.0.1:3479"
24
24
  }
@@ -28,7 +28,7 @@
28
28
  "monitors": [
29
29
  {
30
30
  "name": "tandem-events",
31
- "command": "npx -y tandem-editor@0.20.0 monitor",
31
+ "command": "npx -y tandem-editor@0.20.1 monitor",
32
32
  "description": "Tandem real-time document events (annotations, chat, selections)"
33
33
  }
34
34
  ]
package/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.20.1] - 2026-08-05
11
+
12
+ ### Fixed
13
+
14
+ - **"Restart Claude Code" no longer fails right after you install or update Tandem (#1282).** The button reported *"cwd must be an absolute path inside the user's home directory"* and restarted nothing. It restarts your AI in the folder of whatever document you have open, and Tandem opens two documents on your behalf — the changelog after an update, and the welcome document on a fresh install — both of which live inside the application itself rather than in your own files. Restarting there isn't allowed, so the request was refused outright. That made the failure specific to the two moments every desktop user passes through, which are exactly the moments someone is most likely to reach for a button labelled "Restart Claude Code". The folder is now treated as a preference rather than a requirement: if it can't be used, Tandem restarts in your configured working directory instead and the notification tells you where it landed. The same thing happened for a document on an external drive, on a network share, or in a folder that had since been deleted, and those are fixed by the same change. The command-palette version still refuses, because "Relaunch Claude in this folder" has no meaning without a usable folder. Present since the launcher shipped, not new in v0.20.0 — the recovery buttons added in that release are what made it easy to hit.
15
+
10
16
  ## [0.20.0] - 2026-08-05
11
17
 
12
18
  ### Added
@@ -67,6 +73,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
67
73
 
68
74
  - **Two Claude sessions can now use Tandem at the same time without knocking each other offline (#438).** Connecting a second AI session used to silently disconnect the first one's tool channel: the first session's Tandem tools would start failing until it reconnected, which then broke the second session, and so on. Each session now gets its own connection, so several can work against the same Tandem instance concurrently — a terminal session and a Cowork session, or two terminal sessions in different projects. Abandoned connections are cleaned up automatically instead of accumulating. Note that the *notifications* Tandem pushes are still broadcast to every connected session; scoping those to the relevant session is separate, still-open work.
69
75
 
76
+ ### Security
77
+
78
+ - Pinned `@hono/node-server` to `^2.0.12` (npm `overrides`, forcing the transitive copy under `@modelcontextprotocol/sdk`), clearing GHSA-frvp-7c67-39w9 — path traversal in `serve-static` on Windows. Tandem never calls `serveStatic`: the MCP HTTP transport uses only this package's request adapter, so the affected code was bundled but not reachable. The explicit pin was needed because the automated update on its own only widened the SDK's peer range without moving the resolved version off the affected 1.19.13. It carries `@modelcontextprotocol/sdk` 1.27.1 → 1.30.0 with it — that bump is what widens the range, and it is a production dependency bundled into the server.
79
+ - Bumped the desktop shell's transitive `quinn-proto` 0.11.14 → 0.11.16, clearing GHSA-4w2j-m93h-cj5j (remote memory exhaustion from unbounded buffering, patched in 0.11.15). It arrives through `reqwest`'s optional QUIC/HTTP-3 support rather than through anything Tandem calls.
80
+ - Routine dependency updates otherwise, with no advisory attached: `brace-expansion` 5.0.7 → 5.0.8 (its known advisories are all patched at ≤5.0.6, which the previous version already satisfied) plus the grouped npm updates in #1217, #1235 and #1271.
81
+
70
82
  ### Internal
71
83
 
72
84
  - **Bring-your-own-model support is fully built but switched off (#1123).** The whole mechanism — a server-owned model registry, a local-model collaborator loop, per-model authorship colours and bylines — is merged behind a build flag that is off, so nothing in this release behaves differently. It ships dark deliberately: the alternative is a long-lived branch drifting away from the code around it. Same for the licensing system (ADR-040), whose infrastructure and documentation landed here with its gate still off.
package/dist/cli/index.js CHANGED
@@ -358,7 +358,7 @@ function resolveChannelDist(env = process.env, exists = existsSync) {
358
358
  return resolve2(PACKAGE_ROOT, "dist/channel/index.js");
359
359
  }
360
360
  function resolveCliVersion() {
361
- if (true) return "0.20.0";
361
+ if (true) return "0.20.1";
362
362
  if (typeof __APP_VERSION__ !== "undefined") return __APP_VERSION__;
363
363
  for (const rel of ["../../package.json", "../../../package.json"]) {
364
364
  try {
@@ -3492,7 +3492,7 @@ function evaluateStaleGlobal(bundled, globalVersion) {
3492
3492
  };
3493
3493
  }
3494
3494
  async function checkStaleGlobal(r) {
3495
- const bundled = true ? "0.20.0" : null;
3495
+ const bundled = true ? "0.20.1" : null;
3496
3496
  if (!bundled) return;
3497
3497
  let globalVersion;
3498
3498
  try {
@@ -4590,7 +4590,7 @@ process.once("unhandledRejection", (reason) => {
4590
4590
  `);
4591
4591
  process.exit(1);
4592
4592
  });
4593
- var version = true ? "0.20.0" : "0.0.0-dev";
4593
+ var version = true ? "0.20.1" : "0.0.0-dev";
4594
4594
  var args = process.argv.slice(2);
4595
4595
  if (args.includes("--help") || args.includes("-h")) {
4596
4596
  console.log(`tandem v${version}
@@ -1,4 +1,4 @@
1
- import{A as e,B as t,C as n,D as r,E as i,F as a,H as o,I as s,L as c,M as l,N as u,O as d,P as f,R as p,S as m,T as h,U as g,V as _,_ as ee,a as v,b as y,c as b,d as x,f as S,g as C,h as w,i as T,j as E,k as D,l as O,m as te,n as k,o as A,p as j,r as M,s as N,t as P,u as F,v as I,w as ne,x as L,y as R,z}from"./index-DpPw5n4m.js";var re=d(`<div class="cs-help-text svelte-kvy574" data-testid="cowork-settings-loading">Loading Cowork status...</div>`),B=d(`<div class="cs-info-banner svelte-kvy574" data-testid="cowork-settings-unsupported">Cowork integration is available on Windows today. macOS/Linux support is tracked in #316 /
1
+ import{A as e,B as t,C as n,D as r,E as i,F as a,H as o,I as s,L as c,M as l,N as u,O as d,P as f,R as p,S as m,T as h,U as g,V as _,_ as ee,a as v,b as y,c as b,d as x,f as S,g as C,h as w,i as T,j as E,k as D,l as O,m as te,n as k,o as A,p as j,r as M,s as N,t as P,u as F,v as I,w as ne,x as L,y as R,z}from"./index-9gBq7QKg.js";var re=d(`<div class="cs-help-text svelte-kvy574" data-testid="cowork-settings-loading">Loading Cowork status...</div>`),B=d(`<div class="cs-info-banner svelte-kvy574" data-testid="cowork-settings-unsupported">Cowork integration is available on Windows today. macOS/Linux support is tracked in #316 /
2
2
  #317.</div>`),V=d(`<div class="cs-info-banner svelte-kvy574" data-testid="cowork-settings-undetected"><!> <a class="cs-link svelte-kvy574" target="_blank" rel="noreferrer">Learn more</a></div>`),ie=d(`<div class="cs-reachability" data-testid="cowork-reachability"><div class="cs-reachability-title svelte-kvy574"> </div> <div class="cs-reachability-detail svelte-kvy574"> </div></div>`),ae=d(`<div class="cs-warning-banner svelte-kvy574" data-testid="cowork-enable-confirm" role="dialog"><div class="cs-confirm-heading svelte-kvy574">Confirm: Enable Cowork</div> <div class="cs-confirm-body svelte-kvy574">Tandem will register itself as a plugin in every detected Cowork workspace so Claude in
3
3
  Cowork can reach your open documents. This adds a Windows firewall rule so the Cowork VM
4
4
  can connect back — admin is required once.</div> <div class="cs-actions svelte-kvy574"><button class="cs-btn cs-btn--primary svelte-kvy574" data-testid="cowork-enable-confirm-btn" type="button">Enable</button> <button class="cs-btn cs-btn--ghost svelte-kvy574" data-testid="cowork-enable-cancel-btn" type="button">Cancel</button></div></div>`),oe=d(`<div class="cs-vethernet svelte-kvy574" data-testid="cowork-vethernet-cidr">Detected Cowork environment: <code> </code></div>`),se=d(`<div><label data-testid="cowork-lan-ip-override"><input class="cs-accent-cbx svelte-kvy574" data-testid="cowork-lan-ip-override-checkbox" type="checkbox"/> <span>Use LAN IP instead of host.docker.internal</span></label> <div class="cs-help svelte-kvy574"> </div></div>`),ce=d(`<div class="cs-help-text svelte-kvy574">No Cowork workspaces detected yet.</div>`),le=d(`<a class="cs-report-link svelte-kvy574">Report</a>`),ue=d(`<div class="cs-workspace-row svelte-kvy574"><span class="cs-workspace-id svelte-kvy574"> </span> <span class="cs-workspace-label svelte-kvy574"> </span> <!></div>`),de=d(`<div class="cs-workspace-table svelte-kvy574" data-testid="cowork-workspace-table"></div>`),fe=d(`<label data-testid="cowork-toggle"><input class="cs-accent-cbx svelte-kvy574" data-testid="cowork-toggle-checkbox" type="checkbox"/> <span>Enable Cowork integration</span></label> <div class="cs-help svelte-kvy574"> </div> <!> <details class="cs-explainer svelte-kvy574" data-testid="cowork-explainer"><summary class="svelte-kvy574">What this does &amp; how to verify</summary> <div class="cs-explainer-body svelte-kvy574"><p class="svelte-kvy574">Enabling registers Tandem as a plugin in every detected Cowork workspace, so Claude
@@ -1 +1 @@
1
- import{createTransport as e}from"./prod-DDHRjaXr.js";async function t(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}var n=!1;function r(r){return e(r,async e=>{if(n)return{statusCode:200};try{await t(`plugin:sentry|envelope`,{envelope:e.body})}catch(e){console.error(`Failed to send envelope to Rust:`,e),n=!0}return{statusCode:200}})}function i(e){return n||typeof e.data?.url==`string`&&(e.data.url.startsWith(`ipc://`)||e.data.url.match(/^https?:\/\/ipc\.localhost/))||t(`plugin:sentry|breadcrumb`,{breadcrumb:e}).catch(e=>{console.error(`Failed to send breadcrumb to Rust:`,e),n=!0}),null}var a={dsn:`https://123456@dummy.dsn/0`,integrations:e=>e.filter(e=>e.name!==`BrowserSession`),transport:r,beforeBreadcrumb:i};export{a as defaultOptions};
1
+ import{createTransport as e}from"./prod-CXXJO_PR.js";async function t(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}var n=!1;function r(r){return e(r,async e=>{if(n)return{statusCode:200};try{await t(`plugin:sentry|envelope`,{envelope:e.body})}catch(e){console.error(`Failed to send envelope to Rust:`,e),n=!0}return{statusCode:200}})}function i(e){return n||typeof e.data?.url==`string`&&(e.data.url.startsWith(`ipc://`)||e.data.url.match(/^https?:\/\/ipc\.localhost/))||t(`plugin:sentry|breadcrumb`,{breadcrumb:e}).catch(e=>{console.error(`Failed to send breadcrumb to Rust:`,e),n=!0}),null}var a={dsn:`https://123456@dummy.dsn/0`,integrations:e=>e.filter(e=>e.name!==`BrowserSession`),transport:r,beforeBreadcrumb:i};export{a as defaultOptions};