Skip to content

Unified Types

Imported from the package root or /types:

ts
import type {
  THostId,
  TUnifiedEvent,
  TUnifiedEventName,
  TUnifiedTool,
  IHookResponse,
  THandlerMap,
} from "@pivanov/agent-hooks-bridge";

THostId

ts
type THostId = "claude" | "cursor" | "codex";

TUnifiedEventName

ts
type TUnifiedEventName =
  | "SessionStart"
  | "PreToolUse"
  | "PostToolUse"
  | "UserPromptSubmit"
  | "Stop";

TUnifiedEvent

Discriminated union over event. Common fields on every variant:

ts
interface IUnifiedEventBase {
  host: THostId;
  session_id?: string;
  cwd?: string;
  transcript_path?: string | null;
  model?: string;
  _native?: unknown;
}

model is lifted from the host payload when present (Codex and Cursor both ship it; Claude does not).

Variants

ts
interface ISessionStartEvent extends IUnifiedEventBase {
  event: "SessionStart";
  source?: "startup" | "resume" | "clear" | "compact" | (string & {});
}

interface IPreToolUseEvent extends IUnifiedEventBase {
  event: "PreToolUse";
  tool: TUnifiedTool;
  tool_input: Record<string, unknown>;
  native_tool?: string;
}

interface IPostToolUseEvent extends IUnifiedEventBase {
  event: "PostToolUse";
  tool: TUnifiedTool;
  tool_input: Record<string, unknown>;
  tool_response?: Record<string, unknown> | string;
  native_tool?: string;
  duration_ms?: number;
  sandbox?: boolean;
}

interface IUserPromptSubmitEvent extends IUnifiedEventBase {
  event: "UserPromptSubmit";
  prompt: string;
  attachments?: IUserPromptSubmitAttachment[];
}

interface IUserPromptSubmitAttachment {
  type: string;
  file_path: string;
}

interface IStopEvent extends IUnifiedEventBase {
  event: "Stop";
  stop_hook_active?: boolean;
  last_assistant_message?: string | null;
}

Lifted native fields

The fields below come from the host's native payload but are surfaced as typed properties so handlers don't need to reach into _native:

FieldWhereSource hosts
modelIUnifiedEventBaseCodex, Cursor
native_toolIPreToolUseEvent, IPostToolUseEventAll; equals the host's original tool_name (e.g. "apply_patch" on Codex)
duration_msIPostToolUseEventCursor afterShellExecution, afterMCPExecution
sandboxIPostToolUseEventCursor afterShellExecution
attachmentsIUserPromptSubmitEventCursor beforeSubmitPrompt
last_assistant_messageIStopEventCodex Stop

The native payload is still preserved on event._native for fields the bridge does not surface.

TUnifiedTool

ts
type TUnifiedTool = "Bash" | "Edit" | "Write" | "Read" | "MCP" | (string & {});

The (string & {}) suffix preserves autocomplete on the named values while accepting any string for tools the unified set doesn't enumerate (e.g. Claude's Glob, Grep, Task, MCP-named tools, etc.).

IHookResponse

ts
interface IHookResponse {
  decision?: "allow" | "deny" | "ask";
  reason?: string;
  user_message?: string;
  modified_input?: Record<string, unknown>;
  additional_context?: string;
}

What every field maps to per host: see Capability Matrix.

THandlerMap

ts
type THandlerMap = {
  [E in TUnifiedEventName]?: (
    event: TEventOf<E>,
  ) => IHookResponse | void | Promise<IHookResponse | void>;
};

type TEventOf<E extends TUnifiedEventName> = Extract<TUnifiedEvent, { event: E }>;

defineHook accepts this map. TEventOf<E> narrows each handler's parameter to the variant matching its key: the PreToolUse handler sees IPreToolUseEvent, not the full union.

Not affiliated with Anthropic, Anysphere, or OpenAI. Supported by LogicStar AI.