Files
terminal-layout-sync/src/utils/shellUtils.ts
7000pctAUTO 2aec2b93d9
Some checks failed
CI / test (push) Has been cancelled
Initial upload with CI/CD workflow
2026-02-05 19:31:49 +00:00

71 lines
2.0 KiB
TypeScript

import { execa, ExecaError } from 'execa';
import { ExecResult } from '../models/types';
export class ShellUtils {
async exec(command: string, options?: { cwd?: string; timeout?: number }): Promise<ExecResult> {
try {
const result = await execa(command, {
shell: '/bin/bash',
cwd: options?.cwd,
timeout: options?.timeout || 30000,
reject: false,
});
return {
success: result.exitCode === 0,
stdout: result.stdout || '',
stderr: result.stderr || '',
exitCode: result.exitCode || 0,
};
} catch (error) {
const execaError = error as ExecaError;
return {
success: false,
stdout: execaError.stdout || '',
stderr: execaError.stderr || '',
exitCode: execaError.exitCode || 1,
};
}
}
async execWithOutput(command: string, options?: { cwd?: string; timeout?: number }): Promise<string> {
const result = await this.exec(command, options);
if (!result.success) {
throw new Error(`Command failed: ${command}\n${result.stderr}`);
}
return result.stdout;
}
async execSilent(command: string, options?: { cwd?: string; timeout?: number }): Promise<boolean> {
const result = await this.exec(command, options);
return result.success;
}
async getExitCode(command: string, options?: { cwd?: string }): Promise<number> {
const result = await this.exec(command, options);
return result.exitCode;
}
isCommandAvailable(command: string): Promise<boolean> {
return this.execSilent(`which ${command}`).catch(() => false);
}
async getTmuxVersion(): Promise<string | null> {
const result = await this.exec('tmux -V');
if (result.success) {
return result.stdout;
}
return null;
}
async getScreenVersion(): Promise<string | null> {
const result = await this.exec('screen -v');
if (result.success) {
return result.stdout;
}
return null;
}
}
export const shellUtils = new ShellUtils();