agent-afk 1.21.0 → 2.1.0

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
@@ -831,7 +831,7 @@ Return a well-structured specification (700\u20131000 words) that a developer ca
831
831
  Be direct and clear. Avoid marketing language; favor technical precision.
832
832
  `,"verify.md":'# Phase 6: Verify (Ship-Yesterday Gate)\n\nYou are a quality gate. Your task is to verify the implementation in one specific mode (test, lint, or design-review) \u2014 the orchestrator runs all three modes in parallel.\n\n## Input\nYou are given:\n- The implementation plan from Phase 3 (verification commands, success criteria)\n- The build results from Phase 5 (files changed, test status)\n- Your **mode** \u2014 one of: `test`, `lint`, `design-review`\n\n## Your Task\n\nThe orchestrator runs three modes in parallel: `test` and `lint` are **programmatic** checks; `design-review` is a code-quality review. A green status across all three is the bar to ship.\n\n**If mode is `test`:**\n- Run the full test suite specified in the plan.\n- Capture failures and concrete error messages.\n\n**If mode is `lint`:**\n- Run linting and type-checking.\n- Capture each lint/type error with file:line where possible.\n\n**If mode is `design-review`:**\nEvaluate the implementation diff across these dimensions and decide PASS/FAIL based on whether any dimension has a red (blocker):\n\n1. **Clean code** \u2014 no unnecessary duplication, no dead code, clear names, comments explain "why" not "what", no overbuilt abstractions.\n2. **Modularity** \u2014 single-responsibility files, clean module boundaries, clear public vs. private APIs.\n3. **Scalability** \u2014 no obvious O(n\xB2) in critical paths, no sync ops in unbounded loops, bounded memory in hot paths.\n4. **Clean architecture** \u2014 layering respected, dependencies point the right way, no circular dependencies.\n5. **Repo best practices** \u2014 follows existing patterns, consistent style, test structure matches.\n6. **Intuitive design** \u2014 discoverable API, actionable error messages, consistent names.\n7. **Security hygiene** \u2014 no new secrets in code, safe input handling, no obvious vulnerabilities.\n\nA red on any dimension is a FAIL; yellows are nice-to-have and do not block.\n\n## Output\n\nRespond with a single fenced JSON code block and no prose outside it. The JSON must conform to:\n\n```json\n{\n "status": "PASS",\n "status_reason": "short reason \u2014 only when status is FAIL, omit otherwise",\n "issues": ["src/example.ts:42 \u2014 concrete issue description"],\n "summary": "Optional one-paragraph human-readable summary of what was checked.",\n "signal": {\n "issue": "stable-slug-or-question",\n "stance": "supports",\n "confidence": 0.9,\n "evidence": ["src/example.ts:42"],\n "claim": "Implementation passes this verification mode without blockers."\n }\n}\n```\n\nField semantics:\n- `status` \u2014 `"PASS"` if this mode is green; `"FAIL"` if anything red.\n- `status_reason` \u2014 short reason when `FAIL`; omit when `PASS`.\n- `issues` \u2014 concrete blockers with file:line citations where possible. Empty array when `PASS`.\n- `summary` \u2014 optional narrative; the orchestrator may surface it to the user. Keep it concise.\n- `signal` \u2014 OPTIONAL passive-observation field (v0). When the\n implementation cleanly passes or cleanly fails your mode, you MAY emit a\n `signal` object conforming to the shape shown. See `docs/signal-block.md`\n for the full convention. Rules:\n - `issue` \u2014 a stable slug naming what was checked (e.g.\n `"verify-test-mode"`, `"verify-lint-mode"`, `"verify-design-review"`).\n Use the same slug across reruns of the same mode.\n - `stance` \u2014 `supports` when `status: "PASS"`; `opposes` when\n `status: "FAIL"`; `uncertain` when issues are real but ambiguous;\n `blocks` when the verification tool itself failed (e.g. test runner\n crashed).\n - `confidence` \u2014 how sure you are about the verdict, not how sure you\n are that the code is good overall.\n - `evidence` \u2014 at least one `file:line` citation matching an entry in\n `issues[]`, or pointing to a test/lint output. Empty array permitted\n when `status: "PASS"` and there is nothing to cite.\n - `claim` \u2014 one sentence summarizing your mode-specific verdict.\n - OMIT the entire `signal` field when verification was inconclusive\n (e.g., you could not run the tests). Do not fabricate a stance.\n'}};function I(t){let e=vn[t];if(!e){let n=Object.keys(vn).sort(),r=n.length>0?"Available: "+n.join(", "):"";throw new Error("Unknown skill: "+t+". "+r)}return e}var Ue=new Map;function X(t){Ue.set(t.name,t)}function Z(t){let e=Ue.get(t);if(e)return e;let n=Array.from(Ue.keys()).sort(),r=n.length>0?`
833
833
  Available skills: ${n.join(", ")}`:"";throw new Error(`Skill not found: ${t}${r}`)}function kn(){return Array.from(Ue.keys()).sort()}var ke=class{nodes=new Map;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){let r=this.nodes.get(e);if(!r||r.controller.signal.aborted)return;let o=[],s=[...r.children],i=new Set;for(;s.length;){let a=s.shift();if(i.has(a))continue;i.add(a);let c=this.nodes.get(a);if(c){c.cascading=!0,o.push(a);for(let l of c.children)s.push(l)}}r.controller.abort(n);for(let a of o){let c=this.nodes.get(a);c&&!c.controller.signal.aborted&&c.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)}}};var Se=0,He=5e3;async function xe(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 Le(`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 Sn(t,e,n={}){t&&await t.dispatch(e,n.signal)}async function xn(t,e,n={}){if(!t)return{};try{return await t.dispatch(e,n.signal)}catch(r){return r instanceof K||r instanceof J?(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))),{})}}import{mkdir as os,writeFile as ss}from"fs/promises";import{dirname as is,join as as}from"path";import{join as j,dirname as es}from"path";import{homedir as ts}from"os";import{fileURLToPath as ns}from"url";function q(){return process.env.AFK_HOME||j(ts(),".afk")}function ce(){return j(q(),"agent-framework")}function En(){return j(ce(),"forge-telemetry.jsonl")}function pe(){return j(ce(),"briefs")}function Be(){return j(ce(),"ceiling-ledger")}function ht(){return j(q(),"skills")}function fe(){return j(q(),"plugins")}function rs(){return j(process.cwd(),".afk")}function yt(){return j(rs(),"plugins")}function Ge(){return j(fe(),".index.json")}function bt(){let t=ns(import.meta.url),e=es(t);return j(e,"bundled-plugins")}function Tn(){return j(q(),"state")}function Pn(){return j(Tn(),"sessions")}function Ke(){return j(Tn(),"memory")}function cs(){return as(ce(),"routing-decisions.jsonl")}async function qe(t){if(!(process.env.VITEST||process.env.NODE_ENV==="test"))try{let e=cs();await os(is(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)+`
834
- `;await ss(e,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as ls}from"node:async_hooks";var ds=new ls;function me(){return ds.getStore()}function wt(t){let e=us(t);return e!==void 0?e:ps(t)}function us(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return An(n.trim())}function ps(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=fs(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=An(r);if(o!==void 0)return o}}function fs(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 An(t){try{return JSON.parse(t)}catch{return}}function vt(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function _n(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=wt(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 Rn(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function R(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}var ze=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f){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.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=vt();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=xe(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",this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.currentStatus="failed",this.latestTerminalStatus="failed"),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r="",o;this.currentTrace=vt();let s=this.progressSink??me(),i={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let a of this.session.sendMessageStream(e)){if(s&&s(a,i),a.type==="chunk"){let c=a.chunk;c.type==="content"?r+=c.content:c.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:c.toolUseId,name:c.toolName,inputBytes:Buffer.byteLength(c.toolInput,"utf8")}):c.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:c.toolUseId,isError:c.isError,truncated:c.truncated,sizeBytes:c.sizeBytes}):c.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(a.type==="message")n=a.message,this.currentTrace.turnCount++;else if(a.type==="error"){o=a.error;break}else if(a.type==="done"){if(typeof a.metadata?.usage=="object"&&a.metadata.usage!==null){let c=a.metadata.usage;this.currentTrace.usage={inputTokens:typeof c.input_tokens=="number"?c.input_tokens:void 0,outputTokens:typeof c.output_tokens=="number"?c.output_tokens:void 0,cacheReadTokens:typeof c.cache_read_input_tokens=="number"?c.cache_read_input_tokens:void 0,cacheCreationTokens:typeof c.cache_creation_input_tokens=="number"?c.cache_creation_input_tokens:void 0}}break}}if(o)throw o;if(n)return n;if(r.length>0)return{role:"assistant",content:r,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return _n(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){return Rn(this.id,this.currentStatus,n,this.currentTrace)}}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";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 xn(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace});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 S=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;abortGraph=new ke;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,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){this.abortGraph.abort(this.rootId,e)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await Sn(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal});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,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 le(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??me(),u=new ze(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Se,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,e.idPrefix,d,e.parent.sessionId);return this.active.set(n,u),await qe({event:"subagent.dispatched",subagent_id:n,id_prefix:e.idPrefix,parent_session_id:e.parent.sessionId}),u}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 We(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 ms}from"node:url";import{dirname as gs}from"node:path";var hs=ms(import.meta.url),nd=gs(hs),H={name:"research-agent",systemPrompt:`---
834
+ `;await ss(e,o,{flag:"a"})}catch{}}import{AsyncLocalStorage as ls}from"node:async_hooks";var ds=new ls;function me(){return ds.getStore()}function wt(t){let e=us(t);return e!==void 0?e:ps(t)}function us(t){let e=/```(?:json)?\s*([\s\S]*?)```/gi,n,r;for(;(r=e.exec(t))!==null;)n=r[1];if(n)return An(n.trim())}function ps(t){for(let e=t.length-1;e>=0;e--){if(t[e]!=="}")continue;let n=fs(t,e);if(n===-1)continue;let r=t.slice(n,e+1),o=An(r);if(o!==void 0)return o}}function fs(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 An(t){try{return JSON.parse(t)}catch{return}}function vt(){return{toolCalls:[],toolResults:[],thinkingPresent:!1,turnCount:0}}function _n(t,e,n,r,o){if(!r)return{id:t,status:e,message:n,trace:o};let s=wt(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 Rn(t,e,n,r){let o=n instanceof Error?n:new Error(String(n));return{id:t,status:e,error:o,trace:r}}function R(t){return`${t.status}${t.error?`: ${t.error.message}`:""}`}var ze=class{constructor(e,n,r,o,s,i,a,c,l,d,u,p,f){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.progressSink=p,this.parentId=f}id;session;controller;abortGraph;outputSchema;timeoutMs;hookRegistry;onTerminal;parentInputStreamRef;parentAbortSignal;agentType;currentStatus="idle";inFlight=null;lastMessage;lastDurationMs;latestTerminalStatus;stopDispatched=!1;progressSink;parentId;currentTrace=vt();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=xe(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",this.onTerminal(),o}catch(o){throw this.lastDurationMs=Date.now()-n,this.currentStatus!=="cancelled"&&(this.currentStatus="failed",this.latestTerminalStatus="failed"),this.onTerminal(),o}finally{this.inFlight=null}}async streamToFinalMessage(e){let n,r="",o;this.currentTrace=vt();let s=this.progressSink??me(),i={subagentId:this.id,...this.parentId!==void 0&&{parentId:this.parentId},...this.agentType!==void 0&&{agentType:this.agentType}};for await(let a of this.session.sendMessageStream(e)){if(s&&s(a,i),a.type==="chunk"){let c=a.chunk;c.type==="content"?r+=c.content:c.type==="tool_use_detail"?this.currentTrace.toolCalls.push({id:c.toolUseId,name:c.toolName,inputBytes:Buffer.byteLength(c.toolInput,"utf8")}):c.type==="tool_result"?this.currentTrace.toolResults.push({toolUseId:c.toolUseId,isError:c.isError,truncated:c.truncated,sizeBytes:c.sizeBytes}):c.type==="thinking"&&(this.currentTrace.thinkingPresent=!0)}if(a.type==="message")n=a.message,this.currentTrace.turnCount++;else if(a.type==="error"){o=a.error;break}else if(a.type==="done"){if(typeof a.metadata?.usage=="object"&&a.metadata.usage!==null){let c=a.metadata.usage;this.currentTrace.usage={inputTokens:typeof c.input_tokens=="number"?c.input_tokens:void 0,outputTokens:typeof c.output_tokens=="number"?c.output_tokens:void 0,cacheReadTokens:typeof c.cache_read_input_tokens=="number"?c.cache_read_input_tokens:void 0,cacheCreationTokens:typeof c.cache_creation_input_tokens=="number"?c.cache_creation_input_tokens:void 0}}break}}if(o)throw o;if(n)return n;if(r.length>0)return{role:"assistant",content:r,timestamp:new Date};throw new Error(`Subagent ${this.id} produced no terminal message`)}async runToResult(e){try{let n=await this.run(e);return _n(this.id,this.currentStatus,n,this.outputSchema,this.currentTrace)}catch(n){return Rn(this.id,this.currentStatus,n,this.currentTrace)}}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";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 xn(this.hookRegistry,{event:"SubagentStop",subagentId:this.id,status:e,lastMessage:this.lastMessage,agentType:this.agentType,durationMs:this.lastDurationMs,trace:this.currentTrace});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 S=class{active=new Map;parentCanUseTool;hookRegistry;progressSink;parentApiKey;abortGraph=new ke;rootId;rootController;counter=0;constructor(e={}){if(this.parentCanUseTool=e.canUseTool,this.hookRegistry=e.hookRegistry,this.progressSink=e.progressSink,this.parentApiKey=e.apiKey,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){this.abortGraph.abort(this.rootId,e)}async forkSubagent(e){let n=`${e.idPrefix??"subagent"}-${Date.now()}-${++this.counter}`,r=e.parent.sessionId,o=e.config.hookRegistry??this.hookRegistry;o&&await Sn(o,{event:"SubagentStart",subagentId:n,parentSessionId:e.parent.sessionId},{signal:this.rootController.signal});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,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 le(i),c=e.parent.getInputStreamRef?.(),l=e.parent.abortSignal,d=this.progressSink??me(),u=e.agentType?.trim()||void 0,p=e.parentId?.trim()||void 0,f=new ze(n,a,s,this.abortGraph,e.outputSchema,e.config.timeoutMs??Se,o,()=>{this.active.delete(n),this.abortGraph.dispose(n)},c,l,u??e.idPrefix,d,p??e.parent.sessionId);return this.active.set(n,f),await qe({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 We(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 ms}from"node:url";import{dirname as gs}from"node:path";var hs=ms(import.meta.url),nd=gs(hs),H={name:"research-agent",systemPrompt:`---
835
835
  name: research-agent
836
836
  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.
837
837
  model: sonnet