import type { HookName, OhMyOpenCodeConfig } from "../../config" import type { ModelCacheState } from "../../plugin-state" import type { PluginContext } from "../types" import { createCommentCheckerHooks, createToolOutputTruncatorHook, createDirectoryAgentsInjectorHook, createDirectoryReadmeInjectorHook, createEmptyTaskResponseDetectorHook, createRulesInjectorHook, createTasksTodowriteDisablerHook, createWriteExistingFileGuardHook, createHashlineReadEnhancerHook, createReadImageResizerHook, createJsonErrorRecoveryHook, createTodoDescriptionOverrideHook, } from "../../hooks" import { getOpenCodeVersion, isOpenCodeVersionAtLeast, log, OPENCODE_NATIVE_AGENTS_INJECTION_VERSION, } from "../../shared" import { safeCreateHook } from "../../shared/safe-create-hook" export type ToolGuardHooks = { commentChecker: ReturnType | null toolOutputTruncator: ReturnType | null directoryAgentsInjector: ReturnType | null directoryReadmeInjector: ReturnType | null emptyTaskResponseDetector: ReturnType | null rulesInjector: ReturnType | null tasksTodowriteDisabler: ReturnType | null writeExistingFileGuard: ReturnType | null hashlineReadEnhancer: ReturnType | null jsonErrorRecovery: ReturnType | null readImageResizer: ReturnType | null todoDescriptionOverride: ReturnType | null } export function createToolGuardHooks(args: { ctx: PluginContext pluginConfig: OhMyOpenCodeConfig modelCacheState: ModelCacheState isHookEnabled: (hookName: HookName) => boolean safeHookEnabled: boolean }): ToolGuardHooks { const { ctx, pluginConfig, modelCacheState, isHookEnabled, safeHookEnabled } = args const safeHook = (hookName: HookName, factory: () => T): T | null => safeCreateHook(hookName, factory, { enabled: safeHookEnabled }) const commentChecker = isHookEnabled("comment-checker") ? safeHook("comment-checker", () => createCommentCheckerHooks(pluginConfig.comment_checker)) : null const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? safeHook("tool-output-truncator", () => createToolOutputTruncatorHook(ctx, { modelCacheState, experimental: pluginConfig.experimental, })) : null let directoryAgentsInjector: ReturnType | null = null if (isHookEnabled("directory-agents-injector")) { const currentVersion = getOpenCodeVersion() const hasNativeSupport = currentVersion !== null && isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION) if (hasNativeSupport) { log("directory-agents-injector auto-disabled due to native OpenCode support", { currentVersion, nativeVersion: OPENCODE_NATIVE_AGENTS_INJECTION_VERSION, }) } else { directoryAgentsInjector = safeHook("directory-agents-injector", () => createDirectoryAgentsInjectorHook(ctx, modelCacheState)) } } const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? safeHook("directory-readme-injector", () => createDirectoryReadmeInjectorHook(ctx, modelCacheState)) : null const emptyTaskResponseDetector = isHookEnabled("empty-task-response-detector") ? safeHook("empty-task-response-detector", () => createEmptyTaskResponseDetectorHook(ctx)) : null const rulesInjector = isHookEnabled("rules-injector") ? safeHook("rules-injector", () => createRulesInjectorHook(ctx, modelCacheState)) : null const tasksTodowriteDisabler = isHookEnabled("tasks-todowrite-disabler") ? safeHook("tasks-todowrite-disabler", () => createTasksTodowriteDisablerHook({ experimental: pluginConfig.experimental })) : null const writeExistingFileGuard = isHookEnabled("write-existing-file-guard") ? safeHook("write-existing-file-guard", () => createWriteExistingFileGuardHook(ctx)) : null const hashlineReadEnhancer = isHookEnabled("hashline-read-enhancer") ? safeHook("hashline-read-enhancer", () => createHashlineReadEnhancerHook(ctx, { hashline_edit: { enabled: pluginConfig.hashline_edit ?? false } })) : null const jsonErrorRecovery = isHookEnabled("json-error-recovery") ? safeHook("json-error-recovery", () => createJsonErrorRecoveryHook(ctx)) : null const readImageResizer = isHookEnabled("read-image-resizer") ? safeHook("read-image-resizer", () => createReadImageResizerHook(ctx)) : null const todoDescriptionOverride = isHookEnabled("todo-description-override") ? safeHook("todo-description-override", () => createTodoDescriptionOverrideHook()) : null return { commentChecker, toolOutputTruncator, directoryAgentsInjector, directoryReadmeInjector, emptyTaskResponseDetector, rulesInjector, tasksTodowriteDisabler, writeExistingFileGuard, hashlineReadEnhancer, jsonErrorRecovery, readImageResizer, todoDescriptionOverride, } }