worktree-tool
Version:
A command-line tool for managing Git worktrees with integrated tmux/shell session management
170 lines (169 loc) • 5.84 kB
JavaScript
import { spawn } from "child_process";
import { promises as fs } from "fs";
import * as os from "os";
import * as path from "path";
import { getErrorMessage } from "../utils/error-handler.js";
import { PlatformError } from "../utils/errors.js";
import { TerminalManager } from "./terminal-strategy.js";
/**
* Get the shell command for the given shell type
*/
export function getShellCommand(shellType) {
switch (shellType) {
case "bash":
return "bash";
case "zsh":
return "zsh";
case "powershell":
return "powershell";
default:
throw new PlatformError(`Unsupported shell type: ${shellType}`);
}
}
/**
* Get the shell arguments for the given shell type
*/
export function getShellArgs(shellType) {
switch (shellType) {
case "bash":
case "zsh":
return ["-i"]; // Interactive mode
case "powershell":
return ["-NoExit"]; // Don't exit after running commands
default:
throw new PlatformError(`Unsupported shell type: ${shellType}`);
}
}
/**
* Set the shell prompt for the given shell type and worktree name
* Simple format: [worktreeName] >
*/
export function setShellPrompt(shellType, worktreeName) {
const promptPrefix = `[${worktreeName}] > `;
switch (shellType) {
case "bash":
return [`export PS1="${promptPrefix}"`];
case "zsh":
return [`export PROMPT="${promptPrefix}"`];
case "powershell":
return [`function prompt { "${promptPrefix}" }`];
default:
throw new PlatformError(`Unsupported shell type: ${shellType}`);
}
}
/**
* Spawn a shell in the specified directory with a custom prompt
* Uses shell-specific approaches to ensure prompt is properly set
*/
export async function spawnShell(directory, shellType, worktreeName) {
return new Promise((resolve, reject) => {
void (async () => {
try {
const command = getShellCommand(shellType);
const promptPrefix = `[${worktreeName}] > `;
let args;
const env = { ...process.env };
const tempFiles = [];
switch (shellType) {
case "bash": {
// Create temporary bashrc file with custom prompt
const bashrc = `
# Load original bashrc if it exists
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# Set custom prompt
export PS1="${promptPrefix}"
`;
const tmpBashrc = path.join(os.tmpdir(), `wtt-bashrc-${Date.now().toString()}`);
await fs.writeFile(tmpBashrc, bashrc);
tempFiles.push(tmpBashrc);
args = ["--rcfile", tmpBashrc];
break;
}
case "zsh":
// Set PROMPT environment variable for zsh
env.PROMPT = promptPrefix;
args = ["-i"]; // Interactive mode
break;
case "powershell":
// Set prompt function and stay open
args = ["-NoExit", "-Command", `function prompt { "${promptPrefix}" }`];
break;
default:
throw new PlatformError(`Unsupported shell type: ${shellType}`);
}
const child = spawn(command, args, {
stdio: "inherit",
cwd: directory,
env: env,
detached: false,
});
child.on("error", (error) => {
reject(new PlatformError(`Failed to spawn shell: ${error.message}`));
});
child.on("exit", (code) => {
// Clean up temporary files
void (async () => {
for (const tempFile of tempFiles) {
try {
await fs.unlink(tempFile);
}
catch {
// Ignore cleanup errors
}
}
})();
if (code === 0 || code === null) {
resolve();
}
else {
reject(new PlatformError(`Shell exited with code ${String(code)}`));
}
});
}
catch (error) {
reject(new PlatformError(`Failed to spawn shell: ${getErrorMessage(error)}`));
}
})();
});
}
/**
* Check if a shell command is available on the system
*/
export async function isShellAvailable(shellType) {
return new Promise((resolve) => {
try {
const command = getShellCommand(shellType);
const child = spawn(command, ["--version"], {
stdio: "ignore",
});
child.on("error", () => {
resolve(false);
});
child.on("exit", (code) => {
resolve(code === 0);
});
}
catch {
resolve(false);
}
});
}
/**
* ShellManager class for managing shell operations
*/
export class ShellManager {
terminalManager;
constructor() {
this.terminalManager = new TerminalManager();
}
/**
* Execute a command in a new window
*/
async executeInNewWindow(command, cwd, windowTitle) {
// Use the terminal manager to open a new window
await this.terminalManager.openWindow(command, cwd, windowTitle);
}
}
//# sourceMappingURL=shell.js.map