import type { HookName, OhMyOpenCodeConfig } from "../../config" import type { BackgroundManager } from "../../features/background-agent" import type { PluginContext } from "../types" import { createTodoContinuationEnforcer, createBackgroundNotificationHook, createStopContinuationGuardHook, createCompactionContextInjector, createCompactionTodoPreserverHook, createAtlasHook, createAgentSwitchHook, } from "../../hooks" import { safeCreateHook } from "../../shared/safe-create-hook" import { createUnstableAgentBabysitter } from "../unstable-agent-babysitter" export type ContinuationHooks = { stopContinuationGuard: ReturnType | null compactionContextInjector: ReturnType | null compactionTodoPreserver: ReturnType | null todoContinuationEnforcer: ReturnType | null unstableAgentBabysitter: ReturnType | null backgroundNotificationHook: ReturnType | null atlasHook: ReturnType | null agentSwitchHook: ReturnType | null } type SessionRecovery = { setOnAbortCallback: (callback: (sessionID: string) => void) => void setOnRecoveryCompleteCallback: (callback: (sessionID: string) => void) => void } | null export function createContinuationHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean backgroundManager: BackgroundManager sessionRecovery: SessionRecovery }): ContinuationHooks { const { ctx, pluginConfig, isHookEnabled, safeHookEnabled, backgroundManager, sessionRecovery, } = args const safeHook = (hookName: HookName, factory: () => T): T | null => safeCreateHook(hookName, factory, { enabled: safeHookEnabled }) const stopContinuationGuard = isHookEnabled("stop-continuation-guard") ? safeHook("stop-continuation-guard", () => createStopContinuationGuardHook(ctx)) : null const compactionContextInjector = isHookEnabled("compaction-context-injector") ? safeHook("compaction-context-injector", () => createCompactionContextInjector(backgroundManager)) : null const compactionTodoPreserver = isHookEnabled("compaction-todo-preserver") ? safeHook("compaction-todo-preserver", () => createCompactionTodoPreserverHook(ctx)) : null const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer") ? safeHook("todo-continuation-enforcer", () => createTodoContinuationEnforcer(ctx, { backgroundManager, isContinuationStopped: stopContinuationGuard?.isStopped, })) : null const unstableAgentBabysitter = isHookEnabled("unstable-agent-babysitter") ? safeHook("unstable-agent-babysitter", () => createUnstableAgentBabysitter({ ctx, backgroundManager, pluginConfig })) : null if (sessionRecovery) { const onAbortCallbacks: Array<(sessionID: string) => void> = [] const onRecoveryCompleteCallbacks: Array<(sessionID: string) => void> = [] if (todoContinuationEnforcer) { onAbortCallbacks.push(todoContinuationEnforcer.markRecovering) onRecoveryCompleteCallbacks.push(todoContinuationEnforcer.markRecoveryComplete) } if (onAbortCallbacks.length > 0) { sessionRecovery.setOnAbortCallback((sessionID: string) => { for (const callback of onAbortCallbacks) callback(sessionID) }) } if (onRecoveryCompleteCallbacks.length > 0) { sessionRecovery.setOnRecoveryCompleteCallback((sessionID: string) => { for (const callback of onRecoveryCompleteCallbacks) callback(sessionID) }) } } const backgroundNotificationHook = isHookEnabled("background-notification") ? safeHook("background-notification", () => createBackgroundNotificationHook(backgroundManager)) : null const atlasHook = isHookEnabled("atlas") ? safeHook("atlas", () => createAtlasHook(ctx, { directory: ctx.directory, backgroundManager, isContinuationStopped: (sessionID: string) => stopContinuationGuard?.isStopped(sessionID) ?? false, agentOverrides: pluginConfig.agents, })) : null const agentSwitchHook = isHookEnabled("agent-switch") ? safeHook("agent-switch", () => createAgentSwitchHook(ctx)) : null return { stopContinuationGuard, compactionContextInjector, compactionTodoPreserver, todoContinuationEnforcer, unstableAgentBabysitter, backgroundNotificationHook, atlasHook, agentSwitchHook, } }