2026-01-18 04:50:46 +01:00
|
|
|
#!/usr/bin/env node
|
2026-01-21 08:37:35 +01:00
|
|
|
/**
|
2026-02-26 16:44:34 +01:00
|
|
|
* @fileoverview Codeman CLI entry point
|
2026-01-21 08:37:35 +01:00
|
|
|
*
|
2026-02-26 16:44:34 +01:00
|
|
|
* This is the main executable entry point for the Codeman CLI.
|
2026-01-21 08:37:35 +01:00
|
|
|
* It sets up global error handlers and invokes the CLI parser.
|
|
|
|
|
*
|
|
|
|
|
* @module index
|
|
|
|
|
*/
|
2026-01-18 04:50:46 +01:00
|
|
|
|
|
|
|
|
import { program } from './cli.js';
|
|
|
|
|
|
2026-02-12 14:41:27 +01:00
|
|
|
// Detect if we're running the web server (long-lived process)
|
|
|
|
|
// In web mode, we should NOT exit on transient errors — log and continue
|
|
|
|
|
const isWebMode = process.argv.includes('web');
|
|
|
|
|
|
2026-03-01 13:19:16 +01:00
|
|
|
import { MAX_CONSECUTIVE_ERRORS, ERROR_RESET_MS } from './config/server-timing.js';
|
|
|
|
|
|
2026-02-15 05:26:29 +01:00
|
|
|
// Track consecutive unhandled errors in web mode — restart after too many
|
|
|
|
|
let consecutiveErrors = 0;
|
|
|
|
|
let errorResetTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
|
|
|
|
|
function trackError(): void {
|
|
|
|
|
consecutiveErrors++;
|
|
|
|
|
if (errorResetTimer) clearTimeout(errorResetTimer);
|
2026-02-27 13:16:23 +01:00
|
|
|
errorResetTimer = setTimeout(() => {
|
|
|
|
|
consecutiveErrors = 0;
|
|
|
|
|
}, ERROR_RESET_MS);
|
2026-02-15 05:26:29 +01:00
|
|
|
|
|
|
|
|
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
|
|
|
|
|
console.error(`[FATAL] ${MAX_CONSECUTIVE_ERRORS} consecutive unhandled errors — exiting for systemd restart`);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 04:50:46 +01:00
|
|
|
// Handle uncaught errors
|
|
|
|
|
process.on('uncaughtException', (err) => {
|
|
|
|
|
console.error('Uncaught exception:', err.message);
|
2026-02-12 14:41:27 +01:00
|
|
|
if (isWebMode) {
|
|
|
|
|
console.error('[RECOVERED] Server continuing after uncaught exception:', err.stack);
|
2026-02-15 05:26:29 +01:00
|
|
|
trackError();
|
2026-02-12 14:41:27 +01:00
|
|
|
} else {
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
2026-01-18 04:50:46 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
process.on('unhandledRejection', (reason) => {
|
|
|
|
|
console.error('Unhandled rejection:', reason);
|
2026-02-12 14:41:27 +01:00
|
|
|
if (isWebMode) {
|
|
|
|
|
console.error('[RECOVERED] Server continuing after unhandled rejection');
|
2026-02-15 05:26:29 +01:00
|
|
|
trackError();
|
2026-02-12 14:41:27 +01:00
|
|
|
} else {
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
2026-01-18 04:50:46 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Run CLI
|
|
|
|
|
program.parse();
|