Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Sep 28, 2025

No description provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 28, 2025

📝 Walkthrough

Walkthrough

Adds VS Code telemetry integration (new module, activation/sign-in instrumentation), introduces a save workflow for ZModel preview output, updates release notes text, and augments the schema build to inject a telemetry token and copy resources post-build. Also bumps the JetBrains IDE plugin version to 2.19.1.

Changes

Cohort / File(s) Summary
JetBrains version bump
packages/ide/jetbrains/build.gradle.kts
Increment version from 2.19.0 to 2.19.1.
Schema build pipeline updates
packages/schema/build/bundle.js
Adds post-build token replacement in bundle/extension.js using VSCODE_TELEMETRY_TRACKING_TOKEN; copies src/vscode/res to bundle/res; appends success/error handling to build promise chain.
Telemetry module (VS Code)
packages/schema/src/vscode/vscode-telemetry.ts
New telemetry module with Mixpanel init (conditional), device ID derivation, track and identify methods, and exported token constant/type.
Extension activation & sign-in instrumentation
packages/schema/src/extension.ts
Refactors imports to ./vscode/*; adds telemetry events for activation and sign-in (show/start/complete/error).
Auth provider telemetry identify
packages/schema/src/vscode/zenstack-auth-provider.ts
Imports telemetry and calls telemetry.identify(claims.email!) during auth callback; removes generateState() method.
ZModel preview save feature & telemetry
packages/schema/src/vscode/zmodel-preview.ts
Adds saveZModelDocumentation() command/flow, persistent last-generated markdown, fixed preview filename, context toggling on tab change, error handling, and telemetry for preview/save actions.
Release notes content tweak
packages/schema/src/vscode/res/zmodel-preview-release-notes.html
Updates instructions: removes “simply”, adds explicit save action with toolbar icon and Cmd/Ctrl+Shift+S shortcuts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant VSCode as VS Code
  participant Extension as Extension (activation)
  participant Telemetry as Telemetry

  Note over VSCode,Extension: Activation
  VSCode->>Extension: activate()
  Extension->>Telemetry: track("extension:activate")
  Note over Extension: Extension ready

  Note over User,Extension: Sign-in flow
  User->>Extension: Trigger sign-in
  Extension->>Telemetry: track("auth:signin:show")
  Extension->>Telemetry: track("auth:signin:start")
  Extension->>Extension: Perform auth
  alt success
    Extension->>Telemetry: track("auth:signin:complete")
    Extension-->>User: Signed in
  else error
    Extension->>Telemetry: track("auth:signin:error",{message})
    Extension-->>User: Error message
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Preview as ZModelPreview
  participant FS as File System
  participant Telemetry as Telemetry
  participant VSCode as VS Code UI

  Note over User,Preview: Generate preview
  User->>Preview: Generate documentation
  Preview->>Telemetry: track("zmodel:preview")
  Preview->>Preview: Store lastGeneratedMarkdown
  Preview->>VSCode: openMarkdownPreview(temp "zmodel​-preview.md")

  Note over User,Preview: Save documentation
  User->>Preview: Command zenstack.save-zmodel-documentation
  Preview->>Telemetry: track("zmodel:save:start")
  Preview->>VSCode: Show Save Dialog
  alt user cancels
    Preview-->>User: Cancelled
    Preview->>Telemetry: track("zmodel:save:cancel")
  else path selected
    Preview->>FS: Write lastGeneratedMarkdown to chosen path
    alt write ok
      Preview->>Telemetry: track("zmodel:save:complete")
      Preview->>VSCode: Refresh UI / notifications
    else write error
      Preview-->>User: Error message
      Preview->>Telemetry: track("zmodel:save:error",{message})
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning No pull request description was supplied, leaving reviewers without any summary of the goals, scope, or user impact of the changes in this merge. Please add a concise description outlining the key changes, objectives, and any important migration or usage notes to help reviewers understand the purpose and effect of this pull request.
Title Check ❓ Inconclusive The provided title “merge dev to main (v2.19.1)” accurately notes a branch merge and version bump but fails to summarize the primary functional changes introduced in this pull request—such as the addition of telemetry integration, new documentation save commands, and build enhancements—making it overly generic and tied to internal branch nomenclature rather than user-facing impact. Please update the title to succinctly reflect the main features or fixes included in this release—for example, “Add VSCode telemetry integration and zmodel documentation save command in v2.19.1”—to give reviewers and future readers clear context at a glance.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/schema/src/vscode/zenstack-auth-provider.ts (2)

199-217: JWT decode uses atob (not available in Node) and doesn’t handle base64url

In VS Code’s extension host (Node), atob is undefined and JWT payloads are base64url-encoded. Decode with Buffer + base64url normalization; also keep padding logic.

Apply:

-            const paddedPayload = payload + '='.repeat((4 - (payload.length % 4)) % 4);
-            const decoded = atob(paddedPayload);
-
-            return JSON.parse(decoded);
+            const base64url = payload.replace(/-/g, '+').replace(/_/g, '/');
+            const padded = base64url + '='.repeat((4 - (base64url.length % 4)) % 4);
+            const decoded = Buffer.from(padded, 'base64').toString('utf8');
+            return JSON.parse(decoded);

184-194: Refactor identify call to avoid PII and guard undefined
Replace the raw-email identify and non-null assertion in createSessionFromAccessToken with a stable non-PII id (sub or jti), falling back to a SHA-256 hashed email. The telemetry module already skips all tracking when vscode.env.isTelemetryEnabled is false.

--- a/packages/schema/src/vscode/zenstack-auth-provider.ts
+++ b/packages/schema/src/vscode/zenstack-auth-provider.ts
@@ private async createSessionFromAccessToken(accessToken: string): Promise<vscode.AuthenticationSession> {
-            telemetry.identify(claims.email!);
+            // Identify a stable, non-PII user id; fallback to hashed email if no sub/jti
+            const distinctId = claims.sub ?? claims.jti;
+            if (distinctId) {
+                telemetry.identify(distinctId);
+            } else if (claims.email) {
+                const { createHash } = await import('crypto');
+                const hashedEmail = createHash('sha256').update(claims.email).digest('hex');
+                telemetry.identify(hashedEmail);
+            }
packages/schema/src/vscode/zmodel-preview.ts (2)

194-201: Windows path bug: use fsPath when converting URIs

Using vscode.Uri.file(uri.path) will mis-handle Windows paths (e.g., /c:/...). Use the filesystem path from vscode-uri’s fsPath to construct a proper vscode.Uri.

Apply:

-                        const fileUri = vscode.Uri.file(uri.path);
-                        const fileContent = await vscode.workspace.fs.readFile(fileUri);
-                        const filePath = fileUri.path;
+                        const fileUri = vscode.Uri.file(uri.fsPath);
+                        const fileContent = await vscode.workspace.fs.readFile(fileUri);
+                        const filePath = fileUri.fsPath;

1-11: Import TextEncoder from 'util' to avoid TS/runtime issues

In VS Code extensions, TextEncoder typing may be missing unless dom lib is enabled; importing from util is the safe, cross‑Node choice.

 import * as os from 'os';
+import { TextEncoder } from 'util';

Also applies to: 272-279

🧹 Nitpick comments (14)
packages/schema/src/vscode/zenstack-auth-provider.ts (3)

168-173: Preserve requested scopes on session creation

Scopes collected in this.pendingAuth are dropped; session objects always get []. Pass scopes through for correctness.

Apply:

-    private async createSessionFromAccessToken(accessToken: string): Promise<vscode.AuthenticationSession> {
+    private async createSessionFromAccessToken(
+        accessToken: string,
+        scopes: readonly string[] = []
+    ): Promise<vscode.AuthenticationSession> {
...
-            return {
+            return {
                 id: claims.jti || Math.random().toString(36),
                 accessToken: accessToken,
                 account: {
                     id: claims.sub || 'unknown',
                     label: claims.email || 'unknown@zenstack.dev',
                 },
-                scopes: [],
+                scopes: Array.from(scopes),
             };

And in the callback:

-            const session = await this.createSessionFromAccessToken(accessToken);
+            const session = await this.createSessionFromAccessToken(accessToken, this.pendingAuth?.scopes ?? []);

Also applies to: 192-193


221-236: Logout awaits aren’t honored; show message after removals complete

forEach(async ...) isn’t awaited, so the info message can show before sessions are removed. Use Promise.all.

Apply:

     async logoutAllSessions(): Promise<void> {
         if (this._sessions.length === 0) {
             return;
         }

-        (await this.getSessions()).forEach(async (s) => await this.removeSession(s.id));
-        vscode.window.showInformationMessage('Successfully logged out of ZenStack.');
+        const sessions = await this.getSessions();
+        await Promise.all(sessions.map((s) => this.removeSession(s.id)));
+        vscode.window.showInformationMessage('Successfully logged out of ZenStack.');
     }

Also applies to: 87-94


199-206: Consider validating token expiry (exp) before creating a session

Prevent creating unusable sessions with expired tokens; fail fast with a clear message.

Example:

             const parts = token.split('.');
...
-            return JSON.parse(decoded);
+            const claims = JSON.parse(decoded) as JWTClaims;
+            if (typeof claims.exp === 'number' && Date.now() / 1000 >= claims.exp) {
+                throw new Error('Access token expired');
+            }
+            return claims;
packages/schema/src/extension.ts (2)

21-26: Emit “signin:show” before awaiting the modal

Track the “show” event before showWarningMessage to reflect actual prompt display timing.

-        const selection = await vscode.window.showWarningMessage('Please sign in to use this feature', signIn);
-        telemetry.track('extension:signin:show');
+        telemetry.track('extension:signin:show');
+        const selection = await vscode.window.showWarningMessage('Please sign in to use this feature', signIn);

45-47: Add useful context to activation telemetry

Include extension and VS Code versions for diagnostics.

-    telemetry.track('extension:activate');
+    telemetry.track('extension:activate', {
+        extensionVersion: context.extension.packageJSON.version,
+        vscodeVersion: vscode.version,
+        platform: process.platform,
+        arch: process.arch,
+    });
packages/schema/src/vscode/res/zmodel-preview-release-notes.html (1)

66-75: Verify codicon names and add accessible labels

  • Confirm codicon-preview and codicon-save exist in the referenced codicons version; otherwise icons won’t render.
  • Add aria-label/title for screen readers.

Example:

Click (<span class="codicon codicon-save" aria-label="Save" title="Save"></span>) ...

To check rendering locally, open the preview and confirm icons appear.

packages/schema/build/bundle.js (2)

16-17: Replace all placeholder occurrences, not just the first

String.replace replaces only the first match. Use replaceAll or a global regex.

-    content = content.replace('<VSCODE_TELEMETRY_TRACKING_TOKEN>', telemetryToken);
+    content = content.replaceAll('<VSCODE_TELEMETRY_TRACKING_TOKEN>', telemetryToken);

5-5: path is unused

Remove unused import.

-const path = require('path');
packages/schema/src/vscode/zmodel-preview.ts (3)

324-335: Avoid auto-closing the editor after save; provide actionable toast instead

Opening and immediately closing the saved file is surprising and can close the wrong editor. Offer “Open” / “Reveal” actions instead.

-            // Open and close the saved file to refresh the shown markdown preview
-            await vscode.commands.executeCommand('vscode.open', saveUri);
-            await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
+            const choice = await vscode.window.showInformationMessage(
+                `Documentation saved: ${saveUri.fsPath}`,
+                'Open',
+                'Reveal in Explorer'
+            );
+            if (choice === 'Open') {
+                await vscode.commands.executeCommand('vscode.open', saveUri);
+            } else if (choice === 'Reveal in Explorer') {
+                await vscode.commands.executeCommand('revealFileInOS', saveUri);
+            }

53-64: Initialize markdown-preview context on activation

Context is only updated on tab changes; initialize it once so keybindings/UI dependent on zenstack.isMarkdownPreview work immediately.

         context.subscriptions.push(
             vscode.window.tabGroups.onDidChangeTabs(() => {
-                const activeTabLabels = vscode.window.tabGroups.all.filter((group) =>
+                const activeTabLabels = vscode.window.tabGroups.all.filter((group) =>
                     group.activeTab?.label?.endsWith(this.previewZModelFileName)
                 );
                 if (activeTabLabels.length > 0) {
                     vscode.commands.executeCommand('setContext', 'zenstack.isMarkdownPreview', true);
                 } else {
                     vscode.commands.executeCommand('setContext', 'zenstack.isMarkdownPreview', false);
                 }
             })
         );
+        // initialize once
+        vscode.commands.executeCommand(
+            'setContext',
+            'zenstack.isMarkdownPreview',
+            vscode.window.tabGroups.all.some((g) => g.activeTab?.label?.endsWith(this.previewZModelFileName))
+        );

8-8: Potential circular dependency with requireAuth from ../extension

Importing from the activation module can create cycles (activation ⇒ preview ⇒ extension). Consider extracting requireAuth to a shared auth module.

Could you confirm there’s no load/activation cycle here?

packages/schema/src/vscode/vscode-telemetry.ts (3)

31-35: Remove unsupported geolocate init option

mixpanel Node client doesn’t use a geolocate init flag. Remove it to avoid confusion.

-            this.mixpanel = init(VSCODE_TELEMETRY_TRACKING_TOKEN, {
-                geolocate: true,
-            });
+            this.mixpanel = init(VSCODE_TELEMETRY_TRACKING_TOKEN);

18-29: Avoid heavy work at module import; lazily init the client/device id

Constructing the singleton computes machine ID at import time. Consider lazy init to reduce activation latency and potential I/O during extension load.

If you keep the singleton, defer getDeviceId() to first track/identify call and cache the result.

Also applies to: 75-75


44-63: Add ip: 0 to payload for IP suppression
Per Mixpanel Node.js SDK, setting ip: 0 in the event payload skips GeoIP lookup for that event.

@@ packages/schema/src/vscode/vscode-telemetry.ts:44-63
             const payload = {
                 distinct_id: this.deviceId,
                 time: new Date(),
                 $os: this._os_type,
                 osType: this._os_type,
                 osRelease: this._os_release,
                 osPlatform: this._os_platform,
                 osArch: this._os_arch,
                 osVersion: this._os_version,
                 nodeVersion: process.version,
                 vscodeAppName: this.vscodeAppName,
                 vscodeVersion: this.vscodeVersion,
                 vscodeAppHost: this.vscodeAppHost,
+                ip: 0,
                 ...properties,
             };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8847f8 and ada3469.

⛔ Files ignored due to path filters (14)
  • package.json is excluded by !**/*.json
  • packages/ide/jetbrains/package.json is excluded by !**/*.json
  • packages/language/package.json is excluded by !**/*.json
  • packages/misc/redwood/package.json is excluded by !**/*.json
  • packages/plugins/openapi/package.json is excluded by !**/*.json
  • packages/plugins/swr/package.json is excluded by !**/*.json
  • packages/plugins/tanstack-query/package.json is excluded by !**/*.json
  • packages/plugins/trpc/package.json is excluded by !**/*.json
  • packages/runtime/package.json is excluded by !**/*.json
  • packages/schema/package.json is excluded by !**/*.json
  • packages/schema/tsconfig.json is excluded by !**/*.json
  • packages/sdk/package.json is excluded by !**/*.json
  • packages/server/package.json is excluded by !**/*.json
  • packages/testtools/package.json is excluded by !**/*.json
📒 Files selected for processing (7)
  • packages/ide/jetbrains/build.gradle.kts (1 hunks)
  • packages/schema/build/bundle.js (2 hunks)
  • packages/schema/src/extension.ts (3 hunks)
  • packages/schema/src/vscode/res/zmodel-preview-release-notes.html (1 hunks)
  • packages/schema/src/vscode/vscode-telemetry.ts (1 hunks)
  • packages/schema/src/vscode/zenstack-auth-provider.ts (2 hunks)
  • packages/schema/src/vscode/zmodel-preview.ts (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/schema/src/extension.ts (1)
packages/schema/src/vscode/zenstack-auth-provider.ts (1)
  • AUTH_PROVIDER_ID (11-11)
packages/schema/src/vscode/zmodel-preview.ts (1)
packages/schema/src/vscode/documentation-cache.ts (1)
  • DocumentationCache (15-152)
packages/schema/src/vscode/vscode-telemetry.ts (3)
packages/schema/bin/post-install.js (3)
  • Mixpanel (6-6)
  • os (8-8)
  • payload (16-28)
packages/schema/src/utils/machine-id-utils.ts (1)
  • getMachineId (63-74)
packages/schema/src/global.d.ts (1)
  • TELEMETRY_TRACKING_TOKEN (2-2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: OSSAR-Scan
  • GitHub Check: build-test (20.x)
  • GitHub Check: build-test (20.x)
  • GitHub Check: build-test (20.x)
  • GitHub Check: dependency-review
🔇 Additional comments (5)
packages/ide/jetbrains/build.gradle.kts (1)

12-12: Version bump to 2.19.1 looks good

Matches the PR title and no behavioral changes here.

packages/schema/src/extension.ts (1)

5-10: Telemetry module correctly respects VS Code telemetry settings
VSCodeTelemetry only initializes Mixpanel when vscode.env.isTelemetryEnabled is true, and both track and identify guard on this.mixpanel, making them no-ops when telemetry is disabled.

packages/schema/src/vscode/zenstack-auth-provider.ts (1)

32-41: Manual verification required: ensure extension manifest includes onUri activation and uriHandler
I wasn’t able to locate any package.json in the workspace. Please confirm that your VS Code extension’s manifest declares

  • "activationEvents": ["onUri"]
  • a "uriHandler" contribution
    so that the /auth-callback route is correctly wired up.
packages/schema/build/bundle.js (1)

36-37: No resource collisions detected between src/res and src/vscode/res – I compared the relative paths in both directories and found no overlapping files, so the current copy operations into bundle/res won’t overwrite each other.

packages/schema/src/vscode/zmodel-preview.ts (1)

239-247: Confirm global fetch support in the extension host
Your code calls fetch, which relies on Node’s global fetch (available only in Node ≥ 18). Verify that your extension’s package.json defines an engines.vscode range targeting a VS Code/Electron build with built-in fetch support, or add a fallback import (e.g. dynamic import of node-fetch) in zmodel-preview.ts.

@ymc9 ymc9 merged commit be9c553 into main Sep 29, 2025
17 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants