UNPKG

worktree-tool

Version:

A command-line tool for managing Git worktrees with integrated tmux/shell session management

96 lines 4.16 kB
import { ShellManager } from "../../platform/shell.js"; import { createTmuxSessionWithWindow, createTmuxWindowWithCommand, isTmuxAvailable, sanitizeTmuxName, sanitizeTmuxWindowName, tmuxSessionExists, } from "../../platform/tmux.js"; import { tmuxWindowManager } from "../../platform/tmux-window-manager.js"; import { getErrorMessage } from "../../utils/error-handler.js"; import { ExecutionMode } from "./base.js"; export class WindowMode extends ExecutionMode { config; logger; constructor(config, logger) { super(); this.config = config; this.logger = logger; } async execute(contexts) { const hasTmux = await isTmuxAvailable(); const sessionName = sanitizeTmuxName(this.config.projectName); const sessionExists = this.config.tmux && hasTmux ? await tmuxSessionExists(sessionName) : false; let failureCount = 0; for (let i = 0; i < contexts.length; i++) { const context = contexts[i]; if (!context) { continue; } const windowName = sanitizeTmuxWindowName(`${context.worktreeName}::exec`); try { if (this.config.tmux && hasTmux) { await this.executeTmux(context, windowName, sessionName, i === 0 && !sessionExists); } else { await this.executeShell(context, windowName); } this.logger.success(`Started in ${context.worktreeName}: ${context.command}`); } catch (error) { this.logger.error(`Failed to start in ${context.worktreeName}: ${getErrorMessage(error)}`); failureCount++; } } if (failureCount > 0) { throw new Error(`${String(failureCount)} command(s) failed to start`); } // Sort windows alphabetically if autoSort is enabled and tmux is being used if (this.config.autoSort && this.config.tmux && hasTmux) { try { await tmuxWindowManager.sortWindowsAlphabetically(sessionName); } catch (error) { this.logger.warn(`Failed to sort windows: ${getErrorMessage(error)}`); } } } async executeTmux(context, windowName, sessionName, isFirstWindow) { const fullCommand = this.buildFullCommand(context); if (isFirstWindow) { await createTmuxSessionWithWindow(sessionName, windowName, context.worktreePath, fullCommand); } else { await createTmuxWindowWithCommand(sessionName, windowName, context.worktreePath, fullCommand); } } async executeShell(context, windowName) { const shell = new ShellManager(); const command = this.buildCommand(context); // Set environment variables in current process for the shell const env = this.getEnvironment(context); for (const [key, value] of Object.entries(env)) { if (key.startsWith("WTT_")) { process.env[key] = value; } } await shell.executeInNewWindow(command, context.worktreePath, windowName); } buildCommand(context) { const args = context.args.map((arg) => { // Quote args that contain spaces if (arg.includes(" ")) { return `"${arg}"`; } return arg; }); return [context.command, ...args].join(" "); } buildFullCommand(context) { // Build environment variable exports const env = this.getEnvironment(context); const envCommands = Object.entries(env) .filter(([key]) => key.startsWith("WTT_")) .map(([key, value]) => `export ${key}="${value}"`) .join("; "); const command = this.buildCommand(context); // Create the full command to run in the shell // Add `exec bash` at the end to keep the window open after the command finishes return `${envCommands}; clear; echo "Running: ${command}"; echo; ${command}; exec bash`; } } //# sourceMappingURL=window.js.map