/**
 * AbortHandler — abortSignal 監視と割り込み処理専用モジュール
 *
 * 外部 abortSignal（並列実行モード）または ShutdownManager（シングル実行モード）の
 * どちらかを使い、エンジンの中断処理を担う。
 * EPIPE エラーの抑制も担当する。
 */
import { interruptAllQueries } from '../../../infra/claude/query-manager.js';
import { ShutdownManager } from './shutdownManager.js';
import { EXIT_SIGINT } from '../../../shared/exitCodes.js';
export class AbortHandler {
    options;
    shutdownManager;
    onAbortSignal;
    onEpipe;
    constructor(options) {
        this.options = options;
    }
    /**
     * 中断ハンドラをインストールする。
     * エンジン生成後に呼ぶこと。
     */
    install() {
        const { externalSignal, internalController, getEngine } = this.options;
        this.onEpipe = (err) => {
            if (err.code === 'EPIPE')
                return;
            throw err;
        };
        const abortEngine = () => {
            const engine = getEngine();
            if (!engine || !this.onEpipe) {
                throw new Error('Abort handler invoked before WorkflowEngine initialization');
            }
            if (!internalController.signal.aborted) {
                internalController.abort();
            }
            process.on('uncaughtException', this.onEpipe);
            interruptAllQueries();
            engine.abort();
        };
        if (externalSignal) {
            // 並列実行モード: 外部シグナルへ委譲
            this.onAbortSignal = abortEngine;
            if (externalSignal.aborted) {
                abortEngine();
            }
            else {
                externalSignal.addEventListener('abort', this.onAbortSignal, { once: true });
            }
        }
        else {
            // シングル実行モード: SIGINT を自前でハンドリング
            this.shutdownManager = new ShutdownManager({
                callbacks: {
                    onGraceful: abortEngine,
                    onForceKill: () => process.exit(EXIT_SIGINT),
                },
            });
            this.shutdownManager.install();
        }
    }
    /**
     * ハンドラをクリーンアップする。
     * finally ブロックで必ず呼ぶこと。
     */
    cleanup() {
        this.shutdownManager?.cleanup();
        if (this.onAbortSignal && this.options.externalSignal) {
            this.options.externalSignal.removeEventListener('abort', this.onAbortSignal);
        }
        if (this.onEpipe) {
            process.removeListener('uncaughtException', this.onEpipe);
        }
    }
}
//# sourceMappingURL=abortHandler.js.map