| 7713 | The hook's output was: ${g6(K,null,2)}`}}function kgK(q){let K=q.trim();if(!K.startsWith("{"))return N("Hook output does not start with {, treating as plain text"),{plainText:q};try{let _=vgK(K);if("json"in _)return _;let z=`${_.validationError} |
| 7714 | |
| 7715 | Expected schema: |
| 7716 | ${g6({continue:"boolean (optional)",suppressOutput:"boolean (optional)",stopReason:"string (optional)",decision:'"approve" | "block" (optional)',reason:"string (optional)",systemMessage:"string (optional)",permissionDecision:'"allow" | "deny" | "ask" (optional)',hookSpecificOutput:{"for PreToolUse":{hookEventName:'"PreToolUse"',permissionDecision:'"allow" | "deny" | "ask" (optional)',permissionDecisionReason:"string (optional)",updatedInput:"object (optional) - Modified tool input to use"},"for UserPromptSubmit":{hookEventName:'"UserPromptSubmit"',additionalContext:"string (required)"},"for PostToolUse":{hookEventName:'"PostToolUse"',additionalContext:"string (optional)"}}},null,2)}`;return N(z),{plainText:q,validationError:z}}catch(_){return N(`Failed to parse hook output as JSON: ${_}`),{plainText:q}}}function VgK(q){let K=q.trim();if(K===""){let _=lS6().safeParse({});if(_.success)return N("HTTP hook returned empty body, treating as empty JSON object"),{json:_.data}}if(!K.startsWith("{")){let _=`HTTP hook must return JSON, but got non-JSON response body: ${K.length>200?K.slice(0,200)+"…":K}`;return N(_),{validationError:_}}try{let _=vgK(K);if("json"in _)return _;return N(_.validationError),_}catch(_){let z=`HTTP hook must return valid JSON, but parsing failed: ${_}`;return N(z),{validationError:z}}}function A_7({json:q,command:K,hookName:_,toolUseID:z,hookEvent:Y,expectedHookEvent:$,stdout:A,stderr:O,exitCode:w,durationMs:j}){let H={},J=q;if(J.continue===!1){if(H.preventContinuation=!0,J.stopReason)H.stopReason=J.stopReason}if(q.decision)switch(q.decision){case"approve":H.permissionBehavior="allow";break;case"block":H.permissionBehavior="deny",H.blockingError={blockingError:q.reason||"Blocked by hook",command:K};break;default:throw Error(`Unknown hook decision type: ${q.decision}. Valid types are: approve, block`)}if(q.systemMessage)H.systemMessage=q.systemMessage;if(q.hookSpecificOutput?.hookEventName==="PreToolUse"&&q.hookSpecificOutput.permissionDecision)switch(q.hookSpecificOutput.permissionDecision){case"allow":H.permissionBehavior="allow";break;case"deny":H.permissionBehavior="deny",H.blockingError={blockingError:q.reason||"Blocked by hook",command:K};break;case"ask":H.permissionBehavior="ask";break;default:throw Error(`Unknown hook permissionDecision type: ${q.hookSpecificOutput.permissionDecision}. Valid types are: allow, deny, ask`)}if(H.permissionBehavior!==void 0&&q.reason!==void 0)H.hookPermissionDecisionReason=q.reason;if(q.hookSpecificOutput){if($&&q.hookSpecificOutput.hookEventName!==$)throw Error(`Hook returned incorrect event name: expected '${$}' but got '${q.hookSpecificOutput.hookEventName}'. Full stdout: ${g6(q,null,2)}`);switch(q.hookSpecificOutput.hookEventName){case"PreToolUse":if(q.hookSpecificOutput.permissionDecision)switch(q.hookSpecificOutput.permissionDecision){case"allow":H.permissionBehavior="allow";break;case"deny":H.permissionBehavior="deny",H.blockingError={blockingError:q.hookSpecificOutput.permissionDecisionReason||q.reason||"Blocked by hook",command:K};break;case"ask":H.permissionBehavior="ask";break}if(H.hookPermissionDecisionReason=q.hookSpecificOutput.permissionDecisionReason,q.hookSpecificOutput.updatedInput)H.updatedInput=q.hookSpecificOutput.updatedInput;H.additionalContext=q.hookSpecificOutput.additionalContext;break;case"UserPromptSubmit":H.additionalContext=q.hookSpecificOutput.additionalContext;break;case"SessionStart":if(H.additionalContext=q.hookSpecificOutput.additionalContext,H.initialUserMessage=q.hookSpecificOutput.initialUserMessage,"watchPaths"in q.hookSpecificOutput&&q.hookSpecificOutput.watchPaths)H.watchPaths=q.hookSpecificOutput.watchPaths;break;case"Setup":H.additionalContext=q.hookSpecificOutput.additionalContext;break;case"SubagentStart":H.additionalContext=q.hookSpecificOutput.additionalContext;break;case"PostToolUse":if(H.additionalContext=q.hookSpecificOutput.additionalContext,q.hookSpecificOutput.updatedMCPToolOutput)H.updatedMCPToolOutput=q.hookSpecificOutput.updatedMCPToolOutput;break;case"PostToolUseFailure":H.additionalContext=q.hookSpecificOutput.additionalContext;break;case"PermissionDenied":H.retry=q.hookSpecificOutput.retry;break;case"PermissionRequest":if(q.hookSpecificOutput.decision){if(H.permissionRequestResult=q.hookSpecificOutput.decision,H.permissionBehavior=q.hookSpecificOutput.decision.behavior==="allow"?"allow":"deny",q.hookSpecificOutput.decision.behavior==="allow"&&q.hookSpecificOutput.decision.updatedInput)H.updatedInput=q.hookSpecificOutput.decision.updatedInput}break;case"Elicitation":if(q.hookSpecificOutput.action){if(H.elicitationResponse={action:q.hookSpecificOutput.action,content:q.hookSpecificOutput.content},q.hookSpecificOutput.action==="decline")H.blockingError={blockingError:q.reason||"Elicitation denied by hook",command:K}}break;case"ElicitationResult":if(q.hookSpecificOutput.action){if(H.elicitationResultResponse={action:q.hookSpecificOutput.action,content:q.hookSpecificOutput.content},q.hookSpecificOutput.action==="decline")H.blockingError={blockingError:q.reason||"Elicitation result blocked by hook",command:K}}break}}return{...H,message:H.blockingError?V4({type:"hook_blocking_error",hookName:_,toolUseID:z,hookEvent:Y,blockingError:H.blockingError}):V4({type:"hook_success",hookName:_,toolUseID:z,hookEvent:Y,content:"",stdout:A,stderr:O,exitCode:w,command:K,durationMs:j})}}async function hQ8(q,K,_,z,Y,$,A,O,w,j,H,J){let M=K==="SessionStart"||K==="Setup"||K==="SessionEnd",X=Date.now(),P,W=!1,D=Z1()==="windows",f=q.shell??zD6,G=f==="powershell",Z=D&&!G?(n)=>ff(n):(n)=>n,T=Fz(),v=q.command,V;if(O){if(!await u5(O))throw Error(`Plugin directory does not exist: ${O}`+(w?` (${w} — run /plugin to reinstall)`:""));let n=Z(O);if(v=v.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g,()=>n),w){let l=Z(ei(w));v=v.replace(/\$\{CLAUDE_PLUGIN_DATA\}/g,()=>l)}if(w)V=VG(w),v=kk6(v,V)}if(D&&!G&&v.trim().match(/\.sh(\s|$|")/)){if(!v.trim().startsWith("bash "))v=`bash ${v}`}let E=!G&&process.env.CLAUDE_CODE_SHELL_PREFIX?JI8(process.env.CLAUDE_CODE_SHELL_PREFIX,v):v,S=q.timeout?q.timeout*1000:PO,R={...Ym(),CLAUDE_PROJECT_DIR:Z(T)};if(O){if(R.CLAUDE_PLUGIN_ROOT=Z(O),w)R.CLAUDE_PLUGIN_DATA=Z(ei(w))}if(V)for(let[n,l]of Object.entries(V)){let A6=n.replace(/[^A-Za-z0-9_]/g,"_").toUpperCase();R[`CLAUDE_PLUGIN_OPTION_${A6}`]=String(l)}if(j)R.CLAUDE_PLUGIN_ROOT=Z(j);if(!G&&(K==="SessionStart"||K==="Setup"||K==="CwdChanged"||K==="FileChanged")&&A!==void 0)R.CLAUDE_ENV_FILE=await p5K(K,A);let x=Z8(),I=await u5(x)?x:r1();if(I!==x)N(`Hooks: cwd ${x} not found, falling back to original cwd`,{level:"warn"});let B;if(f==="powershell"){let n=await Pa();if(!n)throw Error(`Hook "${q.command}" has shell: 'powershell' but no PowerShell executable (pwsh or powershell) was found on PATH. Install PowerShell, or remove "shell": "powershell" to use bash.`);B=ZgK(n,Ta1(E),{env:R,cwd:I,windowsHide:!0})}else{let n=D?X41():!0;B=ZgK(E,[],{env:R,cwd:I,shell:n,windowsHide:!0})}let p=new JO(`hook_${B.pid}`,null),C=WI8(B,Y,S,p),g=!1,F=!1;if((q.async||q.asyncRewake)&&!H){let n=`async_hook_${B.pid}`;if(N(`Hooks: Config-based async hook, backgrounding process ${n}`),B.stdin.write(z+` |
| 7717 | `,"utf8"),B.stdin.end(),F=!0,GgK({processId:n,hookId:$,shellCommand:C,asyncResponse:{async:!0,asyncTimeout:S},hookEvent:K,hookName:_,command:q.command,asyncRewake:q.asyncRewake,pluginId:w}))return{stdout:"",stderr:"",output:"",status:0,backgrounded:!0}}let U="",c="",K6="";B.stdout.setEncoding("utf8"),B.stderr.setEncoding("utf8");let t=!1,q6=null,e=new Promise((n)=>{q6=n}),i=new Set,$6=Promise.resolve(),M6="";B.stdout.on("data",(n)=>{if(U+=n,K6+=n,J){M6+=n;let l=M6.split(` |
| 7718 | `);M6=l.pop()??"";for(let A6 of l){let J6=A6.trim();if(!J6)continue;try{let X6=r8(J6),f6=YgK().safeParse(X6);if(f6.success){i.add(J6),N(`Hooks: Detected prompt request from hook: ${J6}`);let N6=f6.data,Z6=J;$6=$6.then(async()=>{try{let V6=await Z6(N6);B.stdin.write(g6(V6)+` |
| 7719 | `,"utf8")}catch(V6){N(`Hooks: Prompt request handling failed: ${V6}`),B.stdin.destroy()}});continue}}catch{}}}if(!t){let l=ce(U).trim();if(!l.includes("}"))return;t=!0,N(`Hooks: Checking first line for async: ${l}`);try{let A6=r8(l);if(N(`Hooks: Parsed initial response: ${g6(A6)}`),rb(A6)&&!H){let J6=`async_hook_${B.pid}`;if(N(`Hooks: Detected async hook, backgrounding process ${J6}`),GgK({processId:J6,hookId:$,shellCommand:C,asyncResponse:A6,hookEvent:K,hookName:_,command:q.command,pluginId:w}))g=!0,q6?.({stdout:U,stderr:c,output:K6,status:0})}else if(rb(A6)&&H)N("Hooks: Detected async hook but forceSyncExecution is true, waiting for completion");else N("Hooks: Initial response is not async, continuing normal processing")}catch(A6){N(`Hooks: Failed to parse initial response as JSON: ${A6}`)}}}),B.stderr.on("data",(n)=>{c+=n,K6+=n});let j6=KB8({hookId:$,hookName:_,hookEvent:K,getOutput:async()=>({stdout:U,stderr:c,output:K6})}),G6=new Promise((n)=>{B.stdout.on("end",()=>n())}),w6=new Promise((n)=>{B.stderr.on("end",()=>n())}),o=F?Promise.resolve():new Promise((n,l)=>{if(B.stdin.on("error",(A6)=>{if(!J)l(A6);else N(`Hooks: stdin error during prompt flow (likely process exited): ${A6}`)}),B.stdin.write(z+` |
| 7720 | `,"utf8"),!J)B.stdin.end();n()}),s=new Promise((n,l)=>{B.on("error",l)}),a=new Promise((n)=>{let l=null;B.on("close",(A6)=>{l=A6??1,Promise.all([G6,w6]).then(()=>{let J6=i.size===0?U:U.split(` |
| 7721 | `).filter((X6)=>!i.has(X6.trim())).join(` |
| 7722 | `);n({stdout:J6,stderr:c,output:K6,status:l,aborted:Y.aborted})})})});try{if(M)c8("info","hook_spawn_started",{hook_event_name:K,index:A});await Promise.race([o,s]);let n=await Promise.race([e,a,s]);return await $6,P=n.status,W=n.aborted??!1,n}catch(n){let l=s1(n);if(P=1,l==="EPIPE"){N("EPIPE error while writing to hook stdin (hook command likely closed early)");let A6="Hook command closed stdin before hook input was fully written (EPIPE)";return{stdout:"",stderr:A6,output:A6,status:1}}else if(l==="ABORT_ERR")return W=!0,{stdout:"",stderr:"Hook cancelled",output:"Hook cancelled",status:1,aborted:!0};else{let J6=`Error occurred while executing hook command: ${d6(n)}`;return{stdout:"",stderr:J6,output:J6,status:1}}}finally{if(M)c8("info","hook_spawn_completed",{hook_event_name:K,index:A,duration_ms:Date.now()-X,exit_code:P,aborted:W});if(j6(),!g)C.cleanup()}}function lhY(q,K){if(!K||K==="*")return!0;if(/^[a-zA-Z0-9_|]+$/.test(K)){if(K.includes("|"))return K.split("|").map((z)=>Zf(z.trim())).includes(q);return q===Zf(K)}try{let _=new RegExp(K);if(_.test(q))return!0;for(let z of $S7(q))if(_.test(z))return!0;return!1}catch{return N(`Invalid regex pattern in hook matcher: ${K}`),!1}}async function nhY(q,K){if(q.hook_event_name!=="PreToolUse"&&q.hook_event_name!=="PostToolUse"&&q.hook_event_name!=="PostToolUseFailure"&&q.hook_event_name!=="PermissionRequest")return;let _=Zf(q.tool_name),z=K&&L5(K,q.tool_name),Y=z?.inputSchema.safeParse(q.tool_input),$=Y?.success&&z?.preparePermissionMatcher?await z.preparePermissionMatcher(Y.data):void 0;return(A)=>{let O=G2(A);if(Zf(O.toolName)!==_)return!1;if(!O.ruleContent)return!0;return $?$(O.ruleContent):!1}}function NgK(q){return q.hook.type==="callback"&&q.hook.internal===!0}function RQ8(q,K){return`${q.pluginRoot??q.skillRoot??""}\x00${K}`}function ygK(q){let K=q.filter((z)=>z.pluginId);if(K.length===0)return;let _={};for(let z of K){let Y=z.pluginId.lastIndexOf("@"),A=Y>0&&_I.has(z.pluginId.slice(Y+1))?z.pluginId:"third-party";_[A]=(_[A]||0)+1}return _}function EgK(q){let K={};for(let _ of q)K[_.hook.type]=(K[_.hook.type]||0)+1;return K}function ihY(q,K,_){let z=[...bQ()?.[_]??[]],Y=fb(),$=sR()?.[_];if($)for(let A of $){if(Y&&"pluginRoot"in A)continue;z.push(A)}if(!Y&&q!==void 0){let A=HL8(q,K,_).get(_);if(A)for(let w of A)z.push(w);let O=Gb4(q,K,_).get(_);if(O)for(let w of O)z.push(w)}return z}function iS6(q,K,_){let z=bQ()?.[q];if(z&&z.length>0)return!0;let Y=sR()?.[q];if(Y&&Y.length>0)return!0;if(K?.sessionHooks.get(_)?.hooks[q])return!0;return!1}async function O_7(q,K,_,z,Y){try{let $=ihY(q,K,_),A=void 0;switch(z.hook_event_name){case"PreToolUse":case"PostToolUse":case"PostToolUseFailure":case"PermissionRequest":case"PermissionDenied":A=z.tool_name;break;case"SessionStart":A=z.source;break;case"Setup":A=z.trigger;break;case"PreCompact":case"PostCompact":A=z.trigger;break;case"Notification":A=z.notification_type;break;case"SessionEnd":A=z.reason;break;case"StopFailure":A=z.error;break;case"SubagentStart":A=z.agent_type;break;case"SubagentStop":A=z.agent_type;break;case"TeammateIdle":case"TaskCreated":case"TaskCompleted":break;case"Elicitation":A=z.mcp_server_name;break;case"ElicitationResult":A=z.mcp_server_name;break;case"ConfigChange":A=z.source;break;case"InstructionsLoaded":A=z.load_reason;break;case"FileChanged":A=dhY(z.file_path);break;default:break}N(`Getting matching hook commands for ${_} with query: ${A}`,{level:"verbose"}),N(`Found ${$.length} hook matchers in settings`,{level:"verbose"});let w=(A?$.filter((v)=>!v.matcher||lhY(A,v.matcher)):$).flatMap((v)=>{let V="pluginRoot"in v?v.pluginRoot:void 0,E="pluginId"in v?v.pluginId:void 0,S="skillRoot"in v?v.skillRoot:void 0,R=V?"pluginName"in v?`plugin:${v.pluginName}`:"plugin":S?"skillName"in v?`skill:${v.skillName}`:"skill":"settings";return v.hooks.map((x)=>({hook:x,pluginRoot:V,pluginId:E,skillRoot:S,hookSource:R}))});if(w.every((v)=>v.hook.type==="callback"||v.hook.type==="function"))return w;let j=(v)=>v.if??"",H=Array.from(new Map(w.filter((v)=>v.hook.type==="command").map((v)=>[RQ8(v,`${v.hook.shell??zD6}\x00${v.hook.command}\x00${j(v.hook)}`),v])).values()),J=Array.from(new Map(w.filter((v)=>v.hook.type==="prompt").map((v)=>[RQ8(v,`${v.hook.prompt}\x00${j(v.hook)}`),v])).values()),M=Array.from(new Map(w.filter((v)=>v.hook.type==="agent").map((v)=>[RQ8(v,`${v.hook.prompt}\x00${j(v.hook)}`),v])).values()),X=Array.from(new Map(w.filter((v)=>v.hook.type==="http").map((v)=>[RQ8(v,`${v.hook.url}\x00${j(v.hook)}`),v])).values()),P=w.filter((v)=>v.hook.type==="callback"),W=w.filter((v)=>v.hook.type==="function"),D=[...H,...J,...M,...X,...P,...W],G=D.some((v)=>(v.hook.type==="command"||v.hook.type==="prompt"||v.hook.type==="agent"||v.hook.type==="http")&&v.hook.if)?await nhY(z,Y):void 0,Z=D.filter((v)=>{if(v.hook.type!=="command"&&v.hook.type!=="prompt"&&v.hook.type!=="agent"&&v.hook.type!=="http")return!0;let V=v.hook.if;if(!V)return!0;if(!G)return N(`Hook if condition "${V}" cannot be evaluated for non-tool event ${z.hook_event_name}`),!1;if(G(V))return!0;return N(`Skipping hook due to if condition "${V}" not matching`),!1}),T=_==="SessionStart"||_==="Setup"?Z.filter((v)=>{if(v.hook.type==="http")return N(`Skipping HTTP hook ${v.hook.url} — HTTP hooks are not supported for ${_}`),!1;return!0}):Z;return N(`Matched ${T.length} unique hooks for query "${A||"no match query"}" (${w.length} before deduplication)`,{level:"verbose"}),T}catch{return[]}}function z87(q,K){return`${q} hook error: ${K.blockingError}`}function G87(q){return`Stop hook feedback: |
| 7723 | ${q.blockingError}`}function T87(q){return`TeammateIdle hook feedback: |
| 7724 | ${q.blockingError}`}function Y67(q){return`TaskCreated hook feedback: |