-
Notifications
You must be signed in to change notification settings - Fork 206
Fix Windows freezes from terminal history loading and home-directory Git scans #591
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Windows freezes on startup or window focus | ||
|
|
||
| A September 3, 2026 report described the latest version as "lagging" and "freezing all the time." The reported investigation found a 250 MB `sessions.db`, approximately 200 MB of terminal history across 92 stopped sessions, an accidental Git repository at the Windows user profile root, and the isolated PTY host disabled. Windows recorded `AppHangTransient`. | ||
|
|
||
| ## Prevention | ||
|
|
||
| - Startup loads only logs and browser panels that need restart cleanup. Terminal state is restored on demand when accessed, including history for stopped and archived sessions. | ||
| - Workspace summaries exclude raw and serialized terminal buffers in SQLite before returning rows to JavaScript. Summary reads do not replace complete cached panel state or write reduced state back to disk. | ||
| - Automatic Git status checks and filesystem watching skip the home directory, log a diagnostic, and report unknown Git status. Windows path comparison ignores case and normalizes separators and dot segments. Choose the actual project folder instead of `C:\Users\<user>`. Existing repository records and `.git` directories are not deleted. | ||
| - New configurations no longer use the home directory as an implicit Git repository. Legacy home-directory `gitRepoPath` values are rejected by the migration accessor. | ||
| - The isolated PTY host defaults to enabled on Windows, including existing configurations without a `usePtyHost` value. Explicit `false` values are preserved. Enable **Settings > Advanced > Use isolated PTY host** and restart Pane to change an existing opt-out. `PANE_USE_PTY_HOST=1` still forces it on for development. | ||
|
|
||
| Terminal history remains on disk. The existing 21-day retention policy for archived sessions is unchanged, and no full `VACUUM` runs during startup. A large database file does not by itself mean all history is resident in the JavaScript heap. | ||
|
|
||
| ## Manual Windows verification | ||
|
|
||
| 1. Use an isolated `PANE_DIR` with a copy of a database containing many stopped and archived terminal panels. Launch Pane, inspect responsiveness and heap use, then reopen an old terminal and verify its history. | ||
| 2. In an isolated test profile with a home-directory Git repository, select a session whose worktree path is that home directory. Repeatedly blur/focus Pane. Confirm no recursive watcher or Git status scan starts, and check the diagnostic in the main-process log. Verify a normal project beneath the profile still refreshes. | ||
| 3. Start with a config missing `usePtyHost`: confirm the settings toggle is enabled and the supervisor forks on Windows. Repeat with explicit `false`, then enable the setting and restart. | ||
|
|
||
| The automated tests cover persistence, summary projections, path normalization, Git scan entry points, and platform defaults. They do not reproduce Windows `AppHangTransient` or validate a packaged Windows PTY host. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import fs from 'fs'; | ||
| import os from 'os'; | ||
| import path from 'path'; | ||
| import { describe, expect, it } from 'vitest'; | ||
| import { DatabaseService } from './database'; | ||
|
|
||
| describe('panel history loading', () => { | ||
| it('keeps terminal history out of startup and workspace summaries while preserving restoration', () => { | ||
| const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pane-panel-loading-')); | ||
| const db = new DatabaseService(path.join(tempDir, 'sessions.db')); | ||
| try { | ||
| db.initialize(); | ||
| const history = 'terminal output\r\n'.repeat(65536); | ||
| for (let index = 0; index < 12; index++) { | ||
| const id = `session-${index}`; | ||
| db.createSession({ | ||
| id, name: id, initial_prompt: '', worktree_name: id, | ||
| worktree_path: tempDir, project_id: null, tool_type: 'none', | ||
| }); | ||
| db.markSessionsAsStopped([id]); | ||
| db.createPanel({ | ||
| id: `panel-${index}`, sessionId: id, type: 'terminal', title: 'Terminal', | ||
| state: { isActive: false, customState: { | ||
| scrollbackBuffer: history, serializedBuffer: history, | ||
| cwd: tempDir, isCliPanel: true, agentType: 'claude', | ||
| } }, | ||
| }); | ||
| if (index % 2 === 0) db.archiveSession(id); | ||
| } | ||
| db.createPanel({ id: 'logs', sessionId: 'session-1', type: 'logs', title: 'Logs' }); | ||
| db.createPanel({ id: 'browser', sessionId: 'session-1', type: 'browser', title: 'Browser' }); | ||
|
|
||
| expect(db.getPanelsForStartup().map(panel => panel.id).sort()).toEqual(['browser', 'logs']); | ||
| for (let index = 0; index < 12; index++) { | ||
| const summary = db.getPanelsForSession(`session-${index}`, false)[0]; | ||
| expect(summary.state.customState).toEqual({ cwd: tempDir, isCliPanel: true, agentType: 'claude' }); | ||
| expect(db.getPanel(`panel-${index}`)?.state.customState).toMatchObject({ scrollbackBuffer: history }); | ||
| } | ||
| expect(db.getPanelsForSession('session-0')[0].state.customState).toMatchObject({ serializedBuffer: history }); | ||
| db.createPanel({ | ||
| id: 'legacy', sessionId: 'session-0', type: 'terminal', title: 'Legacy', | ||
| state: JSON.stringify({ isActive: false, customState: { scrollbackBuffer: [history], cwd: tempDir } }), | ||
| }); | ||
| expect(db.getPanelsForSession('session-0', false).find(panel => panel.id === 'legacy')?.state.customState) | ||
| .toEqual({ cwd: tempDir }); | ||
| } finally { | ||
| db.close(); | ||
| fs.rmSync(tempDir, { recursive: true, force: true }); | ||
| } | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Windows with a WSL-backed project, stored worktree paths are POSIX paths such as
/home/alice, whileisHomeDirectory()defaults to the host'sos.homedir()andwin32path handling, so this check compares that path against something likeC:\Users\Aliceand always returns false. If the WSL user's home is accidentally a repository, execution therefore continues intostartWSLNativeWatcher()and its recursiveinotifywaitor five-secondgit statusfallback; the corresponding status guard fails for the same reason, preserving the freeze this change is intended to prevent. Resolve the distro's home directory whencommandRunner.wslContextis present and compare using POSIX semantics.AGENTS.md reference: AGENTS.md:L47-L47
Useful? React with 👍 / 👎.