@@ -28,6 +28,13 @@ type AgentCompleted = {
2828 text : string ;
2929} ;
3030
31+ type HookEvent = {
32+ workspaceId : string ;
33+ threadId : string ;
34+ turnId : string | null ;
35+ run : Record < string , unknown > ;
36+ } ;
37+
3138type AppServerEventHandlers = {
3239 onWorkspaceConnected ?: ( workspaceId : string ) => void ;
3340 onThreadStarted ?: ( workspaceId : string , thread : Record < string , unknown > ) => void ;
@@ -67,6 +74,8 @@ type AppServerEventHandlers = {
6774 turnId : string ,
6875 payload : { explanation : unknown ; plan : unknown } ,
6976 ) => void ;
77+ onHookStarted ?: ( event : HookEvent ) => void ;
78+ onHookCompleted ?: ( event : HookEvent ) => void ;
7079 onItemStarted ?: ( workspaceId : string , threadId : string , item : Record < string , unknown > ) => void ;
7180 onItemCompleted ?: ( workspaceId : string , threadId : string , item : Record < string , unknown > ) => void ;
7281 onReasoningSummaryDelta ?: ( workspaceId : string , threadId : string , itemId : string , delta : string ) => void ;
@@ -105,6 +114,8 @@ export const METHODS_ROUTED_IN_USE_APP_SERVER_EVENTS = [
105114 "codex/backgroundThread" ,
106115 "codex/connected" ,
107116 "error" ,
117+ "hook/completed" ,
118+ "hook/started" ,
108119 "item/agentMessage/delta" ,
109120 "item/commandExecution/outputDelta" ,
110121 "item/commandExecution/terminalInteraction" ,
@@ -129,6 +140,31 @@ export const METHODS_ROUTED_IN_USE_APP_SERVER_EVENTS = [
129140 "turn/started" ,
130141] as const satisfies readonly SupportedAppServerMethod [ ] ;
131142
143+ function parseHookEvent (
144+ workspaceId : string ,
145+ params : Record < string , unknown > ,
146+ ) : HookEvent | null {
147+ const threadId = String ( params . threadId ?? params . thread_id ?? "" ) . trim ( ) ;
148+ if ( ! threadId ) {
149+ return null ;
150+ }
151+ const run = params . run ;
152+ if ( ! run || typeof run !== "object" || Array . isArray ( run ) ) {
153+ return null ;
154+ }
155+ const turnIdRaw = params . turnId ?? params . turn_id ?? null ;
156+ const turnId =
157+ typeof turnIdRaw === "string" && turnIdRaw . trim ( ) . length > 0
158+ ? turnIdRaw . trim ( )
159+ : null ;
160+ return {
161+ workspaceId,
162+ threadId,
163+ turnId,
164+ run : run as Record < string , unknown > ,
165+ } ;
166+ }
167+
132168export function useAppServerEvents ( handlers : AppServerEventHandlers ) {
133169 // Use ref to keep handlers current without triggering re-subscription
134170 const handlersRef = useRef ( handlers ) ;
@@ -238,6 +274,22 @@ export function useAppServerEvents(handlers: AppServerEventHandlers) {
238274 return ;
239275 }
240276
277+ if ( method === "hook/started" ) {
278+ const event = parseHookEvent ( workspace_id , params ) ;
279+ if ( event ) {
280+ currentHandlers . onHookStarted ?.( event ) ;
281+ }
282+ return ;
283+ }
284+
285+ if ( method === "hook/completed" ) {
286+ const event = parseHookEvent ( workspace_id , params ) ;
287+ if ( event ) {
288+ currentHandlers . onHookCompleted ?.( event ) ;
289+ }
290+ return ;
291+ }
292+
241293 if ( method === "thread/started" ) {
242294 const thread = ( params . thread as Record < string , unknown > | undefined ) ?? null ;
243295 const threadId = String ( thread ?. id ?? "" ) ;
0 commit comments