Files
ci/src/cli/index.ts
T
Jon Chery d6ba76e660 fix(P01): add SIGTERM/SIGINT signal handlers for graceful shutdown
---ci---
project: ci
phase: 1
milestone: v0.8
status: in_progress
decisions:
  - id: D-026
    decision: Graceful drain on SIGTERM/SIGINT: dispose timers then exit
    rationale: Prevents orphaned setTimeout timers from leaking when process is killed
    confidence: 0.88
requirements:
  covered: [FIX-07]
---/ci---

FIX-07: cli/index.ts registers SIGTERM/SIGINT handlers that call
escalationProtocol.dispose() before process.exit. OrchestratorAgent
registers its EscalationProtocol instance via registerEscalationProtocol().
SIGINT exits with code 130, SIGTERM with 143 (standard signal+128 convention).
2026-05-29 20:05:48 +00:00

68 lines
2.0 KiB
JavaScript

#!/usr/bin/env node
import { Command } from "commander";
import { VERSION } from "../version.js";
import { CIAgentFiles } from "../core/ciagent-files.js";
import { isCIAgentInitialized } from "../core/config.js";
import {
createInitCommand,
createRunCommand,
createQuickCommand,
createDebugCommand,
createVerifyCommand,
createReviewCommand,
createStatusCommand,
createAuditCommand,
createClarifyCommand,
createRollbackCommand,
createShipCommand,
createProjectsCommand,
} from "./commands.js";
let activeEscalationProtocol: { dispose(): void } | null = null;
export function registerEscalationProtocol(protocol: { dispose(): void }): void {
activeEscalationProtocol = protocol;
}
function gracefulShutdown(signal: string): void {
if (activeEscalationProtocol) {
try {
activeEscalationProtocol.dispose();
} catch {}
activeEscalationProtocol = null;
}
process.exit(signal === "SIGINT" ? 130 : 143);
}
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
const program = new Command();
program
.name("ciagent")
.description("CIAgent — Continuous Intelligence: autonomous AI-driven software engineering harness")
.version(VERSION)
.option("--project <slug>", "Specify which project to operate on")
.hook("preAction", () => {
const opts = program.opts();
if (opts.project && isCIAgentInitialized(process.cwd())) {
const ciFiles = new CIAgentFiles(process.cwd());
ciFiles.setProjectSlug(opts.project);
}
})
.addCommand(createInitCommand())
.addCommand(createRunCommand())
.addCommand(createQuickCommand())
.addCommand(createDebugCommand())
.addCommand(createVerifyCommand())
.addCommand(createReviewCommand())
.addCommand(createStatusCommand())
.addCommand(createAuditCommand())
.addCommand(createClarifyCommand())
.addCommand(createRollbackCommand())
.addCommand(createShipCommand())
.addCommand(createProjectsCommand());
program.parse();