- GracefulShutdown class handles SIGTERM, SIGINT, SIGHUP - 10-second timeout before force exit - Double SIGINT forces immediate exit - Shutdown sequence: stop HTTP server, stop processes, cleanup - Integrates with CoordinationServer and ProcessManager
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
/**
|
|
* Codewalk District CLI
|
|
*
|
|
* Commander-based CLI with help system and version display.
|
|
* Supports server mode via --server flag.
|
|
*/
|
|
|
|
import { Command } from 'commander';
|
|
import { VERSION } from '../index.js';
|
|
import { CoordinationServer } from '../server/index.js';
|
|
import { GracefulShutdown } from '../server/shutdown.js';
|
|
import { ProcessManager, ProcessRegistry } from '../process/index.js';
|
|
import { LogManager } from '../logging/index.js';
|
|
|
|
/** Environment variable for custom port */
|
|
const CW_PORT_ENV = 'CW_PORT';
|
|
|
|
/**
|
|
* Starts the coordination server in foreground mode.
|
|
* Server runs until terminated via SIGTERM/SIGINT.
|
|
*/
|
|
async function startServer(port?: number): Promise<void> {
|
|
// Get port from option, env var, or default
|
|
const serverPort = port ??
|
|
(process.env[CW_PORT_ENV] ? parseInt(process.env[CW_PORT_ENV], 10) : undefined);
|
|
|
|
// Create dependencies
|
|
const registry = new ProcessRegistry();
|
|
const processManager = new ProcessManager(registry);
|
|
const logManager = new LogManager();
|
|
|
|
// Create and start server
|
|
const server = new CoordinationServer(
|
|
{ port: serverPort },
|
|
processManager,
|
|
logManager
|
|
);
|
|
|
|
try {
|
|
await server.start();
|
|
} catch (error) {
|
|
console.error('Failed to start server:', (error as Error).message);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Install graceful shutdown handlers
|
|
const shutdown = new GracefulShutdown(server, processManager, logManager);
|
|
shutdown.install();
|
|
}
|
|
|
|
/**
|
|
* Creates and configures the CLI program.
|
|
*
|
|
* @param serverHandler - Optional handler to be called for server mode
|
|
* @returns Configured Commander program ready for parsing
|
|
*/
|
|
export function createCli(serverHandler?: (port?: number) => Promise<void>): Command {
|
|
const program = new Command();
|
|
|
|
program
|
|
.name('cw')
|
|
.description('Multi-agent workspace for orchestrating multiple Claude Code agents')
|
|
.version(VERSION, '-v, --version', 'Display version number');
|
|
|
|
// Server mode option (global flag)
|
|
program
|
|
.option('-s, --server', 'Start the coordination server')
|
|
.option('-p, --port <number>', 'Port for the server (default: 3847, env: CW_PORT)', parseInt);
|
|
|
|
// Handle the case where --server is provided without a command
|
|
// This makes --server work as a standalone action
|
|
program.hook('preAction', async (_thisCommand, _actionCommand) => {
|
|
const opts = program.opts();
|
|
if (opts.server && serverHandler) {
|
|
await serverHandler(opts.port);
|
|
process.exit(0);
|
|
}
|
|
});
|
|
|
|
// Placeholder commands - will be implemented in later phases
|
|
program
|
|
.command('status')
|
|
.description('Show workspace status')
|
|
.action(() => {
|
|
console.log('cw status: not implemented');
|
|
});
|
|
|
|
program
|
|
.command('agent')
|
|
.description('Manage agents')
|
|
.action(() => {
|
|
console.log('cw agent: not implemented');
|
|
});
|
|
|
|
program
|
|
.command('task')
|
|
.description('Manage tasks')
|
|
.action(() => {
|
|
console.log('cw task: not implemented');
|
|
});
|
|
|
|
return program;
|
|
}
|
|
|
|
/**
|
|
* Runs the CLI, handling server mode and commands.
|
|
*/
|
|
export async function runCli(): Promise<void> {
|
|
// Check for server flag early, before Commander processes
|
|
const hasServerFlag = process.argv.includes('--server') || process.argv.includes('-s');
|
|
|
|
if (hasServerFlag) {
|
|
// Get port from args if present
|
|
const portIndex = process.argv.findIndex(arg => arg === '-p' || arg === '--port');
|
|
const port = portIndex !== -1 && process.argv[portIndex + 1]
|
|
? parseInt(process.argv[portIndex + 1], 10)
|
|
: undefined;
|
|
|
|
await startServer(port);
|
|
// Server runs indefinitely until signal
|
|
return;
|
|
}
|
|
|
|
// Normal CLI processing
|
|
const program = createCli();
|
|
program.parse(process.argv);
|
|
}
|