agent-afk 2.27.0 → 2.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +3 -3
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1975,7 +1975,7 @@ _ended: ${new Date().toISOString()}_
|
|
|
1975
1975
|
`)}function QA(e){let t=[],n=(r,o)=>{o&&o.trim().length>0&&t.push({label:r,value:o.trim()})};switch(e.kind){case"done":n("done",e.whatWasDone),n("evidence",e.evidence),n("deferred",e.deferred);break;case"blocked":n("blocks",e.whatBlocks),n("unblock",e.unblockCondition),n("progress",e.alreadyDone);break;case"asking":n("question",e.question),n("resolves",e.assumption),n("after",e.followup);break;case"interrupted":n("was doing",e.whatWasInProgress),n("saved at",e.stateLocation),n("resume",e.resumeRequires);break}return t}function eR(e,t){let n=[];e&&n.push({type:"text",text:e});for(let r of t)n.push({type:"image",source:{type:"base64",media_type:r.mediaType,data:r.bytes.toString("base64")}});return n}async function Fg(e,t,n,r,o="summary",s,i){let a=bg(e.text,e.attachments);r.setInFlight(!0);let l="",c=!1,d,u=!1,m=!1,f=!1,g,b=!1,S=[],h=new Map,k=e.text.startsWith("/")?e.text.split(/[\s:]/)[0]?.slice(1):void 0,x=new Wt({out:Wn(),thinkingMode:o,...k?{activeSkillName:k}:{},onCancel:()=>{t.interrupt().catch(w=>{Ce()&&console.error(" "+p.error("session.interrupt() failed:"),w)})},...i?{onBackground:()=>{b=!0}}:{}}),R=async()=>{if(!m){m=!0;try{await x.dispose()}catch{}}};try{console.log(),await x.arm();let w=x.getCompositor();if(s&&w){let v=w;s.fn=E=>v.commitAbove(E)}r.setActiveCompositor?.(w),r.rearmStatus?.();let C=e.attachments.length===0?e.text:eR(e.text,e.attachments),T=t.sendMessageStream(C);if(await Sn(x.sink,async()=>{for await(let v of T){if(b&&i){let E=k??e.text.slice(0,40),I=i.register(E),_=ds(I,i);ps(T,l,a,I,i,_,n,r.onTurnComplete,t.abortSignal),await R(),console.log(p.dim(` \u2192 backgrounded as ${I.id}: ${I.label}`)),r.setInFlight(!1),r.rearmStatus?.();return}if(v.type==="chunk"&&v.chunk.type==="content"?(l+=v.chunk.content,c=!0):v.type==="message"&&!c&&(l=v.message.content),v.type==="chunk"&&v.chunk.type==="tool_use_detail"){let E=v.chunk,I={toolName:E.toolName,toolUseId:E.toolUseId,input:E.toolInput};h.set(E.toolUseId,I),S.push(I)}else if(v.type==="chunk"&&v.chunk.type==="tool_result"){let E=v.chunk,I=h.get(E.toolUseId);I&&(I.result=E.content,I.isError=E.isError,h.delete(E.toolUseId))}if(v.type==="paused"){await R(),console.log(kc({reason:v.reason,...v.resetsAt!==void 0?{resetsAt:v.resetsAt}:{},...v.accountId!==void 0?{accountId:v.accountId}:{}}));continue}if(v.type==="resumed"){let E=v.hotSwapped&&v.accountId?`\u25B6 Resumed on ${v.accountId}`:"\u25B6 Resumed";console.log(p.success(E));continue}if(v.type==="error"){await R(),bn(yn(v.error)),u=!0;continue}x.process(v),v.type==="done"&&(f=!0,g=v.metadata)}}),!m){let v=x.getCompositor();if(v)try{let{text:E,queued:I}=v.getBuffer();I&&E.length>0&&(d=E)}catch{}}if(await R(),f){ss(n,a,l,g,S),r.onTurnComplete&&await r.onTurnComplete(a,l).catch(()=>{}),c&&console.log(`
|
|
1976
1976
|
`);let v=Og(l);if(v&&(console.log(Dg(v)),console.log(),r.onTerminalState))try{r.onTerminalState(v)}catch{}if(tR(g,n),r.onAfterTurn){let E=r.onAfterTurn();E instanceof Promise&&await E.catch(()=>{})}}}catch(w){await R(),u||bn(yn(w))}finally{await R(),s&&(s.fn=w=>console.log(w)),r.setActiveCompositor?.(null),r.setInFlight(!1),r.rearmStatus?.()}return d}function tR(e,t){if(!e)return;let n=[];e.durationMs&&n.push(Z(e.durationMs)),e.totalCostUsd!==void 0&&n.push($e(e.totalCostUsd));let r=Number(e.usage?.input_tokens??0),o=Number(e.usage?.output_tokens??0);r+o>0&&n.push(H(r+o)+" tok"),n.length>0&&console.log(p.dim(" \u25E6 "+n.join(" \xB7 ")));let s=Sa(t);if(s>.5){let i=s>.8?p.error:p.warning;console.log(i(` context ${Math.round(s*100)}% used of ${H(tt(t.model))}`))}console.log()}function Lg(e={}){let t=e.load??ls,n=e.onResize??(i=>xt.subscribe(i)),r="",o,s=n(()=>{r=""});return{renderIfChanged(i){let a=i??"unbound",l=t(a),c=gm(l);return a===o&&c===r?[]:(o=a,r=c,c===""?[]:cs(l))},invalidate(){r=""},dispose(){try{s()}catch{}}}}var dl={done:{glyph:"\u2713",color:p.success,label:"done"},blocked:{glyph:"\u2298",color:p.error,label:"blocked"},asking:{glyph:"?",color:p.warning,label:"asking"},interrupted:{glyph:"\u23F8",color:p.info,label:"interrupted"}};function Ng(e={}){let t=Math.max(2,e.capacity??8),n=[];return{push(r){n.push(r.kind),n.length>t&&(n=n.slice(n.length-t))},reset(){n=[]},entries(){return n},render(){if(n.length===0)return null;let r=p.dim(" ledger "),o=p.dim(" \xB7 "),s=n.map(d=>{let u=dl[d];return u.color(`${u.glyph} ${u.label}`)}),i=p.dim(` (${n.length} turn${n.length===1?"":"s"})`),a=r+s.join(o)+i,l=Math.max(20,te()-2);if(j(a)<=l)return a;let c=r+n.map(d=>dl[d].color(dl[d].glyph)).join(p.dim(" "))+i;return ie(c,l)}}}var jg=["\u25D0","\u25D1","\u25D2","\u25D3"],qs=class{stream;manager;registry;throttleMs;started=!1;lastRepaint=0;spinnerIndex=0;spinnerInterval=null;resizeUnsub=null;updateHandler=null;registryStartedHandler=null;registrySettledHandler=null;subagentRunningCount=0;rowCount=0;onRowCountChange;constructor(t,n,r={}){this.manager=t,this.registry=n,this.stream=r.stream??process.stdout,this.throttleMs=r.throttleMs??200}setRowCountChangeHandler(t){this.onRowCountChange=t}start(){this.started||(this.started=!0,this.updateHandler=()=>this.scheduleRepaint(),this.manager.on("update",this.updateHandler),this.manager.on("complete",this.updateHandler),this.registry&&(this.registryStartedHandler=t=>{this.subagentRunningCount++,this.scheduleRepaint()},this.registrySettledHandler=t=>{this.subagentRunningCount=Math.max(0,this.subagentRunningCount-1),this.scheduleRepaint()},this.registry.on("started",this.registryStartedHandler),this.registry.on("settled",this.registrySettledHandler)),this.resizeUnsub=xt.subscribe(()=>this.repaint()),this.spinnerInterval=setInterval(()=>{this.spinnerIndex=(this.spinnerIndex+1)%jg.length,this.rowCount>0&&this.repaint()},Math.max(this.throttleMs,50)))}stop(){this.started&&(this.started=!1,this.updateHandler&&(this.manager.removeListener("update",this.updateHandler),this.manager.removeListener("complete",this.updateHandler),this.updateHandler=null),this.registry&&(this.registryStartedHandler&&(this.registry.off("started",this.registryStartedHandler),this.registryStartedHandler=null),this.registrySettledHandler&&(this.registry.off("settled",this.registrySettledHandler),this.registrySettledHandler=null)),this.resizeUnsub&&(this.resizeUnsub(),this.resizeUnsub=null),this.spinnerInterval&&(clearInterval(this.spinnerInterval),this.spinnerInterval=null),this.rowCount>0&&(this.clearRows(),this.rowCount=0,this.onRowCountChange?.(0)))}scheduleRepaint(){Date.now()-this.lastRepaint<this.throttleMs||this.repaint()}repaint(){if(!this.started||!this.stream.isTTY)return;this.lastRepaint=Date.now();let t=this.manager.running(),n=t.length+this.subagentRunningCount;if(n!==this.rowCount&&(this.rowCount>0&&this.clearRows(),this.rowCount=n,this.onRowCountChange?.(n)),n===0)return;let o=(this.stream.rows??24)-n;this.stream.write("\x1B[s");for(let s=0;s<t.length;s++){let i=t[s],a=o+s;this.stream.write(`\x1B[${a};1H`),this.stream.write("\x1B[2K"),this.stream.write(this.formatTaskLine(i))}this.stream.write("\x1B[u")}clearRows(){if(!this.stream.isTTY)return;let n=(this.stream.rows??24)-this.rowCount;this.stream.write("\x1B[s");for(let r=0;r<this.rowCount;r++)this.stream.write(`\x1B[${n+r};1H`),this.stream.write("\x1B[2K");this.stream.write("\x1B[u")}formatTaskLine(t){let n=Math.max(4,(this.stream.columns??80)-2),r=p.brand(jg[this.spinnerIndex]),o=p.dim(t.id),s=p.bold(t.label),i=[r,o,s];t.progressDescription&&i.push(p.dim(t.progressDescription));let a=[];t.stats.toolUses>0&&a.push(`${t.stats.toolUses} tool${t.stats.toolUses===1?"":"s"}`),t.stats.tokens>0&&a.push(`${H(t.stats.tokens)} tok`);let l=Date.now()-t.startedAt;return a.push(Z(l)),a.length>0&&i.push(p.dim(a.join(" \xB7 "))),ie(" "+i.join(" "),n)}};function Ug(e,t){let n=p.brand("afk")+p.dim(` (${e})`),r=t?p.warning(" \u25CF plan"):"";return n+r+p.dim(" \u203A ")}async function Bg(e,t,n,r){let o=null,s=[];e.session.waitForInitialization().then(async g=>{Ce()&&(o=as(g)),await $f(e.session),Ce()&&(s=Mf())}).catch(()=>{});let i=await $g(),a,l=Lg(),c=Ng(),d=new us;Cm(d),Im(d),Om(d),Mm(e.backgroundRegistry);let u=new qs(d,e.backgroundRegistry);u.setRowCountChangeHandler(g=>{e.statusLine.setExtraRows(g)}),u.start();let m=50,f=[];d.on("complete",g=>{f.length>=m&&f.shift(),f.push(g)});try{for(;;){if(o&&(e.replRenderer.writeLine(o),e.replRenderer.writeLine(""),o=null),s.length>0){for(let w of s)e.replRenderer.writeLine(w);e.replRenderer.writeLine(""),s=[]}for(;f.length>0;){let w=f.shift(),C=w.status==="succeeded"?"\u2713":"\u2717",T=[];if(w.resultText){let E=w.resultText.trim().split(`
|
|
1977
1977
|
`)[0]?.slice(0,80)??"";E&&T.push(E)}w.error&&T.push(w.error.message);let v=[w.stats.toolUses>0?`${w.stats.toolUses} tools`:"",w.stats.tokens>0?`${Math.round(w.stats.tokens/1e3)}k tok`:"",w.stats.durationMs>0?`${Math.round(w.stats.durationMs/1e3)}s`:""].filter(Boolean).join(" \xB7 ");v&&T.push(v),e.replRenderer.writeLine(Et({kind:w.status==="succeeded"?"checkpoint":"diagnosis",title:`${C} ${w.id} ${w.label}`,body:T})),e.replRenderer.writeLine("")}let g=l.renderIfChanged(e.stats.sessionId);if(g.length>0){for(let w of g)e.replRenderer.writeLine(w);e.replRenderer.writeLine("")}let b=c.render();b&&e.replRenderer.writeLine(b);let S,h;if(a!==void 0){let w=a;a=void 0;let C=Ug(e.stats.model,e.stats.planMode),T=Ir({buffer:w,promptText:C,isTTY:!!process.stdout.isTTY});e.replRenderer.writeLine(T),S=w.trim(),h=[]}else{let w=await _g({rl:e.rl,promptFn:()=>Ug(e.stats.model,e.stats.planMode),onSigint:r,statusLine:e.statusLine,compositor:n.activeCompositor??void 0,history:i,onShiftTab:()=>{let C=e.slashCtx;C.stats.planMode&&C.stats.pendingPlanExit?(C.stats.pendingPlanExit=!1,gt(C,!1,{closureSummarySkipped:!0}).catch(()=>{})):gt(C).catch(()=>{}),e.statusLine.rearm()}});S=w.text.trim(),h=w.attachments}if(!S&&h.length===0)continue;let k=!1;if(S.startsWith("/")){let w=await em(S,e.slashCtx);if(w.handled){if(w.result==="exit"){e.rl.close();return}if((S==="/clear"||S.startsWith("/clear "))&&(await t.rotateOnClear(),e.replRenderer.writeLine(p.dim(` transcript: ${t.path()}`)),c.reset()),w.result!==null&&typeof w.result=="object"&&"kind"in w.result&&w.result.kind==="submit"){a=w.result.message,e.statusLine.rearm();continue}e.statusLine.rearm();continue}k=!0}i.push(S);let x=S;if(k){let w=wa(S);if(w){let C=w.name.replace(/^\//,"").split(":").pop()??"";if(C&&qa(C)){let T={skillName:C,rawArgs:w.args,source:"plugin",capabilities:{compose:!0,subagents:!0}},v=e.session.sessionId,E=Dr(v),I=await Or(T,{cwd:process.cwd(),artifactDir:E},_=>{Ce()&&e.replRenderer.writeLine(p.warning(`\u26A0 preflight(${C}) failed: `)+(_ instanceof Error?_.message:String(_)))});x=Ja(I?.manifestBlock,S)}}}let R;if(e.firstTurnHook&&e.stats.totalTurns===0){let w=e.firstTurnHook;e.firstTurnHook=void 0,R=Promise.resolve().then(()=>w(S)).catch(C=>{console.warn(p.warning("\u26A0 ")+"first-turn hook failed: "+(C instanceof Error?C.message:String(C)))})}a=await Fg({text:x,attachments:h},e.session,e.stats,{setInFlight(w){n.turnInFlight=w},async onTurnComplete(w,C){await t.appendTurn(w,C)},async onAfterTurn(){await e.contextSampler.onTurn(e.stats.totalTurns),await im(e.slashCtx),e.statusLine.rearm()},rearmStatus:()=>e.statusLine.rearm(),onTerminalState:w=>c.push(w),setActiveCompositor:w=>{n.activeCompositor=w,e.replRenderer.setCompositor(w)}},e.options.thinkingUi,e.completionWriter,d),R!==void 0&&await R}}finally{u.stop(),l.dispose()}}import{promises as rR}from"node:fs";import{dirname as oR,join as sR}from"node:path";import{randomBytes as iR}from"node:crypto";import nR from"@anthropic-ai/sdk";import{randomUUID as Wg}from"node:crypto";async function Hg(e){let{token:t,model:n,system:r,user:o,maxTokens:s=64,signal:i,clientFactory:a}=e;if(!t)throw new Error("oneShotCompletion: token required");let l=oo(t),c=or(t,l),d=a?a(c):new nR(c),u=Wg(),m=Wg(),f=Zt(l,u,m),g={};Object.keys(f).length>0&&(g.headers=f),i&&(g.signal=i);let b=await d.messages.create({model:n,max_tokens:s,system:r,messages:[{role:"user",content:o}]},Object.keys(g).length>0?g:void 0),S=[];for(let k of b.content)k.type==="text"&&S.push(k.text);let h=S.join("").trim();return h.length===0&&console.warn("oneShotCompletion: response contained no text blocks \u2014 returning empty string"),h}var aR=["Generate a 2-4 word kebab-case slug describing this work request.","Rules:","- ASCII lowercase letters and digits only, separated by single hyphens","- 2 to 4 hyphen-separated words","- Maximum 30 characters total","- No prefix, no quotes, no punctuation other than hyphens","- Output ONLY the slug \u2014 no explanation, no preamble","Examples: fix-cleanup-race, add-telegram-allowlist, refactor-prompt-loader, debug-flaky-test"].join(`
|
|
1978
|
-
`),Kg=/^[a-z0-9]+(-[a-z0-9]+){1,3}$/,pl=30,lR=1024,cR=8e3,uR="haiku";async function dR(e,t){let n=e.trim();if(n.length===0||n.startsWith("/"))return null;let r=gR(n,lR),o=new AbortController,s=setTimeout(()=>o.abort(),t.timeoutMs??cR),i=t.signal?hR([t.signal,o.signal]):o.signal,a;try{t.slugGenerator?a=await t.slugGenerator(r,i):a=await Hg({token:t.token,model:t.model??uR,system:aR,user:r,maxTokens:32,signal:i})}catch{return null}finally{clearTimeout(s)}let l=pR(a);if(l===null)return null;let c=oR(t.worktreePath);return await mR(l,c)}function pR(e){let t=e.trim().toLowerCase();if(t.length===0)return null;if(Kg.test(t)&&t.length<=pl)return t;let n=t.replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");if(n.length===0)return null;let r=n.split("-").filter(s=>s.length>0).slice(0,4);if(r.length<2)return null;let o=r[0];for(let s=1;s<r.length;s++){let i=`${o}-${r[s]}`;if(i.length>pl)break;o=i}return Kg.test(o)?o:null}async function mR(e,t){if(!await fR(sR(t,e)))return e;let n=iR(2).toString("hex");return`${e.split("-").slice(0,3).join("-").slice(0,pl-5)}-${n}`}async function fR(e){try{return await rR.access(e),!0}catch{return!1}}function gR(e,t){let n=Buffer.from(e,"utf8");if(n.length<=t)return e;let r=t;for(;r>0&&n[r]!==void 0&&(n[r]&192)===128;)r--;return n.slice(0,r).toString("utf8")}function hR(e){let t=AbortSignal.any;if(typeof t=="function")return t.call(AbortSignal,e);let n=new AbortController;for(let r of e){if(r.aborted)return n.abort(r.reason),n.signal;r.addEventListener("abort",()=>n.abort(r.reason),{once:!0})}return n.signal}async function Gg(e){let t=await dR(e.message,{token:e.token,...e.model!==void 0?{model:e.model}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},worktreePath:e.handle.path,...e.signal!==void 0?{signal:e.signal}:{},...e.slugGenerator!==void 0?{slugGenerator:e.slugGenerator}:{}});if(t===null)return{status:"skipped",reason:"slug generation returned null"};let r=await(e.renameFn??Bp)(e.handle,t,e.branchPrefix!==void 0?{branchPrefix:e.branchPrefix}:void 0);return r.ok?(e.session&&e.session.setCwd(r.newPath),{status:"renamed",oldPath:r.oldPath,newPath:r.newPath,oldBranch:r.oldBranch,newBranch:r.newBranch}):(r.partial==="branch"&&e.session&&e.session.setCwd(e.handle.path),{status:"failed",reason:r.reason,...r.partial!==void 0?{partial:r.partial}:{}})}import{spawn as zg}from"child_process";import{existsSync as SR,mkdirSync as vR,readFileSync as qg,unlinkSync as TR,writeFileSync as xR}from"fs";import{get as ER}from"https";import{join as Yg}from"path";import{readFileSync as yR}from"fs";import{dirname as bR,join as kR}from"path";import{fileURLToPath as wR}from"url";function fn(){try{return"2.27.
|
|
1978
|
+
`),Kg=/^[a-z0-9]+(-[a-z0-9]+){1,3}$/,pl=30,lR=1024,cR=8e3,uR="haiku";async function dR(e,t){let n=e.trim();if(n.length===0||n.startsWith("/"))return null;let r=gR(n,lR),o=new AbortController,s=setTimeout(()=>o.abort(),t.timeoutMs??cR),i=t.signal?hR([t.signal,o.signal]):o.signal,a;try{t.slugGenerator?a=await t.slugGenerator(r,i):a=await Hg({token:t.token,model:t.model??uR,system:aR,user:r,maxTokens:32,signal:i})}catch{return null}finally{clearTimeout(s)}let l=pR(a);if(l===null)return null;let c=oR(t.worktreePath);return await mR(l,c)}function pR(e){let t=e.trim().toLowerCase();if(t.length===0)return null;if(Kg.test(t)&&t.length<=pl)return t;let n=t.replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");if(n.length===0)return null;let r=n.split("-").filter(s=>s.length>0).slice(0,4);if(r.length<2)return null;let o=r[0];for(let s=1;s<r.length;s++){let i=`${o}-${r[s]}`;if(i.length>pl)break;o=i}return Kg.test(o)?o:null}async function mR(e,t){if(!await fR(sR(t,e)))return e;let n=iR(2).toString("hex");return`${e.split("-").slice(0,3).join("-").slice(0,pl-5)}-${n}`}async function fR(e){try{return await rR.access(e),!0}catch{return!1}}function gR(e,t){let n=Buffer.from(e,"utf8");if(n.length<=t)return e;let r=t;for(;r>0&&n[r]!==void 0&&(n[r]&192)===128;)r--;return n.slice(0,r).toString("utf8")}function hR(e){let t=AbortSignal.any;if(typeof t=="function")return t.call(AbortSignal,e);let n=new AbortController;for(let r of e){if(r.aborted)return n.abort(r.reason),n.signal;r.addEventListener("abort",()=>n.abort(r.reason),{once:!0})}return n.signal}async function Gg(e){let t=await dR(e.message,{token:e.token,...e.model!==void 0?{model:e.model}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},worktreePath:e.handle.path,...e.signal!==void 0?{signal:e.signal}:{},...e.slugGenerator!==void 0?{slugGenerator:e.slugGenerator}:{}});if(t===null)return{status:"skipped",reason:"slug generation returned null"};let r=await(e.renameFn??Bp)(e.handle,t,e.branchPrefix!==void 0?{branchPrefix:e.branchPrefix}:void 0);return r.ok?(e.session&&e.session.setCwd(r.newPath),{status:"renamed",oldPath:r.oldPath,newPath:r.newPath,oldBranch:r.oldBranch,newBranch:r.newBranch}):(r.partial==="branch"&&e.session&&e.session.setCwd(e.handle.path),{status:"failed",reason:r.reason,...r.partial!==void 0?{partial:r.partial}:{}})}import{spawn as zg}from"child_process";import{existsSync as SR,mkdirSync as vR,readFileSync as qg,unlinkSync as TR,writeFileSync as xR}from"fs";import{get as ER}from"https";import{join as Yg}from"path";import{readFileSync as yR}from"fs";import{dirname as bR,join as kR}from"path";import{fileURLToPath as wR}from"url";function fn(){try{return"2.27.1"}catch{}try{let e=bR(wR(import.meta.url));for(let t of["../../package.json","../package.json"])try{let n=JSON.parse(yR(kR(e,t),"utf-8"));if(typeof n.version=="string")return n.version}catch{}}catch{}return"0.0.0-unknown"}var CR=64*1024,AR=1440*60*1e3,RR="update-check.json",_R="pending-update.json";function Jg(){return Yg(Yr(),RR)}function ml(){return Yg(Yr(),_R)}function Vg(){let e=Yr();SR(e)||vR(e,{recursive:!0})}function PR(e,t){let n=e.split(".").map(Number),r=t.split(".").map(Number),o=Math.max(n.length,r.length);for(let s=0;s<o;s++){let i=n[s]??0,a=r[s]??0;if(a>i)return!0;if(a<i)return!1}return!1}function IR(){try{let e=qg(Jg(),"utf-8"),t=JSON.parse(e);if(typeof t.latestVersion=="string"&&typeof t.checkedAt=="number")return t}catch{}return null}function MR(){try{Vg();let e=`
|
|
1979
1979
|
const https = require('https');
|
|
1980
1980
|
const fs = require('fs');
|
|
1981
1981
|
const url = 'https://registry.npmjs.org/agent-afk/latest';
|
|
@@ -2009,8 +2009,8 @@ ${r}Run \`npm install -g agent-afk\` to update${o}
|
|
|
2009
2009
|
Environment variables:`)),console.log(p.meta(" AFK_MODEL - Default model id (canonical; accepts short aliases or full ids)")),console.log(p.meta(" CLAUDE_MODEL - Legacy alias for AFK_MODEL (Claude-only deployments)")),console.log(p.meta(" ANTHROPIC_API_KEY - Anthropic API key (Claude models)")),console.log(p.meta(" CLAUDE_CODE_OAUTH_TOKEN - Anthropic OAuth token (Claude models)")),console.log(p.meta(" OPENAI_API_KEY / CODEX_API_KEY - OpenAI API key (Codex models)")),console.log(p.meta(" AFK_THINKING - Thinking mode (Claude only: adaptive|disabled|enabled:<N>)")),console.log(p.meta(" AFK_EFFORT - Effort level (low|medium|high|xhigh|max)")),console.log(p.meta(" AFK_TIMEOUT_MS - Per-tick daemon session timeout in ms")),console.log(p.meta(" AFK_SESSIONSTART_COOLDOWN_MS - Phase 6 cooldown between sessionstart fires (default 6h)")),console.log("")}})}import a_ from"path";import l_ from"os";import{createServer as n_}from"node:http";import{mkdirSync as VR,appendFileSync as XR}from"node:fs";import{dirname as ZR}from"node:path";import{execFile as QR}from"node:child_process";import{promisify as e_}from"node:util";import*as uh from"node-cron";import{promises as Ve,existsSync as oh,createReadStream as jR}from"node:fs";import{join as Vs}from"node:path";import{createInterface as UR}from"node:readline";var BR=36e5;function WR(e){let t=e.trim().split(/\n\n+/),n=[];for(let r of t){let o=r.split(`
|
|
2010
2010
|
`),s="",i="",a="",l=!1,c=!1,d=!1;for(let u of o)u.startsWith("worktree ")?s=u.slice(9).trim():u.startsWith("HEAD ")?i=u.slice(5).trim():u.startsWith("branch ")?a=u.slice(7).trim():u.trim()==="locked"?l=!0:u.trim()==="prunable"?c=!0:u.trim()==="bare"&&(d=!0);s&&n.push({path:s,head:i,branch:a,locked:l,prunable:c,isBare:d})}return n}function HR(e,t,n){if(e.locked)return"locked";let r=864e5,o=t*r,s=n*r;return e.commitsAhead===0&&!e.isDirty&&e.ageMs>=BR?"empty":e.isDirty&&e.ageMs>s?"stale-dirty":!e.isDirty&&e.ageMs>o?"stale-clean":"active"}async function KR(e){if(!oh(e))return 0;let t=0;try{let n=UR({input:jR(e),crlfDelay:1/0});for await(let r of n){let o=r.trim();if(o)try{let s=JSON.parse(o);s.taskId==="worktree-prune"&&(s.status==="success"||s.status==="error")&&t++}catch{}}}catch{}return t}var Xs=class extends Error{constructor(t){super(`Worktree sweep lock contested: ${t} \u2014 another sweep may be running.`),this.name="LockContestedError"}};async function GR(e){let t=Vs(e,"..");await Ve.mkdir(t,{recursive:!0}).catch(()=>{});let r=await(async()=>{try{return await Ve.open(e,"wx")}catch(o){if(o.code!=="EEXIST")throw o;let i=null;try{let a=await Ve.readFile(e,"utf-8");i=parseInt(a.trim(),10)}catch{}if(i!==null&&!Number.isNaN(i)){let a=!1;try{process.kill(i,0),a=!0}catch{}if(!a)return await Ve.unlink(e).catch(()=>{}),await Ve.open(e,"wx")}throw new Xs(e)}})();return await r.writeFile(String(process.pid),"utf-8"),await r.close(),async()=>{await Ve.unlink(e).catch(()=>{})}}async function jr(e){let{execFile:t,repoRoot:n,maxAgeDaysClean:r=14,maxAgeDaysDirty:o=30,scope:s="all",telemetryPath:i}=e,a=i??hn(),l=Gl(),c={removed:[],warnings:[],dryRun:e.dryRun??!1,candidates:[]},d=await KR(a),u=e.dryRun===!0||d<3;c.dryRun=u;let m=null;try{m=await GR(l)}catch(f){if(f instanceof Xs)return c.warnings.push(`[WARN] ${f.message}`),c;throw f}try{let f=await t("git",["-C",n,"worktree","list","--porcelain"]),g=WR(f.stdout),b=Vs(n,".afk-worktrees"),S=new Set(g.map(w=>w.path)),h=[];try{h=(await Ve.readdir(b,{withFileTypes:!0})).filter(C=>C.isDirectory()).map(C=>Vs(b,C.name))}catch{}let k=h.filter(w=>!S.has(w));if(s==="all"||s==="interactive")for(let w of k){let C=0;try{let T=await Ve.stat(w);C=Date.now()-T.birthtimeMs}catch{}if(c.candidates.push({path:w,verdict:"orphaned-dir",owner:"interactive",ageMs:C}),!u)try{await Ve.rm(w,{recursive:!0,force:!0}),c.removed.push(w)}catch(T){c.warnings.push(`[ERROR] Failed to remove orphaned dir ${w}: ${T instanceof Error?T.message:String(T)}`)}}let x=!1,R=g[0]?.path;for(let w of g){if(w.path===R||w.isBare||!w.path.startsWith(b))continue;let C;try{let P=await Ve.readFile(Vs(w.path,".afk-worktree-meta.json"),"utf-8");C=JSON.parse(P)}catch{}if(s!=="all"&&C?.owner!==s)continue;let T=C?.owner==="interactive"||C?.owner==="diagnose"?C.owner:"unknown";if(!oh(w.path)){c.candidates.push({path:w.path,verdict:"orphaned-registration",owner:T,ageMs:0}),u||(x=!0);continue}let v=0,E=C?.createdAt;if(E)v=Date.now()-new Date(E).getTime();else try{let P=await Ve.stat(w.path);v=Date.now()-P.birthtimeMs}catch{}let I=!1,_=0;try{I=(await t("git",["-C",w.path,"status","--porcelain"])).stdout.trim().length>0}catch{I=!0}if(!I&&w.head){let P=C?.baseSha??w.head;try{let M=await t("git",["-C",n,"rev-list",`${P}..${w.head}`,"--count"]);_=parseInt(M.stdout.trim(),10)||0}catch{_=0}}let $={path:w.path,head:w.head,branch:w.branch,locked:w.locked,prunable:w.prunable,meta:C,ageMs:v,isDirty:I,commitsAhead:_},F=HR($,r,o);if(c.candidates.push({path:w.path,verdict:F,owner:T,ageMs:v}),!u)try{F==="empty"?(await t("git",["-C",n,"worktree","remove","--force",w.path]),w.branch&&await t("git",["-C",n,"branch","-d",w.branch]).catch(()=>{}),c.removed.push(w.path)):F==="stale-clean"?(await t("git",["-C",n,"worktree","remove","--force",w.path]),c.removed.push(w.path)):F==="stale-dirty"&&c.warnings.push(`[WARN] stale-dirty worktree preserved (uncommitted changes): ${w.path}`)}catch(P){c.warnings.push(`[ERROR] Failed to process ${w.path} (${F}): ${P instanceof Error?P.message:String(P)}`)}}if(x&&!u)try{await t("git",["-C",n,"worktree","prune"])}catch(w){c.warnings.push(`[ERROR] git worktree prune failed: ${w instanceof Error?w.message:String(w)}`)}}finally{m&&await m()}return c}function sh(e){if(!e.taskId)throw new Error("ScheduledTask.taskId is required");if(!e.command)throw new Error(`task ${e.taskId}: command is required`);if((e.trigger==="cron"||e.trigger==="both")&&!e.cronExpression)throw new Error(`task ${e.taskId}: cronExpression required for trigger=${e.trigger}`)}import{existsSync as ih,readFileSync as zR,readdirSync as qR}from"node:fs";var ah=360*60*1e3;function lh(){return bt()}function YR(e,t){if(!ih(t))return null;let n;try{n=zR(t,"utf-8")}catch{return null}let r=n.split(`
|
|
2011
2011
|
`);for(let o=r.length-1;o>=0;o-=1){let s=r[o];if(s)try{let i=JSON.parse(s);if(i.taskId!==e||typeof i.triggeredAt!="string")continue;let a=Date.parse(i.triggeredAt);if(Number.isNaN(a))continue;return a}catch{continue}}return null}function JR(e){if(!ih(e))return 0;try{return qR(e).filter(t=>!t.startsWith(".")).length}catch{return 0}}function ch(e){let t=YR(e.taskId,e.telemetryPath);if(t!==null&&e.cooldownMs>0){let r=e.nowMs-t;if(r<e.cooldownMs)return{fire:!1,skipReason:"cooldown",lastFiredAtMs:t,cooldownRemainingMs:e.cooldownMs-r}}let n=JR(e.briefsDir);return n>0?{fire:!1,skipReason:"briefs_pending",pendingBriefCount:n,...t!==null?{lastFiredAtMs:t}:{}}:{fire:!0,...t!==null?{lastFiredAtMs:t}:{}}}var t_=e_(QR),Zs=class{registry=new Map;options;defaultCooldownMs;briefsDir;now;constructor(t={}){this.options=t,this.defaultCooldownMs=t.cooldownMs??ah,this.briefsDir=t.briefsDir??lh(),this.now=t.now??Date.now,this.ensureTelemetrySink()}register(t){if(sh(t),this.registry.has(t.taskId))throw new Error(`task ${t.taskId} is already registered`);let n;(t.trigger==="cron"||t.trigger==="both")&&(n=uh.schedule(t.cronExpression,()=>{this.runOnce(t,"cron").catch(()=>{})},{name:t.taskId})),this.registry.set(t.taskId,{task:t,cronTask:n})}unregister(t){let n=this.registry.get(t);n&&(n.cronTask&&(Promise.resolve(n.cronTask.stop()).catch(()=>{}),Promise.resolve(n.cronTask.destroy()).catch(()=>{})),this.registry.delete(t))}list(){return Array.from(this.registry.values()).map(t=>t.task)}async tick(t){let n=this.registry.get(t);if(!n)throw new Error(`task ${t} is not registered`);return this.runOnce(n.task,"cron")}async fireOnStart(){let t=Array.from(this.registry.values()).map(r=>r.task).filter(r=>r.trigger==="sessionstart"||r.trigger==="both"),n=[];for(let r of t){let o=r.debounceMs??this.defaultCooldownMs,s=ch({taskId:r.taskId,cooldownMs:o,nowMs:this.now(),telemetryPath:this.telemetryPath(),briefsDir:this.briefsDir});s.fire?n.push(await this.runOnce(r,"sessionstart")):n.push(this.recordSkip(r,s))}return n}async stop(){for(let t of Array.from(this.registry.keys()))this.unregister(t)}async runOnce(t,n){if(t.command==="__BUILTIN_WORKTREE_PRUNE__")return this.runBuiltinWorktreePrune(t,n);let r=new Date(this.now()),o=this.now(),s={taskId:t.taskId,command:jo(t.command),trigger:n,...t.cronExpression!==void 0?{cronExpression:t.cronExpression}:{},triggeredAt:r.toISOString()},i=null,a=null;try{let l=this.spawnSession();i=l.session,a=l.memoryStore;let c=await i.sendMessage(t.command),d={...s,durationMs:this.now()-o,status:"success",responseExcerpt:jo(c.content.slice(0,280))};return this.writeTelemetry(d),d}catch(l){let c=l instanceof Error?l.message:String(l),d={...s,durationMs:this.now()-o,status:"error",errorMessage:c};return this.writeTelemetry(d),d}finally{if(i)try{await i.close()}catch{}a?.close()}}recordSkip(t,n){let r=new Date(this.now()),o={taskId:t.taskId,command:t.command,trigger:"sessionstart",...t.cronExpression!==void 0?{cronExpression:t.cronExpression}:{},triggeredAt:r.toISOString(),durationMs:0,status:"skipped",...n.skipReason!==void 0?{skipReason:n.skipReason}:{}};return this.writeTelemetry(o),o}async runBuiltinWorktreePrune(t,n){let r=new Date(this.now()),o=this.now(),s={taskId:t.taskId,command:t.command,trigger:n,...t.cronExpression!==void 0?{cronExpression:t.cronExpression}:{},triggeredAt:r.toISOString()};try{let i=process.env.AFK_WORKTREE_SWEEP_ROOT??process.cwd(),a=parseInt(process.env.AFK_WORKTREE_MAX_AGE_CLEAN??"",10)||14,l=parseInt(process.env.AFK_WORKTREE_MAX_AGE_DIRTY??"",10)||30,c=await jr({execFile:t_,repoRoot:i,dryRun:!1,maxAgeDaysClean:a,maxAgeDaysDirty:l,scope:"all",telemetryPath:this.telemetryPath()}),d=new Set(["empty","stale-clean","orphaned-dir","orphaned-registration"]),u=c.dryRun?`\u{1F50D} worktree-prune (dry-run): would remove ${c.candidates.filter(f=>d.has(f.verdict)).length} worktree(s)`:`\u2702\uFE0F worktree-prune: removed ${c.removed.length}, warned ${c.warnings.length}`,m={...s,durationMs:this.now()-o,status:"success",responseExcerpt:u};return this.writeTelemetry(m),m}catch(i){let a={...s,durationMs:this.now()-o,status:"error",errorMessage:i instanceof Error?i.message:String(i)};return this.writeTelemetry(a),a}}spawnSession(){let{registry:t,memoryStore:n}=On(void 0,"daemon"),r={model:"sonnet",permissionMode:"bypassPermissions",hookRegistry:t,...this.options.sessionConfig};return{session:this.options.sessionFactory?this.options.sessionFactory(r):new Pe(en(r)),memoryStore:n}}telemetryPath(){return this.options.telemetryPath??hn()}ensureTelemetrySink(){try{VR(ZR(this.telemetryPath()),{recursive:!0})}catch{}}writeTelemetry(t){try{XR(this.telemetryPath(),`${JSON.stringify(t)}
|
|
2012
|
-
`,"utf-8"),this.fireOnTaskComplete(t)}catch(n){let r=n instanceof Error?n.message:String(n);console.error(`[daemon] telemetry write failed: ${r}`)}}fireOnTaskComplete(t){let n=this.options.onTaskComplete;if(n)try{let r=n(t);r instanceof Promise&&r.catch(o=>{let s=o instanceof Error?o.message:String(o);console.error(`[daemon] onTaskComplete callback failed: ${s}`)})}catch(r){let o=r instanceof Error?r.message:String(r);console.error(`[daemon] onTaskComplete callback failed: ${o}`)}}};var r_=7777;async function dh(e={}){let t=new Zs({...e.sessionConfig!==void 0?{sessionConfig:e.sessionConfig}:{},...e.telemetryPath!==void 0?{telemetryPath:e.telemetryPath}:{},...e.sessionFactory!==void 0?{sessionFactory:e.sessionFactory}:{},...e.cooldownMs!==void 0?{cooldownMs:e.cooldownMs}:{},...e.briefsDir!==void 0?{briefsDir:e.briefsDir}:{},...e.now!==void 0?{now:e.now}:{},...e.onTaskComplete!==void 0?{onTaskComplete:e.onTaskComplete}:{}});for(let o of e.tasks??[])t.register(o);let n=n_((o,s)=>o_(o,s,t));return{port:await s_(n,e.port??r_),scheduler:t,registerTask(o){t.register(o)},unregisterTask(o){t.unregister(o)},tickOnce(o){return t.tick(o)},fireOnStart(){return t.fireOnStart()},async stop(){await t.stop(),await i_(n)}}}function o_(e,t,n){let r=e.url??"/";if(e.method==="GET"&&r==="/health"){let o=JSON.stringify({status:"ok",tasks:n.list().length});t.writeHead(200,{"Content-Type":"application/json"}),t.end(o);return}if(e.method==="GET"&&r==="/tasks"){t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n.list()));return}t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"not found"}))}function s_(e,t){return new Promise((n,r)=>{e.once("error",r),e.listen(t,()=>{e.removeListener("error",r);let o=e.address();n(typeof o=="object"&&o?o.port:t)})})}function i_(e){return new Promise((t,n)=>{e.close(r=>{r?n(r):t()})})}No();function ph(e,t){let n=e??t;if(n===void 0||n==="")return;let r=Number(n);if(!Number.isFinite(r)||!Number.isInteger(r)||r<=0)throw new Error(`Invalid timeout-ms: '${n}' \u2014 must be a positive integer (milliseconds).`);return r}function mh(e,t){let n=e??t;if(n===void 0||n==="")return;let r=Number(n);if(!Number.isFinite(r)||!Number.isInteger(r)||r<0)throw new Error(`Invalid sessionstart-cooldown-ms: '${n}' \u2014 must be a non-negative integer (milliseconds).`);return r}function fh(e){if(e
|
|
2013
|
-
`)}function yh(e){e.command("daemon").description("Run agent-afk as a daemon that fires scheduled tasks (e.g. /forge-friction --auto)").option("-p, --port <number>","Control HTTP port","7777").option("-t, --task <command>",`Command to fire on each tick (default: ${bl})`).option("-c, --cron <expression>",'Cron expression (e.g. "0 */6 * * *"). Required when --trigger includes cron.').option("-i, --task-id <id>",`Task identifier (default: ${kl})`).option("--once","Fire one tick and exit (for testing)",!1).option("--timeout-ms <ms>","Per-tick session timeout in ms. Overrides AFK_TIMEOUT_MS. Defaults to the session default (120000).").option("--thinking <mode>","Thinking mode: 'adaptive' | 'disabled' | 'enabled:<N>'").option("--effort <level>","Effort level: low|medium|high|xhigh|max").option("--trigger <mode>","Trigger mode: cron | sessionstart | both. Defaults to cron.").option("--sessionstart-cooldown-ms <ms>","Cooldown between Phase 6 sessionstart fires. Overrides AFK_SESSIONSTART_COOLDOWN_MS. Defaults to 6h.").option("--briefs-dir <path>","Override directory scanned for pending briefs (defaults to ~/.afk/agent-framework/briefs).").option("--dump-prompt [path]",'Dump resolved SDK prompt+options+provenance to file (default: ~/.afk/logs/prompt-dump-<ISO>.json) or "stderr"').action(async t=>{let n=parseInt(t.port,10);(Number.isNaN(n)||n<=0)&&q(new Error(`Invalid port: ${t.port}`));let r=Ae(),o=gh(t.task,process.env.AFK_DAEMON_TASK,r.daemon?.task),s=hh(t.taskId,process.env.AFK_DAEMON_TASK_ID,r.daemon?.taskId),i,a,l;try{i=ph(t.timeoutMs,process.env.AFK_TIMEOUT_MS),a=mh(t.sessionstartCooldownMs,process.env.AFK_SESSIONSTART_COOLDOWN_MS),l=fh(t.trigger)}catch(w){q(w)}(l==="cron"||l==="both")&&!t.cron&&q(new Error(`--cron is required when --trigger is '${l}'.`));let c,d;try{c=$t(t.thinking)??An(),d=Ot(t.effort)??Rn()}catch(w){q(w)}let u={taskId:s,command:o,trigger:l,...t.cron!==void 0?{cronExpression:t.cron}:{}},m=r.daemon?.worktreePrune,f=process.env.AFK_WORKTREE_PRUNE_DISABLE==="1",g=m?.cron??"0 4 * * *",b={taskId:"worktree-prune",command:"__BUILTIN_WORKTREE_PRUNE__",trigger:"cron",cronExpression:g},S=[u];if(!f&&m?.enabled!==!1&&S.push(b),t.dumpPrompt!==void 0&&t.dumpPrompt!==!1){let w=t.dumpPrompt===!0?a_.join(l_.homedir(),".afk","logs",`prompt-dump-${new Date().toISOString().replace(/[:.]/g,"-")}.json`):t.dumpPrompt;process.env.AFK_DUMP_PROMPT=w}let h=0,k=6e4,x=(w,C)=>{let T=Date.now();if(T-h<k)return;h=T;let v=C instanceof Error?`${C.name}: ${C.message}`:String(C);Lo(`\u{1F6D1} agent-afk daemon ${w}
|
|
2012
|
+
`,"utf-8"),this.fireOnTaskComplete(t)}catch(n){let r=n instanceof Error?n.message:String(n);console.error(`[daemon] telemetry write failed: ${r}`)}}fireOnTaskComplete(t){let n=this.options.onTaskComplete;if(n)try{let r=n(t);r instanceof Promise&&r.catch(o=>{let s=o instanceof Error?o.message:String(o);console.error(`[daemon] onTaskComplete callback failed: ${s}`)})}catch(r){let o=r instanceof Error?r.message:String(r);console.error(`[daemon] onTaskComplete callback failed: ${o}`)}}};var r_=7777;async function dh(e={}){let t=new Zs({...e.sessionConfig!==void 0?{sessionConfig:e.sessionConfig}:{},...e.telemetryPath!==void 0?{telemetryPath:e.telemetryPath}:{},...e.sessionFactory!==void 0?{sessionFactory:e.sessionFactory}:{},...e.cooldownMs!==void 0?{cooldownMs:e.cooldownMs}:{},...e.briefsDir!==void 0?{briefsDir:e.briefsDir}:{},...e.now!==void 0?{now:e.now}:{},...e.onTaskComplete!==void 0?{onTaskComplete:e.onTaskComplete}:{}});for(let o of e.tasks??[])t.register(o);let n=n_((o,s)=>o_(o,s,t));return{port:await s_(n,e.port??r_),scheduler:t,registerTask(o){t.register(o)},unregisterTask(o){t.unregister(o)},tickOnce(o){return t.tick(o)},fireOnStart(){return t.fireOnStart()},async stop(){await t.stop(),await i_(n)}}}function o_(e,t,n){let r=e.url??"/";if(e.method==="GET"&&r==="/health"){let o=JSON.stringify({status:"ok",tasks:n.list().length});t.writeHead(200,{"Content-Type":"application/json"}),t.end(o);return}if(e.method==="GET"&&r==="/tasks"){t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(n.list()));return}t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"not found"}))}function s_(e,t){return new Promise((n,r)=>{e.once("error",r),e.listen(t,()=>{e.removeListener("error",r);let o=e.address();n(typeof o=="object"&&o?o.port:t)})})}function i_(e){return new Promise((t,n)=>{e.close(r=>{r?n(r):t()})})}No();function ph(e,t){let n=e??t;if(n===void 0||n==="")return;let r=Number(n);if(!Number.isFinite(r)||!Number.isInteger(r)||r<=0)throw new Error(`Invalid timeout-ms: '${n}' \u2014 must be a positive integer (milliseconds).`);return r}function mh(e,t){let n=e??t;if(n===void 0||n==="")return;let r=Number(n);if(!Number.isFinite(r)||!Number.isInteger(r)||r<0)throw new Error(`Invalid sessionstart-cooldown-ms: '${n}' \u2014 must be a non-negative integer (milliseconds).`);return r}function fh(e,t){if(e!==void 0&&e!==""){if(e==="cron"||e==="sessionstart"||e==="both")return e;throw new Error(`Invalid trigger: '${e}' \u2014 must be one of cron | sessionstart | both.`)}return t!==void 0&&t!==""?"cron":"sessionstart"}var bl="/forge-friction --auto",kl="default";function Vn(e){if(e!==void 0&&e.trim()!=="")return e}function gh(e,t,n){return Vn(e)??Vn(t)??Vn(n)??bl}function hh(e,t,n){return Vn(e)??Vn(t)??Vn(n)??kl}function c_(e){let t=e.status==="success"?"\u2705":e.status==="skipped"?"\u23ED\uFE0F":"\u274C",n=(e.durationMs/1e3).toFixed(1),r=[`${t} daemon task: ${e.taskId} (${e.status})`,`trigger=${e.trigger} duration=${n}s`];return e.skipReason&&r.push(`skipReason=${e.skipReason}`),e.errorMessage&&r.push(`error: ${e.errorMessage.slice(0,400)}`),e.responseExcerpt&&r.push("",e.responseExcerpt.slice(0,600)),r.join(`
|
|
2013
|
+
`)}function yh(e){e.command("daemon").description("Run agent-afk as a daemon that fires scheduled tasks (e.g. /forge-friction --auto)").option("-p, --port <number>","Control HTTP port","7777").option("-t, --task <command>",`Command to fire on each tick (default: ${bl})`).option("-c, --cron <expression>",'Cron expression (e.g. "0 */6 * * *"). Required when --trigger includes cron.').option("-i, --task-id <id>",`Task identifier (default: ${kl})`).option("--once","Fire one tick and exit (for testing)",!1).option("--timeout-ms <ms>","Per-tick session timeout in ms. Overrides AFK_TIMEOUT_MS. Defaults to the session default (120000).").option("--thinking <mode>","Thinking mode: 'adaptive' | 'disabled' | 'enabled:<N>'").option("--effort <level>","Effort level: low|medium|high|xhigh|max").option("--trigger <mode>","Trigger mode: cron | sessionstart | both. Defaults to cron.").option("--sessionstart-cooldown-ms <ms>","Cooldown between Phase 6 sessionstart fires. Overrides AFK_SESSIONSTART_COOLDOWN_MS. Defaults to 6h.").option("--briefs-dir <path>","Override directory scanned for pending briefs (defaults to ~/.afk/agent-framework/briefs).").option("--dump-prompt [path]",'Dump resolved SDK prompt+options+provenance to file (default: ~/.afk/logs/prompt-dump-<ISO>.json) or "stderr"').action(async t=>{let n=parseInt(t.port,10);(Number.isNaN(n)||n<=0)&&q(new Error(`Invalid port: ${t.port}`));let r=Ae(),o=gh(t.task,process.env.AFK_DAEMON_TASK,r.daemon?.task),s=hh(t.taskId,process.env.AFK_DAEMON_TASK_ID,r.daemon?.taskId),i,a,l;try{i=ph(t.timeoutMs,process.env.AFK_TIMEOUT_MS),a=mh(t.sessionstartCooldownMs,process.env.AFK_SESSIONSTART_COOLDOWN_MS),l=fh(t.trigger,t.cron)}catch(w){q(w)}(l==="cron"||l==="both")&&!t.cron&&q(new Error(`--cron is required when --trigger is '${l}'.`));let c,d;try{c=$t(t.thinking)??An(),d=Ot(t.effort)??Rn()}catch(w){q(w)}let u={taskId:s,command:o,trigger:l,...t.cron!==void 0?{cronExpression:t.cron}:{}},m=r.daemon?.worktreePrune,f=process.env.AFK_WORKTREE_PRUNE_DISABLE==="1",g=m?.cron??"0 4 * * *",b={taskId:"worktree-prune",command:"__BUILTIN_WORKTREE_PRUNE__",trigger:"cron",cronExpression:g},S=[u];if(!f&&m?.enabled!==!1&&S.push(b),t.dumpPrompt!==void 0&&t.dumpPrompt!==!1){let w=t.dumpPrompt===!0?a_.join(l_.homedir(),".afk","logs",`prompt-dump-${new Date().toISOString().replace(/[:.]/g,"-")}.json`):t.dumpPrompt;process.env.AFK_DUMP_PROMPT=w}let h=0,k=6e4,x=(w,C)=>{let T=Date.now();if(T-h<k)return;h=T;let v=C instanceof Error?`${C.name}: ${C.message}`:String(C);Lo(`\u{1F6D1} agent-afk daemon ${w}
|
|
2014
2014
|
${v.slice(0,500)}`).catch(E=>{console.error("[daemon] crash notification push failed:",E instanceof Error?E.message:String(E))})};process.on("uncaughtException",w=>{x("uncaughtException",w),process.exit(1)}),process.on("unhandledRejection",w=>{x("unhandledRejection",w),process.exit(1)});let R=process.env.AFK_DAEMON_CWD;try{let w=await dh({port:n,sessionConfig:{model:ve(),...V()!==void 0?{apiKey:V()}:{},...i!==void 0?{timeoutMs:i}:{},...c!==void 0?{thinking:c}:{},...d!==void 0?{effort:d}:{},...R!==void 0&&R.length>0?{cwd:R}:{}},...a!==void 0?{cooldownMs:a}:{},...t.briefsDir!==void 0?{briefsDir:t.briefsDir}:{},tasks:S,onTaskComplete:T=>{Lo(c_(T)).catch(()=>{})}});if(t.once){console.log(p.info(`\u25B6 Firing task '${s}' once...`));let T=await w.tickOnce(s);console.log(JSON.stringify(T,null,2)),await w.stop(),process.exit(T.status==="success"?0:1)}if(l==="sessionstart"||l==="both"){let T=await w.fireOnStart();for(let v of T){let E=v.status==="success"?"\u2714":v.status==="skipped"?"\u23ED":"\u2717";console.log(p.info(`${E} sessionstart: ${JSON.stringify(v)}`))}}console.log(p.success(`\u2714 Daemon listening on http://localhost:${w.port}`)),console.log(p.dim(` task='${s}' command='${o}' trigger='${l}'${t.cron?` cron='${t.cron}'`:""}`)),S.length>1&&console.log(p.meta(` + built-in: worktree-prune (cron: ${g})`)),console.log(p.dim(" Press Ctrl+C to stop."));let C=async()=>{console.log(p.dim(`
|
|
2015
2015
|
\xB7 Shutting down daemon...`)),await w.stop(),process.exit(0)};process.on("SIGINT",C),process.on("SIGTERM",C)}catch(w){q(w)}})}import Xn from"chalk";import{existsSync as u_,readFileSync as d_,writeFileSync as p_,mkdirSync as m_}from"fs";import{dirname as f_}from"path";import{createInterface as g_}from"readline";import bh from"chalk";function qt(e,t,n,r=[]){m_(f_(e),{recursive:!0});let o="";u_(e)&&(o=d_(e,"utf-8"));for(let a of r){let l=new RegExp(`^${a}=.*$
|
|
2016
2016
|
?`,"m");o=o.replace(l,"")}let s=`${t}=${n}`,i=new RegExp(`^${t}=.*$`,"m");i.test(o)?o=o.replace(i,s):(o&&!o.endsWith(`
|