Initial upload with CI/CD workflow
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-02-05 19:31:49 +00:00
parent 3cae1ec3ac
commit 2aec2b93d9

70
src/utils/shellUtils.ts Normal file
View File

@@ -0,0 +1,70 @@
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();