agent-afk 3.3.2 → 3.3.4

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/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