Skip to content

fix (desktop): git lock fix and duplicate input bug#263

Merged
AviPeltz merged 4 commits intomainfrom
compact-capybara-287ced
Dec 6, 2025
Merged

fix (desktop): git lock fix and duplicate input bug#263
AviPeltz merged 4 commits intomainfrom
compact-capybara-287ced

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Dec 5, 2025

Description

Related Issues

Type of Change

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

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • Bug Fixes

    • Better detection and messaging for locked Git repositories during workspace operations, with safe guidance for removing lock files.
  • Improvements

    • More reliable terminal focus and keyboard handling to ensure the latest focus handler is used and cleaned up.
    • Improved macOS window reopen behavior so window controls and IPC tolerate recreated windows and avoid stale references.
  • New Features

    • Added a utility to detach terminal listeners during window lifecycle events.

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

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
website Error Error Dec 6, 2025 0:00am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 5, 2025

Walkthrough

Replace direct BrowserWindow use with a getWindow() getter across routers and main window lifecycle; add TerminalManager.detachAllListeners(); detect git lock-file errors in createWorktree; and refactor terminal focus/keyboard handling to use a ref and a returned cleanup function.

Changes

Cohort / File(s) Summary
Git lock detection
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
In createWorktree catch block, detect lock-related errors (messages like "could not lock", "unable to lock", or presence of .lock files), log diagnostics, and throw a specialized "repository locked" error before existing LFS and generic error branches.
Terminal focus & keyboard refactor
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.ts
Replace useCallback capture with a ref (handleTerminalFocusRef) to ensure latest focus handler is used; setupKeyboardHandler now returns a cleanup function () => void that reattaches a no-op handler to remove prior key handlers. Effect dependencies and cleanup wiring updated accordingly.
Window getter / router signature changes
apps/desktop/src/lib/trpc/routers/index.ts, apps/desktop/src/lib/trpc/routers/projects/projects.ts, apps/desktop/src/lib/trpc/routers/window.ts, apps/desktop/src/main/windows/main.ts
Change router factories to accept `getWindow: () => BrowserWindow
TerminalManager listener detach
apps/desktop/src/main/lib/terminal-manager.ts
Add public method detachAllListeners(): void to remove terminal data: and exit: listeners (avoids duplicate subscribers when windows close/reopen on macOS) while leaving terminal instances running.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Renderer as Renderer (Terminal UI)
  participant IPC as IPC Handler (main)
  participant Main as Main Window Manager
  participant Router as TRPC Routers
  participant TerminalMgr as TerminalManager

  Renderer->>IPC: send request (via trpc) -> e.g., open/terminal actions
  IPC->>Main: ask for current window via getWindow()
  Main-->>IPC: return BrowserWindow or null
  IPC->>Router: route request (routers use getWindow())
  alt window present
    Router->>Main: may invoke window methods (minimize/maximize/...), using getWindow()
    Router-->>Renderer: success response
  else no window
    Router-->>Renderer: short-circuit error/false result
  end

  Note over Main,TerminalMgr: On window close
  Main->>TerminalMgr: detachAllListeners()
  TerminalMgr-->>Main: listeners removed (terminals remain)
  Main->>IPC: detach window-specific handlers
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • main/windows/main.ts — IPC handler reuse, lifecycle and getWindow wiring to avoid duplicate handlers or stale references.
    • projects.ts — multiple dialog flows now depend on getWindow(); ensure error shapes and early returns are handled consistently.
    • git.ts — confirm lock-detection patterns and thrown error format match consumer expectations.
    • Terminal keyboard/focus cleanup — verify returned cleanup is invoked and no stale XTerm handlers persist.

Possibly related PRs

  • PR #256 — Related worktree/git utilities changes; overlaps with LFS and worktree error handling alterations.
  • PR #124 — Terminal subsystem refactors (Terminal components/helpers, xterm integration); related to keyboard/focus changes.
  • PR #59 — Main-window creation and IPC/window-management changes; related to getWindow/getting current window and IPC handler reuse.

Poem

🐇 I nudged the locks and hopped the fence,
A ref for focus, no stale suspense.
Windows fetched by a gentle getter,
Listeners swept so things run better.
Hop, code, hop — a tidy little venture! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is mostly empty template boilerplate with only the 'Bug fix' checkbox marked, but no actual details about what was changed, why, or how to test it. Complete the Description section with details about the git lock error handling and duplicate input bug fixes, fill in Related Issues if applicable, and add Testing steps to verify the changes work correctly.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title references two distinct issues (git lock and duplicate input), but the summary shows the changes span multiple unrelated refactorings to router signatures and terminal handling. Clarify whether the title should focus on the primary change or be more specific about what 'duplicate input bug' refers to in the context of the multiple router and terminal modifications.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch compact-capybara-287ced

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.

@AviPeltz AviPeltz marked this pull request as ready for review December 5, 2025 23:13
Copy link
Copy Markdown
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: 0

🧹 Nitpick comments (1)
apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (1)

182-199: Lock error detection is solid; consider preserving original error details

The new isLockError heuristics capture the common git lock failure shapes and running this check before the LFS branch is the right call, so this should fix misclassified lock/LFS errors.

One small improvement: the thrown Error drops the original message, which can make debugging harder. You could either append it to the message or use an error cause so upstream handlers and logs retain full context, e.g.:

if (isLockError) {
	console.error(
		`Git lock file error during worktree creation: ${errorMessage}`,
	);
	throw new Error(
		`Failed to create worktree: The git repository is locked by another process. ` +
			`This usually happens when another git operation is in progress, or a previous operation crashed. ` +
			`Please wait for the other operation to complete, or manually remove the lock file ` +
			`(e.g., .git/config.lock or .git/index.lock) if you're sure no git operations are running. ` +
			`Original error: ${errorMessage}`,
		// Or, if your TS/Node target supports it:
		// { cause: error instanceof Error ? error : undefined },
	);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1aa4b0 and 973ffb5.

📒 Files selected for processing (3)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (6 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
apps/desktop/**/*.{ts,tsx,js,jsx}

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

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/**/*.{ts,tsx}

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

apps/desktop/**/*.{ts,tsx}: Please 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

Files:

  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/src/lib/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in shared code like src/lib/electron-router-dom.ts - this code runs in both main and renderer processes

Files:

  • apps/desktop/src/lib/trpc/routers/workspaces/utils/git.ts
apps/desktop/src/renderer/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules (fs, path, os, net, etc.) in renderer process code - browser environment only

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
**/components/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

**/components/**/*.tsx: Create one folder per component with structure: ComponentName/ComponentName.tsx + index.ts for barrel export
Co-locate tests next to the component file they test (e.g., ComponentName.test.tsx)
Co-locate dependencies (utils, hooks, constants, config, stories) next to the file using them
Use nested components/ subdirectory within a parent component only if a sub-component is used 2+ times within that parent; otherwise keep it in the parent's components/ folder
One component per file - avoid multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Call IPC methods using window.ipcRenderer.invoke() with object parameters - TypeScript will infer the exact response type automatically

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
🧠 Learnings (1)
📚 Learning: 2025-11-28T01:03:47.963Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.963Z
Learning: Applies to **/*.{ts,tsx} : Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications

Applied to files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
🔇 Additional comments (3)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (1)

137-213: Keyboard handler setup + cleanup look correct and resolve stale-handler risk

Defining the handler locally, attaching it once via attachCustomKeyEventHandler, and returning a cleanup that replaces it with a no-op is a clean way to avoid stale closures or duplicate handlers when terminals are torn down/recreated. The existing Shift+Enter, Cmd+K, and app-hotkey forwarding behavior is preserved while ensuring React’s effect cleanup can fully detach the behavior.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (2)

101-109: Ref-based focus handler avoids unnecessary terminal recreation

Using handleTerminalFocusRef to hold the latest focus callback and wiring setupFocusListener to call handleTerminalFocusRef.current() is a good way to keep the effect’s dependency list small and avoid tearing down/recreating the terminal whenever pane focus logic changes, while still always using the latest pane/windowId.


250-261: Keyboard handler lifecycle is now correctly tied to the terminal effect

Capturing the return from setupKeyboardHandler and invoking cleanupKeyboard() in the effect cleanup, alongside cleanupFocus/cleanupResize, properly scopes the custom key handling to the lifetime of this xterm instance. This should prevent stale handlers and duplicate input when the terminal effect re-runs (e.g., under React StrictMode or when dependencies change), while keeping the main effect dependency array focused on terminal creation inputs only.

Also applies to: 262-265, 275-279, 289-289

Copy link
Copy Markdown
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: 0

🧹 Nitpick comments (2)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (2)

98-101: New no-window path in openNew – ensure caller handles the error variant

The early return when getWindow() is null avoids dialog calls without a window, which is good. It does, however, introduce a new result variant { canceled: false, error: "No window available" } (no project). Please confirm the consumer of this mutation distinguishes between “user canceled” vs. “system error” (presence of error) and doesn’t assume canceled === false always implies a valid project.

If you want to tighten the API, you could consider a small follow-up that formalizes the result as a discriminated union (e.g., type = "success" | "canceled" | "error") to make these states explicit in the client.


176-183: Consistent no-window handling in cloneRepo – consider de-duplicating the error shape

The guard around getWindow() in the “no targetDir” path looks correct and matches the other error-style returns (canceled: false, success: false, error: …). This should avoid unexpected dialog calls when no window is available.

If this “No window available” case is used in multiple routes (here and in openNew), you might consider a tiny helper or shared constant for the error message/shape so callers can handle it consistently and tests don’t need to duplicate the literal.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49f5e39 and 11fb93c.

📒 Files selected for processing (2)
  • apps/desktop/src/lib/trpc/routers/projects/projects.ts (3 hunks)
  • apps/desktop/src/main/lib/terminal-manager.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/main/lib/terminal-manager.ts
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx,js,jsx}

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

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
apps/desktop/**/*.{ts,tsx}

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

apps/desktop/**/*.{ts,tsx}: Please 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

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
apps/desktop/src/lib/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Never import Node.js modules in shared code like src/lib/electron-router-dom.ts - this code runs in both main and renderer processes

Files:

  • apps/desktop/src/lib/trpc/routers/projects/projects.ts
🧬 Code graph analysis (1)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (1)
apps/desktop/src/lib/trpc/routers/projects/index.ts (1)
  • createProjectsRouter (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). (1)
  • GitHub Check: Build
🔇 Additional comments (1)
apps/desktop/src/lib/trpc/routers/projects/projects.ts (1)

83-83: All call sites properly updated for the getWindow callback pattern

The one call site in apps/desktop/src/lib/trpc/routers/index.ts correctly passes the getWindow callback to createProjectsRouter, matching the new signature. The type is properly threaded through from createAppRouter's parameter.

@AviPeltz AviPeltz merged commit 80c5b10 into main Dec 6, 2025
6 of 7 checks passed
@Kitenite Kitenite deleted the compact-capybara-287ced branch December 7, 2025 01:58
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.

1 participant