From cd728404cc02d5cbced8a9d13cfdc4a044650534 Mon Sep 17 00:00:00 2001 From: Adam Bowker Date: Thu, 2 Apr 2026 13:19:01 -0700 Subject: [PATCH] fix(code): fix subagent sessions --- apps/code/src/main/services/agent/service.ts | 69 +++++++++++++++---- ...nthropic-ai__claude-agent-sdk@0.2.76.patch | 13 ++++ pnpm-lock.yaml | 7 +- pnpm-workspace.yaml | 1 + 4 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch diff --git a/apps/code/src/main/services/agent/service.ts b/apps/code/src/main/services/agent/service.ts index a21ecc5e9..a8daf0d03 100644 --- a/apps/code/src/main/services/agent/service.ts +++ b/apps/code/src/main/services/agent/service.ts @@ -177,6 +177,56 @@ const onAgentLog: OnLogCallback = (level, scope, message, data) => { } }; +const HAIKU_EXPLORE_AGENT_OVERRIDE = { + description: + 'Fast agent for exploring and understanding codebases. Use this when you need to find files by pattern (eg. "src/components/**/*.tsx"), search for code or keywords (eg. "where is the auth middleware?"), or answer questions about how the codebase works (eg. "how does the session service handle reconnects?"). When calling this agent, specify a thoroughness level: "quick" for targeted lookups, "medium" for broader exploration, or "very thorough" for comprehensive analysis across multiple locations.', + model: "haiku", + prompt: `You are a fast, read-only codebase exploration agent. + +Your job is to find files, search code, read the most relevant sources, and report findings clearly. + +Rules: +- Never create, modify, delete, move, or copy files. +- Never use shell redirection or any command that changes system state. +- Use Glob for broad file pattern matching. +- Use Grep for searching file contents. +- Use Read when you know the exact file path to inspect. +- Use Bash only for safe read-only commands like ls, git status, git log, git diff, find, cat, head, and tail. +- Adapt your search approach based on the thoroughness level specified by the caller. +- Return file paths as absolute paths in your final response. +- Avoid using emojis. +- Wherever possible, spawn multiple parallel tool calls for grepping and reading files. +- Search efficiently, then read only the most relevant files. +- Return findings directly in your final response — do not create files.`, + tools: [ + "Bash", + "Glob", + "Grep", + "Read", + "WebFetch", + "WebSearch", + "NotebookRead", + "TodoWrite", + ], +}; + +function buildClaudeCodeOptions(args: { + additionalDirectories?: string[]; + effort?: EffortLevel; + plugins: { type: "local"; path: string }[]; +}) { + return { + ...(args.additionalDirectories?.length && { + additionalDirectories: args.additionalDirectories, + }), + ...(args.effort && { effort: args.effort }), + plugins: args.plugins, + agents: { + Explore: HAIKU_EXPLORE_AGENT_OVERRIDE, + }, + }; +} + interface SessionConfig { taskId: string; taskRunId: string; @@ -601,6 +651,11 @@ export class AgentService extends TypedEventEmitter { }, ...externalPlugins, ]; + const claudeCodeOptions = buildClaudeCodeOptions({ + additionalDirectories, + effort, + plugins, + }); let configOptions: SessionConfigOption[] | undefined; let agentSessionId: string; @@ -648,13 +703,7 @@ export class AgentService extends TypedEventEmitter { ...(permissionMode && { permissionMode }), ...(model != null && { model }), claudeCode: { - options: { - ...(additionalDirectories?.length && { - additionalDirectories, - }), - ...(effort && { effort }), - plugins, - }, + options: claudeCodeOptions, }, }, }); @@ -680,11 +729,7 @@ export class AgentService extends TypedEventEmitter { ...(permissionMode && { permissionMode }), ...(model != null && { model }), claudeCode: { - options: { - ...(additionalDirectories?.length && { additionalDirectories }), - ...(effort && { effort }), - plugins, - }, + options: claudeCodeOptions, }, }, }); diff --git a/patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch b/patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch new file mode 100644 index 000000000..19c09d30d --- /dev/null +++ b/patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch @@ -0,0 +1,13 @@ +diff --git a/cli.js b/cli.js +index 6fa1945a6ba0ca6482f142f956f190d308f84a63..3795f0956744567afd7ce134a2f25aa65e569460 100755 +--- a/cli.js ++++ b/cli.js +@@ -14566,7 +14566,7 @@ ${W6.text} + + `);_0({mode:"prompt",value:j6,uuid:WD()}),i();return}if(D&&!X){X=!0,k("[print.ts] Input closed with active teammates, injecting shutdown prompt"),_0({mode:"prompt",value:ohq,uuid:WD()}),i();return}await new Promise((K1)=>setTimeout(K1,500))}}if(D)if(await(async()=>{let o6=O();if(AT8(o6))await qT8($,o6);let V6=O(),b6=V6.teamContext;return b6&&Object.keys(b6.teammates).length>0||cD1(V6)})())_0({mode:"prompt",value:ohq,uuid:WD()}),i();else{if(G.inflightPromise)await Promise.race([G.inflightPromise,new Promise((o6)=>setTimeout(o6,5000))]);G.abortController?.abort(),G.abortController=null,await oF8(),o(),Nt.delete(f),Z.done()}},l=null;if(nhq&&rhq?.isKairosCronEnabled())l=nhq.createCronScheduler({onFire:(T6)=>{if(D)return;_0({mode:"prompt",value:T6,uuid:WD(),priority:"later",isMeta:!0,workload:rA1}),i()},isLoading:()=>M||D,getJitterConfig:xXz?.getCronJitterConfig,isKilled:()=>!rhq?.isKairosCronEnabled()}),l.start();let q6=function(T6,D6){Z.enqueue({type:"control_response",response:{subtype:"success",request_id:T6.request_id,response:D6}})},w6=function(T6,D6){Z.enqueue({type:"control_response",response:{subtype:"error",request_id:T6.request_id,error:D6}})},O6=new Set;A.setUnexpectedResponseCallback(async(T6)=>{await ASq({message:T6,setAppState:$,handledToolUseIds:O6,onEnqueued:()=>{i()}})});let L6=new Map,y6=new Map,G6=new Set,R6=new Map;return(async()=>{let T6=!1;U1("info","cli_message_loop_started");for await(let D6 of A.structuredInput){let Q6="uuid"in D6?D6.uuid:void 0;if(Q6&&D6.type!=="user"&&D6.type!=="control_response")pb(Q6,"started"),pb(Q6,"completed");if(D6.type==="control_request"){if(D6.request.subtype==="interrupt"){if(W)W.abort();G.abortController?.abort(),G.abortController=null,G.lastEmitted=null,G.pendingSuggestion=null,q6(D6)}else if(D6.request.subtype==="end_session"){if(k(`[print.ts] end_session received, reason=${D6.request.reason??"unspecified"}`),W)W.abort();G.abortController?.abort(),G.abortController=null,G.lastEmitted=null,G.pendingSuggestion=null,q6(D6);break}else if(D6.request.subtype==="initialize"){if(D6.request.sdkMcpServers&&D6.request.sdkMcpServers.length>0)for(let k6 of D6.request.sdkMcpServers)w[k6]={type:"sdk",name:k6};if(await FXz(D6.request,D6.request_id,T6,Z,K,h,A,!!j.enableAuthStatus,j,H,O),D6.request.promptSuggestions)$((k6)=>{if(k6.promptSuggestionEnabled)return k6;return{...k6,promptSuggestionEnabled:!0}});if(D6.request.agentProgressSummaries&&w8("tengu_slate_prism",!0))Vu1(!0);if(T6=!0,d36())i()}else if(D6.request.subtype==="set_permission_mode"){let k6=D6.request;$((Z6)=>({...Z6,toolPermissionContext:pXz(k6,D6.request_id,Z6.toolPermissionContext,Z)}))}else if(D6.request.subtype==="set_model"){let k6=D6.request.model??"default",Z6=k6==="default"?g0():k6;R=Z6,MW(Z6),EC1({model:Z6});let u6=fTq(k6,oR(Z6));v.push(...u6);for(let C6 of u6)if(typeof C6.message.content==="string"&&C6.message.content.includes(`<${WP}>`))Z.enqueue({type:"user",message:C6.message,session_id:R1(),parent_tool_use_id:null,uuid:C6.uuid,isReplay:!0});q6(D6)}else if(D6.request.subtype==="set_max_thinking_tokens"){if(D6.request.max_thinking_tokens===null)j.thinkingConfig=void 0;else if(D6.request.max_thinking_tokens===0)j.thinkingConfig={type:"disabled"};else j.thinkingConfig={type:"enabled",budgetTokens:D6.request.max_thinking_tokens};q6(D6)}else if(D6.request.subtype==="mcp_status"){await H6();let k6=O(),Z6=k6.mcp.clients,u6=K0([...k6.mcp.tools,...p.tools],"name"),C6=new Set([...Z6.map((V6)=>V6.name),...u.map((V6)=>V6.name)]),o6=[...Z6,...u,...p.clients.filter((V6)=>!C6.has(V6.name))].map((V6)=>{let b6;if(V6.config.type==="sse"||V6.config.type==="http")b6={type:V6.config.type,url:V6.config.url,headers:V6.config.headers,oauth:V6.config.oauth};else if(V6.config.type==="claudeai-proxy")b6={type:"claudeai-proxy",url:V6.config.url,id:V6.config.id};else if(V6.config.type==="stdio"||V6.config.type===void 0)b6={type:"stdio",command:V6.config.command,args:V6.config.args};let E6=V6.type==="connected"?eB(u6,V6.name).map((U6)=>({name:U6.mcpInfo?.toolName??U6.name,annotations:{readOnly:U6.isReadOnly({})||void 0,destructive:U6.isDestructive?.({})||void 0,openWorld:U6.isOpenWorld?.({})||void 0}})):void 0;return{name:V6.name,status:V6.type,serverInfo:V6.type==="connected"?V6.serverInfo:void 0,error:V6.type==="failed"?V6.error:void 0,config:b6,scope:V6.config.scope,tools:E6}});q6(D6,{mcpServers:o6})}else if(D6.request.subtype==="mcp_message"){let k6=D6.request,Z6=u.find((u6)=>u6.name===k6.server_name);if(Z6&&Z6.type==="connected"&&Z6.client?.transport?.onmessage)Z6.client.transport.onmessage(k6.message);q6(D6)}else if(D6.request.subtype==="rewind_files"){let k6=O(),Z6=await thq(D6.request.user_message_id,k6,$,D6.request.dry_run??!1);if(Z6.canRewind||D6.request.dry_run)q6(D6,Z6);else w6(D6,Z6.error??"Unexpected error")}else if(D6.request.subtype==="cancel_async_message"){let k6=D6.request.message_uuid,Z6=iP1((u6)=>u6.uuid===k6);q6(D6,{cancelled:Z6.length>0})}else if(D6.request.subtype==="mcp_set_servers"){let{response:k6,sdkServersChanged:Z6}=await K6(D6.request.servers);if(q6(D6,k6),Z6)b()}else if(D6.request.subtype==="mcp_reconnect"){await H6();let k6=O(),{serverName:Z6}=D6.request;g.delete(Z6);let u6=cv(Z6)??q.find((C6)=>C6.name===Z6)?.config??u.find((C6)=>C6.name===Z6)?.config??p.clients.find((C6)=>C6.name===Z6)?.config??k6.mcp.clients.find((C6)=>C6.name===Z6)?.config??null;if(!u6)w6(D6,`Server not found: ${Z6}`);else{let C6=await nl(Z6,u6),o6=HC(Z6);if($((V6)=>({...V6,mcp:{...V6.mcp,clients:V6.mcp.clients.map((b6)=>b6.name===Z6?C6.client:b6),tools:[...yN(V6.mcp.tools,(b6)=>b6.name?.startsWith(o6)),...C6.tools],commands:[...yN(V6.mcp.commands,(b6)=>b6.name?.startsWith(o6)),...C6.commands],resources:C6.resources&&C6.resources.length>0?{...V6.mcp.resources,[Z6]:C6.resources}:Z16(V6.mcp.resources,Z6)}})),p={...p,clients:[...p.clients.filter((V6)=>V6.name!==Z6),C6.client],tools:[...p.tools.filter((V6)=>!V6.name?.startsWith(o6)),...C6.tools]},C6.client.type==="connected")B([C6.client]),q6(D6);else{let V6=C6.client.type==="failed"?C6.client.error??"Connection failed":`Server status: ${C6.client.type}`;w6(D6,V6)}}}else if(D6.request.subtype==="mcp_toggle"){await H6();let k6=O(),{serverName:Z6,enabled:u6}=D6.request;g.delete(Z6);let C6=cv(Z6)??q.find((o6)=>o6.name===Z6)?.config??u.find((o6)=>o6.name===Z6)?.config??p.clients.find((o6)=>o6.name===Z6)?.config??k6.mcp.clients.find((o6)=>o6.name===Z6)?.config??null;if(!C6)w6(D6,`Server not found: ${Z6}`);else if(!u6){MZ6(Z6,!1);let o6=[...q,...u,...p.clients,...k6.mcp.clients].find((b6)=>b6.name===Z6);if(o6&&o6.type==="connected")await VN(Z6,C6);let V6=HC(Z6);$((b6)=>({...b6,mcp:{...b6.mcp,clients:b6.mcp.clients.map((E6)=>E6.name===Z6?{name:Z6,type:"disabled",config:C6}:E6),tools:yN(b6.mcp.tools,(E6)=>E6.name?.startsWith(V6)),commands:yN(b6.mcp.commands,(E6)=>E6.name?.startsWith(V6)),resources:Z16(b6.mcp.resources,Z6)}})),q6(D6)}else{MZ6(Z6,!0);let o6=await nl(Z6,C6),V6=HC(Z6);if($((b6)=>({...b6,mcp:{...b6.mcp,clients:b6.mcp.clients.map((E6)=>E6.name===Z6?o6.client:E6),tools:[...yN(b6.mcp.tools,(E6)=>E6.name?.startsWith(V6)),...o6.tools],commands:[...yN(b6.mcp.commands,(E6)=>E6.name?.startsWith(V6)),...o6.commands],resources:o6.resources&&o6.resources.length>0?{...b6.mcp.resources,[Z6]:o6.resources}:Z16(b6.mcp.resources,Z6)}})),o6.client.type==="connected")B([o6.client]),q6(D6);else{let b6=o6.client.type==="failed"?o6.client.error??"Connection failed":`Server status: ${o6.client.type}`;w6(D6,b6)}}}else if(D6.request.subtype==="mcp_authenticate"){await H6();let{serverName:k6}=D6.request,Z6=O(),u6=cv(k6)??q.find((C6)=>C6.name===k6)?.config??Z6.mcp.clients.find((C6)=>C6.name===k6)?.config??null;if(!u6)w6(D6,`Server not found: ${k6}`);else if(u6.type!=="sse"&&u6.type!=="http")w6(D6,`Server type "${u6.type}" does not support OAuth authentication`);else try{L6.get(k6)?.abort();let C6=new AbortController;L6.set(k6,C6);let o6,V6=new Promise((c6)=>{o6=c6}),b6=mv6(k6,u6,(c6)=>o6(c6),C6.signal,{skipBrowserOpen:!0,onWaitingForCallback:(c6)=>{y6.set(k6,c6)}}),E6=await Promise.race([V6,b6.then(()=>null)]);if(E6)q6(D6,{authUrl:E6,requiresUserAction:!0});else q6(D6,{requiresUserAction:!1});R6.set(k6,b6);let U6=b6.then(async()=>{if(iv(k6))return;if(G6.has(k6))return;let c6=await nl(k6,u6),K1=HC(k6);$((j6)=>({...j6,mcp:{...j6.mcp,clients:j6.mcp.clients.map((W6)=>W6.name===k6?c6.client:W6),tools:[...yN(j6.mcp.tools,(W6)=>W6.name?.startsWith(K1)),...c6.tools],commands:[...yN(j6.mcp.commands,(W6)=>W6.name?.startsWith(K1)),...c6.commands],resources:c6.resources&&c6.resources.length>0?{...j6.mcp.resources,[k6]:c6.resources}:Z16(j6.mcp.resources,k6)}})),p={...p,clients:[...p.clients.filter((j6)=>j6.name!==k6),c6.client],tools:[...p.tools.filter((j6)=>!j6.name?.startsWith(K1)),...c6.tools]}}).catch((c6)=>{k(`MCP OAuth failed for ${k6}: ${c6}`,{level:"error"})}).finally(()=>{if(L6.get(k6)===C6)L6.delete(k6),y6.delete(k6),G6.delete(k6),R6.delete(k6)})}catch(C6){w6(D6,_1(C6))}}else if(D6.request.subtype==="mcp_oauth_callback_url"){let{serverName:k6,callbackUrl:Z6}=D6.request,u6=y6.get(k6);if(u6){let C6=!1;try{let o6=new URL(Z6);C6=o6.searchParams.has("code")||o6.searchParams.has("error")}catch{}if(!C6)w6(D6,"Invalid callback URL: missing authorization code. Please paste the full redirect URL including the code parameter.");else{G6.add(k6),u6(Z6);let o6=R6.get(k6);if(o6)try{await o6,q6(D6)}catch(V6){w6(D6,V6 instanceof Error?V6.message:"OAuth authentication failed")}else q6(D6)}}else w6(D6,`No active OAuth flow for server: ${k6}`)}else if(D6.request.subtype==="mcp_clear_auth"){await H6();let{serverName:k6}=D6.request,Z6=O(),u6=cv(k6)??q.find((C6)=>C6.name===k6)?.config??Z6.mcp.clients.find((C6)=>C6.name===k6)?.config??null;if(!u6)w6(D6,`Server not found: ${k6}`);else if(u6.type!=="sse"&&u6.type!=="http")w6(D6,`Cannot clear auth for server type "${u6.type}"`);else{await Tn6(k6,u6);let C6=await nl(k6,u6),o6=HC(k6);$((V6)=>({...V6,mcp:{...V6.mcp,clients:V6.mcp.clients.map((b6)=>b6.name===k6?C6.client:b6),tools:[...yN(V6.mcp.tools,(b6)=>b6.name?.startsWith(o6)),...C6.tools],commands:[...yN(V6.mcp.commands,(b6)=>b6.name?.startsWith(o6)),...C6.commands],resources:C6.resources&&C6.resources.length>0?{...V6.mcp.resources,[k6]:C6.resources}:Z16(V6.mcp.resources,k6)}})),q6(D6,{})}}else if(D6.request.subtype==="apply_flag_settings"){let k6=Fw6()??{},Z6=D6.request.settings;yu1({...k6,...Z6}),tO.notifyChange("flagSettings"),q6(D6)}else if(D6.request.subtype==="get_settings"){let k6=O(),Z6=cK(),u6=yC(Z6)?rq6(Z6,k6.effortValue):void 0;q6(D6,{...Svq(),applied:{model:Z6,effort:typeof u6==="string"?u6:null}})}else if(D6.request.subtype==="stop_task"){let{task_id:k6}=D6.request;try{await Qk1(k6,{abortController:W??sK(),getAppState:O,setAppState:$}),q6(D6,{})}catch(Z6){w6(D6,_1(Z6))}}else if(D6.request.subtype==="generate_session_title"){let{description:k6,persist:Z6}=D6.request,u6=(W&&!W.signal.aborted?W:sK()).signal;(async()=>{try{let C6=await wI1(k6,u6);if(C6&&Z6)try{Xr8(R1(),C6)}catch(o6){_6(o6)}q6(D6,{title:C6})}catch(C6){w6(D6,_1(C6))}})()}else if(D6.request.subtype==="remote_control")if(D6.request.enabled)if(Q)q6(D6,{session_url:hZ(Q.bridgeSessionId,Q.sessionIngressUrl),connect_url:z86(Q.environmentId,Q.sessionIngressUrl),environment_id:Q.environmentId});else try{let{initReplBridge:k6}=await Promise.resolve().then(() => (Ns8(),vs8)),Z6=await k6({onInboundMessage(u6){let C6=_I1(u6);if(!C6)return;let{content:o6,uuid:V6}=C6;_0({value:o6,mode:"prompt",uuid:V6,skipSlashCommands:!0}),i()},onPermissionResponse(u6){A.injectControlResponse(u6)},onInterrupt(){W?.abort()},onSetModel(u6){let C6=u6==="default"?g0():u6;R=C6,MW(C6)},onSetMaxThinkingTokens(u6){if(u6===null)j.thinkingConfig=void 0;else if(u6===0)j.thinkingConfig={type:"disabled"};else j.thinkingConfig={type:"enabled",budgetTokens:u6}},onStateChange(u6,C6){k(`[bridge:sdk] State change: ${u6}${C6?` — ${C6}`:""}`),Z.enqueue({type:"system",subtype:"bridge_state",state:u6,detail:C6,uuid:WD(),session_id:R1()})},initialMessages:v.length>0?v:void 0});if(!Z6)w6(D6,"Remote Control initialization failed");else Q=Z6,U=v.length,A.setOnControlRequestSent((u6)=>{Z6.sendControlRequest(u6)}),A.setOnControlRequestResolved((u6)=>{Z6.sendControlCancelRequest(u6)}),q6(D6,{session_url:hZ(Z6.bridgeSessionId,Z6.sessionIngressUrl),connect_url:z86(Z6.environmentId,Z6.sessionIngressUrl),environment_id:Z6.environmentId})}catch(k6){w6(D6,_1(k6))}else{if(Q)A.setOnControlRequestSent(void 0),A.setOnControlRequestResolved(void 0),await Q.teardown(),Q=null;q6(D6)}else w6(D6,`Unsupported control request subtype: ${D6.request.subtype}`);continue}else if(D6.type==="control_response"){if(j.replayUserMessages)Z.enqueue(D6);continue}else if(D6.type==="keep_alive")continue;else if(D6.type==="update_environment_variables")continue;else if(D6.type==="assistant"||D6.type==="system"){let k6=LR1([D6]);if(v.push(...k6),D6.type==="assistant"&&j.replayUserMessages)Z.enqueue(D6);continue}if(D6.type!=="user")continue;if(T6=!0,D6.uuid){let k6=R1();if(await Zr8(k6,D6.uuid)||PI1.has(D6.uuid)){if(k(`Skipping duplicate user message: ${D6.uuid}`),j.replayUserMessages)k(`Sending acknowledgment for duplicate user message: ${D6.uuid}`),Z.enqueue({type:"user",message:D6.message,session_id:k6,parent_tool_use_id:null,uuid:D6.uuid,isReplay:!0});continue}uXz(D6.uuid)}_0({mode:"prompt",value:D6.message.content,uuid:D6.uuid,priority:D6.priority}),i()}if(D=!0,l?.stop(),!M){if(G.inflightPromise)await Promise.race([G.inflightPromise,new Promise((D6)=>setTimeout(D6,5000))]);G.abortController?.abort(),G.abortController=null,await oF8(),o(),Nt.delete(f),Z.done()}})(),Z}function shq(A){let q=async(K,Y,z,_,w)=>{let O=await tJ(K,Y,z,_,w);if(O.behavior==="allow"||O.behavior==="deny")return O;let{signal:$,cleanup:H}=mN(z.abortController.signal);if($.aborted)return H(),{behavior:"deny",message:"Permission prompt was aborted.",decisionReason:{type:"permissionPromptTool",permissionPromptToolName:K.name,toolResult:void 0}};let j=new Promise((P)=>{$.addEventListener("abort",()=>P("aborted"),{once:!0})}),J=A.call({tool_name:K.name,input:Y,tool_use_id:w},z,q,_),M=await Promise.race([J,j]);if(H(),M==="aborted"||$.aborted)return{behavior:"deny",message:"Permission prompt was aborted.",decisionReason:{type:"permissionPromptTool",permissionPromptToolName:K.name,toolResult:void 0}};let D=M,X=A.mapToolResultToToolResultBlockParam(D.data,"1");if(!X.content||!Array.isArray(X.content)||!X.content[0]||X.content[0].type!=="text"||typeof X.content[0].text!=="string")throw Error('Permission prompt tool returned an invalid result. Expected a single text block param with type="text" and a string text value.');return JV6(ao6().parse(WK(X.content[0].text)),A,Y,z)};return q}function gXz(A,q,K,Y){if(A==="stdio")return q.createCanUseTool(Y);else if(A){let z=K.find((_)=>z3(_,A));if(!z){let _=`Error: MCP tool ${A} (passed via --permission-prompt-tool) not found. Available MCP tools: ${K.map((w)=>w.name).join(", ")||"none"}`;throw process.stderr.write(`${_} + `),fK(1),Error(_)}if(!z.inputJSONSchema){let _=`Error: tool ${A} (passed via --permission-prompt-tool) must be an MCP tool`;throw process.stderr.write(`${_} +-`),fK(1),Error(_)}return shq(z)}return tJ}async function FXz(A,q,K,Y,z,_,w,O,$,H,j){if(K){Y.enqueue({type:"control_response",response:{subtype:"error",error:"Already initialized",request_id:q,pending_permission_requests:w.getPendingPermissionRequests()}});return}if(A.systemPrompt!==void 0)$.systemPrompt=A.systemPrompt;if(A.appendSystemPrompt!==void 0)$.appendSystemPrompt=A.appendSystemPrompt;if(A.promptSuggestions!==void 0)$.promptSuggestions=A.promptSuggestions;if(A.agents){let W=_Q6(A.agents,"flagSettings");H.push(...W)}if($.agent){let W=H.find((Z)=>Z.agentType===$.agent);if(W){if(Wp(W.agentType),!$.systemPrompt&&!Qj(W)){let Z=W.getSystemPrompt();if(Z)$.systemPrompt=Z}if(!$.userSpecifiedModel&&W.model&&W.model!=="inherit"){let Z=H5(W.model);MW(Z)}}}let M=PA()?.outputStyle||hf,D=await Tv6(G1()),X=_c6();if(A.hooks){let W={};for(let[Z,G]of Object.entries(A.hooks))W[Z]=G.map((f)=>{let v=f.hookCallbackIds.map((N)=>{return w.createHookCallback(N,f.timeout)});return{matcher:f.matcher,hooks:v}});KA6(W)}if(A.jsonSchema)cu1(A.jsonSchema);let P={commands:z.filter((W)=>W.userInvocable!==!1).map((W)=>({name:W.userFacingName(),description:Sv6(W),argumentHint:W.argumentHint||""})),agents:H.map((W)=>({name:W.agentType,description:W.whenToUse,model:W.model==="inherit"?void 0:W.model})),output_style:M,available_output_styles:Object.keys(D),models:_,account:{email:X?.email,organization:X?.organization,subscriptionType:X?.subscription,tokenSource:X?.tokenSource,apiKeySource:X?.apiKeySource},pid:process.pid};if(Dq()&&yj()){let W=j();P.fast_mode_state=Mm($.userSpecifiedModel??null,W.fastMode)}if(Y.enqueue({type:"control_response",response:{subtype:"success",request_id:q,response:P}}),O){let Z=e0.getInstance().getStatus();if(Z)Y.enqueue({type:"auth_status",isAuthenticating:Z.isAuthenticating,output:Z.output,error:Z.error,uuid:WD(),session_id:R1()})}}async function thq(A,q,K,Y){if(!iz())return{canRewind:!1,error:"File rewinding is not enabled."};if(!tN1(q.fileHistory,A))return{canRewind:!1,error:"No file checkpoint found for this message."};if(Y){let z=eN1(q.fileHistory,A);return{canRewind:!0,filesChanged:z?.filesChanged,insertions:z?.insertions,deletions:z?.deletions}}try{await sN1((z)=>K((_)=>({..._,fileHistory:z(_.fileHistory)})),A)}catch(z){return{canRewind:!1,error:`Failed to rewind: ${z.message}`}}return{canRewind:!0}}function pXz(A,q,K,Y){if(A.mode==="bypassPermissions"){if(bd())return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to bypassPermissions because it is disabled by settings or configuration"}}),K;if(!K.isBypassPermissionsModeAvailable)return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to bypassPermissions because the session was not launched with --dangerously-skip-permissions"}}),K}if(A.mode==="auto"&&!IN())return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to auto because the dangerous action classifier is not enabled"}}),K;return Y.enqueue({type:"control_response",response:{subtype:"success",request_id:q,response:{mode:A.mode}}}),{...ki(K.mode,A.mode,K),mode:A.mode}}function XI1(A,q){if(q==="stream-json"){let K={type:"result",subtype:"error_during_execution",duration_ms:0,duration_api_ms:0,is_error:!0,num_turns:0,stop_reason:null,session_id:R1(),total_cost_usd:0,usage:gZ,modelUsage:{},permission_denials:[],uuid:WD(),errors:[A]};process.stdout.write(B6(K)+` ++`),fK(1),Error(_)}return shq(z)}return tJ}async function FXz(A,q,K,Y,z,_,w,O,$,H,j){if(K){Y.enqueue({type:"control_response",response:{subtype:"error",error:"Already initialized",request_id:q,pending_permission_requests:w.getPendingPermissionRequests()}});return}if(A.systemPrompt!==void 0)$.systemPrompt=A.systemPrompt;if(A.appendSystemPrompt!==void 0)$.appendSystemPrompt=A.appendSystemPrompt;if(A.promptSuggestions!==void 0)$.promptSuggestions=A.promptSuggestions;if(A.agents){let W=_Q6(A.agents,"flagSettings"),Z=dv([...H,...W]);H.splice(0,H.length,...Z)}if($.agent){let W=H.find((Z)=>Z.agentType===$.agent);if(W){if(Wp(W.agentType),!$.systemPrompt&&!Qj(W)){let Z=W.getSystemPrompt();if(Z)$.systemPrompt=Z}if(!$.userSpecifiedModel&&W.model&&W.model!=="inherit"){let Z=H5(W.model);MW(Z)}}}let M=PA()?.outputStyle||hf,D=await Tv6(G1()),X=_c6();if(A.hooks){let W={};for(let[Z,G]of Object.entries(A.hooks))W[Z]=G.map((f)=>{let v=f.hookCallbackIds.map((N)=>{return w.createHookCallback(N,f.timeout)});return{matcher:f.matcher,hooks:v}});KA6(W)}if(A.jsonSchema)cu1(A.jsonSchema);let P={commands:z.filter((W)=>W.userInvocable!==!1).map((W)=>({name:W.userFacingName(),description:Sv6(W),argumentHint:W.argumentHint||""})),agents:H.map((W)=>({name:W.agentType,description:W.whenToUse,model:W.model==="inherit"?void 0:W.model})),output_style:M,available_output_styles:Object.keys(D),models:_,account:{email:X?.email,organization:X?.organization,subscriptionType:X?.subscription,tokenSource:X?.tokenSource,apiKeySource:X?.apiKeySource},pid:process.pid};if(Dq()&&yj()){let W=j();P.fast_mode_state=Mm($.userSpecifiedModel??null,W.fastMode)}if(Y.enqueue({type:"control_response",response:{subtype:"success",request_id:q,response:P}}),O){let Z=e0.getInstance().getStatus();if(Z)Y.enqueue({type:"auth_status",isAuthenticating:Z.isAuthenticating,output:Z.output,error:Z.error,uuid:WD(),session_id:R1()})}}async function thq(A,q,K,Y){if(!iz())return{canRewind:!1,error:"File rewinding is not enabled."};if(!tN1(q.fileHistory,A))return{canRewind:!1,error:"No file checkpoint found for this message."};if(Y){let z=eN1(q.fileHistory,A);return{canRewind:!0,filesChanged:z?.filesChanged,insertions:z?.insertions,deletions:z?.deletions}}try{await sN1((z)=>K((_)=>({..._,fileHistory:z(_.fileHistory)})),A)}catch(z){return{canRewind:!1,error:`Failed to rewind: ${z.message}`}}return{canRewind:!0}}function pXz(A,q,K,Y){if(A.mode==="bypassPermissions"){if(bd())return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to bypassPermissions because it is disabled by settings or configuration"}}),K;if(!K.isBypassPermissionsModeAvailable)return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to bypassPermissions because the session was not launched with --dangerously-skip-permissions"}}),K}if(A.mode==="auto"&&!IN())return Y.enqueue({type:"control_response",response:{subtype:"error",request_id:q,error:"Cannot set permission mode to auto because the dangerous action classifier is not enabled"}}),K;return Y.enqueue({type:"control_response",response:{subtype:"success",request_id:q,response:{mode:A.mode}}}),{...ki(K.mode,A.mode,K),mode:A.mode}}function XI1(A,q){if(q==="stream-json"){let K={type:"result",subtype:"error_during_execution",duration_ms:0,duration_api_ms:0,is_error:!0,num_turns:0,stop_reason:null,session_id:R1(),total_cost_usd:0,usage:gZ,modelUsage:{},permission_denials:[],uuid:WD(),errors:[A]};process.stdout.write(B6(K)+` + `)}else process.stderr.write(A+` + `)}function ehq(A,q){let K=A.findIndex((Y)=>Y.uuid===q.uuid);if(K!==-1)A.splice(K,2)}async function QXz(A,q){let K=!jS();if(q.continue)try{d("tengu_continue_print",{});let Y=await h66(void 0,void 0);if(Y){if(!q.forkSession){if(Y.sessionId){if(_P(eJ(Y.sessionId),Y.fullPath?ihq(Y.fullPath):null),K)await Zh()}}return co6(Y,A),LF(Y),{messages:Y.messages,turnInterruptionState:Y.turnInterruptionState,agentSetting:Y.agentSetting}}}catch(Y){return _6(Y),fK(1),{messages:[]}}if(q.teleport)try{if(!qD("allow_remote_sessions"))throw Error("Remote sessions are disabled by your organization's policy.");if(d("tengu_teleport_print",{}),typeof q.teleport!=="string")throw Error("No session ID provided for teleport");let{checkOutTeleportedSessionBranch:Y,processMessagesForTeleportResume:z,teleportResumeCodeSession:_,validateGitState:w}=await Promise.resolve().then(() => (S66(),bn4));await w();let O=await _(q.teleport),{branchError:$}=await Y(O.branch);return{messages:z(O.log,$)}}catch(Y){return _6(Y),fK(1),{messages:[]}}if(q.resume)try{d("tengu_resume_print",{});let Y=Whq(typeof q.resume==="string"?q.resume:"");if(!Y){let _="Error: --resume requires a valid session ID when used with --print. Usage: claude -p --resume ";if(typeof q.resume==="string")_+=`. Session IDs must be in UUID format (e.g., 550e8400-e29b-41d4-a716-446655440000). Provided value "${q.resume}" is not a valid UUID`;return XI1(_,q.outputFormat),fK(1),{messages:[]}}if(t6(process.env.CLAUDE_CODE_USE_CCR_V2))await jr8(Y.sessionId);else if(Y.isUrl&&Y.ingressUrl&&t6("true"))await Hr8(Y.sessionId,Y.ingressUrl);let z=await h66(Y.sessionId,Y.jsonlFile||void 0);if(!z)if(Y.isUrl||t6(process.env.CLAUDE_CODE_USE_CCR_V2))return{messages:await C0("startup")};else return XI1(`No conversation found with session ID: ${Y.sessionId}`,q.outputFormat),fK(1),{messages:[]};if(q.resumeSessionAt){let _=z.messages.findIndex((w)=>w.uuid===q.resumeSessionAt);if(_<0)return XI1(`No message found with message.uuid of: ${q.resumeSessionAt}`,q.outputFormat),fK(1),{messages:[]};z.messages=_>=0?z.messages.slice(0,_+1):[]}if(!q.forkSession&&z.sessionId){if(_P(eJ(z.sessionId),z.fullPath?ihq(z.fullPath):null),K)await Zh()}return co6(z,A),LF(z),{messages:z.messages,turnInterruptionState:z.turnInterruptionState,agentSetting:z.agentSetting}}catch(Y){_6(Y);let z=Y instanceof Error?`Failed to resume session: ${Y.message}`:"Failed to resume session with --print mode";return XI1(z,q.outputFormat),fK(1),{messages:[]}}return{messages:await C0("startup")}}function UXz(A,q){let K;if(typeof A==="string")if(A.trim()!=="")K=tV8([B6({type:"user",session_id:"",message:{role:"user",content:A},parent_tool_use_id:null})]);else K=tV8([]);else K=A;return q.sdkUrl?new AI1(q.sdkUrl,K,q.replayUserMessages):new so6(K,q.replayUserMessages)}async function ASq({message:A,setAppState:q,onEnqueued:K,handledToolUseIds:Y}){if(A.response.subtype==="success"&&A.response.response?.toolUseID&&typeof A.response.response.toolUseID==="string"){let z=A.response.response,{toolUseID:_}=z;if(!_)return!1;if(k(`handleOrphanedPermissionResponse: received orphaned control_response for toolUseID=${_} request_id=${A.response.request_id}`),Y.has(_))return k(`handleOrphanedPermissionResponse: skipping duplicate orphaned permission for toolUseID=${_} (already handled)`),!1;let w=await fr8(_);if(!w)return k(`handleOrphanedPermissionResponse: no unresolved tool_use found for toolUseID=${_} (already resolved in transcript)`),!1;return Y.add(_),k(`handleOrphanedPermissionResponse: enqueuing orphaned permission for toolUseID=${_} messageID=${w.message.id}`),_0({mode:"orphaned-permission",value:[],orphanedPermission:{permissionResult:z,assistantMessage:w}}),K?.(),!0}return!1}function Vs8(A){return{...A,scope:"dynamic"}}async function qSq(A,q,K,Y){let z={},_={};for(let[X,P]of Object.entries(A))if(P.type==="sdk")z[X]=P;else _[X]=P;let w=new Set(Object.keys(q.configs)),O=new Set(Object.keys(z)),$=[],H=[],j={...q.configs},J=[...q.clients],M=[...q.tools];for(let X of w)if(!O.has(X)){let P=J.find((Z)=>Z.name===X);if(P&&P.type==="connected")await P.cleanup();J=J.filter((Z)=>Z.name!==X);let W=`mcp__${X}__`;M=M.filter((Z)=>!Z.name.startsWith(W)),delete j[X],H.push(X)}for(let[X,P]of Object.entries(z))if(!w.has(X)){j[X]=P;let W={type:"pending",name:X,config:{...P,scope:"dynamic"}};J=[...J,W],$.push(X)}let D=await KSq(_,K,Y);return{response:{added:[...$,...D.response.added],removed:[...H,...D.response.removed],errors:D.response.errors},newSdkState:{configs:j,clients:J,tools:M},newDynamicState:D.newState,sdkServersChanged:$.length>0||H.length>0}}async function KSq(A,q,K){let Y=new Set(Object.keys(q.configs)),z=new Set(Object.keys(A)),_=[...Y].filter((W)=>!z.has(W)),w=[...z].filter((W)=>!Y.has(W)),$=[...Y].filter((W)=>z.has(W)).filter((W)=>{let Z=q.configs[W],G=A[W];if(!Z||!G)return!0;let f=Vs8(G);return!DGq(Z,f)}),H=[],j=[],J={},M=[...q.clients],D=[...q.tools];for(let W of[..._,...$]){let Z=M.find((v)=>v.name===W),G=q.configs[W];if(Z&&G){if(Z.type==="connected")try{await Z.cleanup()}catch(v){_6(v)}await VN(W,G)}let f=`mcp__${W}__`;if(D=D.filter((v)=>!v.name.startsWith(f)),M=M.filter((v)=>v.name!==W),_.includes(W))H.push(W)}for(let W of[...w,...$]){let Z=A[W];if(!Z)continue;let G=Vs8(Z);if(Z.type==="sdk"){j.push(W);continue}try{let f=await zh(W,G);if(M.push(f),f.type==="connected"){let v=await JE(f);D.push(...v)}else if(f.type==="failed")J[W]=f.error||"Connection failed";j.push(W)}catch(f){let v=f instanceof Error?f.message:String(f);J[W]=v,_6(f instanceof Error?f:Error(v))}}let X={};for(let W of z){let Z=A[W];if(Z)X[W]=Vs8(Z)}let P={clients:M,tools:D,configs:X};return K((W)=>{let Z=new Set([...Object.keys(q.configs),...Object.keys(X)]),G=W.mcp.tools.filter((v)=>{for(let N of Z)if(v.name.startsWith(`mcp__${N}__`))return!1;return!0}),f=W.mcp.clients.filter((v)=>{return!Z.has(v.name)});return{...W,mcp:{...W.mcp,tools:[...G,...D],clients:[...f,...M]}}}),{response:{added:j,removed:H,errors:J},newState:P}}var nhq,xXz,rhq,ohq=` + You are running in non-interactive mode and cannot return a response to the user until your team is shut down. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 214b4c5b3..dab1e0eb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false patchedDependencies: + '@anthropic-ai/claude-agent-sdk@0.2.76': + hash: ed2b8fa29edb3afd00b0251a5059caca4bd2bf1b2039af098af3c501f27b2077 + path: patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch node-pty: hash: 4dfdf785f5ac51a03f5d6032371cebe89036381acd403621f250a896245647c5 path: patches/node-pty.patch @@ -596,7 +599,7 @@ importers: version: 0.16.1(zod@3.25.76) '@anthropic-ai/claude-agent-sdk': specifier: 0.2.76 - version: 0.2.76(zod@3.25.76) + version: 0.2.76(patch_hash=ed2b8fa29edb3afd00b0251a5059caca4bd2bf1b2039af098af3c501f27b2077)(zod@3.25.76) '@anthropic-ai/sdk': specifier: ^0.78.0 version: 0.78.0(zod@3.25.76) @@ -11101,7 +11104,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@anthropic-ai/claude-agent-sdk@0.2.76(zod@3.25.76)': + '@anthropic-ai/claude-agent-sdk@0.2.76(patch_hash=ed2b8fa29edb3afd00b0251a5059caca4bd2bf1b2039af098af3c501f27b2077)(zod@3.25.76)': dependencies: zod: 3.25.76 optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4cea2e4c0..2b67bdeed 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -24,3 +24,4 @@ onlyBuiltDependencies: patchedDependencies: node-pty: patches/node-pty.patch + '@anthropic-ai/claude-agent-sdk@0.2.76': patches/@anthropic-ai__claude-agent-sdk@0.2.76.patch