worktree-tool
Version:
A command-line tool for managing Git worktrees with integrated tmux/shell session management
96 lines • 4.16 kB
JavaScript
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