/** * Adapter Hook Middleware — Lifecycle hooks for agent execution * * Provides beforeExecute / afterExecute / onError hooks that wrap any adapter's * executeAgent call. Hooks run in priority order and can modify the context, * short-circuit execution, or transform results. * * Inspired by Claw-Code's middleware pipeline pattern. * * @module AdapterHooks * @version 1.0.0 */ import type { AgentPayload, AgentContext, AgentResult } from '../types/agent-adapter'; /** Lifecycle phase a hook runs in */ export type HookPhase = 'beforeExecute' | 'afterExecute' | 'onError'; /** * Mutable context threaded through the hook pipeline. * beforeExecute hooks can modify payload/context; afterExecute hooks can modify result. */ export interface HookContext { /** The agent being executed */ agentId: string; /** Mutable payload — beforeExecute hooks may rewrite */ payload: AgentPayload; /** Mutable execution context */ context: AgentContext; /** Result from agent execution (set in afterExecute phase) */ result?: AgentResult; /** Error caught during execution (set in onError phase) */ error?: Error; /** Arbitrary hook-local metadata */ metadata: Record; /** If set to true by a beforeExecute hook, execution is skipped and result is returned as-is */ aborted: boolean; /** * Recursion depth of the current agent call (0 = root, 1 = first sub-agent, etc.). * Hooks can use this to distinguish top-level calls from recursive sub-calls * and apply different policies (e.g. stricter budgets or logging at depth 0 only). */ depth: number; } /** * A single lifecycle hook. */ export interface ExecutionHook { /** Unique hook name */ name: string; /** Which phase this hook fires in */ phase: HookPhase; /** Higher priority hooks run first (default 0) */ priority?: number; /** The hook handler — may mutate ctx and return it */ handler: (ctx: HookContext) => Promise | HookContext; /** Optional matcher — if provided, hook only fires when matcher passes */ matcher?: HookMatcher; } /** * Matcher for filtering when a hook should fire. * All specified conditions must match (AND logic). */ export interface HookMatcher { /** Glob-style pattern matched against agentId. Supports '*' and '?' wildcards. */ agentPattern?: string; /** Glob-style pattern matched against payload.action. Supports '*' and '?' wildcards. */ actionPattern?: string; /** Tool pattern in format 'ToolName(argGlob)' — e.g. 'Bash(git *)' or 'Edit(*.env)' */ toolPattern?: string; /** Custom condition function — return true for the hook to fire */ condition?: (ctx: HookContext) => boolean; } /** * Manages lifecycle hooks for adapter execution. * * Usage: * ```typescript * const hooks = new AdapterHookManager(); * * hooks.register({ * name: 'log-timing', * phase: 'beforeExecute', * handler(ctx) { * ctx.metadata.startTime = Date.now(); * return ctx; * }, * }); * * hooks.register({ * name: 'log-timing-after', * phase: 'afterExecute', * handler(ctx) { * const elapsed = Date.now() - (ctx.metadata.startTime as number); * console.log(`Agent ${ctx.agentId} took ${elapsed}ms`); * return ctx; * }, * }); * ``` */ export declare class AdapterHookManager { private hooks; /** * Register a lifecycle hook. * Throws if a hook with the same name already exists. */ register(hook: ExecutionHook): void; /** * Remove a hook by name. * @returns true if a hook was removed */ unregister(name: string): boolean; /** * List all registered hooks. */ list(): ExecutionHook[]; /** * Create a fresh HookContext for a new execution. * * @param agentId The agent being executed. * @param payload Execution payload (shallow-copied so hooks don't mutate the caller's object). * @param context Execution context (shallow-copied). * @param depth Recursion depth — 0 for root calls, incremented by sub-agent spawners (default: 0). */ createContext(agentId: string, payload: AgentPayload, context: AgentContext, depth?: number): HookContext; /** * Run all beforeExecute hooks in priority order. * If any hook sets ctx.aborted = true, remaining hooks still run but * the caller should skip actual execution. */ runBefore(ctx: HookContext): Promise; /** * Run all afterExecute hooks in priority order. * ctx.result must be set before calling. */ runAfter(ctx: HookContext): Promise; /** * Run all onError hooks in priority order. * ctx.error must be set before calling. */ runOnError(ctx: HookContext): Promise; /** * Total number of registered hooks. */ size(): number; /** * Remove all hooks. */ clear(): void; private runPhase; /** * Check whether a HookMatcher passes for the given context. */ private matchesHook; } /** * Simple glob matcher supporting `*` (any chars) and `?` (single char). * Case-insensitive. */ export declare function matchGlob(pattern: string, value: string): boolean; /** * Match a tool pattern like "Bash(git *)" against a tool string like "Bash(git push)". */ export declare function matchToolPattern(pattern: string, toolStr: string): boolean; //# sourceMappingURL=adapter-hooks.d.ts.map