Skip to content

Conversation

@saddlepaddle
Copy link
Collaborator

@saddlepaddle saddlepaddle commented Jan 13, 2026

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • New Features

    • OAuth sign-in via external browser with encrypted on-disk token storage and token-sync subscriptions.
    • Desktop-auth client to surface session state to UI components.
  • Refactor

    • Moved many RPC calls to an Electron-specific RPC bridge for desktop IPC.
    • Switched auth provider to a token-focused flow and simplified session handling.
  • Chores

    • Added dependency: better-auth.

✏️ Tip: You can customize this high-level summary in your review settings.

…ad for cleaner code / better interop with better auth
@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Reworks desktop authentication to a token-centric flow (Better Auth), moves token persistence to encrypted disk in the main process, introduces an Electron-specific tRPC client/provider, and removes the legacy AuthService plus the user/tasks routers; updates ~100 renderer files to use the new electronTrpc client.

Changes

Cohort / File(s) Summary
Auth core & utilities
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts, apps/desktop/src/lib/trpc/routers/auth/index.ts, apps/desktop/src/main/lib/auth/auth.ts (removed), apps/desktop/src/main/lib/auth/index.ts (removed)
New token-centric auth utilities, encrypted on-disk token load/save, deep-link parsing, handleAuthCallback; replaces legacy AuthService and its APIs.
Main process wiring
apps/desktop/src/main/index.ts, apps/desktop/src/main/lib/api-client.ts (removed)
processDeepLink now uses new auth-functions; api-client removed and previous authService initialization deleted.
Renderer auth client & provider
apps/desktop/src/renderer/lib/auth-client.ts, apps/desktop/src/renderer/providers/AuthProvider/*, apps/desktop/src/renderer/providers/AuthProvider/index.ts
Introduces in-memory authClient (Better Auth usage), set/get token API, refactors AuthProvider to AuthTokenContext and useAuthToken hook, hydrates token from main process.
Electron tRPC client & provider
apps/desktop/src/renderer/lib/electron-trpc.ts, apps/desktop/src/renderer/lib/trpc-client.ts, apps/desktop/src/renderer/providers/ElectronTRPCProvider/*, apps/desktop/src/renderer/providers/TRPCProvider/*
Adds electronTrpc React client, renames/updates clients, adds ElectronTRPCProvider, reworks TRPCProvider instantiation to use new auth token getter.
Router composition
apps/desktop/src/lib/trpc/routers/index.ts, apps/desktop/src/lib/trpc/routers/user/index.ts (removed), apps/desktop/src/lib/trpc/routers/tasks/index.ts (removed)
Removed user and tasks routers from main router and deleted their modules.
Renderer: TRPC → electronTrpc migration (many files)
apps/desktop/src/renderer/components/..., apps/desktop/src/renderer/screens/..., apps/desktop/src/renderer/routes/..., apps/desktop/src/renderer/react-query/..., apps/desktop/src/renderer/stores/..., apps/desktop/src/renderer/hooks/..., ...
~100+ files updated to import/use electronTrpc / electronTrpcClient instead of prior trpc/trpcClient (queries, mutations, subscriptions, utils); mostly systematic client swap.
Auth integration points
apps/desktop/src/renderer/routes/_authenticated/layout.tsx, apps/desktop/src/renderer/routes/sign-in/page.tsx, apps/desktop/src/renderer/routes/_authenticated/providers/*, apps/desktop/src/renderer/routes/_authenticated/settings/*
Session and sign-in/out flows updated to use authClient.useSession() and electronTrpc.auth.* mutations; components now rely on authClient + token model.
Types & package exports
packages/auth/package.json, apps/desktop/package.json
Adds better-auth dependency and exposes ./electron-client in auth package exports.
Tests & mocks
apps/desktop/src/renderer/screens/.../Terminal/helpers.test.ts
Test mocks updated to use electronTrpcClient and include electronReactClient.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Renderer as Renderer (React)
    participant Main as Electron Main
    participant AuthClient as Better Auth Client
    participant API as Backend API

    User->>Renderer: Click "Sign in"
    Renderer->>Main: electronTrpc.auth.signIn (request start)
    Main->>Main: generate CSRF state, save transient state
    Main->>User: open OAuth URL in external browser
    User->>API: complete OAuth in browser
    API->>Main: deep link callback (token, expiresAt, state)
    Main->>Main: parseAuthDeepLink -> handleAuthCallback(validate state)
    Main->>Main: saveToken(encrypted) & emit "token-saved"
    Main->>Renderer: onTokenChanged subscription event (token)
    Renderer->>AuthClient: setAuthToken(token)
    Renderer->>API: authenticated requests via authClient (Bearer token)
    API->>Renderer: session data
    Renderer->>Renderer: update UI as signed-in
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Kitenite

Poem

🐰 I hopped through code to find the key,
Saved tokens safe for you and me,
Electron bridges calls with care,
Better Auth now guards the lair,
Cheers — a rabbit's tiny victory! 🥕✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is empty/incomplete, containing only the template with all sections unfilled (no description, related issues, type of change, testing details, or additional notes provided). Fill in all required template sections: add a detailed description of the refactoring, specify the type of change (Refactor), describe testing performed, and link any related issues.
Docstring Coverage ⚠️ Warning Docstring coverage is 27.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main refactoring: moving auth token management from the main thread to the renderer for better code organization and better-auth interoperability.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

@github-actions
Copy link

github-actions bot commented Jan 13, 2026

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

Copy link

@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: 6

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/react-query/workspaces/useCloseWorkspace.ts (1)

137-151: Add error logging for debugging.

The error is silently discarded. Per coding guidelines, errors should at minimum be logged with context to aid debugging.

Proposed fix
-		onError: (_err, _variables, context) => {
+		onError: (err, variables, context) => {
 			// Rollback to previous state on error
+			console.error("[workspaces/close] Failed to close workspace:", {
+				error: err,
+				workspaceId: variables.id,
+			});
 			if (context?.previousGrouped !== undefined) {
🤖 Fix all issues with AI agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts:
- Around line 105-111: The signOut mutation currently swallows any fs.unlink
errors silently; update the try/catch in the signOut publicProcedure to catch
the error and log it (e.g., using console.error or the app's logger) with
context including TOKEN_FILE and the error object so failures (like permission
issues) are visible; keep returning { success: true } if desired but ensure the
catch does not remain empty.
- Around line 48-56: The subscription in onTokenChanged calls
loadToken().then(...) without handling rejections, causing unhandled promise
rejections; wrap the initial token load with proper error handling (e.g., add a
.catch(...) to the Promise chain or use an async IIFE with try/catch) and on
failure call emit.error(error) or emit.next(null) as appropriate so the
observable handles errors gracefully; update the loadToken call inside the
observable returned by publicProcedure.subscription to ensure any rejection is
caught and forwarded via emit.

In @apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts:
- Around line 34-36: The catch block in
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts that currently
swallows errors and returns { token: null, expiresAt: null } should capture the
caught error (e.g., catch (err)) and log it before returning; update that catch
to log the error using the project's logging utility (or console.error if none
exists) with a clear message like "Failed to load auth token" and the error
object, then continue to return { token: null, expiresAt: null } so behavior is
unchanged but failures are recorded for debugging.

In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx:
- Around line 51-55: The async switchOrganization function doesn't handle
failures from authClient.organization.setActive; wrap the await call in a
try/catch inside switchOrganization, log the error with contextual details
(e.g., newOrgId and a descriptive message) using the existing logger (or
console/error logger if none), and surface the failure appropriately (rethrow or
return a rejection/boolean) so callers can react; ensure you reference
switchOrganization and authClient.organization.setActive when making the change.
- Around line 57-60: The handleSignOut handler currently calls
authClient.signOut() and signOutMutation.mutate() without any error handling;
wrap these calls in a try/catch and handle failures: call await
authClient.signOut() inside try, then execute signOutMutation.mutate() (or call
its async variant) and in catch log the error (use the existing logger or
console.error) and surface user-facing feedback (toast/error dialog) so the UI
won't silently fail; ensure to keep any necessary cleanup in finally (e.g.,
reset local auth state only on success) and reference the handleSignOut
function, authClient.signOut, and signOutMutation.mutate when making the
changes.

In @packages/auth/package.json:
- Around line 14-18: The package export "./electron-client" in package.json
points to a missing file "./src/electron-client.ts"; either add the missing
source by creating packages/auth/src/electron-client.ts implementing the
intended electron client API (matching any referenced types/exports) or remove
the "./electron-client" export entry from package.json if the feature was added
prematurely; update any imports that reference "./electron-client" (or adjust
their paths) to keep exports and source files consistent.
🧹 Nitpick comments (8)
apps/desktop/src/renderer/react-query/workspaces/useCloseWorkspace.ts (1)

152-160: Consider parallelizing independent invalidations.

The two invalidation calls are independent and could run concurrently for slightly better performance.

Proposed fix
 		onSuccess: async (...args) => {
 			// Invalidate to ensure consistency with backend state
-			await utils.workspaces.invalidate();
-			// Invalidate project queries since close updates project metadata
-			await utils.projects.getRecents.invalidate();
+			await Promise.all([
+				utils.workspaces.invalidate(),
+				// Invalidate project queries since close updates project metadata
+				utils.projects.getRecents.invalidate(),
+			]);
 
 			// Call user's onSuccess if provided
 			await options?.onSuccess?.(...args);
 		},
apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (1)

3-4: Inconsistent import path style.

Line 3 uses the alias path (renderer/lib/electron-trpc) while line 4 uses a relative path (../../lib/trpc-client). Per coding guidelines, prefer using aliases as defined in tsconfig.json consistently.

Suggested fix
 import { electronTrpc } from "renderer/lib/electron-trpc";
-import { electronReactClient } from "../../lib/trpc-client";
+import { electronReactClient } from "renderer/lib/trpc-client";
apps/desktop/src/lib/trpc/routers/auth/index.ts (1)

80-84: Extract magic number to named constant.

Per coding guidelines, magic numbers should be extracted to named constants for clarity and maintainability.

Suggested refactor

At the top of the file:

const STATE_EXPIRY_MS = 10 * 60 * 1000; // 10 minutes

Then update usage:

-const tenMinutesAgo = Date.now() - 10 * 60 * 1000;
+const stateExpiryThreshold = Date.now() - STATE_EXPIRY_MS;
 for (const [s, ts] of stateStore) {
-	if (ts < tenMinutesAgo) stateStore.delete(s);
+	if (ts < stateExpiryThreshold) stateStore.delete(s);
 }
apps/desktop/src/renderer/routes/_authenticated/settings/keyboard/page.tsx (1)

42-89: Consider extracting HotkeyRow to a separate file.

Per coding guidelines, prefer one component per file. HotkeyRow could be extracted to a separate file like HotkeyRow.tsx in the same directory for better organization and reusability.

apps/desktop/src/renderer/react-query/workspaces/useSetActiveWorkspace.ts (1)

58-59: Consider improving type safety on the onSuccess callback forwarding.

The as any cast is a known workaround for TypeScript inference limitations with spread args. The biome-ignore comment documents the intent, which is acceptable.

Alternative: Use explicit callback signature

If type safety becomes important here, you could define explicit parameter types instead of spreading:

-			// biome-ignore lint/suspicious/noExplicitAny: spread args for compatibility
-			await (options?.onSuccess as any)?.(data, variables, ...rest);
+			await options?.onSuccess?.(data, variables, rest[0]);

However, this may break if the mutation callback signature changes. The current approach with the documented cast is pragmatic.

apps/desktop/src/renderer/routes/sign-in/page.tsx (1)

29-32: Consider adding user feedback for sign-in errors.

The signInMutation doesn't show error handling in this component. Users may not receive feedback if the sign-in flow fails.

💡 Optional: Add error state feedback
 const signIn = (provider: AuthProvider) => {
   posthog.capture("auth_started", { provider });
-  signInMutation.mutate({ provider });
+  signInMutation.mutate({ provider }, {
+    onError: (error) => {
+      console.error("[auth/signIn] Sign-in failed:", error);
+      // Optionally show a toast or inline error message
+    },
+  });
 };
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)

53-59: Consider removing redundant effect.

This effect duplicates setAuthToken calls that are already made elsewhere:

  • Line 37 & 47: during subscription and hydration
  • Line 64: when clearing on session logout

Every code path that modifies token already calls setAuthToken, making this synchronization effect unnecessary.

♻️ Suggested removal
-	useEffect(() => {
-		if (token) {
-			setAuthToken(token);
-		} else {
-			setAuthToken(null);
-		}
-	}, [token]);
-
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts (1)

14-14: stateStore lacks TTL, risking memory accumulation.

If OAuth flows are abandoned (user closes browser, network failure, etc.), entries remain in stateStore indefinitely. Consider adding expiration timestamps and periodic cleanup.

Suggested approach with TTL
-export const stateStore = new Map<string, number>();
+const STATE_TTL_MS = 10 * 60 * 1000; // 10 minutes
+export const stateStore = new Map<string, number>();
+
+// Cleanup expired states periodically
+setInterval(() => {
+	const now = Date.now();
+	for (const [state, timestamp] of stateStore) {
+		if (now - timestamp > STATE_TTL_MS) {
+			stateStore.delete(state);
+		}
+	}
+}, 60 * 1000);

Then when adding state:

stateStore.set(state, Date.now());

And in handleAuthCallback, validate the timestamp:

const timestamp = stateStore.get(params.state);
if (!timestamp || Date.now() - timestamp > STATE_TTL_MS) {
	return { success: false, error: "Invalid or expired auth session" };
}

Comment on lines +48 to 56
onTokenChanged: publicProcedure.subscription(() => {
return observable<{ token: string; expiresAt: string } | null>((emit) => {
// Emit initial token on subscription
loadToken().then((initial) => {
if (initial.token && initial.expiresAt) {
emit.next({ token: initial.token, expiresAt: initial.expiresAt });
}
});

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle potential rejection from initial token load.

The loadToken().then() call has no error handler. If loadToken() rejects, it will cause an unhandled promise rejection.

Suggested fix
 // Emit initial token on subscription
-loadToken().then((initial) => {
+loadToken().then((initial) => {
 	if (initial.token && initial.expiresAt) {
 		emit.next({ token: initial.token, expiresAt: initial.expiresAt });
 	}
+}).catch((err) => {
+	console.error("[auth/onTokenChanged] Failed to load initial token:", err);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onTokenChanged: publicProcedure.subscription(() => {
return observable<{ token: string; expiresAt: string } | null>((emit) => {
// Emit initial token on subscription
loadToken().then((initial) => {
if (initial.token && initial.expiresAt) {
emit.next({ token: initial.token, expiresAt: initial.expiresAt });
}
});
onTokenChanged: publicProcedure.subscription(() => {
return observable<{ token: string; expiresAt: string } | null>((emit) => {
// Emit initial token on subscription
loadToken().then((initial) => {
if (initial.token && initial.expiresAt) {
emit.next({ token: initial.token, expiresAt: initial.expiresAt });
}
}).catch((err) => {
console.error("[auth/onTokenChanged] Failed to load initial token:", err);
});
🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts around lines 48 - 56, The
subscription in onTokenChanged calls loadToken().then(...) without handling
rejections, causing unhandled promise rejections; wrap the initial token load
with proper error handling (e.g., add a .catch(...) to the Promise chain or use
an async IIFE with try/catch) and on failure call emit.error(error) or
emit.next(null) as appropriate so the observable handles errors gracefully;
update the loadToken call inside the observable returned by
publicProcedure.subscription to ensure any rejection is caught and forwarded via
emit.

Comment on lines 105 to 111
signOut: publicProcedure.mutation(async () => {
await authService.signOut();
console.log("[auth] Clearing token");
try {
await fs.unlink(TOKEN_FILE);
} catch {}
return { success: true };
}),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Empty catch block silently swallows errors.

Per coding guidelines, errors should never be swallowed silently. The fs.unlink failure (e.g., permission issues) should be logged.

Suggested fix
 signOut: publicProcedure.mutation(async () => {
 	console.log("[auth] Clearing token");
 	try {
 		await fs.unlink(TOKEN_FILE);
-	} catch {}
+	} catch (err) {
+		// ENOENT is expected if token file doesn't exist
+		if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
+			console.error("[auth/signOut] Failed to clear token file:", err);
+		}
+	}
 	return { success: true };
 }),
🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/index.ts around lines 105 - 111, The
signOut mutation currently swallows any fs.unlink errors silently; update the
try/catch in the signOut publicProcedure to catch the error and log it (e.g.,
using console.error or the app's logger) with context including TOKEN_FILE and
the error object so failures (like permission issues) are visible; keep
returning { success: true } if desired but ensure the catch does not remain
empty.

Comment on lines +34 to +36
} catch {
return { token: null, expiresAt: null };
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Silent error swallowing masks potential issues.

Per coding guidelines, errors should never be swallowed silently. If token loading fails due to corruption, permission issues, or decryption errors, this should be logged for debugging.

Proposed fix
-	} catch {
+	} catch (error) {
+		console.log("[auth] Failed to load token from disk:", error);
 		return { token: null, expiresAt: null };
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch {
return { token: null, expiresAt: null };
}
} catch (error) {
console.log("[auth] Failed to load token from disk:", error);
return { token: null, expiresAt: null };
}
🤖 Prompt for AI Agents
In @apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts around lines
34 - 36, The catch block in
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts that currently
swallows errors and returns { token: null, expiresAt: null } should capture the
caught error (e.g., catch (err)) and log it before returning; update that catch
to log the error using the project's logging utility (or console.error if none
exists) with a clear message like "Failed to load auth token" and the error
object, then continue to return { token: null, expiresAt: null } so behavior is
unchanged but failures are recorded for debugging.

Comment on lines 51 to 55
const switchOrganization = async (newOrgId: string) => {
await setActiveOrg.mutateAsync({ organizationId: newOrgId });
await authClient.organization.setActive({
organizationId: newOrgId,
});
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for organization switch.

The async operation could fail silently. Per coding guidelines, errors should be logged with context.

Suggested improvement
 const switchOrganization = async (newOrgId: string) => {
-	await authClient.organization.setActive({
-		organizationId: newOrgId,
-	});
+	try {
+		await authClient.organization.setActive({
+			organizationId: newOrgId,
+		});
+	} catch (err) {
+		console.error("[OrganizationDropdown/switchOrganization] Failed:", err);
+	}
 };
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
around lines 51 - 55, The async switchOrganization function doesn't handle
failures from authClient.organization.setActive; wrap the await call in a
try/catch inside switchOrganization, log the error with contextual details
(e.g., newOrgId and a descriptive message) using the existing logger (or
console/error logger if none), and surface the failure appropriately (rethrow or
return a rejection/boolean) so callers can react; ensure you reference
switchOrganization and authClient.organization.setActive when making the change.

Comment on lines +57 to 60
const handleSignOut = async () => {
await authClient.signOut();
signOutMutation.mutate();
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for sign-out operations.

Both authClient.signOut() and signOutMutation.mutate() can fail (network issues, IPC errors). Currently, failures are silently ignored which could leave the user in an inconsistent state.

Suggested improvement
 const handleSignOut = async () => {
-	await authClient.signOut();
-	signOutMutation.mutate();
+	try {
+		await authClient.signOut();
+		await signOutMutation.mutateAsync();
+	} catch (err) {
+		console.error("[OrganizationDropdown/signOut] Failed to sign out:", err);
+	}
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSignOut = async () => {
await authClient.signOut();
signOutMutation.mutate();
};
const handleSignOut = async () => {
try {
await authClient.signOut();
await signOutMutation.mutateAsync();
} catch (err) {
console.error("[OrganizationDropdown/signOut] Failed to sign out:", err);
}
};
🤖 Prompt for AI Agents
In
@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
around lines 57 - 60, The handleSignOut handler currently calls
authClient.signOut() and signOutMutation.mutate() without any error handling;
wrap these calls in a try/catch and handle failures: call await
authClient.signOut() inside try, then execute signOutMutation.mutate() (or call
its async variant) and in catch log the error (use the existing logger or
console.error) and surface user-facing feedback (toast/error dialog) so the UI
won't silently fail; ensure to keep any necessary cleanup in finally (e.g.,
reset local auth state only on success) and reference the handleSignOut
function, authClient.signOut, and signOutMutation.mutate when making the
changes.

Comment on lines +14 to 18
},
"./electron-client": {
"types": "./src/electron-client.ts",
"default": "./src/electron-client.ts"
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd -t f "electron-client.ts" packages/auth/src

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

find . -name "*electron-client*" -type f

Repository: superset-sh/superset

Length of output: 46


Blocker: Referenced file does not exist.

The ./electron-client export references ./src/electron-client.ts, but this file does not exist in the repository. The export entry cannot be approved without the corresponding source file.

Create packages/auth/src/electron-client.ts or remove the export entry if it was added prematurely.

🤖 Prompt for AI Agents
In @packages/auth/package.json around lines 14 - 18, The package export
"./electron-client" in package.json points to a missing file
"./src/electron-client.ts"; either add the missing source by creating
packages/auth/src/electron-client.ts implementing the intended electron client
API (matching any referenced types/exports) or remove the "./electron-client"
export entry from package.json if the feature was added prematurely; update any
imports that reference "./electron-client" (or adjust their paths) to keep
exports and source files consistent.

Copy link

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (1)

24-24: Use the exported constant instead of redefining locally.

GITHUB_STATUS_STALE_TIME is already exported from apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/constants.ts with a value of 30_000 (30 seconds). This file redefines it as 5 * 60 * 1000 (5 minutes), creating a 10x inconsistency in cache freshness across the workspace views.

Import the constant from constants.ts instead to ensure consistent GitHub status refresh behavior:

import { GITHUB_STATUS_STALE_TIME } from "../../WorkspaceSidebar/WorkspaceListItem/constants";

Remove the local definition on line 24.

🤖 Fix all issues with AI agents
In @apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx:
- Around line 33-44: The subscription handler for
electronTrpc.auth.onTokenChanged.useSubscription is causing an infinite loop by
calling persistMutation.mutate (which calls saveToken and re-emits
"token-saved"); update the handler to stop re-persisting: remove the
persistMutation.mutate(...) call and only call setToken and setAuthToken when
data is received (you may keep the token/expiresAt presence check), leaving
token persistence to the original saveToken path that emits authEvents; ensure
no other code in this handler triggers saveToken/authEvents.emit.
♻️ Duplicate comments (4)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx (2)

51-55: Missing error handling for organization switch (previously flagged).

The async authClient.organization.setActive() call can fail silently. This was flagged in a previous review and remains unaddressed.


57-60: Missing error handling for sign-out (previously flagged).

Both authClient.signOut() and signOutMutation.mutate() can fail. This was flagged in a previous review and remains unaddressed.

apps/desktop/src/lib/trpc/routers/auth/index.ts (2)

48-55: Handle potential rejection from initial token load.

The loadToken().then() call lacks an error handler, which will cause an unhandled promise rejection if loadToken() fails.

Suggested fix
 // Emit initial token on subscription
 loadToken().then((initial) => {
 	if (initial.token && initial.expiresAt) {
 		emit.next({ token: initial.token, expiresAt: initial.expiresAt });
 	}
+}).catch((err) => {
+	console.error("[auth/onTokenChanged] Failed to load initial token:", err);
 });

106-112: Empty catch block silently swallows errors.

Per coding guidelines, errors should never be swallowed silently. The fs.unlink failure (e.g., permission issues) should be logged.

Suggested fix
 signOut: publicProcedure.mutation(async () => {
 	console.log("[auth] Clearing token");
 	try {
 		await fs.unlink(TOKEN_FILE);
-	} catch {}
+	} catch (err) {
+		// ENOENT is expected if token file doesn't exist
+		if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
+			console.error("[auth/signOut] Failed to clear token file:", err);
+		}
+	}
 	return { success: true };
 }),
🧹 Nitpick comments (12)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)

145-158: Migration looks correct; consider adding error handling for better UX.

The mutation hooks are properly migrated to electronTrpc. However, both openInApp and copyPath mutations lack error handling. If these operations fail silently, users won't know why their action didn't work.

💡 Optional: Add error handlers for user feedback
-	const openInApp = electronTrpc.external.openInApp.useMutation();
+	const openInApp = electronTrpc.external.openInApp.useMutation({
+		onError: (error) => {
+			console.error("[WorkspaceView/openInApp]", error.message);
+			// Optionally show toast notification to user
+		},
+	});

Similar pattern could be applied to copyPath mutation.

apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx (1)

42-47: Consider adding console logging for debugging.

The mutation works correctly and errors are shown to users via toast.promise on line 107. However, for consistency with patterns like useSetActiveWorkspace.ts and per coding guidelines about prefixed console logging, adding an onError handler with console logging would aid debugging.

♻️ Optional: Add console logging
 const switchBranch =
     electronTrpc.workspaces.switchBranchWorkspace.useMutation({
         onSuccess: () => {
             utils.workspaces.invalidate();
         },
+        onError: (error, variables) => {
+            console.error("[workspace/switchBranch] Failed to switch branch:", {
+                projectId: variables.projectId,
+                branch: variables.branch,
+                error: error.message,
+            });
+        },
     });
apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts (2)

45-50: Add error handling to fire-and-forget mutation.

createOrAttach.mutate() is called without error handling. If terminal session creation fails, the user will see a broken terminal with no indication of the cause. Per coding guidelines, errors should not be swallowed silently.

♻️ Suggested fix
 			// Pre-create terminal session (with initial commands if present)
 			// Terminal component will attach to this session when it mounts
 			createOrAttach.mutate({
 				paneId,
 				tabId,
 				workspaceId: data.workspace.id,
 				initialCommands,
+			}, {
+				onError: (error) => {
+					console.error("[workspaces/openWorktree] Failed to create terminal session:", error);
+				},
 			});

60-62: Consider adding error handling to dismissConfigToast mutation.

Similar to the above, this mutation could fail silently. While less critical than terminal creation, logging the error would aid debugging.

♻️ Suggested fix
 					onDismiss: () => {
-						dismissConfigToast.mutate({ projectId: data.projectId });
+						dismissConfigToast.mutate({ projectId: data.projectId }, {
+							onError: (error) => {
+								console.error("[workspaces/openWorktree] Failed to dismiss config toast:", error);
+							},
+						});
 					},
apps/desktop/src/renderer/react-query/presets/index.ts (1)

60-63: Consider parallelizing independent cache invalidations.

The two invalidation calls are independent and could be executed in parallel for a minor performance improvement.

♻️ Optional refactor
 		onSuccess: async (...args) => {
-			await utils.settings.getTerminalPresets.invalidate();
-			await utils.settings.getDefaultPreset.invalidate();
+			await Promise.all([
+				utils.settings.getTerminalPresets.invalidate(),
+				utils.settings.getDefaultPreset.invalidate(),
+			]);
 			await options?.onSuccess?.(...args);
 		},
apps/desktop/src/renderer/routes/sign-in/page.tsx (1)

16-31: Consider handling mutation errors.

The signInMutation has no error handling. If the sign-in fails, users won't receive feedback. Consider adding onError handling or displaying the mutation's error state.

Suggested improvement
 function SignInPage() {
 	const { data: session } = authClient.useSession();
-	const signInMutation = electronTrpc.auth.signIn.useMutation();
+	const signInMutation = electronTrpc.auth.signIn.useMutation({
+		onError: (error) => {
+			console.error("[sign-in/mutation] Sign-in failed:", error.message);
+			// Consider showing a toast or error message to the user
+		},
+	});
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (1)

23-30: Loading state may persist indefinitely on auth failure.

If authentication fails or the user logs out while on an authenticated route, this spinner will display forever with no way to recover. Consider adding a timeout or redirect to sign-in when auth state is clearly unavailable.

Suggested improvement
+	// Redirect to sign-in if no token after mount
+	if (!token) {
+		return <Navigate to="/sign-in" replace />;
+	}
+
 	// Show loading only on initial mount
 	if (!collections) {
 		return (
apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (3)

3-4: Inconsistent import path styles.

Line 3 uses the renderer/ alias while line 4 uses a relative path. Per coding guidelines, prefer using aliases defined in tsconfig.json when possible.

Suggested fix
 import { electronTrpc } from "renderer/lib/electron-trpc";
-import { electronReactClient } from "../../lib/trpc-client";
+import { electronReactClient } from "renderer/lib/trpc-client";

15-29: QueryClient configuration is duplicated.

The QueryClient instantiation with identical defaultOptions appears in both TRPCProvider and ElectronTRPCProvider. Consider extracting a shared factory function to avoid duplication per DRY principle.

Suggested approach

Create a shared utility:

// renderer/lib/query-client.ts
export function createDefaultQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: { networkMode: "always", retry: false },
      mutations: { networkMode: "always", retry: false },
    },
  });
}

Then use in both providers:

-const [queryClient] = useState(
-  () =>
-    new QueryClient({
-      defaultOptions: {
-        queries: {
-          networkMode: "always",
-          retry: false,
-        },
-        mutations: {
-          networkMode: "always",
-          retry: false,
-        },
-      },
-    }),
-);
+const [queryClient] = useState(createDefaultQueryClient);

10-14: Minor: Prefer importing ReactNode type.

For consistency with TRPCProvider.tsx which imports ReactNode from react, consider using the same pattern here instead of React.ReactNode.

Suggested fix
-import { useState } from "react";
+import { useState, type ReactNode } from "react";
 import { electronTrpc } from "renderer/lib/electron-trpc";
 import { electronReactClient } from "renderer/lib/trpc-client";

 export function ElectronTRPCProvider({
 	children,
 }: {
-	children: React.ReactNode;
+	children: ReactNode;
 }) {
apps/desktop/src/lib/trpc/routers/auth/index.ts (1)

80-84: Extract magic number to a named constant.

Per coding guidelines, hardcoded values should be extracted to named constants for clarity.

Suggested refactor
+const STATE_EXPIRY_MS = 10 * 60 * 1000; // 10 minutes
+
 // Clean up old states (older than 10 minutes)
-const tenMinutesAgo = Date.now() - 10 * 60 * 1000;
+const tenMinutesAgo = Date.now() - STATE_EXPIRY_MS;
 for (const [s, ts] of stateStore) {
 	if (ts < tenMinutesAgo) stateStore.delete(s);
 }
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)

56-62: Redundant setAuthToken call in effect.

This effect duplicates logic already present in:

  • Line 37 (subscription handler)
  • Line 50 (hydration effect)

The effect will re-run on every token change, but setAuthToken is already called at the source of token updates. Consider removing this effect to avoid redundant calls and simplify the flow.

Suggested removal
-	useEffect(() => {
-		if (token) {
-			setAuthToken(token);
-		} else {
-			setAuthToken(null);
-		}
-	}, [token]);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f28a1b and 0110503.

📒 Files selected for processing (43)
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/main/index.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/components/SetupConfigModal/SetupConfigModal.tsx
  • apps/desktop/src/renderer/hooks/useWorkspaceShortcuts.ts
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/components/SettingsSidebar/components/ProjectsSettings/ProjectsSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/project/$projectId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/page.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/screens/main/components/StartView/StartTopBar.tsx
  • apps/desktop/src/renderer/screens/main/components/StartView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/DeleteWorkspaceDialog/DeleteWorkspaceDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
🚧 Files skipped from review as they are similar to previous changes (19)
  • apps/desktop/src/renderer/screens/main/components/StartView/StartTopBar.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/ChangesHeader/ChangesHeader.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx
  • apps/desktop/src/renderer/screens/main/components/SidebarControl/SidebarControl.tsx
  • apps/desktop/src/renderer/stores/tabs/useAgentHookListener.ts
  • apps/desktop/src/renderer/screens/main/components/StartView/index.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/main/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/index.tsx
  • apps/desktop/src/renderer/hooks/useWorkspaceShortcuts.ts
  • apps/desktop/src/renderer/components/SetupConfigModal/SetupConfigModal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/project/$projectId/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/DeleteWorkspaceDialog/DeleteWorkspaceDialog.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/components/SettingsSidebar/components/ProjectsSettings/ProjectsSettings.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx
🧰 Additional context used
📓 Path-based instructions (7)
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

One component per file - do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/team/components/MemberActions/MemberActions.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Co-locate tests with implementation files using .test.ts or .test.tsx suffix

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/routes/sign-in/page.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
  • apps/desktop/src/renderer/routes/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from `trpc/server/observable` instead of async generators, as the library explicitly checks `isObservable(result)` and throws an error otherwise

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/react-query/presets/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts
  • apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/*.ts : Never import Node.js modules in shared code like electron-router-dom.ts - it runs in both main and renderer processes

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/electron-router-dom.ts : Do not import Node.js modules like node:path or dotenv in electron-router-dom.ts and similar shared files - they run in both main and renderer processes

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/*/src/components/{ui,ai-elements,react-flow}/*.tsx : Use kebab-case single files for shadcn/ui components (e.g., button.tsx, base-node.tsx) in src/components/ui/, src/components/ai-elements, and src/components/react-flow/

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Extract business logic from tRPC procedures into utility functions when logic exceeds ~50 lines, is used by multiple procedures, or needs independent testing

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/renderer/**/*.{ts,tsx} : Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.test.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Use TRPCError with appropriate error codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx
  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx
  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to **/*.{ts,tsx} : Never swallow errors silently - at minimum log them with context

Applied to files:

  • apps/desktop/src/lib/trpc/routers/auth/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.

Applied to files:

  • apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : tRPC procedures and API route handlers should validate and delegate; keep orchestrators thin

Applied to files:

  • apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx
🧬 Code graph analysis (19)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/BranchSwitcher/BranchSwitcher.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/react-query/workspaces/useSetActiveWorkspace.ts (1)
  • useSetActiveWorkspace (9-62)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/PortsList/hooks/usePortsData.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (3)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/collections.ts (1)
  • getCollections (189-213)
apps/api/src/trpc/context.ts (1)
  • createContext (4-14)
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
  • useAuthToken (86-92)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/GroupStrip/GroupStrip.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/lib/trpc/routers/auth/index.ts (1)
apps/desktop/src/lib/trpc/routers/auth/utils/auth-functions.ts (5)
  • loadToken (25-37)
  • saveToken (42-55)
  • authEvents (20-20)
  • stateStore (14-14)
  • TOKEN_FILE (13-13)
apps/desktop/src/renderer/screens/main/components/TopBar/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (4)
apps/api/src/trpc/context.ts (1)
  • createContext (4-14)
apps/desktop/src/renderer/providers/AuthProvider/index.ts (2)
  • AuthProvider (1-1)
  • useAuthToken (1-1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/lib/auth-client.ts (1)
  • setAuthToken (7-9)
apps/desktop/src/renderer/react-query/workspaces/useOpenWorktree.ts (3)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/main/lib/terminal/manager.ts (1)
  • createOrAttach (24-60)
apps/desktop/src/renderer/stores/config-modal.ts (1)
  • useOpenConfigModal (34-35)
apps/desktop/src/renderer/routes/sign-in/page.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspaceRow/WorkspaceRow.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/constants.ts (1)
  • GITHUB_STATUS_STALE_TIME (9-9)
apps/desktop/src/renderer/react-query/presets/index.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/screens/main/components/WorkspacesListView/WorkspacesListView.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/index.tsx (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/react-query/workspaces/useDeleteWorktree.ts (1)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (2)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/lib/trpc-client.ts (1)
  • electronReactClient (9-11)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebarHeader/OrganizationDropdown.tsx (2)
apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/CollectionsProvider.tsx (1)
  • useCollections (39-45)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/routes/layout.tsx (5)
apps/desktop/src/renderer/providers/PostHogProvider/PostHogProvider.tsx (1)
  • PostHogProvider (10-24)
apps/desktop/src/renderer/providers/ElectronTRPCProvider/ElectronTRPCProvider.tsx (1)
  • ElectronTRPCProvider (10-39)
apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx (1)
  • AuthProvider (17-84)
apps/desktop/src/renderer/providers/TRPCProvider/TRPCProvider.tsx (1)
  • TRPCProvider (10-47)
apps/desktop/src/renderer/providers/MonacoProvider/MonacoProvider.tsx (1)
  • MonacoProvider (73-105)
apps/desktop/src/renderer/screens/main/components/WorkspaceInitEffects.tsx (3)
apps/desktop/src/main/lib/terminal/manager.ts (1)
  • createOrAttach (24-60)
apps/desktop/src/renderer/lib/electron-trpc.ts (1)
  • electronTrpc (9-9)
apps/desktop/src/renderer/stores/config-modal.ts (1)
  • useOpenConfigModal (34-35)
⏰ 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). (6)
  • GitHub Check: Deploy API
  • GitHub Check: Deploy Admin
  • GitHub Check: Deploy Docs
  • GitHub Check: Deploy Web
  • GitHub Check: Deploy Marketing
  • GitHub Check: Build

Comment on lines +33 to +44
electronTrpc.auth.onTokenChanged.useSubscription(undefined, {
onData: (data) => {
if (data?.token && data?.expiresAt) {
setToken(data.token);
setAuthToken(data.token);
persistMutation.mutate({
token: data.token,
expiresAt: data.expiresAt,
});
}
},
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Infinite mutation loop: subscription handler should not re-persist the token.

The onTokenChanged subscription fires when a token is saved (via authEvents.emit("token-saved")). The handler then calls persistMutation.mutate(), which invokes saveToken(), which emits "token-saved" again—creating an infinite loop.

The subscription exists to notify the renderer when OAuth callback (in main process) saves a new token. At that point the token is already persisted; the renderer only needs to update local state.

Suggested fix
 electronTrpc.auth.onTokenChanged.useSubscription(undefined, {
 	onData: (data) => {
 		if (data?.token && data?.expiresAt) {
 			setToken(data.token);
 			setAuthToken(data.token);
-			persistMutation.mutate({
-				token: data.token,
-				expiresAt: data.expiresAt,
-			});
 		}
 	},
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
electronTrpc.auth.onTokenChanged.useSubscription(undefined, {
onData: (data) => {
if (data?.token && data?.expiresAt) {
setToken(data.token);
setAuthToken(data.token);
persistMutation.mutate({
token: data.token,
expiresAt: data.expiresAt,
});
}
},
});
electronTrpc.auth.onTokenChanged.useSubscription(undefined, {
onData: (data) => {
if (data?.token && data?.expiresAt) {
setToken(data.token);
setAuthToken(data.token);
}
},
});
🤖 Prompt for AI Agents
In @apps/desktop/src/renderer/providers/AuthProvider/AuthProvider.tsx around
lines 33 - 44, The subscription handler for
electronTrpc.auth.onTokenChanged.useSubscription is causing an infinite loop by
calling persistMutation.mutate (which calls saveToken and re-emits
"token-saved"); update the handler to stop re-persisting: remove the
persistMutation.mutate(...) call and only call setToken and setAuthToken when
data is received (you may keep the token/expiresAt presence check), leaving
token persistence to the original saveToken path that emits authEvents; ensure
no other code in this handler triggers saveToken/authEvents.emit.

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.

2 participants