Skip to main content

executeCommandRunUntilError

codebolt.terminal.executeCommandRunUntilError(command: string, executeInMain: boolean): Promise<CommandError>

Executes a given command and keeps running until an error occurs. This method is designed for long-running processes that should continue executing until they encounter an error condition. It listens for WebSocket messages and resolves the promise when an error is encountered.

Parametersโ€‹

  • command (string): The command to be executed and monitored for errors (e.g., "npm run dev", "npm start", "python server.py").
  • executeInMain (boolean): Optional parameter to execute the command in the main terminal instead of a separate terminal instance. Defaults to false.

Returnsโ€‹

  • Promise<CommandError>: A promise that resolves with a CommandError object when an error occurs during command execution, indicating the command has stopped due to an error condition.

Response Structureโ€‹

The method returns a Promise that resolves to a CommandError object when an error occurs:

CommandError (Error Response)โ€‹

  • type (string): Always "commandError".
  • error (string): Error message describing what went wrong or why the command stopped.
  • exitCode (number, optional): The exit code of the failed command.
  • stderr (string, optional): Standard error output from the command.
  • success (boolean, optional): Indicates if the operation was successful (typically false for this method).
  • message (string, optional): Additional information about the response.
  • data (any, optional): Additional data from the response.
  • messageId (string, optional): Unique identifier for the message.
  • threadId (string, optional): Thread identifier for the request.

Examplesโ€‹

// Example 1: Run development server until error
const runDevServer = async () => {
try {
console.log('๐Ÿ”„ Starting development server...');
const errorResult = await codebolt.terminal.executeCommandRunUntilError('npm run dev');

console.log('โŒ Development server stopped due to error:');
console.log('Error:', errorResult.error);
console.log('Exit code:', errorResult.exitCode);
console.log('Stderr:', errorResult.stderr);

return errorResult;
} catch (error) {
console.error('โŒ Exception during server execution:', error.message);
throw error;
}
};

// Usage
await runDevServer();

// Example 2: Run in main terminal
const runInMainTerminal = async () => {
try {
console.log('๐Ÿ”„ Starting application in main terminal...');
const result = await codebolt.terminal.executeCommandRunUntilError('npm start', true);

console.log('โŒ Application stopped in main terminal:');
console.log('Error details:', result.error);

return result;
} catch (error) {
console.error('โŒ Main terminal execution failed:', error.message);
throw error;
}
};

// Example 3: Monitor long-running process with error handling
const monitorProcess = async (command, description) => {
console.log(`๐Ÿ”„ Starting ${description}...`);
console.log(`Command: ${command}`);

const startTime = Date.now();

try {
const errorResult = await codebolt.terminal.executeCommandRunUntilError(command);

const duration = Date.now() - startTime;
const durationSeconds = Math.round(duration / 1000);

console.log(`โŒ ${description} stopped after ${durationSeconds} seconds`);
console.log('Error details:');
console.log(' Type:', errorResult.type);
console.log(' Error:', errorResult.error);
console.log(' Exit Code:', errorResult.exitCode);

if (errorResult.stderr) {
console.log(' Stderr:', errorResult.stderr);
}

return {
command,
description,
duration: durationSeconds,
error: errorResult
};
} catch (error) {
console.error(`โŒ Exception while monitoring ${description}:`, error.message);
throw error;
}
};

// Usage
await monitorProcess('python -m http.server 8000', 'Python HTTP Server');
await monitorProcess('node server.js', 'Node.js Server');

// Example 4: Development workflow with automatic restart
const developmentWorkflow = async () => {
const maxRetries = 3;
let retryCount = 0;

while (retryCount < maxRetries) {
try {
console.log(`๐Ÿ”„ Starting development server (attempt ${retryCount + 1}/${maxRetries})...`);

const errorResult = await codebolt.terminal.executeCommandRunUntilError('npm run dev');

console.log(`โŒ Development server crashed:`);
console.log('Error:', errorResult.error);

// Check if error is recoverable
const isRecoverable = !errorResult.error.includes('EADDRINUSE') &&
!errorResult.error.includes('permission denied') &&
errorResult.exitCode !== 1;

if (isRecoverable && retryCount < maxRetries - 1) {
retryCount++;
console.log('๐Ÿ”„ Error appears recoverable, retrying in 5 seconds...');
await new Promise(resolve => setTimeout(resolve, 5000));
} else {
console.log('โŒ Error is not recoverable or max retries reached');
return errorResult;
}
} catch (error) {
console.error('โŒ Exception in development workflow:', error.message);
retryCount++;

if (retryCount >= maxRetries) {
throw error;
}
}
}
};

// Example 5: Process monitoring with health checks
const monitorWithHealthCheck = async (command, healthCheckInterval = 30000) => {
console.log(`๐Ÿ”„ Starting monitored process: ${command}`);
console.log(`Health check interval: ${healthCheckInterval}ms`);

// Set up health check interval
const healthCheckTimer = setInterval(() => {
console.log('๐Ÿ’“ Process is still running...');
}, healthCheckInterval);

try {
const errorResult = await codebolt.terminal.executeCommandRunUntilError(command);

clearInterval(healthCheckTimer);

console.log('โŒ Process stopped with error:');
console.log('Error:', errorResult.error);
console.log('Exit code:', errorResult.exitCode);

// Analyze error type
if (errorResult.error.includes('SIGTERM')) {
console.log('๐Ÿ”„ Process was terminated externally');
} else if (errorResult.error.includes('SIGKILL')) {
console.log('๐Ÿ’€ Process was forcefully killed');
} else if (errorResult.exitCode && errorResult.exitCode > 0) {
console.log('โš ๏ธ Process exited with error code');
}

return errorResult;
} catch (error) {
clearInterval(healthCheckTimer);
console.error('โŒ Exception during monitoring:', error.message);
throw error;
}
};

// Example 6: Server monitoring with log analysis
const monitorServerWithLogs = async (serverCommand) => {
console.log(`๐Ÿ”„ Starting server with log monitoring: ${serverCommand}`);

const logPatterns = {
critical: /CRITICAL|FATAL|EMERGENCY/i,
error: /ERROR|EXCEPTION|FAIL/i,
warning: /WARN|WARNING/i,
info: /INFO|STARTED|LISTENING/i
};

try {
const errorResult = await codebolt.terminal.executeCommandRunUntilError(serverCommand);

console.log('โŒ Server stopped with error:');
console.log('Error message:', errorResult.error);

// Analyze error message for patterns
const errorMessage = errorResult.error.toLowerCase();

if (logPatterns.critical.test(errorMessage)) {
console.log('๐Ÿšจ CRITICAL ERROR detected');
} else if (logPatterns.error.test(errorMessage)) {
console.log('โŒ ERROR level issue detected');
} else if (logPatterns.warning.test(errorMessage)) {
console.log('โš ๏ธ WARNING level issue detected');
}

// Check for common server issues
if (errorMessage.includes('port') && errorMessage.includes('use')) {
console.log('๐Ÿ”Œ Port conflict detected - another service may be using the port');
} else if (errorMessage.includes('permission')) {
console.log('๐Ÿ”’ Permission issue detected - check file/port permissions');
} else if (errorMessage.includes('memory') || errorMessage.includes('heap')) {
console.log('๐Ÿง  Memory issue detected - consider increasing memory allocation');
}

return errorResult;
} catch (error) {
console.error('โŒ Exception during server monitoring:', error.message);
throw error;
}
};

// Example 7: Batch process monitoring
const monitorMultipleProcesses = async (commands) => {
const results = [];

console.log(`๐Ÿ”„ Starting monitoring for ${commands.length} processes...`);

for (let i = 0; i < commands.length; i++) {
const { name, command, executeInMain = false } = commands[i];

console.log(`[${i + 1}/${commands.length}] Starting ${name}...`);

try {
const startTime = Date.now();
const errorResult = await codebolt.terminal.executeCommandRunUntilError(command, executeInMain);
const duration = Date.now() - startTime;

console.log(`โŒ [${i + 1}] ${name} stopped after ${Math.round(duration / 1000)}s`);
console.log(` Error: ${errorResult.error}`);

results.push({
name,
command,
duration: Math.round(duration / 1000),
error: errorResult,
success: false
});
} catch (error) {
console.log(`โŒ [${i + 1}] ${name} failed with exception: ${error.message}`);

results.push({
name,
command,
error: error.message,
success: false,
exception: true
});
}
}

console.log('๐Ÿ“Š Monitoring summary:');
results.forEach((result, index) => {
console.log(` ${index + 1}. ${result.name}: ${result.exception ? 'Exception' : 'Error'} after ${result.duration || 0}s`);
});

return results;
};

// Usage
const processesToMonitor = [
{ name: 'Web Server', command: 'npm run start' },
{ name: 'API Server', command: 'node api-server.js' },
{ name: 'Background Worker', command: 'python worker.py', executeInMain: true }
];

await monitorMultipleProcesses(processesToMonitor);

// Example 8: Graceful process monitoring with cleanup
const monitorWithCleanup = async (command, cleanupCommands = []) => {
console.log(`๐Ÿ”„ Starting monitored process with cleanup: ${command}`);

let processResult = null;

try {
processResult = await codebolt.terminal.executeCommandRunUntilError(command);

console.log('โŒ Process stopped with error:');
console.log('Error:', processResult.error);

} catch (error) {
console.error('โŒ Exception during process execution:', error.message);
processResult = { error: error.message, type: 'exception' };
} finally {
// Run cleanup commands
if (cleanupCommands.length > 0) {
console.log('๐Ÿงน Running cleanup commands...');

for (const cleanupCmd of cleanupCommands) {
try {
console.log(` Running: ${cleanupCmd}`);
const cleanupResult = await codebolt.terminal.executeCommand(cleanupCmd);

if (cleanupResult.type === 'commandFinish') {
console.log(` โœ… Cleanup successful`);
} else {
console.log(` โš ๏ธ Cleanup warning: ${cleanupResult.error}`);
}
} catch (cleanupError) {
console.log(` โŒ Cleanup failed: ${cleanupError.message}`);
}
}

console.log('๐Ÿงน Cleanup completed');
}
}

return processResult;
};

// Usage
await monitorWithCleanup(
'npm run dev',
[
'pkill -f "node.*dev"', // Kill any remaining dev processes
'rm -rf temp/', // Clean up temporary files
'echo "Cleanup completed"'
]
);

Common Use Casesโ€‹

  1. Development Servers: Monitor development servers that should run continuously until manually stopped
  2. Build Processes: Run build watchers that monitor file changes until an error occurs
  3. Background Services: Monitor long-running background services and daemons
  4. Testing Environments: Run test suites in watch mode until failures occur
  5. Production Monitoring: Monitor production processes and detect when they crash
  6. CI/CD Pipelines: Run deployment processes that should continue until completion or error
  7. File Watchers: Monitor file system changes until an error in processing occurs
  8. Network Services: Monitor network services and detect connection issues

Notesโ€‹

  • This method is specifically designed for long-running processes that should continue until an error
  • The promise only resolves when an error occurs, not on successful completion
  • Use executeInMain: true when you need the command to run in the main terminal context
  • The method is ideal for monitoring development servers, build processes, and background services
  • Consider implementing retry logic for recoverable errors
  • Always handle the resolved CommandError to understand why the process stopped
  • For processes that should run indefinitely, this method helps detect when they unexpectedly terminate
  • Use appropriate cleanup procedures when the monitored process stops