From 0c1944381f44f2a16fbfb3648619e96236e10c23 Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Sat, 14 Nov 2026 02:48:15 -0300 Subject: [PATCH] remote.spin.cliPath read in every window: application scope A window that lost its connection is reconnected by VS Code resolving spin+ again, and by then it is a remote window, which reads a machine-scoped setting from the remote and not from the person's settings: remote.spin.cliPath came back empty, and the reconnect ran the spin on the PATH instead of the one named. Every setting here is of the machine the resolver runs on, the window's, so each is application-scoped, which every window reads from the person's settings; the manifest test holds them to it. Found by vscode-spinbox's spin+ lane in a real VS Code against spin's e2e stack: the tunnel cut under a connected window, VS Code resolved again with an older spin and gave up; with this, the window is back in 1 s with the same terminal shell. Co-Authored-By: Claude Opus 5.5 --- package.json | 2 +- test/package-manifest.test.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 06210be..3a55033 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "remote.spin.cliPath": { "type": "string", "markdownDescription": "The spin CLI that opens Spinbox workspaces (`spin+`). Empty runs the one the Spinbox extension carries, or else `spin` on the PATH.", - "scope": "machine", + "scope": "application", "default": "" } } diff --git a/test/package-manifest.test.ts b/test/package-manifest.test.ts index de4fae7..48abb39 100644 --- a/test/package-manifest.test.ts +++ b/test/package-manifest.test.ts @@ -12,7 +12,7 @@ const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'package.js activationEvents: string[]; enabledApiProposals: string[]; contributes: { - configuration: { properties: Record }; + configuration: { properties: Record }; commands: { command: string }[]; resourceLabelFormatters: { authority: string }[]; }; @@ -44,4 +44,14 @@ describe('package.json', () => { const read = [...src.matchAll(/getConfiguration\('([\w.]+)'\)\.get<\w+>\('([\w.]+)'/g)].map(m => `${m[1]}.${m[2]}`); expect(Object.keys(pkg.contributes.configuration.properties).sort()).toEqual([...new Set(read)].sort()); }); + + // Every setting is of the machine the resolver runs on, which is the window's own and never + // the workspace's: application scope is read from the person's settings in every window. A + // machine one is not, once the window is remote: VS Code reconnecting a dropped window read + // remote.spin.cliPath as empty and ran another spin (test:spin-remote in vscode-spinbox). + it('scopes every setting to the application', () => { + for (const [name, setting] of Object.entries(pkg.contributes.configuration.properties)) { + expect(setting.scope, name).toBe('application'); + } + }); });