agent-afk 3.3.2 → 3.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -969,7 +969,7 @@ Don't refuse the flow; just clarify where the wizard runs.
969
969
  Be terse and operational. The user is doing one-time setup; they want it done, not narrated. Confirm each step in one line, don't over-explain. Use \`\u2713\` for success, \`\u2717\` for failure, and code fences for any command they should run.
970
970
  `}};function de(e){let t=rd[e];if(!t){let n=Object.keys(rd).sort(),r=n.length>0?"Available: "+n.join(", "):"";throw new Error("Unknown skill: "+e+". "+r)}return t}var Wo=new Map;function _e(e){Wo.set(e.name,e)}function we(e){let t=Wo.get(e);if(t)return t;let n=Array.from(Wo.keys()).sort(),r=n.length>0?`
971
971
  Available skills: ${n.join(", ")}`:"";throw new Error(`Skill not found: ${e}${r}`)}function Ze(){return Array.from(Wo.keys()).sort()}var Ho=class{nodes=new Map;traceWriter;constructor(t){this.traceWriter=t}register(t,n){this.nodes.has(t)||this.nodes.set(t,{controller:n,children:new Set,listeners:new Set,cascading:!1})}has(t){return this.nodes.has(t)}getController(t){return this.nodes.get(t)?.controller}linkChild(t,n){let r=this.nodes.get(t),o=this.nodes.get(n);if(!r)throw new Error(`AbortGraph: parent ${t} not registered`);if(!o)throw new Error(`AbortGraph: child ${n} not registered`);if(o.parentId=t,r.children.add(n),r.controller.signal.aborted){o.controller.signal.aborted||(o.cascading=!0,o.controller.abort(r.controller.signal.reason));return}r.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);!s||s.parentId!==t||s.controller.signal.aborted||(s.cascading=!0,s.controller.abort(r.controller.signal.reason))},{once:!0}),o.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);if(!s||s.parentId!==t||s.cascading)return;let i=this.nodes.get(t);if(!i)return;let a={parentId:t,childId:n,reason:s.controller.signal.reason};for(let l of i.listeners)try{l(a)}catch{}},{once:!0})}onChildAborted(t,n){let r=this.nodes.get(t);if(!r)throw new Error(`AbortGraph: ${t} not registered`);return r.listeners.add(n),()=>{r.listeners.delete(n)}}abort(t,n,r="user_signal"){let o=this.nodes.get(t);if(!o||o.controller.signal.aborted)return;let s=[],i=[...o.children],a=new Set;for(;i.length;){let l=i.shift();if(a.has(l))continue;a.add(l);let c=this.nodes.get(l);if(c){c.cascading=!0,s.push(l);for(let d of c.children)i.push(d)}}Wu(this.traceWriter,{origin:r,cascadedTo:s,...n!==void 0?{reason:Iw(n)}:{}}),o.controller.abort(n);for(let l of s){let c=this.nodes.get(l);c&&!c.controller.signal.aborted&&c.controller.abort(n)}}dispose(t){let n=this.nodes.get(t);if(n){n.parentId&&this.nodes.get(n.parentId)?.children.delete(t);for(let r of n.children){let o=this.nodes.get(r);o&&(o.parentId=void 0)}this.nodes.delete(t)}}};function Iw(e){if(typeof e=="string")return e;if(e instanceof Error)return e.message;try{return JSON.stringify(e)}catch{return String(e)}}var Ko=0,Aa=5e3;async function Go(e,t,n={}){if(!Number.isFinite(t)||t<=0)return e;let r,o=new Promise((s,i)=>{r=setTimeout(()=>{let a=n.label?` (${n.label})`:"",l=new Ke(`Operation timed out after ${t}ms${a}`,t);n.controller&&!n.controller.signal.aborted&&n.controller.abort(l),i(l)},t)});try{return await Promise.race([e,o])}finally{r!==void 0&&clearTimeout(r)}}async function Ut(e,t,n,r){if(!e)return;if(r.kind==="blocked"){await jn(e,{hookEvent:t,decision:"block",...r.err.reason!==void 0?{reason:r.err.reason}:{},...t==="PreToolUse"&&n.toolName!==void 0?{blockedTool:n.toolName}:{}});return}let o=r.decision;await jn(e,{hookEvent:t,decision:o.decision,...o.reason!==void 0?{reason:o.reason}:{},...o.injectContext!==void 0?{injectedContextBytes:Buffer.byteLength(o.injectContext,"utf8")}:{}})}async function od(e,t,n={}){if(e)try{let r=await e.dispatch(t,n.signal);await Ut(n.traceWriter,"SubagentStart",{},{kind:"decision",decision:r})}catch(r){throw r instanceof he&&await Ut(n.traceWriter,"SubagentStart",{},{kind:"blocked",err:r}),r}}async function sd(e,t,n={}){if(!e)return{};try{let r=await e.dispatch(t,n.signal);return await Ut(n.traceWriter,"SubagentStop",{},{kind:"decision",decision:r}),r}catch(r){return r instanceof he&&await Ut(n.traceWriter,"SubagentStop",{},{kind:"blocked",err:r}),r instanceof he||r instanceof He?(X(`SubagentStop hook swallowed ${r.name}: ${r.message}`),n.onError?.(r),{}):(X(`SubagentStop hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r))),{})}}async function Ca(e,t,n={}){if(e)try{let r=await e.dispatch(t,n.signal);await Ut(n.traceWriter,"PreToolUse",{toolName:t.toolName},{kind:"decision",decision:r})}catch(r){throw r instanceof he&&await Ut(n.traceWriter,"PreToolUse",{toolName:t.toolName},{kind:"blocked",err:r}),r}}async function id(e,t,n={}){if(e)try{let r=await e.dispatch(t,n.signal);await Ut(n.traceWriter,"PostToolUse",{toolName:t.toolName},{kind:"decision",decision:r})}catch(r){if(r instanceof he&&await Ut(n.traceWriter,"PostToolUse",{toolName:t.toolName},{kind:"blocked",err:r}),r instanceof he||r instanceof He){X(`PostToolUse hook swallowed ${r.name}: ${r.message}`),n.onError?.(r);return}X(`PostToolUse hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r)))}}import{mkdir as _w,writeFile as Mw}from"fs/promises";import{dirname as $w,join as Ow}from"path";function Dw(){return Ow(gt(),"routing-decisions.jsonl")}async function Ge(e){if(!(process.env.VITEST||process.env.NODE_ENV==="test"))try{let t=Dw();await _w($w(t),{recursive:!0});let r={ts:new Date().toISOString().split(".")[0]+"Z",surface:"afk"};for(let[s,i]of Object.entries(e))i!==void 0&&(r[s]=i);let o=JSON.stringify(r)+`
972
- `;await Mw(t,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as Lw}from"node:async_hooks";var ad=new Lw;function Wn(e,t){return ad.run(e,t)}function et(){return ad.getStore()}function ld(e){let t=Fw(e);return t!==void 0?t:Nw(e)}function Fw(e){let t=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=t.exec(e))!==null;)n=r[1];if(n)return cd(n.trim())}function Nw(e){for(let t=e.length-1;t>=0;t--){if(e[t]!=="}")continue;let n=Uw(e,t);if(n===-1)continue;let r=e.slice(n,t+1),o=cd(r);if(o!==void 0)return o}}function Uw(e,t){let n=0,r=!1,o=!1;for(let s=t;s>=0;s--){let i=e[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function cd(e){try{return JSON.parse(e)}catch{return}}function Pa(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function ud(e,t,n,r,o){if(!r)return{id:e,status:t,message:n,trace:o};let s=ld(n.content),i=r.safeParse(s);return i.success?{id:e,status:t,message:n,output:i.data,trace:o}:{id:e,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function dd(e,t,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:e,status:t,error:o,trace:r}}function ge(e){return`${e.status}${e.error?`: ${e.error.message}`:""}`}function pd(e,t){let n=e;return t.partialOutput!==void 0&&t.partialOutput!==null&&(n.partialOutput=t.partialOutput),t.subagentId!==void 0&&(n.subagentId=t.subagentId),n}var qo=class{constructor(t,n,r,o,s,i,a,l,c,d,u,p,f,g){this.id=t;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=l;this.parentInputStreamRef=c;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=g;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=Pa();lastStreamedContent="";get status(){return this.currentStatus}async run(t){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=Go(this.streamToFinalMessage(t),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",mn(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(mn(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(mn(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(t){let n,r;this.lastStreamedContent="",this.currentTrace=Pa();let o=this.progressSink??et(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(t)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(t){try{let n=await this.run(t);return ud(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=dd(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(t,n){this.runToResult(t).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let t=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",mn(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(t)}}async teardown(){if(this.stopDispatched)return;let t=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(t)}}async dispatchStopAndRelease(t){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await sd(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:t,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)X(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){X(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var W=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(t={}){if(this.parentCanUseTool=t.canUseTool,this.hookRegistry=t.hookRegistry,this.progressSink=t.progressSink,this.parentApiKey=t.apiKey,this.parentBaseUrl=t.baseUrl,this.parentCwd=t.cwd,this.abortGraph=new Ho(t.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),t.parentAbortSignal){let n=t.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(t=>({id:t.id,status:t.status}))}get(t){return this.active.get(t)}onChildAborted(t){return this.abortGraph.onChildAborted(this.rootId,t)}abortAll(t,n="user_signal"){this.abortGraph.abort(this.rootId,t,n)}async forkSubagent(t){let n=`${t.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=t.parent.sessionId,o=t.config.hookRegistry??this.hookRegistry;o&&await od(o,{event:"SubagentStart",subagentId:n,parentSessionId:t.parent.sessionId},{signal:this.rootController.signal,...t.config.traceWriter?{traceWriter:t.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...t.config,resume:r,forkSession:r?!0:t.config.forkSession,abortSignal:s.signal,apiKey:t.config.apiKey||this.parentApiKey,baseUrl:t.config.baseUrl??this.parentBaseUrl,...t.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:t.config.hookRegistry??this.hookRegistry,permissionBubbler:t.config.permissionBubbler??(this.parentCanUseTool!==void 0&&t.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new Le(i),l=t.parent.getInputStreamRef?.(),c=t.parent.abortSignal,d=this.progressSink??et(),u=t.agentType?.trim()||void 0,p=t.parentId?.trim()||void 0,f=new qo(n,a,s,this.abortGraph,t.outputSchema,t.config.timeoutMs??Ko,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},l,c,u??t.idPrefix,d,p??t.parent.sessionId,t.config.traceWriter);this.active.set(n,f);let g=typeof t.config.model=="string"?t.config.model:JSON.stringify(t.config.model);return mn(t.config.traceWriter,{transition:"started",subagentId:n,parentId:t.parent.sessionId??this.rootId,model:g,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await Ge({event:"subagent.dispatched",subagent_id:n,id_prefix:t.idPrefix,parent_session_id:t.parent.sessionId}),f}async kill(t){let n=this.active.get(t);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(t=>t.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(t=>t.teardown()))}};async function zo(e,t={}){let{failFast:n=!0,teardown:r=!0}=t;if(e.length===0)return[];let o=new Array(e.length),s=new Set(e.map((a,l)=>l)),i=e.map((a,l)=>a.handle.runToResult(a.prompt).then(c=>{if(o[l]=c,s.delete(l),n&&c.status!=="succeeded")for(let d of s){let u=e[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(e.map(a=>a.handle.teardown())),o}import{fileURLToPath as jw}from"node:url";import{dirname as Bw}from"node:path";var Ww=jw(import.meta.url),PL=Bw(Ww),Fe={name:"research-agent",systemPrompt:`---
972
+ `;await Mw(t,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as Lw}from"node:async_hooks";var ad=new Lw;function Wn(e,t){return ad.run(e,t)}function et(){return ad.getStore()}function ld(e){let t=Fw(e);return t!==void 0?t:Nw(e)}function Fw(e){let t=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=t.exec(e))!==null;)n=r[1];if(n)return cd(n.trim())}function Nw(e){for(let t=e.length-1;t>=0;t--){if(e[t]!=="}")continue;let n=Uw(e,t);if(n===-1)continue;let r=e.slice(n,t+1),o=cd(r);if(o!==void 0)return o}}function Uw(e,t){let n=0,r=!1,o=!1;for(let s=t;s>=0;s--){let i=e[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function cd(e){try{return JSON.parse(e)}catch{return}}function Pa(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function ud(e,t,n,r,o){if(!r)return{id:e,status:t,message:n,trace:o};let s=ld(n.content),i=r.safeParse(s);return i.success?{id:e,status:t,message:n,output:i.data,trace:o}:{id:e,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function dd(e,t,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:e,status:t,error:o,trace:r}}function ge(e){return`${e.status}${e.error?`: ${e.error.message}`:""}`}function pd(e,t){let n=e;return t.partialOutput!==void 0&&t.partialOutput!==null&&(n.partialOutput=t.partialOutput),t.subagentId!==void 0&&(n.subagentId=t.subagentId),n}var qo=class{constructor(t,n,r,o,s,i,a,l,c,d,u,p,f,g){this.id=t;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=l;this.parentInputStreamRef=c;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=g;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=Pa();lastStreamedContent="";get status(){return this.currentStatus}async run(t){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=Go(this.streamToFinalMessage(t),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",mn(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(mn(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(mn(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(t){let n,r;this.lastStreamedContent="",this.currentTrace=Pa();let o=this.progressSink??et(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(t)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(t){try{let n=await this.run(t);return ud(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=dd(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(t,n){this.runToResult(t).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let t=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",mn(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(t)}}async teardown(){if(this.stopDispatched)return;let t=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(t)}}async dispatchStopAndRelease(t){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await sd(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:t,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)X(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){X(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var W=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(t={}){if(this.parentCanUseTool=t.canUseTool,this.hookRegistry=t.hookRegistry,this.progressSink=t.progressSink,this.parentApiKey=t.apiKey,this.parentBaseUrl=t.baseUrl,this.parentCwd=t.cwd,this.abortGraph=new Ho(t.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),t.parentAbortSignal){let n=t.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(t=>({id:t.id,status:t.status}))}get(t){return this.active.get(t)}onChildAborted(t){return this.abortGraph.onChildAborted(this.rootId,t)}abortAll(t,n="user_signal"){this.abortGraph.abort(this.rootId,t,n)}async forkSubagent(t){let n=`${t.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=t.parent.sessionId,o=t.config.hookRegistry??this.hookRegistry;o&&await od(o,{event:"SubagentStart",subagentId:n,parentSessionId:t.parent.sessionId},{signal:this.rootController.signal,...t.config.traceWriter?{traceWriter:t.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...t.config,resume:r,forkSession:r?!0:t.config.forkSession,abortSignal:s.signal,apiKey:t.config.apiKey||this.parentApiKey,baseUrl:t.config.baseUrl??this.parentBaseUrl,...t.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:t.config.hookRegistry??this.hookRegistry,permissionBubbler:t.config.permissionBubbler??(this.parentCanUseTool!==void 0&&t.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new Le(i),l=t.parent.getInputStreamRef?.(),c=t.parent.abortSignal,d=this.progressSink??et(),u=t.agentType?.trim()||void 0,p=t.parentId?.trim()||void 0,f=new qo(n,a,s,this.abortGraph,t.outputSchema,t.config.timeoutMs??Ko,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},l,c,u??t.idPrefix,d,p??t.parent.sessionId,t.config.traceWriter);this.active.set(n,f);let g=typeof t.config.model=="string"?t.config.model:JSON.stringify(t.config.model);return mn(t.config.traceWriter,{transition:"started",subagentId:n,parentId:t.parent.sessionId??this.rootId,model:g,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await Ge({event:"subagent.dispatched",subagent_id:n,id_prefix:t.idPrefix,model:g,parent_session_id:t.parent.sessionId}),f}async kill(t){let n=this.active.get(t);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(t=>t.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(t=>t.teardown()))}};async function zo(e,t={}){let{failFast:n=!0,teardown:r=!0}=t;if(e.length===0)return[];let o=new Array(e.length),s=new Set(e.map((a,l)=>l)),i=e.map((a,l)=>a.handle.runToResult(a.prompt).then(c=>{if(o[l]=c,s.delete(l),n&&c.status!=="succeeded")for(let d of s){let u=e[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(e.map(a=>a.handle.teardown())),o}import{fileURLToPath as jw}from"node:url";import{dirname as Bw}from"node:path";var Ww=jw(import.meta.url),PL=Bw(Ww),Fe={name:"research-agent",systemPrompt:`---
973
973
  name: research-agent
974
974
  description: Read-only sub-agent for research, validation, verification, and codebase inspection. Mechanically locked to Read, Grep, Glob, WebFetch, WebSearch \u2014 cannot Edit, Write, Bash, commit, or push. Delegates git queries to \`git-investigator\`. Use when the dispatched task is findings-only.
975
975
  model: sonnet
@@ -1345,7 +1345,7 @@ Be skeptical. Protect the plugin from fluff. Stage 2 catches patterns that are s
1345
1345
 
1346
1346
  ${h}`);if(_.status!=="succeeded")throw new Error(`skill generation failed: ${ge(_)}`);let S=_.message?.content||"";if(!S)throw new Error("skill generation returned no output");for(let R=1;R<=l;R++){let E=La.systemPrompt;if(!E)throw new Error("qualify agent missing system prompt");let P=await(await new W({apiKey:r}).forkSubagent({parent:{sessionId:t.sessionId},config:{model:"sonnet",systemPrompt:E},idPrefix:`forge-qualify-${R}`,...o?{parentId:o}:{}})).runToResult(`Evaluate this amplifier skill against the force-multiplier criteria:
1347
1347
 
1348
- ${S}`);if(P.status!=="succeeded")throw new Error(`qualify iteration ${R} failed: ${ge(P)}`);let O=P.message?.content||"",{verdict:M,score:L,feedback:V}=Hd(O),F={iteration:R,verdict:M,score:L,feedback:V};if(d.push(F),c=await qe({event:"forge.qualify_iteration",iteration:R,verdict:M,score:L||null}),M==="APPROVE"){u="APPROVED";break}else if(M==="SALVAGE"&&R<l){let C=y["qualify-rework.md"];if(!C)throw new Error("forge skill missing qualify-rework.md prompt");let D=C.replace("{feedback}",V).replace("{original_skill}",S),z=await(await new W({apiKey:r}).forkSubagent({parent:{sessionId:t.sessionId},config:{model:"sonnet",systemPrompt:D},idPrefix:`forge-rework-${R}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(z.status!=="succeeded")throw new Error(`rework iteration ${R} failed: ${ge(z)}`);if(S=z.message?.content||"",!S)throw new Error(`rework iteration ${R} returned no output`)}else M==="REJECT"&&R>=l&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let R=lv(S);if(!R.ok)throw c=await qe({event:"forge.write_failed",reason:R.reason,skill_name_attempted:R.skillNameAttempted}),new Error(`forge write-step invariant failed (${R.reason}): ${R.message}`);let E=R.skillName,x=cv(E,{skillsDir:Er(),registeredSkills:Ze()});if(x)throw c=await qe({event:"forge.write_failed",reason:x.reason,skill_name_attempted:x.skillNameAttempted}),new Error(`forge write-step invariant failed (${x.reason}): ${x.message}`);let $=St(Er(),E);await Kd($,{recursive:!0});let P=St($,"SKILL.md");await Gd(P,S,"utf-8");let O;try{O=await VS(P,"utf-8")}catch{O=""}if(!O.startsWith("---"))throw c=await qe({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:E}),new Error(`forge write-step invariant failed (readback_failed): written file at ${P} did not read back with expected frontmatter`);p=P,k&&f&&await Fa(f,"consumed"),c=await qe({event:"forge.complete",status:"APPROVED",skill_name:E,iterations:d.length})}else u==="MAX_ITERATIONS"&&(k&&f&&await Fa(f,"failed"),c=await qe({event:"forge.complete",status:"MAX_ITERATIONS",iterations:d.length}))}catch(g){throw c=await qe({event:"forge.error",error:g instanceof Error?g.message:String(g)}),g}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:c}}var dv={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:uv,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};_e(dv);import Va from"path";import{appendFileSync as Sx,mkdirSync as vx}from"fs";import{dirname as Tx}from"path";import Ua from"path";import{appendFileSync as Cv,mkdirSync as Pv}from"fs";import{dirname as Iv}from"path";function Na(e,t){return t?.allowedTools?t.allowedTools.includes(e)?{allowed:!0}:{allowed:!1,reason:`Tool "${e}" is not in the configured allowlist`}:{allowed:!0}}var pv={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},mv={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},fv={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},gv={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},hv={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},yv={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},bv={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},kv={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},wv={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},fn={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1348
+ ${S}`);if(P.status!=="succeeded")throw new Error(`qualify iteration ${R} failed: ${ge(P)}`);let O=P.message?.content||"",{verdict:M,score:L,feedback:V}=Hd(O),F={iteration:R,verdict:M,score:L,feedback:V};if(d.push(F),c=await qe({event:"forge.qualify_iteration",iteration:R,verdict:M,score:L||null,feedback:V||null}),M==="APPROVE"){u="APPROVED";break}else if(M==="SALVAGE"&&R<l){let C=y["qualify-rework.md"];if(!C)throw new Error("forge skill missing qualify-rework.md prompt");let D=C.replace("{feedback}",V).replace("{original_skill}",S),z=await(await new W({apiKey:r}).forkSubagent({parent:{sessionId:t.sessionId},config:{model:"sonnet",systemPrompt:D},idPrefix:`forge-rework-${R}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(z.status!=="succeeded")throw new Error(`rework iteration ${R} failed: ${ge(z)}`);if(S=z.message?.content||"",!S)throw new Error(`rework iteration ${R} returned no output`)}else M==="REJECT"&&R>=l&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let R=lv(S);if(!R.ok)throw c=await qe({event:"forge.write_failed",reason:R.reason,skill_name_attempted:R.skillNameAttempted}),new Error(`forge write-step invariant failed (${R.reason}): ${R.message}`);let E=R.skillName,x=cv(E,{skillsDir:Er(),registeredSkills:Ze()});if(x)throw c=await qe({event:"forge.write_failed",reason:x.reason,skill_name_attempted:x.skillNameAttempted}),new Error(`forge write-step invariant failed (${x.reason}): ${x.message}`);let $=St(Er(),E);await Kd($,{recursive:!0});let P=St($,"SKILL.md");await Gd(P,S,"utf-8");let O;try{O=await VS(P,"utf-8")}catch{O=""}if(!O.startsWith("---"))throw c=await qe({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:E}),new Error(`forge write-step invariant failed (readback_failed): written file at ${P} did not read back with expected frontmatter`);p=P,k&&f&&await Fa(f,"consumed"),c=await qe({event:"forge.complete",status:"APPROVED",skill_name:E,iterations:d.length})}else u==="MAX_ITERATIONS"&&(k&&f&&await Fa(f,"failed"),c=await qe({event:"forge.complete",status:"MAX_ITERATIONS",skill_name_attempted:h||null,iterations:d.length}))}catch(g){throw c=await qe({event:"forge.error",error:g instanceof Error?g.message:String(g)}),g}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:c}}var dv={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:uv,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};_e(dv);import Va from"path";import{appendFileSync as Sx,mkdirSync as vx}from"fs";import{dirname as Tx}from"path";import Ua from"path";import{appendFileSync as Cv,mkdirSync as Pv}from"fs";import{dirname as Iv}from"path";function Na(e,t){return t?.allowedTools?t.allowedTools.includes(e)?{allowed:!0}:{allowed:!1,reason:`Tool "${e}" is not in the configured allowlist`}:{allowed:!0}}var pv={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},mv={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},fv={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},gv={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},hv={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},yv={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},bv={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},kv={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},wv={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},fn={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1349
1349
 
1350
1350
  Parallelize: dispatch multiple \`agent\` calls in a single tool-use turn to run independent investigations concurrently.
1351
1351
 
@@ -1826,7 +1826,7 @@ ${v.map(S=>`> - ${S}`).join(`
1826
1826
 
1827
1827
  `:"")+k,_=g.failed.length>0;return{content:T,isError:_}}catch(u){let p=u instanceof Error?u.message:String(u);return Ge({event:"compose.failed",parent_session_id:this.ctx.parentSession.sessionId,error_message:p.slice(0,240),duration_ms:Date.now()-d}).catch(()=>{}),{content:`Compose execution error: ${p}`,isError:!0}}finally{await l.teardownAll()}}};function or(e,t,n,r){let o=ef();o.register("SubagentStop",tf);let s=n??new Ee;return r!==void 0&&o.register("PreToolUse",nf(r)),o.register("SessionEnd",qa(s,t)),o.register("SessionEnd",i=>i.event!=="SessionEnd"?{}:(i.sessionId&&df(i.sessionId),{})),e&&o.register("SubagentStop",i=>i.event!=="SubagentStop"?{}:i.status==="idle"||i.status==="running"?{}:(e({subagentId:i.subagentId,status:i.status,durationMs:i.durationMs,agentType:i.agentType}),{})),{registry:o,memoryStore:s}}function te(e){let t=Math.round(e/1e3);if(t<=0)return"0s";let n=Math.floor(t/86400),r=Math.floor(t%86400/3600),o=Math.floor(t%3600/60),s=t%60;return n>0?`${n}d ${r}h`:r>0?`${r}h ${o}m`:o>0?`${o}m ${s}s`:`${s}s`}function Ce(e){return e===0?"$0.00":e<.01?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function q(e){if(e<1e3)return String(e);if(e<1e6){let n=e/1e3;return n%1===0?`${n}k`:`${n.toFixed(1).replace(/\.0$/,"")}k`}let t=e/1e6;return t%1===0?`${t}m`:`${t.toFixed(1).replace(/\.0$/,"")}m`}var XR="[skill-routing: active]\n\nRoute recurring work through registered skills instead of rolling ad-hoc solutions:\n\n- Bugs, failing tests, or regressions \u2192 `/diagnose`\n- High-stakes sub-agent output that will drive edits or commits \u2192 `/shadow-verify` before acting\n- Refactor needing parallel waves \u2192 `/parallelize`\n- Parallel or dependent multi-task work \u2192 `compose` tool (DAG of subagent nodes)\n- Greenfield feature where a written spec would genuinely help (novel scope, multi-day work, or external stakeholders involved) \u2192 `/mint`\n\nDo NOT reach for `/mint` for: bug fixes (use `/diagnose`), refactors with known shape, single-feature edits, work already spec'd in chat, or anything where the spec/approve pause would feel like ceremony. Implement directly in those cases.\n\nCommon composed sequences \u2014 reach for these when the task shape matches:\n\n- Bug with failing test and non-trivial fix \u2192 `/diagnose` \u2192 `/shadow-verify` on the proposed fix\n- Refactor needing parallel waves \u2192 plan \u2192 `/parallelize` \u2192 build waves\n- Diagnose + fix in parallel \u2192 `compose` with two independent nodes\n- Research \u2192 implement \u2192 verify pipeline \u2192 `compose` with edges: research\u2192implement\u2192verify\n- Multiple independent investigations \u2192 `compose` with N nodes, no edges\n\nReach for context-isolated investigators when the task is exploratory:\n\n- Map an unfamiliar module before editing \u2192 `/gather` or `/research`\n- Re-derive a load-bearing claim independently \u2192 `/shadow-verify`\n- Audit a diff before merge \u2192 `/review`\n- Survey git + infra + memory before non-trivial work \u2192 `/ground-state`\n- Generate alternatives before committing to a plan \u2192 `/devils-advocate`\n\nOr dispatch a raw `agent` call when no skill matches but the work is parallelizable, verification-heavy, or would otherwise consume substantial inline context.\n\nSkip orchestration for: single-line edits, trivial Q&A, and direct tool calls the user explicitly requested. The goal is leverage, not ceremony. If a skill would add overhead without adding value, don't invoke it.";function Ms(e,t){return!e||!t?e:`${e}
1828
1828
 
1829
- ${XR}`}import Yt from"chalk";var QR={read:Yt.hex("#C9B584"),write:Yt.hex("#E8A33D"),shell:Yt.hex("#A8E060"),subagent:m.plan,skill:Yt.hex("#F08AC4"),dag:Yt.hex("#4EC9B0"),mcp:Yt.hex("#5FE0C0"),web:Yt.hex("#A0C4C0"),planning:m.meta,schedule:Yt.hex("#D4A84B"),other:m.meta},ZR={read:"\u25CF",write:"\u270E",shell:"$",subagent:"\u2192",skill:"\u25C6",dag:"\u2B21",mcp:"\u22A1",web:"\u2316",planning:"\u25B1",schedule:"\u23F2",other:"\u25CF"};function vl(e){return{color:QR[e],glyph:ZR[e]}}function sr(e){return vl(Sn(e))}function pf(e){let{description:t,summary:n,lastToolName:r,totalTokens:o,toolUses:s,durationMs:i}=e,a=[];if(r){let{color:c,glyph:d}=sr(r);a.push(`via ${c(`${d} ${r}`)}`)}s&&a.push(`${s} tool${s===1?"":"s"}`),o&&a.push(`${q(o)} tok`),i&&a.push(te(i));let l=a.length>0?` (${a.join(" \xB7 ")})`:"";return n?[m.dim(` \u25E6 ${t}`),m.dim(` ${n}${l}`)]:[m.dim(` \u25E6 ${t}${l}`)]}function $s(e){let t=e.status==="succeeded"?"\u2713":e.status==="failed"?"\u2717":"\u2298",n=e.agentType??e.subagentId,r=[t,n];return e.durationMs!==void 0&&r.push(`\xB7 ${te(e.durationMs)}`),m.dim(` ${r.join(" ")}`)}import{EventEmitter as eA}from"node:events";var tA=300*1e3,mf=5e3,nA=10,Xr=class extends Error{constructor(t,n){super(`Background job cap reached (${t}/${n} running). Wait for existing jobs to finish or cancel them before spawning more.`),this.name="BackgroundJobCapError"}},Os=class extends eA{jobs=new Map;counter=0;traceWriter;maxConcurrentJobs;constructor(t={}){super(),this.traceWriter=t.traceWriter,this.maxConcurrentJobs=t.maxConcurrentJobs??nA}register(t){let n=[...this.jobs.values()].filter(c=>c.status==="running").length;if(n>=this.maxConcurrentJobs)throw new Xr(n,this.maxConcurrentJobs);let r=this.nextJobId(),o=t.prompt.trim().slice(0,80),s=Date.now(),i,a=new Promise(c=>{i=c}),l={jobId:r,subagentId:t.handle.id,label:o,model:t.model,startedAt:s,status:"running",handle:t.handle,joiners:[],terminalSettled:a,settle:i};return this.jobs.set(r,l),Bn(this.traceWriter,{transition:"started",jobId:r,subagentId:t.handle.id,label:o,model:t.model}),this.emit("started",this.snapshot(l)),t.handle.runInBackground(t.prompt,c=>{this.markTerminal(r,c)}),this.snapshot(l)}get(t){let n=this.jobs.get(t);return n?this.snapshot(n):void 0}list(){return[...this.jobs.values()].map(t=>this.snapshot(t))}async join(t){let n=this.jobs.get(t);if(!n)throw new Error(`Background job not found: "${t}". Completed and cancelled jobs are evicted from the registry ~5 minutes after they settle. If the jobId looks correct, the job may have already been evicted.`);let r=await n.terminalSettled;return Bn(this.traceWriter,{transition:"joined",jobId:t,subagentId:n.subagentId,jobStatus:n.status}),this.emit("joined",this.snapshot(n)),r}async cancelJob(t){let n=this.jobs.get(t);return!n||n.status!=="running"?!1:(n.cancelSource="explicit",await n.handle.cancel(),!0)}async cancelAll(){let t=[...this.jobs.values()].filter(n=>n.status==="running");for(let n of t)n.cancelSource="cascade";await Promise.allSettled(t.map(n=>n.handle.cancel())),await Promise.allSettled(t.map(n=>{let r=new Promise(o=>setTimeout(()=>{console.warn(`[BackgroundAgentRegistry] cancelAll: job ${n.jobId} did not settle within ${mf}ms \u2014 continuing teardown`),o()},mf).unref());return Promise.race([n.terminalSettled,r])}))}nextJobId(){return this.counter+=1,`bg-${Date.now().toString(36)}-${this.counter}`}markTerminal(t,n){let r=this.jobs.get(t);if(!r||r.status!=="running")return;r.result=n,r.endedAt=Date.now();let o=r.endedAt-r.startedAt;if(r.status=this.statusFromResult(n.status),r.status==="completed"){let i=n.message?.content,a=typeof i=="string"?i:i!==void 0?JSON.stringify(i):"";Bn(this.traceWriter,{transition:"completed",jobId:t,subagentId:r.subagentId,durationMs:o,outputBytes:Buffer.byteLength(a,"utf8")}),this.emit("settled",this.snapshot(r))}else if(r.status==="failed"){let i=n.error;Bn(this.traceWriter,{transition:"failed",jobId:t,subagentId:r.subagentId,durationMs:o,errorClass:i?.name??"Error",errorMessage:i?.message??"unknown"}),this.emit("settled",this.snapshot(r))}else Bn(this.traceWriter,{transition:"cancelled",jobId:t,subagentId:r.subagentId,source:r.cancelSource??"explicit"}),this.emit("settled",this.snapshot(r));r.settle(n),setTimeout(()=>{this.jobs.delete(t)},tA).unref()}statusFromResult(t){return t==="succeeded"?"completed":t==="failed"?"failed":t==="cancelled"?"cancelled":"failed"}snapshot(t){return{jobId:t.jobId,subagentId:t.subagentId,label:t.label,model:t.model,startedAt:t.startedAt,status:t.status,...t.result!==void 0?{result:t.result}:{},...t.endedAt!==void 0?{endedAt:t.endedAt}:{}}}};var ff=new Set;function gf(e){ff.add(e)}function hf(e){return ff.has(e)}var Tl=new Set,xl=new Set;function yf(e){Tl.add(e)}function bf(e){Tl.delete(e)}function kf(e){xl.add(e)}function wf(e){xl.delete(e)}function Sf(e){for(let t of Tl)t(e)}function vf(e){for(let t of xl)t(e)}function rA(e){if(typeof e!="object"||e===null)return;let t=e.name;if(typeof t!="string")return;let n=t.trim();return n.length>0?n:void 0}function oA(e){if(typeof e!="object"||e===null)throw new Error("Skill tool input must be an object");let t=e,n=t.name;if(typeof n!="string"||n.trim().length===0)throw new Error('Skill tool input must have a non-empty "name" field');let r,o=t.arguments;if(o!==void 0){if(typeof o!="string")throw new Error('Skill tool "arguments" must be a string');r=o}return{name:n.trim(),arguments:r}}var Vt=class{constructor(t){this.ctx=t}ctx;pluginBodies=null;async execute(t){if(t.signal.aborted)return{content:"Skill tool call aborted",isError:!0};let n=this.ctx.depth??0,r=this.ctx.maxDepth??ir;if(n>=r){let l=rA(t.input);return Ge({event:"delegation.skipped",parent_session_id:this.ctx.parentSession.sessionId,reason:"max_depth",depth:n,requested_name:l}).catch(()=>{}),{content:`Skill tool not available at nesting depth ${n} (max ${r})`,isError:!0}}let o;try{o=oA(t.input)}catch(l){return{content:`Skill tool input validation failed: ${l instanceof Error?l.message:String(l)}`,isError:!0}}try{let l=we(o.name);return await this.executeRegistrySkill(l,o.arguments,t)}catch{}let s=this.getPluginSkillBody(o.name);if(s)return await this.executePluginSkill(o.name,s.body,s.pluginPath,o.arguments,t);let a=wn(this.ctx.pluginConfigs).map(l=>l.name).join(", ");return{content:`Skill "${o.name}" not found. Available skills: ${a||"(none)"}`,isError:!0}}async executeRegistrySkill(t,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};if(t.context==="fork")return this.executeForkedRegistrySkill(t,n,r);let o=hf(t.name);o&&vf(t.name);let s=Date.now(),i,a;try{a=await t.handler(n&&n.length>0?n:void 0,this.ctx.parentSession,{apiKey:this.ctx.apiKey,defaultModel:this.ctx.defaultModel,defaultSubagentModel:this.ctx.defaultSubagentModel,callId:r.id,dispatchSkill:this.createDispatchSkillCallback(r)})}catch(c){i=c}finally{if(o){let c=Date.now()-s;Sf({skillName:t.name,durationMs:c,...i!==void 0?{isError:!0}:{}})}}return i!==void 0?{content:`Skill execution error: ${i instanceof Error?i.message:String(i)}`,isError:!0}:{content:typeof a=="string"?a:a!=null?JSON.stringify(a):"Skill completed successfully."}}buildForkedChildConfig(t,n){let r=this.ctx.depth??0,o=this.ctx.maxDepth??ir,s={...t};if(!this.ctx.childProviderFactory||r>=o)return{childConfig:s,childManager:void 0};let i=new W({parentAbortSignal:n}),a=new Xt({subagentManager:i,parentSession:Qr(n),defaultConfig:{model:s.model,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{}},defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),l=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,n):void 0;return s.provider=this.ctx.childProviderFactory({childExecutor:a,childSkillExecutor:l}),{childConfig:s,childManager:i}}async executeForkedRegistrySkill(t,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};let o;try{if(o=de(t.name)["system.md"],!o)return{content:`Skill "${t.name}" has context: "fork" but no prompts/system.md found`,isError:!0}}catch(l){return{content:`Failed to load skill prompts: ${l instanceof Error?l.message:String(l)}`,isError:!0}}let s=new W({parentAbortSignal:r.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:et()}),{childConfig:i,childManager:a}=this.buildForkedChildConfig({model:t.model??this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:o},r.signal);try{let l=await s.forkSubagent({parent:this.ctx.parentSession,config:i,idPrefix:`skill-fork-${t.name}`,parentId:r.id,agentType:t.name}),c=n&&n.length>0?n:"Run the skill.",d=await l.runToResult(c);return d.status==="succeeded"&&d.message?{content:d.message.content}:{content:d.error?.message??"Forked skill failed with no output",isError:!0}}catch(l){return{content:`Forked skill execution error: ${l instanceof Error?l.message:String(l)}`,isError:!0}}finally{await a?.teardownAll(),await s.teardownAll()}}async executePluginSkill(t,n,r,o,s){if(s.signal.aborted)return{content:"Skill call aborted",isError:!0};let i=new W({parentAbortSignal:s.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:et()}),{childConfig:a,childManager:l}=this.buildForkedChildConfig({model:this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:n,env:{PLUGIN_ROOT:r}},s.signal);try{let c=await i.forkSubagent({parent:this.ctx.parentSession,config:a,idPrefix:`skill-${t}`,parentId:s.id,agentType:t}),d=o&&o.length>0?o:"Run the skill.",u=await c.runToResult(d);return u.status==="succeeded"&&u.message?{content:u.message.content}:{content:u.error?.message??"Plugin skill failed with no output",isError:!0}}catch(c){return{content:`Plugin skill execution error: ${c instanceof Error?c.message:String(c)}`,isError:!0}}finally{await l?.teardownAll(),await i.teardownAll()}}getPluginSkillBody(t){return this.pluginBodies||(this.pluginBodies=Ss(this.ctx.pluginConfigs)),this.pluginBodies.get(t)}createDispatchSkillCallback(t){return async(n,r)=>{let o={id:`${t.id}-dispatch-${n}`,name:"skill",input:{name:n,...r!==void 0?{arguments:r}:{}},signal:t.signal},s=await this.execute(o);if(s.isError)throw new Error(s.content);return s.content}}};var ir=3;function Qr(e){return{sessionId:void 0,getInputStreamRef:()=>({pushUserMessage:()=>{}}),abortSignal:e}}var sA=[...Tt,"agent","skill"];function Ds(){return({childExecutor:e,childSkillExecutor:t})=>new Ae({permissions:{allowedTools:sA},subagentExecutor:e,skillExecutor:t})}function Ls(e,t,n,r){let o=(s,i,a)=>new Vt({parentSession:Qr(a),defaultModel:e,apiKey:t,...r!==void 0?{baseUrl:r}:{},depth:s,maxDepth:i,childProviderFactory:n,childSkillExecutorFactory:o});return o}function Tf(e){return e.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"")}function iA(e){if(typeof e!="object"||e===null)throw new Error("Agent tool input must be an object");let t=e,n=t.prompt;if(typeof n!="string")throw new Error('Agent tool input must have a "prompt" field of type string');if(n.trim().length===0)throw new Error("Agent tool prompt cannot be empty");let r,o=t.model;if(o!==void 0){if(typeof o!="string")throw new Error("Agent tool model must be a string");r=o}let s=10,i=t.max_turns;if(i!==void 0){if(typeof i!="number")throw new Error("Agent tool max_turns must be a number");s=Math.max(1,Math.min(50,Math.floor(i)))}let a="agent-tool",l=t.id_prefix;if(l!==void 0){if(typeof l!="string")throw new Error("Agent tool id_prefix must be a string");a=l}let c="foreground",d=t.mode;if(d!==void 0){if(d!=="foreground"&&d!=="background")throw new Error(`Agent tool mode must be "foreground" or "background", got: ${JSON.stringify(d)}`);c=d}return{prompt:n,model:r,max_turns:s,id_prefix:a,mode:c}}function El(e){try{return Ge(e).catch(()=>{})}catch{return Promise.resolve()}}function Zr(e,t=240){return e.length<=t?e:e.slice(0,t)+"\u2026"}function Ef(e){if(e!=null){if(typeof e=="string")return e.length;try{return JSON.stringify(e).length}catch{return}}}var aA=4096,xf=1024;function lA(e){if(e==null)return;let t=Ef(e);return t!==void 0&&t>aA?{truncated:!0,chars:t}:e}function cA(e){let t={status:e.status,error:Zr(e.errorMessage,xf),subagent_id:e.subagentId};e.schemaErrorMessage&&(t.schemaError=Zr(e.schemaErrorMessage,xf));let n=lA(e.partialOutput);return n!==void 0&&(t.partialOutput=n),t}var Xt=class e{constructor(t){this.ctx=t}ctx;async execute(t){if(t.signal.aborted)return{content:"Agent tool call aborted",isError:!0};let n;try{n=iA(t.input)}catch(p){return{content:`Agent tool input validation failed: ${p instanceof Error?p.message:String(p)}`,isError:!0}}let r=this.ctx.depth??0,o=this.ctx.maxDepth??ir,s,i={model:n.model??this.ctx.defaultSubagentModel??"sonnet",apiKey:this.ctx.defaultConfig.apiKey,systemPrompt:this.ctx.defaultConfig.systemPrompt,baseUrl:this.ctx.defaultConfig.baseUrl,maxTurns:n.max_turns},a;if(this.ctx.childProviderFactory&&r<o){s=new W({parentAbortSignal:t.signal}),a=Qr(t.signal);let p=new e({subagentManager:s,parentSession:a,defaultConfig:this.ctx.defaultConfig,defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),f=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,t.signal):void 0;i.provider=this.ctx.childProviderFactory({childExecutor:p,childSkillExecutor:f})}let l;try{l=await this.ctx.subagentManager.forkSubagent({parent:this.ctx.parentSession,parentId:t.id,config:i,idPrefix:n.id_prefix,agentType:n.id_prefix&&n.id_prefix!=="agent-tool"?Tf(n.id_prefix).replace(/[\r\n]+/g," ").trim()||"agent":Tf(n.prompt).replace(/[\r\n]+/g," ").slice(0,40).trim()||"agent"}),a!==void 0&&(a.sessionId=l.id)}catch(p){return{content:`Failed to fork subagent: ${p instanceof Error?p.message:String(p)}`,isError:!0}}if(n.mode==="background"){let p=this.ctx.backgroundRegistry;if(!p)return await l.teardown().catch(h=>X("subagent-executor: handle teardown failed: "+(h instanceof Error?h.message:String(h)))),{content:'Background mode is not available in this session \u2014 no BackgroundAgentRegistry is wired. Re-issue the call with mode="foreground" or run inside `afk interactive`.',isError:!0};let f;try{f=p.register({handle:l,prompt:n.prompt,model:i.model??"sonnet"})}catch(h){if(h instanceof Xr)return await l.teardown().catch(k=>X("subagent-executor: handle teardown failed after cap error: "+(k instanceof Error?k.message:String(k)))),{content:h.message,isError:!0};throw h}let g={status:"running",jobId:f.jobId,subagentId:f.subagentId,label:f.label,message:`Background subagent started (jobId=${f.jobId}). It is running detached and its result will NOT auto-inject into this context. Retrieve it later via /bgsub:join ${f.jobId} or ask the user to join.`};return{content:JSON.stringify(g)}}let c=()=>{l.cancel()};t.signal.addEventListener("abort",c,{once:!0});let d=Date.now(),u=this.ctx.parentSession.sessionId;try{let p=await l.runToResult(n.prompt);if(p.status==="succeeded"&&p.message){let k=p.message.content,y=typeof k=="string"?k:JSON.stringify(k),w=p.trace;return El({event:"subagent.completed",subagent_id:l.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,content_chars:y.length,depth:r,tool_call_count:w?.toolCalls.length,thinking_present:w?.thinkingPresent,tool_names:w?.toolCalls.length?JSON.stringify([...new Set(w.toolCalls.map(v=>v.name))]):void 0}),{content:y}}let f=p.error?.message??"Subagent failed with no output",g=p.trace;El({event:"subagent.failed",subagent_id:l.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,error_message:Zr(f),schema_error:p.schemaError?Zr(p.schemaError.message):void 0,partial_output_chars:Ef(p.partialOutput),depth:r,tool_call_count:g?.toolCalls.length,thinking_present:g?.thinkingPresent,tool_names:g?.toolCalls.length?JSON.stringify([...new Set(g.toolCalls.map(k=>k.name))]):void 0});let h=cA({status:p.status,errorMessage:f,schemaErrorMessage:p.schemaError?.message,partialOutput:p.partialOutput,subagentId:l.id});return{content:JSON.stringify(h),isError:!0}}catch(p){let f=p instanceof Error?p.message:String(p);throw El({event:"subagent.failed",subagent_id:l.id,parent_session_id:u,status:"failed",duration_ms:Date.now()-d,error_message:Zr(f),depth:r}),p}finally{t.signal.removeEventListener("abort",c),await s?.teardownAll(),await l.teardown()}}};import{randomUUID as MA}from"node:crypto";import{createHash as CA}from"crypto";import{mkdir as PA,open as IA,writeFile as _A}from"fs/promises";import{join as Lf}from"path";import{z as b}from"zod";var uA=b.object({phase:b.literal("started"),toolUseId:b.string(),name:b.string(),inputBytes:b.number().int().nonnegative(),subagentId:b.string().optional()}),dA=b.object({phase:b.literal("completed"),toolUseId:b.string(),name:b.string(),resultBytes:b.number().int().nonnegative(),isError:b.boolean(),truncated:b.boolean(),durationMs:b.number().nonnegative(),subagentId:b.string().optional()}),Rf=b.discriminatedUnion("phase",[uA,dA]),pA=b.enum(["PreToolUse","PostToolUse","SessionStart","SessionEnd","SubagentStart","SubagentStop"]),Af=b.object({hookEvent:pA,decision:b.union([b.literal("block"),b.literal("approve"),b.undefined()]),reason:b.string().optional(),blockedTool:b.string().optional(),injectedContextBytes:b.number().int().nonnegative().optional()}),mA=b.object({transition:b.literal("started"),subagentId:b.string(),parentId:b.string(),model:b.string(),allowedTools:b.array(b.string()).readonly().optional(),systemPromptHash:b.string().optional()}),fA=b.object({transition:b.literal("succeeded"),subagentId:b.string(),durationMs:b.number().nonnegative(),turnCount:b.number().int().nonnegative(),totalCostUsd:b.number().nonnegative().optional(),outputBytes:b.number().int().nonnegative()}),gA=b.object({transition:b.literal("failed"),subagentId:b.string(),errorClass:b.string(),errorMessage:b.string(),partialOutputBytes:b.number().int().nonnegative()}),hA=b.object({transition:b.literal("cancelled"),subagentId:b.string(),source:b.enum(["cascade","explicit"])}),Cf=b.discriminatedUnion("transition",[mA,fA,gA,hA]),yA=b.object({transition:b.literal("started"),jobId:b.string(),subagentId:b.string(),label:b.string(),model:b.string()}),bA=b.object({transition:b.literal("completed"),jobId:b.string(),subagentId:b.string(),durationMs:b.number().nonnegative(),outputBytes:b.number().int().nonnegative()}),kA=b.object({transition:b.literal("failed"),jobId:b.string(),subagentId:b.string(),durationMs:b.number().nonnegative(),errorClass:b.string(),errorMessage:b.string()}),wA=b.object({transition:b.literal("cancelled"),jobId:b.string(),subagentId:b.string(),source:b.enum(["explicit","cascade"])}),SA=b.object({transition:b.literal("joined"),jobId:b.string(),subagentId:b.string(),jobStatus:b.enum(["completed","failed","cancelled"])}),Pf=b.discriminatedUnion("transition",[yA,bA,kA,wA,SA]),If=b.object({kind:b.literal("monetary"),runningCostUsd:b.number().nonnegative(),maxBudgetUsd:b.number().nonnegative(),lastTurnCostUsd:b.number().nonnegative()}),vA=b.enum(["user_signal","cascade","timeout","budget","hook_block"]),_f=b.object({origin:vA,cascadedTo:b.array(b.string()).readonly(),reason:b.string().optional()}),Mf=b.enum(["manual","token_threshold","turn_count"]),TA=b.object({path:b.string(),sizeBytes:b.number().int().nonnegative(),sha256:b.string().regex(/^[0-9a-f]{64}$/)}),xA=b.object({trigger:Mf,preCompactionMessages:b.array(b.unknown()),summary:b.string(),keptTailCount:b.number().int().nonnegative(),keepLastNConfig:b.number().int().nonnegative(),messagesBefore:b.number().int().nonnegative(),messagesAfter:b.number().int().nonnegative(),tokensSavedEstimate:b.number().nonnegative().optional(),summarizationTokens:b.object({input:b.number().int().nonnegative(),output:b.number().int().nonnegative()}).optional()}),EA=b.object({trigger:Mf,preCompactionMessagesRef:TA,summary:b.string(),keptTailCount:b.number().int().nonnegative(),keepLastNConfig:b.number().int().nonnegative(),messagesBefore:b.number().int().nonnegative(),messagesAfter:b.number().int().nonnegative(),tokensSavedEstimate:b.number().nonnegative().optional(),summarizationTokens:b.object({input:b.number().int().nonnegative(),output:b.number().int().nonnegative()}).optional()}),RA=b.enum(["model_end_turn","iteration_cap","abort","timeout","budget_exceeded","hook_blocked","max_turns_exceeded"]),$f=b.object({reason:RA,finalTurnCount:b.number().int().nonnegative(),finalCostUsd:b.number().nonnegative(),finalTokens:b.object({input:b.number().int().nonnegative().optional(),output:b.number().int().nonnegative().optional(),cacheRead:b.number().int().nonnegative().optional(),cacheCreation:b.number().int().nonnegative().optional()}),lastStopReason:b.string().optional()}),Of=b.object({source:b.string(),assertion:b.string(),evidence:b.array(b.string()).readonly(),confidence:b.number().min(0).max(1),dissent:b.string().optional()}),AA=b.object({status:b.enum(["succeeded","failed","cancelled"]),finalCostUsd:b.number().nonnegative(),finalTurnCount:b.number().int().nonnegative(),closedAt:b.string().datetime()}),Df=b.discriminatedUnion("kind",[b.object({kind:b.literal("tool_call"),payload:Rf}),b.object({kind:b.literal("hook_decision"),payload:Af}),b.object({kind:b.literal("subagent_lifecycle"),payload:Cf}),b.object({kind:b.literal("background_agent"),payload:Pf}),b.object({kind:b.literal("budget"),payload:If}),b.object({kind:b.literal("abort"),payload:_f}),b.object({kind:b.literal("compaction"),payload:xA}),b.object({kind:b.literal("closure"),payload:$f}),b.object({kind:b.literal("claim"),payload:Of})]),zK=b.discriminatedUnion("kind",[b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("tool_call"),payload:Rf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("hook_decision"),payload:Af}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("subagent_lifecycle"),payload:Cf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("background_agent"),payload:Pf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("budget"),payload:If}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("abort"),payload:_f}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("compaction"),payload:EA}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("closure"),payload:$f}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("claim"),payload:Of}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("session_sealed"),payload:AA})]);var Fs=class{traceDir;tracePath;seq=0;sealed=!1;fh=null;writeQueue=Promise.resolve();constructor(t){this.traceDir=t.traceDir,this.tracePath=Lf(this.traceDir,"trace.jsonl")}getTracePath(){return this.tracePath}async write(t){if(this.sealed)throw new Error("NdjsonTraceWriter: trace is sealed; write() rejected");return Df.parse(t),this.enqueue(async()=>{await this.ensureOpen();let n=await this.materializePersistedEvent(t);await this.appendLine(n)})}async seal(t){this.sealed||(this.sealed=!0,await this.enqueue(async()=>{await this.ensureOpen();let n={ts:new Date().toISOString(),seq:this.seq++,kind:"session_sealed",payload:t};await this.appendLine(n),this.fh&&await this.fh.sync()}),await this.closeHandle())}async close(){await this.enqueue(async()=>{}),await this.closeHandle()}enqueue(t){let n=this.writeQueue.then(t,t);return this.writeQueue=n.then(()=>{},()=>{}),n}async ensureOpen(){this.fh||(await PA(this.traceDir,{recursive:!0}),this.fh=await IA(this.tracePath,"a"))}async closeHandle(){if(!this.fh)return;let t=this.fh;this.fh=null,await t.close()}async appendLine(t){if(!this.fh)throw new Error("NdjsonTraceWriter: file handle missing");await this.fh.appendFile(`${JSON.stringify(t)}
1829
+ ${XR}`}import Yt from"chalk";var QR={read:Yt.hex("#C9B584"),write:Yt.hex("#E8A33D"),shell:Yt.hex("#A8E060"),subagent:m.plan,skill:Yt.hex("#F08AC4"),dag:Yt.hex("#4EC9B0"),mcp:Yt.hex("#5FE0C0"),web:Yt.hex("#A0C4C0"),planning:m.meta,schedule:Yt.hex("#D4A84B"),other:m.meta},ZR={read:"\u25CF",write:"\u270E",shell:"$",subagent:"\u2192",skill:"\u25C6",dag:"\u2B21",mcp:"\u22A1",web:"\u2316",planning:"\u25B1",schedule:"\u23F2",other:"\u25CF"};function vl(e){return{color:QR[e],glyph:ZR[e]}}function sr(e){return vl(Sn(e))}function pf(e){let{description:t,summary:n,lastToolName:r,totalTokens:o,toolUses:s,durationMs:i}=e,a=[];if(r){let{color:c,glyph:d}=sr(r);a.push(`via ${c(`${d} ${r}`)}`)}s&&a.push(`${s} tool${s===1?"":"s"}`),o&&a.push(`${q(o)} tok`),i&&a.push(te(i));let l=a.length>0?` (${a.join(" \xB7 ")})`:"";return n?[m.dim(` \u25E6 ${t}`),m.dim(` ${n}${l}`)]:[m.dim(` \u25E6 ${t}${l}`)]}function $s(e){let t=e.status==="succeeded"?"\u2713":e.status==="failed"?"\u2717":"\u2298",n=e.agentType??e.subagentId,r=[t,n];return e.durationMs!==void 0&&r.push(`\xB7 ${te(e.durationMs)}`),m.dim(` ${r.join(" ")}`)}import{EventEmitter as eA}from"node:events";var tA=300*1e3,mf=5e3,nA=10,Xr=class extends Error{constructor(t,n){super(`Background job cap reached (${t}/${n} running). Wait for existing jobs to finish or cancel them before spawning more.`),this.name="BackgroundJobCapError"}},Os=class extends eA{jobs=new Map;counter=0;traceWriter;maxConcurrentJobs;constructor(t={}){super(),this.traceWriter=t.traceWriter,this.maxConcurrentJobs=t.maxConcurrentJobs??nA}register(t){let n=[...this.jobs.values()].filter(c=>c.status==="running").length;if(n>=this.maxConcurrentJobs)throw new Xr(n,this.maxConcurrentJobs);let r=this.nextJobId(),o=t.prompt.trim().slice(0,80),s=Date.now(),i,a=new Promise(c=>{i=c}),l={jobId:r,subagentId:t.handle.id,label:o,model:t.model,startedAt:s,status:"running",handle:t.handle,joiners:[],terminalSettled:a,settle:i};return this.jobs.set(r,l),Bn(this.traceWriter,{transition:"started",jobId:r,subagentId:t.handle.id,label:o,model:t.model}),this.emit("started",this.snapshot(l)),t.handle.runInBackground(t.prompt,c=>{this.markTerminal(r,c)}),this.snapshot(l)}get(t){let n=this.jobs.get(t);return n?this.snapshot(n):void 0}list(){return[...this.jobs.values()].map(t=>this.snapshot(t))}async join(t){let n=this.jobs.get(t);if(!n)throw new Error(`Background job not found: "${t}". Completed and cancelled jobs are evicted from the registry ~5 minutes after they settle. If the jobId looks correct, the job may have already been evicted.`);let r=await n.terminalSettled;return Bn(this.traceWriter,{transition:"joined",jobId:t,subagentId:n.subagentId,jobStatus:n.status}),this.emit("joined",this.snapshot(n)),r}async cancelJob(t){let n=this.jobs.get(t);return!n||n.status!=="running"?!1:(n.cancelSource="explicit",await n.handle.cancel(),!0)}async cancelAll(){let t=[...this.jobs.values()].filter(n=>n.status==="running");for(let n of t)n.cancelSource="cascade";await Promise.allSettled(t.map(n=>n.handle.cancel())),await Promise.allSettled(t.map(n=>{let r=new Promise(o=>setTimeout(()=>{console.warn(`[BackgroundAgentRegistry] cancelAll: job ${n.jobId} did not settle within ${mf}ms \u2014 continuing teardown`),o()},mf).unref());return Promise.race([n.terminalSettled,r])}))}nextJobId(){return this.counter+=1,`bg-${Date.now().toString(36)}-${this.counter}`}markTerminal(t,n){let r=this.jobs.get(t);if(!r||r.status!=="running")return;r.result=n,r.endedAt=Date.now();let o=r.endedAt-r.startedAt;if(r.status=this.statusFromResult(n.status),r.status==="completed"){let i=n.message?.content,a=typeof i=="string"?i:i!==void 0?JSON.stringify(i):"";Bn(this.traceWriter,{transition:"completed",jobId:t,subagentId:r.subagentId,durationMs:o,outputBytes:Buffer.byteLength(a,"utf8")}),this.emit("settled",this.snapshot(r))}else if(r.status==="failed"){let i=n.error;Bn(this.traceWriter,{transition:"failed",jobId:t,subagentId:r.subagentId,durationMs:o,errorClass:i?.name??"Error",errorMessage:i?.message??"unknown"}),this.emit("settled",this.snapshot(r))}else Bn(this.traceWriter,{transition:"cancelled",jobId:t,subagentId:r.subagentId,source:r.cancelSource??"explicit"}),this.emit("settled",this.snapshot(r));r.settle(n),setTimeout(()=>{this.jobs.delete(t)},tA).unref()}statusFromResult(t){return t==="succeeded"?"completed":t==="failed"?"failed":t==="cancelled"?"cancelled":"failed"}snapshot(t){return{jobId:t.jobId,subagentId:t.subagentId,label:t.label,model:t.model,startedAt:t.startedAt,status:t.status,...t.result!==void 0?{result:t.result}:{},...t.endedAt!==void 0?{endedAt:t.endedAt}:{}}}};var ff=new Set;function gf(e){ff.add(e)}function hf(e){return ff.has(e)}var Tl=new Set,xl=new Set;function yf(e){Tl.add(e)}function bf(e){Tl.delete(e)}function kf(e){xl.add(e)}function wf(e){xl.delete(e)}function Sf(e){for(let t of Tl)t(e)}function vf(e){for(let t of xl)t(e)}function rA(e){if(typeof e!="object"||e===null)return;let t=e.name;if(typeof t!="string")return;let n=t.trim();return n.length>0?n:void 0}function oA(e){if(typeof e!="object"||e===null)throw new Error("Skill tool input must be an object");let t=e,n=t.name;if(typeof n!="string"||n.trim().length===0)throw new Error('Skill tool input must have a non-empty "name" field');let r,o=t.arguments;if(o!==void 0){if(typeof o!="string")throw new Error('Skill tool "arguments" must be a string');r=o}return{name:n.trim(),arguments:r}}var Vt=class{constructor(t){this.ctx=t}ctx;pluginBodies=null;async execute(t){if(t.signal.aborted)return{content:"Skill tool call aborted",isError:!0};let n=this.ctx.depth??0,r=this.ctx.maxDepth??ir;if(n>=r){let l=rA(t.input);return Ge({event:"delegation.skipped",parent_session_id:this.ctx.parentSession.sessionId,reason:"max_depth",depth:n,requested_name:l}).catch(()=>{}),{content:`Skill tool not available at nesting depth ${n} (max ${r})`,isError:!0}}let o;try{o=oA(t.input)}catch(l){return{content:`Skill tool input validation failed: ${l instanceof Error?l.message:String(l)}`,isError:!0}}try{let l=we(o.name);return await this.executeRegistrySkill(l,o.arguments,t)}catch{}let s=this.getPluginSkillBody(o.name);if(s)return await this.executePluginSkill(o.name,s.body,s.pluginPath,o.arguments,t);let a=wn(this.ctx.pluginConfigs).map(l=>l.name).join(", ");return{content:`Skill "${o.name}" not found. Available skills: ${a||"(none)"}`,isError:!0}}async executeRegistrySkill(t,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};if(t.context==="fork")return this.executeForkedRegistrySkill(t,n,r);let o=hf(t.name);o&&vf(t.name);let s=Date.now(),i,a;try{a=await t.handler(n&&n.length>0?n:void 0,this.ctx.parentSession,{apiKey:this.ctx.apiKey,defaultModel:this.ctx.defaultModel,defaultSubagentModel:this.ctx.defaultSubagentModel,callId:r.id,dispatchSkill:this.createDispatchSkillCallback(r)})}catch(c){i=c}finally{if(o){let c=Date.now()-s;Sf({skillName:t.name,durationMs:c,...i!==void 0?{isError:!0}:{}})}}return i!==void 0?{content:`Skill execution error: ${i instanceof Error?i.message:String(i)}`,isError:!0}:{content:typeof a=="string"?a:a!=null?JSON.stringify(a):"Skill completed successfully."}}buildForkedChildConfig(t,n){let r=this.ctx.depth??0,o=this.ctx.maxDepth??ir,s={...t};if(!this.ctx.childProviderFactory||r>=o)return{childConfig:s,childManager:void 0};let i=new W({parentAbortSignal:n}),a=new Xt({subagentManager:i,parentSession:Qr(n),defaultConfig:{model:s.model,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{}},defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),l=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,n):void 0;return s.provider=this.ctx.childProviderFactory({childExecutor:a,childSkillExecutor:l}),{childConfig:s,childManager:i}}async executeForkedRegistrySkill(t,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};let o;try{if(o=de(t.name)["system.md"],!o)return{content:`Skill "${t.name}" has context: "fork" but no prompts/system.md found`,isError:!0}}catch(l){return{content:`Failed to load skill prompts: ${l instanceof Error?l.message:String(l)}`,isError:!0}}let s=new W({parentAbortSignal:r.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:et()}),{childConfig:i,childManager:a}=this.buildForkedChildConfig({model:t.model??this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:o},r.signal);try{let l=await s.forkSubagent({parent:this.ctx.parentSession,config:i,idPrefix:`skill-fork-${t.name}`,parentId:r.id,agentType:t.name}),c=n&&n.length>0?n:"Run the skill.",d=await l.runToResult(c);return d.status==="succeeded"&&d.message?{content:d.message.content}:{content:d.error?.message??"Forked skill failed with no output",isError:!0}}catch(l){return{content:`Forked skill execution error: ${l instanceof Error?l.message:String(l)}`,isError:!0}}finally{await a?.teardownAll(),await s.teardownAll()}}async executePluginSkill(t,n,r,o,s){if(s.signal.aborted)return{content:"Skill call aborted",isError:!0};let i=new W({parentAbortSignal:s.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:et()}),{childConfig:a,childManager:l}=this.buildForkedChildConfig({model:this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:n,env:{PLUGIN_ROOT:r}},s.signal);try{let c=await i.forkSubagent({parent:this.ctx.parentSession,config:a,idPrefix:`skill-${t}`,parentId:s.id,agentType:t}),d=o&&o.length>0?o:"Run the skill.",u=await c.runToResult(d);return u.status==="succeeded"&&u.message?{content:u.message.content}:{content:u.error?.message??"Plugin skill failed with no output",isError:!0}}catch(c){return{content:`Plugin skill execution error: ${c instanceof Error?c.message:String(c)}`,isError:!0}}finally{await l?.teardownAll(),await i.teardownAll()}}getPluginSkillBody(t){return this.pluginBodies||(this.pluginBodies=Ss(this.ctx.pluginConfigs)),this.pluginBodies.get(t)}createDispatchSkillCallback(t){return async(n,r)=>{let o={id:`${t.id}-dispatch-${n}`,name:"skill",input:{name:n,...r!==void 0?{arguments:r}:{}},signal:t.signal},s=await this.execute(o);if(s.isError)throw new Error(s.content);return s.content}}};var ir=3;function Qr(e){return{sessionId:void 0,getInputStreamRef:()=>({pushUserMessage:()=>{}}),abortSignal:e}}var sA=[...Tt,"agent","skill"];function Ds(){return({childExecutor:e,childSkillExecutor:t})=>new Ae({permissions:{allowedTools:sA},subagentExecutor:e,skillExecutor:t})}function Ls(e,t,n,r){let o=(s,i,a)=>new Vt({parentSession:Qr(a),defaultModel:e,apiKey:t,...r!==void 0?{baseUrl:r}:{},depth:s,maxDepth:i,childProviderFactory:n,childSkillExecutorFactory:o});return o}function Tf(e){return e.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"")}function iA(e){if(typeof e!="object"||e===null)throw new Error("Agent tool input must be an object");let t=e,n=t.prompt;if(typeof n!="string")throw new Error('Agent tool input must have a "prompt" field of type string');if(n.trim().length===0)throw new Error("Agent tool prompt cannot be empty");let r,o=t.model;if(o!==void 0){if(typeof o!="string")throw new Error("Agent tool model must be a string");r=o}let s=10,i=t.max_turns;if(i!==void 0){if(typeof i!="number")throw new Error("Agent tool max_turns must be a number");s=Math.max(1,Math.min(50,Math.floor(i)))}let a="agent-tool",l=t.id_prefix;if(l!==void 0){if(typeof l!="string")throw new Error("Agent tool id_prefix must be a string");a=l}let c="foreground",d=t.mode;if(d!==void 0){if(d!=="foreground"&&d!=="background")throw new Error(`Agent tool mode must be "foreground" or "background", got: ${JSON.stringify(d)}`);c=d}return{prompt:n,model:r,max_turns:s,id_prefix:a,mode:c}}function El(e){try{return Ge(e).catch(()=>{})}catch{return Promise.resolve()}}function Zr(e,t=240){return e.length<=t?e:e.slice(0,t)+"\u2026"}function Ef(e){if(e!=null){if(typeof e=="string")return e.length;try{return JSON.stringify(e).length}catch{return}}}var aA=4096,xf=1024;function lA(e){if(e==null)return;let t=Ef(e);return t!==void 0&&t>aA?{truncated:!0,chars:t}:e}function cA(e){let t={status:e.status,error:Zr(e.errorMessage,xf),subagent_id:e.subagentId};e.schemaErrorMessage&&(t.schemaError=Zr(e.schemaErrorMessage,xf));let n=lA(e.partialOutput);return n!==void 0&&(t.partialOutput=n),t}var Xt=class e{constructor(t){this.ctx=t}ctx;async execute(t){if(t.signal.aborted)return{content:"Agent tool call aborted",isError:!0};let n;try{n=iA(t.input)}catch(p){return{content:`Agent tool input validation failed: ${p instanceof Error?p.message:String(p)}`,isError:!0}}let r=this.ctx.depth??0,o=this.ctx.maxDepth??ir,s,i={model:n.model??this.ctx.defaultSubagentModel??"sonnet",apiKey:this.ctx.defaultConfig.apiKey,systemPrompt:this.ctx.defaultConfig.systemPrompt,baseUrl:this.ctx.defaultConfig.baseUrl,maxTurns:n.max_turns},a;if(this.ctx.childProviderFactory&&r<o){s=new W({parentAbortSignal:t.signal}),a=Qr(t.signal);let p=new e({subagentManager:s,parentSession:a,defaultConfig:this.ctx.defaultConfig,defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),f=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,t.signal):void 0;i.provider=this.ctx.childProviderFactory({childExecutor:p,childSkillExecutor:f})}let l;try{l=await this.ctx.subagentManager.forkSubagent({parent:this.ctx.parentSession,parentId:t.id,config:i,idPrefix:n.id_prefix,agentType:n.id_prefix&&n.id_prefix!=="agent-tool"?Tf(n.id_prefix).replace(/[\r\n]+/g," ").trim()||"agent":Tf(n.prompt).replace(/[\r\n]+/g," ").slice(0,40).trim()||"agent"}),a!==void 0&&(a.sessionId=l.id)}catch(p){return{content:`Failed to fork subagent: ${p instanceof Error?p.message:String(p)}`,isError:!0}}if(n.mode==="background"){let p=this.ctx.backgroundRegistry;if(!p)return await l.teardown().catch(h=>X("subagent-executor: handle teardown failed: "+(h instanceof Error?h.message:String(h)))),{content:'Background mode is not available in this session \u2014 no BackgroundAgentRegistry is wired. Re-issue the call with mode="foreground" or run inside `afk interactive`.',isError:!0};let f;try{f=p.register({handle:l,prompt:n.prompt,model:i.model??"sonnet"})}catch(h){if(h instanceof Xr)return await l.teardown().catch(k=>X("subagent-executor: handle teardown failed after cap error: "+(k instanceof Error?k.message:String(k)))),{content:h.message,isError:!0};throw h}let g={status:"running",jobId:f.jobId,subagentId:f.subagentId,label:f.label,message:`Background subagent started (jobId=${f.jobId}). It is running detached and its result will NOT auto-inject into this context. Retrieve it later via /bgsub:join ${f.jobId} or ask the user to join.`};return{content:JSON.stringify(g)}}let c=()=>{l.cancel()};t.signal.addEventListener("abort",c,{once:!0});let d=Date.now(),u=this.ctx.parentSession.sessionId;try{let p=await l.runToResult(n.prompt);if(p.status==="succeeded"&&p.message){let k=p.message.content,y=typeof k=="string"?k:JSON.stringify(k),w=p.trace;return El({event:"subagent.completed",subagent_id:l.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,content_chars:y.length,depth:r,tool_call_count:w?.toolCalls.length,thinking_present:w?.thinkingPresent,tool_names:w?.toolCalls.length?JSON.stringify([...new Set(w.toolCalls.map(v=>v.name))]):void 0}),{content:y}}let f=p.error?.message??"Subagent failed with no output",g=p.trace;El({event:"subagent.failed",subagent_id:l.id,id_prefix:n.id_prefix,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,error_message:Zr(f),schema_error:p.schemaError?Zr(p.schemaError.message):void 0,partial_output_chars:Ef(p.partialOutput),depth:r,tool_call_count:g?.toolCalls.length,thinking_present:g?.thinkingPresent,tool_names:g?.toolCalls.length?JSON.stringify([...new Set(g.toolCalls.map(k=>k.name))]):void 0});let h=cA({status:p.status,errorMessage:f,schemaErrorMessage:p.schemaError?.message,partialOutput:p.partialOutput,subagentId:l.id});return{content:JSON.stringify(h),isError:!0}}catch(p){let f=p instanceof Error?p.message:String(p);throw El({event:"subagent.failed",subagent_id:l.id,id_prefix:n.id_prefix,parent_session_id:u,status:"failed",duration_ms:Date.now()-d,error_message:Zr(f),depth:r}),p}finally{t.signal.removeEventListener("abort",c),await s?.teardownAll(),await l.teardown()}}};import{randomUUID as MA}from"node:crypto";import{createHash as CA}from"crypto";import{mkdir as PA,open as IA,writeFile as _A}from"fs/promises";import{join as Lf}from"path";import{z as b}from"zod";var uA=b.object({phase:b.literal("started"),toolUseId:b.string(),name:b.string(),inputBytes:b.number().int().nonnegative(),subagentId:b.string().optional()}),dA=b.object({phase:b.literal("completed"),toolUseId:b.string(),name:b.string(),resultBytes:b.number().int().nonnegative(),isError:b.boolean(),truncated:b.boolean(),durationMs:b.number().nonnegative(),subagentId:b.string().optional()}),Rf=b.discriminatedUnion("phase",[uA,dA]),pA=b.enum(["PreToolUse","PostToolUse","SessionStart","SessionEnd","SubagentStart","SubagentStop"]),Af=b.object({hookEvent:pA,decision:b.union([b.literal("block"),b.literal("approve"),b.undefined()]),reason:b.string().optional(),blockedTool:b.string().optional(),injectedContextBytes:b.number().int().nonnegative().optional()}),mA=b.object({transition:b.literal("started"),subagentId:b.string(),parentId:b.string(),model:b.string(),allowedTools:b.array(b.string()).readonly().optional(),systemPromptHash:b.string().optional()}),fA=b.object({transition:b.literal("succeeded"),subagentId:b.string(),durationMs:b.number().nonnegative(),turnCount:b.number().int().nonnegative(),totalCostUsd:b.number().nonnegative().optional(),outputBytes:b.number().int().nonnegative()}),gA=b.object({transition:b.literal("failed"),subagentId:b.string(),errorClass:b.string(),errorMessage:b.string(),partialOutputBytes:b.number().int().nonnegative()}),hA=b.object({transition:b.literal("cancelled"),subagentId:b.string(),source:b.enum(["cascade","explicit"])}),Cf=b.discriminatedUnion("transition",[mA,fA,gA,hA]),yA=b.object({transition:b.literal("started"),jobId:b.string(),subagentId:b.string(),label:b.string(),model:b.string()}),bA=b.object({transition:b.literal("completed"),jobId:b.string(),subagentId:b.string(),durationMs:b.number().nonnegative(),outputBytes:b.number().int().nonnegative()}),kA=b.object({transition:b.literal("failed"),jobId:b.string(),subagentId:b.string(),durationMs:b.number().nonnegative(),errorClass:b.string(),errorMessage:b.string()}),wA=b.object({transition:b.literal("cancelled"),jobId:b.string(),subagentId:b.string(),source:b.enum(["explicit","cascade"])}),SA=b.object({transition:b.literal("joined"),jobId:b.string(),subagentId:b.string(),jobStatus:b.enum(["completed","failed","cancelled"])}),Pf=b.discriminatedUnion("transition",[yA,bA,kA,wA,SA]),If=b.object({kind:b.literal("monetary"),runningCostUsd:b.number().nonnegative(),maxBudgetUsd:b.number().nonnegative(),lastTurnCostUsd:b.number().nonnegative()}),vA=b.enum(["user_signal","cascade","timeout","budget","hook_block"]),_f=b.object({origin:vA,cascadedTo:b.array(b.string()).readonly(),reason:b.string().optional()}),Mf=b.enum(["manual","token_threshold","turn_count"]),TA=b.object({path:b.string(),sizeBytes:b.number().int().nonnegative(),sha256:b.string().regex(/^[0-9a-f]{64}$/)}),xA=b.object({trigger:Mf,preCompactionMessages:b.array(b.unknown()),summary:b.string(),keptTailCount:b.number().int().nonnegative(),keepLastNConfig:b.number().int().nonnegative(),messagesBefore:b.number().int().nonnegative(),messagesAfter:b.number().int().nonnegative(),tokensSavedEstimate:b.number().nonnegative().optional(),summarizationTokens:b.object({input:b.number().int().nonnegative(),output:b.number().int().nonnegative()}).optional()}),EA=b.object({trigger:Mf,preCompactionMessagesRef:TA,summary:b.string(),keptTailCount:b.number().int().nonnegative(),keepLastNConfig:b.number().int().nonnegative(),messagesBefore:b.number().int().nonnegative(),messagesAfter:b.number().int().nonnegative(),tokensSavedEstimate:b.number().nonnegative().optional(),summarizationTokens:b.object({input:b.number().int().nonnegative(),output:b.number().int().nonnegative()}).optional()}),RA=b.enum(["model_end_turn","iteration_cap","abort","timeout","budget_exceeded","hook_blocked","max_turns_exceeded"]),$f=b.object({reason:RA,finalTurnCount:b.number().int().nonnegative(),finalCostUsd:b.number().nonnegative(),finalTokens:b.object({input:b.number().int().nonnegative().optional(),output:b.number().int().nonnegative().optional(),cacheRead:b.number().int().nonnegative().optional(),cacheCreation:b.number().int().nonnegative().optional()}),lastStopReason:b.string().optional()}),Of=b.object({source:b.string(),assertion:b.string(),evidence:b.array(b.string()).readonly(),confidence:b.number().min(0).max(1),dissent:b.string().optional()}),AA=b.object({status:b.enum(["succeeded","failed","cancelled"]),finalCostUsd:b.number().nonnegative(),finalTurnCount:b.number().int().nonnegative(),closedAt:b.string().datetime()}),Df=b.discriminatedUnion("kind",[b.object({kind:b.literal("tool_call"),payload:Rf}),b.object({kind:b.literal("hook_decision"),payload:Af}),b.object({kind:b.literal("subagent_lifecycle"),payload:Cf}),b.object({kind:b.literal("background_agent"),payload:Pf}),b.object({kind:b.literal("budget"),payload:If}),b.object({kind:b.literal("abort"),payload:_f}),b.object({kind:b.literal("compaction"),payload:xA}),b.object({kind:b.literal("closure"),payload:$f}),b.object({kind:b.literal("claim"),payload:Of})]),zK=b.discriminatedUnion("kind",[b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("tool_call"),payload:Rf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("hook_decision"),payload:Af}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("subagent_lifecycle"),payload:Cf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("background_agent"),payload:Pf}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("budget"),payload:If}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("abort"),payload:_f}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("compaction"),payload:EA}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("closure"),payload:$f}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("claim"),payload:Of}),b.object({ts:b.string().datetime(),seq:b.number().int().nonnegative(),kind:b.literal("session_sealed"),payload:AA})]);var Fs=class{traceDir;tracePath;seq=0;sealed=!1;fh=null;writeQueue=Promise.resolve();constructor(t){this.traceDir=t.traceDir,this.tracePath=Lf(this.traceDir,"trace.jsonl")}getTracePath(){return this.tracePath}async write(t){if(this.sealed)throw new Error("NdjsonTraceWriter: trace is sealed; write() rejected");return Df.parse(t),this.enqueue(async()=>{await this.ensureOpen();let n=await this.materializePersistedEvent(t);await this.appendLine(n)})}async seal(t){this.sealed||(this.sealed=!0,await this.enqueue(async()=>{await this.ensureOpen();let n={ts:new Date().toISOString(),seq:this.seq++,kind:"session_sealed",payload:t};await this.appendLine(n),this.fh&&await this.fh.sync()}),await this.closeHandle())}async close(){await this.enqueue(async()=>{}),await this.closeHandle()}enqueue(t){let n=this.writeQueue.then(t,t);return this.writeQueue=n.then(()=>{},()=>{}),n}async ensureOpen(){this.fh||(await PA(this.traceDir,{recursive:!0}),this.fh=await IA(this.tracePath,"a"))}async closeHandle(){if(!this.fh)return;let t=this.fh;this.fh=null,await t.close()}async appendLine(t){if(!this.fh)throw new Error("NdjsonTraceWriter: file handle missing");await this.fh.appendFile(`${JSON.stringify(t)}
1830
1830
  `)}async materializePersistedEvent(t){let n=new Date().toISOString(),r=this.seq++;if(t.kind==="compaction"){let o=await this.persistCompactionSidecar(t.payload,r,n);return{ts:n,seq:r,kind:"compaction",payload:o}}return{ts:n,seq:r,kind:t.kind,payload:t.payload}}async persistCompactionSidecar(t,n,r){let o=r.replace(/[:.]/g,"-"),s=Lf(this.traceDir,`${String(n).padStart(6,"0")}-${o}-pre-compaction.json`),i=JSON.stringify(t.preCompactionMessages),a=Buffer.byteLength(i,"utf8"),l=CA("sha256").update(i).digest("hex");await _A(s,i,{encoding:"utf8",flag:"w"});let c={path:s,sizeBytes:a,sha256:l};return{trigger:t.trigger,preCompactionMessagesRef:c,summary:t.summary,keptTailCount:t.keptTailCount,keepLastNConfig:t.keepLastNConfig,messagesBefore:t.messagesBefore,messagesAfter:t.messagesAfter,...t.tokensSavedEstimate!==void 0?{tokensSavedEstimate:t.tokensSavedEstimate}:{},...t.summarizationTokens!==void 0?{summarizationTokens:t.summarizationTokens}:{}}}};function Ns(e={}){if(process.env.AFK_TRACE_DISABLED==="1")return null;let t=e.sessionLabel??MA(),n=fu(t),r=new Fs({traceDir:n});return{writer:r,tracePath:r.getTracePath(),sessionLabel:t}}function jf(e){e.command("chat").description("Send a message to the agent").argument("<message>","Message to send").option("-m, --model <model>","Model to use. Short aliases: opus|opus_1m|sonnet|sonnet_1m|haiku. Any other value (e.g. `auto` for cursor-api-proxy, or a full `claude-*` ID) passes through to the SDK/proxy untouched.",Re()).option("-s, --stream","[no-op] reserved; chat currently waits for the full response",!1).option("-f, --format <format>","Output format (text|json)","text").option("--max-turns <number>","Maximum conversation turns","10").option("--thinking <mode>","Thinking mode: 'adaptive' | 'disabled' | 'enabled:<N>'","enabled:max").option("--effort <level>","Effort level: low|medium|high|xhigh|max").option("--max-budget-usd <usd>","Hard session cost ceiling in USD. Env: AFK_MAX_BUDGET_USD").option("--task-budget <tokens>","Soft per-task token budget. Env: AFK_TASK_BUDGET").option("--max-output-tokens <n|max>","Per-response output cap ('max' = model ceiling). Env: AFK_MAX_OUTPUT_TOKENS").option("--provider <name>","Provider to use: anthropic|anthropic-direct|openai|openai-compatible. Default: auto-selected by model").option("--dump-prompt [path]",'Dump resolved SDK prompt+options+provenance to file (default: ~/.afk/logs/prompt-dump-<ISO>.json) or "stderr"').option("-w, --worktree [branch]","Create a git worktree for an isolated one-shot. Optional value sets the branch name; otherwise auto-named. On clean exit (no uncommitted changes) the worktree and branch are auto-removed; on dirty exit the worktree is preserved. Mirrors `afk interactive -w`.").action(async(t,n)=>{let r=$A("Initializing agent...").start(),o=null,s,i,a;try{if(n.worktree!==void 0)try{i=await bs(n.worktree),a=i.path,r.text=`Worktree ready at ${i.path} (branch: ${i.branch})`}catch(M){r.fail("Failed to create worktree"),U(M)}let l,c,d,u,p,f;try{l=qt(n.thinking)??Yn(),c=zt(n.effort)??Vn(),d=Xn(n.maxBudgetUsd)??tl(),u=Xn(n.taskBudget)??nl(),p=Qn(n.maxOutputTokens)??Jr(),f=void 0}catch(M){r.fail("Invalid options"),U(M)}if(n.dumpPrompt!==void 0){let M=n.dumpPrompt===!0?Uf.join(Nf.homedir(),".afk","logs",`prompt-dump-${new Date().toISOString().replace(/[:.]/g,"-")}.json`):String(n.dumpPrompt);process.env.AFK_DUMP_PROMPT=M,n.provider!==void 0&&n.provider!=="anthropic"&&n.provider!=="anthropic-direct"&&console.error(`[--dump-prompt] WARNING: active provider (${n.provider}) does not support prompt dumping. No file will be written.`)}let g=Z(),h=Jn()??zn(),k=Me(),y=k.systemPromptSource,w=k.autoRouting?.chat??!1,v=Ms(h,w),A,T=new W({apiKey:g,...k.baseUrl!==void 0?{baseUrl:k.baseUrl}:{},...a!==void 0?{cwd:a}:{}}),_=Ds(),S={get sessionId(){return A?.sessionId},getInputStreamRef(){return A?.getInputStreamRef?.()??{pushUserMessage:()=>{}}},get abortSignal(){return A?.abortSignal??new AbortController().signal}},R=Ls(n.model,g,_,k.baseUrl),E=new Xt({subagentManager:T,parentSession:S,defaultConfig:{apiKey:g,systemPrompt:h,...k.baseUrl!==void 0?{baseUrl:k.baseUrl}:{}},defaultSubagentModel:Gt(),childProviderFactory:_,childSkillExecutorFactory:R}),x=new Vt({parentSession:S,defaultModel:n.model,defaultSubagentModel:Gt(),apiKey:g,childProviderFactory:_,childSkillExecutorFactory:R,...k.baseUrl!==void 0?{baseUrl:k.baseUrl}:{}}),$=new rr({parentSession:S,defaultModel:n.model,defaultSubagentModel:Gt(),apiKey:g,...k.baseUrl!==void 0?{baseUrl:k.baseUrl}:{},systemPrompt:h??""});s=new Ee,f=ws(n.provider,{subagentExecutor:E,skillExecutor:x,composeExecutor:$,memoryStore:s,model:String(n.model),...k.openaiBaseUrl!==void 0?{openaiBaseUrl:k.openaiBaseUrl}:{}})??new Ae({permissions:{allowedTools:[...Tt,...Ht,"agent","skill","compose"]},subagentExecutor:E,skillExecutor:x,composeExecutor:$,memoryStore:s,surface:"cli"});let P=Ns();o=new Le(kn({model:n.model,apiKey:g,maxTurns:parseInt(n.maxTurns,10),hookRegistry:or(M=>{console.log($s(M))},"cli",s).registry,...v!==void 0?{systemPrompt:v}:{},...y!==void 0?{systemPromptSource:y}:{},...l!==void 0?{thinking:l}:{},...c!==void 0?{effort:c}:{},...d!==void 0?{maxBudgetUsd:d}:{},...u!==void 0?{taskBudget:u}:{},...p!==void 0?{maxOutputTokens:p}:{},...k.baseUrl!==void 0?{baseUrl:k.baseUrl}:{},...P?{traceWriter:P.writer}:{},...k.autoResumeOnUsageLimit!==void 0?{autoResumeOnUsageLimit:k.autoResumeOnUsageLimit}:{},...a!==void 0?{cwd:a}:{},provider:f})),A=o,r.text="Sending message...";let O=await o.sendMessage(t,{stream:n.stream});if(r.succeed("Response received"),n.format==="json"){let M=o.getLastResponseMetadata(),L=M?Number(M.usage?.input_tokens??0):0,V=M?Number(M.usage?.output_tokens??0):0;console.log(JSON.stringify({success:!0,model:n.model,message:O.content,timestamp:O.timestamp,...M?.totalCostUsd!==void 0?{costUsd:M.totalCostUsd}:{},...M?.durationMs!==void 0?{durationMs:M.durationMs}:{},...L>0?{inputTokens:L}:{},...V>0?{outputTokens:V}:{}},null,2))}else{console.log(Ff.cyan(`
1831
1831
  \u{1F916} Claude:`)),console.log(lt(O.content));let M=o.getLastResponseMetadata();if(M){let L=[];M.durationMs&&L.push(te(M.durationMs)),M.totalCostUsd!==void 0&&L.push(Ce(M.totalCostUsd));let V=Number(M.usage?.input_tokens??0),F=Number(M.usage?.output_tokens??0);V+F>0&&L.push(q(V+F)+" tokens"),L.length>0&&console.log(Ff.dim(" \xB7 "+L.join(" \xB7 ")))}console.log("")}}catch(l){r.fail("Failed to send message"),U(l)}finally{o&&await o.close(),s?.close(),i!==void 0&&await i.cleanup()}})}import b0 from"ora";import*as Qy from"node:os";import*as $n from"node:path";import{execFileSync as k0}from"node:child_process";var Us=new Set;function ar(e){return Us.add(e),()=>{Us.delete(e)}}async function Rl(){await Promise.all([...Us].map(e=>e())),Us.clear()}import{readFileSync as OA,writeFileSync as DA,existsSync as Al,mkdirSync as LA,readdirSync as FA,statSync as NA}from"fs";import{join as Bf,basename as Wf}from"path";function Cl(){return ku(),_t()}function Pl(e){return Bf(Cl(),`${e}.json`)}function js(e,t){let n=Cl();Al(n)||LA(n,{recursive:!0});let r=t??e.sessionId??`session-${Date.now()}`,o={sessionId:e.sessionId,model:e.model,startedAt:e.sessionStartTime,savedAt:Date.now(),totalTurns:e.totalTurns,totalCostUsd:e.totalCostUsd,totalTokens:e.totalTokens,totalDurationMs:e.totalDurationMs,turns:e.turns},s=Pl(r);return DA(s,JSON.stringify(o,null,2)),s}function eo(e){let t=e.includes("/")?e:Pl(e);if(Al(t))try{let n=OA(t,"utf-8");return JSON.parse(n)}catch{return}}function Bs(e){let t=e.includes("/")?e:Pl(e),n=eo(t);if(n)return{path:t,id:Wf(t,".json"),data:n};for(let r of to()){if(r.id!==e&&r.sessionId!==e)continue;let o=eo(r.path);if(o)return{path:r.path,id:r.id,data:o}}}function to(){let e=Cl();if(!Al(e))return[];let t=[];for(let n of FA(e)){if(!n.endsWith(".json"))continue;let r=Bf(e,n);try{if(!NA(r).isFile())continue;let s=eo(r);if(!s||typeof s.savedAt!="number"||typeof s.model!="string")continue;t.push({path:r,id:Wf(n,".json"),sessionId:s.sessionId,model:s.model,startedAt:s.startedAt,savedAt:s.savedAt,totalTurns:s.totalTurns,totalCostUsd:s.totalCostUsd})}catch{}}return t.sort((n,r)=>r.savedAt-n.savedAt),t}var UA=/^[A-Za-z0-9_@%+=:,./-]+$/;function Hf(e){return UA.test(e)?e:`'${e.replace(/'/g,"'\\''")}'`}function lr(e,t){let n=["afk","interactive"];return typeof t=="string"&&t.length>0&&n.push("--model",Hf(t)),n.push("--resume",Hf(e)),n.join(" ")}import{homedir as jA}from"node:os";import{sep as dt}from"node:path";function Ws(e,t={}){if(!e)return"";let n=t.homedir??jA(),r=BA(e,n),o=t.maxWidth;if(o===void 0||o<=0||B(r)<=o)return r;let s=r.split(dt).filter(u=>u.length>0);if(s.length<=1)return ce(r,o);let a=r.startsWith("~")?"~":s[0],l=1,c=s[s.length-1],d=[];for(let u=s.length-2;u>=l;u--){let p=s.slice(l,u+1),f=p.length>0?p.join(dt)+dt:"";d.push(`${a}${dt}${f}\u2026${dt}${c}`)}d.push(`${a}${dt}\u2026${dt}${c}`);for(let u of d)if(B(u)<=o)return u;return ce(d[d.length-1],o)}function BA(e,t){if(!t)return e;if(e===t)return"~";let n=t.endsWith(dt)?t:t+dt;return e.startsWith(n)?"~"+dt+e.slice(n.length):e}import*as my from"node:readline";function Kf(e){let t=Math.max(0,Math.min(1,e.ratio)),n=t>.8?m.error:t>.5?m.warning:m.meta,r=20,o=Math.round(t*r),s=r-o,i="["+"\u2588".repeat(o)+"\u2591".repeat(s)+"]",a=Math.round(t*100)+"%",l="";e.used!==void 0&&e.limit!==void 0&&(l=q(e.used)+"/"+q(e.limit));let c=l?`${i} ${a} ${l}`:`${i} ${a}`,d=`${i} ${a}`,u=`ctx ${a}`,p=e.sparkline?m.meta(e.sparkline)+" ":"",f=e.sparkline?B(e.sparkline)+1:0,g=Math.max(0,e.width-f);if(B(c)<=g&&g>90)return p+n(c);if(B(d)<=g&&g>32)return p+n(d);if(B(u)<=g)return p+n(u);if(e.width>0){let h=p+n(u);return ce(h,e.width)}return n(a)}var Hs=class{stream;force;throttleMs;started=!1;lastRepaint=0;lastFields=null;resizeUnsub=null;lastPaintedRow=null;extraRows=0;constructor(t={}){this.stream=t.stream??process.stdout,this.force=t.force??!1,this.throttleMs=t.throttleMs??100}get enabled(){return this.force||!!this.stream.isTTY}start(){if(this.started||!this.enabled)return;this.started=!0,this.lastRepaint=0;let t=this.currentRows();this.stream.write("\x1B[s"),this.writeScrollRegion(t),this.stream.write("\x1B[u"),this.resizeUnsub===null&&(this.resizeUnsub=Dt.subscribe(()=>{this.onResize()}))}onResize(){if(!this.started||!this.enabled)return;let t=this.currentRows();this.stream.write("\x1B[s"),this.lastPaintedRow!==null&&this.lastPaintedRow!==this.paintRow(t)&&(this.stream.write(`\x1B[${this.lastPaintedRow};1H`),this.stream.write("\x1B[2K")),this.writeScrollRegion(t),this.stream.write("\x1B[u"),this.flush()}repaint(t){if(!this.enabled||!this.started){this.lastFields=t;return}let n=Date.now();if(n-this.lastRepaint<this.throttleMs){this.lastFields=t;return}this.lastRepaint=n,this.lastFields=t;let r=this.currentRows();this.stream.write("\x1B[s"),this.stream.write(`\x1B[${this.paintRow(r)};1H`),this.stream.write("\x1B[2K"),this.stream.write(this.formatLine(t)),this.stream.write("\x1B[u"),this.lastPaintedRow=this.paintRow(r)}flush(){this.lastRepaint=0,this.lastFields&&this.repaint(this.lastFields)}setExtraRows(t){if(this.extraRows=t,this.started&&this.enabled){let n=this.currentRows();this.stream.write("\x1B[s"),this.writeScrollRegion(n),this.stream.write("\x1B[u"),this.flush()}}getExtraRows(){return this.extraRows}rearm(){if(!this.started||!this.enabled)return;let t=this.currentRows();this.stream.write("\x1B[s"),this.writeScrollRegion(t),this.stream.write("\x1B[u"),this.flush()}stop(){if(this.resizeUnsub!==null&&(this.resizeUnsub(),this.resizeUnsub=null),!this.started||!this.enabled){this.started=!1;return}let t=this.currentRows();this.stream.write("\x1B[s"),this.stream.write(`\x1B[${this.lastPaintedRow??this.paintRow(t)};1H`),this.stream.write("\x1B[2K"),this.stream.write("\x1B[r"),this.stream.write("\x1B[u"),this.started=!1,this.lastRepaint=0,this.lastPaintedRow=null}formatLine(t){let n=[],r=Math.max(4,(this.stream.columns??80)-2);if(t.cwd){let s=Math.max(8,Math.floor(r*.4)),i=Ws(t.cwd,{maxWidth:s});i&&n.push(m.dim(i))}if(n.push(m.brand(t.model)),t.planMode&&n.push(m.warning("\u25CF plan")),t.contextPct!==void 0){let s=Kf({ratio:t.contextPct,used:t.contextUsedTokens,limit:t.contextLimit,sparkline:t.contextSparkline,width:r});n.push(s)}t.cost!==void 0&&n.push(m.meta(`$${t.cost.toFixed(2)}`)),t.tokens!==void 0&&n.push(m.meta(`${WA(t.tokens)} tok`));let o=n.join(m.dim(" \xB7 "));return ce(o,r)}currentRows(){let t=this.stream.rows;return typeof t=="number"&&t>0?t:24}paintRow(t){return t>1?t:1}writeScrollRegion(t){let n=1+this.extraRows;if(t>n){this.stream.write(`\x1B[1;${t-n}r`);return}this.stream.write("\x1B[r")}};function WA(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:`${e}`}var Ue=new Map,vn=new Map;function ie(e){if(Ue.has(e.name))throw new Error(`Slash command already registered: ${e.name}`);Ue.set(e.name,e);for(let t of e.aliases??[]){if(vn.has(t)||Ue.has(t))throw new Error(`Slash alias collides: ${t}`);vn.set(t,e.name)}}function Qt(e){if(Ue.has(e.name)){for(let[t,n]of vn.entries())n===e.name&&vn.delete(t);Ue.delete(e.name)}ie(e)}function Gf(e){Ue.has(e.name)||ie(e)}function qf(){Ue.clear(),vn.clear()}function nt(){return[...Ue.values()].sort((e,t)=>e.name.localeCompare(t.name))}function zf(){let e=[];for(let[t,n]of vn.entries()){let r=Ue.get(n);r&&e.push({alias:t,canonical:n,summary:r.summary})}return e.sort((t,n)=>t.alias.localeCompare(n.alias))}function HA(e){if(Ue.has(e))return Ue.get(e);let t=vn.get(e);return t?Ue.get(t):void 0}function KA(e,t){let n=Array.from({length:e.length+1},()=>new Array(t.length+1).fill(0));for(let r=0;r<=e.length;r++)n[r][0]=r;for(let r=0;r<=t.length;r++)n[0][r]=r;for(let r=1;r<=e.length;r++)for(let o=1;o<=t.length;o++){let s=e[r-1]===t[o-1]?0:1;n[r][o]=Math.min(n[r-1][o]+1,n[r][o-1]+1,n[r-1][o-1]+s)}return n[e.length][t.length]}function GA(e,t=3){let n;for(let r of Ue.keys()){let o=KA(e,r);o<=t&&(n===void 0||o<n.dist)&&(n={name:r,dist:o})}return n?.name}function Il(e){let t=e.trim();if(!t.startsWith("/"))return null;let n=t.indexOf(" ");return n===-1?{name:t,args:""}:{name:t.slice(0,n),args:t.slice(n+1).trim()}}async function Jf(e,t,n){let r=Il(e);if(r===null)return{handled:!1};let o=HA(r.name);if(!o){let a=GA(r.name);return a?t.out.warn(`Unknown command: ${r.name} (did you mean ${a}?)`):t.out.warn(`Unknown command: ${r.name} (type /help for commands)`),{handled:!0,result:"continue"}}let s=n??[];s.length>0&&o.acceptsAttachments!==!0&&t.out.warn(`\u26A0 Image attachments are ignored by ${r.name} (images only reach the model on skill commands like /forge, /mint).`);let i=await o.handler(t,r.args,o.acceptsAttachments===!0?s:void 0);return i==="forward"?{handled:!1}:{handled:!0,result:i}}import zA from"ora";function Yf(e){return{totalTurns:0,totalCostUsd:0,totalTokens:0,totalDurationMs:0,sessionStartTime:Date.now(),turnCosts:[],turnTokens:[],turns:[],model:e,planMode:!1}}function Vf(e){e.totalTurns=0,e.totalCostUsd=0,e.totalTokens=0,e.totalDurationMs=0,e.sessionStartTime=Date.now(),e.turnCosts.length=0,e.turnTokens.length=0,e.turns.length=0,delete e.sessionId,delete e.pendingPlanExit}function Ks(e,t,n,r,o){let s=r?.totalCostUsd??0,i=r?.durationMs??0,a=Number(r?.usage?.input_tokens??0),l=Number(r?.usage?.output_tokens??0),c=a,d=l,u=Number(r?.usage?.cache_read_input_tokens??0)+Number(r?.usage?.cache_creation_input_tokens??0),p=r?.usage?.iterations;if(Array.isArray(p)&&p.length>0){let g=p[p.length-1];if(g&&typeof g=="object"){let h=g;c=Number(h.input_tokens??0),d=Number(h.output_tokens??0),u=Number(h.cache_read_input_tokens??0)+Number(h.cache_creation_input_tokens??0)}}e.totalTurns+=1,e.totalCostUsd+=s,e.totalDurationMs+=i,e.totalTokens+=a+l,e.turnCosts.push(s),e.turnTokens.push({input:c,output:d,cache:u}),r?.sessionId&&!e.sessionId&&(e.sessionId=String(r.sessionId));let f={user:t,assistant:n,timestamp:Date.now(),costUsd:s,durationMs:i,inputTokens:a,outputTokens:l,...o&&o.length>0?{toolEvents:o}:{}};return e.turns.push(f),f}function Xf(e,t=5){if(e.length===0)return"";let n=e.slice(-t),r=["\u2581","\u2582","\u2583","\u2584","\u2585","\u2586","\u2587","\u2588"];return n.map(o=>{let s=Math.max(0,Math.min(1,o)),i=Math.min(7,Math.floor(s*8));return r[i]}).join("")}function Gs(e,t,n){e.totalTurns=t.totalTurns,e.totalCostUsd=t.totalCostUsd,e.totalTokens=t.totalTokens,e.totalDurationMs=t.totalDurationMs,e.turns=[...t.turns],e.sessionId=t.sessionId??n,e.model=t.model,e.sessionStartTime=t.startedAt??Date.now()}var qs={stream:process.stdout,hideCursor:!1,discardStdin:!1};function _l(e,t){if(t?.getRatio()!==void 0)return t.getRatio();let n=e.turnTokens[e.turnTokens.length-1];if(!n)return 0;let r=n.input+n.output+n.cache;return Math.min(1,r/Ve(e.model))}function no(e,t){let n=_l(e,t),r=Ve(e.model),o,s=t?.getDetail();if(s!==void 0)o=s.used;else{let a=e.turnTokens[e.turnTokens.length-1];a&&(o=a.input+a.output+a.cache)}let i;if(e.turnTokens.length>=2){let a=e.turnTokens.map(c=>(c.input+c.output+c.cache)/r),l=Xf(a,5);l.length>0&&(i=l)}return{model:e.model,cost:e.totalCostUsd,tokens:e.totalTokens,contextPct:n,contextLimit:r,contextUsedTokens:o,contextSparkline:i,planMode:e.planMode,...e.cwd!==void 0?{cwd:e.cwd}:{}}}var JA={name:"/exit",aliases:["/quit"],summary:"Exit the session",hint:"When you want to tear down the REPL \u2014 Ctrl+D on an empty prompt does the same.",async handler(){return"exit"}},YA={name:"/clear",summary:"Clear conversation history",hint:"When the current thread has drifted off-topic or you want a clean slate without restarting the session.",async handler(e){try{await e.session.current.reset(),e.ui.clearScreen(),Vf(e.stats),e.ledger?.clear(),e.out.success("Conversation history cleared.")}catch(t){e.out.error(t instanceof Error?t.message:"Unknown error")}return"continue"}},VA={name:"/compact",summary:"Compact history (summarize older messages)",hint:"When context is filling up but you want to keep the thread \u2014 summarizes old turns and keeps the recent ones intact.",async handler(e){let t=zA({text:m.meta("Summarizing earlier turns..."),...qs}).start();try{let n=await e.session.current.compact();if(t.stop(),n.compacted){let r=n.tokensSavedEstimate?` (~${n.tokensSavedEstimate} input tokens saved)`:"";e.out.success(`Compacted ${n.messagesBefore} \u2192 ${n.messagesAfter} messages${r}.`)}else{let r=n.reason??"unknown";r==="aborted"?e.out.info("Compaction cancelled."):r.startsWith("summarization-failed")?e.out.error(`Compaction failed: ${r}. History unchanged.`):r==="nothing-to-summarize"?e.out.info("Nothing to compact \u2014 all history is within the keep window."):e.out.info(`Nothing to compact (${r}).`)}}catch(n){t.stop(),e.out.error(n instanceof Error?n.message:"Unknown error")}return"continue"}},XA={name:"/help",summary:"Show this help",hint:"When you want the full command list with usage strings \u2014 broader than this inline dropdown.",async handler(e){let t=nt(),n=t.reduce((r,o)=>Math.max(r,o.name.length),0)+2;e.out.line(),e.out.line(m.bold(m.brand("Commands"))),e.out.line(fe());for(let r of t){let o=r.usage??r.name,s=" ".repeat(Math.max(0,n-o.length));e.out.line(` ${m.warning(o)}${s} ${m.dim(r.summary)}`)}return e.out.line(),e.out.line(m.dim(" Tip: Ctrl+C interrupts a running turn; a second press exits.")),e.out.line(),"continue"}},Qf=[JA,YA,VA,XA];function Ml(e,t=30){return!e||e.length===0?m.dim("(none)"):e.length<=t?e.join(", "):`${e.slice(0,t).join(", ")}, ${m.dim(`+${e.length-t} more`)}`}function Xe(e,t){return` ${m.label(e.padEnd(16))} ${t}`}function zs(e){let t=[];t.push(" "+fe("Session Debug")),e.sessionId&&t.push(Xe("session",e.sessionId)),e.model&&t.push(Xe("model",e.model)),e.permissionMode&&t.push(Xe("permission",e.permissionMode)),e.cwd&&t.push(Xe("cwd",e.cwd)),e.claudeCodeVersion&&t.push(Xe("sdk",`v${e.claudeCodeVersion}`)),e.apiKeySource&&t.push(Xe("api key",e.apiKeySource)),e.outputStyle&&t.push(Xe("output style",e.outputStyle));let n=e.tools?.length??0;t.push(Xe(`tools (${n})`,Ml(e.tools)));let r=e.mcpServers??[],o=r.length?r.map(c=>`${c.name}[${c.status}]`).join(", "):m.dim("(none)");t.push(Xe(`mcp (${r.length})`,o));let s=e.skills?.length??0;t.push(Xe(`skills (${s})`,Ml(e.skills)));let i=e.plugins?.length??0,a=i?(e.plugins??[]).map(c=>c.name).join(", "):m.dim("(none)");t.push(Xe(`plugins (${i})`,a));let l=e.slashCommands?.length??0;return t.push(Xe(`slash (${l})`,Ml(e.slashCommands))),t.push(" "+fe()),t.join(`
1832
1832
  `)}var $l=["opus","opus_1m","sonnet","sonnet_1m","haiku"],QA={name:"/cost",summary:"Show total and per-turn cost",hint:"When you want a dollar breakdown of this session \u2014 total, average per turn, and the recent turn-by-turn series.",async handler(e){let{stats:t,out:n}=e;if(n.line(),n.line(m.bold("Session cost")),n.line(fe()),n.line(` total ${m.success(Ce(t.totalCostUsd))}`),n.line(` turns ${m.meta(String(t.totalTurns))}`),t.totalTurns>0){let r=t.totalCostUsd/t.totalTurns;n.line(` avg/turn ${m.meta(Ce(r))}`)}if(t.turnCosts.length>0){let r=t.turnCosts.slice(-5).map(Ce).join(m.dim(" \xB7 "));n.line(` last 5 ${r}`)}return n.line(),"continue"}};function ZA(e,t){let n=t.apiUsage,r=n?.input_tokens??0,o=n?.output_tokens??0,s=n?.cache_read_input_tokens??0,i=n?.cache_creation_input_tokens??0,a=r+o+s+i;e.line(),e.line(m.bold("Token usage")+m.dim(" (SDK breakdown)")),e.line(fe()),e.line(` total ${m.success(q(t.totalTokens))} of ${m.meta(q(t.maxTokens))} (${m.meta(`${Math.round(t.percentage*100)/100}%`)})`),t.autoCompactThreshold&&t.isAutoCompactEnabled&&e.line(` compact at ${m.meta(q(t.autoCompactThreshold))}`),e.line(),e.line(m.dim(" Last turn (API):")),e.line(` input ${m.meta(q(r))}`),e.line(` output ${m.meta(q(o))}`),e.line(` cache read ${m.meta(q(s))}`),e.line(` cache creat ${m.meta(q(i))}`),e.line(` total ${m.meta(q(a))}`);let l=t.categories??[];if(l.length>0){let p=[...l].sort((f,g)=>g.tokens-f.tokens).slice(0,5);e.line(),e.line(m.dim(" Top categories:"));for(let f of p)e.line(` ${m.warning(f.name.padEnd(18))} ${m.meta(q(f.tokens))}`)}let c=t.systemTools??[],d=t.mcpTools??[];if(c.length>0||d.length>0){e.line();let p=c.reduce((g,h)=>g+h.tokens,0),f=d.reduce((g,h)=>g+h.tokens,0);c.length>0&&e.line(m.dim(` system tools ${c.length} tools, ${q(p)} tokens`)),d.length>0&&e.line(m.dim(` MCP tools ${d.length} tools, ${q(f)} tokens`))}let u=t.agents??[];if(u.length>0){let p=u.reduce((f,g)=>f+g.tokens,0);e.line(m.dim(` agents ${u.length} loaded, ${q(p)} tokens`))}if(t.skills){let p=t.skills;e.line(m.dim(` skills ${p.includedSkills}/${p.totalSkills} included, ${q(p.tokens)} tokens`))}if(t.slashCommands){let p=t.slashCommands;e.line(m.dim(` slash cmds ${p.includedCommands}/${p.totalCommands} included, ${q(p.tokens)} tokens`))}e.line()}function eC(e,t){let n=t.turnTokens.reduce((c,d)=>c+d.input,0),r=t.turnTokens.reduce((c,d)=>c+d.output,0),o=t.turnTokens.reduce((c,d)=>c+d.cache,0),s=n+r,i=Ve(t.model),a=n+r+o,l=Math.round(a/i*100);e.line(),e.line(m.bold("Token usage")+m.dim(" (local stats \u2014 SDK breakdown unavailable)")),e.line(fe()),e.line(` input ${m.meta(q(n))}`),e.line(` output ${m.meta(q(r))}`),e.line(` cache read ${m.meta(q(o))}`),e.line(` total ${m.success(q(s))}`),e.line(` context ${m.meta(`${l}% of ${q(i)} (${t.model})`)}`),e.line()}var tC={name:"/tokens",aliases:["/ctx"],summary:"Show token usage (SDK breakdown with local-stats fallback)",hint:"When you want to know how full the context window is \u2014 input/output/cache breakdown plus % of the model's limit used.",async handler(e){try{let t=await e.session.current.getContextUsage();ZA(e.out,t)}catch{eC(e.out,e.stats)}return"continue"}},nC={name:"/history",summary:"Show conversation history",async handler(e){let{stats:t,out:n}=e;return t.turns.length===0?(n.info("No turns yet in this session."),"continue"):(n.line(),n.line(m.bold(`Session history (${t.turns.length} turn${t.turns.length===1?"":"s"})`)),n.line(fe()),t.turns.forEach((r,o)=>{let s=m.meta(`#${o+1}`),i=r.user.length>100?r.user.slice(0,97)+"...":r.user,a=r.assistant.length>100?r.assistant.slice(0,97)+"...":r.assistant;n.line(` ${s} ${m.user("\u25B6")} ${i}`),n.line(` ${m.brand("\u25C6")} ${m.dim(a)}`)}),n.line(),"continue")}},rC={name:"/reset",summary:"Clear screen, history, and session stats",async handler(e){let{stats:t,ui:n,out:r}=e;try{await e.session.current.sendMessage("/clear")}catch{}return t.totalTurns=0,t.totalCostUsd=0,t.totalTokens=0,t.totalDurationMs=0,t.turnCosts.length=0,t.turnTokens.length=0,t.turns.length=0,t.sessionStartTime=Date.now(),n.clearScreen(),r.success("Session reset."),"continue"}},oC={name:"/model",usage:"/model <opus|opus_1m|sonnet|sonnet_1m|haiku>",summary:"Switch the active model mid-session",hint:"When you want to upgrade to opus for a hard problem or downshift to haiku for cheap iteration \u2014 context carries over.",async handler(e,t){let n=t.trim().toLowerCase();if(!n)return e.out.info(`Current model: ${m.brand(e.stats.model)}`),e.out.line(m.dim(` Valid: ${$l.join(", ")}`)),"continue";if(!$l.includes(n))return e.out.warn(`Unknown model: ${n}. Valid: ${$l.join(", ")}`),"continue";try{await e.session.current.setModel(n),e.stats.model=n,e.ui.repaintStatusLine(),e.out.success(`Model switched to ${m.brand(n)}`)}catch(r){e.out.error(`Failed to switch model: ${r instanceof Error?r.message:String(r)}`)}return"continue"}},sC={name:"/tools",summary:"List tools available to the session",async handler(e){try{let n=(await e.session.current.waitForInitialization()).tools??[];if(n.length===0)return e.out.info("No tools reported by the session."),"continue";e.out.line(),e.out.line(m.bold(`Tools (${n.length})`)),e.out.line(fe());let r=3,o=Math.ceil(n.length/r),s=Math.max(...n.map(i=>i.length))+2;for(let i=0;i<o;i++){let a=[];for(let l=0;l<r;l++){let c=l*o+i;c<n.length&&a.push(n[c].padEnd(s))}e.out.line(" "+a.join(""))}e.out.line()}catch(t){e.out.error(`Could not read session tools: ${t instanceof Error?t.message:String(t)}`)}return"continue"}},iC={name:"/mcp",summary:"List MCP servers connected to the session",async handler(e){try{let n=(await e.session.current.waitForInitialization()).mcpServers??[];if(n.length===0)return e.out.info("No MCP servers connected."),"continue";e.out.line(),e.out.line(m.bold(`MCP servers (${n.length})`)),e.out.line(fe());for(let r of n){let o=typeof r=="string"?r:r.name??JSON.stringify(r),s=typeof r=="object"&&r!==null&&"status"in r?String(r.status):"",i=s==="connected"?m.success("\u25CF"):m.warning("\u25CF");e.out.line(` ${i} ${o}${s?m.dim(` (${s})`):""}`)}e.out.line()}catch(t){e.out.error(`Could not read MCP servers: ${t instanceof Error?t.message:String(t)}`)}return"continue"}},aC={name:"/limits",summary:"Show known per-model context-window limits",async handler(e){e.out.line(),e.out.line(m.bold("Context-window limits")),e.out.line(fe());for(let[t,n]of Object.entries(fs)){let r=t===e.stats.model?m.brand(" \u2190 active"):"";e.out.line(` ${m.warning(t.padEnd(12))} ${m.meta(q(n))}${r}`)}return e.out.line(),"continue"}},lC={name:"/debug",summary:"Show SDK session metadata (tools, MCP, skills, plugins, etc.)",hint:"When something feels broken and you want to inspect what the session actually loaded \u2014 tools, MCP servers, plugins, system prompt source.",async handler(e){try{let t=await e.session.current.waitForInitialization();e.out.line(),e.out.line(zs(t)),e.out.line()}catch(t){e.out.error(`Could not read session metadata: ${t instanceof Error?t.message:String(t)}`)}return"continue"}},Zf=[QA,tC,nC,rC,oC,sC,iC,aC,lC];var Ol=!1;async function Et(e,t,n={}){let r=e.stats.planMode,o=t!==void 0?t:!r;try{if(await e.session.current.setPermissionMode(o?"plan":"default"),e.stats.planMode=o,e.ui.repaintStatusLine(),o){let s=Ol?"":m.dim(" Shift+Tab or /plan to exit.");Ol||(Ol=!0),e.out.success(m.warning("\u25CF plan mode ON")+m.dim(" \u2014 write_file, edit_file, and write-intent bash are refused.")+s)}else n.closureSummarySkipped?e.out.success(m.success("\u25CB plan mode OFF")+m.dim(" \u2014 force-exit (closure summary skipped). Default permissions restored.")):e.out.success(m.success("\u25CB plan mode OFF")+m.dim(" \u2014 default permissions restored"))}catch(s){e.out.error(`Could not toggle plan mode: ${s instanceof Error?s.message:String(s)}`)}}async function eg(e){e.stats.pendingPlanExit&&(await Et(e,!1),e.stats.planMode||(e.stats.pendingPlanExit=!1))}var cC=["You are about to exit plan mode. Before I flip permissions back to default on the next turn, emit your final plan in three sections:",""," - **Chosen approach** \u2014 the plan you recommend, in one to three sentences."," - **Risks named** \u2014 the concrete failure modes, constraints, or unknowns this plan does not eliminate."," - **Alternatives considered** \u2014 the options you weighed and why you rejected them.","","This is the record. Be specific. Do not propose write actions in this turn \u2014 writes are still refused until the mode flips."].join(`
@@ -1977,7 +1977,7 @@ _ended: ${new Date().toISOString()}_
1977
1977
  `)}function U_(e){let t=[],n=(r,o)=>{o&&o.trim().length>0&&t.push({label:r,value:o.trim()})};switch(e.kind){case"done":n("done",e.whatWasDone),n("evidence",e.evidence),n("deferred",e.deferred);break;case"blocked":n("blocks",e.whatBlocks),n("unblock",e.unblockCondition),n("progress",e.alreadyDone);break;case"asking":n("question",e.question),n("resolves",e.assumption),n("after",e.followup);break;case"interrupted":n("was doing",e.whatWasInProgress),n("saved at",e.stateLocation),n("resume",e.resumeRequires);break}return t}function Oy(e,t,n){let r=[];n&&n.trim().length>0&&r.push({type:"text",text:n}),e&&r.push({type:"text",text:e});for(let o of t)r.push({type:"image",source:{type:"base64",media_type:o.mediaType,data:o.bytes.toString("base64")}});return r}async function Dy(e,t,n,r,o="summary",s,i,a){let l=wy(e.text,e.attachments);r.setInFlight(!0);let c="",d=!1,u,p=!1,f=!1,g=!1,h,k=!1,y=[],w=new Map,v=e.text.startsWith("/")?e.text.split(/[\s:]/)[0]?.slice(1):void 0,A=new rn({out:dr(),thinkingMode:o,...v?{activeSkillName:v}:{},onCancel:()=>{t.interrupt().catch(_=>{Ie()&&console.error(" "+m.error("session.interrupt() failed:"),_)})},...i?{onBackground:()=>{k=!0}}:{},...a?.history?{history:a.history}:{},...a?.autocompleteState?{autocompleteState:a.autocompleteState}:{}}),T=async()=>{if(!f){f=!0;try{await A.dispose()}catch{}}};try{console.log(),await A.arm();let _=A.getCompositor();if(s&&_){let E=_;s.fn=x=>E.commitAbove(x)}r.setActiveCompositor?.(_),r.rearmStatus?.();let S=e.attachments.length===0?e.text:Oy(e.text,e.attachments),R=t.sendMessageStream(S);if(await Wn(A.sink,async()=>{for await(let E of R){if(k&&i){let x=v??e.text.slice(0,40),$=i.register(x),P=Xs($,i);Qs(R,c,l,$,i,P,n,r.onTurnComplete,t.abortSignal),await T(),console.log(m.dim(` \u2192 backgrounded as ${$.id}: ${$.label}`)),r.setInFlight(!1),r.rearmStatus?.();return}if(E.type==="chunk"&&E.chunk.type==="content"?(c+=E.chunk.content,d=!0):E.type==="message"&&!d&&(c=E.message.content),E.type==="chunk"&&E.chunk.type==="tool_use_detail"){let x=E.chunk,$={toolName:x.toolName,toolUseId:x.toolUseId,input:x.toolInput};w.set(x.toolUseId,$),y.push($)}else if(E.type==="chunk"&&E.chunk.type==="tool_result"){let x=E.chunk,$=w.get(x.toolUseId);$&&($.result=x.content,$.isError=x.isError,w.delete(x.toolUseId))}if(E.type==="paused"){await T(),console.log(ju({reason:E.reason,...E.resetsAt!==void 0?{resetsAt:E.resetsAt}:{},...E.accountId!==void 0?{accountId:E.accountId}:{}}));continue}if(E.type==="resumed"){let x=E.hotSwapped&&E.accountId?`\u25B6 Resumed on ${E.accountId}`:"\u25B6 Resumed";console.log(m.success(x));continue}if(E.type==="error"){await T(),Un(Nn(E.error)),p=!0;continue}A.process(E),E.type==="done"&&(g=!0,h=E.metadata)}}),!f){let E=A.getCompositor();if(E)try{let{text:x,queued:$}=E.getBuffer();$&&x.length>0&&(u=x)}catch{}}if(await T(),g){Ks(n,l,c,h,y),r.onTurnComplete&&await r.onTurnComplete(l,c).catch(()=>{}),d&&console.log(`
1978
1978
  `);let E=My(c);if(E&&(console.log($y(E)),console.log(),r.onTerminalState))try{r.onTerminalState(E)}catch{}if(j_(h,n),r.onAfterTurn){let x=r.onAfterTurn();x instanceof Promise&&await x.catch(()=>{})}}}catch(_){await T(),p||Un(Nn(_))}finally{await T(),s&&(s.fn=_=>console.log(_)),r.setActiveCompositor?.(null),r.setInFlight(!1),r.rearmStatus?.()}return u}function j_(e,t){if(!e)return;let n=[];e.durationMs&&n.push(te(e.durationMs)),e.totalCostUsd!==void 0&&n.push(Ce(e.totalCostUsd));let r=Number(e.usage?.input_tokens??0),o=Number(e.usage?.output_tokens??0);r+o>0&&n.push(q(r+o)+" tok"),n.length>0&&console.log(m.dim(" \u25E6 "+n.join(" \xB7 ")));let s=_l(t);if(s>.5){let i=s>.8?m.error:m.warning;console.log(i(` context ${Math.round(s*100)}% used of ${q(Ve(t.model))}`))}console.log()}function Ly(e={}){let t=e.load??Js,n=e.onResize??(i=>Dt.subscribe(i)),r="",o,s=n(()=>{r=""});return{renderIfChanged(i){let a=i??"unbound",l=t(a),c=cg(l);return a===o&&c===r?[]:(o=a,r=c,c===""?[]:Ys(l))},invalidate(){r=""},dispose(){try{s()}catch{}}}}var xc={done:{glyph:"\u2713",color:m.success,label:"done"},blocked:{glyph:"\u2298",color:m.error,label:"blocked"},asking:{glyph:"?",color:m.warning,label:"asking"},interrupted:{glyph:"\u23F8",color:m.meta,label:"interrupted"}};function Fy(e={}){let t=Math.max(2,e.capacity??8),n=[];return{push(r){n.push(r.kind),n.length>t&&(n=n.slice(n.length-t))},reset(){n=[]},entries(){return n},render(){if(n.length===0)return null;let r=m.dim(" ledger "),o=m.dim(" \xB7 "),s=n.map(d=>{let u=xc[d];return u.color(`${u.glyph} ${u.label}`)}),i=m.dim(` (${n.length} turn${n.length===1?"":"s"})`),a=r+s.join(o)+i,l=Math.max(20,ee()-2);if(B(a)<=l)return a;let c=r+n.map(d=>xc[d].color(xc[d].glyph)).join(m.dim(" "))+i;return ce(c,l)}}}var Ny=["\u25D0","\u25D1","\u25D2","\u25D3"],ji=class{stream;manager;registry;throttleMs;started=!1;lastRepaint=0;spinnerIndex=0;spinnerInterval=null;resizeUnsub=null;updateHandler=null;registryStartedHandler=null;registrySettledHandler=null;subagentRunningCount=0;rowCount=0;onRowCountChange;constructor(t,n,r={}){this.manager=t,this.registry=n,this.stream=r.stream??process.stdout,this.throttleMs=r.throttleMs??200}setRowCountChangeHandler(t){this.onRowCountChange=t}start(){this.started||(this.started=!0,this.updateHandler=()=>this.scheduleRepaint(),this.manager.on("update",this.updateHandler),this.manager.on("complete",this.updateHandler),this.registry&&(this.registryStartedHandler=t=>{this.subagentRunningCount++,this.scheduleRepaint()},this.registrySettledHandler=t=>{this.subagentRunningCount=Math.max(0,this.subagentRunningCount-1),this.scheduleRepaint()},this.registry.on("started",this.registryStartedHandler),this.registry.on("settled",this.registrySettledHandler)),this.resizeUnsub=Dt.subscribe(()=>this.repaint()),this.spinnerInterval=setInterval(()=>{this.spinnerIndex=(this.spinnerIndex+1)%Ny.length,this.rowCount>0&&this.repaint()},Math.max(this.throttleMs,50)))}stop(){this.started&&(this.started=!1,this.updateHandler&&(this.manager.removeListener("update",this.updateHandler),this.manager.removeListener("complete",this.updateHandler),this.updateHandler=null),this.registry&&(this.registryStartedHandler&&(this.registry.off("started",this.registryStartedHandler),this.registryStartedHandler=null),this.registrySettledHandler&&(this.registry.off("settled",this.registrySettledHandler),this.registrySettledHandler=null)),this.resizeUnsub&&(this.resizeUnsub(),this.resizeUnsub=null),this.spinnerInterval&&(clearInterval(this.spinnerInterval),this.spinnerInterval=null),this.rowCount>0&&(this.clearRows(),this.rowCount=0,this.onRowCountChange?.(0)))}scheduleRepaint(){Date.now()-this.lastRepaint<this.throttleMs||this.repaint()}repaint(){if(!this.started||!this.stream.isTTY)return;this.lastRepaint=Date.now();let t=this.manager.running(),n=t.length+this.subagentRunningCount;if(n!==this.rowCount&&(this.rowCount>0&&this.clearRows(),this.rowCount=n,this.onRowCountChange?.(n)),n===0)return;let o=(this.stream.rows??24)-n;this.stream.write("\x1B[s");for(let s=0;s<t.length;s++){let i=t[s],a=o+s;this.stream.write(`\x1B[${a};1H`),this.stream.write("\x1B[2K"),this.stream.write(this.formatTaskLine(i))}this.stream.write("\x1B[u")}clearRows(){if(!this.stream.isTTY)return;let n=(this.stream.rows??24)-this.rowCount;this.stream.write("\x1B[s");for(let r=0;r<this.rowCount;r++)this.stream.write(`\x1B[${n+r};1H`),this.stream.write("\x1B[2K");this.stream.write("\x1B[u")}formatTaskLine(t){let n=Math.max(4,(this.stream.columns??80)-2),r=m.brand(Ny[this.spinnerIndex]),o=m.dim(t.id),s=m.bold(t.label),i=[r,o,s];t.progressDescription&&i.push(m.dim(t.progressDescription));let a=[];t.stats.toolUses>0&&a.push(`${t.stats.toolUses} tool${t.stats.toolUses===1?"":"s"}`),t.stats.tokens>0&&a.push(`${q(t.stats.tokens)} tok`);let l=Date.now()-t.startedAt;return a.push(te(l)),a.length>0&&i.push(m.dim(a.join(" \xB7 "))),ce(" "+i.join(" "),n)}};function Uy(e,t){let n=m.brand("afk")+m.dim(` (${e})`),r=t?m.warning(" \u25CF plan"):"";return n+r+m.dim(" \u203A ")}async function jy(e,t,n,r){let o=null,s=[];e.session.current.waitForInitialization().then(async h=>{Ie()&&(o=zs(h)),await bi(e.session.current),Ie()&&(s=Lh())}).catch(()=>{});let i=await _y(),a=Fi(),l,c=Ly(),d=Fy();e.clearVerdictLedger=()=>d.reset();let u=new Vs;wg(u),Eg(u),Cg(u),Rg(e.backgroundRegistry);let p=new ji(u,e.backgroundRegistry);p.setRowCountChangeHandler(h=>{e.statusLine.setExtraRows(h)}),p.start();let f=50,g=[];u.on("complete",h=>{g.length>=f&&g.shift(),g.push(h)});try{for(;;){if(o&&(e.replRenderer.writeLine(o),e.replRenderer.writeLine(""),o=null),s.length>0){for(let S of s)e.replRenderer.writeLine(S);e.replRenderer.writeLine(""),s=[]}for(;g.length>0;){let S=g.shift(),R=S.status==="succeeded"?"\u2713":"\u2717",E=[];if(S.resultText){let $=S.resultText.trim().split(`
1979
1979
  `)[0]?.slice(0,80)??"";$&&E.push($)}S.error&&E.push(S.error.message);let x=[S.stats.toolUses>0?`${S.stats.toolUses} tools`:"",S.stats.tokens>0?`${Math.round(S.stats.tokens/1e3)}k tok`:"",S.stats.durationMs>0?`${Math.round(S.stats.durationMs/1e3)}s`:""].filter(Boolean).join(" \xB7 ");x&&E.push(x),e.replRenderer.writeLine(Lt({kind:S.status==="succeeded"?"checkpoint":"diagnosis",title:`${R} ${S.id} ${S.label}`,body:E})),e.replRenderer.writeLine("")}let h=c.renderIfChanged(e.stats.sessionId);if(h.length>0){for(let S of h)e.replRenderer.writeLine(S);e.replRenderer.writeLine("")}let k=d.render();k&&e.replRenderer.writeLine(k);let y,w;if(l!==void 0){let S=l;l=void 0;let R=Uy(e.stats.model,e.stats.planMode),E=so({buffer:S.text,promptText:R,isTTY:!!process.stdout.isTTY});e.replRenderer.writeLine(E),y=S.text.trim(),w=S.attachments}else{let S=await Ay({rl:e.rl,promptFn:()=>Uy(e.stats.model,e.stats.planMode),onSigint:r,statusLine:e.statusLine,compositor:n.activeCompositor??void 0,history:i,autocompleteState:a,onShiftTab:()=>{let R=e.slashCtx;R.stats.planMode&&R.stats.pendingPlanExit?(R.stats.pendingPlanExit=!1,Et(R,!1,{closureSummarySkipped:!0}).catch(()=>{})):Et(R).catch(()=>{}),e.statusLine.rearm()}});y=S.text.trim(),w=S.attachments}if(!y&&w.length===0)continue;let v=!1;if(y.startsWith("/")){let S=await Jf(y,e.slashCtx,w);if(S.handled){if(S.result==="exit"){e.rl.close();return}if((y==="/clear"||y.startsWith("/clear "))&&(await t.rotateOnClear(),e.replRenderer.writeLine(m.dim(` transcript: ${t.path()}`)),d.reset()),S.result!==null&&typeof S.result=="object"&&"kind"in S.result&&S.result.kind==="submit"){l={text:S.result.message,attachments:w??[]},e.statusLine.rearm();continue}e.statusLine.rearm();continue}v=!0}i.push(y);let A=y;if(v){let S=Il(y);if(S){let R=S.name.replace(/^\//,"").split(":").pop()??"";if(R&&sc(R)){let E={skillName:R,rawArgs:S.args,source:"plugin",capabilities:{compose:!0,subagents:!0}},x=e.session.current.sessionId,$=po(x),P=await uo(E,{cwd:process.cwd(),artifactDir:$},O=>{Ie()&&e.replRenderer.writeLine(m.warning(`\u26A0 preflight(${R}) failed: `)+(O instanceof Error?O.message:String(O)))});A=ac(P?.manifestBlock,y)}}}let T;if(e.firstTurnHook&&e.stats.totalTurns===0){let S=e.firstTurnHook;e.firstTurnHook=void 0,T=Promise.resolve().then(()=>S(y)).catch(R=>{e.completionWriter.fn(m.warning("\u26A0 ")+"first-turn hook failed: "+(R instanceof Error?R.message:String(R)))})}let _=await Dy({text:A,attachments:w},e.session.current,e.stats,{setInFlight(S){n.turnInFlight=S},async onTurnComplete(S,R){await t.appendTurn(S,R)},async onAfterTurn(){await e.contextSampler.onTurn(e.stats.totalTurns),await eg(e.slashCtx),e.statusLine.rearm()},rearmStatus:()=>e.statusLine.rearm(),onTerminalState:S=>d.push(S),setActiveCompositor:S=>{n.activeCompositor=S,e.replRenderer.setCompositor(S)}},e.options.thinkingUi,e.completionWriter,u,{history:i,autocompleteState:a});l=_!==void 0?{text:_,attachments:[]}:void 0,T!==void 0&&await T}}finally{for(let h of u.running())u.cancel(h.id);p.stop(),c.dispose()}}import{promises as W_}from"node:fs";import{dirname as H_,join as K_}from"node:path";import{randomBytes as G_}from"node:crypto";import B_ from"@anthropic-ai/sdk";import{randomUUID as By}from"node:crypto";async function Wy(e){let{token:t,model:n,system:r,user:o,maxTokens:s=64,signal:i,clientFactory:a}=e;if(!t)throw new Error("oneShotCompletion: token required");let l=No(t),c=_r(t,l),d=a?a(c):new B_(c),u=By(),p=By(),f=bt(l,u,p),g={};Object.keys(f).length>0&&(g.headers=f),i&&(g.signal=i);let h=await d.messages.create({model:n,max_tokens:s,system:r,messages:[{role:"user",content:o}]},Object.keys(g).length>0?g:void 0),k=[];for(let w of h.content)w.type==="text"&&k.push(w.text);let y=k.join("").trim();return y.length===0&&console.warn("oneShotCompletion: response contained no text blocks \u2014 returning empty string"),y}var q_=["Generate a 2-4 word kebab-case slug describing this work request.","Rules:","- ASCII lowercase letters and digits only, separated by single hyphens","- 2 to 4 hyphen-separated words","- Maximum 30 characters total","- No prefix, no quotes, no punctuation other than hyphens","- Output ONLY the slug \u2014 no explanation, no preamble","Examples: fix-cleanup-race, add-telegram-allowlist, refactor-prompt-loader, debug-flaky-test"].join(`
1980
- `),Hy=/^[a-z0-9]+(-[a-z0-9]+){1,3}$/,Ec=30,z_=1024,J_=8e3,Y_="haiku";async function V_(e,t){let n=e.trim();if(n.length===0||n.startsWith("/"))return null;let r=e0(n,z_),o=new AbortController,s=setTimeout(()=>o.abort(),t.timeoutMs??J_),i=t.signal?t0([t.signal,o.signal]):o.signal,a;try{t.slugGenerator?a=await t.slugGenerator(r,i):a=await Wy({token:t.token,model:t.model??Y_,system:q_,user:r,maxTokens:32,signal:i})}catch{return null}finally{clearTimeout(s)}let l=X_(a);if(l===null)return null;let c=H_(t.worktreePath);return await Q_(l,c)}function X_(e){let t=e.trim().toLowerCase();if(t.length===0)return null;if(Hy.test(t)&&t.length<=Ec)return t;let n=t.replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");if(n.length===0)return null;let r=n.split("-").filter(s=>s.length>0).slice(0,4);if(r.length<2)return null;let o=r[0];for(let s=1;s<r.length;s++){let i=`${o}-${r[s]}`;if(i.length>Ec)break;o=i}return Hy.test(o)?o:null}async function Q_(e,t){if(!await Z_(K_(t,e)))return e;let n=G_(2).toString("hex");return`${e.split("-").slice(0,3).join("-").slice(0,Ec-5)}-${n}`}async function Z_(e){try{return await W_.access(e),!0}catch{return!1}}function e0(e,t){let n=Buffer.from(e,"utf8");if(n.length<=t)return e;let r=t;for(;r>0&&n[r]!==void 0&&(n[r]&192)===128;)r--;return n.slice(0,r).toString("utf8")}function t0(e){let t=AbortSignal.any;if(typeof t=="function")return t.call(AbortSignal,e);let n=new AbortController;for(let r of e){if(r.aborted)return n.abort(r.reason),n.signal;r.addEventListener("abort",()=>n.abort(r.reason),{once:!0})}return n.signal}async function Ky(e){let t=await V_(e.message,{token:e.token,...e.model!==void 0?{model:e.model}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},worktreePath:e.handle.path,...e.signal!==void 0?{signal:e.signal}:{},...e.slugGenerator!==void 0?{slugGenerator:e.slugGenerator}:{}});if(t===null)return{status:"skipped",reason:"slug generation returned null"};let r=await(e.renameFn??Xp)(e.handle,t,e.branchPrefix!==void 0?{branchPrefix:e.branchPrefix}:void 0);return r.ok?(e.session&&e.session.setCwd(r.newPath),{status:"renamed",oldPath:r.oldPath,newPath:r.newPath,oldBranch:r.oldBranch,newBranch:r.newBranch}):(r.partial==="branch"&&e.session&&e.session.setCwd(e.handle.path),{status:"failed",reason:r.reason,...r.partial!==void 0?{partial:r.partial}:{}})}import{spawn as Gy}from"child_process";import{existsSync as i0,mkdirSync as a0,readFileSync as qy,unlinkSync as l0,writeFileSync as c0}from"fs";import{get as u0}from"https";import{join as zy}from"path";import{readFileSync as n0}from"fs";import{dirname as r0,join as o0}from"path";import{fileURLToPath as s0}from"url";function At(){try{return"3.3.2"}catch{}try{let e=r0(s0(import.meta.url));for(let t of["../../package.json","../package.json"])try{let n=JSON.parse(n0(o0(e,t),"utf-8"));if(typeof n.version=="string")return n.version}catch{}}catch{}return"0.0.0-unknown"}var d0=64*1024,p0=1440*60*1e3,m0="update-check.json",f0="pending-update.json";function Jy(){return zy(Co(),m0)}function Rc(){return zy(Co(),f0)}function Yy(){let e=Co();i0(e)||a0(e,{recursive:!0})}function g0(e,t){let n=e.split(".").map(Number),r=t.split(".").map(Number),o=Math.max(n.length,r.length);for(let s=0;s<o;s++){let i=n[s]??0,a=r[s]??0;if(a>i)return!0;if(a<i)return!1}return!1}function h0(){try{let e=qy(Jy(),"utf-8"),t=JSON.parse(e);if(typeof t.latestVersion=="string"&&typeof t.checkedAt=="number")return t}catch{}return null}function y0(){try{Yy();let e=`
1980
+ `),Hy=/^[a-z0-9]+(-[a-z0-9]+){1,3}$/,Ec=30,z_=1024,J_=8e3,Y_="haiku";async function V_(e,t){let n=e.trim();if(n.length===0||n.startsWith("/"))return null;let r=e0(n,z_),o=new AbortController,s=setTimeout(()=>o.abort(),t.timeoutMs??J_),i=t.signal?t0([t.signal,o.signal]):o.signal,a;try{t.slugGenerator?a=await t.slugGenerator(r,i):a=await Wy({token:t.token,model:t.model??Y_,system:q_,user:r,maxTokens:32,signal:i})}catch{return null}finally{clearTimeout(s)}let l=X_(a);if(l===null)return null;let c=H_(t.worktreePath);return await Q_(l,c)}function X_(e){let t=e.trim().toLowerCase();if(t.length===0)return null;if(Hy.test(t)&&t.length<=Ec)return t;let n=t.replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");if(n.length===0)return null;let r=n.split("-").filter(s=>s.length>0).slice(0,4);if(r.length<2)return null;let o=r[0];for(let s=1;s<r.length;s++){let i=`${o}-${r[s]}`;if(i.length>Ec)break;o=i}return Hy.test(o)?o:null}async function Q_(e,t){if(!await Z_(K_(t,e)))return e;let n=G_(2).toString("hex");return`${e.split("-").slice(0,3).join("-").slice(0,Ec-5)}-${n}`}async function Z_(e){try{return await W_.access(e),!0}catch{return!1}}function e0(e,t){let n=Buffer.from(e,"utf8");if(n.length<=t)return e;let r=t;for(;r>0&&n[r]!==void 0&&(n[r]&192)===128;)r--;return n.slice(0,r).toString("utf8")}function t0(e){let t=AbortSignal.any;if(typeof t=="function")return t.call(AbortSignal,e);let n=new AbortController;for(let r of e){if(r.aborted)return n.abort(r.reason),n.signal;r.addEventListener("abort",()=>n.abort(r.reason),{once:!0})}return n.signal}async function Ky(e){let t=await V_(e.message,{token:e.token,...e.model!==void 0?{model:e.model}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},worktreePath:e.handle.path,...e.signal!==void 0?{signal:e.signal}:{},...e.slugGenerator!==void 0?{slugGenerator:e.slugGenerator}:{}});if(t===null)return{status:"skipped",reason:"slug generation returned null"};let r=await(e.renameFn??Xp)(e.handle,t,e.branchPrefix!==void 0?{branchPrefix:e.branchPrefix}:void 0);return r.ok?(e.session&&e.session.setCwd(r.newPath),{status:"renamed",oldPath:r.oldPath,newPath:r.newPath,oldBranch:r.oldBranch,newBranch:r.newBranch}):(r.partial==="branch"&&e.session&&e.session.setCwd(e.handle.path),{status:"failed",reason:r.reason,...r.partial!==void 0?{partial:r.partial}:{}})}import{spawn as Gy}from"child_process";import{existsSync as i0,mkdirSync as a0,readFileSync as qy,unlinkSync as l0,writeFileSync as c0}from"fs";import{get as u0}from"https";import{join as zy}from"path";import{readFileSync as n0}from"fs";import{dirname as r0,join as o0}from"path";import{fileURLToPath as s0}from"url";function At(){try{return"3.3.3"}catch{}try{let e=r0(s0(import.meta.url));for(let t of["../../package.json","../package.json"])try{let n=JSON.parse(n0(o0(e,t),"utf-8"));if(typeof n.version=="string")return n.version}catch{}}catch{}return"0.0.0-unknown"}var d0=64*1024,p0=1440*60*1e3,m0="update-check.json",f0="pending-update.json";function Jy(){return zy(Co(),m0)}function Rc(){return zy(Co(),f0)}function Yy(){let e=Co();i0(e)||a0(e,{recursive:!0})}function g0(e,t){let n=e.split(".").map(Number),r=t.split(".").map(Number),o=Math.max(n.length,r.length);for(let s=0;s<o;s++){let i=n[s]??0,a=r[s]??0;if(a>i)return!0;if(a<i)return!1}return!1}function h0(){try{let e=qy(Jy(),"utf-8"),t=JSON.parse(e);if(typeof t.latestVersion=="string"&&typeof t.checkedAt=="number")return t}catch{}return null}function y0(){try{Yy();let e=`
1981
1981
  const https = require('https');
1982
1982
  const fs = require('fs');
1983
1983
  const url = 'https://registry.npmjs.org/agent-afk/latest';
package/dist/index.mjs CHANGED
@@ -918,7 +918,7 @@ Don't refuse the flow; just clarify where the wizard runs.
918
918
  Be terse and operational. The user is doing one-time setup; they want it done, not narrated. Confirm each step in one line, don't over-explain. Use \`\u2713\` for success, \`\u2717\` for failure, and code fences for any command they should run.
919
919
  `}};function L(t){let e=wr[t];if(!e){let n=Object.keys(wr).sort(),r=n.length>0?"Available: "+n.join(", "):"";throw new Error("Unknown skill: "+t+". "+r)}return e}var dt=new Map;function z(t){dt.set(t.name,t)}function Ee(t){let e=dt.get(t);if(e)return e;let n=Array.from(dt.keys()).sort(),r=n.length>0?`
920
920
  Available skills: ${n.join(", ")}`:"";throw new Error(`Skill not found: ${t}${r}`)}function ut(){return Array.from(dt.keys()).sort()}var He=class{nodes=new Map;traceWriter;constructor(e){this.traceWriter=e}register(e,n){this.nodes.has(e)||this.nodes.set(e,{controller:n,children:new Set,listeners:new Set,cascading:!1})}has(e){return this.nodes.has(e)}getController(e){return this.nodes.get(e)?.controller}linkChild(e,n){let r=this.nodes.get(e),o=this.nodes.get(n);if(!r)throw new Error(`AbortGraph: parent ${e} not registered`);if(!o)throw new Error(`AbortGraph: child ${n} not registered`);if(o.parentId=e,r.children.add(n),r.controller.signal.aborted){o.controller.signal.aborted||(o.cascading=!0,o.controller.abort(r.controller.signal.reason));return}r.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);!s||s.parentId!==e||s.controller.signal.aborted||(s.cascading=!0,s.controller.abort(r.controller.signal.reason))},{once:!0}),o.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);if(!s||s.parentId!==e||s.cascading)return;let i=this.nodes.get(e);if(!i)return;let a={parentId:e,childId:n,reason:s.controller.signal.reason};for(let c of i.listeners)try{c(a)}catch{}},{once:!0})}onChildAborted(e,n){let r=this.nodes.get(e);if(!r)throw new Error(`AbortGraph: ${e} not registered`);return r.listeners.add(n),()=>{r.listeners.delete(n)}}abort(e,n,r="user_signal"){let o=this.nodes.get(e);if(!o||o.controller.signal.aborted)return;let s=[],i=[...o.children],a=new Set;for(;i.length;){let c=i.shift();if(a.has(c))continue;a.add(c);let l=this.nodes.get(c);if(l){l.cascading=!0,s.push(c);for(let d of l.children)i.push(d)}}rr(this.traceWriter,{origin:r,cascadedTo:s,...n!==void 0?{reason:qi(n)}:{}}),o.controller.abort(n);for(let c of s){let l=this.nodes.get(c);l&&!l.controller.signal.aborted&&l.controller.abort(n)}}dispose(e){let n=this.nodes.get(e);if(n){n.parentId&&this.nodes.get(n.parentId)?.children.delete(e);for(let r of n.children){let o=this.nodes.get(r);o&&(o.parentId=void 0)}this.nodes.delete(e)}}};function qi(t){if(typeof t=="string")return t;if(t instanceof Error)return t.message;try{return JSON.stringify(t)}catch{return String(t)}}var Be=0,pt=5e3;async function We(t,e,n={}){if(!Number.isFinite(e)||e<=0)return t;let r,o=new Promise((s,i)=>{r=setTimeout(()=>{let a=n.label?` (${n.label})`:"",c=new pe(`Operation timed out after ${e}ms${a}`,e);n.controller&&!n.controller.signal.aborted&&n.controller.abort(c),i(c)},e)});try{return await Promise.race([t,o])}finally{r!==void 0&&clearTimeout(r)}}async function me(t,e,n,r){if(!t)return;if(r.kind==="blocked"){await Ie(t,{hookEvent:e,decision:"block",...r.err.reason!==void 0?{reason:r.err.reason}:{},...e==="PreToolUse"&&n.toolName!==void 0?{blockedTool:n.toolName}:{}});return}let o=r.decision;await Ie(t,{hookEvent:e,decision:o.decision,...o.reason!==void 0?{reason:o.reason}:{},...o.injectContext!==void 0?{injectedContextBytes:Buffer.byteLength(o.injectContext,"utf8")}:{}})}async function kr(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await me(n.traceWriter,"SubagentStart",{},{kind:"decision",decision:r})}catch(r){throw r instanceof H&&await me(n.traceWriter,"SubagentStart",{},{kind:"blocked",err:r}),r}}async function vr(t,e,n={}){if(!t)return{};try{let r=await t.dispatch(e,n.signal);return await me(n.traceWriter,"SubagentStop",{},{kind:"decision",decision:r}),r}catch(r){return r instanceof H&&await me(n.traceWriter,"SubagentStop",{},{kind:"blocked",err:r}),r instanceof H||r instanceof ee?(_(`SubagentStop hook swallowed ${r.name}: ${r.message}`),n.onError?.(r),{}):(_(`SubagentStop hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r))),{})}}async function sn(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await me(n.traceWriter,"PreToolUse",{toolName:e.toolName},{kind:"decision",decision:r})}catch(r){throw r instanceof H&&await me(n.traceWriter,"PreToolUse",{toolName:e.toolName},{kind:"blocked",err:r}),r}}async function Sr(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await me(n.traceWriter,"PostToolUse",{toolName:e.toolName},{kind:"decision",decision:r})}catch(r){if(r instanceof H&&await me(n.traceWriter,"PostToolUse",{toolName:e.toolName},{kind:"blocked",err:r}),r instanceof H||r instanceof ee){_(`PostToolUse hook swallowed ${r.name}: ${r.message}`),n.onError?.(r);return}_(`PostToolUse hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r)))}}import{mkdir as Qi,writeFile as Zi}from"fs/promises";import{dirname as ea,join as ta}from"path";import{join as U,dirname as zi}from"path";import{homedir as Vi}from"os";import{fileURLToPath as Ji}from"url";function J(){return process.env.AFK_HOME||U(Vi(),".afk")}function Ae(){return U(J(),"agent-framework")}function ft(){return U(Ae(),"forge-telemetry.jsonl")}function Ce(){return U(Ae(),"briefs")}function mt(){return U(Ae(),"ceiling-ledger")}function ht(){return U(J(),"skills")}function Me(){return U(J(),"plugins")}function Yi(){return U(process.cwd(),".afk")}function an(){return U(Yi(),"plugins")}function gt(){return U(Me(),".index.json")}function cn(){return U(Xi(),"schedules.json")}function ln(){let t=Ji(import.meta.url),e=zi(t);return U(e,"bundled-plugins")}function Xi(){return U(J(),"config")}function yt(){return U(J(),"state")}function xr(){return U(yt(),"sessions")}function bt(){return U(yt(),"memory")}function De(){return U(yt(),"session-grants.jsonl")}function Tr(){return U(J(),"farms")}function Er(t){return U(Tr(),t)}function Ar(t="default"){return U(yt(),"daemon",`agent-afk@${t}`)}function na(){return ta(Ae(),"routing-decisions.jsonl")}async function wt(t){if(!(process.env.VITEST||process.env.NODE_ENV==="test"))try{let e=na();await Qi(ea(e),{recursive:!0});let r={ts:new Date().toISOString().split(".")[0]+"Z",surface:"afk"};for(let[s,i]of Object.entries(t))i!==void 0&&(r[s]=i);let o=JSON.stringify(r)+`
921
- `;await Zi(e,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as ra}from"node:async_hooks";var _r=new ra;function Rr(t,e){return _r.run(t,e)}function Oe(){return _r.getStore()}function dn(t){let e=oa(t);return e!==void 0?e:sa(t)}function oa(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return Pr(n.trim())}function sa(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=ia(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=Pr(r);if(o!==void 0)return o}}function ia(t,e){let n=0,r=!1,o=!1;for(let s=e;s>=0;s--){let i=t[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function Pr(t){try{return JSON.parse(t)}catch{return}}function un(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function Ir(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=dn(n.content),i=r.safeParse(s);return i.success?{id:t,status:e,message:n,output:i.data,trace:o}:{id:t,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function Cr(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function F(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}var kt=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f,h){this.id=e;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=c;this.parentInputStreamRef=l;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=h;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=un();lastStreamedContent="";get status(){return this.currentStatus}async run(e){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=We(this.streamToFinalMessage(e),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",Se(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(Se(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(Se(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r;this.lastStreamedContent="",this.currentTrace=un();let o=this.progressSink??Oe(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(e)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return Ir(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=Cr(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(e,n){this.runToResult(e).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",Se(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async teardown(){if(this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async dispatchStopAndRelease(e){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await vr(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)_(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){_(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var E=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,this.parentBaseUrl=e.baseUrl,this.parentCwd=e.cwd,this.abortGraph=new He(e.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),e.parentAbortSignal){let n=e.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(e=>({id:e.id,status:e.status}))}get(e){return this.active.get(e)}onChildAborted(e){return this.abortGraph.onChildAborted(this.rootId,e)}abortAll(e,n="user_signal"){this.abortGraph.abort(this.rootId,e,n)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await kr(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal,...e.config.traceWriter?{traceWriter:e.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...e.config,resume:r,forkSession:r?!0:e.config.forkSession,abortSignal:s.signal,apiKey:e.config.apiKey||this.parentApiKey,baseUrl:e.config.baseUrl??this.parentBaseUrl,...e.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:e.config.hookRegistry??this.hookRegistry,permissionBubbler:e.config.permissionBubbler??(this.parentCanUseTool!==void 0&&e.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new _e(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??Oe(),u=e.agentType?.trim()||void 0,p=e.parentId?.trim()||void 0,f=new kt(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Be,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,u??e.idPrefix,d,p??e.parent.sessionId,e.config.traceWriter);this.active.set(n,f);let h=typeof e.config.model=="string"?e.config.model:JSON.stringify(e.config.model);return Se(e.config.traceWriter,{transition:"started",subagentId:n,parentId:e.parent.sessionId??this.rootId,model:h,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await wt({event:"subagent.dispatched",subagent_id:n,id_prefix:e.idPrefix,parent_session_id:e.parent.sessionId}),f}async kill(e){let n=this.active.get(e);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(e=>e.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(e=>e.teardown()))}};async function vt(t,e={}){let{failFast:n=!0,teardown:r=!0}=e;if(t.length===0)return[];let o=new Array(t.length),s=new Set(t.map((a,c)=>c)),i=t.map((a,c)=>a.handle.runToResult(a.prompt).then(l=>{if(o[c]=l,s.delete(c),n&&l.status!=="succeeded")for(let d of s){let u=t[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(t.map(a=>a.handle.teardown())),o}import{fileURLToPath as aa}from"node:url";import{dirname as ca}from"node:path";var la=aa(import.meta.url),dm=ca(la),V={name:"research-agent",systemPrompt:`---
921
+ `;await Zi(e,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as ra}from"node:async_hooks";var _r=new ra;function Rr(t,e){return _r.run(t,e)}function Oe(){return _r.getStore()}function dn(t){let e=oa(t);return e!==void 0?e:sa(t)}function oa(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return Pr(n.trim())}function sa(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=ia(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=Pr(r);if(o!==void 0)return o}}function ia(t,e){let n=0,r=!1,o=!1;for(let s=e;s>=0;s--){let i=t[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function Pr(t){try{return JSON.parse(t)}catch{return}}function un(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function Ir(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=dn(n.content),i=r.safeParse(s);return i.success?{id:t,status:e,message:n,output:i.data,trace:o}:{id:t,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function Cr(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function F(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}var kt=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f,h){this.id=e;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=c;this.parentInputStreamRef=l;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=h;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=un();lastStreamedContent="";get status(){return this.currentStatus}async run(e){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=We(this.streamToFinalMessage(e),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",Se(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(Se(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(Se(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r;this.lastStreamedContent="",this.currentTrace=un();let o=this.progressSink??Oe(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(e)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return Ir(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=Cr(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(e,n){this.runToResult(e).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",Se(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async teardown(){if(this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async dispatchStopAndRelease(e){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await vr(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)_(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){_(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var E=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,this.parentBaseUrl=e.baseUrl,this.parentCwd=e.cwd,this.abortGraph=new He(e.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),e.parentAbortSignal){let n=e.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(e=>({id:e.id,status:e.status}))}get(e){return this.active.get(e)}onChildAborted(e){return this.abortGraph.onChildAborted(this.rootId,e)}abortAll(e,n="user_signal"){this.abortGraph.abort(this.rootId,e,n)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await kr(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal,...e.config.traceWriter?{traceWriter:e.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...e.config,resume:r,forkSession:r?!0:e.config.forkSession,abortSignal:s.signal,apiKey:e.config.apiKey||this.parentApiKey,baseUrl:e.config.baseUrl??this.parentBaseUrl,...e.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:e.config.hookRegistry??this.hookRegistry,permissionBubbler:e.config.permissionBubbler??(this.parentCanUseTool!==void 0&&e.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new _e(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??Oe(),u=e.agentType?.trim()||void 0,p=e.parentId?.trim()||void 0,f=new kt(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Be,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,u??e.idPrefix,d,p??e.parent.sessionId,e.config.traceWriter);this.active.set(n,f);let h=typeof e.config.model=="string"?e.config.model:JSON.stringify(e.config.model);return Se(e.config.traceWriter,{transition:"started",subagentId:n,parentId:e.parent.sessionId??this.rootId,model:h,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await wt({event:"subagent.dispatched",subagent_id:n,id_prefix:e.idPrefix,model:h,parent_session_id:e.parent.sessionId}),f}async kill(e){let n=this.active.get(e);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(e=>e.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(e=>e.teardown()))}};async function vt(t,e={}){let{failFast:n=!0,teardown:r=!0}=e;if(t.length===0)return[];let o=new Array(t.length),s=new Set(t.map((a,c)=>c)),i=t.map((a,c)=>a.handle.runToResult(a.prompt).then(l=>{if(o[c]=l,s.delete(c),n&&l.status!=="succeeded")for(let d of s){let u=t[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(t.map(a=>a.handle.teardown())),o}import{fileURLToPath as aa}from"node:url";import{dirname as ca}from"node:path";var la=aa(import.meta.url),dm=ca(la),V={name:"research-agent",systemPrompt:`---
922
922
  name: research-agent
923
923
  description: Read-only sub-agent for research, validation, verification, and codebase inspection. Mechanically locked to Read, Grep, Glob, WebFetch, WebSearch \u2014 cannot Edit, Write, Bash, commit, or push. Delegates git queries to \`git-investigator\`. Use when the dispatched task is findings-only.
924
924
  model: sonnet
@@ -978,9 +978,9 @@ If \`scope_check\` flags implementation (non-git), the orchestrator should dispa
978
978
  ${Ta(x)}`,artifacts:x,runPrompt:`Inspect every ${v} listed in the artifact section.`})}if(l.runHookInspector){let v=p.hook;if(v){let x=mn(J(),"settings.json"),I=Ur(x);m.push({type:"hook",prompt:`${v}
979
979
  ${Ea(x,I)}`,artifacts:[],runPrompt:`Inspect every hook listed in the Discovered hooks section. Settings file: ${x}.`})}}let g=[];if(m.length>0){let v=await Promise.all(m.map(P=>k.forkSubagent({parent:{sessionId:d},config:{model:"sonnet",systemPrompt:`${V.systemPrompt}
980
980
 
981
- ${P.prompt}`,canUseTool:b()},idPrefix:`inspector-${P.type}`,outputSchema:O.array(Wr),...o?{parentId:o}:{}}))),x=await vt(m.map((P,q)=>{let $=v[q];if(!$)throw new Error(`audit-fit: missing handle for ${P.type} inspector`);return{handle:$,prompt:P.runPrompt}}),{failFast:!1}),I=[];for(let P=0;P<x.length;P++){let q=x[P],$=m[P];if(!$)continue;let Z=Aa($.type,q);if(Z.kind==="failure"){I.push(Z.message);continue}let ue=new Map;for(let K of $.artifacts)ue.set(K.path,K.source);for(let K of Z.output){if($.type==="hook"){if(K.source!=="user"){I.push(`${$.type}: hook verdict has source=${K.source} (must be 'user')`);continue}}else{let M=ue.get(K.path);if(M===void 0){I.push(`${$.type}: verdict for unknown path ${K.path} (not in discovered list)`);continue}if(K.source!==M){I.push(`${$.type}: verdict source mismatch for ${K.path} (expected ${M}, got ${K.source})`);continue}}g.push(K)}}if(I.length>0){let P=I.map(q=>` - ${q}`).join(`
981
+ ${P.prompt}`,canUseTool:b()},idPrefix:`inspector-${P.type}`,outputSchema:O.array(Wr),...o?{parentId:o}:{}}))),x=await vt(m.map((P,K)=>{let $=v[K];if(!$)throw new Error(`audit-fit: missing handle for ${P.type} inspector`);return{handle:$,prompt:P.runPrompt}}),{failFast:!1}),I=[];for(let P=0;P<x.length;P++){let K=x[P],$=m[P];if(!$)continue;let Z=Aa($.type,K);if(Z.kind==="failure"){I.push(Z.message);continue}let ue=new Map;for(let q of $.artifacts)ue.set(q.path,q.source);for(let q of Z.output){if($.type==="hook"){if(q.source!=="user"){I.push(`${$.type}: hook verdict has source=${q.source} (must be 'user')`);continue}}else{let M=ue.get(q.path);if(M===void 0){I.push(`${$.type}: verdict for unknown path ${q.path} (not in discovered list)`);continue}if(q.source!==M){I.push(`${$.type}: verdict source mismatch for ${q.path} (expected ${M}, got ${q.source})`);continue}}g.push(q)}}if(I.length>0){let P=I.map(K=>` - ${K}`).join(`
982
982
  `);throw new Error(`audit-fit: ${I.length} inspector failure(s):
983
- ${P}`)}}let{inventory:w,misfits:C}=Sa(g),N=0;if(a){let v=Ce();await jr(v,{recursive:!0});for(let x of C.filter(xa)){let I=x.path.replace(/[^a-z0-9]+/gi,"-").toLowerCase().slice(0,30),P=mn(v,`audit-fit-${I}.md`),q=`---
983
+ ${P}`)}}let{inventory:w,misfits:C}=Sa(g),N=0;if(a){let v=Ce();await jr(v,{recursive:!0});for(let x of C.filter(xa)){let I=x.path.replace(/[^a-z0-9]+/gi,"-").toLowerCase().slice(0,30),P=mn(v,`audit-fit-${I}.md`),K=`---
984
984
  theme: audit-fit
985
985
  session_count: 1
986
986
  ---
@@ -1002,7 +1002,7 @@ ${x.rationale}
1002
1002
 
1003
1003
  ---
1004
1004
  Generated by audit-fit on ${new Date().toISOString().split(".")[0]}Z
1005
- `;await Hr(P,q),N++}}let D=Ae();await jr(D,{recursive:!0});let T=v=>{let x=0;for(let I of Object.values(v))for(let P of Object.values(I))x+=P;return x},R=v=>{let x=w.user[v]??{},I=w.plugin[v]??{},P=q=>Object.values(q).reduce(($,Z)=>$+Z,0);return P(x)+P(I)},A={timestamp:new Date().toISOString(),surface:"afk",scope:c,total_artifacts:g.length,misfits_count:C.length,briefs_written:N,by_source:{user:T(w.user),plugin:T(w.plugin)},by_type:{skill:R("skill"),command:R("command"),agent:R("agent"),hook:R("hook")}},G=mn(D,"audit-fit-telemetry.jsonl");return await Hr(G,JSON.stringify(A)+`
1005
+ `;await Hr(P,K),N++}}let D=Ae();await jr(D,{recursive:!0});let T=v=>{let x=0;for(let I of Object.values(v))for(let P of Object.values(I))x+=P;return x},R=v=>{let x=w.user[v]??{},I=w.plugin[v]??{},P=K=>Object.values(K).reduce(($,Z)=>$+Z,0);return P(x)+P(I)},A={timestamp:new Date().toISOString(),surface:"afk",scope:c,total_artifacts:g.length,misfits_count:C.length,briefs_written:N,by_source:{user:T(w.user),plugin:T(w.plugin)},by_type:{skill:R("skill"),command:R("command"),agent:R("agent"),hook:R("hook")}},G=mn(D,"audit-fit-telemetry.jsonl");return await Hr(G,JSON.stringify(A)+`
1006
1006
  `),{inventory:w,misfits:C,briefs_written:N,total_artifacts:g.length}}var Ra={name:"audit-fit",description:"Audit ~/.afk artifacts (skills, commands, agents, hooks) for correct type categorization. Walks user-scope dirs (~/.afk/{skills,commands,agents}/) and every plugin installed under ~/.afk/plugins/ (flat and marketplace-cache layouts), plus ~/.afk/settings.json for hooks. Dispatches per-type inspectors in parallel, applies decision heuristics (progressive-disclosure value, isolation need, deterministic vs. reasoning), flags misfits. Generates migration briefs only for user-scope misfits (plugin misfits are inventory-only \u2014 refactoring vendored plugin code is the maintainer's job). Optional `scope` input filters to `user`, `plugin`, or `all` (default). Use for inventory audits after bulk authoring, imports, or periodic hygiene.",handler:_a,argumentHint:"[--write-briefs]",whenToUse:"When the user wants ~/.afk artifacts (skills, commands, agents, hooks) audited for correct type categorization.",flags:["--write-briefs"]};z(Ra);import{z as S}from"zod";import{execFile as Ma}from"node:child_process";import{promisify as Da}from"node:util";import{tmpdir as Oa}from"node:os";import{join as qr}from"node:path";function Kr(t){return t.confidence<.5?{verify:!0,reason:`low confidence (${t.confidence.toFixed(2)} < ${.5})`}:t.boundary_flag&&t.boundary_flag.length>0?{verify:!0,reason:`boundary flag set: ${t.boundary_flag}`}:t.coverage_gaps&&t.coverage_gaps.length>0?{verify:!0,reason:`coverage gap${t.coverage_gaps.length===1?"":"s"}: ${t.coverage_gaps.length} unresolved`}:{verify:!1,reason:`confidence ${t.confidence.toFixed(2)} with no gaps or boundary`}}import{fileURLToPath as Pa}from"node:url";import{dirname as Ia}from"node:path";var Ca=Pa(import.meta.url),Km=Ia(Ca),hn={name:"git-investigator",systemPrompt:'---\nname: git-investigator\ndescription: Read-only git specialist. Dispatched by research-agent (or any research-shaped caller) when a finding requires git history, reflog, diff, blame, branch/remote state, or merge-base analysis. Runs git commands only \u2014 no mutations, no shell escapes.\nmodel: sonnet\ntools: Bash, Read, Grep, Glob\n---\n\nYou are `git-investigator`, a leaf sub-agent specialized for read-only git queries.\n\nYou have Bash, Read, Grep, and Glob. You do not dispatch other sub-agents. You do not Edit or Write. Your Bash surface is restricted **by this prompt** to `git ...` invocations and benign output-shaping pipes.\n\n## Allowed commands\n\nRead-only git only:\n\n- `git status`, `git log`, `git diff`, `git show`\n- `git rev-parse`, `git rev-list`, `git reflog`\n- `git branch -v / -vv / -a` (list only)\n- `git remote -v`, `git ls-remote`\n- `git ls-files`, `git blame`\n- `git merge-base`, `git for-each-ref`, `git describe`\n- `git cat-file`, `git shortlog`\n- `git tag` (list/show only)\n- `git stash list`, `git stash show`\n- `git config --get`, `git config --get-all`, `git config --list`\n- `git worktree list` (read only)\n\nOutput-shaping pipes are fine: `| head`, `| tail`, `| wc`, `| grep`, `| jq`, `| awk \'NR==...\'` (for formatting only \u2014 no mutations).\n\n## Forbidden\n\nAnything that mutates repo or working tree state:\n\n- `commit`, `push`, `pull`, `fetch --prune`\n- `reset`, `revert`, `rebase`, `merge`, `cherry-pick`\n- `checkout` (except `checkout -- <path>` file-restore, and even that is mutation \u2014 avoid it, just report the need)\n- `restore`, `switch`\n- `branch -d / -D / -m / -M`, `branch <new>`\n- `stash push / pop / drop / apply / clear`\n- `tag -d`, creating a new tag\n- `remote add / remove / set-url`\n- `config --set`, `config --unset`\n- `gc`, `fsck`, `prune`, `reflog delete`, `reflog expire`\n- `filter-branch`, `filter-repo`\n- `worktree add / remove / move`\n- `hooks install`, `submodule add / update`\n- Any non-`git` command that mutates: `rm`, `mv`, `cp` (writes), `sed -i`, `> file`, `>> file`, `tee`, `curl`, `wget`, `pip install`, shell builtins that change state.\n\nIf the caller asks for any of the above, do not run it. Return `scope_check: "requires mutation: <reason>"` and stop.\n\n## Behavior\n\n- Run the minimum set of commands needed. Prefer `git log -n 5 --oneline -- <path>` over `git log -- <path>` when a count is fine.\n- Cite concrete evidence: commit SHAs (short form OK), ref names, `path:line` references from blame, diff hunks trimmed to the relevant range.\n- Use `Read`/`Grep`/`Glob` for follow-up inspection of files the git output identifies (e.g., `git show SHA:path | head` then `Read` the current file to diff mentally).\n- Do not speculate beyond what the commands show. If a question needs history the commands don\'t surface (deleted-file recovery, ancient reflog that has expired), say so in `caveats`.\n- Keep output compact \u2014 dispatchers merge your findings into a larger response. No preamble, no ceremony.\n\n## Return shape\n\n```\n{\n "findings": "<summary of what the git data shows>",\n "evidence": ["<SHA>", "<ref>", "<path:line>", ...],\n "git_commands_run": ["git log ...", "git diff ...", ...],\n "caveats": "<gaps, ambiguity, or \'none\'>",\n "scope_check": "pure git research" | "requires mutation: <reason>"\n}\n```\n\nBegin your response with the first schema field. No preamble.\n',sourcePath:"agent-framework-private/agents/git-investigator.md",allowedTools:["Bash","Read","Grep","Glob"],description:"Read-only git specialist. Dispatched by research-agent (or any research-shaped caller) when a finding requires git history, reflog, diff, blame, branch/remote state, or merge-base analysis. Runs git commands only \u2014 no mutations, no shell escapes.",model:"sonnet"};function gn(t){let e={description:t.description,prompt:t.systemPrompt};return t.allowedTools&&(e.tools=[...t.allowedTools]),t.model&&(e.model=t.model),e}var Tt=Da(Ma),Jr=S.object({id:S.string(),claim:S.string(),confidence:S.number().min(0).max(1),evidence_sources:S.array(S.string()),location:S.string().optional(),proposed_fix:S.string().optional(),coverage_gaps:S.array(S.string()).optional(),boundary_flag:S.string().optional()}),Fa=S.object({hypothesis_id:S.string(),claim:S.string(),verdict:S.enum(["VERIFIED","REFUTED","INCONCLUSIVE"]),evidence:S.string(),gate_reason:S.string()}),Yr=S.object({hypothesis_id:S.string(),reproducer_passed:S.boolean(),regressions:S.array(S.string()),confidence:S.number().min(0).max(1),verification_log:S.string()}),La=S.enum(["crash","regression","logic-error","flaky","environment","unknown"]),Na=S.object({failure_type:La,error_signature:S.string(),affected_area:S.string()}),$a=S.enum(["clear_winner","multiple_plausible","dissent","all_inconclusive","no_hypotheses"]),ch=S.object({reproducer:S.string().optional(),triage:Na.optional(),hypotheses:S.array(Jr),premise_verifications:S.array(Fa).optional(),winner:S.object({hypothesis_id:S.string(),verification_log:S.string(),proposed_fix:S.string()}).optional(),verification_results:S.array(Yr).optional(),outcome:$a.optional(),recommended_next_skill:S.enum(["spec"]).optional()});async function Ua(t,e){let n=t.map(c=>({hypothesis:c,decision:Kr(c)})).filter(c=>c.decision.verify);if(n.length===0)return{premise_verifications:[],hypotheses_to_test:t};let r=[],o;try{r=await e(n.map(c=>c.hypothesis.claim))}catch(c){o=c instanceof Error?c.message:String(c)}let s=n.map((c,l)=>{let d=r[l];return o!==void 0?{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:"INCONCLUSIVE",evidence:`shadow-verify dispatch failed: ${o}`,gate_reason:c.decision.reason}:d?{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:d.verdict,evidence:d.evidence,gate_reason:c.decision.reason}:{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:"INCONCLUSIVE",evidence:"no verifier result for this claim",gate_reason:c.decision.reason}}),i=new Set(s.filter(c=>c.verdict==="REFUTED").map(c=>c.hypothesis_id)),a=i.size===0?t:t.filter(c=>!i.has(c.id));return{premise_verifications:s,hypotheses_to_test:a}}async function ja(t,e,n){let r=n?.apiKey,o=(()=>{if(typeof t=="string")return{failure:t,repoPath:process.cwd(),context:"",maxHypotheses:4};if(typeof t=="object"&&t!==null){let M=t;if(typeof M.failure=="string")return{failure:M.failure,repoPath:M.repoPath||process.cwd(),context:M.context||"",maxHypotheses:Math.min(M.maxHypotheses||4,4)}}throw new Error("diagnose handler requires input.failure (string) or a string argument")})();if(!e?.sessionId)throw new Error("diagnose requires a parent session with sessionId");let s=e.sessionId,i=L("diagnose"),a=i["system.md"],c=i["research.md"],l=i["hypothesis.md"],d=i["verify.md"];if(!a||!c||!l||!d)throw new Error("diagnose skill missing required prompts (system.md, research.md, hypothesis.md, verify.md)");let u=new E({apiKey:r}),p=Ga(o.context),f=Ha(o.failure,o.context),h=`Triage:
1007
1007
  failure_type: ${f.failure_type}
1008
1008
  error_signature: ${f.error_signature}
@@ -1034,7 +1034,7 @@ ${JSON.stringify(N.git,null,2)}
1034
1034
 
1035
1035
  Original failure: ${o.failure}`,R;try{R=await D.runToResult(T)}finally{await D.teardown().catch(()=>{})}if(R.status!=="succeeded"||!R.output){if(R.schemaError){let M=R.message?.content||"(no response)";throw new Error(`hypothesis synthesis schema mismatch: ${R.schemaError.message}
1036
1036
  Raw response (first 500 chars): ${M.slice(0,500)}
1037
- Hint: model response must include a fenced JSON block with a hypotheses array.`)}throw new Error(`hypothesis synthesis failed: ${F(R)}`)}let A=R.output.hypotheses.slice(0,o.maxHypotheses);if(A.length===0)return{reproducer:p,triage:f,hypotheses:[],verification_results:[],outcome:"no_hypotheses"};let{premise_verifications:G,hypotheses_to_test:v}=await Ua(A,async M=>{if(!n?.dispatchSkill)throw new Error("shadow-verify dispatch unavailable (no dispatchSkill in ctx)");let ve=JSON.stringify({claims:M,context:`Original failure: ${o.failure}`}),Ci=await n.dispatchSkill("shadow-verify",ve);return JSON.parse(Ci).verifications});if(v.length===0)return{reproducer:p,triage:f,hypotheses:A,premise_verifications:G,verification_results:[],outcome:"no_hypotheses"};let x=p||o.failure,I=v.map(M=>qa(M,x,o.repoPath,s,d,u,b)),P=await Promise.all(I),$=P.filter(M=>M.reproducer_passed&&M.regressions.length===0).slice().sort((M,ve)=>ve.confidence-M.confidence)[0]??P.find(M=>M.reproducer_passed),Z=Wa(A,P),ue=$?A.find(M=>M.id===$.hypothesis_id):void 0,K=Z==="clear_winner"&&ue&&Ba(ue)?"spec":void 0;return{reproducer:p,triage:f,hypotheses:A,premise_verifications:G.length>0?G:void 0,winner:$?{hypothesis_id:$.hypothesis_id,verification_log:$.verification_log,proposed_fix:ue?.proposed_fix||""}:void 0,verification_results:P,outcome:Z,recommended_next_skill:K}}function Ha(t,e){let n=`${t}
1037
+ Hint: model response must include a fenced JSON block with a hypotheses array.`)}throw new Error(`hypothesis synthesis failed: ${F(R)}`)}let A=R.output.hypotheses.slice(0,o.maxHypotheses);if(A.length===0)return{reproducer:p,triage:f,hypotheses:[],verification_results:[],outcome:"no_hypotheses"};let{premise_verifications:G,hypotheses_to_test:v}=await Ua(A,async M=>{if(!n?.dispatchSkill)throw new Error("shadow-verify dispatch unavailable (no dispatchSkill in ctx)");let ve=JSON.stringify({claims:M,context:`Original failure: ${o.failure}`}),Ci=await n.dispatchSkill("shadow-verify",ve);return JSON.parse(Ci).verifications});if(v.length===0)return{reproducer:p,triage:f,hypotheses:A,premise_verifications:G,verification_results:[],outcome:"no_hypotheses"};let x=p||o.failure,I=v.map(M=>qa(M,x,o.repoPath,s,d,u,b)),P=await Promise.all(I),$=P.filter(M=>M.reproducer_passed&&M.regressions.length===0).slice().sort((M,ve)=>ve.confidence-M.confidence)[0]??P.find(M=>M.reproducer_passed),Z=Wa(A,P),ue=$?A.find(M=>M.id===$.hypothesis_id):void 0,q=Z==="clear_winner"&&ue&&Ba(ue)?"spec":void 0;return{reproducer:p,triage:f,hypotheses:A,premise_verifications:G.length>0?G:void 0,winner:$?{hypothesis_id:$.hypothesis_id,verification_log:$.verification_log,proposed_fix:ue?.proposed_fix||""}:void 0,verification_results:P,outcome:Z,recommended_next_skill:q}}function Ha(t,e){let n=`${t}
1038
1038
  ${e}`,r="unknown",o=n.toLowerCase();/flaky|non-?deterministic|intermittent|sometimes fails|race/.test(o)?r="flaky":/regression|used to work|worked before|broke in|ci.*green.*red|was passing/.test(o)?r="regression":/\b(uncaught|unhandled)\b|panic|segfault|exit(ed)? (with )?(code )?[1-9]|sigsegv|stack overflow|fatal|traceback|core dumped|abort(ed)?|\b(type|reference|range|syntax|internal|eval|uri)error\b/.test(o)?r="crash":/platform|node version|python version|dependency|version mismatch|works on .* not |env(ironment)?|config drift/.test(o)?r="environment":/expected .* but|got .* expected|wrong|incorrect|unexpected/.test(o)&&(r="logic-error");let s=t.split(`
1039
1039
  `).map(l=>l.trim()).find(l=>l.length>0),i=s?s.length>200?`${s.slice(0,197)}...`:s:"unknown",c=n.match(/(?:^|[\s'"`(])((?:\.{1,2}\/)?[\w@./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|java|kt|cpp|c|h|hpp|md|json|yaml|yml)(?::\d+(?::\d+)?)?)/)?.[1]??"unknown";return{failure_type:r,error_signature:i,affected_area:c}}function Ba(t){let n=`${t.proposed_fix??""}
1040
1040
  ${t.location??""}`.match(/(?:^|[\s'"`(])((?:\.{1,2}\/)?[\w@./-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|java|kt|cpp|c|h|hpp))/g);return n?new Set(n.map(o=>o.trim().replace(/^[\s'"`(]+/,"").split(":")[0])).size>2:!1}function Wa(t,e){if(t.length===0)return"no_hypotheses";let n=e.filter(o=>o.reproducer_passed&&o.regressions.length===0);return n.length===1?"clear_winner":n.length>=2?"multiple_plausible":t.filter(o=>o.confidence>=.7).length>=2?"dissent":"all_inconclusive"}function Ga(t){if(!t)return;let e=[/test:\s*(.+)/i,/command:\s*(.+)/i,/reproducer:\s*(.+)/i,/failing test:\s*(.+)/i];for(let n of e){let r=t.match(n);if(r)return r[1]}}function zr(){return async t=>V.allowedTools.includes(t)?{behavior:"allow"}:{behavior:"deny",message:`Tool ${t} not allowed. Allowed tools: ${V.allowedTools.join(", ")}`}}var Vr=[...V.allowedTools,"Agent"];function Ka(){return async t=>Vr.includes(t)?{behavior:"allow"}:{behavior:"deny",message:`Tool ${t} not allowed for git orchestrator. Allowed tools: ${Vr.join(", ")}`}}async function qa(t,e,n,r,o,s,i){let a=qr(Oa(),`diagnose-hyp-${t.id}-${Date.now()}`),c;try{await Tt("git",["worktree","add","--detach",a,"HEAD"],{cwd:n});try{let{writeFile:u}=await import("node:fs/promises"),p="",f="";try{p=(await Tt("git",["rev-parse","HEAD"],{cwd:n})).stdout.trim()}catch{}try{f=(await Tt("git",["symbolic-ref","--short","HEAD"],{cwd:n})).stdout.trim()}catch{}await u(qr(a,".afk-worktree-meta.json"),JSON.stringify({owner:"diagnose",createdAt:new Date().toISOString(),baseSha:p,baseBranch:f},null,2),"utf-8")}catch{}c=await s.forkSubagent({parent:{sessionId:r},config:{model:"sonnet",systemPrompt:`${o}
@@ -1294,7 +1294,7 @@ Be skeptical. Protect the plugin from fluff. Stage 2 catches patterns that are s
1294
1294
 
1295
1295
  ${y}`);if(N.status!=="succeeded")throw new Error(`skill generation failed: ${F(N)}`);let D=N.message?.content||"";if(!D)throw new Error("skill generation returned no output");for(let T=1;T<=c;T++){let R=yn.systemPrompt;if(!R)throw new Error("qualify agent missing system prompt");let v=await(await new E({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:R},idPrefix:`forge-qualify-${T}`,...o?{parentId:o}:{}})).runToResult(`Evaluate this amplifier skill against the force-multiplier criteria:
1296
1296
 
1297
- ${D}`);if(v.status!=="succeeded")throw new Error(`qualify iteration ${T} failed: ${F(v)}`);let x=v.message?.content||"",{verdict:I,score:P,feedback:q}=oo(x),$={iteration:T,verdict:I,score:P,feedback:q};if(d.push($),l=await Y({event:"forge.qualify_iteration",iteration:T,verdict:I,score:P||null}),I==="APPROVE"){u="APPROVED";break}else if(I==="SALVAGE"&&T<c){let Z=b["qualify-rework.md"];if(!Z)throw new Error("forge skill missing qualify-rework.md prompt");let ue=Z.replace("{feedback}",q).replace("{original_skill}",D),ve=await(await new E({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:ue},idPrefix:`forge-rework-${T}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(ve.status!=="succeeded")throw new Error(`rework iteration ${T} failed: ${F(ve)}`);if(D=ve.message?.content||"",!D)throw new Error(`rework iteration ${T} returned no output`)}else I==="REJECT"&&T>=c&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let T=Tc(D);if(!T.ok)throw l=await Y({event:"forge.write_failed",reason:T.reason,skill_name_attempted:T.skillNameAttempted}),new Error(`forge write-step invariant failed (${T.reason}): ${T.message}`);let R=T.skillName,A=Ec(R,{skillsDir:ht(),registeredSkills:ut()});if(A)throw l=await Y({event:"forge.write_failed",reason:A.reason,skill_name_attempted:A.skillNameAttempted}),new Error(`forge write-step invariant failed (${A.reason}): ${A.message}`);let G=ie(ht(),R);await so(G,{recursive:!0});let v=ie(G,"SKILL.md");await io(v,D,"utf-8");let x;try{x=await pc(v,"utf-8")}catch{x=""}if(!x.startsWith("---"))throw l=await Y({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:R}),new Error(`forge write-step invariant failed (readback_failed): written file at ${v} did not read back with expected frontmatter`);p=v,k&&f&&await bn(f,"consumed"),l=await Y({event:"forge.complete",status:"APPROVED",skill_name:R,iterations:d.length})}else u==="MAX_ITERATIONS"&&(k&&f&&await bn(f,"failed"),l=await Y({event:"forge.complete",status:"MAX_ITERATIONS",iterations:d.length}))}catch(h){throw l=await Y({event:"forge.error",error:h instanceof Error?h.message:String(h)}),h}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:l}}var _c={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:Ac,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};z(_c);import Cn from"path";import{appendFileSync as Ud,mkdirSync as jd}from"fs";import{dirname as Hd}from"path";import wn from"path";import{appendFileSync as Kc,mkdirSync as qc}from"fs";import{dirname as zc}from"path";function qe(t,e){return e?.allowedTools?e.allowedTools.includes(t)?{allowed:!0}:{allowed:!1,reason:`Tool "${t}" is not in the configured allowlist`}:{allowed:!0}}var Rc={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},Pc={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},Ic={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},Cc={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},Mc={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},Dc={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},Oc={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},Fc={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},Lc={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},ge={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1297
+ ${D}`);if(v.status!=="succeeded")throw new Error(`qualify iteration ${T} failed: ${F(v)}`);let x=v.message?.content||"",{verdict:I,score:P,feedback:K}=oo(x),$={iteration:T,verdict:I,score:P,feedback:K};if(d.push($),l=await Y({event:"forge.qualify_iteration",iteration:T,verdict:I,score:P||null,feedback:K||null}),I==="APPROVE"){u="APPROVED";break}else if(I==="SALVAGE"&&T<c){let Z=b["qualify-rework.md"];if(!Z)throw new Error("forge skill missing qualify-rework.md prompt");let ue=Z.replace("{feedback}",K).replace("{original_skill}",D),ve=await(await new E({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:ue},idPrefix:`forge-rework-${T}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(ve.status!=="succeeded")throw new Error(`rework iteration ${T} failed: ${F(ve)}`);if(D=ve.message?.content||"",!D)throw new Error(`rework iteration ${T} returned no output`)}else I==="REJECT"&&T>=c&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let T=Tc(D);if(!T.ok)throw l=await Y({event:"forge.write_failed",reason:T.reason,skill_name_attempted:T.skillNameAttempted}),new Error(`forge write-step invariant failed (${T.reason}): ${T.message}`);let R=T.skillName,A=Ec(R,{skillsDir:ht(),registeredSkills:ut()});if(A)throw l=await Y({event:"forge.write_failed",reason:A.reason,skill_name_attempted:A.skillNameAttempted}),new Error(`forge write-step invariant failed (${A.reason}): ${A.message}`);let G=ie(ht(),R);await so(G,{recursive:!0});let v=ie(G,"SKILL.md");await io(v,D,"utf-8");let x;try{x=await pc(v,"utf-8")}catch{x=""}if(!x.startsWith("---"))throw l=await Y({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:R}),new Error(`forge write-step invariant failed (readback_failed): written file at ${v} did not read back with expected frontmatter`);p=v,k&&f&&await bn(f,"consumed"),l=await Y({event:"forge.complete",status:"APPROVED",skill_name:R,iterations:d.length})}else u==="MAX_ITERATIONS"&&(k&&f&&await bn(f,"failed"),l=await Y({event:"forge.complete",status:"MAX_ITERATIONS",skill_name_attempted:y||null,iterations:d.length}))}catch(h){throw l=await Y({event:"forge.error",error:h instanceof Error?h.message:String(h)}),h}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:l}}var _c={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:Ac,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};z(_c);import Cn from"path";import{appendFileSync as Ud,mkdirSync as jd}from"fs";import{dirname as Hd}from"path";import wn from"path";import{appendFileSync as Kc,mkdirSync as qc}from"fs";import{dirname as zc}from"path";function qe(t,e){return e?.allowedTools?e.allowedTools.includes(t)?{allowed:!0}:{allowed:!1,reason:`Tool "${t}" is not in the configured allowlist`}:{allowed:!0}}var Rc={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},Pc={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},Ic={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},Cc={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},Mc={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},Dc={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},Oc={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},Fc={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},Lc={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},ge={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1298
1298
 
1299
1299
  Parallelize: dispatch multiple \`agent\` calls in a single tool-use turn to run independent investigations concurrently.
1300
1300
 
package/dist/telegram.mjs CHANGED
@@ -1075,7 +1075,7 @@ Don't refuse the flow; just clarify where the wizard runs.
1075
1075
  Be terse and operational. The user is doing one-time setup; they want it done, not narrated. Confirm each step in one line, don't over-explain. Use \`\u2713\` for success, \`\u2717\` for failure, and code fences for any command they should run.
1076
1076
  `}};function $(t){let e=Ko[t];if(!e){let n=Object.keys(Ko).sort(),r=n.length>0?"Available: "+n.join(", "):"";throw new Error("Unknown skill: "+t+". "+r)}return e}var jt=new Map;function Y(t){jt.set(t.name,t)}function le(t){let e=jt.get(t);if(e)return e;let n=Array.from(jt.keys()).sort(),r=n.length>0?`
1077
1077
  Available skills: ${n.join(", ")}`:"";throw new Error(`Skill not found: ${t}${r}`)}function Ht(){return Array.from(jt.keys()).sort()}var Bt=class{nodes=new Map;traceWriter;constructor(e){this.traceWriter=e}register(e,n){this.nodes.has(e)||this.nodes.set(e,{controller:n,children:new Set,listeners:new Set,cascading:!1})}has(e){return this.nodes.has(e)}getController(e){return this.nodes.get(e)?.controller}linkChild(e,n){let r=this.nodes.get(e),o=this.nodes.get(n);if(!r)throw new Error(`AbortGraph: parent ${e} not registered`);if(!o)throw new Error(`AbortGraph: child ${n} not registered`);if(o.parentId=e,r.children.add(n),r.controller.signal.aborted){o.controller.signal.aborted||(o.cascading=!0,o.controller.abort(r.controller.signal.reason));return}r.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);!s||s.parentId!==e||s.controller.signal.aborted||(s.cascading=!0,s.controller.abort(r.controller.signal.reason))},{once:!0}),o.controller.signal.addEventListener("abort",()=>{let s=this.nodes.get(n);if(!s||s.parentId!==e||s.cascading)return;let i=this.nodes.get(e);if(!i)return;let a={parentId:e,childId:n,reason:s.controller.signal.reason};for(let c of i.listeners)try{c(a)}catch{}},{once:!0})}onChildAborted(e,n){let r=this.nodes.get(e);if(!r)throw new Error(`AbortGraph: ${e} not registered`);return r.listeners.add(n),()=>{r.listeners.delete(n)}}abort(e,n,r="user_signal"){let o=this.nodes.get(e);if(!o||o.controller.signal.aborted)return;let s=[],i=[...o.children],a=new Set;for(;i.length;){let c=i.shift();if(a.has(c))continue;a.add(c);let l=this.nodes.get(c);if(l){l.cascading=!0,s.push(c);for(let d of l.children)i.push(d)}}Lo(this.traceWriter,{origin:r,cascadedTo:s,...n!==void 0?{reason:ll(n)}:{}}),o.controller.abort(n);for(let c of s){let l=this.nodes.get(c);l&&!l.controller.signal.aborted&&l.controller.abort(n)}}dispose(e){let n=this.nodes.get(e);if(n){n.parentId&&this.nodes.get(n.parentId)?.children.delete(e);for(let r of n.children){let o=this.nodes.get(r);o&&(o.parentId=void 0)}this.nodes.delete(e)}}};function ll(t){if(typeof t=="string")return t;if(t instanceof Error)return t.message;try{return JSON.stringify(t)}catch{return String(t)}}var Wt=0,jn=5e3;async function Gt(t,e,n={}){if(!Number.isFinite(e)||e<=0)return t;let r,o=new Promise((s,i)=>{r=setTimeout(()=>{let a=n.label?` (${n.label})`:"",c=new ae(`Operation timed out after ${e}ms${a}`,e);n.controller&&!n.controller.signal.aborted&&n.controller.abort(c),i(c)},e)});try{return await Promise.race([t,o])}finally{r!==void 0&&clearTimeout(r)}}async function be(t,e,n,r){if(!t)return;if(r.kind==="blocked"){await Ue(t,{hookEvent:e,decision:"block",...r.err.reason!==void 0?{reason:r.err.reason}:{},...e==="PreToolUse"&&n.toolName!==void 0?{blockedTool:n.toolName}:{}});return}let o=r.decision;await Ue(t,{hookEvent:e,decision:o.decision,...o.reason!==void 0?{reason:o.reason}:{},...o.injectContext!==void 0?{injectedContextBytes:Buffer.byteLength(o.injectContext,"utf8")}:{}})}async function qo(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await be(n.traceWriter,"SubagentStart",{},{kind:"decision",decision:r})}catch(r){throw r instanceof B&&await be(n.traceWriter,"SubagentStart",{},{kind:"blocked",err:r}),r}}async function zo(t,e,n={}){if(!t)return{};try{let r=await t.dispatch(e,n.signal);return await be(n.traceWriter,"SubagentStop",{},{kind:"decision",decision:r}),r}catch(r){return r instanceof B&&await be(n.traceWriter,"SubagentStop",{},{kind:"blocked",err:r}),r instanceof B||r instanceof Z?(C(`SubagentStop hook swallowed ${r.name}: ${r.message}`),n.onError?.(r),{}):(C(`SubagentStop hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r))),{})}}async function Hn(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await be(n.traceWriter,"PreToolUse",{toolName:e.toolName},{kind:"decision",decision:r})}catch(r){throw r instanceof B&&await be(n.traceWriter,"PreToolUse",{toolName:e.toolName},{kind:"blocked",err:r}),r}}async function Jo(t,e,n={}){if(t)try{let r=await t.dispatch(e,n.signal);await be(n.traceWriter,"PostToolUse",{toolName:e.toolName},{kind:"decision",decision:r})}catch(r){if(r instanceof B&&await be(n.traceWriter,"PostToolUse",{toolName:e.toolName},{kind:"blocked",err:r}),r instanceof B||r instanceof Z){C(`PostToolUse hook swallowed ${r.name}: ${r.message}`),n.onError?.(r);return}C(`PostToolUse hook unexpected error: ${String(r)}`),n.onError?.(r instanceof Error?r:new Error(String(r)))}}import{mkdir as dl,writeFile as ul}from"fs/promises";import{dirname as pl,join as fl}from"path";function ml(){return fl(xe(),"routing-decisions.jsonl")}async function ee(t){if(!(process.env.VITEST||process.env.NODE_ENV==="test"))try{let e=ml();await dl(pl(e),{recursive:!0});let r={ts:new Date().toISOString().split(".")[0]+"Z",surface:"afk"};for(let[s,i]of Object.entries(t))i!==void 0&&(r[s]=i);let o=JSON.stringify(r)+`
1078
- `;await ul(e,o,{flag:"a"})}catch{}}function Vo(t){let e=gl(t);return e!==void 0?e:hl(t)}function gl(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return Yo(n.trim())}function hl(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=yl(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=Yo(r);if(o!==void 0)return o}}function yl(t,e){let n=0,r=!1,o=!1;for(let s=e;s>=0;s--){let i=t[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function Yo(t){try{return JSON.parse(t)}catch{return}}function Bn(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function Xo(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=Vo(n.content),i=r.safeParse(s);return i.success?{id:t,status:e,message:n,output:i.data,trace:o}:{id:t,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function Qo(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function j(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}function Zo(t,e){let n=t;return e.partialOutput!==void 0&&e.partialOutput!==null&&(n.partialOutput=e.partialOutput),e.subagentId!==void 0&&(n.subagentId=e.subagentId),n}var Kt=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f,g){this.id=e;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=c;this.parentInputStreamRef=l;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=g;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=Bn();lastStreamedContent="";get status(){return this.currentStatus}async run(e){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=Gt(this.streamToFinalMessage(e),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",Ee(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(Ee(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(Ee(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r;this.lastStreamedContent="",this.currentTrace=Bn();let o=this.progressSink??oe(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(e)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return Xo(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=Qo(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(e,n){this.runToResult(e).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",Ee(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async teardown(){if(this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async dispatchStopAndRelease(e){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await zo(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)C(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){C(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var P=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,this.parentBaseUrl=e.baseUrl,this.parentCwd=e.cwd,this.abortGraph=new Bt(e.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),e.parentAbortSignal){let n=e.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(e=>({id:e.id,status:e.status}))}get(e){return this.active.get(e)}onChildAborted(e){return this.abortGraph.onChildAborted(this.rootId,e)}abortAll(e,n="user_signal"){this.abortGraph.abort(this.rootId,e,n)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await qo(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal,...e.config.traceWriter?{traceWriter:e.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...e.config,resume:r,forkSession:r?!0:e.config.forkSession,abortSignal:s.signal,apiKey:e.config.apiKey||this.parentApiKey,baseUrl:e.config.baseUrl??this.parentBaseUrl,...e.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:e.config.hookRegistry??this.hookRegistry,permissionBubbler:e.config.permissionBubbler??(this.parentCanUseTool!==void 0&&e.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new we(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??oe(),u=e.agentType?.trim()||void 0,p=e.parentId?.trim()||void 0,f=new Kt(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Wt,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,u??e.idPrefix,d,p??e.parent.sessionId,e.config.traceWriter);this.active.set(n,f);let g=typeof e.config.model=="string"?e.config.model:JSON.stringify(e.config.model);return Ee(e.config.traceWriter,{transition:"started",subagentId:n,parentId:e.parent.sessionId??this.rootId,model:g,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await ee({event:"subagent.dispatched",subagent_id:n,id_prefix:e.idPrefix,parent_session_id:e.parent.sessionId}),f}async kill(e){let n=this.active.get(e);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(e=>e.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(e=>e.teardown()))}};async function qt(t,e={}){let{failFast:n=!0,teardown:r=!0}=e;if(t.length===0)return[];let o=new Array(t.length),s=new Set(t.map((a,c)=>c)),i=t.map((a,c)=>a.handle.runToResult(a.prompt).then(l=>{if(o[c]=l,s.delete(c),n&&l.status!=="succeeded")for(let d of s){let u=t[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(t.map(a=>a.handle.teardown())),o}import{fileURLToPath as bl}from"node:url";import{dirname as wl}from"node:path";var kl=bl(import.meta.url),Xy=wl(kl),X={name:"research-agent",systemPrompt:`---
1078
+ `;await ul(e,o,{flag:"a"})}catch{}}function Vo(t){let e=gl(t);return e!==void 0?e:hl(t)}function gl(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return Yo(n.trim())}function hl(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=yl(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=Yo(r);if(o!==void 0)return o}}function yl(t,e){let n=0,r=!1,o=!1;for(let s=e;s>=0;s--){let i=t[s];if(o){o=!1;continue}if(r){if(i==="\\"){o=!0;continue}i==='"'&&(r=!1);continue}if(i==='"'){r=!0;continue}if(i==="}")n++;else if(i==="{"&&(n--,n===0))return s}return-1}function Yo(t){try{return JSON.parse(t)}catch{return}}function Bn(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function Xo(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=Vo(n.content),i=r.safeParse(s);return i.success?{id:t,status:e,message:n,output:i.data,trace:o}:{id:t,status:"failed",message:n,error:new Error(`structured output did not match schema: ${i.error.message}`,{cause:i.error}),schemaError:i.error,trace:o}}function Qo(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function j(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}function Zo(t,e){let n=t;return e.partialOutput!==void 0&&e.partialOutput!==null&&(n.partialOutput=e.partialOutput),e.subagentId!==void 0&&(n.subagentId=e.subagentId),n}var Kt=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f,g){this.id=e;this.session=n;this.controller=r;this.abortGraph=o;this.outputSchema=s;this.timeoutMs=i;this.hookRegistry=a;this.onTerminal=c;this.parentInputStreamRef=l;this.parentAbortSignal=d;this.agentType=u;this.traceWriter=g;this.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;traceWriter;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=Bn();lastStreamedContent="";get status(){return this.currentStatus}async run(e){if(this.currentStatus==="running")throw new Error(`Subagent ${this.id} is already running`);if(this.currentStatus==="cancelled")throw new Error(`Subagent ${this.id} is cancelled`);this.currentStatus="running";let n=Date.now(),r=Gt(this.streamToFinalMessage(e),this.timeoutMs,{controller:this.controller,label:this.id});this.inFlight=r;try{let o=await r;return this.lastMessage=o.content,this.lastDurationMs=Date.now()-n,this.currentStatus="succeeded",this.latestTerminalStatus="succeeded",Ee(this.traceWriter,{transition:"succeeded",subagentId:this.id,durationMs:this.lastDurationMs,turnCount:this.currentTrace.turnCount,outputBytes:Buffer.byteLength(this.lastMessage,"utf8")}),this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.controller.signal.aborted?(Ee(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"cascade"}),this.currentStatus="cancelled",this.latestTerminalStatus="cancelled"):(Ee(this.traceWriter,{transition:"failed",subagentId:this.id,errorClass:o instanceof Error?o.constructor.name:"Unknown",errorMessage:o instanceof Error?o.message:String(o),partialOutputBytes:Buffer.byteLength(this.lastStreamedContent,"utf8")}),this.currentStatus="failed",this.latestTerminalStatus="failed")),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r;this.lastStreamedContent="",this.currentTrace=Bn();let o=this.progressSink??oe(),s={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let i of this.session.sendMessageStream(e)){if(o&&o(i,s),i.type==="chunk"){let a=i.chunk;a.type==="content"?this.lastStreamedContent+=a.content:a.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:a.toolUseId,name:a.toolName,inputBytes:Buffer.byteLength(a.toolInput,"utf8")}):a.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:a.toolUseId,isError:a.isError,truncated:a.truncated,sizeBytes:a.sizeBytes}):a.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(i.type==="message")n=i.message,this.currentTrace.turnCount++;else if(i.type==="error"){r=i.error;break}else if(i.type==="done"){if(typeof i.metadata?.usage=="object"&&i.metadata.usage!==null){let a=i.metadata.usage;this.currentTrace.usage={inputTokens:typeof a.input_tokens=="number"?a.input_tokens:void 0,outputTokens:typeof a.output_tokens=="number"?a.output_tokens:void 0,cacheReadTokens:typeof a.cache_read_input_tokens=="number"?a.cache_read_input_tokens:void 0,cacheCreationTokens:typeof a.cache_creation_input_tokens=="number"?a.cache_creation_input_tokens:void 0}}break}}if(r)throw r;if(n)return n;if(this.lastStreamedContent.length>0)return{role:"assistant",content:this.lastStreamedContent,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return Xo(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){let r=Qo(this.id,this.currentStatus,n,this.currentTrace);return this.lastStreamedContent.length>0&&(r.partialOutput=this.lastStreamedContent),r}}runInBackground(e,n){this.runToResult(e).then(r=>{n?.(r)})}async cancel(){if(this.currentStatus==="cancelled"||this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";this.currentStatus="cancelled",Ee(this.traceWriter,{transition:"cancelled",subagentId:this.id,source:"explicit"});try{this.abortGraph.abort(this.id,"cancelled")}catch{}try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async teardown(){if(this.stopDispatched)return;let e=this.latestTerminalStatus??"cancelled";try{this.inFlight&&await this.session.interrupt()}catch{}try{await this.session.close()}finally{await this.dispatchStopAndRelease(e)}}async dispatchStopAndRelease(e){if(this.stopDispatched){this.onTerminal();return}this.stopDispatched=!0;let n=await zo(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace},this.traceWriter?{traceWriter:this.traceWriter}:{});if(n.injectContext&&this.parentInputStreamRef)if(this.parentAbortSignal?.aborted)C(`Skipping SubagentStop injectContext for ${this.id}: parent is aborted`);else try{this.parentInputStreamRef.pushUserMessage(n.injectContext)}catch(r){C(`Failed to inject context from SubagentStop handler: ${String(r)}`)}this.onTerminal()}};var P=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;parentBaseUrl;parentCwd;abortGraph;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,this.parentBaseUrl=e.baseUrl,this.parentCwd=e.cwd,this.abortGraph=new Bt(e.traceWriter),this.rootId=`manager-root-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,this.rootController=new AbortController,this.abortGraph.register(this.rootId,this.rootController),e.parentAbortSignal){let n=e.parentAbortSignal;n.aborted?this.rootController.abort(n.reason):n.addEventListener("abort",()=>{this.rootController.signal.aborted||this.rootController.abort(n.reason)},{once:!0})}}list(){return[...this.active.values()].map(e=>({id:e.id,status:e.status}))}get(e){return this.active.get(e)}onChildAborted(e){return this.abortGraph.onChildAborted(this.rootId,e)}abortAll(e,n="user_signal"){this.abortGraph.abort(this.rootId,e,n)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await qo(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal,...e.config.traceWriter?{traceWriter:e.config.traceWriter}:{}});let s=new AbortController;this.abortGraph.register(n,s),this.abortGraph.linkChild(this.rootId,n);let i={...e.config,resume:r,forkSession:r?!0:e.config.forkSession,abortSignal:s.signal,apiKey:e.config.apiKey||this.parentApiKey,baseUrl:e.config.baseUrl??this.parentBaseUrl,...e.config.cwd===void 0&&this.parentCwd!==void 0?{cwd:this.parentCwd}:{},hookRegistry:e.config.hookRegistry??this.hookRegistry,permissionBubbler:e.config.permissionBubbler??(this.parentCanUseTool!==void 0&&e.config.canUseTool===void 0?{canUseTool:this.parentCanUseTool}:void 0)},a=new we(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??oe(),u=e.agentType?.trim()||void 0,p=e.parentId?.trim()||void 0,f=new Kt(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Wt,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,u??e.idPrefix,d,p??e.parent.sessionId,e.config.traceWriter);this.active.set(n,f);let g=typeof e.config.model=="string"?e.config.model:JSON.stringify(e.config.model);return Ee(e.config.traceWriter,{transition:"started",subagentId:n,parentId:e.parent.sessionId??this.rootId,model:g,...i.tools?.allowedTools?{allowedTools:[...i.tools.allowedTools]}:{}}),await ee({event:"subagent.dispatched",subagent_id:n,id_prefix:e.idPrefix,model:g,parent_session_id:e.parent.sessionId}),f}async kill(e){let n=this.active.get(e);return n?(await n.cancel(),!0):!1}async killAll(){await Promise.allSettled([...this.active.values()].map(e=>e.cancel()))}async teardownAll(){await Promise.allSettled([...this.active.values()].map(e=>e.teardown()))}};async function qt(t,e={}){let{failFast:n=!0,teardown:r=!0}=e;if(t.length===0)return[];let o=new Array(t.length),s=new Set(t.map((a,c)=>c)),i=t.map((a,c)=>a.handle.runToResult(a.prompt).then(l=>{if(o[c]=l,s.delete(c),n&&l.status!=="succeeded")for(let d of s){let u=t[d];u&&u.handle.status==="running"&&u.handle.cancel().catch(()=>{})}}));return await Promise.all(i),r&&await Promise.allSettled(t.map(a=>a.handle.teardown())),o}import{fileURLToPath as bl}from"node:url";import{dirname as wl}from"node:path";var kl=bl(import.meta.url),Xy=wl(kl),X={name:"research-agent",systemPrompt:`---
1079
1079
  name: research-agent
1080
1080
  description: Read-only sub-agent for research, validation, verification, and codebase inspection. Mechanically locked to Read, Grep, Glob, WebFetch, WebSearch \u2014 cannot Edit, Write, Bash, commit, or push. Delegates git queries to \`git-investigator\`. Use when the dispatched task is findings-only.
1081
1081
  model: sonnet
@@ -1135,9 +1135,9 @@ If \`scope_check\` flags implementation (non-git), the orchestrator should dispa
1135
1135
  ${Fl(E)}`,artifacts:E,runPrompt:`Inspect every ${v} listed in the artifact section.`})}if(l.runHookInspector){let v=p.hook;if(v){let E=Kn(J(),"settings.json"),M=as(E);h.push({type:"hook",prompt:`${v}
1136
1136
  ${Ll(E,M)}`,artifacts:[],runPrompt:`Inspect every hook listed in the Discovered hooks section. Settings file: ${E}.`})}}let y=[];if(h.length>0){let v=await Promise.all(h.map(D=>w.forkSubagent({parent:{sessionId:d},config:{model:"sonnet",systemPrompt:`${X.systemPrompt}
1137
1137
 
1138
- ${D.prompt}`,canUseTool:b()},idPrefix:`inspector-${D.type}`,outputSchema:U.array(us),...o?{parentId:o}:{}}))),E=await qt(h.map((D,K)=>{let L=v[K];if(!L)throw new Error(`audit-fit: missing handle for ${D.type} inspector`);return{handle:L,prompt:D.runPrompt}}),{failFast:!1}),M=[];for(let D=0;D<E.length;D++){let K=E[D],L=h[D];if(!L)continue;let z=Nl(L.type,K);if(z.kind==="failure"){M.push(z.message);continue}let re=new Map;for(let W of L.artifacts)re.set(W.path,W.source);for(let W of z.output){if(L.type==="hook"){if(W.source!=="user"){M.push(`${L.type}: hook verdict has source=${W.source} (must be 'user')`);continue}}else{let O=re.get(W.path);if(O===void 0){M.push(`${L.type}: verdict for unknown path ${W.path} (not in discovered list)`);continue}if(W.source!==O){M.push(`${L.type}: verdict source mismatch for ${W.path} (expected ${O}, got ${W.source})`);continue}}y.push(W)}}if(M.length>0){let D=M.map(K=>` - ${K}`).join(`
1138
+ ${D.prompt}`,canUseTool:b()},idPrefix:`inspector-${D.type}`,outputSchema:U.array(us),...o?{parentId:o}:{}}))),E=await qt(h.map((D,G)=>{let L=v[G];if(!L)throw new Error(`audit-fit: missing handle for ${D.type} inspector`);return{handle:L,prompt:D.runPrompt}}),{failFast:!1}),M=[];for(let D=0;D<E.length;D++){let G=E[D],L=h[D];if(!L)continue;let z=Nl(L.type,G);if(z.kind==="failure"){M.push(z.message);continue}let re=new Map;for(let W of L.artifacts)re.set(W.path,W.source);for(let W of z.output){if(L.type==="hook"){if(W.source!=="user"){M.push(`${L.type}: hook verdict has source=${W.source} (must be 'user')`);continue}}else{let O=re.get(W.path);if(O===void 0){M.push(`${L.type}: verdict for unknown path ${W.path} (not in discovered list)`);continue}if(W.source!==O){M.push(`${L.type}: verdict source mismatch for ${W.path} (expected ${O}, got ${W.source})`);continue}}y.push(W)}}if(M.length>0){let D=M.map(G=>` - ${G}`).join(`
1139
1139
  `);throw new Error(`audit-fit: ${M.length} inspector failure(s):
1140
- ${D}`)}}let{inventory:k,misfits:_}=Dl(y),I=0;if(a){let v=Oe();await cs(v,{recursive:!0});for(let E of _.filter(Ol)){let M=E.path.replace(/[^a-z0-9]+/gi,"-").toLowerCase().slice(0,30),D=Kn(v,`audit-fit-${M}.md`),K=`---
1140
+ ${D}`)}}let{inventory:k,misfits:_}=Dl(y),I=0;if(a){let v=Oe();await cs(v,{recursive:!0});for(let E of _.filter(Ol)){let M=E.path.replace(/[^a-z0-9]+/gi,"-").toLowerCase().slice(0,30),D=Kn(v,`audit-fit-${M}.md`),G=`---
1141
1141
  theme: audit-fit
1142
1142
  session_count: 1
1143
1143
  ---
@@ -1159,7 +1159,7 @@ ${E.rationale}
1159
1159
 
1160
1160
  ---
1161
1161
  Generated by audit-fit on ${new Date().toISOString().split(".")[0]}Z
1162
- `;await ls(D,K),I++}}let S=xe();await cs(S,{recursive:!0});let x=v=>{let E=0;for(let M of Object.values(v))for(let D of Object.values(M))E+=D;return E},A=v=>{let E=k.user[v]??{},M=k.plugin[v]??{},D=K=>Object.values(K).reduce((L,z)=>L+z,0);return D(E)+D(M)},R={timestamp:new Date().toISOString(),surface:"afk",scope:c,total_artifacts:y.length,misfits_count:_.length,briefs_written:I,by_source:{user:x(k.user),plugin:x(k.plugin)},by_type:{skill:A("skill"),command:A("command"),agent:A("agent"),hook:A("hook")}},F=Kn(S,"audit-fit-telemetry.jsonl");return await ls(F,JSON.stringify(R)+`
1162
+ `;await ls(D,G),I++}}let S=xe();await cs(S,{recursive:!0});let x=v=>{let E=0;for(let M of Object.values(v))for(let D of Object.values(M))E+=D;return E},A=v=>{let E=k.user[v]??{},M=k.plugin[v]??{},D=G=>Object.values(G).reduce((L,z)=>L+z,0);return D(E)+D(M)},R={timestamp:new Date().toISOString(),surface:"afk",scope:c,total_artifacts:y.length,misfits_count:_.length,briefs_written:I,by_source:{user:x(k.user),plugin:x(k.plugin)},by_type:{skill:A("skill"),command:A("command"),agent:A("agent"),hook:A("hook")}},F=Kn(S,"audit-fit-telemetry.jsonl");return await ls(F,JSON.stringify(R)+`
1163
1163
  `),{inventory:k,misfits:_,briefs_written:I,total_artifacts:y.length}}var Ul={name:"audit-fit",description:"Audit ~/.afk artifacts (skills, commands, agents, hooks) for correct type categorization. Walks user-scope dirs (~/.afk/{skills,commands,agents}/) and every plugin installed under ~/.afk/plugins/ (flat and marketplace-cache layouts), plus ~/.afk/settings.json for hooks. Dispatches per-type inspectors in parallel, applies decision heuristics (progressive-disclosure value, isolation need, deterministic vs. reasoning), flags misfits. Generates migration briefs only for user-scope misfits (plugin misfits are inventory-only \u2014 refactoring vendored plugin code is the maintainer's job). Optional `scope` input filters to `user`, `plugin`, or `all` (default). Use for inventory audits after bulk authoring, imports, or periodic hygiene.",handler:$l,argumentHint:"[--write-briefs]",whenToUse:"When the user wants ~/.afk artifacts (skills, commands, agents, hooks) audited for correct type categorization.",flags:["--write-briefs"]};Y(Ul);import{z as T}from"zod";import{execFile as Wl}from"node:child_process";import{promisify as Gl}from"node:util";import{tmpdir as Kl}from"node:os";import{join as ms}from"node:path";function fs(t){return t.confidence<.5?{verify:!0,reason:`low confidence (${t.confidence.toFixed(2)} < ${.5})`}:t.boundary_flag&&t.boundary_flag.length>0?{verify:!0,reason:`boundary flag set: ${t.boundary_flag}`}:t.coverage_gaps&&t.coverage_gaps.length>0?{verify:!0,reason:`coverage gap${t.coverage_gaps.length===1?"":"s"}: ${t.coverage_gaps.length} unresolved`}:{verify:!1,reason:`confidence ${t.confidence.toFixed(2)} with no gaps or boundary`}}import{fileURLToPath as jl}from"node:url";import{dirname as Hl}from"node:path";var Bl=jl(import.meta.url),Mb=Hl(Bl),qn={name:"git-investigator",systemPrompt:'---\nname: git-investigator\ndescription: Read-only git specialist. Dispatched by research-agent (or any research-shaped caller) when a finding requires git history, reflog, diff, blame, branch/remote state, or merge-base analysis. Runs git commands only \u2014 no mutations, no shell escapes.\nmodel: sonnet\ntools: Bash, Read, Grep, Glob\n---\n\nYou are `git-investigator`, a leaf sub-agent specialized for read-only git queries.\n\nYou have Bash, Read, Grep, and Glob. You do not dispatch other sub-agents. You do not Edit or Write. Your Bash surface is restricted **by this prompt** to `git ...` invocations and benign output-shaping pipes.\n\n## Allowed commands\n\nRead-only git only:\n\n- `git status`, `git log`, `git diff`, `git show`\n- `git rev-parse`, `git rev-list`, `git reflog`\n- `git branch -v / -vv / -a` (list only)\n- `git remote -v`, `git ls-remote`\n- `git ls-files`, `git blame`\n- `git merge-base`, `git for-each-ref`, `git describe`\n- `git cat-file`, `git shortlog`\n- `git tag` (list/show only)\n- `git stash list`, `git stash show`\n- `git config --get`, `git config --get-all`, `git config --list`\n- `git worktree list` (read only)\n\nOutput-shaping pipes are fine: `| head`, `| tail`, `| wc`, `| grep`, `| jq`, `| awk \'NR==...\'` (for formatting only \u2014 no mutations).\n\n## Forbidden\n\nAnything that mutates repo or working tree state:\n\n- `commit`, `push`, `pull`, `fetch --prune`\n- `reset`, `revert`, `rebase`, `merge`, `cherry-pick`\n- `checkout` (except `checkout -- <path>` file-restore, and even that is mutation \u2014 avoid it, just report the need)\n- `restore`, `switch`\n- `branch -d / -D / -m / -M`, `branch <new>`\n- `stash push / pop / drop / apply / clear`\n- `tag -d`, creating a new tag\n- `remote add / remove / set-url`\n- `config --set`, `config --unset`\n- `gc`, `fsck`, `prune`, `reflog delete`, `reflog expire`\n- `filter-branch`, `filter-repo`\n- `worktree add / remove / move`\n- `hooks install`, `submodule add / update`\n- Any non-`git` command that mutates: `rm`, `mv`, `cp` (writes), `sed -i`, `> file`, `>> file`, `tee`, `curl`, `wget`, `pip install`, shell builtins that change state.\n\nIf the caller asks for any of the above, do not run it. Return `scope_check: "requires mutation: <reason>"` and stop.\n\n## Behavior\n\n- Run the minimum set of commands needed. Prefer `git log -n 5 --oneline -- <path>` over `git log -- <path>` when a count is fine.\n- Cite concrete evidence: commit SHAs (short form OK), ref names, `path:line` references from blame, diff hunks trimmed to the relevant range.\n- Use `Read`/`Grep`/`Glob` for follow-up inspection of files the git output identifies (e.g., `git show SHA:path | head` then `Read` the current file to diff mentally).\n- Do not speculate beyond what the commands show. If a question needs history the commands don\'t surface (deleted-file recovery, ancient reflog that has expired), say so in `caveats`.\n- Keep output compact \u2014 dispatchers merge your findings into a larger response. No preamble, no ceremony.\n\n## Return shape\n\n```\n{\n "findings": "<summary of what the git data shows>",\n "evidence": ["<SHA>", "<ref>", "<path:line>", ...],\n "git_commands_run": ["git log ...", "git diff ...", ...],\n "caveats": "<gaps, ambiguity, or \'none\'>",\n "scope_check": "pure git research" | "requires mutation: <reason>"\n}\n```\n\nBegin your response with the first schema field. No preamble.\n',sourcePath:"agent-framework-private/agents/git-investigator.md",allowedTools:["Bash","Read","Grep","Glob"],description:"Read-only git specialist. Dispatched by research-agent (or any research-shaped caller) when a finding requires git history, reflog, diff, blame, branch/remote state, or merge-base analysis. Runs git commands only \u2014 no mutations, no shell escapes.",model:"sonnet"};function zn(t){let e={description:t.description,prompt:t.systemPrompt};return t.allowedTools&&(e.tools=[...t.allowedTools]),t.model&&(e.model=t.model),e}var Vt=Gl(Wl),ys=T.object({id:T.string(),claim:T.string(),confidence:T.number().min(0).max(1),evidence_sources:T.array(T.string()),location:T.string().optional(),proposed_fix:T.string().optional(),coverage_gaps:T.array(T.string()).optional(),boundary_flag:T.string().optional()}),ql=T.object({hypothesis_id:T.string(),claim:T.string(),verdict:T.enum(["VERIFIED","REFUTED","INCONCLUSIVE"]),evidence:T.string(),gate_reason:T.string()}),bs=T.object({hypothesis_id:T.string(),reproducer_passed:T.boolean(),regressions:T.array(T.string()),confidence:T.number().min(0).max(1),verification_log:T.string()}),zl=T.enum(["crash","regression","logic-error","flaky","environment","unknown"]),Jl=T.object({failure_type:zl,error_signature:T.string(),affected_area:T.string()}),Vl=T.enum(["clear_winner","multiple_plausible","dissent","all_inconclusive","no_hypotheses"]),Vb=T.object({reproducer:T.string().optional(),triage:Jl.optional(),hypotheses:T.array(ys),premise_verifications:T.array(ql).optional(),winner:T.object({hypothesis_id:T.string(),verification_log:T.string(),proposed_fix:T.string()}).optional(),verification_results:T.array(bs).optional(),outcome:Vl.optional(),recommended_next_skill:T.enum(["spec"]).optional()});async function Yl(t,e){let n=t.map(c=>({hypothesis:c,decision:fs(c)})).filter(c=>c.decision.verify);if(n.length===0)return{premise_verifications:[],hypotheses_to_test:t};let r=[],o;try{r=await e(n.map(c=>c.hypothesis.claim))}catch(c){o=c instanceof Error?c.message:String(c)}let s=n.map((c,l)=>{let d=r[l];return o!==void 0?{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:"INCONCLUSIVE",evidence:`shadow-verify dispatch failed: ${o}`,gate_reason:c.decision.reason}:d?{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:d.verdict,evidence:d.evidence,gate_reason:c.decision.reason}:{hypothesis_id:c.hypothesis.id,claim:c.hypothesis.claim,verdict:"INCONCLUSIVE",evidence:"no verifier result for this claim",gate_reason:c.decision.reason}}),i=new Set(s.filter(c=>c.verdict==="REFUTED").map(c=>c.hypothesis_id)),a=i.size===0?t:t.filter(c=>!i.has(c.id));return{premise_verifications:s,hypotheses_to_test:a}}async function Xl(t,e,n){let r=n?.apiKey,o=(()=>{if(typeof t=="string")return{failure:t,repoPath:process.cwd(),context:"",maxHypotheses:4};if(typeof t=="object"&&t!==null){let O=t;if(typeof O.failure=="string")return{failure:O.failure,repoPath:O.repoPath||process.cwd(),context:O.context||"",maxHypotheses:Math.min(O.maxHypotheses||4,4)}}throw new Error("diagnose handler requires input.failure (string) or a string argument")})();if(!e?.sessionId)throw new Error("diagnose requires a parent session with sessionId");let s=e.sessionId,i=$("diagnose"),a=i["system.md"],c=i["research.md"],l=i["hypothesis.md"],d=i["verify.md"];if(!a||!c||!l||!d)throw new Error("diagnose skill missing required prompts (system.md, research.md, hypothesis.md, verify.md)");let u=new P({apiKey:r}),p=td(o.context),f=Ql(o.failure,o.context),g=`Triage:
1164
1164
  failure_type: ${f.failure_type}
1165
1165
  error_signature: ${f.error_signature}
@@ -1451,7 +1451,7 @@ Be skeptical. Protect the plugin from fluff. Stage 2 catches patterns that are s
1451
1451
 
1452
1452
  ${m}`);if(I.status!=="succeeded")throw new Error(`skill generation failed: ${j(I)}`);let S=I.message?.content||"";if(!S)throw new Error("skill generation returned no output");for(let x=1;x<=c;x++){let A=Jn.systemPrompt;if(!A)throw new Error("qualify agent missing system prompt");let v=await(await new P({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:A},idPrefix:`forge-qualify-${x}`,...o?{parentId:o}:{}})).runToResult(`Evaluate this amplifier skill against the force-multiplier criteria:
1453
1453
 
1454
- ${S}`);if(v.status!=="succeeded")throw new Error(`qualify iteration ${x} failed: ${j(v)}`);let E=v.message?.content||"",{verdict:M,score:D,feedback:K}=_s(E),L={iteration:x,verdict:M,score:D,feedback:K};if(d.push(L),l=await te({event:"forge.qualify_iteration",iteration:x,verdict:M,score:D||null}),M==="APPROVE"){u="APPROVED";break}else if(M==="SALVAGE"&&x<c){let z=b["qualify-rework.md"];if(!z)throw new Error("forge skill missing qualify-rework.md prompt");let re=z.replace("{feedback}",K).replace("{original_skill}",S),Se=await(await new P({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:re},idPrefix:`forge-rework-${x}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(Se.status!=="succeeded")throw new Error(`rework iteration ${x} failed: ${j(Se)}`);if(S=Se.message?.content||"",!S)throw new Error(`rework iteration ${x} returned no output`)}else M==="REJECT"&&x>=c&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let x=Fd(S);if(!x.ok)throw l=await te({event:"forge.write_failed",reason:x.reason,skill_name_attempted:x.skillNameAttempted}),new Error(`forge write-step invariant failed (${x.reason}): ${x.message}`);let A=x.skillName,R=Ld(A,{skillsDir:gt(),registeredSkills:Ht()});if(R)throw l=await te({event:"forge.write_failed",reason:R.reason,skill_name_attempted:R.skillNameAttempted}),new Error(`forge write-step invariant failed (${R.reason}): ${R.message}`);let F=pe(gt(),A);await As(F,{recursive:!0});let v=pe(F,"SKILL.md");await Rs(v,S,"utf-8");let E;try{E=await xd(v,"utf-8")}catch{E=""}if(!E.startsWith("---"))throw l=await te({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:A}),new Error(`forge write-step invariant failed (readback_failed): written file at ${v} did not read back with expected frontmatter`);p=v,w&&f&&await Vn(f,"consumed"),l=await te({event:"forge.complete",status:"APPROVED",skill_name:A,iterations:d.length})}else u==="MAX_ITERATIONS"&&(w&&f&&await Vn(f,"failed"),l=await te({event:"forge.complete",status:"MAX_ITERATIONS",iterations:d.length}))}catch(g){throw l=await te({event:"forge.error",error:g instanceof Error?g.message:String(g)}),g}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:l}}var $d={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:Nd,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};Y($d);import ar from"path";import{appendFileSync as Mp,mkdirSync as Dp}from"fs";import{dirname as Op}from"path";import Xn from"path";import{appendFileSync as Qd,mkdirSync as Zd}from"fs";import{dirname as eu}from"path";function Yn(t,e){return e?.allowedTools?e.allowedTools.includes(t)?{allowed:!0}:{allowed:!1,reason:`Tool "${t}" is not in the configured allowlist`}:{allowed:!0}}var Ud={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},jd={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},Hd={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},Bd={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},Wd={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},Gd={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},Kd={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},qd={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},zd={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},Ae={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1454
+ ${S}`);if(v.status!=="succeeded")throw new Error(`qualify iteration ${x} failed: ${j(v)}`);let E=v.message?.content||"",{verdict:M,score:D,feedback:G}=_s(E),L={iteration:x,verdict:M,score:D,feedback:G};if(d.push(L),l=await te({event:"forge.qualify_iteration",iteration:x,verdict:M,score:D||null,feedback:G||null}),M==="APPROVE"){u="APPROVED";break}else if(M==="SALVAGE"&&x<c){let z=b["qualify-rework.md"];if(!z)throw new Error("forge skill missing qualify-rework.md prompt");let re=z.replace("{feedback}",G).replace("{original_skill}",S),Se=await(await new P({apiKey:r}).forkSubagent({parent:{sessionId:e.sessionId},config:{model:"sonnet",systemPrompt:re},idPrefix:`forge-rework-${x}`,...o?{parentId:o}:{}})).runToResult("Refine the skill based on the feedback.");if(Se.status!=="succeeded")throw new Error(`rework iteration ${x} failed: ${j(Se)}`);if(S=Se.message?.content||"",!S)throw new Error(`rework iteration ${x} returned no output`)}else M==="REJECT"&&x>=c&&(u="MAX_ITERATIONS")}if(u==="APPROVED"){let x=Fd(S);if(!x.ok)throw l=await te({event:"forge.write_failed",reason:x.reason,skill_name_attempted:x.skillNameAttempted}),new Error(`forge write-step invariant failed (${x.reason}): ${x.message}`);let A=x.skillName,R=Ld(A,{skillsDir:gt(),registeredSkills:Ht()});if(R)throw l=await te({event:"forge.write_failed",reason:R.reason,skill_name_attempted:R.skillNameAttempted}),new Error(`forge write-step invariant failed (${R.reason}): ${R.message}`);let F=pe(gt(),A);await As(F,{recursive:!0});let v=pe(F,"SKILL.md");await Rs(v,S,"utf-8");let E;try{E=await xd(v,"utf-8")}catch{E=""}if(!E.startsWith("---"))throw l=await te({event:"forge.write_failed",reason:"readback_failed",skill_name_attempted:A}),new Error(`forge write-step invariant failed (readback_failed): written file at ${v} did not read back with expected frontmatter`);p=v,w&&f&&await Vn(f,"consumed"),l=await te({event:"forge.complete",status:"APPROVED",skill_name:A,iterations:d.length})}else u==="MAX_ITERATIONS"&&(w&&f&&await Vn(f,"failed"),l=await te({event:"forge.complete",status:"MAX_ITERATIONS",skill_name_attempted:m||null,iterations:d.length}))}catch(g){throw l=await te({event:"forge.error",error:g instanceof Error?g.message:String(g)}),g}return{status:u,skill_path:p,qualify_verdicts:d,brief_id:f,telemetry_ref:l}}var $d={name:"forge",description:'Creates new amplifier skills gated by forge-gate-check, with autonomous gap discovery, skill generation, and qualify iteration loop \u22643\xD7. Writes approved skills and appends telemetry to shared JSONL with surface: "afk".',handler:Nd,argumentHint:"[--brief <path>]",whenToUse:"When the user wants to grow the plugin with a new amplifier skill \u2014 autonomously generates and validates one.",flags:["--brief"]};Y($d);import ar from"path";import{appendFileSync as Mp,mkdirSync as Dp}from"fs";import{dirname as Op}from"path";import Xn from"path";import{appendFileSync as Qd,mkdirSync as Zd}from"fs";import{dirname as eu}from"path";function Yn(t,e){return e?.allowedTools?e.allowedTools.includes(t)?{allowed:!0}:{allowed:!1,reason:`Tool "${t}" is not in the configured allowlist`}:{allowed:!0}}var Ud={name:"bash",category:"shell",concurrencySafe:!1,description:"Execute a shell command and return its stdout and stderr. Use for running programs, installing packages, git operations, and any task that requires a shell. Commands run in the user's default shell. Long-running commands should use timeout_ms. Output is capped at ~100KB; excess is truncated with a notice.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds (default 120000, max 600000). The command is killed if it exceeds this duration."}},required:["command"]}},jd={name:"read_file",category:"read",concurrencySafe:!0,description:"Read a file from the filesystem. Returns the file content with line numbers. Use offset and limit to read specific sections of large files. When the read returns a partial view, the response ends with a `... (showing lines X-Y of Z [\u2014 pass offset=N to continue])` annotation indicating the full file size and how to continue. Binary files are detected and rejected. Missing files return an error.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to read."},offset:{type:"number",description:"Line number to start reading from (1-based). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to read. Defaults to 2000."}},required:["file_path"]}},Hd={name:"write_file",category:"write",concurrencySafe:!1,description:"Write content to a file, creating it if it does not exist or overwriting if it does. Parent directories are created automatically. Prefer edit_file for modifying existing files \u2014 use write_file only for new files or complete rewrites.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to write."},content:{type:"string",description:"The full content to write to the file."}},required:["file_path","content"]}},Bd={name:"edit_file",category:"write",concurrencySafe:!1,description:"Perform an exact string replacement in a file. Finds old_string and replaces it with new_string. The edit fails if old_string is not found or matches multiple locations (unless replace_all is true). Always use read_file first to verify the exact content before editing.",input_schema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to the file to edit."},old_string:{type:"string",description:"The exact string to find and replace. Must match file content exactly."},new_string:{type:"string",description:"The replacement string."},replace_all:{type:"boolean",description:"If true, replace all occurrences. If false (default), fail when multiple matches exist."}},required:["file_path","old_string","new_string"]}},Wd={name:"glob",category:"read",concurrencySafe:!0,description:'Find files matching a glob pattern. Returns matching file paths, capped at 500 results. Use for discovering files before reading them. Patterns follow standard glob syntax (e.g., "src/**/*.ts", "*.json").',input_schema:{type:"object",properties:{pattern:{type:"string",description:'Glob pattern to match (e.g., "src/**/*.ts").'},path:{type:"string",description:"Base directory to search from. Defaults to the current working directory."}},required:["pattern"]}},Gd={name:"grep",category:"read",concurrencySafe:!0,description:"Search file contents for lines matching a pattern. Returns matches in file:line:content format. Uses grep -rn (or ripgrep if available). Output is capped to prevent overflow. Use for finding symbols, strings, or patterns across the codebase.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Search pattern (basic regex by default)."},path:{type:"string",description:"Directory or file to search. Defaults to current working directory."},include:{type:"string",description:'File glob to restrict search (e.g., "*.ts"). Passed as --include to grep.'}},required:["pattern"]}},Kd={name:"list_directory",category:"read",concurrencySafe:!0,description:"List the contents of a directory. Returns file and subdirectory names with type annotations (directories end with /). Use for exploring project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Absolute path to the directory to list."}},required:["path"]}},qd={name:"send_telegram",category:"web",concurrencySafe:!1,riskClass:"caution",description:"Send a Telegram message to the operator. Use to surface terminal-state notifications, blocking questions, or important status updates when the user is away from keyboard (AFK). The message is delivered through the same Telegram bot the operator uses to drive this session, to every chat ID in `AFK_TELEGRAM_ALLOWED_CHAT_IDS` (typically just the operator).\n\nPlain text only \u2014 Telegram's 4096-character limit per message is enforced. Returns an error if Telegram is not configured (missing `TELEGRAM_BOT_TOKEN` or empty allowlist) so the tool is safe to attempt unconditionally.\n\nUse sparingly: this is a real push notification to a human. Reserve for terminal states (Done/Blocked/Asking) and material progress, not running commentary. When running inside the Telegram bot, prefer replying normally \u2014 your response already reaches the operator through the bot. Use this tool only from CLI or daemon sessions.",input_schema:{type:"object",properties:{message:{type:"string",description:"Plain-text message body to send to the operator. Max 4096 characters (Telegram API limit). Must be non-empty."}},required:["message"]}},zd={name:"web_scrape",category:"web",concurrencySafe:!0,description:'Scrape a web page or run a web search and return text content suitable for reasoning over. Three modes:\n\n- `markdown` (default): converts the target URL to clean markdown via Jina Reader (https://r.jina.ai). Handles JS-rendered pages because rendering happens server-side. Use this for articles, docs, blog posts, and most "I want to read this page" cases.\n- `raw`: GETs the URL directly with no transformation. Use for JSON APIs, robots.txt, RSS, plain-text endpoints, or when you need the literal bytes.\n- `search`: queries Jina Web Search (https://s.jina.ai) and returns ranked markdown results. Use when you need to FIND a URL, not read one. Provide `query` instead of `url`.\n\nIf `JINA_API_KEY` is set in the environment, it is sent as a bearer token to the two Jina-backed modes \u2014 anonymous requests work but are heavily rate-limited.\n\nOutputs are capped at `max_bytes` UTF-8 bytes (default 1MB, ceiling 10MB) and the request is aborted after `timeout_ms` (default 30000, ceiling 120000).',input_schema:{type:"object",properties:{mode:{type:"string",enum:["markdown","raw","search"],description:'Fetch mode. Defaults to "markdown".'},url:{type:"string",description:"Absolute http(s) URL. Required for markdown and raw modes. Ignored in search mode."},query:{type:"string",description:"Search query string. Required for search mode. Ignored otherwise."},timeout_ms:{type:"number",description:"Request timeout in milliseconds (default 30000, clamped to 120000)."},max_bytes:{type:"number",description:"Maximum UTF-8 bytes returned. Content beyond this is truncated with a marker. Default 1000000, clamped to 10000000."}},required:[]}},Ae={name:"agent",category:"subagent",concurrencySafe:!0,description:`Dispatch an independent subagent with its own context window and tool access. Use for tasks that protect the main session's context: codebase exploration, multi-file inspection, repo search, verification, debugging, failing-test investigation, PR review, parallel hypothesis testing, independent re-derivation of a claim, audit work, stale-path detection, feature-wiring checks, and any research-shaped investigation.
1455
1455
 
1456
1456
  Parallelize: dispatch multiple \`agent\` calls in a single tool-use turn to run independent investigations concurrently.
1457
1457
 
@@ -1486,21 +1486,21 @@ SECURITY NOTE: upstream node output injected into downstream prompts is user-con
1486
1486
  --
1487
1487
  ${d.content}`,isError:!0}),i.push({call:l,result:d}),yield{type:"tool.output",toolUseId:l.id,content:d.content,...d.isError===!0?{isError:!0}:{},sessionId:this.initSessionId}}}this.priorTurns.push(pi(e.assistantText,r));for(let a of fi(i))this.priorTurns.push(a)}async interrupt(){let e=this.abortController;if(e&&!e.signal.aborted){e.abort("interrupted");return}this.pendingAbortReason="interrupted"}async setModel(e){e!==void 0&&(this.currentModel=e)}async setPermissionMode(e){this.currentPermissionMode=mi(e)}async supportedCommands(){try{return Ce().map(n=>{let r={name:n.name,description:n.description};return n.argumentHint&&(r.argumentHint=n.argumentHint),r})}catch{return[]}}async supportedModels(){return[{value:"gpt-4o",displayName:"GPT-4o",description:"OpenAI flagship multimodal"},{value:"gpt-4o-mini",displayName:"GPT-4o mini",description:"Fast/cheap GPT-4o"},{value:"gpt-4.1",displayName:"GPT-4.1",description:"Long-context GPT-4"},{value:"gpt-4.1-mini",displayName:"GPT-4.1 mini",description:"Fast 4.1 variant"},{value:"o1",displayName:"o1",description:"Reasoning model"},{value:"o1-mini",displayName:"o1 mini",description:"Fast reasoning"},{value:"o3-mini",displayName:"o3 mini",description:"Newer reasoning, faster"}]}async supportedAgents(){return[]}async getContextUsage(){let e=this.lastUsage,n=sn(this.currentModel),r;if(e&&n>0){let o=(e.inputTokens??0)+(e.outputTokens??0)+(e.cachedInputTokens??0)+(e.cacheCreationTokens??0);r=Math.min(100,Math.max(0,o/n*100))}return{tools:[],agents:[],isAutoCompactEnabled:!1,apiUsage:this.lastUsage,...r!==void 0?{percentage:r}:{},maxTokens:n}}async mcpServerStatus(){return[]}async accountInfo(){return{authSource:this.opts.auth.source}}async rewindFiles(e,n){return{canRewind:!1,error:`${ir} provider does not support file checkpoint rewind yet.`}}close(){this.closed=!0;let e=this.abortController;e&&!e.signal.aborted?e.abort("closed"):this.pendingAbortReason="closed",this.closeResolve?.(),C(`\u{1F7E2} ${ir}: closed`)}};function Ip(t){let e={apiKey:t.apiKey};return t.baseURL!==void 0&&(e.baseURL=t.baseURL),new Ap(e)}function Cp(t){if(!t||typeof t!="object")return"";let e=t,n=e.file_path??e.path??e.filePath;if(typeof n=="string")return" "+n;let r=e.command??e.cmd;if(typeof r=="string"){let s=r.split(`
1488
1488
  `)[0];return" "+(s.length>80?s.slice(0,77)+"\u2026":s)}let o=e.query??e.pattern??e.url??e.description;return typeof o=="string"?" "+o:""}function gi(t,e,n={}){let r=or(t.apiKey),o=t.resume??`openai-pending-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s=typeof t.model=="string"?t.model:"gpt-4o-mini",i={auth:r,model:s,synthesizedSessionId:o,promptStream:e,config:t};return n.baseURL!==void 0&&(i.baseURL=n.baseURL),n.toolDispatcher!==void 0&&(i.toolDispatcher=n.toolDispatcher),new an(i)}var Fp="openai-compatible",Me=class{name=Fp;providerOpts;memoryStore;schemas;_sharedReadRoots;_sharedWriteRoots;_initialResolveBase;constructor(e={}){this.providerOpts=e,this.memoryStore=e.memoryStore??new V;let n=[...fe];e.subagentExecutor&&n.push(Ae),e.skillExecutor&&n.push(Re),e.composeExecutor&&n.push(Pe),n.push(...ge),this.schemas=n}query(e){let n=e.config,r=n.permissionMode??"default";this.ensureSharedRoots(n.cwd),n.readRoots&&this._sharedReadRoots&&this._sharedReadRoots.length<=1&&(this._sharedReadRoots.length=0,this._sharedReadRoots.push(...n.readRoots)),n.writeRoots&&this._sharedWriteRoots&&this._sharedWriteRoots.length<=1&&(this._sharedWriteRoots.length=0,this._sharedWriteRoots.push(...n.writeRoots));let o=this.providerOpts.tools??this.buildDispatcher(r,{...n.cwd!==void 0?{cwd:n.cwd}:{},...this._sharedReadRoots!==void 0?{readRoots:this._sharedReadRoots}:{},...this._sharedWriteRoots!==void 0?{writeRoots:this._sharedWriteRoots}:{},...n.sessionId!==void 0?{sessionId:n.sessionId}:{},...n.traceWriter!==void 0?{traceWriter:n.traceWriter}:{}}),s={};return this.providerOpts.baseURL!==void 0&&(s.baseURL=this.providerOpts.baseURL),s.toolDispatcher=o,gi(n,e.prompt,s)}buildDispatcher(e,n){let r=on(e,n.cwd),o=Ze(this.memoryStore,void 0,this.providerOpts.surface??"cli");for(let[i,a]of o)r.set(i,a);let s={handlers:r,schemas:[...this.schemas]};return this.providerOpts.hookRegistry!==void 0&&(s.hookRegistry=this.providerOpts.hookRegistry),this.providerOpts.permissions!==void 0&&(s.permissions=this.providerOpts.permissions),this.providerOpts.subagentExecutor!==void 0&&(s.subagentExecutor=this.providerOpts.subagentExecutor),this.providerOpts.skillExecutor!==void 0&&(s.skillExecutor=this.providerOpts.skillExecutor),this.providerOpts.composeExecutor!==void 0&&(s.composeExecutor=this.providerOpts.composeExecutor),n.cwd!==void 0&&(s.cwd=n.cwd),n.readRoots!==void 0&&(s.readRoots=n.readRoots),n.writeRoots!==void 0&&(s.writeRoots=n.writeRoots),n.sessionId!==void 0&&(s.sessionId=n.sessionId),n.traceWriter!==void 0&&(s.traceWriter=n.traceWriter),new Ie(s)}ensureSharedRoots(e){if(!this._sharedReadRoots){let n=e?[e]:[];this._sharedReadRoots=n.slice(),this._sharedWriteRoots=n.slice(),e&&!this._initialResolveBase&&(this._initialResolveBase=e)}}addReadRoot(e,n="slash",r){this.ensureSharedRoots();let o=ar.resolve(e);this._sharedReadRoots.includes(o)||this._sharedReadRoots.push(o),this.appendProviderAuditLog({action:"grant-read",path:o,source:n,sessionId:r})}addWriteRoot(e,n="slash",r){this.ensureSharedRoots();let o=ar.resolve(e);this._sharedReadRoots.includes(o)||this._sharedReadRoots.push(o),this._sharedWriteRoots.includes(o)||this._sharedWriteRoots.push(o),this.appendProviderAuditLog({action:"grant-write",path:o,source:n,sessionId:r})}revokeRoot(e,n="slash",r){if(!this._sharedReadRoots)return;let o=ar.resolve(e);if(this._initialResolveBase&&o===this._initialResolveBase)return;let s=this._sharedReadRoots.indexOf(o);if(s!==-1&&this._sharedReadRoots.splice(s,1),this._sharedWriteRoots){let i=this._sharedWriteRoots.indexOf(o);i!==-1&&this._sharedWriteRoots.splice(i,1)}this.appendProviderAuditLog({action:"revoke",path:o,source:n,sessionId:r})}getGrants(){return{resolveBase:this._initialResolveBase,readRoots:this._sharedReadRoots?.slice()??[],writeRoots:this._sharedWriteRoots?.slice()??[]}}appendProviderAuditLog(e){try{let n=Le();Dp(Op(n),{recursive:!0});let r=JSON.stringify({timestamp:new Date().toISOString(),sessionId:e.sessionId??null,action:e.action,path:e.path,source:e.source});Mp(n,r+`
1489
- `)}catch{}}close(){this.memoryStore.close()}},Lp=new Me;import{readFileSync as ki,existsSync as lr}from"fs";import{join as dn}from"path";import{config as jp}from"dotenv";var cn={opus:"claude-opus-4-7",opus_1m:"claude-opus-4-7",sonnet:"claude-sonnet-4-6",sonnet_1m:"claude-sonnet-4-6",haiku:"claude-haiku-4-5-20251001"};function ln(t){return t in cn}function hi(t){let e=cn[t];if(!e)throw new Error(`Invalid model: ${t}`);return e}function De(t){if(t!==void 0)return typeof t=="string"&&ln(t)?hi(t):t}import{execFile as Np}from"node:child_process";import{promisify as $p}from"node:util";var zv=$p(Np);var Up=/^[A-Za-z0-9_\-./]*$/,yi=64;function bi(t,e){if(t.length>yi)throw new Error(`Invalid branch prefix from ${e}: length ${t.length} exceeds ${yi}.`);if(!Up.test(t))throw new Error(`Invalid branch prefix from ${e}: '${t}' \u2014 only [A-Za-z0-9_-./] are allowed.`);if(t.startsWith("-"))throw new Error(`Invalid branch prefix from ${e}: '${t}' \u2014 must not start with '-' (would be parsed by git as a flag).`);return t}var ct={model:"sonnet",maxTokens:4096,temperature:1,updatePolicy:"notify"},wi=!1;function lt(){return process.env.ANTHROPIC_API_KEY||process.env.CLAUDE_CODE_OAUTH_TOKEN||ye()}var cr;function Hp(){if(cr!==void 0)return cr;if(!wi){let o=[dn(process.cwd(),".env"),Ye(),Or()];for(let s of o)lr(s)&&jp({path:s,override:!1});wi=!0}let t={},e=lt();e!==void 0&&(t.apiKey=e);let n=process.env.AFK_MODEL??process.env.CLAUDE_MODEL;if(n){let o=n.toLowerCase();t.model=ln(o)?o:n}let r=process.env.AFK_LOCAL_BASE_URL;if(r&&r.length>0&&(t.baseUrl=r,t.apiKey=process.env.AFK_LOCAL_API_KEY||"local"),process.env.AFK_MAX_TOKENS&&(t.maxTokens=parseInt(process.env.AFK_MAX_TOKENS,10)),process.env.AFK_TEMPERATURE&&(t.temperature=parseFloat(process.env.AFK_TEMPERATURE)),process.env.AFK_SYSTEM_PROMPT&&(t.systemPrompt=process.env.AFK_SYSTEM_PROMPT),process.env.AFK_AUTO_ROUTING){let o=process.env.AFK_AUTO_ROUTING.toLowerCase()==="true";t.autoRouting={interactive:o,chat:o,telegram:o,daemon:o}}return process.env.AFK_OPENAI_BASE_URL&&(t.openaiBaseUrl=process.env.AFK_OPENAI_BASE_URL),cr=t,t}var He,Be;function Bp(){if(He!==void 0)return He;let t=[dn(process.cwd(),"afk.config.json"),Dr(),Fr()];for(let e of t)if(lr(e))try{let n=ki(e,"utf-8"),r=JSON.parse(n),o={};if(typeof r.model=="string"&&r.model.length>0&&(o.model=(ln(r.model),r.model)),typeof r.maxTokens=="number"&&(o.maxTokens=r.maxTokens),typeof r.temperature=="number"&&(o.temperature=r.temperature),r.systemPrompt&&(o.systemPrompt=r.systemPrompt),r.autoRouting&&typeof r.autoRouting=="object"){let s={};typeof r.autoRouting.interactive=="boolean"&&(s.interactive=r.autoRouting.interactive),typeof r.autoRouting.chat=="boolean"&&(s.chat=r.autoRouting.chat),typeof r.autoRouting.telegram=="boolean"&&(s.telegram=r.autoRouting.telegram),typeof r.autoRouting.daemon=="boolean"&&(s.daemon=r.autoRouting.daemon),o.autoRouting=s}if(r.daemon&&typeof r.daemon=="object"){let s={};typeof r.daemon.task=="string"&&(s.task=r.daemon.task),typeof r.daemon.taskId=="string"&&(s.taskId=r.daemon.taskId);let i=r.daemon.worktreePrune;i&&typeof i=="object"&&(s.worktreePrune={enabled:typeof i.enabled=="boolean"?i.enabled:!0,cron:typeof i.cron=="string"?i.cron:"0 4 * * *",maxAgeDaysClean:typeof i.maxAgeDaysClean=="number"?i.maxAgeDaysClean:14,maxAgeDaysDirty:typeof i.maxAgeDaysDirty=="number"?i.maxAgeDaysDirty:30,scope:typeof i.scope=="string"?i.scope:"all"}),o.daemon=s}if(r.updatePolicy&&["notify","auto","off"].includes(r.updatePolicy)&&(o.updatePolicy=r.updatePolicy),typeof r.autoResumeOnUsageLimit=="boolean"&&(o.autoResumeOnUsageLimit=r.autoResumeOnUsageLimit),r.interactive&&typeof r.interactive=="object"){let s={};typeof r.interactive.worktreeAutoname=="boolean"&&(s.worktreeAutoname=r.interactive.worktreeAutoname),typeof r.interactive.worktreeBranchPrefix=="string"&&(s.worktreeBranchPrefix=bi(r.interactive.worktreeBranchPrefix,`${e}#/interactive/worktreeBranchPrefix`)),Object.keys(s).length>0&&(o.interactive=s)}return He={config:o,sourcePath:e},He}catch(n){console.error(`Warning: Failed to parse ${e}:`,n)}return He={config:{},sourcePath:void 0},He}function Wp(){if(Be!==void 0)return Be.value;let t=[dn(process.cwd(),"AFK.md"),dn(J(),"AFK.md")];for(let e of t)if(lr(e))try{let n=ki(e,"utf-8").trim();if(n.length>0)return Be={value:{content:n,path:e}},Be.value}catch{}return Be={value:null},Be.value}function dr(t){let e=Hp(),{config:n,sourcePath:r}=Bp(),o={...ct,...e,...n,...t},s;if(e.systemPrompt!==void 0)s="env:AFK_SYSTEM_PROMPT";else if(n.systemPrompt!==void 0&&r!==void 0)s=`file:${r}`;else if(o.systemPrompt===void 0){let a=Wp();a!==null&&(o.systemPrompt=a.content,s=`afk-md:${a.path}`)}let i={model:o.model??ct.model,maxTokens:o.maxTokens??ct.maxTokens,temperature:o.temperature??ct.temperature,updatePolicy:o.updatePolicy??ct.updatePolicy,...o.apiKey!==void 0?{apiKey:o.apiKey}:{},...o.baseUrl!==void 0?{baseUrl:o.baseUrl}:{},...o.openaiBaseUrl!==void 0?{openaiBaseUrl:o.openaiBaseUrl}:{},...o.systemPrompt!==void 0?{systemPrompt:o.systemPrompt}:{},...s!==void 0?{systemPromptSource:s}:{},...o.autoRouting!==void 0?{autoRouting:o.autoRouting}:{},...o.daemon!==void 0?{daemon:o.daemon}:{}};if(typeof i.model=="string"&&i.model.toLowerCase().startsWith("local-")&&(i.baseUrl===void 0||i.baseUrl.length===0))throw new Error(`Model '${i.model}' requires AFK_LOCAL_BASE_URL to be set (e.g. AFK_LOCAL_BASE_URL=http://127.0.0.1:8080). Point it at your local Anthropic-Messages-compatible server.`);return i}function G(){return lt()}function un(){let t=process.env.AFK_DEFAULT_SUBAGENT_MODEL;return!t||t.length===0?"sonnet":t}function Gp(t){if(t===void 0)return;if(t==="max")return Number.POSITIVE_INFINITY;if(t===""||t==="NaN")throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Expected a positive integer or 'max'.`);if(!/^\d+$/.test(t))throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Expected a positive integer or 'max'.`);let e=Number(t);if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Must be a positive integer.`);return e}function vi(){return Gp(process.env.AFK_MAX_OUTPUT_TOKENS)}async function Si(t,e,n,r){let s=$("mint")["spec.md"];if(!s)throw new Error("mint skill missing spec.md prompt");let c=await(await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:G()},idPrefix:"mint-spec",...r?{parentId:r}:{}})).runToResult(`Create a detailed specification for: ${t}`);if(c.status!=="succeeded"||!c.message)throw new Error(`spec phase failed: ${j(c)}`);return c.message.content}async function xi(t,e,n,r){let s=$("mint")["research.md"];if(!s)throw new Error("mint skill missing research.md prompt");let c=await(await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:G()},idPrefix:"mint-research",...r?{parentId:r}:{}})).runToResult(`Gather context and research for this specification:
1489
+ `)}catch{}}close(){this.memoryStore.close()}},Lp=new Me;import{readFileSync as ki,existsSync as lr}from"fs";import{join as dn}from"path";import{config as jp}from"dotenv";var cn={opus:"claude-opus-4-7",opus_1m:"claude-opus-4-7",sonnet:"claude-sonnet-4-6",sonnet_1m:"claude-sonnet-4-6",haiku:"claude-haiku-4-5-20251001"};function ln(t){return t in cn}function hi(t){let e=cn[t];if(!e)throw new Error(`Invalid model: ${t}`);return e}function De(t){if(t!==void 0)return typeof t=="string"&&ln(t)?hi(t):t}import{execFile as Np}from"node:child_process";import{promisify as $p}from"node:util";var zv=$p(Np);var Up=/^[A-Za-z0-9_\-./]*$/,yi=64;function bi(t,e){if(t.length>yi)throw new Error(`Invalid branch prefix from ${e}: length ${t.length} exceeds ${yi}.`);if(!Up.test(t))throw new Error(`Invalid branch prefix from ${e}: '${t}' \u2014 only [A-Za-z0-9_-./] are allowed.`);if(t.startsWith("-"))throw new Error(`Invalid branch prefix from ${e}: '${t}' \u2014 must not start with '-' (would be parsed by git as a flag).`);return t}var ct={model:"sonnet",maxTokens:4096,temperature:1,updatePolicy:"notify"},wi=!1;function lt(){return process.env.ANTHROPIC_API_KEY||process.env.CLAUDE_CODE_OAUTH_TOKEN||ye()}var cr;function Hp(){if(cr!==void 0)return cr;if(!wi){let o=[dn(process.cwd(),".env"),Ye(),Or()];for(let s of o)lr(s)&&jp({path:s,override:!1});wi=!0}let t={},e=lt();e!==void 0&&(t.apiKey=e);let n=process.env.AFK_MODEL??process.env.CLAUDE_MODEL;if(n){let o=n.toLowerCase();t.model=ln(o)?o:n}let r=process.env.AFK_LOCAL_BASE_URL;if(r&&r.length>0&&(t.baseUrl=r,t.apiKey=process.env.AFK_LOCAL_API_KEY||"local"),process.env.AFK_MAX_TOKENS&&(t.maxTokens=parseInt(process.env.AFK_MAX_TOKENS,10)),process.env.AFK_TEMPERATURE&&(t.temperature=parseFloat(process.env.AFK_TEMPERATURE)),process.env.AFK_SYSTEM_PROMPT&&(t.systemPrompt=process.env.AFK_SYSTEM_PROMPT),process.env.AFK_AUTO_ROUTING){let o=process.env.AFK_AUTO_ROUTING.toLowerCase()==="true";t.autoRouting={interactive:o,chat:o,telegram:o,daemon:o}}return process.env.AFK_OPENAI_BASE_URL&&(t.openaiBaseUrl=process.env.AFK_OPENAI_BASE_URL),cr=t,t}var He,Be;function Bp(){if(He!==void 0)return He;let t=[dn(process.cwd(),"afk.config.json"),Dr(),Fr()];for(let e of t)if(lr(e))try{let n=ki(e,"utf-8"),r=JSON.parse(n),o={};if(typeof r.model=="string"&&r.model.length>0&&(o.model=(ln(r.model),r.model)),typeof r.maxTokens=="number"&&(o.maxTokens=r.maxTokens),typeof r.temperature=="number"&&(o.temperature=r.temperature),r.systemPrompt&&(o.systemPrompt=r.systemPrompt),r.autoRouting&&typeof r.autoRouting=="object"){let s={};typeof r.autoRouting.interactive=="boolean"&&(s.interactive=r.autoRouting.interactive),typeof r.autoRouting.chat=="boolean"&&(s.chat=r.autoRouting.chat),typeof r.autoRouting.telegram=="boolean"&&(s.telegram=r.autoRouting.telegram),typeof r.autoRouting.daemon=="boolean"&&(s.daemon=r.autoRouting.daemon),o.autoRouting=s}if(r.daemon&&typeof r.daemon=="object"){let s={};typeof r.daemon.task=="string"&&(s.task=r.daemon.task),typeof r.daemon.taskId=="string"&&(s.taskId=r.daemon.taskId);let i=r.daemon.worktreePrune;i&&typeof i=="object"&&(s.worktreePrune={enabled:typeof i.enabled=="boolean"?i.enabled:!0,cron:typeof i.cron=="string"?i.cron:"0 4 * * *",maxAgeDaysClean:typeof i.maxAgeDaysClean=="number"?i.maxAgeDaysClean:14,maxAgeDaysDirty:typeof i.maxAgeDaysDirty=="number"?i.maxAgeDaysDirty:30,scope:typeof i.scope=="string"?i.scope:"all"}),o.daemon=s}if(r.updatePolicy&&["notify","auto","off"].includes(r.updatePolicy)&&(o.updatePolicy=r.updatePolicy),typeof r.autoResumeOnUsageLimit=="boolean"&&(o.autoResumeOnUsageLimit=r.autoResumeOnUsageLimit),r.interactive&&typeof r.interactive=="object"){let s={};typeof r.interactive.worktreeAutoname=="boolean"&&(s.worktreeAutoname=r.interactive.worktreeAutoname),typeof r.interactive.worktreeBranchPrefix=="string"&&(s.worktreeBranchPrefix=bi(r.interactive.worktreeBranchPrefix,`${e}#/interactive/worktreeBranchPrefix`)),Object.keys(s).length>0&&(o.interactive=s)}return He={config:o,sourcePath:e},He}catch(n){console.error(`Warning: Failed to parse ${e}:`,n)}return He={config:{},sourcePath:void 0},He}function Wp(){if(Be!==void 0)return Be.value;let t=[dn(process.cwd(),"AFK.md"),dn(J(),"AFK.md")];for(let e of t)if(lr(e))try{let n=ki(e,"utf-8").trim();if(n.length>0)return Be={value:{content:n,path:e}},Be.value}catch{}return Be={value:null},Be.value}function dr(t){let e=Hp(),{config:n,sourcePath:r}=Bp(),o={...ct,...e,...n,...t},s;if(e.systemPrompt!==void 0)s="env:AFK_SYSTEM_PROMPT";else if(n.systemPrompt!==void 0&&r!==void 0)s=`file:${r}`;else if(o.systemPrompt===void 0){let a=Wp();a!==null&&(o.systemPrompt=a.content,s=`afk-md:${a.path}`)}let i={model:o.model??ct.model,maxTokens:o.maxTokens??ct.maxTokens,temperature:o.temperature??ct.temperature,updatePolicy:o.updatePolicy??ct.updatePolicy,...o.apiKey!==void 0?{apiKey:o.apiKey}:{},...o.baseUrl!==void 0?{baseUrl:o.baseUrl}:{},...o.openaiBaseUrl!==void 0?{openaiBaseUrl:o.openaiBaseUrl}:{},...o.systemPrompt!==void 0?{systemPrompt:o.systemPrompt}:{},...s!==void 0?{systemPromptSource:s}:{},...o.autoRouting!==void 0?{autoRouting:o.autoRouting}:{},...o.daemon!==void 0?{daemon:o.daemon}:{}};if(typeof i.model=="string"&&i.model.toLowerCase().startsWith("local-")&&(i.baseUrl===void 0||i.baseUrl.length===0))throw new Error(`Model '${i.model}' requires AFK_LOCAL_BASE_URL to be set (e.g. AFK_LOCAL_BASE_URL=http://127.0.0.1:8080). Point it at your local Anthropic-Messages-compatible server.`);return i}function K(){return lt()}function un(){let t=process.env.AFK_DEFAULT_SUBAGENT_MODEL;return!t||t.length===0?"sonnet":t}function Gp(t){if(t===void 0)return;if(t==="max")return Number.POSITIVE_INFINITY;if(t===""||t==="NaN")throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Expected a positive integer or 'max'.`);if(!/^\d+$/.test(t))throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Expected a positive integer or 'max'.`);let e=Number(t);if(!Number.isFinite(e)||!Number.isInteger(e)||e<=0)throw new Error(`Invalid --max-output-tokens value: ${JSON.stringify(t)}. Must be a positive integer.`);return e}function vi(){return Gp(process.env.AFK_MAX_OUTPUT_TOKENS)}async function Si(t,e,n,r){let s=$("mint")["spec.md"];if(!s)throw new Error("mint skill missing spec.md prompt");let c=await(await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:K()},idPrefix:"mint-spec",...r?{parentId:r}:{}})).runToResult(`Create a detailed specification for: ${t}`);if(c.status!=="succeeded"||!c.message)throw new Error(`spec phase failed: ${j(c)}`);return c.message.content}async function xi(t,e,n,r){let s=$("mint")["research.md"];if(!s)throw new Error("mint skill missing research.md prompt");let c=await(await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:K()},idPrefix:"mint-research",...r?{parentId:r}:{}})).runToResult(`Gather context and research for this specification:
1490
1490
 
1491
- ${t}`);if(c.status!=="succeeded"||!c.message)throw new Error(`research phase failed: ${j(c)}`);return c.message.content}async function Ei(t,e,n,r,o){let i=$("mint")["plan.md"];if(!i)throw new Error("mint skill missing plan.md prompt");let c=await new P(r!==void 0?{cwd:r}:{}).forkSubagent({parent:{sessionId:n},config:{model:"sonnet",systemPrompt:i,apiKey:G()},idPrefix:"mint-plan",...o?{parentId:o}:{}}),l=`Specification:
1491
+ ${t}`);if(c.status!=="succeeded"||!c.message)throw new Error(`research phase failed: ${j(c)}`);return c.message.content}async function Ei(t,e,n,r,o){let i=$("mint")["plan.md"];if(!i)throw new Error("mint skill missing plan.md prompt");let c=await new P(r!==void 0?{cwd:r}:{}).forkSubagent({parent:{sessionId:n},config:{model:"sonnet",systemPrompt:i,apiKey:K()},idPrefix:"mint-plan",...o?{parentId:o}:{}}),l=`Specification:
1492
1492
  ${t}
1493
1493
 
1494
1494
  Research findings:
1495
1495
  ${e}
1496
1496
 
1497
- Create a detailed implementation plan based on the spec and research.`,d=await c.runToResult(l);if(d.status!=="succeeded"||!d.message)throw new Error(`plan phase failed: ${j(d)}`);return d.message.content}function Kp(t){let e=/[\w./@-]*\.(?:ts|tsx|js|jsx|mjs|cjs|py|md|json|yaml|yml|toml|sh)\b/gi,n=new Set;for(let r of t.matchAll(e))n.add(r[0].toLowerCase());return n.size}async function Ti(t,e,n){if(Kp(t)<3)return{kind:"skipped",reason:"too-few-files"};let o=!1;try{let s=le("parallelize");return o=!0,{kind:"plan",plan:await s.handler({plan:t})}}catch(s){if(o)return{kind:"failed",error:`parallelize skill handler threw: ${s instanceof Error?s.message:String(s)}`}}try{let i=pn().get("parallelize");if(!i)return{kind:"skipped",reason:"skill-body-missing"};let a=new P({parentAbortSignal:e.abortSignal,apiKey:G(),...e.cwd!==void 0?{cwd:e.cwd}:{}});try{let l=await(await a.forkSubagent({parent:e,config:{model:"sonnet",systemPrompt:i.body,env:{PLUGIN_ROOT:i.pluginPath}},idPrefix:"mint-parallelize",...n?{parentId:n}:{}})).runToResult(JSON.stringify({plan:t}));return l.status==="succeeded"&&l.message?{kind:"plan",plan:l.message.content}:l.status!=="succeeded"?{kind:"failed",error:`parallelize subagent status=${l.status}${l.error?.message?`: ${l.error.message}`:""}`}:{kind:"failed",error:"parallelize subagent returned no message"}}finally{await a.teardownAll()}}catch(s){return{kind:"failed",error:`parallelize dispatch threw: ${s instanceof Error?s.message:String(s)}`}}}import{z as me}from"zod";function Ge(t){let e=oe();e&&e({type:"panel",spec:t},{subagentId:"__main__"})}var qp=me.object({status:me.enum(["PASS","FAIL"]),status_reason:me.string().optional(),files_changed:me.array(me.string()),tests_passed:me.boolean(),build_passed:me.boolean().optional(),verification_passed:me.boolean().optional(),notes:me.string()});async function _i(t,e,n,r,o){let i=$("mint")["build.md"];if(!i)throw new Error("mint skill missing build.md prompt");let c=await new P(r!==void 0?{cwd:r}:{}).forkSubagent({parent:{sessionId:n},config:{model:"sonnet",systemPrompt:i,apiKey:G()},idPrefix:"mint-build",outputSchema:qp,...o?{parentId:o}:{}}),l=`Implementation plan:
1497
+ Create a detailed implementation plan based on the spec and research.`,d=await c.runToResult(l);if(d.status!=="succeeded"||!d.message)throw new Error(`plan phase failed: ${j(d)}`);return d.message.content}function Kp(t){let e=/[\w./@-]*\.(?:ts|tsx|js|jsx|mjs|cjs|py|md|json|yaml|yml|toml|sh)\b/gi,n=new Set;for(let r of t.matchAll(e))n.add(r[0].toLowerCase());return n.size}async function Ti(t,e,n){if(Kp(t)<3)return{kind:"skipped",reason:"too-few-files"};let o=!1;try{let s=le("parallelize");return o=!0,{kind:"plan",plan:await s.handler({plan:t})}}catch(s){if(o)return{kind:"failed",error:`parallelize skill handler threw: ${s instanceof Error?s.message:String(s)}`}}try{let i=pn().get("parallelize");if(!i)return{kind:"skipped",reason:"skill-body-missing"};let a=new P({parentAbortSignal:e.abortSignal,apiKey:K(),...e.cwd!==void 0?{cwd:e.cwd}:{}});try{let l=await(await a.forkSubagent({parent:e,config:{model:"sonnet",systemPrompt:i.body,env:{PLUGIN_ROOT:i.pluginPath}},idPrefix:"mint-parallelize",...n?{parentId:n}:{}})).runToResult(JSON.stringify({plan:t}));return l.status==="succeeded"&&l.message?{kind:"plan",plan:l.message.content}:l.status!=="succeeded"?{kind:"failed",error:`parallelize subagent status=${l.status}${l.error?.message?`: ${l.error.message}`:""}`}:{kind:"failed",error:"parallelize subagent returned no message"}}finally{await a.teardownAll()}}catch(s){return{kind:"failed",error:`parallelize dispatch threw: ${s instanceof Error?s.message:String(s)}`}}}import{z as me}from"zod";function Ge(t){let e=oe();e&&e({type:"panel",spec:t},{subagentId:"__main__"})}var qp=me.object({status:me.enum(["PASS","FAIL"]),status_reason:me.string().optional(),files_changed:me.array(me.string()),tests_passed:me.boolean(),build_passed:me.boolean().optional(),verification_passed:me.boolean().optional(),notes:me.string()});async function _i(t,e,n,r,o){let i=$("mint")["build.md"];if(!i)throw new Error("mint skill missing build.md prompt");let c=await new P(r!==void 0?{cwd:r}:{}).forkSubagent({parent:{sessionId:n},config:{model:"sonnet",systemPrompt:i,apiKey:K()},idPrefix:"mint-build",outputSchema:qp,...o?{parentId:o}:{}}),l=`Implementation plan:
1498
1498
  ${t}
1499
1499
 
1500
1500
  `+(e?`Wave orchestration plan:
1501
1501
  ${JSON.stringify(e,null,2)}
1502
1502
 
1503
- `:"")+"Execute the implementation plan following TDD (test-first) principles.",d=await c.runToResult(l);if(d.status!=="succeeded"||!d.output)throw new Error(`build phase failed: ${j(d)}`);let u=d.output,p={filesChanged:u.files_changed,testsPassed:u.tests_passed,notes:u.notes};return Ge({kind:"checkpoint",title:"build",body:[`Files changed: ${p.filesChanged.length}`,`Tests: ${p.testsPassed?"passed":"failed"}`,"Next: verify"]}),p}import{z as Ke}from"zod";var zp=Ke.object({status:Ke.enum(["PASS","FAIL"]),status_reason:Ke.string().optional(),issues:Ke.array(Ke.string()).default([]),summary:Ke.string().optional()});async function ur(t,e,n,r,o,s,i){let c=await new P(s!==void 0?{cwd:s}:{}).forkSubagent({parent:{sessionId:r},config:{model:"sonnet",systemPrompt:o,apiKey:G()},idPrefix:`mint-verify-${t}`,outputSchema:zp,...i?{parentId:i}:{}}),l=`Plan:
1503
+ `:"")+"Execute the implementation plan following TDD (test-first) principles.",d=await c.runToResult(l);if(d.status!=="succeeded"||!d.output)throw new Error(`build phase failed: ${j(d)}`);let u=d.output,p={filesChanged:u.files_changed,testsPassed:u.tests_passed,notes:u.notes};return Ge({kind:"checkpoint",title:"build",body:[`Files changed: ${p.filesChanged.length}`,`Tests: ${p.testsPassed?"passed":"failed"}`,"Next: verify"]}),p}import{z as Ke}from"zod";var zp=Ke.object({status:Ke.enum(["PASS","FAIL"]),status_reason:Ke.string().optional(),issues:Ke.array(Ke.string()).default([]),summary:Ke.string().optional()});async function ur(t,e,n,r,o,s,i){let c=await new P(s!==void 0?{cwd:s}:{}).forkSubagent({parent:{sessionId:r},config:{model:"sonnet",systemPrompt:o,apiKey:K()},idPrefix:`mint-verify-${t}`,outputSchema:zp,...i?{parentId:i}:{}}),l=`Plan:
1504
1504
  ${e}
1505
1505
 
1506
1506
  Build results:
@@ -1513,7 +1513,7 @@ Tests: ${n.testsPassed?"PASS":"FAIL"}
1513
1513
  Lint: ${n.lintPassed?"PASS":"FAIL"}
1514
1514
  Design: ${n.designReviewPassed?"PASS":"FAIL"}
1515
1515
  Issues: ${n.issues?.join(`
1516
- `)||"none"}`,c=await i.handler({failure:a,repoPath:o.cwd??process.cwd(),context:t}),l="";if(typeof c=="object"&&c!==null&&"winner"in c&&typeof c.winner=="object"&&c.winner!==null){let k=c.winner;typeof k.proposed_fix=="string"&&(l=k.proposed_fix)}let u=$("mint")["heal.md"];if(!u)throw new Error("mint skill missing heal.md prompt");let f=await new P(o.cwd!==void 0?{cwd:o.cwd}:{}).forkSubagent({parent:{sessionId:o.sessionId},config:{model:"sonnet",systemPrompt:u,apiKey:G()},idPrefix:"mint-heal",...s?{parentId:s}:{}}),g=n.issues?.join(`
1516
+ `)||"none"}`,c=await i.handler({failure:a,repoPath:o.cwd??process.cwd(),context:t}),l="";if(typeof c=="object"&&c!==null&&"winner"in c&&typeof c.winner=="object"&&c.winner!==null){let k=c.winner;typeof k.proposed_fix=="string"&&(l=k.proposed_fix)}let u=$("mint")["heal.md"];if(!u)throw new Error("mint skill missing heal.md prompt");let f=await new P(o.cwd!==void 0?{cwd:o.cwd}:{}).forkSubagent({parent:{sessionId:o.sessionId},config:{model:"sonnet",systemPrompt:u,apiKey:K()},idPrefix:"mint-heal",...s?{parentId:s}:{}}),g=n.issues?.join(`
1517
1517
  `)??"none",m=`Plan:
1518
1518
  ${t}
1519
1519
 
@@ -1523,7 +1523,7 @@ ${l}
1523
1523
  Verification issues:
1524
1524
  ${g}
1525
1525
 
1526
- Apply the fix and update the implementation.`,w=await f.runToResult(m);if(w.status!=="succeeded"||!w.message)throw new Error(`heal phase failed: ${j(w)}`);let b=/^\s*FIX_APPLIED:\s*(true|false)/im.exec(w.message.content)?.[1]?.toLowerCase()==="true",h=r+1;if(!b)return{healed:!1,newHealIterations:h,newVerifyResults:n};if(!o.sessionId)throw new Error("Parent session ID required for verification");let y=await fn(t,e,o.sessionId,o.cwd,s);return{healed:y.testsPassed&&y.lintPassed&&y.designReviewPassed,newHealIterations:h,newVerifyResults:y}}catch{return{healed:!1,newHealIterations:r+1,newVerifyResults:n}}}async function Ri(t,e,n,r){let s=$("mint")["ship.md"];if(!s)throw new Error("mint skill missing ship.md prompt");let a=await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:G()},idPrefix:"mint-ship",...r?{parentId:r}:{}}),c=`Idea: ${t.idea}
1526
+ Apply the fix and update the implementation.`,w=await f.runToResult(m);if(w.status!=="succeeded"||!w.message)throw new Error(`heal phase failed: ${j(w)}`);let b=/^\s*FIX_APPLIED:\s*(true|false)/im.exec(w.message.content)?.[1]?.toLowerCase()==="true",h=r+1;if(!b)return{healed:!1,newHealIterations:h,newVerifyResults:n};if(!o.sessionId)throw new Error("Parent session ID required for verification");let y=await fn(t,e,o.sessionId,o.cwd,s);return{healed:y.testsPassed&&y.lintPassed&&y.designReviewPassed,newHealIterations:h,newVerifyResults:y}}catch{return{healed:!1,newHealIterations:r+1,newVerifyResults:n}}}async function Ri(t,e,n,r){let s=$("mint")["ship.md"];if(!s)throw new Error("mint skill missing ship.md prompt");let a=await new P(n!==void 0?{cwd:n}:{}).forkSubagent({parent:{sessionId:e},config:{model:"sonnet",systemPrompt:s,apiKey:K()},idPrefix:"mint-ship",...r?{parentId:r}:{}}),c=`Idea: ${t.idea}
1527
1527
 
1528
1528
  Specification:
1529
1529
  ${t.spec}
@@ -1635,9 +1635,9 @@ ${y.map(S=>`> - ${S}`).join(`
1635
1635
 
1636
1636
  `:"")+w,I=g.failed.length>0;return{content:_,isError:I}}catch(u){let p=u instanceof Error?u.message:String(u);return ee({event:"compose.failed",parent_session_id:this.ctx.parentSession.sessionId,error_message:p.slice(0,240),duration_ms:Date.now()-d}).catch(()=>{}),{content:`Compose execution error: ${p}`,isError:!0}}finally{await c.teardownAll()}}};function Tr(t,e,n,r){let o=ga();o.register("SubagentStop",ha);let s=n??new V;return r!==void 0&&o.register("PreToolUse",va(r)),o.register("SessionEnd",Pn(s,e)),o.register("SessionEnd",i=>i.event!=="SessionEnd"?{}:(i.sessionId&&Ia(i.sessionId),{})),t&&o.register("SubagentStop",i=>i.event!=="SubagentStop"?{}:i.status==="idle"||i.status==="running"?{}:(t({subagentId:i.subagentId,status:i.status,durationMs:i.durationMs,agentType:i.agentType}),{})),{registry:o,memoryStore:s}}var Jm="[skill-routing: active]\n\nRoute recurring work through registered skills instead of rolling ad-hoc solutions:\n\n- Bugs, failing tests, or regressions \u2192 `/diagnose`\n- High-stakes sub-agent output that will drive edits or commits \u2192 `/shadow-verify` before acting\n- Refactor needing parallel waves \u2192 `/parallelize`\n- Parallel or dependent multi-task work \u2192 `compose` tool (DAG of subagent nodes)\n- Greenfield feature where a written spec would genuinely help (novel scope, multi-day work, or external stakeholders involved) \u2192 `/mint`\n\nDo NOT reach for `/mint` for: bug fixes (use `/diagnose`), refactors with known shape, single-feature edits, work already spec'd in chat, or anything where the spec/approve pause would feel like ceremony. Implement directly in those cases.\n\nCommon composed sequences \u2014 reach for these when the task shape matches:\n\n- Bug with failing test and non-trivial fix \u2192 `/diagnose` \u2192 `/shadow-verify` on the proposed fix\n- Refactor needing parallel waves \u2192 plan \u2192 `/parallelize` \u2192 build waves\n- Diagnose + fix in parallel \u2192 `compose` with two independent nodes\n- Research \u2192 implement \u2192 verify pipeline \u2192 `compose` with edges: research\u2192implement\u2192verify\n- Multiple independent investigations \u2192 `compose` with N nodes, no edges\n\nReach for context-isolated investigators when the task is exploratory:\n\n- Map an unfamiliar module before editing \u2192 `/gather` or `/research`\n- Re-derive a load-bearing claim independently \u2192 `/shadow-verify`\n- Audit a diff before merge \u2192 `/review`\n- Survey git + infra + memory before non-trivial work \u2192 `/ground-state`\n- Generate alternatives before committing to a plan \u2192 `/devils-advocate`\n\nOr dispatch a raw `agent` call when no skill matches but the work is parallelizable, verification-heavy, or would otherwise consume substantial inline context.\n\nSkip orchestration for: single-line edits, trivial Q&A, and direct tool calls the user explicitly requested. The goal is leverage, not ceremony. If a skill would add overhead without adding value, don't invoke it.";function _r(t,e){return!t||!e?t:`${t}
1637
1637
 
1638
- ${Jm}`}var y_=300*1e3;var Sn=class extends Error{constructor(e,n){super(`Background job cap reached (${e}/${n} running). Wait for existing jobs to finish or cancel them before spawning more.`),this.name="BackgroundJobCapError"}};var Vm=new Set;function Ca(t){return Vm.has(t)}var Ym=new Set,Xm=new Set;function Ma(t){for(let e of Ym)e(t)}function Da(t){for(let e of Xm)e(t)}function Qm(t){if(typeof t!="object"||t===null)return;let e=t.name;if(typeof e!="string")return;let n=e.trim();return n.length>0?n:void 0}function Zm(t){if(typeof t!="object"||t===null)throw new Error("Skill tool input must be an object");let e=t,n=e.name;if(typeof n!="string"||n.trim().length===0)throw new Error('Skill tool input must have a non-empty "name" field');let r,o=e.arguments;if(o!==void 0){if(typeof o!="string")throw new Error('Skill tool "arguments" must be a string');r=o}return{name:n.trim(),arguments:r}}var qe=class{constructor(e){this.ctx=e}ctx;pluginBodies=null;async execute(e){if(e.signal.aborted)return{content:"Skill tool call aborted",isError:!0};let n=this.ctx.depth??0,r=this.ctx.maxDepth??ze;if(n>=r){let c=Qm(e.input);return ee({event:"delegation.skipped",parent_session_id:this.ctx.parentSession.sessionId,reason:"max_depth",depth:n,requested_name:c}).catch(()=>{}),{content:`Skill tool not available at nesting depth ${n} (max ${r})`,isError:!0}}let o;try{o=Zm(e.input)}catch(c){return{content:`Skill tool input validation failed: ${c instanceof Error?c.message:String(c)}`,isError:!0}}try{let c=le(o.name);return await this.executeRegistrySkill(c,o.arguments,e)}catch{}let s=this.getPluginSkillBody(o.name);if(s)return await this.executePluginSkill(o.name,s.body,s.pluginPath,o.arguments,e);let a=Ce(this.ctx.pluginConfigs).map(c=>c.name).join(", ");return{content:`Skill "${o.name}" not found. Available skills: ${a||"(none)"}`,isError:!0}}async executeRegistrySkill(e,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};if(e.context==="fork")return this.executeForkedRegistrySkill(e,n,r);let o=Ca(e.name);o&&Da(e.name);let s=Date.now(),i,a;try{a=await e.handler(n&&n.length>0?n:void 0,this.ctx.parentSession,{apiKey:this.ctx.apiKey,defaultModel:this.ctx.defaultModel,defaultSubagentModel:this.ctx.defaultSubagentModel,callId:r.id,dispatchSkill:this.createDispatchSkillCallback(r)})}catch(l){i=l}finally{if(o){let l=Date.now()-s;Ma({skillName:e.name,durationMs:l,...i!==void 0?{isError:!0}:{}})}}return i!==void 0?{content:`Skill execution error: ${i instanceof Error?i.message:String(i)}`,isError:!0}:{content:typeof a=="string"?a:a!=null?JSON.stringify(a):"Skill completed successfully."}}buildForkedChildConfig(e,n){let r=this.ctx.depth??0,o=this.ctx.maxDepth??ze,s={...e};if(!this.ctx.childProviderFactory||r>=o)return{childConfig:s,childManager:void 0};let i=new P({parentAbortSignal:n}),a=new Je({subagentManager:i,parentSession:ut(n),defaultConfig:{model:s.model,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{}},defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),c=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,n):void 0;return s.provider=this.ctx.childProviderFactory({childExecutor:a,childSkillExecutor:c}),{childConfig:s,childManager:i}}async executeForkedRegistrySkill(e,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};let o;try{if(o=$(e.name)["system.md"],!o)return{content:`Skill "${e.name}" has context: "fork" but no prompts/system.md found`,isError:!0}}catch(c){return{content:`Failed to load skill prompts: ${c instanceof Error?c.message:String(c)}`,isError:!0}}let s=new P({parentAbortSignal:r.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:oe()}),{childConfig:i,childManager:a}=this.buildForkedChildConfig({model:e.model??this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:o},r.signal);try{let c=await s.forkSubagent({parent:this.ctx.parentSession,config:i,idPrefix:`skill-fork-${e.name}`,parentId:r.id,agentType:e.name}),l=n&&n.length>0?n:"Run the skill.",d=await c.runToResult(l);return d.status==="succeeded"&&d.message?{content:d.message.content}:{content:d.error?.message??"Forked skill failed with no output",isError:!0}}catch(c){return{content:`Forked skill execution error: ${c instanceof Error?c.message:String(c)}`,isError:!0}}finally{await a?.teardownAll(),await s.teardownAll()}}async executePluginSkill(e,n,r,o,s){if(s.signal.aborted)return{content:"Skill call aborted",isError:!0};let i=new P({parentAbortSignal:s.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:oe()}),{childConfig:a,childManager:c}=this.buildForkedChildConfig({model:this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:n,env:{PLUGIN_ROOT:r}},s.signal);try{let l=await i.forkSubagent({parent:this.ctx.parentSession,config:a,idPrefix:`skill-${e}`,parentId:s.id,agentType:e}),d=o&&o.length>0?o:"Run the skill.",u=await l.runToResult(d);return u.status==="succeeded"&&u.message?{content:u.message.content}:{content:u.error?.message??"Plugin skill failed with no output",isError:!0}}catch(l){return{content:`Plugin skill execution error: ${l instanceof Error?l.message:String(l)}`,isError:!0}}finally{await c?.teardownAll(),await i.teardownAll()}}getPluginSkillBody(e){return this.pluginBodies||(this.pluginBodies=pn(this.ctx.pluginConfigs)),this.pluginBodies.get(e)}createDispatchSkillCallback(e){return async(n,r)=>{let o={id:`${e.id}-dispatch-${n}`,name:"skill",input:{name:n,...r!==void 0?{arguments:r}:{}},signal:e.signal},s=await this.execute(o);if(s.isError)throw new Error(s.content);return s.content}}};var ze=3;function ut(t){return{sessionId:void 0,getInputStreamRef:()=>({pushUserMessage:()=>{}}),abortSignal:t}}var eg=[...it,"agent","skill"];function Oa(){return({childExecutor:t,childSkillExecutor:e})=>new ie({permissions:{allowedTools:eg},subagentExecutor:t,skillExecutor:e})}function Fa(t,e,n,r){let o=(s,i,a)=>new qe({parentSession:ut(a),defaultModel:t,apiKey:e,...r!==void 0?{baseUrl:r}:{},depth:s,maxDepth:i,childProviderFactory:n,childSkillExecutorFactory:o});return o}function La(t){return t.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"")}function tg(t){if(typeof t!="object"||t===null)throw new Error("Agent tool input must be an object");let e=t,n=e.prompt;if(typeof n!="string")throw new Error('Agent tool input must have a "prompt" field of type string');if(n.trim().length===0)throw new Error("Agent tool prompt cannot be empty");let r,o=e.model;if(o!==void 0){if(typeof o!="string")throw new Error("Agent tool model must be a string");r=o}let s=10,i=e.max_turns;if(i!==void 0){if(typeof i!="number")throw new Error("Agent tool max_turns must be a number");s=Math.max(1,Math.min(50,Math.floor(i)))}let a="agent-tool",c=e.id_prefix;if(c!==void 0){if(typeof c!="string")throw new Error("Agent tool id_prefix must be a string");a=c}let l="foreground",d=e.mode;if(d!==void 0){if(d!=="foreground"&&d!=="background")throw new Error(`Agent tool mode must be "foreground" or "background", got: ${JSON.stringify(d)}`);l=d}return{prompt:n,model:r,max_turns:s,id_prefix:a,mode:l}}function Ar(t){try{return ee(t).catch(()=>{})}catch{return Promise.resolve()}}function pt(t,e=240){return t.length<=e?t:t.slice(0,e)+"\u2026"}function $a(t){if(t!=null){if(typeof t=="string")return t.length;try{return JSON.stringify(t).length}catch{return}}}var ng=4096,Na=1024;function rg(t){if(t==null)return;let e=$a(t);return e!==void 0&&e>ng?{truncated:!0,chars:e}:t}function og(t){let e={status:t.status,error:pt(t.errorMessage,Na),subagent_id:t.subagentId};t.schemaErrorMessage&&(e.schemaError=pt(t.schemaErrorMessage,Na));let n=rg(t.partialOutput);return n!==void 0&&(e.partialOutput=n),e}var Je=class t{constructor(e){this.ctx=e}ctx;async execute(e){if(e.signal.aborted)return{content:"Agent tool call aborted",isError:!0};let n;try{n=tg(e.input)}catch(p){return{content:`Agent tool input validation failed: ${p instanceof Error?p.message:String(p)}`,isError:!0}}let r=this.ctx.depth??0,o=this.ctx.maxDepth??ze,s,i={model:n.model??this.ctx.defaultSubagentModel??"sonnet",apiKey:this.ctx.defaultConfig.apiKey,systemPrompt:this.ctx.defaultConfig.systemPrompt,baseUrl:this.ctx.defaultConfig.baseUrl,maxTurns:n.max_turns},a;if(this.ctx.childProviderFactory&&r<o){s=new P({parentAbortSignal:e.signal}),a=ut(e.signal);let p=new t({subagentManager:s,parentSession:a,defaultConfig:this.ctx.defaultConfig,defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),f=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,e.signal):void 0;i.provider=this.ctx.childProviderFactory({childExecutor:p,childSkillExecutor:f})}let c;try{c=await this.ctx.subagentManager.forkSubagent({parent:this.ctx.parentSession,parentId:e.id,config:i,idPrefix:n.id_prefix,agentType:n.id_prefix&&n.id_prefix!=="agent-tool"?La(n.id_prefix).replace(/[\r\n]+/g," ").trim()||"agent":La(n.prompt).replace(/[\r\n]+/g," ").slice(0,40).trim()||"agent"}),a!==void 0&&(a.sessionId=c.id)}catch(p){return{content:`Failed to fork subagent: ${p instanceof Error?p.message:String(p)}`,isError:!0}}if(n.mode==="background"){let p=this.ctx.backgroundRegistry;if(!p)return await c.teardown().catch(m=>C("subagent-executor: handle teardown failed: "+(m instanceof Error?m.message:String(m)))),{content:'Background mode is not available in this session \u2014 no BackgroundAgentRegistry is wired. Re-issue the call with mode="foreground" or run inside `afk interactive`.',isError:!0};let f;try{f=p.register({handle:c,prompt:n.prompt,model:i.model??"sonnet"})}catch(m){if(m instanceof Sn)return await c.teardown().catch(w=>C("subagent-executor: handle teardown failed after cap error: "+(w instanceof Error?w.message:String(w)))),{content:m.message,isError:!0};throw m}let g={status:"running",jobId:f.jobId,subagentId:f.subagentId,label:f.label,message:`Background subagent started (jobId=${f.jobId}). It is running detached and its result will NOT auto-inject into this context. Retrieve it later via /bgsub:join ${f.jobId} or ask the user to join.`};return{content:JSON.stringify(g)}}let l=()=>{c.cancel()};e.signal.addEventListener("abort",l,{once:!0});let d=Date.now(),u=this.ctx.parentSession.sessionId;try{let p=await c.runToResult(n.prompt);if(p.status==="succeeded"&&p.message){let w=p.message.content,b=typeof w=="string"?w:JSON.stringify(w),h=p.trace;return Ar({event:"subagent.completed",subagent_id:c.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,content_chars:b.length,depth:r,tool_call_count:h?.toolCalls.length,thinking_present:h?.thinkingPresent,tool_names:h?.toolCalls.length?JSON.stringify([...new Set(h.toolCalls.map(y=>y.name))]):void 0}),{content:b}}let f=p.error?.message??"Subagent failed with no output",g=p.trace;Ar({event:"subagent.failed",subagent_id:c.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,error_message:pt(f),schema_error:p.schemaError?pt(p.schemaError.message):void 0,partial_output_chars:$a(p.partialOutput),depth:r,tool_call_count:g?.toolCalls.length,thinking_present:g?.thinkingPresent,tool_names:g?.toolCalls.length?JSON.stringify([...new Set(g.toolCalls.map(w=>w.name))]):void 0});let m=og({status:p.status,errorMessage:f,schemaErrorMessage:p.schemaError?.message,partialOutput:p.partialOutput,subagentId:c.id});return{content:JSON.stringify(m),isError:!0}}catch(p){let f=p instanceof Error?p.message:String(p);throw Ar({event:"subagent.failed",subagent_id:c.id,parent_session_id:u,status:"failed",duration_ms:Date.now()-d,error_message:pt(f),depth:r}),p}finally{e.signal.removeEventListener("abort",l),await s?.teardownAll(),await c.teardown()}}};var Ba="unknown";try{let t=Ha(ja(Ua(import.meta.url)),"..","package.json"),e=JSON.parse(Rr(t,"utf8"));e.version&&(Ba=e.version)}catch{console.warn("\u26A0\uFE0F [daemon] Could not read package.json at startup \u2014 version drift check disabled.")}async function ig(){let t;try{t=dr()}catch(l){console.error("\u274C Configuration error:",l.message),process.exit(1)}let e=We(t.model);if(e==="openai-compatible"||e==="openai-codex"){let l=process.env.OPENAI_API_KEY||process.env.CODEX_API_KEY;console.log(l?"\u{1F4DD} Using OPENAI_API_KEY / CODEX_API_KEY for OpenAI auth":"\u{1F4DD} Will attempt API key from ~/.codex/auth.json (run `afk provider auth diagnose` for details)")}else{let l=lt();(!l||l.length===0)&&(console.error("\u274C Claude models require ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN."),console.error(" Set one in your environment, run `afk login`, or sign in to Claude Code."),process.exit(1)),Nt(l)==="oauth"?(process.env.CLAUDE_CODE_OAUTH_TOKEN=l,console.log("\u{1F4DD} Using CLAUDE_CODE_OAUTH_TOKEN for Anthropic auth (OAuth, auto-refresh on 401)")):(process.env.ANTHROPIC_API_KEY=l,console.log("\u{1F4DD} Using ANTHROPIC_API_KEY for Anthropic auth")),t.apiKey=l}lg(Ye());let n=process.env.TELEGRAM_BOT_TOKEN;n||(console.error("\u274C Error: TELEGRAM_BOT_TOKEN environment variable is required"),console.error(`
1638
+ ${Jm}`}var y_=300*1e3;var Sn=class extends Error{constructor(e,n){super(`Background job cap reached (${e}/${n} running). Wait for existing jobs to finish or cancel them before spawning more.`),this.name="BackgroundJobCapError"}};var Vm=new Set;function Ca(t){return Vm.has(t)}var Ym=new Set,Xm=new Set;function Ma(t){for(let e of Ym)e(t)}function Da(t){for(let e of Xm)e(t)}function Qm(t){if(typeof t!="object"||t===null)return;let e=t.name;if(typeof e!="string")return;let n=e.trim();return n.length>0?n:void 0}function Zm(t){if(typeof t!="object"||t===null)throw new Error("Skill tool input must be an object");let e=t,n=e.name;if(typeof n!="string"||n.trim().length===0)throw new Error('Skill tool input must have a non-empty "name" field');let r,o=e.arguments;if(o!==void 0){if(typeof o!="string")throw new Error('Skill tool "arguments" must be a string');r=o}return{name:n.trim(),arguments:r}}var qe=class{constructor(e){this.ctx=e}ctx;pluginBodies=null;async execute(e){if(e.signal.aborted)return{content:"Skill tool call aborted",isError:!0};let n=this.ctx.depth??0,r=this.ctx.maxDepth??ze;if(n>=r){let c=Qm(e.input);return ee({event:"delegation.skipped",parent_session_id:this.ctx.parentSession.sessionId,reason:"max_depth",depth:n,requested_name:c}).catch(()=>{}),{content:`Skill tool not available at nesting depth ${n} (max ${r})`,isError:!0}}let o;try{o=Zm(e.input)}catch(c){return{content:`Skill tool input validation failed: ${c instanceof Error?c.message:String(c)}`,isError:!0}}try{let c=le(o.name);return await this.executeRegistrySkill(c,o.arguments,e)}catch{}let s=this.getPluginSkillBody(o.name);if(s)return await this.executePluginSkill(o.name,s.body,s.pluginPath,o.arguments,e);let a=Ce(this.ctx.pluginConfigs).map(c=>c.name).join(", ");return{content:`Skill "${o.name}" not found. Available skills: ${a||"(none)"}`,isError:!0}}async executeRegistrySkill(e,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};if(e.context==="fork")return this.executeForkedRegistrySkill(e,n,r);let o=Ca(e.name);o&&Da(e.name);let s=Date.now(),i,a;try{a=await e.handler(n&&n.length>0?n:void 0,this.ctx.parentSession,{apiKey:this.ctx.apiKey,defaultModel:this.ctx.defaultModel,defaultSubagentModel:this.ctx.defaultSubagentModel,callId:r.id,dispatchSkill:this.createDispatchSkillCallback(r)})}catch(l){i=l}finally{if(o){let l=Date.now()-s;Ma({skillName:e.name,durationMs:l,...i!==void 0?{isError:!0}:{}})}}return i!==void 0?{content:`Skill execution error: ${i instanceof Error?i.message:String(i)}`,isError:!0}:{content:typeof a=="string"?a:a!=null?JSON.stringify(a):"Skill completed successfully."}}buildForkedChildConfig(e,n){let r=this.ctx.depth??0,o=this.ctx.maxDepth??ze,s={...e};if(!this.ctx.childProviderFactory||r>=o)return{childConfig:s,childManager:void 0};let i=new P({parentAbortSignal:n}),a=new Je({subagentManager:i,parentSession:ut(n),defaultConfig:{model:s.model,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{}},defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),c=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,n):void 0;return s.provider=this.ctx.childProviderFactory({childExecutor:a,childSkillExecutor:c}),{childConfig:s,childManager:i}}async executeForkedRegistrySkill(e,n,r){if(r.signal.aborted)return{content:"Skill call aborted",isError:!0};let o;try{if(o=$(e.name)["system.md"],!o)return{content:`Skill "${e.name}" has context: "fork" but no prompts/system.md found`,isError:!0}}catch(c){return{content:`Failed to load skill prompts: ${c instanceof Error?c.message:String(c)}`,isError:!0}}let s=new P({parentAbortSignal:r.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:oe()}),{childConfig:i,childManager:a}=this.buildForkedChildConfig({model:e.model??this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:o},r.signal);try{let c=await s.forkSubagent({parent:this.ctx.parentSession,config:i,idPrefix:`skill-fork-${e.name}`,parentId:r.id,agentType:e.name}),l=n&&n.length>0?n:"Run the skill.",d=await c.runToResult(l);return d.status==="succeeded"&&d.message?{content:d.message.content}:{content:d.error?.message??"Forked skill failed with no output",isError:!0}}catch(c){return{content:`Forked skill execution error: ${c instanceof Error?c.message:String(c)}`,isError:!0}}finally{await a?.teardownAll(),await s.teardownAll()}}async executePluginSkill(e,n,r,o,s){if(s.signal.aborted)return{content:"Skill call aborted",isError:!0};let i=new P({parentAbortSignal:s.signal,apiKey:this.ctx.apiKey,...this.ctx.baseUrl!==void 0?{baseUrl:this.ctx.baseUrl}:{},progressSink:oe()}),{childConfig:a,childManager:c}=this.buildForkedChildConfig({model:this.ctx.defaultSubagentModel??this.ctx.defaultModel??"sonnet",systemPrompt:n,env:{PLUGIN_ROOT:r}},s.signal);try{let l=await i.forkSubagent({parent:this.ctx.parentSession,config:a,idPrefix:`skill-${e}`,parentId:s.id,agentType:e}),d=o&&o.length>0?o:"Run the skill.",u=await l.runToResult(d);return u.status==="succeeded"&&u.message?{content:u.message.content}:{content:u.error?.message??"Plugin skill failed with no output",isError:!0}}catch(l){return{content:`Plugin skill execution error: ${l instanceof Error?l.message:String(l)}`,isError:!0}}finally{await c?.teardownAll(),await i.teardownAll()}}getPluginSkillBody(e){return this.pluginBodies||(this.pluginBodies=pn(this.ctx.pluginConfigs)),this.pluginBodies.get(e)}createDispatchSkillCallback(e){return async(n,r)=>{let o={id:`${e.id}-dispatch-${n}`,name:"skill",input:{name:n,...r!==void 0?{arguments:r}:{}},signal:e.signal},s=await this.execute(o);if(s.isError)throw new Error(s.content);return s.content}}};var ze=3;function ut(t){return{sessionId:void 0,getInputStreamRef:()=>({pushUserMessage:()=>{}}),abortSignal:t}}var eg=[...it,"agent","skill"];function Oa(){return({childExecutor:t,childSkillExecutor:e})=>new ie({permissions:{allowedTools:eg},subagentExecutor:t,skillExecutor:e})}function Fa(t,e,n,r){let o=(s,i,a)=>new qe({parentSession:ut(a),defaultModel:t,apiKey:e,...r!==void 0?{baseUrl:r}:{},depth:s,maxDepth:i,childProviderFactory:n,childSkillExecutorFactory:o});return o}function La(t){return t.replace(/\x1b\[[0-9;]*[a-zA-Z]/g,"")}function tg(t){if(typeof t!="object"||t===null)throw new Error("Agent tool input must be an object");let e=t,n=e.prompt;if(typeof n!="string")throw new Error('Agent tool input must have a "prompt" field of type string');if(n.trim().length===0)throw new Error("Agent tool prompt cannot be empty");let r,o=e.model;if(o!==void 0){if(typeof o!="string")throw new Error("Agent tool model must be a string");r=o}let s=10,i=e.max_turns;if(i!==void 0){if(typeof i!="number")throw new Error("Agent tool max_turns must be a number");s=Math.max(1,Math.min(50,Math.floor(i)))}let a="agent-tool",c=e.id_prefix;if(c!==void 0){if(typeof c!="string")throw new Error("Agent tool id_prefix must be a string");a=c}let l="foreground",d=e.mode;if(d!==void 0){if(d!=="foreground"&&d!=="background")throw new Error(`Agent tool mode must be "foreground" or "background", got: ${JSON.stringify(d)}`);l=d}return{prompt:n,model:r,max_turns:s,id_prefix:a,mode:l}}function Ar(t){try{return ee(t).catch(()=>{})}catch{return Promise.resolve()}}function pt(t,e=240){return t.length<=e?t:t.slice(0,e)+"\u2026"}function $a(t){if(t!=null){if(typeof t=="string")return t.length;try{return JSON.stringify(t).length}catch{return}}}var ng=4096,Na=1024;function rg(t){if(t==null)return;let e=$a(t);return e!==void 0&&e>ng?{truncated:!0,chars:e}:t}function og(t){let e={status:t.status,error:pt(t.errorMessage,Na),subagent_id:t.subagentId};t.schemaErrorMessage&&(e.schemaError=pt(t.schemaErrorMessage,Na));let n=rg(t.partialOutput);return n!==void 0&&(e.partialOutput=n),e}var Je=class t{constructor(e){this.ctx=e}ctx;async execute(e){if(e.signal.aborted)return{content:"Agent tool call aborted",isError:!0};let n;try{n=tg(e.input)}catch(p){return{content:`Agent tool input validation failed: ${p instanceof Error?p.message:String(p)}`,isError:!0}}let r=this.ctx.depth??0,o=this.ctx.maxDepth??ze,s,i={model:n.model??this.ctx.defaultSubagentModel??"sonnet",apiKey:this.ctx.defaultConfig.apiKey,systemPrompt:this.ctx.defaultConfig.systemPrompt,baseUrl:this.ctx.defaultConfig.baseUrl,maxTurns:n.max_turns},a;if(this.ctx.childProviderFactory&&r<o){s=new P({parentAbortSignal:e.signal}),a=ut(e.signal);let p=new t({subagentManager:s,parentSession:a,defaultConfig:this.ctx.defaultConfig,defaultSubagentModel:this.ctx.defaultSubagentModel,childProviderFactory:this.ctx.childProviderFactory,childSkillExecutorFactory:this.ctx.childSkillExecutorFactory,depth:r+1,maxDepth:o}),f=this.ctx.childSkillExecutorFactory?this.ctx.childSkillExecutorFactory(r+1,o,e.signal):void 0;i.provider=this.ctx.childProviderFactory({childExecutor:p,childSkillExecutor:f})}let c;try{c=await this.ctx.subagentManager.forkSubagent({parent:this.ctx.parentSession,parentId:e.id,config:i,idPrefix:n.id_prefix,agentType:n.id_prefix&&n.id_prefix!=="agent-tool"?La(n.id_prefix).replace(/[\r\n]+/g," ").trim()||"agent":La(n.prompt).replace(/[\r\n]+/g," ").slice(0,40).trim()||"agent"}),a!==void 0&&(a.sessionId=c.id)}catch(p){return{content:`Failed to fork subagent: ${p instanceof Error?p.message:String(p)}`,isError:!0}}if(n.mode==="background"){let p=this.ctx.backgroundRegistry;if(!p)return await c.teardown().catch(m=>C("subagent-executor: handle teardown failed: "+(m instanceof Error?m.message:String(m)))),{content:'Background mode is not available in this session \u2014 no BackgroundAgentRegistry is wired. Re-issue the call with mode="foreground" or run inside `afk interactive`.',isError:!0};let f;try{f=p.register({handle:c,prompt:n.prompt,model:i.model??"sonnet"})}catch(m){if(m instanceof Sn)return await c.teardown().catch(w=>C("subagent-executor: handle teardown failed after cap error: "+(w instanceof Error?w.message:String(w)))),{content:m.message,isError:!0};throw m}let g={status:"running",jobId:f.jobId,subagentId:f.subagentId,label:f.label,message:`Background subagent started (jobId=${f.jobId}). It is running detached and its result will NOT auto-inject into this context. Retrieve it later via /bgsub:join ${f.jobId} or ask the user to join.`};return{content:JSON.stringify(g)}}let l=()=>{c.cancel()};e.signal.addEventListener("abort",l,{once:!0});let d=Date.now(),u=this.ctx.parentSession.sessionId;try{let p=await c.runToResult(n.prompt);if(p.status==="succeeded"&&p.message){let w=p.message.content,b=typeof w=="string"?w:JSON.stringify(w),h=p.trace;return Ar({event:"subagent.completed",subagent_id:c.id,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,content_chars:b.length,depth:r,tool_call_count:h?.toolCalls.length,thinking_present:h?.thinkingPresent,tool_names:h?.toolCalls.length?JSON.stringify([...new Set(h.toolCalls.map(y=>y.name))]):void 0}),{content:b}}let f=p.error?.message??"Subagent failed with no output",g=p.trace;Ar({event:"subagent.failed",subagent_id:c.id,id_prefix:n.id_prefix,parent_session_id:u,status:p.status,duration_ms:Date.now()-d,error_message:pt(f),schema_error:p.schemaError?pt(p.schemaError.message):void 0,partial_output_chars:$a(p.partialOutput),depth:r,tool_call_count:g?.toolCalls.length,thinking_present:g?.thinkingPresent,tool_names:g?.toolCalls.length?JSON.stringify([...new Set(g.toolCalls.map(w=>w.name))]):void 0});let m=og({status:p.status,errorMessage:f,schemaErrorMessage:p.schemaError?.message,partialOutput:p.partialOutput,subagentId:c.id});return{content:JSON.stringify(m),isError:!0}}catch(p){let f=p instanceof Error?p.message:String(p);throw Ar({event:"subagent.failed",subagent_id:c.id,id_prefix:n.id_prefix,parent_session_id:u,status:"failed",duration_ms:Date.now()-d,error_message:pt(f),depth:r}),p}finally{e.signal.removeEventListener("abort",l),await s?.teardownAll(),await c.teardown()}}};var Ba="unknown";try{let t=Ha(ja(Ua(import.meta.url)),"..","package.json"),e=JSON.parse(Rr(t,"utf8"));e.version&&(Ba=e.version)}catch{console.warn("\u26A0\uFE0F [daemon] Could not read package.json at startup \u2014 version drift check disabled.")}async function ig(){let t;try{t=dr()}catch(l){console.error("\u274C Configuration error:",l.message),process.exit(1)}let e=We(t.model);if(e==="openai-compatible"||e==="openai-codex"){let l=process.env.OPENAI_API_KEY||process.env.CODEX_API_KEY;console.log(l?"\u{1F4DD} Using OPENAI_API_KEY / CODEX_API_KEY for OpenAI auth":"\u{1F4DD} Will attempt API key from ~/.codex/auth.json (run `afk provider auth diagnose` for details)")}else{let l=lt();(!l||l.length===0)&&(console.error("\u274C Claude models require ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN."),console.error(" Set one in your environment, run `afk login`, or sign in to Claude Code."),process.exit(1)),Nt(l)==="oauth"?(process.env.CLAUDE_CODE_OAUTH_TOKEN=l,console.log("\u{1F4DD} Using CLAUDE_CODE_OAUTH_TOKEN for Anthropic auth (OAuth, auto-refresh on 401)")):(process.env.ANTHROPIC_API_KEY=l,console.log("\u{1F4DD} Using ANTHROPIC_API_KEY for Anthropic auth")),t.apiKey=l}lg(Ye());let n=process.env.TELEGRAM_BOT_TOKEN;n||(console.error("\u274C Error: TELEGRAM_BOT_TOKEN environment variable is required"),console.error(`
1639
1639
  How to get a bot token:`),console.error(" 1. Open Telegram and search for @BotFather"),console.error(" 2. Send /newbot and follow the instructions"),console.error(" 3. Run: afk telegram setup"),process.exit(1));let r=rt(process.env.AFK_TELEGRAM_ALLOWED_CHAT_IDS,console.warn);r.size===0&&(console.error("\u274C Error: AFK_TELEGRAM_ALLOWED_CHAT_IDS must list at least one chat ID"),console.error(`
1640
- This is an allowlist that gates who can message the bot.`),console.error("Run `afk telegram setup` to set it interactively, or set it manually:"),console.error(" AFK_TELEGRAM_ALLOWED_CHAT_IDS=123456789,-100987654321"),process.exit(1)),console.log("\u{1F50E} Validating bot token...");let o=await Oo(n);o||(console.error("\u274C Error: TELEGRAM_BOT_TOKEN was rejected by Telegram (getMe failed)"),console.error(" The token may be revoked, malformed, or your network may be unreachable."),console.error(" Re-run `afk telegram setup` to refresh it."),process.exit(1));let s=o.username?`@${o.username}`:o.firstName;console.log(""),console.log(`\u{1F916} Starting Agent AFK Telegram Bot as ${s} (id ${o.id})`),console.log(`\u{1F4E1} Model: ${t.model} \xB7 Provider: ${e}`),console.log(`\u{1F512} Allowlist: ${r.size} chat ID(s)`);let i=new V,a=process.env.AFK_TELEGRAM_CWD,c=new Lt({botToken:n,apiKey:t.apiKey??"",dataDir:process.env.TELEGRAM_DATA_DIR||"./data/telegram-sessions",defaultModel:t.model,verbose:process.env.TELEGRAM_VERBOSE==="true",allowedChatIds:r,settingSources:["user","project"],createSession:async l=>{let d=De(l.model)??l.model;console.log(`Creating session with model: ${l.model} -> ${d}`);let u=We(d),p=u==="openai-compatible"||u==="openai-codex",f=p?void 0:vi(),g;if(!p){let k,_=l.apiKey??t.apiKey??"",I=t.baseUrl,S=l.cwd??a,x=new P({apiKey:_,...I!==void 0?{baseUrl:I}:{},...S!==void 0&&S.length>0?{cwd:S}:{}}),A={get sessionId(){return k?.sessionId},getInputStreamRef(){return k?.getInputStreamRef?.()??{pushUserMessage:()=>{}}},get abortSignal(){return k?.abortSignal??new AbortController().signal}},R=Oa(),F=Fa(l.model,_,R,I),v=new Je({subagentManager:x,parentSession:A,defaultConfig:{apiKey:_,systemPrompt:l.systemPrompt??t.systemPrompt,...I!==void 0?{baseUrl:I}:{}},defaultSubagentModel:un(),childProviderFactory:R,childSkillExecutorFactory:F}),E=new qe({parentSession:A,defaultModel:l.model,defaultSubagentModel:un(),apiKey:_,childProviderFactory:R,childSkillExecutorFactory:F,...I!==void 0?{baseUrl:I}:{}}),M=l.systemPrompt??t.systemPrompt,D=new vn({parentSession:A,defaultModel:l.model,defaultSubagentModel:un(),apiKey:_,...I!==void 0?{baseUrl:I}:{},systemPrompt:typeof M=="string"?M:""}),K=[...it,...St,"agent","skill","compose"];g=new ie({permissions:{allowedTools:K},subagentExecutor:v,skillExecutor:E,composeExecutor:D});let L=l.systemPrompt??t.systemPrompt,z=t.autoRouting?.telegram??!1,re=typeof L=="string"?_r(L,z):L,W=new we({...l.apiKey!==void 0?{apiKey:l.apiKey}:{},model:l.model,...re!==void 0?{systemPrompt:re}:{},maxTurns:100,...f!==void 0?{maxOutputTokens:f}:{},...I!==void 0?{baseUrl:I}:{},...S!==void 0&&S.length>0?{cwd:S}:{},provider:g,hookRegistry:Tr(void 0,"telegram",i).registry});return k=W,W}let m=l.systemPrompt??t.systemPrompt,w=t.autoRouting?.telegram??!1,b=typeof m=="string"?_r(m,w):m,h=l.cwd??a;return new we({...l.apiKey!==void 0?{apiKey:l.apiKey}:{},model:l.model,...b!==void 0?{systemPrompt:b}:{},maxTurns:100,...f!==void 0?{maxOutputTokens:f}:{},...h!==void 0&&h.length>0?{cwd:h}:{},hookRegistry:Tr(void 0,"telegram",i).registry})}});try{c.start(),console.log("\u2705 Bot started successfully!"),console.log(`
1640
+ This is an allowlist that gates who can message the bot.`),console.error("Run `afk telegram setup` to set it interactively, or set it manually:"),console.error(" AFK_TELEGRAM_ALLOWED_CHAT_IDS=123456789,-100987654321"),process.exit(1)),console.log("\u{1F50E} Validating bot token...");let o=await Oo(n);o||(console.error("\u274C Error: TELEGRAM_BOT_TOKEN was rejected by Telegram (getMe failed)"),console.error(" The token may be revoked, malformed, or your network may be unreachable."),console.error(" Re-run `afk telegram setup` to refresh it."),process.exit(1));let s=o.username?`@${o.username}`:o.firstName;console.log(""),console.log(`\u{1F916} Starting Agent AFK Telegram Bot as ${s} (id ${o.id})`),console.log(`\u{1F4E1} Model: ${t.model} \xB7 Provider: ${e}`),console.log(`\u{1F512} Allowlist: ${r.size} chat ID(s)`);let i=new V,a=process.env.AFK_TELEGRAM_CWD,c=new Lt({botToken:n,apiKey:t.apiKey??"",dataDir:process.env.TELEGRAM_DATA_DIR||"./data/telegram-sessions",defaultModel:t.model,verbose:process.env.TELEGRAM_VERBOSE==="true",allowedChatIds:r,settingSources:["user","project"],createSession:async l=>{let d=De(l.model)??l.model;console.log(`Creating session with model: ${l.model} -> ${d}`);let u=We(d),p=u==="openai-compatible"||u==="openai-codex",f=p?void 0:vi(),g;if(!p){let k,_=l.apiKey??t.apiKey??"",I=t.baseUrl,S=l.cwd??a,x=new P({apiKey:_,...I!==void 0?{baseUrl:I}:{},...S!==void 0&&S.length>0?{cwd:S}:{}}),A={get sessionId(){return k?.sessionId},getInputStreamRef(){return k?.getInputStreamRef?.()??{pushUserMessage:()=>{}}},get abortSignal(){return k?.abortSignal??new AbortController().signal}},R=Oa(),F=Fa(l.model,_,R,I),v=new Je({subagentManager:x,parentSession:A,defaultConfig:{apiKey:_,systemPrompt:l.systemPrompt??t.systemPrompt,...I!==void 0?{baseUrl:I}:{}},defaultSubagentModel:un(),childProviderFactory:R,childSkillExecutorFactory:F}),E=new qe({parentSession:A,defaultModel:l.model,defaultSubagentModel:un(),apiKey:_,childProviderFactory:R,childSkillExecutorFactory:F,...I!==void 0?{baseUrl:I}:{}}),M=l.systemPrompt??t.systemPrompt,D=new vn({parentSession:A,defaultModel:l.model,defaultSubagentModel:un(),apiKey:_,...I!==void 0?{baseUrl:I}:{},systemPrompt:typeof M=="string"?M:""}),G=[...it,...St,"agent","skill","compose"];g=new ie({permissions:{allowedTools:G},subagentExecutor:v,skillExecutor:E,composeExecutor:D});let L=l.systemPrompt??t.systemPrompt,z=t.autoRouting?.telegram??!1,re=typeof L=="string"?_r(L,z):L,W=new we({...l.apiKey!==void 0?{apiKey:l.apiKey}:{},model:l.model,...re!==void 0?{systemPrompt:re}:{},maxTurns:100,...f!==void 0?{maxOutputTokens:f}:{},...I!==void 0?{baseUrl:I}:{},...S!==void 0&&S.length>0?{cwd:S}:{},provider:g,hookRegistry:Tr(void 0,"telegram",i).registry});return k=W,W}let m=l.systemPrompt??t.systemPrompt,w=t.autoRouting?.telegram??!1,b=typeof m=="string"?_r(m,w):m,h=l.cwd??a;return new we({...l.apiKey!==void 0?{apiKey:l.apiKey}:{},model:l.model,...b!==void 0?{systemPrompt:b}:{},maxTurns:100,...f!==void 0?{maxOutputTokens:f}:{},...h!==void 0&&h.length>0?{cwd:h}:{},hookRegistry:Tr(void 0,"telegram",i).registry})}});try{c.start(),console.log("\u2705 Bot started successfully!"),console.log(`
1641
1641
  \u{1F4DD} Slash commands (Agent SDK):`),console.log(" /start - Welcome and command list"),console.log(" /help - Show command list"),console.log(" /clear - Clear conversation history"),console.log(" /compact - Compact history (summarize older messages)"),console.log(" /model - Switch model (opus/sonnet/haiku/gpt-5.4/...)"),console.log(`
1642
1642
  \u{1F4AC} Send any message to chat with the agent.`),console.log(`
1643
1643
  \u23F9\uFE0F Press Ctrl+C to stop the bot.`);let l=setInterval(()=>{let u=c.getStats();console.log(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-afk",
3
- "version": "3.3.2",
3
+ "version": "3.3.3",
4
4
  "description": "CLI tool for interacting with AI agents via multiple interfaces",
5
5
  "main": "dist/index.mjs",
6
6
  "type": "module",