diff --git a/CHANGELOG.md b/CHANGELOG.md index 2838630..91f7977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,8 @@ this one does not look. `gemdb.admin.garbage_collect()`, `gemdb.admin.backup()` and `gemdb.sessions.all()` now raise a security error; **Collect Garbage Now** and **Stop a Database Session…** cover the first and last. +- **Usage data now records which editor GemDB runs in** (VS Code, Cursor, …), so a + fork's users are not mistaken for VS Code users on an old release. `USAGE_DATA.md` lists it. ### Fixed diff --git a/USAGE_DATA.md b/USAGE_DATA.md index f56c1a4..aef34ea 100644 --- a/USAGE_DATA.md +++ b/USAGE_DATA.md @@ -24,7 +24,7 @@ VS Code automatically attaches its own common properties to every event: `common.isnewappinstall`, `common.sqmid`, `common.devDeviceId`, `common.telemetryclientversion`. -GemDB adds three properties of its own to every event: +GemDB adds five properties of its own to every event: - `extensionMode`, which is `production` for an installed extension and `development` or `test` when a GemDB developer is running it from source. @@ -34,6 +34,10 @@ GemDB adds three properties of its own to every event: - `firstSeen` — the ordinary case: GemDB recorded this as a new install. - `reinstall` — GemDB's own files were reinstalled while the database survived. +- `appName` and `appUriScheme`, which name the editor GemDB runs in, as its + name and its URL scheme (e.g. "Cursor" and `cursor`). Editors built on VS + Code report the VS Code version they are based on, so this is what tells + them apart. `common.vscodemachineid` is a pseudonymous identifier VS Code generates per installation. It is not tied to your name or email, but under GDPR it counts @@ -98,5 +102,5 @@ delete the matching records. ## Changes -Last updated: 2026-10-05. Changes to this notice will be published in this +Last updated: 2026-10-07. Changes to this notice will be published in this repository. diff --git a/docs/telemetry.md b/docs/telemetry.md index 0ac93e9..feaca80 100644 --- a/docs/telemetry.md +++ b/docs/telemetry.md @@ -29,6 +29,14 @@ take the earliest event of that kind for its `common.vscodemachineid`. | `extensionMode` | `production`, `development`, `test` | Only `production` is a real user. Filter out the others in every report. | | `installDay` | a date, e.g. `2026-09-15` | Roughly when GemDB was first used on this machine. | | `installDaySource` | `firstSeen`, `reinstall` | `reinstall`: GemDB was reinstalled but the user's database was still there. | +| `appUriScheme` | e.g. `vscode`, `vscode-insiders`, `cursor`, `windsurf` | Which editor GemDB runs in. Editors built on VS Code report the VS Code version they are based on in `common.vscodeversion`, so group by this before reading versions. Missing on events from 1.5.4 and earlier. | +| `appName` | e.g. `Visual Studio Code`, `Cursor` | The same editor, by its display name. Missing on events from 1.5.4 and earlier. | + +In a remote window (Dev Container, SSH, WSL), `appUriScheme` and `appName` +describe the editor on the user's desktop, not the remote machine, so a remote +window reports the same values as a local one. `common.remotename` says whether +the window was remote. When the editor runs in a web browser, as with +`code serve-web`, they describe that web version of the editor instead. VS Code adds its own `common.*` properties too (machine id, OS, VS Code version, extension version). [USAGE_DATA.md](../USAGE_DATA.md) lists them. diff --git a/src/__mocks__/vscode.ts b/src/__mocks__/vscode.ts index eb4bfd8..d88502f 100644 --- a/src/__mocks__/vscode.ts +++ b/src/__mocks__/vscode.ts @@ -112,6 +112,8 @@ const FAKE_COMMON_PROPERTIES: Record = { 'common.fake': 'yes' }; /** Two-line insurance: nothing here reads `env` today, but `activate()` does. */ export const env = { machineId: 'fake-machine-id', + appName: 'Visual Studio Code', + uriScheme: 'vscode', remoteName: undefined as string | undefined, clipboard: { writeText: (text: string): Promise => { diff --git a/src/__tests__/telemetryDocs.test.ts b/src/__tests__/telemetryDocs.test.ts index 05080d3..7a8899f 100644 --- a/src/__tests__/telemetryDocs.test.ts +++ b/src/__tests__/telemetryDocs.test.ts @@ -101,3 +101,22 @@ describe('docs/telemetry.md', () => { expect(undocumented, `document these in ${DOC_PATH}`).toEqual([]); }); }); + +// The same `beforeAll` is what makes this assertion mean "every event": it +// drives all seven `report*` functions, and the suite above fails if that +// list ever falls behind `EVENT`. Asserting it off one event — activation, +// say — would pass for a `report*` that built its own properties object +// instead of going through `send`. +describe('every event', () => { + it('names the editor GemDB runs in', () => { + // Forks report their base VS Code version, so these are what tells a + // Cursor user from a VS Code user on an old release. + expect(__telemetry.length).toBeGreaterThan(0); + for (const event of __telemetry) { + expect(event.properties, event.name).toMatchObject({ + appUriScheme: 'vscode', + appName: 'Visual Studio Code', + }); + } + }); +}); diff --git a/src/telemetry.ts b/src/telemetry.ts index 05cbc48..3b95140 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -82,8 +82,16 @@ let reporter: TelemetryReporter | undefined; * Properties stamped on every event, established once at activation. * * `extensionMode`, plus `installDay` and `installDaySource` (see - * `resolveInstallDay`). VS Code's own `common.*` properties are mixed in by - * the extension host and are not repeated here. + * `resolveInstallDay`), plus `appUriScheme` and `appName`, which name the + * editor GemDB runs in. Forks (Cursor, Windsurf) report their *base* + * VS Code version in `common.vscodeversion`, and no `common.*` property names + * the app, so without these a fork's users read as VS Code users stuck on an + * old release. Sent as raw strings, not mapped to a list, so a new fork shows + * up without a release. In a remote window they are still the desktop app's: + * the desktop builds the remote extension host's init data from its own + * product info (`remoteExtensionHost.ts`) and the server never overrides + * `appName` or `appUriScheme`. VS Code's own `common.*` + * properties are mixed in by the extension host and are not repeated here. */ let baseProperties: Record = {}; @@ -217,6 +225,8 @@ export function initTelemetry(context: vscode.ExtensionContext, databaseExists: extensionMode: extensionModeName(context.extensionMode), installDay, installDaySource, + appUriScheme: vscode.env.uriScheme, + appName: vscode.env.appName, }; // Disposal flushes queued events, so the subscription is load-bearing. reporter = new TelemetryReporter(CONNECTION_STRING);