Skip to content

fix(main): requestSingleInstanceLock to prevent PTY loss on replace#56

Open
JeanBaptisteRenard wants to merge 1 commit into
doctly:mainfrom
JeanBaptisteRenard:upstream/fix-single-instance-lock
Open

fix(main): requestSingleInstanceLock to prevent PTY loss on replace#56
JeanBaptisteRenard wants to merge 1 commit into
doctly:mainfrom
JeanBaptisteRenard:upstream/fix-single-instance-lock

Conversation

@JeanBaptisteRenard

Copy link
Copy Markdown

Closes #31.

Problem

Replacing the installed binary (e.g. an AppImage on Linux) while Switchboard has active node-pty sessions can kill or orphan those sessions. The OS launches the new binary, which initialises a second Electron process; the two race on user-data and PTY pipes.

I hit this on 2026-05-23 when overwriting ~/Applications/Switchboard.AppImage while a Claude CLI session was running — the running PTY died silently and the renderer reconnected to nothing.

Fix

Electron's standard app.requestSingleInstanceLock():

  • The first instance acquires the lock and continues normally.
  • Any subsequent launch fails to acquire the lock, calls app.quit() immediately, and exits without touching the existing process or its PTYs.
  • A 'second-instance' listener on the first instance brings its main window to the front, so the user sees the existing app instead of nothing happening.

The whole existing app.whenReady().then(...) block is wrapped in the else branch so it only runs for the genuine first instance.

Issue link

Also requested in #31 ("Feature request: single-instance mode (focus existing window when re-launched)") — same mechanism solves both the data-loss case and the UX issue.

Tested on

Linux / AppImage. The mechanism is platform-agnostic; requestSingleInstanceLock is documented for all three desktop platforms.

Notes

  • I have a fork branch off this change that touches more files (worktree dialog, subagent observability, etc.). This PR is intentionally minimal — just the single-instance lock so it can land independently.
  • If you'd like a test for the second-instance path I can add one, though it's tricky to spawn a second Electron in a unit test; manual repro is the easiest validation.

… replace

On 2026-05-23, replacing the AppImage while Switchboard had active node-pty
sessions killed those sessions. The OS spawned the new binary which initialised
a second Electron process; the two instances raced and the running PTYs were
orphaned/killed.

Electron's requestSingleInstanceLock() is the standard fix:
- The first instance acquires the lock and continues normally.
- Any subsequent launch (e.g. the new AppImage binary after an in-place replace)
  fails to acquire the lock, calls app.quit() immediately, and exits without
  touching any PTY.
- A 'second-instance' listener on the first instance brings its main window to
  the front, so the user gets visual confirmation the app is still running.

Changes:
- main.js: call app.requestSingleInstanceLock() before app.whenReady()
- Wrap app.whenReady() and all init code in the else-branch so it only runs for
  the true first instance
- Register app.on('second-instance') to restore/focus mainWindow
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.

Feature request: single-instance mode (focus existing window when re-launched)

1 participant