From 2e8869607162cec62ebcbc11b67978fa09f40bd0 Mon Sep 17 00:00:00 2001 From: Amrit Subramanian Date: Tue, 7 Oct 2025 14:55:35 -0400 Subject: [PATCH] Add configurable worktree root directory setting Users can now configure where worktrees are stored via the settings modal. The setting is persisted and applies to all new sessions created after the change. Changes: - Added worktreeDir field to TerminalSettings interface - Added UI controls in settings modal for selecting worktree directory - Updated worktree creation logic to use configured directory - Defaults to ~/worktrees for backward compatibility --- index.html | 9 +++++++++ main.ts | 14 +++++++++++--- renderer.ts | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index e3ce5f7..5ee5d7b 100644 --- a/index.html +++ b/index.html @@ -225,6 +225,15 @@ +
+ +
+ + +
+ Directory where session worktrees will be stored +
+
diff --git a/main.ts b/main.ts index 61aa526..84405a8 100644 --- a/main.ts +++ b/main.ts @@ -22,6 +22,14 @@ function getPersistedSessions(): PersistedSession[] { return (store as any).get("sessions", []); } +function getWorktreeBaseDir(): string { + const settings = (store as any).get("terminalSettings"); + if (settings && settings.worktreeDir) { + return settings.worktreeDir; + } + return path.join(os.homedir(), "worktrees"); +} + function isTerminalReady(buffer: string, startPos: number = 0): boolean { const searchBuffer = buffer.slice(startPos); @@ -63,7 +71,7 @@ function extractProjectMcpConfig(projectDir: string): any { // Get a safe directory name from project path, with collision handling function getProjectWorktreeDirName(projectDir: string): string { const baseName = path.basename(projectDir); - const worktreesBaseDir = path.join(os.homedir(), "worktrees"); + const worktreesBaseDir = getWorktreeBaseDir(); const candidatePath = path.join(worktreesBaseDir, baseName); // If directory doesn't exist or points to the same project, use base name @@ -90,7 +98,7 @@ function getProjectWorktreeDirName(projectDir: string): string { function writeMcpConfigFile(projectDir: string, mcpServers: any): string | null { try { const projectDirName = getProjectWorktreeDirName(projectDir); - const worktreesDir = path.join(os.homedir(), "worktrees"); + const worktreesDir = getWorktreeBaseDir(); if (!fs.existsSync(worktreesDir)) { fs.mkdirSync(worktreesDir, { recursive: true }); } @@ -303,7 +311,7 @@ async function createWorktree(projectDir: string, parentBranch: string, sessionN const git = simpleGit(projectDir); const projectDirName = getProjectWorktreeDirName(projectDir); - const worktreesBaseDir = path.join(os.homedir(), "worktrees"); + const worktreesBaseDir = getWorktreeBaseDir(); const projectWorktreeDir = path.join(worktreesBaseDir, projectDirName); const worktreeName = customBranchName || `session${sessionNumber}`; const worktreePath = path.join(projectWorktreeDir, worktreeName); diff --git a/renderer.ts b/renderer.ts index 8aa1a50..c593187 100644 --- a/renderer.ts +++ b/renderer.ts @@ -30,6 +30,7 @@ interface TerminalSettings { fontSize: number; theme: string; // Theme preset name cursorBlink: boolean; + worktreeDir: string; } interface ThemeColors { @@ -203,6 +204,7 @@ const DEFAULT_SETTINGS: TerminalSettings = { fontSize: 11, theme: getSystemTheme() === "dark" ? "macos-dark" : "macos-light", cursorBlink: false, + worktreeDir: require("path").join(require("os").homedir(), "worktrees"), }; const sessions = new Map(); @@ -1217,6 +1219,8 @@ const settingsTheme = document.getElementById("settings-theme") as HTMLSelectEle const settingsFontFamily = document.getElementById("settings-font-family") as HTMLSelectElement; const settingsFontSize = document.getElementById("settings-font-size") as HTMLInputElement; const settingsCursorBlink = document.getElementById("settings-cursor-blink") as HTMLInputElement; +const settingsWorktreeDir = document.getElementById("settings-worktree-dir") as HTMLInputElement; +const browseWorktreeDirBtn = document.getElementById("browse-worktree-dir"); // Load saved settings on startup async function loadSettings() { @@ -1243,6 +1247,7 @@ function populateSettingsForm() { settingsFontSize.value = terminalSettings.fontSize.toString(); settingsCursorBlink.checked = terminalSettings.cursorBlink; + settingsWorktreeDir.value = terminalSettings.worktreeDir; } // Apply settings to all existing terminals @@ -1281,6 +1286,14 @@ resetSettingsBtn?.addEventListener("click", () => { populateSettingsForm(); }); +// Browse worktree directory +browseWorktreeDirBtn?.addEventListener("click", async () => { + const dir = await ipcRenderer.invoke("select-directory"); + if (dir) { + settingsWorktreeDir.value = dir; + } +}); + // Save settings saveSettingsBtn?.addEventListener("click", async () => { // Read values from form @@ -1288,6 +1301,7 @@ saveSettingsBtn?.addEventListener("click", async () => { terminalSettings.fontFamily = settingsFontFamily.value || DEFAULT_SETTINGS.fontFamily; terminalSettings.fontSize = parseInt(settingsFontSize.value) || DEFAULT_SETTINGS.fontSize; terminalSettings.cursorBlink = settingsCursorBlink.checked; + terminalSettings.worktreeDir = settingsWorktreeDir.value || DEFAULT_SETTINGS.worktreeDir; // Save to electron-store await ipcRenderer.invoke("save-terminal-settings", terminalSettings);