agent-afk 3.87.0 → 3.87.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/README.md +3 -2
- package/dist/cli.mjs +365 -346
- package/dist/index.mjs +1 -1
- package/dist/telegram.mjs +2 -2
- package/package.json +10 -6
package/dist/index.mjs
CHANGED
|
@@ -1315,7 +1315,7 @@ Switch to:`,{parse_mode:"HTML",reply_markup:Yc.inlineKeyboard(u).reply_markup});
|
|
|
1315
1315
|
Aliases: ${Bt.join(", ")}, or org/model HF id`));return}try{await e.switchModel(r,a),await t.reply(Tt(a))}catch(d){n("Model switch error:",d),await t.reply(B(d))}}function xy(t,e){let n=t.trim();return n==="~"?Xc():n.startsWith("~/")?go(Xc(),n.slice(2)):Ey(n)?go(n):go(e,n)}async function Zc(t,e,n){let r=t.chat?.id;if(!r){await t.reply(B("Could not identify chat"));return}let s=t.message.text.split(/\s+/).slice(1).filter(l=>l.length>0);if(s.length===0){let l=e.getCwd(r);await t.reply(Ns(l));return}let i=s[0];if(!i){await t.reply(B("Please specify a directory path"));return}let a=e.getCwd(r)??process.cwd(),c=xy(i,a);try{if(!(await _y.stat(c)).isDirectory()){await t.reply(B(`Not a directory: ${c}`));return}}catch(l){let d=l.code;d==="ENOENT"?await t.reply(yr("ENOENT",c)):d==="EACCES"?await t.reply(yr("EACCES",c)):(n("cwd stat error:",l),await t.reply(B(l)));return}try{await e.setCwd(r,c),await t.reply($s(c))}catch(l){n("Cwd switch error:",l),await t.reply(B(l))}}async function el(t,e,n){let r=t.chat?.id;if(!r){await t.reply(B("Could not identify chat"));return}let s=t.message.text.split(/\s+/).slice(1).join(" ").trim();if(!s){await t.reply(Us(e.getSessionName(r)));return}let i=Nn(s);if(!i){await t.reply(Bs());return}try{let{persisted:a}=e.setSessionName(r,i),c=a?Vc(i,e.getModel(r)):void 0;await t.reply(Hs(i,c))}catch(a){n("Name set error:",a),await t.reply(`\u{1F3F7}\uFE0F Named "${i}" but couldn't save it \u2014 it'll retry on your next message.`)}}import{execFile as Wy,spawn as Ky}from"node:child_process";import{promisify as Gy}from"node:util";U();import{execFile as Ay}from"node:child_process";import{randomBytes as Ty}from"node:crypto";import{promises as Un}from"node:fs";import{join as Bn}from"node:path";import{promisify as Ry}from"node:util";var rM=Ry(Ay);var Fe=class extends Error{cause;code;constructor(e,n,r){super(e),this.name="WorktreeError",this.cause=n,this.code=r}};function Py(t,e=40){return t.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,e).replace(/-+$/g,"")||"task"}function Iy(){return Ty(4).toString("hex").slice(0,4)}function Cy(t){let e=n=>String(n).padStart(2,"0");return`${t.getUTCFullYear()}${e(t.getUTCMonth()+1)}${e(t.getUTCDate())}T${e(t.getUTCHours())}${e(t.getUTCMinutes())}${e(t.getUTCSeconds())}`}function tl(t,e={}){let n=(e.now??(()=>new Date))(),r=(e.randomSuffix??Iy)();return`${Cy(n)}-${Py(t,32)}-${r}`}function My(t){let e=t;return e.respawnedAt===void 0&&(e.respawnedAt=void 0),e.respawnedAs===void 0&&(e.respawnedAs=void 0),e.prUrl===void 0&&(e.prUrl=void 0),e.prCreatedAt===void 0&&(e.prCreatedAt=void 0),e}async function lt(t){let e=Bn(ts(t),"farm.json");try{let n=await Un.readFile(e,"utf8"),r=JSON.parse(n);if(r.schemaVersion!==1&&r.schemaVersion!==2&&r.schemaVersion!==3)throw new Fe(`unsupported farm manifest schema: ${r.schemaVersion} (expected 1, 2, or 3)`,void 0,"unsupported-schema");return My(r)}catch(n){if(n.code==="ENOENT")return null;throw n instanceof Fe?n:new Fe(`failed to load farm manifest ${e}`,n,"invalid")}}async function nl(t,e){let n=await lt(t);if(!n)throw new Fe(`farm not found: ${t}`);return n.human_decision=e,n.decidedAt=new Date().toISOString(),n.schemaVersion=3,await Un.writeFile(Bn(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1316
1316
|
`,"utf8"),n}async function rl(t,e){let n=await lt(t);if(!n)throw new Fe(`farm not found: ${t}`);return n.respawnedAt=new Date().toISOString(),n.respawnedAs=e,n.schemaVersion=3,await Un.writeFile(Bn(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1317
1317
|
`,"utf8"),n}async function ol(t,e){let n=await lt(t);if(!n)throw new Fe(`farm not found: ${t}`);return n.prUrl=e,n.prCreatedAt=new Date().toISOString(),n.schemaVersion=3,await Un.writeFile(Bn(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1318
|
-
`,"utf8"),n}import{execFile as Oy}from"node:child_process";import{promisify as Dy}from"node:util";var Fy=Dy(Oy),Ly=2e4,jt=class extends Error{kind;exitCode;stderr;constructor(e,n,r,o){super(e),this.name="GhError",this.kind=n,this.exitCode=r,this.stderr=o}},Hn=null,Ht=null;function Ny(t,e,n){return n===!0?"timeout":e==="ENOENT"?"not-found":/already exists/i.test(t)?"already-exists":/authentication|please log in|HTTP 40[13]|bad credentials|token|scope/i.test(t)?"unauthed":/ETIMEDOUT|ECONNRESET|ECONNREFUSED/i.test(t+(e??""))?"network":"unknown"}function sl(t,e){return Fy(t,e,{timeout:Ly,killSignal:"SIGTERM"}).then(n=>({stdout:n.stdout,stderr:n.stderr}))}async function il(t={}){let e=(t._now??(()=>Date.now()))(),n=t.ttlMs??6e4,r=t.execFn??sl,o=t.log??(()=>{});return Hn&&Hn.expiresAt>e?(o("[gh] checkGhReady cache hit"),Hn.result):(o("[gh] checkGhReady cache miss \u2014 probing"),Ht||(Ht=(async()=>{try{await r("gh",["--version"])}catch(a){let c=a;return c.killed?{ok:!1,hint:"`gh` timed out \u2014 check connectivity"}:c.code==="ENOENT"?{ok:!1,hint:"`gh` CLI not found \u2014 install with: brew install gh"}:{ok:!1,hint:"`gh --version` failed unexpectedly \u2014 check gh installation"}}try{await r("gh",["auth","status"])}catch(a){let c=a;return c.killed||/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(String(c.code??""))?{ok:!1,hint:"check network \u2014 cannot reach GitHub"}:{ok:!1,hint:"`gh` is not authenticated \u2014 run: gh auth login"}}let i={ok:!0};return n>0&&(Hn={result:i,expiresAt:e+n}),i})().finally(()=>{Ht=null}),Ht))}async function al(t,e){let n=e??sl,r=["pr","create","--base",t.base,"--head",t.head,"--title",t.title,"--body",t.body];try{let{stdout:o}=await n("gh",r);return o.trim()}catch(o){let s=o,i=s.stderr??"",a=s.code,c=s.exitCode??1,l=Ny(i,a,s.killed);throw new jt(`gh pr create failed (${l}): ${i.trim()}`,l,c,i)}}function cl(t,e){let n;try{n=e?._store??new be}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}try{let r={type:"farm-decision",taskSlug:t.taskSlug,decision:t.decision,decidedAt:t.decidedAt,via:t.via};return{factId:n.storeFact({category:"decision",content:JSON.stringify(r),source_surface:"afk"})}}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}}import{promises as $y}from"node:fs";import{join as Uy}from"node:path";function ul(t){let e=t.filter(r=>r.score!==null),n=t.filter(r=>r.score===null).map(r=>r.index).sort((r,o)=>r-o);return e.sort((r,o)=>{let s=r.score,i=o.score,a=ll(s),c=ll(i);if(a!==c)return c-a;let l=dl(s.lint_ok),d=dl(i.lint_ok);return l!==d?d-l:s.loc_delta!==i.loc_delta?s.loc_delta-i.loc_delta:r.index-o.index}),[...e.map(r=>r.index),...n]}function ll(t){let e=t.pass+t.fail;return e===0?0:t.pass/e}function dl(t){return t===!0?2:t===!1?1:0}async function jn(t,e={}){if(t.branches.length===0)throw new Error(`resolveWinnerBranch: farm ${t.taskSlug} has no branches`);let n=e.loadScore??By,r=await Promise.all(t.branches.map(async i=>({index:i.index,score:await n(t.farmDir,i.index)}))),o=ul(r),s=new Map(t.branches.map(i=>[i.index,i]));for(let i of o){let a=r.find(c=>c.index===i)?.score;if(a&&a.pass>0&&a.fail===0){let c=s.get(i);if(c)return{branch:c,source:"winner"}}}for(let i of o)if(r.find(c=>c.index===i)?.score){let c=s.get(i);if(c)return{branch:c,source:"top-scored"}}return{branch:t.branches[0],source:"fallback-first-branch"}}async function By(t,e){let n=Uy(t,"scores",`branch-${e}.json`);try{let r=await $y.readFile(n,"utf8");return JSON.parse(r)}catch(r){return r.code==="ENOENT",null}}var Wn="afk:f:";var Hy=new Set(["p","d","r","x"]),jy=/^[a-z0-9T][a-z0-9T-]{0,62}$/;function pl(t){if(!t||!t.startsWith(Wn)||Buffer.byteLength(t,"utf8")>64)return null;let e=t.slice(Wn.length),n=e.indexOf(":");if(n<1)return null;let r=e.slice(0,n),o=e.slice(n+1);return!Hy.has(r)||!jy.test(o)?null:{action:r,taskSlug:o}}var qy=Gy(Wy),bo=new Map;async function ml(t,e={}){let n=e.log??(()=>{}),r=zy(t),o=pl(r);if(!o){await z(t,"Unknown action",n);return}if(t.chat?.id===void 0){await z(t,"No chat context",n);return}let s=e.loadFarm??lt,i;try{i=await s(o.taskSlug)}catch(a){n("[farm-callback] loadFarm failed:",a),await z(t,"Farm load failed",n);return}if(!i){await z(t,"Farm not found (already GC\u2019d?)",n);return}try{await Jy(o.action,t,i,e,n)}catch(a){n("[farm-callback] dispatch error:",a),await z(t,"Internal error",n)}}function zy(t){return t.callbackQuery?.data}async function z(t,e,n){try{await t.answerCbQuery(e)}catch(r){n("[farm-callback] answerCbQuery failed:",r)}}async function Jy(t,e,n,r,o){switch(t){case"x":return Qy(e,n,r,o);case"d":return Zy(e,n,r,o);case"p":return fl(`p:${n.taskSlug}`,e,n,r,o,Vy);case"r":return fl(`r:${n.taskSlug}`,e,n,r,o,Xy)}}async function fl(t,e,n,r,o,s){let i=bo.get(t);if(i){o(`[farm-callback] ${t} \u2014 second tap, awaiting in-flight lock`);try{await i}catch{}let c=r.loadFarm??lt,l;try{l=await c(n.taskSlug)}catch{await z(e,"Farm load failed",o);return}if(!l){await z(e,"Farm not found",o);return}return s(e,l,r,o)}let a=s(e,n,r,o);return bo.set(t,a),a.finally(()=>{bo.delete(t)}),a}async function Vy(t,e,n,r){if(e.prUrl){await z(t,`PR already open: ${e.prUrl}`,r);return}await z(t,"Opening PR\u2026",r);let o=n.checkGhReady??il,s;try{s=await o()}catch(m){r("[farm-callback] checkGhReady threw:",m);try{await t.reply("gh readiness check failed \u2014 see daemon logs")}catch{}return}if(!s.ok){try{await t.reply(s.hint)}catch{}return}let i=n.resolveWinnerBranch??jn,a;try{a=await i(e)}catch(m){r("[farm-callback] resolveWinnerBranch failed:",m);try{await t.reply("Winner lookup failed")}catch{}return}let c=a.branch.branch,l=e.baseBranch??"main",d=`Auto PR: ${e.taskName}`,u=`Auto-generated by afk farm ${e.taskSlug} | winner: ${c} | created: ${new Date().toISOString()}`,p=n.createPr??al,f;try{f=await p({base:l,head:c,title:d,body:u})}catch(m){if(m instanceof jt){let k={"not-found":"gh CLI not found \u2014 install with: brew install gh","already-exists":"PR already exists for this branch",unauthed:"gh is not authenticated \u2014 run: gh auth login",network:"Network error \u2014 check gh connectivity",timeout:"gh timed out \u2014 check connectivity",unknown:"gh pr create failed \u2014 see daemon logs"};try{await t.reply(k[m.kind])}catch{}return}r("[farm-callback] createPr failed:",m);try{await t.reply("gh pr create failed \u2014 see daemon logs")}catch{}return}let g=n.recordPrCreated??ol;try{await g(e.taskSlug,f)}catch(m){r("[farm-callback] recordPrCreated failed:",m)}try{await t.reply(`PR opened \u2713
|
|
1318
|
+
`,"utf8"),n}import{execFile as Oy,spawn as iM}from"node:child_process";import{promisify as Dy}from"node:util";var Fy=Dy(Oy),Ly=2e4,jt=class extends Error{kind;exitCode;stderr;constructor(e,n,r,o){super(e),this.name="GhError",this.kind=n,this.exitCode=r,this.stderr=o}},Hn=null,Ht=null;function Ny(t,e,n){return n===!0?"timeout":e==="ENOENT"?"not-found":/already exists/i.test(t)?"already-exists":/authentication|please log in|HTTP 40[13]|bad credentials|token|scope/i.test(t)?"unauthed":/ETIMEDOUT|ECONNRESET|ECONNREFUSED/i.test(t+(e??""))?"network":"unknown"}function sl(t,e){return Fy(t,e,{timeout:Ly,killSignal:"SIGTERM"}).then(n=>({stdout:n.stdout,stderr:n.stderr}))}async function il(t={}){let e=(t._now??(()=>Date.now()))(),n=t.ttlMs??6e4,r=t.execFn??sl,o=t.log??(()=>{});return Hn&&Hn.expiresAt>e?(o("[gh] checkGhReady cache hit"),Hn.result):(o("[gh] checkGhReady cache miss \u2014 probing"),Ht||(Ht=(async()=>{try{await r("gh",["--version"])}catch(a){let c=a;return c.killed?{ok:!1,hint:"`gh` timed out \u2014 check connectivity"}:c.code==="ENOENT"?{ok:!1,hint:"`gh` CLI not found \u2014 install with: brew install gh"}:{ok:!1,hint:"`gh --version` failed unexpectedly \u2014 check gh installation"}}try{await r("gh",["auth","status"])}catch(a){let c=a;return c.killed||/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(String(c.code??""))?{ok:!1,hint:"check network \u2014 cannot reach GitHub"}:{ok:!1,hint:"`gh` is not authenticated \u2014 run: gh auth login"}}let i={ok:!0};return n>0&&(Hn={result:i,expiresAt:e+n}),i})().finally(()=>{Ht=null}),Ht))}async function al(t,e){let n=e??sl,r=["pr","create","--base",t.base,"--head",t.head,"--title",t.title,"--body",t.body];try{let{stdout:o}=await n("gh",r);return o.trim()}catch(o){let s=o,i=s.stderr??"",a=s.code,c=s.exitCode??1,l=Ny(i,a,s.killed);throw new jt(`gh pr create failed (${l}): ${i.trim()}`,l,c,i)}}function cl(t,e){let n;try{n=e?._store??new be}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}try{let r={type:"farm-decision",taskSlug:t.taskSlug,decision:t.decision,decidedAt:t.decidedAt,via:t.via};return{factId:n.storeFact({category:"decision",content:JSON.stringify(r),source_surface:"afk"})}}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}}import{promises as $y}from"node:fs";import{join as Uy}from"node:path";function ul(t){let e=t.filter(r=>r.score!==null),n=t.filter(r=>r.score===null).map(r=>r.index).sort((r,o)=>r-o);return e.sort((r,o)=>{let s=r.score,i=o.score,a=ll(s),c=ll(i);if(a!==c)return c-a;let l=dl(s.lint_ok),d=dl(i.lint_ok);return l!==d?d-l:s.loc_delta!==i.loc_delta?s.loc_delta-i.loc_delta:r.index-o.index}),[...e.map(r=>r.index),...n]}function ll(t){let e=t.pass+t.fail;return e===0?0:t.pass/e}function dl(t){return t===!0?2:t===!1?1:0}async function jn(t,e={}){if(t.branches.length===0)throw new Error(`resolveWinnerBranch: farm ${t.taskSlug} has no branches`);let n=e.loadScore??By,r=await Promise.all(t.branches.map(async i=>({index:i.index,score:await n(t.farmDir,i.index)}))),o=ul(r),s=new Map(t.branches.map(i=>[i.index,i]));for(let i of o){let a=r.find(c=>c.index===i)?.score;if(a&&a.pass>0&&a.fail===0){let c=s.get(i);if(c)return{branch:c,source:"winner"}}}for(let i of o)if(r.find(c=>c.index===i)?.score){let c=s.get(i);if(c)return{branch:c,source:"top-scored"}}return{branch:t.branches[0],source:"fallback-first-branch"}}async function By(t,e){let n=Uy(t,"scores",`branch-${e}.json`);try{let r=await $y.readFile(n,"utf8");return JSON.parse(r)}catch(r){return r.code==="ENOENT",null}}var Wn="afk:f:";var Hy=new Set(["p","d","r","x"]),jy=/^[a-z0-9T][a-z0-9T-]{0,62}$/;function pl(t){if(!t||!t.startsWith(Wn)||Buffer.byteLength(t,"utf8")>64)return null;let e=t.slice(Wn.length),n=e.indexOf(":");if(n<1)return null;let r=e.slice(0,n),o=e.slice(n+1);return!Hy.has(r)||!jy.test(o)?null:{action:r,taskSlug:o}}var qy=Gy(Wy),bo=new Map;async function ml(t,e={}){let n=e.log??(()=>{}),r=zy(t),o=pl(r);if(!o){await z(t,"Unknown action",n);return}if(t.chat?.id===void 0){await z(t,"No chat context",n);return}let s=e.loadFarm??lt,i;try{i=await s(o.taskSlug)}catch(a){n("[farm-callback] loadFarm failed:",a),await z(t,"Farm load failed",n);return}if(!i){await z(t,"Farm not found (already GC\u2019d?)",n);return}try{await Jy(o.action,t,i,e,n)}catch(a){n("[farm-callback] dispatch error:",a),await z(t,"Internal error",n)}}function zy(t){return t.callbackQuery?.data}async function z(t,e,n){try{await t.answerCbQuery(e)}catch(r){n("[farm-callback] answerCbQuery failed:",r)}}async function Jy(t,e,n,r,o){switch(t){case"x":return Qy(e,n,r,o);case"d":return Zy(e,n,r,o);case"p":return fl(`p:${n.taskSlug}`,e,n,r,o,Vy);case"r":return fl(`r:${n.taskSlug}`,e,n,r,o,Xy)}}async function fl(t,e,n,r,o,s){let i=bo.get(t);if(i){o(`[farm-callback] ${t} \u2014 second tap, awaiting in-flight lock`);try{await i}catch{}let c=r.loadFarm??lt,l;try{l=await c(n.taskSlug)}catch{await z(e,"Farm load failed",o);return}if(!l){await z(e,"Farm not found",o);return}return s(e,l,r,o)}let a=s(e,n,r,o);return bo.set(t,a),a.finally(()=>{bo.delete(t)}),a}async function Vy(t,e,n,r){if(e.prUrl){await z(t,`PR already open: ${e.prUrl}`,r);return}await z(t,"Opening PR\u2026",r);let o=n.checkGhReady??il,s;try{s=await o()}catch(m){r("[farm-callback] checkGhReady threw:",m);try{await t.reply("gh readiness check failed \u2014 see daemon logs")}catch{}return}if(!s.ok){try{await t.reply(s.hint)}catch{}return}let i=n.resolveWinnerBranch??jn,a;try{a=await i(e)}catch(m){r("[farm-callback] resolveWinnerBranch failed:",m);try{await t.reply("Winner lookup failed")}catch{}return}let c=a.branch.branch,l=e.baseBranch??"main",d=`Auto PR: ${e.taskName}`,u=`Auto-generated by afk farm ${e.taskSlug} | winner: ${c} | created: ${new Date().toISOString()}`,p=n.createPr??al,f;try{f=await p({base:l,head:c,title:d,body:u})}catch(m){if(m instanceof jt){let k={"not-found":"gh CLI not found \u2014 install with: brew install gh","already-exists":"PR already exists for this branch",unauthed:"gh is not authenticated \u2014 run: gh auth login",network:"Network error \u2014 check gh connectivity",timeout:"gh timed out \u2014 check connectivity",unknown:"gh pr create failed \u2014 see daemon logs"};try{await t.reply(k[m.kind])}catch{}return}r("[farm-callback] createPr failed:",m);try{await t.reply("gh pr create failed \u2014 see daemon logs")}catch{}return}let g=n.recordPrCreated??ol;try{await g(e.taskSlug,f)}catch(m){r("[farm-callback] recordPrCreated failed:",m)}try{await t.reply(`PR opened \u2713
|
|
1319
1319
|
\u{1F517} ${f}`)}catch(m){r("[farm-callback] reply failed:",m)}}function Yy(t,e=()=>{}){e("[farm] spawning child afk process",{args:t});let n=Ky("afk",t,{detached:!0,stdio:"ignore"});n.on("error",r=>{e("[farm] child spawn error",{args:t,err:r.message})}),n.on("exit",(r,o)=>{r!==0&&e("[farm] child exited with non-zero code",{args:t,code:r,signal:o})}),n.unref()}async function Xy(t,e,n,r){if(e.respawnedAs){await z(t,`Already respawned as ${e.respawnedAs}`,r);return}if(e.branches.length===0){await z(t,"No branches remain \u2014 cannot respawn",r);return}await z(t,"Respawning\u2026",r);let o=n.resolveWinnerBranch??jn,s;try{s=await o(e)}catch(u){r("[farm-callback] resolveWinnerBranch failed:",u);try{await t.reply("Winner lookup failed")}catch{}return}let i=s.branch,a=tl(e.taskName,{now:n._now,randomSuffix:n._randomSuffix}),c=e.branches.length;r("[farm] spawning child",{childSlug:a,baseRef:i.branch,branches:c});let l=n.spawnFarm??(u=>Yy(u,r));try{l(["farm",e.taskName,"--branches",String(c),"--base-ref",i.branch,"--task-slug",a])}catch(u){r("[farm-callback] spawnFarm failed:",u);try{await t.reply("Respawn failed")}catch{}return}let d=n.recordRespawn??rl;try{await d(e.taskSlug,a)}catch(u){r("[farm-callback] recordRespawn failed:",u)}try{await t.reply(`Respawning as \`${a}\` from ${i.branch} \u2713
|
|
1320
1320
|
\u{1F504} Farm \`${e.taskSlug}\` respawned.
|
|
1321
1321
|
Child slug: \`${a}\`
|
package/dist/telegram.mjs
CHANGED
|
@@ -1486,7 +1486,7 @@ Switch to:`,{parse_mode:"HTML",reply_markup:ed.inlineKeyboard(u).reply_markup});
|
|
|
1486
1486
|
Aliases: ${zt.join(", ")}, or org/model HF id`));return}try{await e.switchModel(r,a),await t.reply(mn(a))}catch(d){n("Model switch error:",d),await t.reply(W(d))}}function Dw(t,e){let n=t.trim();return n==="~"?td():n.startsWith("~/")?Ko(td(),n.slice(2)):Ow(n)?Ko(n):Ko(e,n)}async function rd(t,e,n){let r=t.chat?.id;if(!r){await t.reply(W("Could not identify chat"));return}let s=t.message.text.split(/\s+/).slice(1).filter(l=>l.length>0);if(s.length===0){let l=e.getCwd(r);await t.reply(js(l));return}let i=s[0];if(!i){await t.reply(W("Please specify a directory path"));return}let a=e.getCwd(r)??process.cwd(),c=Dw(i,a);try{if(!(await Mw.stat(c)).isDirectory()){await t.reply(W(`Not a directory: ${c}`));return}}catch(l){let d=l.code;d==="ENOENT"?await t.reply(Pr("ENOENT",c)):d==="EACCES"?await t.reply(Pr("EACCES",c)):(n("cwd stat error:",l),await t.reply(W(l)));return}try{await e.setCwd(r,c),await t.reply(Ws(c))}catch(l){n("Cwd switch error:",l),await t.reply(W(l))}}async function od(t,e,n){let r=t.chat?.id;if(!r){await t.reply(W("Could not identify chat"));return}let s=t.message.text.split(/\s+/).slice(1).join(" ").trim();if(!s){await t.reply(Ks(e.getSessionName(r)));return}let i=ln(s);if(!i){await t.reply(Gs());return}try{let{persisted:a}=e.setSessionName(r,i),c=a?Zl(i,e.getModel(r)):void 0;await t.reply(qs(i,c))}catch(a){n("Name set error:",a),await t.reply(`\u{1F3F7}\uFE0F Named "${i}" but couldn't save it \u2014 it'll retry on your next message.`)}}import{execFile as Qw,spawn as Zw}from"node:child_process";import{promisify as eS}from"node:util";U();import{execFile as Fw}from"node:child_process";import{randomBytes as Nw}from"node:crypto";import{promises as ir}from"node:fs";import{join as ar}from"node:path";import{promisify as Lw}from"node:util";var C0=Lw(Fw);var Ne=class extends Error{cause;code;constructor(e,n,r){super(e),this.name="WorktreeError",this.cause=n,this.code=r}};function $w(t,e=40){return t.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,e).replace(/-+$/g,"")||"task"}function Uw(){return Nw(4).toString("hex").slice(0,4)}function Hw(t){let e=n=>String(n).padStart(2,"0");return`${t.getUTCFullYear()}${e(t.getUTCMonth()+1)}${e(t.getUTCDate())}T${e(t.getUTCHours())}${e(t.getUTCMinutes())}${e(t.getUTCSeconds())}`}function sd(t,e={}){let n=(e.now??(()=>new Date))(),r=(e.randomSuffix??Uw)();return`${Hw(n)}-${$w(t,32)}-${r}`}function Bw(t){let e=t;return e.respawnedAt===void 0&&(e.respawnedAt=void 0),e.respawnedAs===void 0&&(e.respawnedAs=void 0),e.prUrl===void 0&&(e.prUrl=void 0),e.prCreatedAt===void 0&&(e.prCreatedAt=void 0),e}async function kt(t){let e=ar(us(t),"farm.json");try{let n=await ir.readFile(e,"utf8"),r=JSON.parse(n);if(r.schemaVersion!==1&&r.schemaVersion!==2&&r.schemaVersion!==3)throw new Ne(`unsupported farm manifest schema: ${r.schemaVersion} (expected 1, 2, or 3)`,void 0,"unsupported-schema");return Bw(r)}catch(n){if(n.code==="ENOENT")return null;throw n instanceof Ne?n:new Ne(`failed to load farm manifest ${e}`,n,"invalid")}}async function id(t,e){let n=await kt(t);if(!n)throw new Ne(`farm not found: ${t}`);return n.human_decision=e,n.decidedAt=new Date().toISOString(),n.schemaVersion=3,await ir.writeFile(ar(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1487
1487
|
`,"utf8"),n}async function ad(t,e){let n=await kt(t);if(!n)throw new Ne(`farm not found: ${t}`);return n.respawnedAt=new Date().toISOString(),n.respawnedAs=e,n.schemaVersion=3,await ir.writeFile(ar(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1488
1488
|
`,"utf8"),n}async function cd(t,e){let n=await kt(t);if(!n)throw new Ne(`farm not found: ${t}`);return n.prUrl=e,n.prCreatedAt=new Date().toISOString(),n.schemaVersion=3,await ir.writeFile(ar(n.farmDir,"farm.json"),JSON.stringify(n,null,2)+`
|
|
1489
|
-
`,"utf8"),n}import{execFile as jw}from"node:child_process";import{promisify as Ww}from"node:util";var Kw=Ww(jw),Gw=2e4,Vt=class extends Error{kind;exitCode;stderr;constructor(e,n,r,o){super(e),this.name="GhError",this.kind=n,this.exitCode=r,this.stderr=o}},cr=null,Jt=null;function qw(t,e,n){return n===!0?"timeout":e==="ENOENT"?"not-found":/already exists/i.test(t)?"already-exists":/authentication|please log in|HTTP 40[13]|bad credentials|token|scope/i.test(t)?"unauthed":/ETIMEDOUT|ECONNRESET|ECONNREFUSED/i.test(t+(e??""))?"network":"unknown"}function ld(t,e){return Kw(t,e,{timeout:Gw,killSignal:"SIGTERM"}).then(n=>({stdout:n.stdout,stderr:n.stderr}))}async function dd(t={}){let e=(t._now??(()=>Date.now()))(),n=t.ttlMs??6e4,r=t.execFn??ld,o=t.log??(()=>{});return cr&&cr.expiresAt>e?(o("[gh] checkGhReady cache hit"),cr.result):(o("[gh] checkGhReady cache miss \u2014 probing"),Jt||(Jt=(async()=>{try{await r("gh",["--version"])}catch(a){let c=a;return c.killed?{ok:!1,hint:"`gh` timed out \u2014 check connectivity"}:c.code==="ENOENT"?{ok:!1,hint:"`gh` CLI not found \u2014 install with: brew install gh"}:{ok:!1,hint:"`gh --version` failed unexpectedly \u2014 check gh installation"}}try{await r("gh",["auth","status"])}catch(a){let c=a;return c.killed||/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(String(c.code??""))?{ok:!1,hint:"check network \u2014 cannot reach GitHub"}:{ok:!1,hint:"`gh` is not authenticated \u2014 run: gh auth login"}}let i={ok:!0};return n>0&&(cr={result:i,expiresAt:e+n}),i})().finally(()=>{Jt=null}),Jt))}async function ud(t,e){let n=e??ld,r=["pr","create","--base",t.base,"--head",t.head,"--title",t.title,"--body",t.body];try{let{stdout:o}=await n("gh",r);return o.trim()}catch(o){let s=o,i=s.stderr??"",a=s.code,c=s.exitCode??1,l=qw(i,a,s.killed);throw new Vt(`gh pr create failed (${l}): ${i.trim()}`,l,c,i)}}function pd(t,e){let n;try{n=e?._store??new oe}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}try{let r={type:"farm-decision",taskSlug:t.taskSlug,decision:t.decision,decidedAt:t.decidedAt,via:t.via};return{factId:n.storeFact({category:"decision",content:JSON.stringify(r),source_surface:"afk"})}}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}}import{promises as zw}from"node:fs";import{join as Jw}from"node:path";function gd(t){let e=t.filter(r=>r.score!==null),n=t.filter(r=>r.score===null).map(r=>r.index).sort((r,o)=>r-o);return e.sort((r,o)=>{let s=r.score,i=o.score,a=fd(s),c=fd(i);if(a!==c)return c-a;let l=md(s.lint_ok),d=md(i.lint_ok);return l!==d?d-l:s.loc_delta!==i.loc_delta?s.loc_delta-i.loc_delta:r.index-o.index}),[...e.map(r=>r.index),...n]}function fd(t){let e=t.pass+t.fail;return e===0?0:t.pass/e}function md(t){return t===!0?2:t===!1?1:0}async function lr(t,e={}){if(t.branches.length===0)throw new Error(`resolveWinnerBranch: farm ${t.taskSlug} has no branches`);let n=e.loadScore??Vw,r=await Promise.all(t.branches.map(async i=>({index:i.index,score:await n(t.farmDir,i.index)}))),o=gd(r),s=new Map(t.branches.map(i=>[i.index,i]));for(let i of o){let a=r.find(c=>c.index===i)?.score;if(a&&a.pass>0&&a.fail===0){let c=s.get(i);if(c)return{branch:c,source:"winner"}}}for(let i of o)if(r.find(c=>c.index===i)?.score){let c=s.get(i);if(c)return{branch:c,source:"top-scored"}}return{branch:t.branches[0],source:"fallback-first-branch"}}async function Vw(t,e){let n=Jw(t,"scores",`branch-${e}.json`);try{let r=await zw.readFile(n,"utf8");return JSON.parse(r)}catch(r){return r.code==="ENOENT",null}}var dr="afk:f:";var Yw=new Set(["p","d","r","x"]),Xw=/^[a-z0-9T][a-z0-9T-]{0,62}$/;function hd(t){if(!t||!t.startsWith(dr)||Buffer.byteLength(t,"utf8")>64)return null;let e=t.slice(dr.length),n=e.indexOf(":");if(n<1)return null;let r=e.slice(0,n),o=e.slice(n+1);return!Yw.has(r)||!Xw.test(o)?null:{action:r,taskSlug:o}}var tS=eS(Qw),zo=new Map;async function bd(t,e={}){let n=e.log??(()=>{}),r=nS(t),o=hd(r);if(!o){await Q(t,"Unknown action",n);return}if(t.chat?.id===void 0){await Q(t,"No chat context",n);return}let s=e.loadFarm??kt,i;try{i=await s(o.taskSlug)}catch(a){n("[farm-callback] loadFarm failed:",a),await Q(t,"Farm load failed",n);return}if(!i){await Q(t,"Farm not found (already GC\u2019d?)",n);return}try{await rS(o.action,t,i,e,n)}catch(a){n("[farm-callback] dispatch error:",a),await Q(t,"Internal error",n)}}function nS(t){return t.callbackQuery?.data}async function Q(t,e,n){try{await t.answerCbQuery(e)}catch(r){n("[farm-callback] answerCbQuery failed:",r)}}async function rS(t,e,n,r,o){switch(t){case"x":return aS(e,n,r,o);case"d":return cS(e,n,r,o);case"p":return yd(`p:${n.taskSlug}`,e,n,r,o,oS);case"r":return yd(`r:${n.taskSlug}`,e,n,r,o,iS)}}async function yd(t,e,n,r,o,s){let i=zo.get(t);if(i){o(`[farm-callback] ${t} \u2014 second tap, awaiting in-flight lock`);try{await i}catch{}let c=r.loadFarm??kt,l;try{l=await c(n.taskSlug)}catch{await Q(e,"Farm load failed",o);return}if(!l){await Q(e,"Farm not found",o);return}return s(e,l,r,o)}let a=s(e,n,r,o);return zo.set(t,a),a.finally(()=>{zo.delete(t)}),a}async function oS(t,e,n,r){if(e.prUrl){await Q(t,`PR already open: ${e.prUrl}`,r);return}await Q(t,"Opening PR\u2026",r);let o=n.checkGhReady??dd,s;try{s=await o()}catch(g){r("[farm-callback] checkGhReady threw:",g);try{await t.reply("gh readiness check failed \u2014 see daemon logs")}catch{}return}if(!s.ok){try{await t.reply(s.hint)}catch{}return}let i=n.resolveWinnerBranch??lr,a;try{a=await i(e)}catch(g){r("[farm-callback] resolveWinnerBranch failed:",g);try{await t.reply("Winner lookup failed")}catch{}return}let c=a.branch.branch,l=e.baseBranch??"main",d=`Auto PR: ${e.taskName}`,u=`Auto-generated by afk farm ${e.taskSlug} | winner: ${c} | created: ${new Date().toISOString()}`,p=n.createPr??ud,m;try{m=await p({base:l,head:c,title:d,body:u})}catch(g){if(g instanceof Vt){let y={"not-found":"gh CLI not found \u2014 install with: brew install gh","already-exists":"PR already exists for this branch",unauthed:"gh is not authenticated \u2014 run: gh auth login",network:"Network error \u2014 check gh connectivity",timeout:"gh timed out \u2014 check connectivity",unknown:"gh pr create failed \u2014 see daemon logs"};try{await t.reply(y[g.kind])}catch{}return}r("[farm-callback] createPr failed:",g);try{await t.reply("gh pr create failed \u2014 see daemon logs")}catch{}return}let h=n.recordPrCreated??cd;try{await h(e.taskSlug,m)}catch(g){r("[farm-callback] recordPrCreated failed:",g)}try{await t.reply(`PR opened \u2713
|
|
1489
|
+
`,"utf8"),n}import{execFile as jw,spawn as D0}from"node:child_process";import{promisify as Ww}from"node:util";var Kw=Ww(jw),Gw=2e4,Vt=class extends Error{kind;exitCode;stderr;constructor(e,n,r,o){super(e),this.name="GhError",this.kind=n,this.exitCode=r,this.stderr=o}},cr=null,Jt=null;function qw(t,e,n){return n===!0?"timeout":e==="ENOENT"?"not-found":/already exists/i.test(t)?"already-exists":/authentication|please log in|HTTP 40[13]|bad credentials|token|scope/i.test(t)?"unauthed":/ETIMEDOUT|ECONNRESET|ECONNREFUSED/i.test(t+(e??""))?"network":"unknown"}function ld(t,e){return Kw(t,e,{timeout:Gw,killSignal:"SIGTERM"}).then(n=>({stdout:n.stdout,stderr:n.stderr}))}async function dd(t={}){let e=(t._now??(()=>Date.now()))(),n=t.ttlMs??6e4,r=t.execFn??ld,o=t.log??(()=>{});return cr&&cr.expiresAt>e?(o("[gh] checkGhReady cache hit"),cr.result):(o("[gh] checkGhReady cache miss \u2014 probing"),Jt||(Jt=(async()=>{try{await r("gh",["--version"])}catch(a){let c=a;return c.killed?{ok:!1,hint:"`gh` timed out \u2014 check connectivity"}:c.code==="ENOENT"?{ok:!1,hint:"`gh` CLI not found \u2014 install with: brew install gh"}:{ok:!1,hint:"`gh --version` failed unexpectedly \u2014 check gh installation"}}try{await r("gh",["auth","status"])}catch(a){let c=a;return c.killed||/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(String(c.code??""))?{ok:!1,hint:"check network \u2014 cannot reach GitHub"}:{ok:!1,hint:"`gh` is not authenticated \u2014 run: gh auth login"}}let i={ok:!0};return n>0&&(cr={result:i,expiresAt:e+n}),i})().finally(()=>{Jt=null}),Jt))}async function ud(t,e){let n=e??ld,r=["pr","create","--base",t.base,"--head",t.head,"--title",t.title,"--body",t.body];try{let{stdout:o}=await n("gh",r);return o.trim()}catch(o){let s=o,i=s.stderr??"",a=s.code,c=s.exitCode??1,l=qw(i,a,s.killed);throw new Vt(`gh pr create failed (${l}): ${i.trim()}`,l,c,i)}}function pd(t,e){let n;try{n=e?._store??new oe}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}try{let r={type:"farm-decision",taskSlug:t.taskSlug,decision:t.decision,decidedAt:t.decidedAt,via:t.via};return{factId:n.storeFact({category:"decision",content:JSON.stringify(r),source_surface:"afk"})}}catch(r){return{skipped:!0,reason:r instanceof Error?r.message:String(r)}}}import{promises as zw}from"node:fs";import{join as Jw}from"node:path";function gd(t){let e=t.filter(r=>r.score!==null),n=t.filter(r=>r.score===null).map(r=>r.index).sort((r,o)=>r-o);return e.sort((r,o)=>{let s=r.score,i=o.score,a=fd(s),c=fd(i);if(a!==c)return c-a;let l=md(s.lint_ok),d=md(i.lint_ok);return l!==d?d-l:s.loc_delta!==i.loc_delta?s.loc_delta-i.loc_delta:r.index-o.index}),[...e.map(r=>r.index),...n]}function fd(t){let e=t.pass+t.fail;return e===0?0:t.pass/e}function md(t){return t===!0?2:t===!1?1:0}async function lr(t,e={}){if(t.branches.length===0)throw new Error(`resolveWinnerBranch: farm ${t.taskSlug} has no branches`);let n=e.loadScore??Vw,r=await Promise.all(t.branches.map(async i=>({index:i.index,score:await n(t.farmDir,i.index)}))),o=gd(r),s=new Map(t.branches.map(i=>[i.index,i]));for(let i of o){let a=r.find(c=>c.index===i)?.score;if(a&&a.pass>0&&a.fail===0){let c=s.get(i);if(c)return{branch:c,source:"winner"}}}for(let i of o)if(r.find(c=>c.index===i)?.score){let c=s.get(i);if(c)return{branch:c,source:"top-scored"}}return{branch:t.branches[0],source:"fallback-first-branch"}}async function Vw(t,e){let n=Jw(t,"scores",`branch-${e}.json`);try{let r=await zw.readFile(n,"utf8");return JSON.parse(r)}catch(r){return r.code==="ENOENT",null}}var dr="afk:f:";var Yw=new Set(["p","d","r","x"]),Xw=/^[a-z0-9T][a-z0-9T-]{0,62}$/;function hd(t){if(!t||!t.startsWith(dr)||Buffer.byteLength(t,"utf8")>64)return null;let e=t.slice(dr.length),n=e.indexOf(":");if(n<1)return null;let r=e.slice(0,n),o=e.slice(n+1);return!Yw.has(r)||!Xw.test(o)?null:{action:r,taskSlug:o}}var tS=eS(Qw),zo=new Map;async function bd(t,e={}){let n=e.log??(()=>{}),r=nS(t),o=hd(r);if(!o){await Q(t,"Unknown action",n);return}if(t.chat?.id===void 0){await Q(t,"No chat context",n);return}let s=e.loadFarm??kt,i;try{i=await s(o.taskSlug)}catch(a){n("[farm-callback] loadFarm failed:",a),await Q(t,"Farm load failed",n);return}if(!i){await Q(t,"Farm not found (already GC\u2019d?)",n);return}try{await rS(o.action,t,i,e,n)}catch(a){n("[farm-callback] dispatch error:",a),await Q(t,"Internal error",n)}}function nS(t){return t.callbackQuery?.data}async function Q(t,e,n){try{await t.answerCbQuery(e)}catch(r){n("[farm-callback] answerCbQuery failed:",r)}}async function rS(t,e,n,r,o){switch(t){case"x":return aS(e,n,r,o);case"d":return cS(e,n,r,o);case"p":return yd(`p:${n.taskSlug}`,e,n,r,o,oS);case"r":return yd(`r:${n.taskSlug}`,e,n,r,o,iS)}}async function yd(t,e,n,r,o,s){let i=zo.get(t);if(i){o(`[farm-callback] ${t} \u2014 second tap, awaiting in-flight lock`);try{await i}catch{}let c=r.loadFarm??kt,l;try{l=await c(n.taskSlug)}catch{await Q(e,"Farm load failed",o);return}if(!l){await Q(e,"Farm not found",o);return}return s(e,l,r,o)}let a=s(e,n,r,o);return zo.set(t,a),a.finally(()=>{zo.delete(t)}),a}async function oS(t,e,n,r){if(e.prUrl){await Q(t,`PR already open: ${e.prUrl}`,r);return}await Q(t,"Opening PR\u2026",r);let o=n.checkGhReady??dd,s;try{s=await o()}catch(g){r("[farm-callback] checkGhReady threw:",g);try{await t.reply("gh readiness check failed \u2014 see daemon logs")}catch{}return}if(!s.ok){try{await t.reply(s.hint)}catch{}return}let i=n.resolveWinnerBranch??lr,a;try{a=await i(e)}catch(g){r("[farm-callback] resolveWinnerBranch failed:",g);try{await t.reply("Winner lookup failed")}catch{}return}let c=a.branch.branch,l=e.baseBranch??"main",d=`Auto PR: ${e.taskName}`,u=`Auto-generated by afk farm ${e.taskSlug} | winner: ${c} | created: ${new Date().toISOString()}`,p=n.createPr??ud,m;try{m=await p({base:l,head:c,title:d,body:u})}catch(g){if(g instanceof Vt){let y={"not-found":"gh CLI not found \u2014 install with: brew install gh","already-exists":"PR already exists for this branch",unauthed:"gh is not authenticated \u2014 run: gh auth login",network:"Network error \u2014 check gh connectivity",timeout:"gh timed out \u2014 check connectivity",unknown:"gh pr create failed \u2014 see daemon logs"};try{await t.reply(y[g.kind])}catch{}return}r("[farm-callback] createPr failed:",g);try{await t.reply("gh pr create failed \u2014 see daemon logs")}catch{}return}let h=n.recordPrCreated??cd;try{await h(e.taskSlug,m)}catch(g){r("[farm-callback] recordPrCreated failed:",g)}try{await t.reply(`PR opened \u2713
|
|
1490
1490
|
\u{1F517} ${m}`)}catch(g){r("[farm-callback] reply failed:",g)}}function sS(t,e=()=>{}){e("[farm] spawning child afk process",{args:t});let n=Zw("afk",t,{detached:!0,stdio:"ignore"});n.on("error",r=>{e("[farm] child spawn error",{args:t,err:r.message})}),n.on("exit",(r,o)=>{r!==0&&e("[farm] child exited with non-zero code",{args:t,code:r,signal:o})}),n.unref()}async function iS(t,e,n,r){if(e.respawnedAs){await Q(t,`Already respawned as ${e.respawnedAs}`,r);return}if(e.branches.length===0){await Q(t,"No branches remain \u2014 cannot respawn",r);return}await Q(t,"Respawning\u2026",r);let o=n.resolveWinnerBranch??lr,s;try{s=await o(e)}catch(u){r("[farm-callback] resolveWinnerBranch failed:",u);try{await t.reply("Winner lookup failed")}catch{}return}let i=s.branch,a=sd(e.taskName,{now:n._now,randomSuffix:n._randomSuffix}),c=e.branches.length;r("[farm] spawning child",{childSlug:a,baseRef:i.branch,branches:c});let l=n.spawnFarm??(u=>sS(u,r));try{l(["farm",e.taskName,"--branches",String(c),"--base-ref",i.branch,"--task-slug",a])}catch(u){r("[farm-callback] spawnFarm failed:",u);try{await t.reply("Respawn failed")}catch{}return}let d=n.recordRespawn??ad;try{await d(e.taskSlug,a)}catch(u){r("[farm-callback] recordRespawn failed:",u)}try{await t.reply(`Respawning as \`${a}\` from ${i.branch} \u2713
|
|
1491
1491
|
\u{1F504} Farm \`${e.taskSlug}\` respawned.
|
|
1492
1492
|
Child slug: \`${a}\`
|
|
@@ -1542,7 +1542,7 @@ Enter a number${y}`}m&&(s.allowSkip?g+=`
|
|
|
1542
1542
|
|
|
1543
1543
|
<i>Enter empty to skip, or :cancel to cancel.</i>`:g+=`
|
|
1544
1544
|
|
|
1545
|
-
<i>Type :cancel to cancel.</i>`),e.telegram.sendMessage(n,g,{parse_mode:"HTML"}).catch(()=>{u||(u=!0,i.signal.removeEventListener("abort",p),console.warn("[elicitation-handler] sendMessage failed; declining elicitation for chatId",n),t.pendingElicitations.delete(n),d({action:"decline"}))})})}}var mr=class{bot;sessionManager;options;running=!1;registeredCommandChats=new Set;messageHandler;constructor(e){this.options=e,this.bot=new SS(e.botToken),this.sessionManager=new un(e),this.messageHandler=new ur(this.bot,this.sessionManager,this.registeredCommandChats,this.log.bind(this)),this.setupHandlers()}setupHandlers(){this.bot.use(Wi(this.options.allowedChatIds,this.log.bind(this))),this.bot.command("start",n=>Cr(n)),this.bot.command("help",n=>Mr(n,this.sessionManager)),this.bot.command("clear",async n=>{let r=n.chat?.id;if(!r){await n.reply(W("Could not identify chat"));return}(await this.sessionManager.getSession(r)).state!=="idle"?(this.messageHandler.enqueueClear(r,n),await n.reply("Clear queued.")):await Go(n,this.sessionManager,this.registeredCommandChats,this.log.bind(this))}),this.bot.command("compact",async n=>{let r=n.chat?.id;if(!r){await n.reply(W("Could not identify chat"));return}if((await this.sessionManager.getSession(r)).state!=="idle")this.messageHandler.enqueueCompact(r,n),await n.reply("Compact queued.");else try{await nd(n,this.sessionManager,this.log.bind(this))}finally{this.messageHandler.drainQueue(r).catch(s=>this.log("Drain error:",s))}}),this.bot.command("model",n=>qo(n,this.sessionManager,this.log.bind(this))),this.bot.command(["cd","cwd"],n=>rd(n,this.sessionManager,this.log.bind(this))),this.bot.command("name",n=>od(n,this.sessionManager,this.log.bind(this))),this.bot.on("text",n=>this.messageHandler.handle(n)),this.bot.on("photo",n=>this.messageHandler.handlePhoto(n));let e=new RegExp(`^${Ed(dr)}`);this.bot.action(e,n=>bd(n,{log:this.log.bind(this)})),this.bot.action(/^afk:m:/,async n=>{if(await n.answerCbQuery().catch(()=>{}),n.chat?.id!==void 0&&!this.options.allowedChatIds.has(n.chat.id))return;let o=(typeof n.callbackQuery=="object"&&"data"in n.callbackQuery?n.callbackQuery.data:"").replace("afk:m:",""),s=n.chat?.id;if(!(!s||!o)&&zt.includes(o))try{await this.sessionManager.switchModel(s,o);let i=mn(o);await n.editMessageText(i).catch(()=>n.reply(i))}catch(i){this.log("Model action error:",i)}}),this.bot.catch((n,r)=>{this.log("Bot error:",n),r.reply(W("An unexpected error occurred. Please try again.")).catch(o=>this.log("Failed to send error message:",o))})}async start(){if(this.running)throw new Error("Bot is already running");this.log("Loading sessions..."),await this.sessionManager.loadSessions();let e=[...this.options.allowedChatIds];if(e.length>0){let r=e[0],o=new RegExp(`^${Ed(Ze)}`);Nt.install(_d(this.messageHandler,this.bot,r)),this.bot.action(o,async s=>{await s.answerCbQuery().catch(()=>{})})}this.log("Starting bot..."),await this.bot.launch(),this.log("Registering bot commands..."),await this.bot.telegram.setMyCommands([{command:"start",description:"Show welcome and command list"},{command:"help",description:"Show this command list"},{command:"clear",description:"Clear conversation history"},{command:"compact",description:"Compact conversation history"},{command:"model",description:"Switch Claude model (opus/sonnet/haiku)"},{command:"cd",description:"Show or change session working directory"},{command:"name",description:"Show or set the session name"}]),this.running=!0,this.log("Bot started successfully");let n=async r=>{this.log(`Received ${r}, shutting down...`),await this.stop(),process.exit(0)};process.once("SIGINT",()=>n("SIGINT")),process.once("SIGTERM",()=>n("SIGTERM"))}async stop(){if(this.running){this.log("Stopping bot..."),this.running=!1,this.log("Uninstalling elicitation handler..."),Nt.uninstall(),this.log("Closing sessions..."),await this.sessionManager.closeAll(),this.log("Stopping bot polling...");try{this.bot.stop()}catch(e){this.log("Error stopping bot (may not have been started):",e)}this.log("Bot stopped")}}getStats(){return{running:this.running,activeSessions:this.sessionManager.getSessionCount(),totalChats:this.sessionManager.getChatCount()}}async handleStart(e){return Cr(e)}async handleHelp(e){return Mr(e,this.sessionManager)}async handleClear(e){let n=e.chat?.id;if(!n){await e.reply(W("Could not identify chat"));return}if((await this.sessionManager.getSession(n)).state!=="idle")this.messageHandler.enqueueClear(n,e),await e.reply("Clear queued.");else return Go(e,this.sessionManager,this.registeredCommandChats,this.log.bind(this))}async handleMessage(e){return this.messageHandler.handle(e)}async handlePhoto(e){return this.messageHandler.handlePhoto(e)}async handleModelSwitch(e){return qo(e,this.sessionManager,this.log.bind(this))}log(...e){this.options.verbose&&console.log("[TelegramBot]",...e)}};function Ed(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}import BD from"chalk";U();$();var kS="https://api.telegram.org";async function xd(t){try{let e=await fetch(`${kS}/bot${t}/getMe`);if(!e.ok)return null;let n=await e.json();return!n.ok||!n.result?.id||!n.result?.first_name?null:{id:n.result.id,...n.result.username!==void 0?{username:n.result.username}:{},firstName:n.result.first_name}}catch{return null}}$();U();import{randomUUID as JS}from"node:crypto";import{createHash as KS}from"crypto";import{mkdir as GS,open as qS,writeFile as zS}from"fs/promises";import{join as $d}from"path";import{z as f}from"zod";var vS=f.object({phase:f.literal("started"),toolUseId:f.string(),name:f.string(),inputBytes:f.number().int().nonnegative(),subagentId:f.string().optional()}),_S=f.object({phase:f.literal("completed"),toolUseId:f.string(),name:f.string(),resultBytes:f.number().int().nonnegative(),isError:f.boolean(),truncated:f.boolean(),durationMs:f.number().nonnegative(),subagentId:f.string().optional()}),Td=f.discriminatedUnion("phase",[vS,_S]),ES=f.enum(["PreToolUse","PostToolUse","SessionStart","SessionEnd","SubagentStart","SubagentStop"]),Ad=f.object({hookEvent:ES,decision:f.union([f.literal("block"),f.literal("approve"),f.undefined()]),reason:f.string().optional(),blockedTool:f.string().optional(),injectedContextBytes:f.number().int().nonnegative().optional()}),xS=f.object({transition:f.literal("started"),subagentId:f.string(),parentId:f.string(),model:f.string(),allowedTools:f.array(f.string()).readonly().optional(),systemPromptHash:f.string().optional()}),TS=f.object({transition:f.literal("succeeded"),subagentId:f.string(),durationMs:f.number().nonnegative(),turnCount:f.number().int().nonnegative(),totalCostUsd:f.number().nonnegative().optional(),outputBytes:f.number().int().nonnegative()}),AS=f.object({transition:f.literal("failed"),subagentId:f.string(),errorClass:f.string(),errorMessage:f.string(),partialOutputBytes:f.number().int().nonnegative()}),RS=f.object({transition:f.literal("cancelled"),subagentId:f.string(),source:f.enum(["cascade","explicit"])}),Rd=f.discriminatedUnion("transition",[xS,TS,AS,RS]),IS=f.object({transition:f.literal("started"),jobId:f.string(),subagentId:f.string(),label:f.string(),model:f.string()}),PS=f.object({transition:f.literal("completed"),jobId:f.string(),subagentId:f.string(),durationMs:f.number().nonnegative(),outputBytes:f.number().int().nonnegative()}),CS=f.object({transition:f.literal("failed"),jobId:f.string(),subagentId:f.string(),durationMs:f.number().nonnegative(),errorClass:f.string(),errorMessage:f.string()}),MS=f.object({transition:f.literal("cancelled"),jobId:f.string(),subagentId:f.string(),source:f.enum(["explicit","cascade"])}),OS=f.object({transition:f.literal("joined"),jobId:f.string(),subagentId:f.string(),jobStatus:f.enum(["completed","failed","cancelled"])}),Id=f.discriminatedUnion("transition",[IS,PS,CS,MS,OS]),Pd=f.object({kind:f.literal("monetary"),runningCostUsd:f.number().nonnegative(),maxBudgetUsd:f.number().nonnegative(),lastTurnCostUsd:f.number().nonnegative()}),DS=f.enum(["user_signal","cascade","timeout","budget","hook_block"]),Cd=f.object({origin:DS,cascadedTo:f.array(f.string()).readonly(),reason:f.string().optional()}),Md=f.enum(["manual","token_threshold","turn_count"]),FS=f.object({path:f.string(),sizeBytes:f.number().int().nonnegative(),sha256:f.string().regex(/^[0-9a-f]{64}$/)}),NS=f.object({trigger:Md,preCompactionMessages:f.array(f.unknown()),summary:f.string(),keptTailCount:f.number().int().nonnegative(),keepLastNConfig:f.number().int().nonnegative(),messagesBefore:f.number().int().nonnegative(),messagesAfter:f.number().int().nonnegative(),tokensSavedEstimate:f.number().nonnegative().optional(),summarizationTokens:f.object({input:f.number().int().nonnegative(),output:f.number().int().nonnegative()}).optional()}),LS=f.object({trigger:Md,preCompactionMessagesRef:FS,summary:f.string(),keptTailCount:f.number().int().nonnegative(),keepLastNConfig:f.number().int().nonnegative(),messagesBefore:f.number().int().nonnegative(),messagesAfter:f.number().int().nonnegative(),tokensSavedEstimate:f.number().nonnegative().optional(),summarizationTokens:f.object({input:f.number().int().nonnegative(),output:f.number().int().nonnegative()}).optional()}),$S=f.enum(["model_end_turn","iteration_cap","abort","timeout","budget_exceeded","hook_blocked","max_turns_exceeded"]),Od=f.object({reason:$S,finalTurnCount:f.number().int().nonnegative(),finalCostUsd:f.number().nonnegative(),finalTokens:f.object({input:f.number().int().nonnegative().optional(),output:f.number().int().nonnegative().optional(),cacheRead:f.number().int().nonnegative().optional(),cacheCreation:f.number().int().nonnegative().optional()}),lastStopReason:f.string().optional()}),Dd=f.object({source:f.string(),assertion:f.string(),evidence:f.array(f.string()).readonly(),confidence:f.number().min(0).max(1),dissent:f.string().optional()}),US=f.enum(["browser_open","browser_observe","browser_act","browser_screenshot","browser_extract","browser_close"]),HS=f.enum(["click","fill","press","select","hover","scroll_to","wait_for"]),BS=f.object({kind:f.enum(["semantic","element_id","selector"]),text:f.string().max(80).optional(),role:f.string().optional(),elementId:f.string().optional(),selectorHash:f.string().regex(/^[0-9a-f]{8}$/).optional()}),Fd=f.object({tool:US,action:HS.optional(),toolUseId:f.string(),target:BS.optional(),urlBefore:f.string().nullable(),urlAfter:f.string().nullable(),status:f.enum(["ok","error","ambiguous_target","blocked_by_policy"]),screenshotPath:f.string().optional(),observationSummary:f.string().max(500).optional(),error:f.object({reason:f.string(),recoverable:f.boolean()}).optional(),durationMs:f.number().nonnegative()}),jS=f.enum(["bootstrap_start","bootstrap_done","session_init_start","session_init_done","mcp_connect_start","mcp_connect_done","mcp_server_start","mcp_server_done","loop_start","loop_end","model_ttfb"]),Nd=f.object({phase:jS,durationMs:f.number().nonnegative().optional(),metadata:f.record(f.string(),f.union([f.string(),f.number(),f.boolean()])).optional()}),WS=f.object({status:f.enum(["succeeded","failed","cancelled"]),finalCostUsd:f.number().nonnegative(),finalTurnCount:f.number().int().nonnegative(),closedAt:f.string().datetime(),subagentCount:f.number().int().nonnegative().optional(),subagentTokens:f.object({input:f.number().int().nonnegative().optional(),output:f.number().int().nonnegative().optional(),cacheRead:f.number().int().nonnegative().optional(),cacheCreation:f.number().int().nonnegative().optional()}).optional(),subagentCostUsd:f.number().nonnegative().optional()}),Ld=f.discriminatedUnion("kind",[f.object({kind:f.literal("tool_call"),payload:Td}),f.object({kind:f.literal("hook_decision"),payload:Ad}),f.object({kind:f.literal("subagent_lifecycle"),payload:Rd}),f.object({kind:f.literal("background_agent"),payload:Id}),f.object({kind:f.literal("budget"),payload:Pd}),f.object({kind:f.literal("abort"),payload:Cd}),f.object({kind:f.literal("compaction"),payload:NS}),f.object({kind:f.literal("closure"),payload:Od}),f.object({kind:f.literal("claim"),payload:Dd}),f.object({kind:f.literal("browser_event"),payload:Fd}),f.object({kind:f.literal("session_phase"),payload:Nd})]),JD=f.discriminatedUnion("kind",[f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("tool_call"),payload:Td}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("hook_decision"),payload:Ad}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("subagent_lifecycle"),payload:Rd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("background_agent"),payload:Id}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("budget"),payload:Pd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("abort"),payload:Cd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("compaction"),payload:LS}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("closure"),payload:Od}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("claim"),payload:Dd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("browser_event"),payload:Fd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("session_phase"),payload:Nd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("session_sealed"),payload:WS})]);var gr=class{traceDir;tracePath;seq=0;sealed=!1;fh=null;writeQueue=Promise.resolve();constructor(e){this.traceDir=e.traceDir,this.tracePath=$d(this.traceDir,"trace.jsonl")}getTracePath(){return this.tracePath}async write(e){if(this.sealed)throw new Error("NdjsonTraceWriter: trace is sealed; write() rejected");return Ld.parse(e),this.enqueue(async()=>{await this.ensureOpen();let n=await this.materializePersistedEvent(e);await this.appendLine(n)})}async seal(e){this.sealed||(this.sealed=!0,await this.enqueue(async()=>{await this.ensureOpen();let n={ts:new Date().toISOString(),seq:this.seq++,kind:"session_sealed",payload:e};await this.appendLine(n),this.fh&&await this.fh.sync()}),await this.closeHandle())}async close(){await this.enqueue(async()=>{}),await this.closeHandle()}enqueue(e){let n=this.writeQueue.then(e,e);return this.writeQueue=n.then(()=>{},()=>{}),n}async ensureOpen(){this.fh||(await GS(this.traceDir,{recursive:!0}),this.fh=await qS(this.tracePath,"a"))}async closeHandle(){if(!this.fh)return;let e=this.fh;this.fh=null,await e.close()}async appendLine(e){if(!this.fh)throw new Error("NdjsonTraceWriter: file handle missing");await this.fh.appendFile(`${JSON.stringify(e)}
|
|
1545
|
+
<i>Type :cancel to cancel.</i>`),e.telegram.sendMessage(n,g,{parse_mode:"HTML"}).catch(()=>{u||(u=!0,i.signal.removeEventListener("abort",p),console.warn("[elicitation-handler] sendMessage failed; declining elicitation for chatId",n),t.pendingElicitations.delete(n),d({action:"decline"}))})})}}var mr=class{bot;sessionManager;options;running=!1;registeredCommandChats=new Set;messageHandler;constructor(e){this.options=e,this.bot=new SS(e.botToken),this.sessionManager=new un(e),this.messageHandler=new ur(this.bot,this.sessionManager,this.registeredCommandChats,this.log.bind(this)),this.setupHandlers()}setupHandlers(){this.bot.use(Wi(this.options.allowedChatIds,this.log.bind(this))),this.bot.command("start",n=>Cr(n)),this.bot.command("help",n=>Mr(n,this.sessionManager)),this.bot.command("clear",async n=>{let r=n.chat?.id;if(!r){await n.reply(W("Could not identify chat"));return}(await this.sessionManager.getSession(r)).state!=="idle"?(this.messageHandler.enqueueClear(r,n),await n.reply("Clear queued.")):await Go(n,this.sessionManager,this.registeredCommandChats,this.log.bind(this))}),this.bot.command("compact",async n=>{let r=n.chat?.id;if(!r){await n.reply(W("Could not identify chat"));return}if((await this.sessionManager.getSession(r)).state!=="idle")this.messageHandler.enqueueCompact(r,n),await n.reply("Compact queued.");else try{await nd(n,this.sessionManager,this.log.bind(this))}finally{this.messageHandler.drainQueue(r).catch(s=>this.log("Drain error:",s))}}),this.bot.command("model",n=>qo(n,this.sessionManager,this.log.bind(this))),this.bot.command(["cd","cwd"],n=>rd(n,this.sessionManager,this.log.bind(this))),this.bot.command("name",n=>od(n,this.sessionManager,this.log.bind(this))),this.bot.on("text",n=>this.messageHandler.handle(n)),this.bot.on("photo",n=>this.messageHandler.handlePhoto(n));let e=new RegExp(`^${Ed(dr)}`);this.bot.action(e,n=>bd(n,{log:this.log.bind(this)})),this.bot.action(/^afk:m:/,async n=>{if(await n.answerCbQuery().catch(()=>{}),n.chat?.id!==void 0&&!this.options.allowedChatIds.has(n.chat.id))return;let o=(typeof n.callbackQuery=="object"&&"data"in n.callbackQuery?n.callbackQuery.data:"").replace("afk:m:",""),s=n.chat?.id;if(!(!s||!o)&&zt.includes(o))try{await this.sessionManager.switchModel(s,o);let i=mn(o);await n.editMessageText(i).catch(()=>n.reply(i))}catch(i){this.log("Model action error:",i)}}),this.bot.catch((n,r)=>{this.log("Bot error:",n),r.reply(W("An unexpected error occurred. Please try again.")).catch(o=>this.log("Failed to send error message:",o))})}async start(){if(this.running)throw new Error("Bot is already running");this.log("Loading sessions..."),await this.sessionManager.loadSessions();let e=[...this.options.allowedChatIds];if(e.length>0){let r=e[0],o=new RegExp(`^${Ed(Ze)}`);Nt.install(_d(this.messageHandler,this.bot,r)),this.bot.action(o,async s=>{await s.answerCbQuery().catch(()=>{})})}this.log("Starting bot..."),await this.bot.launch(),this.log("Registering bot commands..."),await this.bot.telegram.setMyCommands([{command:"start",description:"Show welcome and command list"},{command:"help",description:"Show this command list"},{command:"clear",description:"Clear conversation history"},{command:"compact",description:"Compact conversation history"},{command:"model",description:"Switch Claude model (opus/sonnet/haiku)"},{command:"cd",description:"Show or change session working directory"},{command:"name",description:"Show or set the session name"}]),this.running=!0,this.log("Bot started successfully");let n=async r=>{this.log(`Received ${r}, shutting down...`),await this.stop(),process.exit(0)};process.once("SIGINT",()=>n("SIGINT")),process.once("SIGTERM",()=>n("SIGTERM"))}async stop(){if(this.running){this.log("Stopping bot..."),this.running=!1,this.log("Uninstalling elicitation handler..."),Nt.uninstall(),this.log("Closing sessions..."),await this.sessionManager.closeAll(),this.log("Stopping bot polling...");try{this.bot.stop()}catch(e){this.log("Error stopping bot (may not have been started):",e)}this.log("Bot stopped")}}getStats(){return{running:this.running,activeSessions:this.sessionManager.getSessionCount(),totalChats:this.sessionManager.getChatCount()}}async handleStart(e){return Cr(e)}async handleHelp(e){return Mr(e,this.sessionManager)}async handleClear(e){let n=e.chat?.id;if(!n){await e.reply(W("Could not identify chat"));return}if((await this.sessionManager.getSession(n)).state!=="idle")this.messageHandler.enqueueClear(n,e),await e.reply("Clear queued.");else return Go(e,this.sessionManager,this.registeredCommandChats,this.log.bind(this))}async handleMessage(e){return this.messageHandler.handle(e)}async handlePhoto(e){return this.messageHandler.handlePhoto(e)}async handleModelSwitch(e){return qo(e,this.sessionManager,this.log.bind(this))}log(...e){this.options.verbose&&console.log("[TelegramBot]",...e)}};function Ed(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}import jD from"chalk";U();$();var kS="https://api.telegram.org";async function xd(t){try{let e=await fetch(`${kS}/bot${t}/getMe`);if(!e.ok)return null;let n=await e.json();return!n.ok||!n.result?.id||!n.result?.first_name?null:{id:n.result.id,...n.result.username!==void 0?{username:n.result.username}:{},firstName:n.result.first_name}}catch{return null}}$();U();import{randomUUID as JS}from"node:crypto";import{createHash as KS}from"crypto";import{mkdir as GS,open as qS,writeFile as zS}from"fs/promises";import{join as $d}from"path";import{z as f}from"zod";var vS=f.object({phase:f.literal("started"),toolUseId:f.string(),name:f.string(),inputBytes:f.number().int().nonnegative(),subagentId:f.string().optional()}),_S=f.object({phase:f.literal("completed"),toolUseId:f.string(),name:f.string(),resultBytes:f.number().int().nonnegative(),isError:f.boolean(),truncated:f.boolean(),durationMs:f.number().nonnegative(),subagentId:f.string().optional()}),Td=f.discriminatedUnion("phase",[vS,_S]),ES=f.enum(["PreToolUse","PostToolUse","SessionStart","SessionEnd","SubagentStart","SubagentStop"]),Ad=f.object({hookEvent:ES,decision:f.union([f.literal("block"),f.literal("approve"),f.undefined()]),reason:f.string().optional(),blockedTool:f.string().optional(),injectedContextBytes:f.number().int().nonnegative().optional()}),xS=f.object({transition:f.literal("started"),subagentId:f.string(),parentId:f.string(),model:f.string(),allowedTools:f.array(f.string()).readonly().optional(),systemPromptHash:f.string().optional()}),TS=f.object({transition:f.literal("succeeded"),subagentId:f.string(),durationMs:f.number().nonnegative(),turnCount:f.number().int().nonnegative(),totalCostUsd:f.number().nonnegative().optional(),outputBytes:f.number().int().nonnegative()}),AS=f.object({transition:f.literal("failed"),subagentId:f.string(),errorClass:f.string(),errorMessage:f.string(),partialOutputBytes:f.number().int().nonnegative()}),RS=f.object({transition:f.literal("cancelled"),subagentId:f.string(),source:f.enum(["cascade","explicit"])}),Rd=f.discriminatedUnion("transition",[xS,TS,AS,RS]),IS=f.object({transition:f.literal("started"),jobId:f.string(),subagentId:f.string(),label:f.string(),model:f.string()}),PS=f.object({transition:f.literal("completed"),jobId:f.string(),subagentId:f.string(),durationMs:f.number().nonnegative(),outputBytes:f.number().int().nonnegative()}),CS=f.object({transition:f.literal("failed"),jobId:f.string(),subagentId:f.string(),durationMs:f.number().nonnegative(),errorClass:f.string(),errorMessage:f.string()}),MS=f.object({transition:f.literal("cancelled"),jobId:f.string(),subagentId:f.string(),source:f.enum(["explicit","cascade"])}),OS=f.object({transition:f.literal("joined"),jobId:f.string(),subagentId:f.string(),jobStatus:f.enum(["completed","failed","cancelled"])}),Id=f.discriminatedUnion("transition",[IS,PS,CS,MS,OS]),Pd=f.object({kind:f.literal("monetary"),runningCostUsd:f.number().nonnegative(),maxBudgetUsd:f.number().nonnegative(),lastTurnCostUsd:f.number().nonnegative()}),DS=f.enum(["user_signal","cascade","timeout","budget","hook_block"]),Cd=f.object({origin:DS,cascadedTo:f.array(f.string()).readonly(),reason:f.string().optional()}),Md=f.enum(["manual","token_threshold","turn_count"]),FS=f.object({path:f.string(),sizeBytes:f.number().int().nonnegative(),sha256:f.string().regex(/^[0-9a-f]{64}$/)}),NS=f.object({trigger:Md,preCompactionMessages:f.array(f.unknown()),summary:f.string(),keptTailCount:f.number().int().nonnegative(),keepLastNConfig:f.number().int().nonnegative(),messagesBefore:f.number().int().nonnegative(),messagesAfter:f.number().int().nonnegative(),tokensSavedEstimate:f.number().nonnegative().optional(),summarizationTokens:f.object({input:f.number().int().nonnegative(),output:f.number().int().nonnegative()}).optional()}),LS=f.object({trigger:Md,preCompactionMessagesRef:FS,summary:f.string(),keptTailCount:f.number().int().nonnegative(),keepLastNConfig:f.number().int().nonnegative(),messagesBefore:f.number().int().nonnegative(),messagesAfter:f.number().int().nonnegative(),tokensSavedEstimate:f.number().nonnegative().optional(),summarizationTokens:f.object({input:f.number().int().nonnegative(),output:f.number().int().nonnegative()}).optional()}),$S=f.enum(["model_end_turn","iteration_cap","abort","timeout","budget_exceeded","hook_blocked","max_turns_exceeded"]),Od=f.object({reason:$S,finalTurnCount:f.number().int().nonnegative(),finalCostUsd:f.number().nonnegative(),finalTokens:f.object({input:f.number().int().nonnegative().optional(),output:f.number().int().nonnegative().optional(),cacheRead:f.number().int().nonnegative().optional(),cacheCreation:f.number().int().nonnegative().optional()}),lastStopReason:f.string().optional()}),Dd=f.object({source:f.string(),assertion:f.string(),evidence:f.array(f.string()).readonly(),confidence:f.number().min(0).max(1),dissent:f.string().optional()}),US=f.enum(["browser_open","browser_observe","browser_act","browser_screenshot","browser_extract","browser_close"]),HS=f.enum(["click","fill","press","select","hover","scroll_to","wait_for"]),BS=f.object({kind:f.enum(["semantic","element_id","selector"]),text:f.string().max(80).optional(),role:f.string().optional(),elementId:f.string().optional(),selectorHash:f.string().regex(/^[0-9a-f]{8}$/).optional()}),Fd=f.object({tool:US,action:HS.optional(),toolUseId:f.string(),target:BS.optional(),urlBefore:f.string().nullable(),urlAfter:f.string().nullable(),status:f.enum(["ok","error","ambiguous_target","blocked_by_policy"]),screenshotPath:f.string().optional(),observationSummary:f.string().max(500).optional(),error:f.object({reason:f.string(),recoverable:f.boolean()}).optional(),durationMs:f.number().nonnegative()}),jS=f.enum(["bootstrap_start","bootstrap_done","session_init_start","session_init_done","mcp_connect_start","mcp_connect_done","mcp_server_start","mcp_server_done","loop_start","loop_end","model_ttfb"]),Nd=f.object({phase:jS,durationMs:f.number().nonnegative().optional(),metadata:f.record(f.string(),f.union([f.string(),f.number(),f.boolean()])).optional()}),WS=f.object({status:f.enum(["succeeded","failed","cancelled"]),finalCostUsd:f.number().nonnegative(),finalTurnCount:f.number().int().nonnegative(),closedAt:f.string().datetime(),subagentCount:f.number().int().nonnegative().optional(),subagentTokens:f.object({input:f.number().int().nonnegative().optional(),output:f.number().int().nonnegative().optional(),cacheRead:f.number().int().nonnegative().optional(),cacheCreation:f.number().int().nonnegative().optional()}).optional(),subagentCostUsd:f.number().nonnegative().optional()}),Ld=f.discriminatedUnion("kind",[f.object({kind:f.literal("tool_call"),payload:Td}),f.object({kind:f.literal("hook_decision"),payload:Ad}),f.object({kind:f.literal("subagent_lifecycle"),payload:Rd}),f.object({kind:f.literal("background_agent"),payload:Id}),f.object({kind:f.literal("budget"),payload:Pd}),f.object({kind:f.literal("abort"),payload:Cd}),f.object({kind:f.literal("compaction"),payload:NS}),f.object({kind:f.literal("closure"),payload:Od}),f.object({kind:f.literal("claim"),payload:Dd}),f.object({kind:f.literal("browser_event"),payload:Fd}),f.object({kind:f.literal("session_phase"),payload:Nd})]),VD=f.discriminatedUnion("kind",[f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("tool_call"),payload:Td}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("hook_decision"),payload:Ad}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("subagent_lifecycle"),payload:Rd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("background_agent"),payload:Id}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("budget"),payload:Pd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("abort"),payload:Cd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("compaction"),payload:LS}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("closure"),payload:Od}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("claim"),payload:Dd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("browser_event"),payload:Fd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("session_phase"),payload:Nd}),f.object({ts:f.string().datetime(),seq:f.number().int().nonnegative(),kind:f.literal("session_sealed"),payload:WS})]);var gr=class{traceDir;tracePath;seq=0;sealed=!1;fh=null;writeQueue=Promise.resolve();constructor(e){this.traceDir=e.traceDir,this.tracePath=$d(this.traceDir,"trace.jsonl")}getTracePath(){return this.tracePath}async write(e){if(this.sealed)throw new Error("NdjsonTraceWriter: trace is sealed; write() rejected");return Ld.parse(e),this.enqueue(async()=>{await this.ensureOpen();let n=await this.materializePersistedEvent(e);await this.appendLine(n)})}async seal(e){this.sealed||(this.sealed=!0,await this.enqueue(async()=>{await this.ensureOpen();let n={ts:new Date().toISOString(),seq:this.seq++,kind:"session_sealed",payload:e};await this.appendLine(n),this.fh&&await this.fh.sync()}),await this.closeHandle())}async close(){await this.enqueue(async()=>{}),await this.closeHandle()}enqueue(e){let n=this.writeQueue.then(e,e);return this.writeQueue=n.then(()=>{},()=>{}),n}async ensureOpen(){this.fh||(await GS(this.traceDir,{recursive:!0}),this.fh=await qS(this.tracePath,"a"))}async closeHandle(){if(!this.fh)return;let e=this.fh;this.fh=null,await e.close()}async appendLine(e){if(!this.fh)throw new Error("NdjsonTraceWriter: file handle missing");await this.fh.appendFile(`${JSON.stringify(e)}
|
|
1546
1546
|
`)}async materializePersistedEvent(e){let n=new Date().toISOString(),r=this.seq++;if(e.kind==="compaction"){let o=await this.persistCompactionSidecar(e.payload,r,n);return{ts:n,seq:r,kind:"compaction",payload:o}}return{ts:n,seq:r,kind:e.kind,payload:e.payload}}async persistCompactionSidecar(e,n,r){let o=r.replace(/[:.]/g,"-"),s=$d(this.traceDir,`${String(n).padStart(6,"0")}-${o}-pre-compaction.json`),i=JSON.stringify(e.preCompactionMessages),a=Buffer.byteLength(i,"utf8"),c=KS("sha256").update(i).digest("hex");await zS(s,i,{encoding:"utf8",flag:"w"});let l={path:s,sizeBytes:a,sha256:c};return{trigger:e.trigger,preCompactionMessagesRef:l,summary:e.summary,keptTailCount:e.keptTailCount,keepLastNConfig:e.keepLastNConfig,messagesBefore:e.messagesBefore,messagesAfter:e.messagesAfter,...e.tokensSavedEstimate!==void 0?{tokensSavedEstimate:e.tokensSavedEstimate}:{},...e.summarizationTokens!==void 0?{summarizationTokens:e.summarizationTokens}:{}}}};function Ud(t={}){if(_.AFK_TRACE_DISABLED==="1")return null;let e=t.sessionLabel??JS(),n=tn(e),r=new gr({traceDir:n});return{writer:r,tracePath:r.getTracePath(),sessionLabel:e}}function Yo(t,e={}){let n=(e.createTraceWriter??Ud)(),r=n?{traceWriter:n.writer,...t}:t;return(e.newSession??(s=>new je(s)))(r)}function Hd(){return xi()}var VS=["shadow-verify","shadow_verify","resolve","diagnose","appmap","mint","review"],YS=[/\bverdict(s)?\b/i,/\brecommend(ation)?s?\b/i,/\bshould\s+(delete|remove|rewrite|refactor|rename|reject|merge|revert|disable)\b/i,/\b(USELESS|KEEP|REJECT|APPROVE|SALVAGE|BLOCK|FAIL)\b/,/\b(redundant|duplicated|superseded|obsolete)\b/i,/\bvulnerab\w*\b/i,/\bunused\b/i,/\bbroken\b/i,/\bregress\w*\b/i,/\|\s*(status|verdict|decision|severity|risk|finding|priority|holds\??)\s*\|/i,/\bfound\s+\d+\s*(issue|problem|bug|error|finding|vulnerabilit)/i,/\b(critical|high|medium|low)\s+(severity|priority|risk)\b/i,/\bclaim(s)?\b[^\n]{0,80}\b(holds?|refuted|verified|partial|confirmed|disputed)\b/i,/\b(root\s*cause|incident)\b/i,/\brecommend\s+(removing|deleting|rewriting|refactoring|merging|reverting)\b/i,/\bI\s+(applied|committed|pushed|edited|wrote|fixed|patched|reset|restored|staged)\b/i,/\b(applied|committed|pushed|fixed|patched)\s+(the|these|those)\s+(change|commit|fix|patch|edit)/i],XS=[/\bverifier_verdict\b/i,/"\s*claim\s*"\s*:/i,/\bre-derived\b[^.\n]{0,80}\bindependent/i,/\bindependently\s+(re-derived|re-verified|verified|checked)\b/i,/\bverifier\s+(agrees|disagrees|confirms|refutes)\b/i],QS=`shadow-verify nudge:
|
|
1547
1547
|
|
|
1548
1548
|
The sub-agent that just finished returned output that reads like **decision-driving findings** (verdicts, recommendations, audit conclusions, or claim-style results that could drive file edits, deletions, commits, or external side-effects).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-afk",
|
|
3
|
-
"version": "3.87.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.87.1",
|
|
4
|
+
"description": "Local-first control plane for long-running AI agent work — delegation, traces, resumable sessions, verification, and notifications.",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -13,11 +13,15 @@
|
|
|
13
13
|
"NOTICE"
|
|
14
14
|
],
|
|
15
15
|
"keywords": [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
16
|
+
"ai-agent",
|
|
17
|
+
"agent-runtime",
|
|
18
|
+
"control-plane",
|
|
19
|
+
"orchestration",
|
|
20
|
+
"verification",
|
|
21
|
+
"local-first",
|
|
22
|
+
"mcp",
|
|
19
23
|
"telegram",
|
|
20
|
-
"
|
|
24
|
+
"cli"
|
|
21
25
|
],
|
|
22
26
|
"author": "Griffin Long",
|
|
23
27
|
"license": "Apache-2.0",
|