agentix-cli 0.121.1 → 0.122.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/{App-AMIGKAXO.js → App-2D5W26LY.js} +2 -2
  2. package/dist/{ChatApp-WMI4HQSY.js → ChatApp-FZFZD2XY.js} +2 -2
  3. package/dist/{agent-KR4B2G24.js → agent-PCRE3TRK.js} +2 -2
  4. package/dist/{board-dashboard-WBIQPRHQ.js → board-dashboard-ZDJ4UDW4.js} +264 -230
  5. package/dist/board-dashboard-ZDJ4UDW4.js.map +1 -0
  6. package/dist/{chunk-MSYBNVY3.js → chunk-2UDSIG5K.js} +2 -2
  7. package/dist/{chunk-6FVFD5WU.js → chunk-54XX2LSW.js} +4 -4
  8. package/dist/{chunk-6FVFD5WU.js.map → chunk-54XX2LSW.js.map} +1 -1
  9. package/dist/{chunk-HVYS5ZBQ.js → chunk-5SLTRG66.js} +2 -2
  10. package/dist/{chunk-KFSA2ZI7.js → chunk-7ZGTRXWS.js} +2 -2
  11. package/dist/{chunk-EI7D5V2L.js → chunk-BRVQZC6P.js} +2 -2
  12. package/dist/{chunk-6TUQHOO3.js → chunk-C52IPIKJ.js} +2 -2
  13. package/dist/chunk-DMPTCBX6.js +532 -0
  14. package/dist/chunk-DMPTCBX6.js.map +1 -0
  15. package/dist/{chunk-4GDLXWCH.js → chunk-EHKI2RKD.js} +2 -2
  16. package/dist/{chunk-CAS2IWSM.js → chunk-NFS2VR3L.js} +2 -2
  17. package/dist/{chunk-43CLFC4B.js → chunk-NYAMY7EA.js} +2 -2
  18. package/dist/{chunk-7ZABMMSW.js → chunk-QCPSGOSK.js} +2 -2
  19. package/dist/{chunk-BLEW5WQL.js → chunk-SB7WMFJV.js} +2 -2
  20. package/dist/{chunk-7KY7EEEI.js → chunk-TLCURHW3.js} +2 -2
  21. package/dist/{chunk-H5Z42X7W.js → chunk-TYFGL2YS.js} +2 -2
  22. package/dist/{chunk-FIB5LD6R.js → chunk-UVV6GUOG.js} +232 -228
  23. package/dist/chunk-UVV6GUOG.js.map +1 -0
  24. package/dist/{chunk-ELUEF4NC.js → chunk-WJDFR3WE.js} +2 -2
  25. package/dist/{chunk-IKBWV7YJ.js → chunk-XBRVV4ZT.js} +2 -2
  26. package/dist/{chunk-D7LGD7ZI.js → chunk-XLCUHG3N.js} +5 -5
  27. package/dist/{chunk-D7LGD7ZI.js.map → chunk-XLCUHG3N.js.map} +1 -1
  28. package/dist/{chunk-2IMK3NGJ.js → chunk-XX6MLDTL.js} +2 -2
  29. package/dist/{chunk-PAWCJIPZ.js → chunk-YCMO3KZ4.js} +2 -2
  30. package/dist/{chunk-Y4PR5LR3.js → chunk-YUNMSLZN.js} +2 -2
  31. package/dist/{chunk-OPNZWQ6Y.js → chunk-ZLUROC2Y.js} +5 -5
  32. package/dist/chunk-ZLUROC2Y.js.map +1 -0
  33. package/dist/{chunk-25XR6QK2.js → chunk-ZWZADDXV.js} +2 -2
  34. package/dist/cli.js +1 -1
  35. package/dist/{client-ICDRAZBU.js → client-TFZEASIJ.js} +2 -2
  36. package/dist/config-IXCOAOPZ.js +2 -0
  37. package/dist/config-mutator-EPYIZVSG.js +2 -0
  38. package/dist/{doctor-LRTOOCM6.js → doctor-G5TM5GVF.js} +2 -2
  39. package/dist/{grants-ZMHSJMYE.js → grants-NGBKFONG.js} +2 -2
  40. package/dist/index.d.ts +144 -77
  41. package/dist/index.js +1 -1
  42. package/dist/{program-4J6WMXLI.js → program-CGPPGRMR.js} +201 -199
  43. package/dist/program-CGPPGRMR.js.map +1 -0
  44. package/dist/{promote-4LW53AMH.js → promote-VTVIPRTC.js} +2 -2
  45. package/dist/{query-4OPS5PET.js → query-3CVDT2GZ.js} +2 -2
  46. package/dist/{registry-XK2FTQZV.js → registry-NOJMMWE3.js} +2 -2
  47. package/dist/{request-planner-GDXSBNN4.js → request-planner-E2Q5O66N.js} +2 -2
  48. package/dist/{review-candidates-TUVDG2LR.js → review-candidates-I36HEYKX.js} +2 -2
  49. package/dist/{routing-OKDZ4VYH.js → routing-KBUZON5R.js} +2 -2
  50. package/dist/schedule-tool-GUHHYYTO.js +2 -0
  51. package/dist/scheduler-PGUELFMB.js +2 -0
  52. package/dist/{seat-K6FNHYMY.js → seat-NGY2BMP6.js} +2 -2
  53. package/dist/{select-QMJXHNUP.js → select-X7VBGZ6X.js} +2 -2
  54. package/dist/{set-enabled-I77LPL6Q.js → set-enabled-6NP63KCU.js} +2 -2
  55. package/dist/{tool-QTGNWXUA.js → tool-EZIILXYL.js} +2 -2
  56. package/dist/tool-WKIF52OH.js +6 -0
  57. package/dist/tool-WKIF52OH.js.map +1 -0
  58. package/dist/wiki-7BFVMMNR.js +2 -0
  59. package/package.json +1 -1
  60. package/dist/board-dashboard-WBIQPRHQ.js.map +0 -1
  61. package/dist/chunk-BWHHZJNJ.js +0 -482
  62. package/dist/chunk-BWHHZJNJ.js.map +0 -1
  63. package/dist/chunk-FIB5LD6R.js.map +0 -1
  64. package/dist/chunk-OPNZWQ6Y.js.map +0 -1
  65. package/dist/config-K4UYPR7W.js +0 -2
  66. package/dist/config-mutator-IGA6D4S5.js +0 -2
  67. package/dist/program-4J6WMXLI.js.map +0 -1
  68. package/dist/schedule-tool-MJLXMXN5.js +0 -2
  69. package/dist/scheduler-E5SASFAH.js +0 -2
  70. package/dist/tool-BQUKONSF.js +0 -4
  71. package/dist/tool-BQUKONSF.js.map +0 -1
  72. package/dist/wiki-PAMLP6WO.js +0 -2
  73. /package/dist/{App-AMIGKAXO.js.map → App-2D5W26LY.js.map} +0 -0
  74. /package/dist/{ChatApp-WMI4HQSY.js.map → ChatApp-FZFZD2XY.js.map} +0 -0
  75. /package/dist/{agent-KR4B2G24.js.map → agent-PCRE3TRK.js.map} +0 -0
  76. /package/dist/{chunk-MSYBNVY3.js.map → chunk-2UDSIG5K.js.map} +0 -0
  77. /package/dist/{chunk-HVYS5ZBQ.js.map → chunk-5SLTRG66.js.map} +0 -0
  78. /package/dist/{chunk-KFSA2ZI7.js.map → chunk-7ZGTRXWS.js.map} +0 -0
  79. /package/dist/{chunk-EI7D5V2L.js.map → chunk-BRVQZC6P.js.map} +0 -0
  80. /package/dist/{chunk-6TUQHOO3.js.map → chunk-C52IPIKJ.js.map} +0 -0
  81. /package/dist/{chunk-4GDLXWCH.js.map → chunk-EHKI2RKD.js.map} +0 -0
  82. /package/dist/{chunk-CAS2IWSM.js.map → chunk-NFS2VR3L.js.map} +0 -0
  83. /package/dist/{chunk-43CLFC4B.js.map → chunk-NYAMY7EA.js.map} +0 -0
  84. /package/dist/{chunk-7ZABMMSW.js.map → chunk-QCPSGOSK.js.map} +0 -0
  85. /package/dist/{chunk-BLEW5WQL.js.map → chunk-SB7WMFJV.js.map} +0 -0
  86. /package/dist/{chunk-7KY7EEEI.js.map → chunk-TLCURHW3.js.map} +0 -0
  87. /package/dist/{chunk-H5Z42X7W.js.map → chunk-TYFGL2YS.js.map} +0 -0
  88. /package/dist/{chunk-ELUEF4NC.js.map → chunk-WJDFR3WE.js.map} +0 -0
  89. /package/dist/{chunk-IKBWV7YJ.js.map → chunk-XBRVV4ZT.js.map} +0 -0
  90. /package/dist/{chunk-2IMK3NGJ.js.map → chunk-XX6MLDTL.js.map} +0 -0
  91. /package/dist/{chunk-PAWCJIPZ.js.map → chunk-YCMO3KZ4.js.map} +0 -0
  92. /package/dist/{chunk-Y4PR5LR3.js.map → chunk-YUNMSLZN.js.map} +0 -0
  93. /package/dist/{chunk-25XR6QK2.js.map → chunk-ZWZADDXV.js.map} +0 -0
  94. /package/dist/{client-ICDRAZBU.js.map → client-TFZEASIJ.js.map} +0 -0
  95. /package/dist/{config-K4UYPR7W.js.map → config-IXCOAOPZ.js.map} +0 -0
  96. /package/dist/{config-mutator-IGA6D4S5.js.map → config-mutator-EPYIZVSG.js.map} +0 -0
  97. /package/dist/{doctor-LRTOOCM6.js.map → doctor-G5TM5GVF.js.map} +0 -0
  98. /package/dist/{grants-ZMHSJMYE.js.map → grants-NGBKFONG.js.map} +0 -0
  99. /package/dist/{promote-4LW53AMH.js.map → promote-VTVIPRTC.js.map} +0 -0
  100. /package/dist/{query-4OPS5PET.js.map → query-3CVDT2GZ.js.map} +0 -0
  101. /package/dist/{registry-XK2FTQZV.js.map → registry-NOJMMWE3.js.map} +0 -0
  102. /package/dist/{request-planner-GDXSBNN4.js.map → request-planner-E2Q5O66N.js.map} +0 -0
  103. /package/dist/{review-candidates-TUVDG2LR.js.map → review-candidates-I36HEYKX.js.map} +0 -0
  104. /package/dist/{routing-OKDZ4VYH.js.map → routing-KBUZON5R.js.map} +0 -0
  105. /package/dist/{schedule-tool-MJLXMXN5.js.map → schedule-tool-GUHHYYTO.js.map} +0 -0
  106. /package/dist/{scheduler-E5SASFAH.js.map → scheduler-PGUELFMB.js.map} +0 -0
  107. /package/dist/{seat-K6FNHYMY.js.map → seat-NGY2BMP6.js.map} +0 -0
  108. /package/dist/{select-QMJXHNUP.js.map → select-X7VBGZ6X.js.map} +0 -0
  109. /package/dist/{set-enabled-I77LPL6Q.js.map → set-enabled-6NP63KCU.js.map} +0 -0
  110. /package/dist/{tool-QTGNWXUA.js.map → tool-EZIILXYL.js.map} +0 -0
  111. /package/dist/{wiki-PAMLP6WO.js.map → wiki-7BFVMMNR.js.map} +0 -0
@@ -1,482 +0,0 @@
1
- import{a as $e}from"./chunk-GTJIKXDB.js";import{q as zt}from"./chunk-S2GAEH2F.js";import{a as te,b as w}from"./chunk-BGG3ZSMW.js";import{b as qt}from"./chunk-WCXXXAHV.js";import{f as Kt,g as ve,i as U,j as B,l as Gt}from"./chunk-6FVFD5WU.js";import{t as Bt,u as Ht}from"./chunk-H5Z42X7W.js";import{d as Ft,e as Ut}from"./chunk-AQASR6KR.js";import{A as Se,b as ke,v as Dt,x as ee,y as xe}from"./chunk-7KY7EEEI.js";import{a as jt,b as Vt,d as Wt}from"./chunk-Y4CYQV7G.js";import{a as Et,b as Tt}from"./chunk-SHEUCITK.js";import{g as Pt,h as Lt,i as Mt,k as Ot,l as Nt}from"./chunk-BLEW5WQL.js";import{q as Ct}from"./chunk-25XR6QK2.js";import{a as Rt,b as _t}from"./chunk-2IMK3NGJ.js";import{A as qr,ba as we,ia as $t,ja as At,ma as It,n as Q,o as wt,p as kt,q as Br,y as St,z as vt}from"./chunk-OPNZWQ6Y.js";import{a as be,h as Hr}from"./chunk-BRK6M6LA.js";import{f as xt,n as zr}from"./chunk-UIBUZ2N3.js";import{existsSync as Kr,readdirSync as Gr,readFileSync as Xr,statSync as Jr}from"fs";import{resolve as Yr}from"path";function Xt(t,e,n=Date.now(),i=7){let r=i*864e5,o=new Map;for(let s of e){let a=o.get(s.workflowId);a?a.push(s):o.set(s.workflowId,[s])}return t.map(s=>{let a=o.get(s.id)??[],c=a.filter(g=>n-g.at<=r),l=a.filter(g=>n-g.at>r&&n-g.at<=r*2),u=c.filter(g=>g.status==="failed").length,d=a.filter(g=>g.status==="paused").length,p=a.length?Math.max(...a.map(g=>g.at)):null,f=a.length?l.length>0&&c.length===0?"dormant":c.length>0&&u*2>=c.length?"failing":c.length>0?"active":"quiet":"never";return{id:s.id,name:s.name||s.id,state:f,lastRunAt:p,recent:c.length,prior:l.length,failed:u,paused:d}}).sort((s,a)=>{let c={dormant:0,failing:1,active:2,quiet:3,never:4};return c[s.state]-c[a.state]||(a.lastRunAt??0)-(s.lastRunAt??0)})}var ne=new Map;function ka(t,e=1e3){if(!Kr(t))return[];let n=Gr(t).filter(o=>o.endsWith(".jsonl")).map(o=>{let s=Yr(t,o);return{path:s,mtime:Jr(s).mtimeMs}}).sort((o,s)=>s.mtime-o.mtime).slice(0,e),i=new Set(n.map(o=>o.path));for(let o of ne.keys())i.has(o)||ne.delete(o);let r=[];for(let{path:o,mtime:s}of n){let a=ne.get(o);if(a&&a.mtime===s){a.summary&&r.push(a.summary);continue}let c=Zr(o,s);ne.set(o,{mtime:s,summary:c}),c&&r.push(c)}return r}function Zr(t,e){try{let n=Xr(t,"utf-8").split(`
2
- `).filter(Boolean);if(!n.length)return null;let i=JSON.parse(n[0]),r=i.run?.workflowId;if(!r)return null;let o=i.run?.status??"unknown";for(let s=n.length-1;s>=0;s--){let a=JSON.parse(n[s]),c=a.status??a.run?.status;if(c){o=c;break}}return{workflowId:r,status:o,at:e}}catch{return null}}var Qr={failStreak:3,disabledDays:30,missedFires:2,graceMs:15*6e4},k={routines:200,summary:160,filters:6,filterValue:60,text:120},ei=(t,e,n)=>{try{return Ct(t,e,n)}catch{return null}},Jt=864e5;function $a(t){let e=t.now??Date.now(),n={...Qr,...t.thresholds},i=t.nextFire??ei,r=[];for(let a of t.crons){let c=t.cronRuns.get(a.id)??[],l=a.timezone||"UTC",u=c.map(f=>({at:Date.parse(f.startedAt),status:f.status})),d=c[0],p={id:`cron:${a.id}`,source:"cron",kind:"schedule",name:$(a.id,k.text),trigger:{schedule:$(a.schedule,k.text),timezone:l},agent:a.agent||null,enabled:a.enabled,state:a.enabled?"enabled":"disabled",nextRunAt:a.enabled?Ae(a.nextRun)??Ae(i(a.schedule,new Date(e),l)):null,lastRun:d?{at:d.startedAt,status:d.status,summary:si(d.status==="success"?void 0:d.errorSummary,k.summary)}:null,lastSuccessAt:c.find(f=>f.status==="success")?.startedAt??null,consecutiveFailures:Yt(u),sampledRuns:c.length,flags:[],attention:null};p.flags=Zt(p,u,a.schedule,l,null,e,n,i),r.push(Qt(p))}let o=new Map(Xt(t.workflows.map(a=>({id:a.id,name:a.title})),t.workflowRuns,e).map(a=>[a.id,a])),s=new Map;for(let a of t.workflowRuns){let c=s.get(a.workflowId);c?c.push(a):s.set(a.workflowId,[a])}for(let a of t.workflows){let c=a.nodes.find(R=>R.type.startsWith("trigger."));if(!c||c.type!=="trigger.cron"&&c.type!=="trigger.hook")continue;let l=c.config??{},u=a.state||"active",d=u==="active",p=(s.get(a.id)??[]).slice().sort((R,ye)=>ye.at-R.at),f=p.map(R=>({at:R.at,status:ri(R.status)})),g=f[0],h=c.type==="trigger.cron",y=typeof l.spec=="string"?l.spec:"",D=typeof l.timezone=="string"?l.timezone:"UTC",N={id:`workflow:${a.id}`,source:"workflow",kind:h?"schedule":"event",name:$(a.title||a.id,k.text),trigger:h?{schedule:$(y,k.text),timezone:D}:{event:$(typeof l.event=="string"?l.event:"",k.text),filters:oi(l.filter,a)},agent:ii(a),enabled:d,state:u,nextRunAt:h&&d&&y?Ae(i(y,new Date(e),D)):null,lastRun:g?{at:new Date(g.at).toISOString(),status:g.status}:null,lastSuccessAt:(()=>{let R=f.find(ye=>ye.status==="success");return R?new Date(R.at).toISOString():null})(),consecutiveFailures:Yt(f),sampledRuns:p.length,flags:[],attention:null},Z=Date.parse(a.updated||a.created||"");N.flags=h?Zt(N,f,y,D,Number.isFinite(Z)?Z:null,e,n,i):ti(N,o.get(a.id)?.state==="dormant",Number.isFinite(Z)?Z:null,e,n),r.push(Qt(N))}return r.sort(ni).slice(0,k.routines)}function Yt(t){let e=0;for(let n of t)if(!(n.status==="running"||n.status==="paused"||n.status==="unknown"))if(n.status==="failed"||n.status==="timeout")e++;else break;return e}function Zt(t,e,n,i,r,o,s,a){let c=[],l=e.length?e[0].at:null;if(!t.enabled){let p=tn(l,r,o,s);return p&&c.push(p),c}if(t.consecutiveFailures>=s.failStreak&&c.push({reason:"failing",detail:`${t.consecutiveFailures} failed attempts in a row`}),l===null)return c.push({reason:"never-ran",detail:"No persisted attempt"}),c;let u=new Date(l),d=null;for(let p=0;p<s.missedFires&&(d=a(n,u,i),!!d);p++)u=d;return d&&o>d.getTime()+s.graceMs&&c.push({reason:"overdue",detail:`No attempt since ${new Date(l).toISOString()}; ${s.missedFires} scheduled fires missed`}),c}function ti(t,e,n,i,r){let o=[],s=t.lastRun?Date.parse(t.lastRun.at):null;if(!t.enabled){let a=tn(s,n,i,r);return a&&o.push(a),o}return t.consecutiveFailures>=r.failStreak&&o.push({reason:"failing",detail:`${t.consecutiveFailures} failed runs in a row`}),s===null?o.push({reason:"never-ran",detail:"No run recorded for this trigger"}):e&&o.push({reason:"dormant",detail:"Fired in the prior week, silent in the last one"}),o}function tn(t,e,n,i){let r=Math.max(t??0,e??0);return r&&n-r<i.disabledDays*Jt?null:{reason:"disabled-long",detail:r?`Disabled; no activity for ${Math.floor((n-r)/Jt)} days`:"Disabled and never ran"}}function Qt(t){let e=new Set(t.flags.map(n=>n.reason));return t.attention=e.has("failing")?"critical":e.has("overdue")||e.has("dormant")||e.has("never-ran")?"warning":e.has("disabled-long")?"info":null,t}var en={critical:0,warning:1,info:2};function ni(t,e){let n=t.attention?en[t.attention]:3,i=e.attention?en[e.attention]:3;return n-i||Number(e.enabled)-Number(t.enabled)||t.name.localeCompare(e.name)}function ri(t){switch(t){case"completed":case"ok":return"success";case"failed":return"failed";case"timeout":return"timeout";case"canceled":return"canceled";case"running":return"running";case"paused":return"paused";default:return"unknown"}}function ii(t){if(t.ownerAgent)return $(t.ownerAgent,k.text);let e=t.nodes.find(n=>n.type==="agent"&&typeof n.config?.agentId=="string"&&n.config.agentId);return e?$(String(e.config.agentId),k.text):null}function oi(t,e){let n=[],i=e?.project;if(i&&n.push($(`project=${i}`,k.filterValue)),t&&typeof t=="object"&&!Array.isArray(t))for(let[r,o]of Object.entries(t)){let s=Array.isArray(o)?o.map(String):o==null?[]:[String(o)];s.length&&n.push($(`${r}=${s.join(",")}`,k.filterValue))}return n.slice(0,k.filters)}function Ae(t){if(!t)return null;let e=t instanceof Date?t:new Date(t);return Number.isFinite(e.getTime())?e.toISOString():null}function $(t,e){return t.length<=e?t:t.slice(0,e-3)+"..."}function si(t,e){return t===void 0?void 0:$(t,e)}import{existsSync as oe,readdirSync as $i,readFileSync as Ai}from"fs";import{resolve as E}from"path";import{randomBytes as on}from"crypto";import{existsSync as ci,mkdirSync as li,readdirSync as ui,readFileSync as di,renameSync as sn,unlinkSync as pi,writeFileSync as fi}from"fs";import{resolve as an}from"path";function nn(t){return[...t.account?["--account",t.account]:[],...t.store?["--store",t.store]:[]]}var ai=t=>t.trim().split(`
3
- `).pop()?.slice(0,300)||"no output";async function rn(t,e,n,i=$e){let r=await i(t.bin,[...nn(t),"send","text","--to",e,"--message",n,"--no-preview"],{timeoutMs:6e4});return r.code===0?{ok:!0}:{ok:!1,error:`wacli send failed: ${ai(r.stderr||r.stdout)}`}}async function Ra(t,e,n,i,r=$e){return(await r(t.bin,[...nn(t),"--read-only","media","download","--chat",e,"--id",n,"--output",i],{timeoutMs:12e4})).code===0}var gi=2e3,mi=t=>rn(t.wacli,t.to,t.text);function Ie(t){return an(t,".agentx","whatsapp-triage","drafts")}var hi=t=>/^[a-z0-9-]{8,64}$/.test(t),re=(t,e)=>an(Ie(t),`${e}.json`);function cn(t,e){li(Ie(t),{recursive:!0});let n=re(t,e.id),i=`${n}.${process.pid}.tmp`;fi(i,JSON.stringify(e,null,2)+`
4
- `,{mode:384}),sn(i,n)}function Pa(t,e,n=Date.now()){let i=e.text.trim().slice(0,gi);if(!i)throw new Error("empty draft");let r={...e,text:i,id:`${n.toString(36)}-${on(4).toString("hex")}`,status:"pending",created_at:new Date(n).toISOString()};return cn(t,r),r}function ie(t,e){if(!hi(e))return null;try{return JSON.parse(di(re(t,e),"utf-8"))}catch{return null}}function ln(t,e){let n=Ie(t);return ci(n)?ui(n).filter(i=>i.endsWith(".json")).map(i=>ie(t,i.slice(0,-5))).filter(i=>!!i&&(!e||i.status===e)).sort((i,r)=>i.created_at.localeCompare(r.created_at)):[]}async function un(t,e,n,i={}){let r=ie(t,e);if(!r||r.status!=="pending")return{ok:!1,error:`no reply draft "${e}" is waiting`};let o=`${re(t,e)}.${process.pid}.${on(3).toString("hex")}.claim`;try{sn(re(t,e),o)}catch{return{ok:!1,error:`reply draft "${e}" is already being decided`}}let s={...r,decided_by:i.by??"operator",decided_at:new Date(i.now??Date.now()).toISOString()};if(n==="no")s.status="rejected";else{let a=await(i.send??mi)(r).catch(c=>({ok:!1,error:String(c?.message??c)}));a.ok?s.status="sent":(s.status="failed",s.error=a.error)}cn(t,s);try{pi(o)}catch{}return s.status==="failed"?{ok:!1,error:s.error??"send failed"}:{ok:!0,draft:s}}import{mkdirSync as yi,readFileSync as bi,renameSync as wi,writeFileSync as ki}from"fs";import{resolve as xi}from"path";function dn(t){return xi(ve(t),"_state.json")}function A(t){try{let e=JSON.parse(bi(dn(t),"utf-8"));return{snoozed:e&&typeof e.snoozed=="object"&&e.snoozed?e.snoozed:{},...typeof e?.lastDigest=="string"?{lastDigest:e.lastDigest}:{},...e?.popped&&typeof e.popped=="object"?{popped:e.popped}:{},...typeof e?.passAt=="string"?{passAt:e.passAt}:{},...Array.isArray(e?.wanted)?{wanted:e.wanted.filter(n=>typeof n=="string")}:{}}}catch{return{snoozed:{}}}}function H(t,e){yi(ve(t),{recursive:!0});let n=dn(t),i=`${n}.${process.pid}.tmp`;ki(i,JSON.stringify(e,null,2)+`
5
- `),wi(i,n)}function pn(t,e,n,i=Date.now()){let r=A(t),o={};for(let[s,a]of Object.entries(r.snoozed))Date.parse(a)>i&&(o[s]=a);o[e]=n.toISOString(),H(t,{...r,snoozed:o})}function ja(t,e){H(t,{...A(t),lastDigest:e})}function fn(t,e,n,i=Date.now()){let r=A(t),o=new Set(n),s={};for(let[c,l]of Object.entries(r.popped??{}))o.has(c)&&(s[c]=l);s[e]=new Date(i).toISOString();let a=(r.wanted??[]).filter(c=>c!==e&&o.has(c));H(t,{...r,popped:s,wanted:a})}function gn(t,e){let n=A(t);H(t,{...n,wanted:[...(n.wanted??[]).filter(i=>i!==e),e]})}function Va(t,e=Date.now()){H(t,{...A(t),popped:{},passAt:new Date(e).toISOString()})}zr();qr();import{existsSync as Si,readFileSync as vi}from"fs";It();Hr();function mn(t){let e=Rt(t),n={};if(Si(e))try{n=$t(JSON.parse(vi(e,"utf-8")))}catch{n={}}let i=we.safeParse(n?.requests);return i.success?i.data:we.parse(void 0)}async function za(t,e={}){let n=(t.channels??[]).filter(i=>!be.has(i.toLowerCase().split("@")[0]));return n.length?{success:!1,error:`unknown channel ${n.map(i=>`"${i}"`).join(", ")}: use ${[...be].join(", ")}`}:_t(i=>{let r=i.requests??={};for(let o of["enabled","channels","from","staleAfterHours","retentionDays"])t[o]!==void 0&&(r[o]=t[o])},{configPath:e.configPath,reload:e.reload})}var yn=["card","schedule","memory","wiki","whatsapp","request"],Ii=280;function L(t,e=Ii){let n=t.replace(/\s+/g," ").trim();return n.length>e?`${n.slice(0,e-1)}\u2026`:n}function Re(t){if(t.configPath)return E(t.configPath);let e=[E(t.root,"agentx.json"),E(t.root,".agentx","config.json")];return e.find(n=>oe(n))??e[0]}function _e(t){return t.wikiDir?E(t.wikiDir):E(t.root,".agentx","wiki")}function Ri(t){return B(t.root,"pending").map(_i)}function _i(t){return{key:`card:${t.id}`,kind:"card",title:t.title,ask:t.ask,yes:`tell ${t.raised_by} yes`,no:`tell ${t.raised_by} no`,recommend:t.recommend,if_silent:t.if_silent,expires:t.expires,...t.source?{source:t.source}:{},raised_by:t.raised_by,...t.node?{node:t.node}:{},created_at:t.created_at,...t.choices?{choices:t.choices,more:`agentx approvals popup card:${t.id}`}:{},...t.draft?{draft:t.draft}:{},...t.context||t.draft?{detail:L([t.context,t.draft?`Suggested message: ${t.draft}`:""].filter(Boolean).join(" \xB7 "))}:{}}}function Ci(t){let e=Re(t);if(!oe(e))return[];let n;try{n=JSON.parse(Ai(e,"utf-8"))}catch{return[]}let i=new Date(t.now??Date.now()),r=[];for(let[o,s]of Object.entries(n?.crons??{})){let a=s?.approval;if(!a||a.action!=="create"&&a.action!=="delete")continue;let c=s.timezone||"UTC",l=s.schedule?Pt(s.schedule):"",u=s.schedule?`${l.charAt(0).toLowerCase()}${l.slice(1)} (${s.schedule})`:"no schedule",d=String(s.prompt??s.command??""),p=a.action==="create";r.push({key:`schedule:${o}`,kind:"schedule",title:p?`New schedule "${o}" for ${s.agent??"an agent"}`:`Delete schedule "${o}"`,ask:p?`Let ${s.agent??"the agent"} run this ${u}?`:`Remove the schedule "${o}" (${u})?`,yes:p?"enable it":"remove it",no:p?"drop the request":"keep the schedule",raised_by:String(a.requestedBy??"unknown"),created_at:String(a.requestedAt??""),detail:L(`${d}${p&&s.schedule?` \xB7 first run ${Mt(Lt(s.schedule,c,i),c)}`:""}`),more:"agentx schedule list"})}return r}function bn(t){let e=E(t,".agentx","memory");return oe(e)?$i(e).filter(n=>n.endsWith(".jsonl")).map(n=>n.slice(0,-6)).sort():[]}function Di(t){let e=bn(t.root);if(e.length===0)return[];let n=new ke(t.root),i=[];for(let r of e)for(let o of n.held(r))i.push({key:`memory:${r}/${o.id}`,kind:"memory",title:`Fact ${r} learned from ${o.source.channel}`,ask:`Let ${r} use this fact in its prompts?`,yes:"use it",no:"keep it out for good",raised_by:r,created_at:o.createdAt,detail:L(o.content),more:`agentx memory facts held --agent ${r}`});return i}function Ei(t){let e=t.sources.filter(n=>n.failure);return e.length?e.map(n=>`Recurring failure: ${n.agentId}'s ${n.failure.tool} fails with "${n.failure.errorClass}" in ${n.occurrences??1} sessions (${n.failure.runs} runs).`).join(" "):`${t.sources.length} source(s)${t.occurrences>1?`, seen in ${t.occurrences} sessions`:""}.`}function Ti(t){return Ut(_e(t),"pending").map(e=>{let n=e.evidence;return{key:`wiki:${e.id}`,kind:"wiki",title:e.article.title,ask:e.replaces?`Update "${e.article.path}" in the shared wiki?`:`Add "${e.article.path}" to the shared wiki?`,yes:"write the article",no:"decline it",raised_by:n.agents.join(", ")||"wiki promote",created_at:e.createdAt,detail:L(`${Ei(n)} ${e.article.content}`),more:`agentx wiki proposals show ${e.id}`}})}function Pi(t){return ln(t.root,"pending").map(e=>({key:`whatsapp:${e.id}`,kind:"whatsapp",title:`WhatsApp reply to ${e.chat_name||e.to}`,ask:`Send this to ${e.chat_name||e.to}? "${e.text}"`,yes:"send it on WhatsApp",no:"drop the draft",raised_by:e.agent,created_at:e.created_at,detail:L(`${e.triage}: ${e.summary}`),more:"agentx whatsapp triage log"}))}function z(t){if(t.requests)return t.requests;if(E(t.root)!==process.cwd()||!oe(E(t.root,".agentx","db.sqlite")))return null;let e=xt({quiet:!0});if(!e)return null;let n=hn.get(e);return!n&&!St(e)?null:(n||hn.set(e,n=new vt(e)),n)}var hn=new WeakMap;function Li(t){let e=z(t);return e?e.listByState("needs_attention").map(n=>({key:`request:${n.id}`,kind:"request",title:`Request not finished: ${L(n.text,80)}`,ask:`Ask ${n.agentId} to pick it up again?`,yes:`hand it back to ${n.agentId}`,no:"drop the request",raised_by:n.agentId,created_at:new Date(n.createdAt).toISOString(),detail:L(`${n.attentionReason??"It needs attention"}. Asked on ${n.channel}: ${n.text}`),more:`agentx requests show ${n.id}`})):[]}var wn={card:Ri,schedule:Ci,memory:Di,wiki:Ti,whatsapp:Pi,request:Li};function Mi(t,e){let n=t.expires?Date.parse(t.expires):1/0,i=e.expires?Date.parse(e.expires):1/0;return n!==i?n-i:(Date.parse(t.created_at)||0)-(Date.parse(e.created_at)||0)}function oc(t,e={}){let n=t.now??Date.now(),{snoozed:i}=A(t.root),r=[],o=[],s=0;for(let a of e.kinds??yn){let c;try{c=wn[a](t)}catch(l){o.push({kind:a,error:String(l?.message??l).slice(0,200)});continue}for(let l of c){let u=i[l.key];if(u&&Date.parse(u)>n){if(!e.includeSnoozed){s++;continue}l.snoozed_until=u}r.push(l)}}return r.sort(Mi),{items:r,snoozed:s,errors:o}}function Oi(t){let e=t.indexOf(":");if(e<=0)return null;let n=t.slice(0,e),i=t.slice(e+1);return!yn.includes(n)||!i?null:{kind:n,ref:i}}function Ni(t,e,n){switch(e){case"card":return U(t.root,n)?.status==="pending";case"wiki":return Ft(_e(t),n)?.status==="pending";case"whatsapp":return ie(t.root,n)?.status==="pending";default:return wn[e](t).some(i=>i.key===`${e}:${n}`)}}async function kn(t,e,n,i={}){let r=Oi(e);if(!r)return{ok:!1,error:`unknown item "${e}": use a key from \`agentx approvals list\``};let{kind:o,ref:s}=r,a=t.now??Date.now(),c=i.by??"operator";if(n==="later"){if(!Ni(t,o,s))return{ok:!1,error:`nothing waiting for "${e}"`};let u=i.laterHours&&i.laterHours>0?i.laterHours:24,d=new Date(a+u*36e5);return pn(t.root,e,d,a),{ok:!0,message:`${e} put off until ${d.toISOString()}`}}let l=n==="yes";switch(o){case"card":{let u=Gt(t.root,s,l?"yes":"no",{by:c,note:i.note,now:a,choice:i.choice,text:i.text});return u.ok?{ok:!0,message:`${e}: ${u.card.raised_by} will be told ${l?"yes":"no"}${u.card.choice?` (${u.card.choice})`:""}`}:u}case"schedule":{let u=await(l?Ot:Nt)(s,{configPath:Re(t),reload:t.reload});return u.success?{ok:!0,message:u.message}:{ok:!1,error:u.message}}case"memory":{let u=s.indexOf("/");if(u<=0)return{ok:!1,error:"memory keys look like memory:<agent>/<fact-id>"};let d=s.slice(0,u),p=s.slice(u+1);if(!bn(t.root).includes(d))return{ok:!1,error:`no memory for agent "${d}"`};let f=new ke(t.root);return f.held(d).some(g=>g.id===p)?(f.review(d,p,l?"approved":"rejected",c),{ok:!0,message:`${e} ${l?"approved: the agent may use it":"rejected: it stays out of prompts"}`}):{ok:!1,error:`fact "${p}" isn't waiting for review`}}case"wiki":{let u=_e(t),d=l?Bt(u,s,{by:c,force:i.force,now:a}):Ht(u,s,{by:c,reason:i.note,now:a});return d.ok?{ok:!0,message:l?`${d.proposal.article.path} written to the shared wiki`:`${e} rejected`}:d}case"whatsapp":{let u=await un(t.root,s,l?"yes":"no",{by:c,now:a,send:t.sendWhatsApp});return u.ok?{ok:!0,message:l?`${e}: sent to ${u.draft.chat_name||u.draft.to}`:`${e}: dropped, nothing sent`}:u}case"request":{let u=z(t),d=u?.get(s);return!u||!d||d.state!=="needs_attention"?{ok:!1,error:`nothing waiting for "${e}"`}:l?mn(Re(t)).enabled?(u.requestPickup(s,a),{ok:!0,message:`${e}: ${d.agentId} will be asked to pick it up again`}):{ok:!1,error:"Requests are off, so nothing would hand it back. Turn them on (agentx requests settings --enabled on), or answer no to drop it."}:(u.close(s,"dropped",i.note?.trim()||`dropped by ${c}`,a),{ok:!0,message:`${e}: dropped`})}}}var xn=new Set(["127.0.0.1","::1","::ffff:127.0.0.1"]);function ac(t){return t==="/api/memory"||t.startsWith("/api/memory/")||t==="/approvals"||t.startsWith("/approvals/")||t==="/requests"||t.startsWith("/requests/")||t==="/events/recent"||/^\/agents\/[^/]+\/events$/.test(t)||t==="/a2a/delegations"||t.startsWith("/a2a/delegations/")||t==="/traces"||t.startsWith("/traces/")||t==="/voice/history"||t.startsWith("/voice/history/")||t==="/voice/transcribe"||t==="/voice/speak"||t==="/app-files"||t==="/calls"||t.startsWith("/calls/")||t==="/webrtc/camera"||t.startsWith("/webrtc/camera/")||t==="/mesh/guests"||t.startsWith("/mesh/guests/")||t==="/wiki/agents"||t==="/wiki/entries"||t==="/wiki/articles"||t==="/wiki/article"}function cc(t){return t==="/reload"||t==="/api/processes/kill"||t==="/send"||t==="/send/agent"||t==="/send/contact"||t==="/mesh/announce"||t==="/voice/settings"||t==="/voice/preview"||/^\/api\/tasks\/[^/]+\/(cancel|followup)$/.test(t)||/^\/mesh\/guests\/[^/]+\/(pause|resume|end|update)$/.test(t)||/^\/crons\/[^/]+\/enabled$/.test(t)}function lc(t){return xn.has(t)}function uc(t){if(t.foreignBrowser)return{allowed:!1,reason:"foreign-browser-origin"};if(t.enforcementDisabled)return{allowed:!0,reason:"disabled"};if(xn.has(t.remoteAddress))return{allowed:!0,reason:"loopback"};if(t.acceptedTokens.size===0)return{allowed:!0,reason:"no-tokens-configured"};let e=t.authorizationHeader||"",n=e.startsWith("Bearer ")?e.slice(7).trim():"";return n&&t.acceptedTokens.has(n)?{allowed:!0,reason:"token"}:{allowed:!1,reason:"missing-or-invalid-token"}}function dc(t,e=process.env){let n=new Set;e.MESH_TOKEN&&n.add(e.MESH_TOKEN);for(let i of t.mesh?.peers||[])i.token&&n.add(i.token);return n}function pc(t,e,n=process.env){let i=o=>o.replace(/\/+$/,"");return(e===i(t.daemonUrl)?t.token:t.daemons.find(o=>i(o.url)===e)?.token)||n.MESH_TOKEN||void 0}function se(t){return(Array.isArray(t)?t[0]:t)?.trim()??""}function ji(t){try{return new URL(t).host.toLowerCase()}catch{return null}}function Vi(t=process.env){return new Set((t.AGENTX_ALLOWED_ORIGINS||"").split(",").map(e=>e.trim().replace(/\/+$/,"").toLowerCase()).filter(Boolean))}function gc(t,e=Vi()){let n=se(t.origin);if(n){if(e.has(n.replace(/\/+$/,"").toLowerCase()))return"same-origin";let r=ji(n),o=[se(t.host),se(t["x-forwarded-host"])].filter(Boolean).map(s=>s.toLowerCase());return r&&o.includes(r)?"same-origin":"foreign"}let i=se(t["sec-fetch-site"]).toLowerCase();return i==="cross-site"||i==="same-site"?"foreign":"none"}function mc(t){let e=(t||"GET").toUpperCase();return e!=="GET"&&e!=="HEAD"}import{existsSync as qn,mkdirSync as mo,readFileSync as ho,renameSync as yo,writeFileSync as bo}from"fs";import{homedir as wo}from"os";import{dirname as ko,join as xo}from"path";import{execFile as Ji,execFileSync as Yi}from"child_process";import{execFileSync as Wi}from"child_process";import{existsSync as vn,mkdirSync as Fi,readdirSync as Ui,readFileSync as $n,renameSync as Bi,writeFileSync as Hi}from"fs";import{homedir as An}from"os";import{join as De}from"path";var S="siri:",In="com.apple.ttsbundle.gryphon-neural_",Rn=t=>!!t&&t.startsWith(In),zi=["/usr/bin/say","/usr/bin/defaults","/usr/bin/plutil"],qi=()=>{try{return Wi("/usr/bin/defaults",["read","com.apple.Accessibility"],{stdio:"ignore",timeout:5e3}),!0}catch{return!1}},Ce;function Ee(t={}){let e=t.platform!==void 0||t.exists!==void 0||t.prefDomain!==void 0;if(!e&&Ce!==void 0)return Ce;let{platform:n=process.platform,exists:i=vn,prefDomain:r=qi}=t,o=n==="darwin"&&zi.every(s=>i(s))&&r();return e||(Ce=o),o}var _n=["/System/Library/AssetsV2/com_apple_MobileAsset_Trial_Siri_SiriTextToSpeech/purpose_auto","/System/Library/AssetsV2/com_apple_MobileAsset_UAF_Siri_TextToSpeech/purpose_auto"],Cn={aaron:"male",damon:"male",daniel:"male",pierre:"male",samer:"male",arthur:"male",gordon:"male",martin:"male",nora:"female",simone:"female",marie:"female",soha:"female",martha:"female",catherine:"female",helena:"female",nicky:"female"},Te=t=>Cn[t.toLowerCase()]??null;function ae(t){let e=/^com\.apple\.ttsbundle\.gryphon-neural_([a-z]+)_([a-z]{2}-[A-Z]{2})_premium$/.exec(t);return e?{name:e[1],locale:e[2]}:null}var Ki=/com\.apple\.siri\.tts\.voice\.([a-z]{2})_([A-Z]{2})\.([a-z]+)\.neural\.premium/g;function Gi(t){let e=new Map;for(let n of t)for(let[,i,r,o]of n.matchAll(Ki)){let s=`${i}-${r}`,a=`${In}${o}_${s}_premium`;e.has(a)||e.set(a,{id:a,name:o[0].toUpperCase()+o.slice(1),locale:s,quality:"premium",gender:Cn[o]??null,siri:!0})}return[...e.values()]}function ce(t=_n,e={}){if(!Ee(e))return[];let n=[];for(let i of t){let r;try{r=Ui(i)}catch{continue}for(let o of r)try{n.push($n(De(i,o,"Info.plist"),"latin1"))}catch{}}return Gi(n)}var Sn=`#!/bin/sh
6
- # Written by agentx; shared by the daemon and AgentX Voice. Do not edit.
7
- # siri-say.sh [voice] < text speak one line. A Siri voice id switches
8
- # the OS default for it; any other id is
9
- # passed to say -v.
10
- # siri-say.sh --stop silence the line speaking, drop the queue.
11
- # siri-say.sh --restore put back a voice a killed line left switched.
12
- # AGENTX_SAY_RATE=<words a minute> sets the speed; unset, say's own.
13
- D=com.apple.Accessibility K=SpokenContentDefaultVoiceSelectionsByLanguage
14
- dir="$HOME/.agentx/voice" lock="$HOME/.agentx/voice/siri.lock" saved="$HOME/.agentx/voice/siri-saved.plist"
15
- stops="$dir/stop"
16
- read_s=\${AGENTX_SAY_READ_S:-5} stale_s=\${AGENTX_SAY_STALE_S:-30} max_s=\${AGENTX_SAY_MAX_S:-300}
17
- assets=\${AGENTX_SIRI_ASSET_DIRS:-"${_n.join(" ")}"}
18
- if [ "$1" = --stop ]; then
19
- mkdir -p "$dir" || exit 1
20
- # Queued lines see this change and drop. The owner's trap stops say,
21
- # restores the voice, and frees the lock.
22
- echo "$$ $(date +%s)" > "$stops"
23
- owner=$(cat "$lock/pid" 2>/dev/null)
24
- [ -n "$owner" ] && kill "$owner" 2>/dev/null
25
- exit 0
26
- fi
27
- mode=speak
28
- [ "$1" = --restore ] && { mode=restore; set --; }
29
- case "$1" in com.apple.ttsbundle.gryphon-neural_*) siri=$1 voice= ;; *) siri= voice=$1 ;; esac
30
- rate=\${AGENTX_SAY_RATE:-}
31
- case "$rate" in *[!0-9]*) rate= ;; esac
32
- case "$siri" in *[!A-Za-z0-9._-]*) echo "bad voice id" >&2; exit 2;; esac
33
- # Not macOS, or no pref tools: speak as is and never touch a pref.
34
- if [ "$(uname)" != Darwin ] || ! command -v defaults >/dev/null || ! command -v plutil >/dev/null; then
35
- [ "$mode" = restore ] && exit 0
36
- if [ -n "$voice" ]; then exec say \${rate:+-r "$rate"} -v "$voice"; else exec say \${rate:+-r "$rate"}; fi
37
- fi
38
- mkdir -p "$dir" || exit 1
39
- mine=$(cat "$stops" 2>/dev/null)
40
- stopped() { [ "$(cat "$stops" 2>/dev/null)" != "$mine" ]; }
41
- txt=$(mktemp "\${TMPDIR:-/tmp}/agentx-say.XXXXXX") || exit 1
42
- say_pid= dog=
43
- restore() {
44
- [ -f "$saved" ] || return 0
45
- if [ -s "$saved" ]; then defaults write $D $K "$(cat "$saved")"; else defaults delete $D $K 2>/dev/null; fi
46
- rm -f "$saved"
47
- }
48
- finish() {
49
- [ -n "$say_pid" ] && kill "$say_pid" 2>/dev/null
50
- [ -n "$dog" ] && { pkill -P "$dog" 2>/dev/null; kill "$dog" 2>/dev/null; }
51
- restore; rm -rf "$lock"; rm -f "$txt"; exit "$1"
52
- }
53
- drop() { rm -f "$txt"; exit 75; }
54
- # A Siri voice whose asset macOS purged: switching to it makes the OS
55
- # speak a fallback of its own (Eloquence Flo), so leave the pref alone.
56
- if [ -n "$siri" ]; then
57
- s=\${siri#com.apple.ttsbundle.gryphon-neural_} ; name=\${s%%_*} ; s=\${s#*_} ; loc=$(printf %s "\${s%%_*}" | tr - _)
58
- found=
59
- for a in $assets; do
60
- grep -aqs "com.apple.siri.tts.voice.$loc.$name.neural.premium" "$a"/*/Info.plist && { found=1; break; }
61
- done
62
- [ -z "$found" ] && { echo "Siri voice $siri is not installed; speaking with the OS default" >&2; siri=; }
63
- fi
64
- # The whole text first, before the lock: a writer that never closes stdin
65
- # must not hold up every other speaker.
66
- [ "$mode" = restore ] && exec 0</dev/null
67
- exec 3<&0 0</dev/null
68
- cat <&3 > "$txt" & cat_pid=$!
69
- exec 3<&-
70
- n=0
71
- while kill -0 "$cat_pid" 2>/dev/null; do
72
- if [ $n -ge $((read_s * 10)) ]; then
73
- kill "$cat_pid" 2>/dev/null; echo "stdin never closed; nothing said" >&2; rm -f "$txt"; exit 3
74
- fi
75
- sleep 0.1; n=$((n + 1))
76
- done
77
- # One speaker at a time. A lock whose owner died is taken over. A line
78
- # that waits past stale_s, or that a stop overtook, is dropped unsaid.
79
- n=0
80
- while ! mkdir "$lock" 2>/dev/null; do
81
- stopped && drop
82
- if [ $n -ge $((stale_s * 10)) ]; then echo "waited \${stale_s}s for the speaker; dropped" >&2; drop; fi
83
- owner=$(cat "$lock/pid" 2>/dev/null)
84
- if [ -n "$owner" ] && ! kill -0 "$owner" 2>/dev/null; then rm -rf "$lock"
85
- elif [ -z "$owner" ] && [ -n "$(find "$lock" -maxdepth 0 -mmin +1 2>/dev/null)" ]; then rm -rf "$lock"
86
- else sleep 0.1; n=$((n + 1)); fi
87
- done
88
- echo $$ > "$lock/pid"
89
- trap 'finish 143' TERM INT HUP
90
- stopped && finish 75
91
- [ "$mode" = restore ] && finish 0
92
- restore
93
- if [ -n "$siri" ]; then
94
- lang=$(defaults read -g AppleLanguages 2>/dev/null | sed -n '2s/^[^A-Za-z]*\\([A-Za-z]*\\).*/\\1/p')
95
- defaults export $D - 2>/dev/null | plutil -extract $K xml1 -o "$saved.tmp" - 2>/dev/null || : > "$saved.tmp"
96
- mv "$saved.tmp" "$saved"
97
- defaults write $D $K -array "\${lang:-en}" "{ _type = \\"Speech.VoiceSelection\\"; _version = 0; voiceId = \\"$siri\\"; }"
98
- fi
99
- # A watchdog: no line runs past its length's worth of speech (a hung say
100
- # held the lock for minutes), capped at max_s.
101
- limit=$((5 + $(wc -w < "$txt") * 6 / 10))
102
- [ $limit -gt $max_s ] && limit=$max_s
103
- if [ -n "$voice" ]; then say \${rate:+-r "$rate"} -v "$voice" -f "$txt" & else say \${rate:+-r "$rate"} -f "$txt" & fi
104
- say_pid=$!
105
- ( sleep "$limit"; echo "say ran past \${limit}s; stopped" >&2; kill "$say_pid" 2>/dev/null ) & dog=$!
106
- wait "$say_pid"
107
- status=$?
108
- say_pid=
109
- finish $status
110
- `,Xi=(t=An())=>De(t,".agentx","voice","siri-say.sh");function Dn(t=An()){let e=Xi(t);return vn(e)&&$n(e,"utf8")===Sn||(Fi(De(t,".agentx","voice"),{recursive:!0}),Hi(`${e}.tmp`,Sn,{mode:493}),Bi(`${e}.tmp`,e)),e}var En=`ObjC.import("AVFoundation")
111
- const vs = $.AVSpeechSynthesisVoice.speechVoices, out = []
112
- for (let i = 0; i < vs.count; i++) {
113
- const v = vs.objectAtIndex(i)
114
- out.push([v.identifier.js, v.name.js, v.language.js, Number(v.quality), Number(v.gender)].join("\\t"))
115
- }
116
- out.join("\\n")`,Zi=new Set(["Fred","Kathy","Ralph","Junior"]),Qi={Flo:"female",Sandy:"female",Shelley:"female",Grandma:"female",Kathy:"female",Eddy:"male",Reed:"male",Rocko:"male",Grandpa:"male",Fred:"male",Ralph:"male",Junior:"male"};function Tn(t){let e=[];for(let n of t.split(`
117
- `)){let[i,r,o,s,a]=n.split(" ");!i||!r||!o||i.includes(".siri_")||i.startsWith("com.apple.speech.synthesis.voice.")&&!Zi.has(r)||e.push({id:i,name:r,locale:o,quality:s==="3"?"premium":s==="2"?"enhanced":"standard",gender:a==="1"?"male":a==="2"?"female":Qi[r]??null})}return e}var eo=10*60*1e3,$c=60*1e3,j=null,Pe=!1;function Le(t=Date.now(),e=eo){if(process.platform!=="darwin")return[];if(j)t-j.at>e&&!Pe&&(Pe=!0,Ji("osascript",["-l","JavaScript","-e",En],{timeout:1e4},(n,i)=>{Pe=!1,n||(j={at:Date.now(),voices:[...Tn(String(i)),...ce()]})}));else try{j={at:t,voices:[...Tn(Yi("osascript",["-l","JavaScript","-e",En],{encoding:"utf8",timeout:1e4})),...ce()]}}catch(n){Me(`[voice] could not list system voices: ${String(n?.message??n).split(`
118
- `)[0]}`),j={at:t,voices:ce()}}return j.voices}var Me=t=>process.stderr.write(t+`
119
- `),le=new Set;function Ac(t){Me=t}function M(t,e){le.has(t)||(le.add(t),Me(e))}function Mn(t){for(let e of le)t(e)&&le.delete(e)}var On=()=>{};function Ic(t){On=t}function Nn(t){try{On(t)}catch(e){M("missing-hook",`[voice] missing-voice check failed: ${e?.message??e}`)}}var to={premium:3,enhanced:2,standard:1},no=new Set(["Grandma","Grandpa"]);function Pn(t){let e=t.id.startsWith("com.apple.voice.")?2:t.id.startsWith("com.apple.eloquence.")&&!no.has(t.name)?1:0;return to[t.quality]*10+e}var V=t=>t.toLowerCase().split(/[-_]/)[0],Ln=t=>t.id.startsWith("com.apple.voice.");function Oe(t,e,n,i=new Set){let r=q(t.filter(a=>!a.siri&&V(a.locale)===V(e)),e);if(r.some(Ln)&&(r=r.filter(Ln)),n==="female"||n==="male"){let a=r.filter(c=>c.gender===n);a.length&&(r=a)}if(!r.length)return null;let o=r.filter(a=>a.quality===r[0].quality),s=new Set([...i].map(a=>a.toLowerCase()));return o.find(a=>!s.has(a.name.toLowerCase()))??o[0]}function q(t,e="en"){let n=e.toLowerCase().replace("_","-"),i=V(e),r=t.filter(o=>V(o.locale)===i);return(r.length?r:t).slice().sort((o,s)=>Pn(s)-Pn(o)||+(s.locale.toLowerCase()===n)-+(o.locale.toLowerCase()===n)||o.name.localeCompare(s.name)||o.locale.localeCompare(s.locale))}function K(t,e,n="en"){let i=t.trim();if(!i)return null;let r=e.find(l=>l.id===i);if(r)return r;if(i.toLowerCase().startsWith(S)){let l=i.slice(S.length).trim().toLowerCase(),u=q(e.filter(p=>p.siri&&p.name.toLowerCase()===l),n)[0];if(u||!l)return u??null;let d=K(l,e.filter(p=>V(p.locale)===V(n)),n);return d&&M(`siri:${l}`,`[voice] Siri voice "${l}" is not installed; speaking with ${d.name} (${d.locale}) instead.`),d}e=e.filter(l=>!l.siri);let o=/^(.+?)\s*\((premium|enhanced)\)$/i.exec(i),s=(o?o[1]:i.replace(/\s*\(.*\)\s*$/,"")).trim().toLowerCase(),a=q(e.filter(l=>l.name.toLowerCase()===s),n);return(o?a.find(l=>l.quality===o[2].toLowerCase()):void 0)??a[0]??null}function jn(t,e,n=new Set){let i=new Map;if(!e.length)return i;let r=new Set([...n].map(s=>s.toLowerCase())),o="female";for(let s of t){let a=s.gender==="female"||s.gender==="male",c=a?s.gender:o,l=e.filter(d=>!r.has(d.name.toLowerCase())),u=l.find(d=>d.gender===c)??(a?e.find(d=>d.gender===c):void 0)??l[0]??e[i.size%e.length];i.set(s.id,u),r.add(u.name.toLowerCase()),a||(o=o==="female"?"male":"female")}return i}wt();var Ne="system",ro=t=>t.trim().toLowerCase()===Ne,io="21m00Tcm4TlvDq8ikWAM";function je(t,e,n={},i=Le()){let r=e[t],o=r?.name||t,s=r?.voice,a=We(e,n,i).get(t)??null,c=co(t,s?.system,s?.gender,n,i);return{agentId:t,name:o,provider:s?.provider??n.provider??"system",elevenlabsVoiceId:s?.elevenlabsVoiceId||null,systemVoice:a?.id??null,systemVoiceName:a?de(a):null,systemByLanguage:c,fallback:(n.fallback??"system")==="system",gender:s?.gender??null,style:s?.style||null,intro:s?.intro||uo(o,r?.systemPrompt),...s?.rate?{rate:s.rate}:{},...s?.priority?{priority:s.priority}:{}}}var de=t=>`${t.name}${t.siri?" (Siri)":t.quality==="standard"?"":` (${t.quality[0].toUpperCase()}${t.quality.slice(1)})`} ${t.locale}`;function oo(t,e,n,i){if(!e||!n.length)return null;let r=K(e,n,i);return r||(M(`${t}:${e}`,`[voice] ${t}: system voice "${e}" is not installed; using the next choice. Run \`agentx voice list\` to see installed voices.`),Nn(e)),r}function Un(t,e){let n=t.trim();if(n.toLowerCase().startsWith(S))return{locale:e,gender:Te(n.slice(S.length).trim())};let i=ae(n);return i?{locale:i.locale,gender:Te(i.name)}:{locale:/^com\.apple\.voice\.[a-z]+\.([a-z]{2}-[A-Z]{2})\./.exec(n)?.[1]??e,gender:null}}var Bn=t=>t.toLowerCase().split(/[-_]/)[0],Vn=(t,e)=>typeof t=="string"?t:t?.[Bn(e)];function ue(t,e,n,i){if(e!==void 0)return ro(e)?null:oo(t,e,n,i)??void 0}var Ve=(t,e)=>!t||!t.gender||t.gender==="neutral"||!e||e==="neutral"||t.gender===e;function so(t,e,n,i=new Set){let r=e.locale??"en",o=new Map,s=[],a=ue("voice.system",Vn(e.system,r),n,r),c=()=>new Set([...i,...[...o.values()].flatMap(u=>u?[u.name]:[])]);for(let u of t){let d=Vn(u.system,r),p=ue(u.id,d,n,r),f=p!==void 0?p:d!==void 0&&n.length?ao(u,d,r,a,n,c()):a!==void 0&&Ve(a,u.gender)?a:void 0;f!==void 0?o.set(u.id,f):s.push({id:u.id,gender:u.gender??null})}let l=c();for(let[u,d]of jn(s,q(n.filter(p=>!p.siri),r),l))o.set(u,d);return o}function ao(t,e,n,i,r,o){for(let a of t.fallbacks??[]){let c=ue(`${t.id}.fallbacks`,a,r,n);if(c!==void 0)return c}if(i!==void 0&&Ve(i,t.gender))return i;let s=Un(e,n);return Oe(r,s.locale,t.gender??s.gender,o)??void 0}function co(t,e,n,i,r){if(typeof e=="string")return{};let o={},s=(a,c,l)=>{if(!(!c||typeof c=="string"))for(let[u,d]of Object.entries(c)){let p=ue(`${a}.${u}`,d,r,u);p===void 0&&r.length&&(p=Oe(r,u,n??Un(d,u).gender)??void 0),p!==void 0&&l(p)&&(o[Bn(u)]=p)}};return s("voice.system",i.system,a=>Ve(a,n)),s(t,e,()=>!0),o}function Ec(t,e){let n=e?Q(e):null;if(!n||!(n in t.systemByLanguage))return t;let i=t.systemByLanguage[n];return{...t,systemVoice:i?.id??null,systemVoiceName:i?de(i):null}}function We(t,e={},n=Le()){let i=Object.entries(t).map(([r,o])=>({id:r,system:o.voice?.system,gender:o.voice?.gender,fallbacks:o.voice?.fallbacks}));return so(i,e,n)}function Fe(t,e){let n={provider:t.provider,elevenlabs:lo(e,t.elevenlabsVoiceId),system:t.systemVoice,fallback:t.fallback},i=Object.entries(t.systemByLanguage??{});return i.length&&(n.languages=Object.fromEntries(i.map(([r,o])=>[r,o?.id??null]))),t.rate&&t.rate!==1&&(n.rate=t.rate),t.priority&&t.priority!=="normal"&&(n.priority=t.priority),n}function lo(t,e){return t||e||process.env.AGENTX_VOICE_ID||io}function uo(t,e){let n=(e??"").split(/(?<=\.)\s/)[0]??"",i=/^You are (.+?)\.?$/i.exec(n.trim());if(!i)return`Hello, this is ${t}.`;let r=i[1].replace(/\s*\([^)]*\)/g,"").trim(),[o,...s]=r.split(/,\s*/),a=s.join(", ");return a&&o.toLowerCase()===t.toLowerCase()?`Hello, this is ${t}, ${a}.`:!/^an? /i.test(r)&&r.toLowerCase().includes(t.toLowerCase())?`Hello, this is ${r}.`:`Hello, this is ${t}, ${r}.`}var po=8*60*60*1e3,fo=500,Wn=class{constructor(e=po){this.gapMs=e}lastSpoke=new Map;needsIntro(e,n,i=Date.now()){let r=this.lastSpoke.get(Fn(e,n));return r===void 0||i-r>this.gapMs}spoke(e,n,i=Date.now()){let r=Fn(e,n);this.lastSpoke.delete(r),this.lastSpoke.set(r,i),this.lastSpoke.size>fo&&this.lastSpoke.delete(this.lastSpoke.keys().next().value)}},Fn=(t,e)=>`${t}\0${e}`;function Hn(t,e){let n=t.style?` Your speaking manner: ${t.style}.`:"";return e?`[VOICE INTRO] This is your first spoken exchange with this person in a while. Open with one short sentence introducing yourself in your own manner, along the lines of "${t.intro}", then answer.${n}`:"[VOICE CASUAL] You have already introduced yourself in this voice conversation. Do not introduce yourself or greet again; talk casually, like a colleague in the same office."+n}function Tc(t,e,n,i={}){let r=e[t],o=je(t,e,i),s=(r?.systemPrompt??"").split(/\n\s*\n/)[0].slice(0,600).trim();return{agentId:t,name:o.name,voice:Fe(o),persona:s||`You are ${o.name}.`,introLine:Hn(o,n)}}var go="[VOICE MODE] This question arrived by voice and your reply will be spoken aloud by a TTS engine. Answer in two or three short sentences. Plain language, no markdown, no code blocks, no bullet points, no URLs. Speak conversationally.";function Pc(t){let e=t;if(e?.channel!=="voice"||!e.voice||typeof e.voice!="object")return;let n=o=>typeof o=="string"?o.replace(/\s+/g," ").slice(0,200):"",i=n(e.voice.intro),r={agentId:"",name:"",provider:"system",elevenlabsVoiceId:null,systemVoice:null,systemVoiceName:null,systemByLanguage:{},fallback:!0,gender:null,style:n(e.voice.style)||null,intro:i||"Hello."};return`${go}
120
- ${Hn(r,e.voice.introduce===!0&&!!i)}`}var So="System Settings \u203A Accessibility \u203A Spoken Content \u203A System voice \u203A Manage Voices",Kn=(t=wo())=>xo(t,".agentx","voice","health.json");function vo(t,e,n){let i=t.trim();if(!i||i.toLowerCase()===Ne)return!0;if(i.toLowerCase().startsWith(S)){let r=i.slice(S.length).trim().toLowerCase();return e.some(o=>o.siri&&o.name.toLowerCase()===r)}return K(i,e,n)!==null}function $o(t){let e=t.voice?.locale??"en",n=[],i=(r,o)=>{if(typeof o=="string")n.push({owner:r,name:o,locale:e,perLanguage:!1});else for(let[s,a]of Object.entries(o??{}))n.push({owner:r,name:a,locale:s,perLanguage:!0})};i("voice.system",t.voice?.system);for(let[r,o]of Object.entries(t.agents))(o.voice?.provider??t.voice?.provider??"system")!=="system"&&t.voice?.fallback==="none"||i(r,o.voice?.system);return n}function Ao(t,e){if(!e.length)return[];let n=new Map,i;for(let{owner:r,name:o,locale:s,perLanguage:a}of $o(t)){if(vo(o,e,s))continue;i??=We(t.agents,t.voice,e);let c=n.get(o)??{voice:o,agents:[],speaksWith:{}};c.agents.includes(r)||c.agents.push(r);let l=i.get(r);r!=="voice.system"&&!a&&(c.speaksWith[r]=l?de(l):"the OS default voice"),n.set(o,c)}return[...n.values()]}function Ue(t){let e=ae(t);if(e)return`Siri ${e.name[0].toUpperCase()}${e.name.slice(1)} (${e.locale})`;if(t.toLowerCase().startsWith(S)){let n=t.slice(S.length).trim();return`Siri ${n[0]?.toUpperCase()??""}${n.slice(1)}`}return t}function Io(t){let e=t.map(n=>{let i=n.agents.map(r=>n.speaksWith[r]?`${r} (now ${n.speaksWith[r]})`:r).join(", ");return`\u2022 ${Ue(n.voice)}: ${i}`});return{title:t.length===1?"AgentX: a voice is not installed":`AgentX: ${t.length} voices are not installed`,message:`${e.join(`
121
- `)}
122
- Reinstall in ${So}. Agents switch back on their own once it is installed.`}}function Ro(t=Kn()){if(!qn(t))return null;try{let e=JSON.parse(ho(t,"utf8"));return e&&Array.isArray(e.missing)?e:null}catch{return null}}function _o(t,e){mo(ko(t),{recursive:!0}),bo(`${t}.tmp`,JSON.stringify(e,null,2)+`
123
- `),yo(`${t}.tmp`,t)}var zn=class{constructor(e){this.deps=e}running=!1;missingNow=!1;hasMissing(){return this.missingNow}async check(e,n,i=new Date){if(this.running||!n.length)return null;this.running=!0;try{let r=this.deps.file??Kn(),o=new Map((Ro(r)?.missing??[]).map(d=>[d.voice,d])),s=Ao(e,n),a=s.map(d=>({...d,since:o.get(d.voice)?.since??i.toISOString(),...o.get(d.voice)?.notifiedAt?{notifiedAt:o.get(d.voice).notifiedAt}:{}})),c=[...o.keys()].filter(d=>!s.some(p=>p.voice===d));for(let d of c)this.deps.log(`[voice] ${Ue(d)} is installed again; its agents speak with it again`);c.length&&Mn(d=>c.some(p=>d===p||d.endsWith(`:${p}`)));let l=a.filter(d=>!d.notifiedAt);if(l.length){let{title:d,message:p}=Io(l);try{await this.deps.notify(d,p);for(let f of l)f.notifiedAt=i.toISOString();this.deps.log(`[voice] told the owner: ${l.map(f=>Ue(f.voice)).join(", ")} not installed`)}catch(f){this.deps.log(`[voice] could not send the missing-voice notice: ${f?.message??f}`)}}this.missingNow=a.length>0;let u={checkedAt:i.toISOString(),missing:a};return(!qn(r)||JSON.stringify(a)!==JSON.stringify([...o.values()]))&&_o(r,u),u}finally{this.running=!1}}};import{readFileSync as He,writeFileSync as Qn,existsSync as ze,readdirSync as No,statSync as jo}from"fs";import{resolve as qe,join as Vo}from"path";import{existsSync as Gn,mkdirSync as Co,readFileSync as Do,writeFileSync as Xn}from"fs";import{dirname as Eo,resolve as Jn}from"path";import{z as m}from"zod";var To=m.object({type:m.enum(["gitlab","github"]),host:m.string().optional(),project:m.string(),iid:m.number().int().positive(),url:m.string()}),Po=m.object({id:m.string(),title:m.string(),description:m.string().optional(),assignee:m.string().optional(),labels:m.array(m.string()).default([]),milestone:m.string().optional(),status:m.enum(["todo","doing","blocked","done"]).default("todo"),priority:m.number().int().optional(),estimatedSeconds:m.number().int().optional(),source:To.optional(),importedAt:m.string().optional(),createdAt:m.string(),updatedAt:m.string(),blocker:m.string().optional(),doneNote:m.string().optional()}),Lo=m.object({version:m.literal(1),items:m.array(Po).default([])}),pe=class{constructor(e){this.path=e}jsonPath(){return Jn(process.cwd(),this.path).replace(/\.md$/i,".json")}mdPath(){return Jn(process.cwd(),this.path).replace(/\.json$/i,".md")}exists(){return Gn(this.jsonPath())}load(){let e=this.jsonPath();if(!Gn(e))return{version:1,items:[]};let n=Do(e,"utf-8");try{return Lo.parse(JSON.parse(n))}catch(i){throw new Error(`Backlog file invalid (${e}): ${i.message}`)}}save(e){let n=this.jsonPath();Co(Eo(n),{recursive:!0}),Xn(n,JSON.stringify(e,null,2)+`
124
- `),Xn(this.mdPath(),this.toMarkdown(e))}list(){return this.load().items}findById(e){return this.list().find(n=>n.id===e)}add(e){let n=this.load();if(n.items.some(o=>o.id===e.id))throw new Error(`backlog item ${e.id} already exists`);let i=new Date().toISOString(),r={...e,labels:e.labels??[],status:e.status??"todo",createdAt:e.createdAt??i,updatedAt:i};return n.items.push(r),this.save(n),r}addMany(e){let n=this.load(),i=new Set(n.items.map(s=>s.id)),r=new Date().toISOString(),o=[];for(let s of e){if(i.has(s.id))continue;let a={...s,labels:s.labels??[],status:s.status??"todo",createdAt:s.createdAt??r,updatedAt:r};n.items.push(a),o.push(a),i.add(a.id)}return o.length&&this.save(n),o}update(e,n){let i=this.load(),r=i.items.findIndex(s=>s.id===e);if(r<0)throw new Error(`backlog item ${e} not found`);let o={...i.items[r],...n,id:i.items[r].id,createdAt:i.items[r].createdAt,updatedAt:new Date().toISOString()};return i.items[r]=o,this.save(i),o}remove(e){let n=this.load(),i=n.items.length;return n.items=n.items.filter(r=>r.id!==e),n.items.length===i?!1:(this.save(n),!0)}toMarkdown(e){let n=["# Backlog","","_Generated from `backlog.json`. Do not edit by hand \u2014 use `agentx backlog` commands._",""],i={doing:[],blocked:[],todo:[],done:[]};for(let o of e.items)i[o.status].push(o);let r=[["doing","Doing"],["blocked","Blocked"],["todo","To Do"],["done","Done"]];for(let[o,s]of r)if(i[o].length){n.push(`## ${s}`,"");for(let a of i[o]){let c=o==="done"?"x":" ",l=a.assignee?`@${a.assignee} `:"",u=a.estimatedSeconds?` [time: ${Math.round(a.estimatedSeconds/60)}m]`:"",d=a.source?` (${a.source.type}: ${a.source.project}#${a.source.iid})`:"";n.push(`- [${c}] ${l}${a.title}${u}${d}`),a.source?.url&&n.push(` - <${a.source.url}>`),a.labels.length&&n.push(` - labels: ${a.labels.join(", ")}`),a.milestone&&n.push(` - milestone: ${a.milestone}`),a.blocker&&n.push(` - BLOCKED: ${a.blocker}`)}n.push("")}return n.join(`
125
- `)}};function zc(t){return`${t.type}:${t.project}:${t.iid}`}function Yn(t,e,n){let i=[];if(e.type==="gitlab"){let r=n.channels.gitlab?.agentMappings??[];for(let o of t){let s=r.find(a=>a.agentId===o);s?.gitlabUsernames?.length?i.push(s.gitlabUsernames[0]):i.push(o)}}else if(e.type==="github"){let r=n.channels.github?.agentMappings??[];for(let o of t){let s=r.find(a=>a.agentId===o);s?.githubUsernames?.length?i.push(s.githubUsernames[0]):i.push(o)}}return i}async function Be(t,e,n,i=()=>{}){return t.source?t.source.type==="gitlab"?Mo(t.source,e,n,i):t.source.type==="github"?Oo(t.source,e,n,i):{ok:!1,error:`unknown source.type ${t.source.type}`,attempts:[]}:{ok:!0,attempts:[]}}async function Mo(t,e,n,i){let r=n.channels.gitlab,o=r?.token,s=r?.host||(t.host?`https://${t.host}`:void 0);if(!o||!s)return{ok:!1,error:"gitlab token/host not configured",attempts:[]};let a=[],c=async(f,g={})=>fetch(`${s}/api/v4${f}`,{...g,headers:{"PRIVATE-TOKEN":o,"Content-Type":"application/json",...g.headers||{}}}),l=encodeURIComponent(t.project),u;e.assigneeUsernames!==void 0&&(u=(await Promise.all(e.assigneeUsernames.map(async g=>{try{let h=await fetch(`${s}/api/v4/users?username=${encodeURIComponent(g)}`,{headers:{"PRIVATE-TOKEN":o}});if(!h.ok)return null;let y=await h.json();return Array.isArray(y)&&y[0]?.id?y[0].id:null}catch{return null}}))).filter(g=>typeof g=="number"));let d;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")d=0;else try{let f=await c(`/projects/${l}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);if(f.ok){let g=await f.json();Array.isArray(g)&&g[0]?.id&&(d=g[0].id)}}catch(f){i(`[backlog-sync] milestone lookup failed: ${f.message}`)}let p={};if(e.title!==void 0&&(p.title=e.title),e.description!==void 0&&(p.description=e.description),e.labels!==void 0&&(p.labels=e.labels.join(",")),e.addLabels?.length&&(p.add_labels=e.addLabels.join(",")),e.removeLabels?.length&&(p.remove_labels=e.removeLabels.join(",")),u!==void 0&&(p.assignee_ids=u),d!==void 0&&(p.milestone_id=d),e.state&&(p.state_event=e.state==="closed"?"close":"reopen"),Object.keys(p).length)try{let f=await c(`/projects/${l}/issues/${t.iid}`,{method:"PUT",body:JSON.stringify(p)});if(a.push({kind:"PUT issue",ok:f.ok,status:f.status}),!f.ok){let g=await f.text().catch(()=>"");return{ok:!1,attempts:a,error:`PUT issue ${f.status}: ${g.slice(0,200)}`,url:t.url}}}catch(f){return a.push({kind:"PUT issue",ok:!1,error:f.message}),{ok:!1,attempts:a,error:f.message,url:t.url}}if(e.note)try{let f=await c(`/projects/${l}/issues/${t.iid}/notes`,{method:"POST",body:JSON.stringify({body:e.note})});a.push({kind:"POST note",ok:f.ok,status:f.status})}catch(f){a.push({kind:"POST note",ok:!1,error:f.message})}return{ok:a.every(f=>f.ok),attempts:a,url:t.url}}async function Oo(t,e,n,i){let o=n.channels.github?.token;if(!o)return{ok:!1,error:"github token not configured",attempts:[]};let s=[],a=async(p,f={})=>fetch(`https://api.github.com${p}`,{...f,headers:{Authorization:`Bearer ${o}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28",...f.headers||{}}}),c=t.project,l;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")l=null;else try{let p=await a(`/repos/${c}/milestones?state=all&per_page=100`);if(p.ok){let f=await p.json(),g=Array.isArray(f)?f.find(h=>h.title===e.milestoneTitle):null;g?.number&&(l=g.number)}}catch(p){i(`[backlog-sync] github milestone lookup failed: ${p.message}`)}let u;if(e.labels!==void 0)u=e.labels;else if(e.addLabels?.length||e.removeLabels?.length)try{let p=await a(`/repos/${c}/issues/${t.iid}`);if(p.ok){let f=await p.json(),g=Array.isArray(f.labels)?f.labels.map(y=>typeof y=="string"?y:y.name):[],h=new Set([...g,...e.addLabels??[]]);for(let y of e.removeLabels??[])h.delete(y);u=[...h]}}catch(p){i(`[backlog-sync] github label fetch failed: ${p.message}`)}let d={};if(e.title!==void 0&&(d.title=e.title),e.description!==void 0&&(d.body=e.description),u!==void 0&&(d.labels=u),e.assigneeUsernames!==void 0&&(d.assignees=e.assigneeUsernames),l!==void 0&&(d.milestone=l),e.state&&(d.state=e.state),Object.keys(d).length)try{let p=await a(`/repos/${c}/issues/${t.iid}`,{method:"PATCH",body:JSON.stringify(d)});if(s.push({kind:"PATCH issue",ok:p.ok,status:p.status}),!p.ok){let f=await p.text().catch(()=>"");return{ok:!1,attempts:s,error:`PATCH issue ${p.status}: ${f.slice(0,200)}`,url:t.url}}}catch(p){return s.push({kind:"PATCH issue",ok:!1,error:p.message}),{ok:!1,attempts:s,error:p.message,url:t.url}}if(e.note)try{let p=await a(`/repos/${c}/issues/${t.iid}/comments`,{method:"POST",body:JSON.stringify({body:e.note})});s.push({kind:"POST comment",ok:p.ok,status:p.status})}catch(p){s.push({kind:"POST comment",ok:!1,error:p.message})}return{ok:s.every(p=>p.ok),attempts:s,url:t.url}}var Ke=/^(\s*)-\s*\[( |x|X)\]\s*(.*)$/,fe=/@([a-z0-9_-]+)/i,Zn=/\[time:\s*([0-9hm\s]+)\]/i;function Wo(t){let e=t.match(/(\d+)\s*h/i),n=t.match(/(\d+)\s*m/i);return(e?parseInt(e[1],10)*3600:0)+(n?parseInt(n[1],10)*60:0)}var Ge=class{constructor(e,n,i=()=>{}){this.path=e;this.daemon=n;this.log=i;this.store=new pe(this.path)}type="backlog";capabilities={listAll:!0,create:!1,transition:!1,labels:!0,search:!1};store;getStore(){return this.store}readMd(){let e=qe(process.cwd(),this.path);return ze(e)?He(e,"utf-8").split(`
126
- `):[]}writeMd(e){let n=qe(process.cwd(),this.path);Qn(n,e.join(`
127
- `))}async listOpen(e){if(this.store.exists())return this.store.list().filter(o=>o.status!=="done"&&(!o.assignee||o.assignee.toLowerCase()===e.toLowerCase())).map(o=>this.toWorkItem(o));let n=this.readMd(),i=[];for(let r=0;r<n.length;r++){let o=n[r].match(Ke);if(!o||o[2].toLowerCase()==="x")continue;let a=o[3],c=a.match(fe);if(c&&c[1].toLowerCase()!==e.toLowerCase())continue;let l=a.match(Zn),u=a.replace(fe,"").replace(Zn,"").trim();i.push({id:`backlog:${r}`,title:u||`Task at line ${r+1}`,assignee:c?c[1]:void 0,estimatedSeconds:l?Wo(l[1]):void 0,priority:r})}return i}async listAll(e={}){return this.store.exists()?this.store.list().map(n=>this.toWorkItem(n)):[]}async claim(e,n){if(!this.store.exists())return;let i=this.store.findById(n);if(!i)return;let r=this.store.update(n,{assignee:i.assignee||e,status:"doing"});if(r.source&&this.daemon){let o=Yn([r.assignee||e],r.source,this.daemon);Be(r,{assigneeUsernames:o,addLabels:["Doing"],removeLabels:["To Do"]},this.daemon,this.log).catch(s=>this.log(`[backlog-sync] claim failed for ${n}: ${s?.message??s}`))}}async report(e,n){if(this.store.exists()&&this.store.findById(e)){let a={};n.status==="done"?a.status="done":n.status==="blocked"?(a.status="blocked",a.blocker=n.blocker||n.note||void 0):n.status==="in-progress"&&(a.status="doing"),n.timeSeconds&&(a.estimatedSeconds=n.timeSeconds);let c=this.store.update(e,a);if(c.source&&this.daemon){let l={};n.status==="done"?(l.addLabels=["Done"],l.removeLabels=["Doing"]):n.status==="blocked"&&(l.addLabels=["Blocked"]),n.note&&(l.note=n.note),Object.keys(l).length&&Be(c,l,this.daemon,this.log).catch(u=>this.log(`[backlog-sync] report failed for ${e}: ${u?.message??u}`))}return}if(!e.startsWith("backlog:"))throw new Error(`not a backlog id: ${e}`);let i=parseInt(e.slice(8),10),r=this.readMd(),o=r[i];if(!o)throw new Error(`backlog line ${i} missing`);if(!o.match(Ke))throw new Error(`backlog line ${i} not a checkbox`);if(n.status==="done"){r[i]=o.replace(/- \[ \]/,"- [x]");let a=n.timeSeconds?` <!-- done by agent, ${Math.round(n.timeSeconds/60)}m -->`:" <!-- done by agent -->";r.splice(i+1,0,a)}else n.status==="blocked"?r.splice(i+1,0,` <!-- BLOCKED: ${n.blocker||n.note||"?"} -->`):n.note&&r.splice(i+1,0,` <!-- ${n.note.replace(/-->/g,"\u2014 >")} -->`);this.writeMd(r)}toWorkItem(e){let n={todo:"todo",doing:"doing",blocked:"onhold",done:"done"}[e.status];return{id:e.id,title:e.title,description:e.description,assignee:e.assignee,estimatedSeconds:e.estimatedSeconds,priority:e.priority,labels:e.labels,stage:n,milestone:e.milestone,url:e.source?.url,updatedAt:e.updatedAt,state:e.status==="done"?"closed":"opened"}}},Xe=class{constructor(e,n){this.root=e;this.glob=n}type="wiki";capabilities={listAll:!1,create:!1,transition:!1,labels:!1,search:!1};walk(e,n){if(ze(e))for(let i of No(e)){let r=Vo(e,i);jo(r).isDirectory()?this.walk(r,n):i.endsWith(".md")&&n.push(r)}}async listOpen(e){let n=[];this.walk(qe(process.cwd(),this.root),n);let i=[];for(let r of n){let o=He(r,"utf-8").split(`
128
- `);for(let s=0;s<o.length;s++){let a=o[s].match(Ke);if(!a||a[2].toLowerCase()==="x")continue;let c=a[3].match(fe);!c||c[1].toLowerCase()!==e.toLowerCase()||i.push({id:`wiki:${r}:${s}`,title:a[3].replace(fe,"").trim(),assignee:c[1],priority:s})}}return i}async claim(){}async report(e,n){let i=e.split(":"),r=parseInt(i[i.length-1],10),o=i.slice(1,-1).join(":");if(!ze(o))return;let s=He(o,"utf-8").split(`
129
- `);n.status==="done"&&s[r]&&(s[r]=s[r].replace(/- \[ \]/,"- [x]"),Qn(o,s.join(`
130
- `)))}},Je=class{constructor(e,n,i,r,o){this.host=e;this.token=n;this.projects=i;this.agentUsernames=r;this.log=o}type="gitlab";capabilities={listAll:!0,create:!0,transition:!0,labels:!0,search:!0};usernameToAgent(e){for(let[n,i]of Object.entries(this.agentUsernames))if(i.some(r=>r.toLowerCase()===e.toLowerCase()))return n}mapIssue(e,n){let i=e.references?.full?.split("#")[0]||n,r=[],o;Array.isArray(e.labels)&&(e.labels.length&&typeof e.labels[0]=="object"?(o=e.labels.map(l=>({name:l.name,color:l.color,text_color:l.text_color})),r=o.map(l=>l.name)):r=e.labels);let a=(Array.isArray(e.assignees)&&e.assignees.length?e.assignees:e.assignee?[e.assignee]:[]).map(l=>({username:l.username,name:l.name,avatarUrl:l.avatar_url})),c=a[0]?.username;return{id:`gitlab:${i}:issue:${e.iid}`,title:e.title,description:e.description||void 0,assignee:c?this.usernameToAgent(c)||c:void 0,assignees:a,url:e.web_url,priority:e.weight??99,estimatedSeconds:e.time_stats?.time_estimate||void 0,labels:r,labelDetails:o,updatedAt:e.updated_at,state:e.state==="closed"?"closed":"opened",milestone:e.milestone?.title||void 0}}async api(e,n={}){let i=await fetch(`${this.host}/api/v4${e}`,{...n,headers:{"PRIVATE-TOKEN":this.token,"Content-Type":"application/json",...n.headers||{}}});if(!i.ok)throw new Error(`GitLab ${i.status}: ${await i.text().catch(()=>"")}`);return i.json()}async listOpen(e){let n=this.agentUsernames[e]||[];if(!n.length)return[];let i=[],r=this.projects.length?this.projects:["__ALL__"];for(let o of n)for(let s of r)try{let a=`assignee_username=${encodeURIComponent(o)}&state=opened&scope=all&per_page=20`,c=s==="__ALL__"?`/issues?${a}`:`/projects/${encodeURIComponent(s)}/issues?${a}`,l=await this.api(c);for(let u of l){let d=this.mapIssue(u,s);d.assignee=e,i.push(d)}}catch(a){this.log(`[business] GitLab listOpen failed for ${o} on ${s}: ${a.message}`)}return i}async claim(e,n){let{project:i,iid:r,type:o}=this.parseId(n),s=`/projects/${encodeURIComponent(i)}/${o==="issue"?"issues":"merge_requests"}/${r}?add_labels=Doing&remove_labels=To Do`;try{await this.api(s,{method:"PUT"})}catch(a){this.log(`[business] claim label update failed: ${a.message}`)}}async report(e,n){let{project:i,iid:r,type:o}=this.parseId(e),s=o==="issue"?"issues":"merge_requests";if(n.timeSeconds&&n.timeSeconds>0){let a=Math.max(1,Math.round(n.timeSeconds/60)),c=a>=60?`${Math.floor(a/60)}h${a%60?` ${a%60}m`:""}`:`${a}m`;try{await this.api(`/projects/${encodeURIComponent(i)}/${s}/${r}/add_spent_time?duration=${encodeURIComponent(c)}`,{method:"POST"})}catch(l){this.log(`[business] add_spent_time failed: ${l.message}`)}}if(n.status==="done")try{await this.api(`/projects/${encodeURIComponent(i)}/${s}/${r}?add_labels=Done&remove_labels=Doing`,{method:"PUT"})}catch(a){this.log(`[business] done label update failed: ${a.message}`)}else if(n.status==="blocked")try{await this.api(`/projects/${encodeURIComponent(i)}/${s}/${r}?add_labels=Blocked`,{method:"PUT"})}catch(a){this.log(`[business] blocked label update failed: ${a.message}`)}if(n.note)try{await this.api(`/projects/${encodeURIComponent(i)}/${s}/${r}/notes`,{method:"POST",body:JSON.stringify({body:n.note})})}catch(a){this.log(`[business] report note failed: ${a.message}`)}}async listAll(e={}){let n=e.sinceDays??30,i=new Date(Date.now()-n*24*36e5).toISOString(),r=new URLSearchParams,o=e.state??"opened";r.set("state",o),r.set("updated_after",i),r.set("scope","all"),r.set("per_page","100"),r.set("with_labels_details","true"),r.set("order_by","updated_at"),r.set("sort","desc"),e.labels?.length&&r.set("labels",e.labels.join(",")),e.milestone&&r.set("milestone",e.milestone),e.search&&r.set("search",e.search);let s=this.projects.length?this.projects:["__ALL__"],a=[];for(let l of s)try{let u=l==="__ALL__"?`/issues?${r.toString()}`:`/projects/${encodeURIComponent(l)}/issues?${r.toString()}`,d=await this.api(u);for(let p of d)a.push(this.mapIssue(p,l))}catch(u){this.log(`[business] GitLab listAll failed on ${l}: ${u.message}`)}let c=a;if(e.notLabels?.length){let l=new Set(e.notLabels);c=c.filter(u=>!(u.labels||[]).some(d=>l.has(d)))}if(e.withoutScopedPrefix){let l=e.withoutScopedPrefix+"::";c=c.filter(u=>!(u.labels||[]).some(d=>d.startsWith(l)))}return c}async setState(e,n){let{project:i,iid:r,type:o}=this.parseId(e),s=o==="issue"?"issues":"merge_requests";await this.api(`/projects/${encodeURIComponent(i)}/${s}/${r}?state_event=${n}`,{method:"PUT"})}async getItem(e){let{project:n,iid:i}=this.parseId(e);try{let r=await this.api(`/projects/${encodeURIComponent(n)}/issues/${i}?with_labels_details=true`);return{...this.mapIssue(r,n),descriptionHtml:r.description_html||void 0,createdAt:r.created_at,author:r.author?{username:r.author.username,name:r.author.name,avatarUrl:r.author.avatar_url}:void 0,allLabels:Array.isArray(r.labels)?typeof r.labels[0]=="object"?r.labels.map(s=>s.name):r.labels:[]}}catch(r){return this.log(`[board] GitLab getItem failed for ${e}: ${r.message}`),null}}async updateItem(e,n){let{project:i,iid:r}=this.parseId(e),o;n.assigneeUsernames&&(o=(await Promise.all(n.assigneeUsernames.map(async u=>{try{let d=await this.api(`/users?username=${encodeURIComponent(u)}`);return Array.isArray(d)&&d[0]?.id?d[0].id:null}catch{return null}}))).filter(u=>typeof u=="number"));let s;if(n.milestoneTitle!==void 0)if(n.milestoneTitle===null||n.milestoneTitle==="")s=0;else try{let l=await this.api(`/projects/${encodeURIComponent(i)}/milestones?title=${encodeURIComponent(n.milestoneTitle)}`);Array.isArray(l)&&l[0]?.id&&(s=l[0].id)}catch(l){this.log(`[board] milestone lookup failed for "${n.milestoneTitle}": ${l.message}`)}let a={};n.title!==void 0&&(a.title=n.title),n.description!==void 0&&(a.description=n.description),n.labels!==void 0&&(a.labels=n.labels.join(",")),n.addLabels?.length&&(a.add_labels=n.addLabels.join(",")),n.removeLabels?.length&&(a.remove_labels=n.removeLabels.join(",")),o!==void 0&&(a.assignee_ids=o),s!==void 0&&(a.milestone_id=s);let c=await this.api(`/projects/${encodeURIComponent(i)}/issues/${r}`,{method:"PUT",body:JSON.stringify(a)});return this.mapIssue(c,i)}async listMembers(){let e=new Map;for(let n of this.projects)try{let i=await this.api(`/projects/${encodeURIComponent(n)}/members/all?per_page=100`);for(let r of i)r.username&&!e.has(r.username)&&e.set(r.username,{username:r.username,name:r.name,avatarUrl:r.avatar_url})}catch(i){this.log(`[board] listMembers failed for ${n}: ${i.message}`)}return[...e.values()].sort((n,i)=>n.username.localeCompare(i.username))}async listMilestones(){let e=new Map;for(let i of this.projects)try{let r=await this.api(`/projects/${encodeURIComponent(i)}/milestones?per_page=100`);for(let o of r)o.title&&!e.has(o.title)&&e.set(o.title,{id:o.id,title:o.title,state:o.state,dueDate:o.due_date})}catch(r){this.log(`[board] listMilestones failed for ${i}: ${r.message}`)}let n=[...e.values()];return n.sort((i,r)=>i.state!==r.state?i.state==="active"?-1:1:i.title.localeCompare(r.title)),n}async create(e){let n=e.projectHint||this.projects[0];if(!n)throw new Error("GitLabWorkSource.create requires projectHint or configured projects");let i,r=e.assigneeUsernames?.length?e.assigneeUsernames:e.assignee?(this.agentUsernames[e.assignee]||[]).slice(0,1):[];r.length&&(i=(await Promise.all(r.map(async l=>{try{let u=await this.api(`/users?username=${encodeURIComponent(l)}`);return Array.isArray(u)&&u[0]?.id?u[0].id:null}catch(u){return this.log(`[board] user lookup failed for ${l}: ${u.message}`),null}}))).filter(l=>typeof l=="number"));let o;if(e.milestoneTitle)try{let c=await this.api(`/projects/${encodeURIComponent(n)}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);Array.isArray(c)&&c[0]?.id&&(o=c[0].id)}catch(c){this.log(`[board] milestone lookup failed for "${e.milestoneTitle}": ${c.message}`)}let s={title:e.title,description:e.description,labels:(e.labels||[]).join(",")};i?.length&&(s.assignee_ids=i),o!==void 0&&(s.milestone_id=o);let a=await this.api(`/projects/${encodeURIComponent(n)}/issues`,{method:"POST",body:JSON.stringify(s)});return this.mapIssue(a,n)}async transition(e,n,i){await this.transitionMany(e,n?[n]:[],i?[i]:[])}async transitionMany(e,n,i){let{project:r,iid:o,type:s}=this.parseId(e),a=s==="issue"?"issues":"merge_requests",c=new URLSearchParams;n.length&&c.set("add_labels",n.join(",")),i.length&&c.set("remove_labels",i.join(",")),c.toString()&&await this.api(`/projects/${encodeURIComponent(r)}/${a}/${o}?${c.toString()}`,{method:"PUT"})}parseId(e){let i=e.replace(/^gitlab:/,"").split(":"),r=i.pop(),o=i.pop()==="mr"?"mr":"issue";return{project:i.join(":"),type:o,iid:r}}};function Zc(t,e,n){let i=t.workSource;switch(i.type){case"backlog":return new Ge(i.path,e,n);case"wiki":return new Xe(i.path,i.glob);case"gitlab":{let r=e.channels.gitlab;if(!r?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let o={};for(let a of r.agentMappings)a.gitlabUsernames.length&&(o[a.agentId]=a.gitlabUsernames);let s=i.projects.length?i.projects:r.routes.map(a=>a.project);return new Je(r.host,r.token,s,o,n)}}}var Ye="unmapped";function Ze(t,e=[]){if(!t)return Ye;let n=e.find(r=>r.id===t);if(n?.client)return n.client;let i=t.indexOf("/");return i>0?t.slice(0,i):t}function Fo(t){let e=new Map,n=t.projects??[],i=t.orgChart??{};for(let o of n)o.pm&&(e.has(o.pm)||e.set(o.pm,Ze(o.id,n)));let r=(o,s=new Set)=>{if(e.has(o))return e.get(o);if(s.has(o))return;s.add(o);let a=i[o]?.reportsTo;if(!a)return;let c=r(a,s);return c&&e.set(o,c),c};for(let o of Object.keys(i))r(o);return e}function Uo(t,e,n=[]){if(!n.length)return;let i=n.filter(r=>!r.channel||r.channel===t);return i.find(r=>r.chatId&&e.chatId&&r.chatId===e.chatId)??i.find(r=>r.username&&e.username&&r.username===e.username)??i.find(r=>r.senderId&&e.senderId&&r.senderId===e.senderId)??i.find(r=>r.channel&&!r.chatId&&!r.username&&!r.senderId)}function el(t,e){let n=Uo(t.channel,{chatId:t.chatId,username:t.username},e.contactMap);if(n)return n.client;if(t.project)return Ze(t.project,e.projects);if(t.agentId){let i=Fo(e).get(t.agentId);if(i)return i}return Ye}function tl(t,e){let n=String(t||"").split(":");if(n.length<3)return{agentId:e};let[i,r,...o]=n,s=o.join(":"),a={agentId:e||i,channel:r};return r==="gitlab"||r==="github"?a.project=s.split(":")[0]:r==="cron"||r==="api"||(a.chatId=s.split("@")[0]),a}var Bo=t=>t===Ye?"internal":"client";function Ho(t,e){let n=e.clients?.[t];return{id:t,name:n?.name||t,kind:n?.kind??Bo(t),respondWithinMinutes:zo(n?.respondWithin),standing:n?.standing??[],declared:!!n}}function nl(t){let e=new Set;for(let n of t.projects??[])e.add(Ze(n.id,t.projects));for(let n of t.contactMap??[])e.add(n.client);for(let n of Object.keys(t.clients??{}))e.add(n);return[...e].sort().map(n=>Ho(n,t))}function zo(t){let e=/^(\d+)\s*([mhd])$/.exec(String(t??"").trim());if(!e)return;let n=Number(e[1]);return e[2]==="m"?n:e[2]==="h"?n*60:n*1440}var qo=/(^|\n)[ \t]*```[ \t]*agentx:ui[ \t]*\r?\n/i,Ko=/(^|\n)[ \t]*```[ \t]*agentx:ui[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```[ \t]*(?=\n|$)/gi;function er(t){if(!t||!t.includes("agentx:ui"))return{cleanText:t};let e=[...t.matchAll(Ko)];if(e.length===0)return{cleanText:t};let n=e[e.length-1],i=n[2],r=Go(i);if(!r)return{cleanText:t};let o=n.index??0,s=n[1]??"";return{cleanText:(t.slice(0,o)+s+t.slice(o+n[0].length)).trim(),ui:r}}function il(t){if(!t||!t.includes("agentx:ui"))return t;let e=qo.exec(t);return e?t.slice(0,e.index).trimEnd():t}function Go(t){let e;try{e=JSON.parse(t)}catch{return null}if(!e||typeof e!="object")return null;let n={};if(Array.isArray(e.buttons)){let i=[],r=[],o=[];for(let s of e.buttons)!s||typeof s.label!="string"||(typeof s.url=="string"&&/^https?:\/\//i.test(s.url)?i.push({label:s.label,url:s.url}):typeof s.reply=="string"&&s.reply.trim()?r.push({label:s.label,reply:s.reply.trim()}):s.action!=null&&o.push(s.label));i.length&&(n.buttons=i),r.length&&(n.replies=r),o.length&&(n.skippedActions=o)}if(e.poll&&typeof e.poll=="object"){let i=e.poll.question,r=e.poll.options;typeof i=="string"&&i.trim()&&Array.isArray(r)&&r.filter(o=>typeof o=="string").length>=2&&(n.poll={question:i,options:r.filter(o=>typeof o=="string"),multiple:e.poll.multiple===!0})}if(e.media&&typeof e.media=="object"){let{type:i,url:r,caption:o}=e.media;["image","document","audio","video"].includes(i)&&typeof r=="string"&&r&&(n.media={type:i,url:r,...typeof o=="string"?{caption:o}:{}})}if(Array.isArray(e.quickReplies)){let i=e.quickReplies.filter(r=>typeof r=="string"&&r.trim()).map(r=>r.trim());i.length&&(n.quickReplies=i)}return!n.buttons&&!n.poll&&!n.media&&!n.quickReplies&&!n.replies&&!n.skippedActions?null:n}function sl(t,e){let n=`${e}/call?to=${encodeURIComponent(t.from)}&callId=${encodeURIComponent(t.callId)}`;return t.reason==="camera"?`\u{1F4F7} ${t.from} is sharing a phone camera \u2014 tap to watch: ${n}&watch=1`:`\u{1F4DE} ${t.from} is calling \u2014 tap to join: ${n}`}var Xo=5*6e4;function T(t){return t.toLowerCase().replace(/[^a-z0-9]/g,"")}var tr=class{subs=new Set;log;forwarder;localName;allowedCallers;pending=new Map;cleanupTimer;ringHandler;recentRings=new Map;constructor(e,n=[],i=console.error.bind(console,"[webrtc]")){this.localName=e,this.allowedCallers=new Set(n.map(T)),this.log=i,this.cleanupTimer=setInterval(()=>this.cleanupExpired(),1e4)}pendingKey(e,n){return`${e}|${T(n)}`}cleanupExpired(){let e=Date.now();for(let[n,i]of this.pending){let r=i.filter(o=>o.expiresAt>e);r.length===0?this.pending.delete(n):r.length!==i.length&&this.pending.set(n,r)}for(let[n,i]of this.recentRings)i<=e&&this.recentRings.delete(n)}setForwarder(e){this.forwarder=e}setRingHandler(e){this.ringHandler=e}subscribe(e,n,i){return this.addSubscriber(e,n,{kind:"sse",res:i})}subscribeInternal(e,n,i){return this.addSubscriber(e,n,{kind:"callback",deliver:i})}addSubscriber(e,n,i){let r={callId:e,recipient:n,sink:i};this.subs.add(r);let o=i.kind==="sse"?"sse":"internal";this.log(`subscribe[${o}] call=${e} as=${n} (${this.subs.size} total)`);let s=this.pendingKey(e,n),a=this.pending.get(s);if(a&&a.length){let c=Date.now(),l=a.filter(u=>u.expiresAt>c);for(let{signal:u}of l)this.deliverTo(r,u);this.pending.delete(s),l.length&&this.log(`flushed ${l.length} buffered signal(s) to new subscriber call=${e} as=${n}`)}return()=>{this.subs.delete(r),this.log(`unsubscribe[${o}] call=${e} as=${n} (${this.subs.size} remaining)`)}}deliverTo(e,n){try{return e.sink.kind==="sse"?e.sink.res.write(`event: signal
131
- data: ${JSON.stringify(n)}
132
-
133
- `):e.sink.deliver(n),!0}catch{return!1}}async handleOutgoing(e){let n=T(e.to);if(n===T(this.localName)||this.hasSubscriberFor(e.callId,n))return this.fanOut(e),{ok:!0};if(!this.forwarder)return{ok:!1,error:"mesh forwarder not wired"};let r=await this.forwarder(e.to,e);return r?{ok:r}:{ok:!1,error:`forward to "${e.to}" failed`}}hasSubscriberFor(e,n){for(let i of this.subs)if(i.callId===e&&T(i.recipient)===n)return!0;return!1}handleIncoming(e){if((e.kind==="offer"||e.kind==="ring")&&this.allowedCallers.size>0&&!this.allowedCallers.has(T(e.from)))return this.log(`reject inbound ${e.kind} from "${e.from}": not in allowedCallers`),{ok:!1,error:"caller not allowed"};if(e.kind==="ring"){let i=Date.now(),r=this.recentRings.get(e.callId);if(r&&r>i)return this.log(`dedup ring for call=${e.callId} (already notified)`),{ok:!0};if(this.recentRings.set(e.callId,i+Xo),this.ringHandler)try{this.ringHandler(e)}catch(o){this.log(`ringHandler threw: ${o.message}`)}else this.log(`ring received for call=${e.callId} but no handler wired`);return{ok:!0}}if(this.fanOut(e)===0){let i=this.pendingKey(e.callId,e.to),r=this.pending.get(i)||[];r.push({signal:e,expiresAt:Date.now()+3e4}),this.pending.set(i,r),this.log(`buffered ${e.kind} for call=${e.callId} to=${e.to} (no subscriber yet, ${r.length} pending)`)}return{ok:!0}}fanOut(e){let n=0,i=T(e.to);for(let r of this.subs)r.callId===e.callId&&T(r.recipient)===i&&(this.deliverTo(r,e)?n++:this.subs.delete(r));return n}get subscriberCount(){return this.subs.size}shutdown(){this.cleanupTimer&&clearInterval(this.cleanupTimer);for(let e of this.subs)if(e.sink.kind==="sse")try{e.sink.res.end()}catch{}this.subs.clear(),this.pending.clear()}};var Jo={perClient:5,global:10,windowMs:10*60*1e3,lockoutMs:5*60*1e3},nr=class{constructor(e=Jo,n=Date.now){this.opts=e;this.now=n}clients=new Map;all={failures:[],lockedUntil:0};retryAfter(e){let n=this.now(),i=Math.max(this.all.lockedUntil,this.clients.get(e)?.lockedUntil??0);return i>n?Math.ceil((i-n)/1e3):0}fail(e){let n=this.clients.get(e);n||this.clients.set(e,n={failures:[],lockedUntil:0}),this.bump(n,this.opts.perClient),this.bump(this.all,this.opts.global)}succeed(e){this.clients.delete(e)}bump(e,n){let i=this.now();e.failures=e.failures.filter(r=>i-r<this.opts.windowMs),e.failures.push(i),e.failures.length>=n&&(e.lockedUntil=i+this.opts.lockoutMs)}},Yo="That code didn't work. Check it, or run agentx app pair for a new one.",Zo=400;async function ll(t,e){let n=Date.now(),i=e.log??(l=>console.log(l)),r=t.socket.remoteAddress||"unknown",o=e.limiter.retryAfter(r);if(o>0)return i(`[app] pair-code refused from ${r}: locked out for ${o}s more`),{status:429,body:{error:"too many attempts",retryAfter:o},retryAfter:o};let s=null;try{s=(await qt(t,1024)).code}catch{}let a=e.codes.redeem(s),c=a?e.verify(a.token):null;return await Qo(n,e.minMs??Zo),!a||!c?(e.limiter.fail(r),i(`[app] pair-code failed from ${r}`),{status:401,body:{error:Yo}}):(e.limiter.succeed(r),i(`[app] pair-code paired ${a.tokenId} (${c}) from ${r}`),{status:200,body:{device:c},token:a.token})}async function Qo(t,e){let n=t+e-Date.now();n>0&&await new Promise(i=>setTimeout(i,n))}var es=200,rr=4e3;function ts(t){return t.replace(/```[\s\S]*?```/g," ").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^\s{0,3}(#{1,6}|>|[-*+]|\d+[.)])\s+/gm,"").replace(/[*_~`]+/g,"").replace(/\s+/g," ").trim()}function Qe(t,e=es){let n=ts(t);if(n.length<=e)return n;let i=n.slice(0,e),r=Math.max(i.lastIndexOf(". "),i.lastIndexOf("? "),i.lastIndexOf("! "));return r>e/2?i.slice(0,r+1):`${i.slice(0,e-1).trimEnd()}\u2026`}function pl(t,e){let n=e.lastAnswer(t.id),i=n&&n.text.length>rr?`${n.text.slice(0,rr)}
134
-
135
- \u2026`:n?.text;return{...t,summary:Qe(t.text),textHtml:te(t.text),why:t.state==="waiting_owner"?t.question:t.state==="needs_attention"?t.attentionReason:null,ownerNoteHtml:t.ownerNote?te(t.ownerNote):null,lastAnswer:n?{agentId:n.agentId,at:n.at,html:te(i)}:null}}import{execFile as ws}from"child_process";import{mkdtempSync as ps,rmSync as fs,writeFileSync as gs}from"fs";import{tmpdir as ms}from"os";import{join as cr}from"path";import{randomBytes as ns}from"crypto";var _={top:8,side:32,bottom:60},et={height:56,keep:52},ir=`
136
- :root {
137
- --ac-paper: #fafaf9; --ac-soft: #f4f4f2; --ac-edge: #e9e9e6;
138
- --ac-text: #0b1413; --ac-muted: #4a5856; --ac-subtle: #7c8987;
139
- --ac-primary: #1e3a8a; --ac-primary-deep: #172554;
140
- --ac-blue: #1e3a8a; --ac-blue-2: #1d4ed8;
141
- --ac-accent: #14b8a6; --ac-accent-deep: #0f766e;
142
- --ac-rim: rgba(11,20,19,.10);
143
- --ac-shadow: 0 0 0 .5px rgba(11,20,19,.05), 0 24px 48px -16px rgba(11,20,19,.30), 0 2px 6px rgba(11,20,19,.06);
144
- --ac-lift: 0 12px 40px rgba(30,58,138,.20), 0 2px 6px rgba(11,20,19,.06);
145
- --ac-font: "Geist", -apple-system, BlinkMacSystemFont, "Noto Sans Arabic", system-ui, sans-serif;
146
- --ac-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
147
- color-scheme: light;
148
- }
149
- [data-theme="dark"] {
150
- --ac-paper: #111c1b; --ac-soft: #172322; --ac-edge: #263433;
151
- --ac-text: #e8eeed; --ac-muted: #a7b3b1; --ac-subtle: #83918f;
152
- --ac-primary: #2563eb; --ac-primary-deep: #1d4ed8;
153
- --ac-blue: #93c5fd; --ac-blue-2: #60a5fa;
154
- --ac-accent-deep: #5eead4;
155
- --ac-rim: rgba(255,255,255,.09);
156
- --ac-shadow: 0 0 0 .5px rgba(0,0,0,.6), 0 28px 56px -16px rgba(0,0,0,.65), 0 2px 8px rgba(0,0,0,.3);
157
- color-scheme: dark;
158
- }
159
- * { box-sizing: border-box; }
160
- html, body { margin: 0; background: transparent; }
161
- body {
162
- font: 13.5px/1.5 var(--ac-font); color: var(--ac-text); font-feature-settings: "ss01", "cv11";
163
- -webkit-font-smoothing: antialiased; -webkit-user-select: none; user-select: none; cursor: default;
164
- }
165
- .wrap { padding: ${_.top}px ${_.side}px ${_.bottom}px; }
166
- .card {
167
- background: var(--ac-paper); border: 1px solid var(--ac-rim); border-radius: 18px;
168
- box-shadow: var(--ac-shadow); overflow: hidden; animation: ac-in .26s cubic-bezier(.65,0,.35,1);
169
- position: relative; display: flex; flex-direction: column; max-height: calc(100vh - ${_.top+_.bottom}px);
170
- }
171
- .card::before {
172
- content: ""; position: absolute; top: 6px; left: 50%; width: 32px; height: 4px; margin-left: -16px;
173
- border-radius: 2px; background: var(--ac-edge);
174
- }
175
- @keyframes ac-in { from { transform: translateY(14px); opacity: 0; } }
176
- .card.still { animation: none; }
177
- @media (prefers-reduced-motion: reduce) { .card { animation: none; } }
178
- .head { flex: none; display: flex; align-items: center; gap: 10px; padding: 18px 20px 0; cursor: grab; }
179
- .body { padding: 14px 20px 16px; min-height: 0; overflow-y: auto; }
180
- .fold {
181
- flex: none; width: 24px; height: 24px; display: grid; place-items: center; padding: 0; border-radius: 6px;
182
- border: 1px solid var(--ac-edge); background: var(--ac-soft); color: var(--ac-subtle); cursor: pointer;
183
- }
184
- .fold:hover { color: var(--ac-text); border-color: var(--ac-subtle); }
185
- .folded .fold svg { transform: rotate(180deg); }
186
- .folded .body > :not(h1), .folded .foot { display: none; }
187
- .avatar {
188
- flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
189
- font-size: 14px; font-weight: 600; color: #fff;
190
- background: linear-gradient(135deg, var(--ac-blue-2), var(--ac-accent));
191
- }
192
- .who { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
193
- .who b { font-size: 13.5px; font-weight: 560; letter-spacing: -.008em; line-height: 1.25; }
194
- .who span { font-size: 12px; line-height: 1.3; color: var(--ac-subtle); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
195
- .label, .kind, .edited { font-family: var(--ac-mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
196
- .kind {
197
- padding: 3px 8px; border-radius: 999px; white-space: nowrap;
198
- color: var(--ac-muted); background: var(--ac-soft); border: 1px solid var(--ac-edge);
199
- }
200
- .kind.decision {
201
- color: var(--ac-blue); background: color-mix(in oklab, var(--ac-blue-2) 10%, var(--ac-paper));
202
- border-color: color-mix(in oklab, var(--ac-blue-2) 22%, var(--ac-edge));
203
- }
204
- h1 { margin: 0; font-size: 18.5px; line-height: 1.3; font-weight: 540; letter-spacing: -.018em; text-wrap: balance; }
205
- h1:dir(rtl) { letter-spacing: 0; }
206
- .context { margin: 6px 0 0; color: var(--ac-muted); white-space: pre-wrap; unicode-bidi: plaintext; text-wrap: pretty; }
207
- .ask { margin: 10px 0 0; font-weight: 500; unicode-bidi: plaintext; }
208
- .label-row { margin-top: 16px; display: flex; align-items: center; gap: 8px; min-height: 18px; }
209
- .label { color: var(--ac-subtle); margin-inline-end: auto; }
210
- .dot { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--ac-accent); }
211
- .rec { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ac-subtle); }
212
- .why { margin: 8px 0 0; font-size: 12px; line-height: 1.4; color: var(--ac-subtle); unicode-bidi: plaintext; }
213
- .options { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
214
- .opt {
215
- display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px 5px 5px; padding-inline: 5px 12px;
216
- border-radius: 999px; border: 1px solid var(--ac-edge); background: var(--ac-paper); color: var(--ac-text);
217
- font: inherit; font-size: 13px; line-height: 1.35; text-align: start; cursor: pointer;
218
- transition: background .15s ease, border-color .15s ease, transform .15s ease;
219
- }
220
- .opt:hover { transform: translateY(-1px); }
221
- .opt .n {
222
- flex: none; width: 20px; height: 20px; display: grid; place-items: center; border-radius: 6px;
223
- border: 1px solid var(--ac-edge); border-bottom-width: 2px; background: var(--ac-soft); color: var(--ac-subtle);
224
- font-family: var(--ac-mono); font-size: 10.5px;
225
- }
226
- .opt .t { unicode-bidi: plaintext; }
227
- .opt[aria-checked="true"] { background: var(--ac-primary); border-color: var(--ac-primary); color: #fff; }
228
- .opt[aria-checked="true"] .n { background: rgba(255,255,255,.16); border-color: rgba(255,255,255,.28); color: #fff; }
229
- .opt[aria-checked="true"] .dot { background: #5eead4; }
230
- .edited { display: none; align-items: center; gap: 5px; color: var(--ac-accent-deep); }
231
- .edited .dot { width: 5px; height: 5px; }
232
- .reset { display: none; border: 0; background: none; padding: 0; font: inherit; font-size: 12px; color: var(--ac-muted); cursor: pointer; }
233
- .reset:hover { color: var(--ac-text); }
234
- .touched .edited { display: inline-flex; }
235
- .touched .reset { display: inline; }
236
- textarea {
237
- margin-top: 6px; display: block; width: 100%; min-height: 60px; max-height: 240px; resize: none; overflow-y: auto;
238
- padding: 10px 12px; border: 1px solid var(--ac-edge); border-radius: 10px; background: var(--ac-soft);
239
- color: var(--ac-text); font: inherit; line-height: 1.45; outline: none; unicode-bidi: plaintext;
240
- -webkit-user-select: text; user-select: text; cursor: text; transition: border-color .15s ease, box-shadow .15s ease;
241
- }
242
- textarea::placeholder { color: var(--ac-subtle); }
243
- textarea:focus {
244
- border-color: var(--ac-accent); background: var(--ac-paper);
245
- box-shadow: 0 0 0 4px color-mix(in oklab, var(--ac-accent) 18%, transparent);
246
- }
247
- .notes { margin-top: 14px; display: flex; flex-direction: column; gap: 5px; font-size: 12px; line-height: 1.4; color: var(--ac-subtle); }
248
- .notes div { display: flex; gap: 7px; align-items: flex-start; }
249
- .notes svg { flex: none; margin-top: 1.5px; }
250
- .foot { flex: none; display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--ac-edge); background: var(--ac-soft); }
251
- .foot .later { margin-inline-end: auto; }
252
- button.btn {
253
- display: inline-flex; align-items: center; gap: 8px; padding: 9px 14px; border-radius: 999px;
254
- font: inherit; font-weight: 500; letter-spacing: -.005em; white-space: nowrap; cursor: pointer;
255
- background: transparent; color: var(--ac-text); border: 1px solid var(--ac-edge);
256
- transition: transform .15s ease, background .15s ease, box-shadow .15s ease, border-color .15s ease;
257
- }
258
- button.btn:hover { background: var(--ac-soft); border-color: var(--ac-subtle); }
259
- button.primary, button.primary:hover { background: var(--ac-primary); border-color: transparent; color: #fff; }
260
- button.primary:hover:not(:disabled) { transform: translateY(-1px); background: var(--ac-primary-deep); box-shadow: var(--ac-lift); }
261
- button.primary:disabled { opacity: .55; cursor: not-allowed; }
262
- kbd { font: 11px var(--ac-mono); color: var(--ac-subtle); }
263
- button.primary kbd { color: inherit; opacity: .7; }
264
- `;var or=t=>t.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"}),sr=t=>`${t.getDate()} ${t.toLocaleDateString("en-US",{month:"short"})}`;function rs(t,e){let n=new Date(t);return Number.isNaN(n.getTime())?"":`since ${n.toDateString()===new Date(e).toDateString()?or(n):sr(n)}`}function is(t,e){let n=new Date(t),i=n.getTime()-e<6*864e5;return[n.toLocaleDateString("en-US",{weekday:"short"}),...i?[]:[sr(n)],or(n)].join(" ")}function os(t){let e=t.trim().split(/[\s_-]+/).filter(Boolean);return(e.length>1?e[0][0]+e[1][0]:t.trim().slice(0,1)).toUpperCase()}function ss(t){let e=(t.recommend??"").trim(),n=e.toLowerCase(),i=t.choices??[],r=-1;if(i.forEach((s,a)=>{!n.startsWith(s.toLowerCase())||!/^\s*($|[:,.;–—-](\s|$))/.test(e.slice(s.length))||(r<0||s.length>i[r].length)&&(r=a)}),r<0)return{index:r,why:e};let o=e.slice(i[r].length).replace(/^[\s:,.;–—-]+/,"");return{index:r,why:o.slice(0,1).toUpperCase()+o.slice(1)}}function as(t){return t.origin?.kind==="request"?"Hand it back":t.draft?"Send":t.choices?.length?"Choose":"Yes"}var tt=t=>`<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${t}</svg>`,cs=tt('<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>'),ls=tt('<path d="m6 15 6-6 6 6"/>'),us=tt('<rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>');function ar(t,e={}){let n=e.now??Date.now(),i=e.from||t.raised_by,r=ns(12).toString("base64"),o=t.choices??[],s=t.origin?.kind==="reminder",a=t.origin?.kind==="request",c=ss(t),l=o.map((p,f)=>`<button class="opt" role="radio" aria-checked="false" data-i="${f}"><span class="n">${f+1}</span><span class="t">${w(p)}</span>${f===c.index?'<i class="dot"></i>':""}</button>`).join(""),u=t.recommend?`<span class="rec"><i class="dot"></i>${w(i)} recommends</span>`:"",d={choices:o,draft:t.draft??"",placeholder:Vt,chime:e.sound==="chime",volume:Math.min(1,Math.max(0,e.volume??.4)),theme:e.theme??"system",pick:e.pick&&e.pick<=o.length?e.pick-1:c.index};return`<!doctype html>
265
- <html lang="en"><head><meta charset="utf-8">
266
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'nonce-${r}'">
267
- <title>AgentX</title>
268
- <style>${ir}</style></head>
269
- <body><div class="wrap"><main class="card${e.still?" still":""}">
270
- <div class="head" title="Drag to move"><span class="avatar">${w(os(i))}</span>
271
- <div class="who"><b>${w(i)}</b><span>${w(rs(t.created_at,n))}</span></div>
272
- <span class="kind${s?"":" decision"}">${s?"Reminder":a?"Request":"Decision"}</span>
273
- <button class="fold" id="fold" title="Shrink" aria-label="Shrink the card" aria-expanded="true">${ls}</button></div>
274
- <div class="body"><h1 dir="auto">${w(t.title)}</h1>
275
- ${t.context?`<p class="context" dir="auto">${w(t.context)}</p>`:""}
276
- <p class="ask" dir="auto">${w(t.ask)}</p>
277
- ${l||u?`<div class="label-row">${l?'<span class="label">Pick one</span>':""}${u}</div>`:""}
278
- ${l?`<div class="options" role="radiogroup">${l}</div>`:""}
279
- ${c.why?`<p class="why" dir="auto">${w(c.why)}</p>`:""}
280
- ${t.draft?`<div class="label-row" id="msg"><span class="label">Message</span><span class="edited"><i class="dot"></i>Edited</span><button class="reset" id="reset">Reset</button></div>
281
- <textarea id="text" dir="auto" rows="2" spellcheck="true"></textarea>`:""}
282
- <div class="notes"><div>${cs}<span>${a?"It stays in Open requests on the Approvals page until you close it.":`If you don't answer by ${w(is(t.expires,n))}: ${w(t.if_silent)}.`}</span></div>
283
- <div>${us}<span>Nothing goes out until you click.</span></div></div>
284
- </div><div class="foot"><button class="btn later" id="later">Not now<kbd>esc</kbd></button>
285
- <button class="btn" id="no">${a?"Drop":"No"}</button>
286
- <button class="btn primary" id="yes">${as(t)}<kbd>\u2318\u21A9</kbd></button></div>
287
- </main></div>
288
- <script type="application/json" id="data">${JSON.stringify(d).replace(/</g,"\\u003c")}</script>
289
- <script nonce="${r}">${ds}</script>
290
- </body></html>`}var ds=`
291
- (function () {
292
- var d = JSON.parse(document.getElementById("data").textContent);
293
- var root = document.documentElement;
294
- var dark = d.theme === "dark" || (d.theme === "system" && matchMedia("(prefers-color-scheme: dark)").matches);
295
- if (dark) root.setAttribute("data-theme", "dark");
296
- var opts = [].slice.call(document.querySelectorAll(".opt"));
297
- var box = document.getElementById("text");
298
- var msg = document.getElementById("msg");
299
- var yes = document.getElementById("yes");
300
- var card = document.querySelector(".card");
301
- var body = document.querySelector(".body");
302
- var fold = document.getElementById("fold");
303
- var pick = -1, touched = false, done = false;
304
-
305
- function fill(i) { return d.draft.split(d.placeholder).join(i >= 0 ? d.choices[i] : "").trim(); }
306
- function send(a) { if (done) return; done = true; window.agentxAnswer = JSON.stringify(a); document.title = "agentx:answer"; }
307
- // What the card needs, not what it has: in a window too short for it, its middle scrolls.
308
- function fit() {
309
- // The title carries the answer signal once sent: a late resize must not write over it.
310
- if (done) return;
311
- var wrap = document.querySelector(".wrap"), head = document.querySelector(".head"), foot = document.querySelector(".foot");
312
- document.title = "agentx:size:" + Math.ceil(wrap.offsetHeight - card.clientHeight + head.offsetHeight + body.scrollHeight + foot.offsetHeight);
313
- }
314
- function mark() { touched = box.value.trim() !== fill(pick); msg.classList.toggle("touched", touched); }
315
- function update() {
316
- opts.forEach(function (o, i) { o.setAttribute("aria-checked", String(i === pick)); });
317
- yes.disabled = (d.choices.length > 0 && pick < 0) || (box && !box.value.trim());
318
- }
319
- function grow() { if (!box) return; box.style.height = "auto"; box.style.height = box.scrollHeight + 4 + "px"; }
320
- // quiet: the pick made on open. The box is not focused, so the number keys still pick.
321
- function choose(i, quiet) {
322
- // An edited message keeps the edits, with the old pick swapped for the new one.
323
- if (box && touched && pick >= 0) box.value = box.value.split(d.choices[pick]).join(d.choices[i]);
324
- else if (box) box.value = fill(i);
325
- pick = i;
326
- if (box) { grow(); mark(); }
327
- update();
328
- if (box && !quiet) box.focus();
329
- }
330
- opts.forEach(function (o, i) { o.addEventListener("click", function () { choose(i); }); });
331
- if (box) {
332
- box.value = d.choices.length ? "" : fill(-1);
333
- box.placeholder = d.choices.length ? "Pick an option above" : "";
334
- grow();
335
- box.addEventListener("input", function () { grow(); mark(); update(); });
336
- document.getElementById("reset").addEventListener("click", function () { box.value = fill(pick); grow(); mark(); update(); box.focus(); });
337
- }
338
- yes.addEventListener("click", function () {
339
- if (yes.disabled) return;
340
- var a = { action: "yes" };
341
- if (pick >= 0) a.choice = d.choices[pick];
342
- if (box) a.text = box.value.trim();
343
- send(a);
344
- });
345
- document.getElementById("no").addEventListener("click", function () { send({ action: "no" }); });
346
- document.getElementById("later").addEventListener("click", function () { send({ action: "dismiss", why: "not now" }); });
347
- fold.addEventListener("click", function () {
348
- var shrunk = card.classList.toggle("folded");
349
- fold.setAttribute("aria-expanded", String(!shrunk));
350
- fold.title = shrunk ? "Show all" : "Shrink";
351
- fit();
352
- });
353
- document.addEventListener("keydown", function (e) {
354
- if (e.key === "Escape") return send({ action: "dismiss", why: "not now" });
355
- // A shrunk card hides its buttons: no answer by key while they can't be seen.
356
- if (card.classList.contains("folded")) return;
357
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); return yes.click(); }
358
- // preventDefault: choose() focuses the box, and the digit must not be typed into it.
359
- if (document.activeElement !== box && /^[1-9]$/.test(e.key) && opts[+e.key - 1]) { e.preventDefault(); choose(+e.key - 1); }
360
- });
361
- if (d.pick >= 0) choose(d.pick, true); else update();
362
- requestAnimationFrame(fit);
363
- if (box) new ResizeObserver(fit).observe(box);
364
-
365
- if (d.chime) try {
366
- var ac = new AudioContext(), t = ac.currentTime + 0.05;
367
- [[783.99, 0], [1046.5, 0.14]].forEach(function (n) {
368
- [1, 2].forEach(function (h) {
369
- var o = ac.createOscillator(), g = ac.createGain();
370
- o.type = "sine"; o.frequency.value = n[0] * h;
371
- g.gain.setValueAtTime(0, t + n[1]);
372
- g.gain.linearRampToValueAtTime(d.volume * (h === 1 ? 0.5 : 0.12), t + n[1] + 0.012);
373
- g.gain.exponentialRampToValueAtTime(0.0001, t + n[1] + 1.4);
374
- o.connect(g).connect(ac.destination); o.start(t + n[1]); o.stop(t + n[1] + 1.5);
375
- });
376
- });
377
- } catch (e) {}
378
- })();
379
- `;var hs=440,ys=`
380
- ObjC.import("Cocoa"); ObjC.import("WebKit")
381
- function run(argv) {
382
- var path = argv[0], side = ${_.side}, gripTop = ${_.top}, gripEnd = ${_.top+et.height}, keep = ${et.keep}, w = Number(argv[1]) + 2 * side, h = 420, secs = Number(argv[2]), capture = argv[3] || ""
383
- var app = $.NSApplication.sharedApplication
384
- app.setActivationPolicy($.NSApplicationActivationPolicyAccessory)
385
- ObjC.registerSubclass({ name: "AgentXCardView", superclass: "WKWebView", methods: {
386
- "acceptsFirstMouse:": { types: ["bool", ["id"]], implementation: function () { return true } },
387
- } })
388
- var vis = $.NSScreen.mainScreen.visibleFrame
389
- var top = vis.origin.y + vis.size.height - 4, right = vis.origin.x + vis.size.width - 14 + side
390
- var mask = $.NSWindowStyleMaskTitled | $.NSWindowStyleMaskClosable | $.NSWindowStyleMaskFullSizeContentView
391
- var win = $.NSPanel.alloc.initWithContentRectStyleMaskBackingDefer($.NSMakeRect(right - w, top - h, w, h), mask, $.NSBackingStoreBuffered, false)
392
- win.titlebarAppearsTransparent = true
393
- win.titleVisibility = $.NSWindowTitleHidden
394
- win.movableByWindowBackground = true
395
- win.level = $.NSFloatingWindowLevel
396
- win.releasedWhenClosed = false
397
- win.hidesOnDeactivate = false
398
- win.collectionBehavior = $.NSWindowCollectionBehaviorCanJoinAllSpaces
399
- win.opaque = false
400
- win.backgroundColor = $.NSColor.clearColor
401
- win.hasShadow = false
402
- ;[$.NSWindowCloseButton, $.NSWindowMiniaturizeButton, $.NSWindowZoomButton].forEach(function (b) { win.standardWindowButton(b).hidden = true })
403
- var cfg = $.WKWebViewConfiguration.alloc.init
404
- cfg.mediaTypesRequiringUserActionForPlayback = 0
405
- var web = $.AgentXCardView.alloc.initWithFrameConfiguration($.NSMakeRect(0, 0, w, h), cfg)
406
- web.autoresizingMask = $.NSViewWidthSizable | $.NSViewHeightSizable
407
- web.setValueForKey(false, "drawsBackground")
408
- win.contentView = web
409
- var url = $.NSURL.fileURLWithPath(path)
410
- web.loadFileURLAllowingReadAccessToURL(url, url.URLByDeletingLastPathComponent)
411
- win.makeKeyAndOrderFront(null)
412
- app.activateIgnoringOtherApps(true)
413
- var end = Date.now() + secs * 1000, sized = 0, shot = false, seen = "", asked = false, answer = null
414
- // Every kind of event, as a number. JXA hands the AppKit constant for it over as text, and a
415
- // loop asking with that gets no event at all: no click, no drag, no key.
416
- var anyEvent = Number.MAX_SAFE_INTEGER
417
- while (Date.now() < end) {
418
- var ev = app.nextEventMatchingMaskUntilDateInModeDequeue(anyEvent, $.NSDate.dateWithTimeIntervalSinceNow(0.05), $.NSDefaultRunLoopMode, true)
419
- if (ev && !ev.isNil()) {
420
- if (onGrip(ev)) win.performWindowDragWithEvent(ev); else app.sendEvent(ev)
421
- }
422
- if (answer !== null) { win.close; return answer }
423
- if (!win.isVisible) return gone("closed")
424
- var t = web.title.js || ""
425
- if (t === "agentx:answer" && !asked) {
426
- asked = true
427
- web.evaluateJavaScriptCompletionHandler("window.agentxAnswer", function (r) { answer = String(ObjC.unwrap(r) || "") })
428
- }
429
- if (t !== seen && t.indexOf("agentx:size:") === 0) {
430
- seen = t
431
- var want = Math.min(Number(t.slice(12)), vis.size.height - 8)
432
- var f = win.frame
433
- if (want > 80) { win.setFrameDisplayAnimate($.NSMakeRect(f.origin.x, f.origin.y + f.size.height - want, w, want), true, true); sized = Date.now() }
434
- }
435
- if (capture && !shot && sized && Date.now() - sized > 900) {
436
- shot = true
437
- var sa = Application.currentApplication(); sa.includeStandardAdditions = true
438
- sa.doShellScript("/usr/sbin/screencapture -x -o -l " + win.windowNumber + " " + quoted(capture))
439
- end = Math.min(end, Date.now() + 300)
440
- }
441
- }
442
- win.close
443
- return gone("timed out")
444
- function onGrip(ev) {
445
- if (ev.type != $.NSEventTypeLeftMouseDown || ev.windowNumber != win.windowNumber) return false
446
- var p = ev.locationInWindow, down = win.frame.size.height - p.y
447
- return down >= gripTop && down <= gripEnd && p.x >= side && p.x <= w - side - keep
448
- }
449
- }
450
- function gone(why) { return JSON.stringify({ action: "dismiss", why: why }) }
451
- function quoted(s) { return "'" + String(s).replace(/'/g, "'\\\\''") + "'" }
452
- `;function bs(t,e){let n=t.trim().split(`
453
- `).pop()??"",i;try{i=JSON.parse(n)}catch{return{action:"dismiss"}}if(i?.action==="no")return{action:"no"};if(i?.action==="dismiss"&&ur.includes(i.why))return{action:"dismiss",why:i.why};if(i?.action!=="yes")return{action:"dismiss"};let r=e.choices??[],o;if(r.length){if(typeof i.choice!="string"||!r.includes(i.choice))return{action:"dismiss"};o=i.choice}let s;return e.draft&&(s=typeof i.text=="string"?i.text.replace(/\r\n?/g,`
454
- `).trim():"",!s||s.length>jt.text)?{action:"dismiss"}:{action:"yes",...o?{choice:o}:{},...s?{text:s}:{}}}async function lr(t,e,n){let i=Math.max(10,Math.round(e.timeoutSeconds)),r=ps(cr(ms(),"agentx-card-"));try{let o=cr(r,"card.html");gs(o,ar(t,{...e,still:!!e.capture}),{mode:384});let s=["-l","JavaScript","-e",ys,o,String(hs),String(i),...e.capture?[e.capture]:[]],a=await n("/usr/bin/osascript",s,(i+10)*1e3);return a.ok?bs(a.stdout,t):null}finally{fs(r,{recursive:!0,force:!0})}}var ur=["not now","timed out","closed"],ks=(t,e,n)=>new Promise(i=>{try{ws(t,e,{timeout:n},(r,o)=>i({ok:!r,stdout:String(o??"")}))}catch{i({ok:!1,stdout:""})}}),dr=160,nt=15e3;function pr(t){let e=(t.say||t.title).replace(/\s+/g," ").trim();return e.length>dr?e.slice(0,dr):e}async function xs(t,e,n,i,r){let o=e.sound==="chime"?i?"":"Glass":e.sound,s=o?zt(o):null;if(s&&await n("/usr/bin/afplay",["-v",String(Math.min(1,Math.max(0,e.volume))),s],nt),!!e.speak)if(r){let a;await Promise.race([r(pr(t)),new Promise(c=>{a=setTimeout(c,nt)})]),clearTimeout(a)}else{let a=e.voice&&/^[\w .()-]+$/.test(e.voice)?["-v",e.voice]:[];await n("/usr/bin/say",[...a,"--",pr(t)],nt)}}function mr(t,e){return[...t.flatMap(n=>["-e",n]),...e]}function Ss(t,e,n){return mr(["on run argv","activate","set opts to items 3 thru -1 of argv",'set pick to choose from list opts with title (item 1 of argv) with prompt (item 2 of argv) OK button name "Next" cancel button name "Not now"','if pick is false then return ""',"return item 1 of pick","end run"],[t,e,...n])}function fr(t,e,n,i,r){return mr(["on run argv","activate","set AppleScript's text item delimiters to linefeed","set btns to text items of (item 3 of argv)","set secs to (item 5 of argv) as integer","if (count of argv) > 5 then","set r to display dialog (item 2 of argv) with title (item 1 of argv) default answer (item 6 of argv) buttons btns default button (item 4 of argv) giving up after secs","else","set r to display dialog (item 2 of argv) with title (item 1 of argv) buttons btns default button (item 4 of argv) giving up after secs","end if",'if gave up of r then return ""',"if (count of argv) > 5 then return (button returned of r) & linefeed & (text returned of r)","return button returned of r","end run"],[t,e,n.join(`
455
- `),n[n.length-1],String(i),...r!==void 0?[r]:[]])}function gr(t){let e=t.replace(/\n$/,"");if(!e)return null;let n=e.indexOf(`
456
- `);return n<0?{button:e,text:""}:{button:e.slice(0,n),text:e.slice(n+1)}}function rt(t){return[t.ask,t.recommend?`Recommended: ${t.recommend}`:"",`From ${t.raised_by}`].filter(Boolean).join(`
457
-
458
- `)}async function hr(t,e,n={}){let i=n.run??ks,r=(e.style??"card")==="card",o=xs(t,e,i,r,n.speak).catch(()=>{});if(r){let s=await lr(t,{timeoutSeconds:e.timeoutSeconds,sound:e.sound,volume:e.volume,theme:e.theme,from:n.from,capture:n.capture,pick:n.pick},i).catch(()=>null);if(s)return s}return await o,vs(t,e,i)}async function vs(t,e,n){let i=Math.max(10,Math.round(e.timeoutSeconds)),r=(i+5)*1e3,o=`${t.raised_by}: ${t.title}`,s;if(t.choices?.length){let l=await n("/usr/bin/osascript",Ss(o,rt(t),t.choices),r);if(s=l.stdout.replace(/\n$/,""),!l.ok||!t.choices.includes(s))return{action:"dismiss"};if(!t.draft)return{action:"yes",choice:s}}if(t.draft){let l=s?`${s}
459
-
460
- Message (edit it if you like):`:`${rt(t)}
461
-
462
- Message (edit it if you like):`,d=await n("/usr/bin/osascript",fr(o,l,s?["Cancel","Send"]:["Not now","No","Send"],i,Wt(t.draft,s)),r),p=d.ok?gr(d.stdout):null;if(p?.button==="Send"){let f=p.text.trim();return f?{action:"yes",...s?{choice:s}:{},text:f}:{action:"dismiss"}}return p?.button==="No"?{action:"no"}:{action:"dismiss"}}let a=await n("/usr/bin/osascript",fr(o,rt(t),["Not now","No","Yes"],i),r),c=a.ok?gr(a.stdout):null;return c?.button==="Yes"?{action:"yes"}:c?.button==="No"?{action:"no"}:{action:"dismiss"}}var ot=24*36e5,it=!1,$s=10*6e4,yr=-1/0;function br(t){let e=t.now??Date.now(),{popped:n={},snoozed:i,passAt:r,wanted:o=[]}=A(t.root),s=r?Date.parse(r):NaN,a=B(t.root,"pending").filter(l=>Date.parse(l.expires)>e),c=a.find(l=>o.includes(`card:${l.id}`));if(c)return c;for(let l of a){let u=`card:${l.id}`;if(n[u])continue;let d=i[u];if(d&&Date.parse(d)>e)continue;let p=Date.parse(l.created_at);if(!(e-p>ot&&!(p<=s)))return l}return null}function wr(t){try{return z(t)?.listByState("needs_attention")??[]}catch{return[]}}function As(t){let e=t.now??Date.now(),{popped:n={},snoozed:i}=A(t.root);return wr(t).find(r=>{let o=`request:${r.id}`,s=i[o];return!n[o]&&!(s&&Date.parse(s)>e)&&e-r.updatedAt<=ot})??null}function Is(t,e){return{id:t.id,title:Qe(t.text,Kt.title),context:t.attentionReason??"It is not finished and nothing is retrying it.",ask:`Hand it back to ${t.agentId}, or drop it?`,say:"A request you made is not finished.",recommend:"",if_silent:"keep",expires:new Date(e+ot).toISOString(),raised_by:t.agentId,created_at:new Date(t.createdAt).toISOString(),status:"pending",origin:{kind:"request",id:t.id}}}async function Vl(t){let{ctx:e,settings:n,log:i}=t;if(!n.enabled||(t.platform??process.platform)!=="darwin")return"off";if(it)return"busy";let r=br(e)?null:As(e),o=r?Is(r,e.now??Date.now()):br(e);if(!o)return"none";let s=(t.focus??Et)();if(s.active)return"held";it=!0;let a=`${r?"request":"card"}:${o.id}`;try{let c=[...B(e.root,"pending").map(h=>`card:${h.id}`),...wr(e).map(h=>`request:${h.id}`)];fn(e.root,a,c,e.now),i(`[approvals] popup: showing ${a} from ${o.raised_by}`);let l=e.now??Date.now(),u=!!r&&l-yr<$s;r&&n.speak&&(yr=l);let d=t.agentName?.(o.raised_by)??(o.node?`${o.raised_by} on ${o.node}`:void 0),p=await(t.show??hr)(o,u?{...n,speak:!1}:n,{from:d,speak:t.speak});if(p.action==="dismiss")return i(`[approvals] popup: ${a} left waiting: ${p.why??"no answer"} (${Tt(s)} when shown)`),"shown";if(!(r?z(e)?.get(r.id)?.state==="needs_attention":U(e.root,o.id)?.status==="pending"))return i(`[approvals] popup: ${a} was answered elsewhere; popup answer ignored`),"shown";let g=await kn(e,a,p.action,{by:"operator (popup)",...p.action==="yes"?{choice:p.choice,text:p.text}:{}});return i(g.ok?`[approvals] popup: ${g.message}`:`[approvals] popup: ${a} not recorded: ${g.error}`),"shown"}catch(c){return i(`[approvals] popup failed for ${a}: ${c?.message??c}`),"shown"}finally{it=!1}}function Wl(t,e,n){if(!n)return{ok:!1,error:"the Mac popup is off; turn it on with `agentx approvals settings --popup on`"};let i=e.startsWith("card:")?U(t.root,e.slice(5)):null;return i?i.status!=="pending"?{ok:!1,error:`${e} is already ${i.status}`}:(gn(t.root,e),{ok:!0,message:`${e} will show on the Mac within a minute`}):{ok:!1,error:`no card "${e}"; the popup shows decision cards only`}}import{closeSync as G,createReadStream as Rs,fstatSync as _s,openSync as Cs,realpathSync as kr}from"fs";import{isAbsolute as Ds,resolve as xr,sep as Sr}from"path";var ql="/app-files",Es=/^[A-Za-z0-9_.:-]{1,64}$/;function Ts(t,e,n=process.cwd()){if(!e||e.length>ee.pathChars||e.includes("\0"))return{ok:!1,status:400,error:"bad file path"};if(e.split(/[\\/]/).includes(".."))return{ok:!1,status:403,error:`the path leaves the workspace: copy the file into ${Se}/ first`};if(!xe(e))return{ok:!1,status:415,error:"this type of file is not served"};let i;try{i=kr(xr(n,t))}catch{return{ok:!1,status:404,error:"the agent's workspace is missing"}}let r;try{r=kr(Ds(e)?e:xr(i,e))}catch{return{ok:!1,status:404,error:"file not found"}}if(!r.startsWith(i+Sr))return{ok:!1,status:403,error:`the file is outside the agent's workspace: copy it into ${Se}/ first`};let o=xe(r);return o?{ok:!0,path:r,...o}:{ok:!1,status:415,error:"this type of file is not served"}}function Ps(t,e){let n=t.replace(/[^\x20-\x7e]/g,"_").replace(/["\\;]/g,"_").slice(0,120)||"file";return`${e==="file"?"attachment":"inline"}; filename="${n}"; filename*=UTF-8''${encodeURIComponent(t.slice(0,120))}`}function Ls(t,e,n){return{"Content-Type":t,"Content-Disposition":Ps(e,n),"X-Content-Type-Options":"nosniff","Content-Security-Policy":"default-src 'none'; img-src 'self'; media-src 'self'; sandbox","Cache-Control":"private, max-age=3600","Accept-Ranges":"bytes"}}function Ms(t,e){let n=/^bytes=(\d*)-(\d*)$/.exec(String(t||"").trim());if(!n||!n[1]&&!n[2])return null;let i,r;return n[1]?(i=Number(n[1]),r=n[2]?Math.min(Number(n[2]),e-1):e-1):(i=Math.max(0,e-Number(n[2])),r=e-1),i>r||i>=e?"unsatisfiable":{start:i,end:r}}function Kl(t,e,n,i){let r=(D,N)=>{e.writeHead(D,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),e.end(JSON.stringify(N))};if(t.method!=="GET"&&t.method!=="HEAD")return r(405,{error:"GET only"});let o=n.searchParams.get("agent")||"",s=n.searchParams.get("file")||"";if(!Es.test(o))return r(400,{error:"bad agent id"});let a=i.workspaceOf(o);if(!a)return r(404,{error:`no agent "${o}" on this computer`});let c=Ts(a,s,i.cwd);if(!c.ok)return i.log?.(`[app-files] refused ${JSON.stringify(s.slice(0,200))} from ${o}: ${c.error}`),r(c.status,{error:c.error});let l;try{l=Cs(c.path,"r")}catch{return r(404,{error:"file not found"})}let u;try{let D=_s(l);if(!D.isFile())return G(l),r(404,{error:"not a file"});u=D.size}catch{return G(l),r(404,{error:"file not found"})}if(u>ee.bytes)return G(l),r(413,{error:`the file is larger than ${ee.bytes/1024/1024} MB`});let d=c.path.split(Sr).pop()||"file",p=Ls(c.mime,d,c.kind),f=Ms(t.headers.range,u);if(f==="unsatisfiable"){G(l),e.writeHead(416,{...p,"Content-Range":`bytes */${u}`}),e.end();return}let{start:g,end:h}=f??{start:0,end:u-1};if(e.writeHead(f?206:200,{...p,"Content-Length":String(u?h-g+1:0),...f?{"Content-Range":`bytes ${g}-${h}/${u}`}:{}}),t.method==="HEAD"||u===0){G(l),e.end();return}let y=Rs("",{fd:l,start:g,end:h,autoClose:!0});y.on("error",()=>e.destroy()),e.on("close",()=>y.destroy()),y.pipe(e)}import{spawn as X}from"child_process";import{readFileSync as Os,writeFileSync as Ns}from"fs";import{tmpdir as js}from"os";import{join as Vs}from"path";wt();var vr=t=>t&&t!==1?Math.round(175*t):null,ge=t=>t&&t!==1?Math.min(1.2,Math.max(.7,t)):null;function Ws(){if(process.env.ELEVENLABS_API_KEY)return process.env.ELEVENLABS_API_KEY;for(let t of[`${process.env.HOME}/.elevenlabs/key`,`${process.env.HOME}/.agentx/elevenlabs-key.txt`])try{let e=Os(t,"utf8").trim();if(e)return e}catch{}return null}function nu(t=Ws()){let e=0;return async(n,i)=>{if(n.voice.provider==="system")return null;if(!t){if(n.voice.fallback)return null;throw new Error("ElevenLabs is the voice provider but no key is set")}try{let r=await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${n.voice.elevenlabs}/stream?output_format=mp3_44100_128`,{method:"POST",headers:{"xi-api-key":t,"Content-Type":"application/json"},body:JSON.stringify({text:n.text,model_id:"eleven_flash_v2_5",...ge(n.voice.rate)?{voice_settings:{speed:ge(n.voice.rate)}}:{}}),signal:i});if(!r.ok)throw new Error(`ElevenLabs ${r.status}: ${(await r.text()).slice(0,160)}`);let o=Vs(js(),`agentx-say-${process.pid}-${++e}.mp3`);return Ns(o,Buffer.from(await r.arrayBuffer())),o}catch(r){if(i.aborted||!n.voice.fallback)throw r;return M(`elevenlabs:${String(r?.message??r).slice(0,40)}`,`[voice] ElevenLabs failed (${String(r?.message??r).slice(0,160)}); speaking with the system voice`),null}}}function $r(t,e){let n=t.languages&&Q(e);return n&&t.languages&&n in t.languages?t.languages[n]:t.system}var Fs=(t,e="")=>{let n=$r(t,e),i=vr(t.rate);return[...n&&!Rn(n)?["-v",n]:[],...i?["-r",String(i)]:[]]};function Us(t,e,n){if(!n)return["say",Fs(t,e)];let i=$r(t,e);return["/bin/sh",[n,...i?[i]:[]]]}function ru(t){let e=t.split(/\s+/).filter(Boolean).length;return Math.min(300,5+Math.floor(e*6/10))*1e3}function iu(t=st()){if(t)try{X("/bin/sh",[t,"--stop"],{stdio:"ignore"}).on("error",()=>{})}catch{}}function ou(t=st()){if(t)try{X("/bin/sh",[t,"--restore"],{stdio:"ignore"}).on("error",()=>{})}catch{}}function st(t={},e){if(!Ee(t))return null;try{return Dn(e)}catch(n){return M("siri-say",`[voice] could not write the Siri voice script (${String(n?.message??n).split(`
463
- `)[0]}); Siri voices will not switch`),null}}var su=(t,e)=>{if(!t){let[n,i]=Us(e.voice,e.text,st()),r=vr(e.voice.rate),o=r?{...process.env,AGENTX_SAY_RATE:String(r)}:process.env,s=X(n,i,{stdio:["pipe","ignore","ignore"],env:o});return s.stdin?.on("error",()=>{}),s.stdin?.end(e.text),s}return process.platform==="darwin"?X("afplay",[t],{stdio:"ignore"}):X("mpg123",["-q",t],{stdio:"ignore"})};import{spawn as Ar}from"child_process";import{accessSync as Bs,constants as Hs,readFileSync as Ir}from"fs";import{homedir as zs}from"os";import{basename as W,delimiter as Rr,dirname as qs,extname as Ks,join as at}from"path";var P={ms:2*60*1e3,bitsPerSecond:64e3,bytes:2*1024*1024};function _r(t){let e=Array.isArray(t)?t[0]:t;return!e||!/^\d{1,9}$/.test(e.trim())?{status:400,error:"Say how long the recording is (X-Audio-Duration-Ms)."}:Number(e)>P.ms+2e3?{status:413,error:lt()}:null}var lt=()=>`The recording is longer than ${P.ms/6e4} minutes.`,Gs={"audio/webm":"webm","video/webm":"webm","audio/ogg":"ogg","audio/mp4":"m4a","video/mp4":"m4a","audio/x-m4a":"m4a","audio/aac":"aac","audio/mpeg":"mp3","audio/wav":"wav","audio/x-wav":"wav","audio/wave":"wav"};function Cr(t){let e=String(t||"").split(";")[0].trim().toLowerCase();return Gs[e]??null}function Dr(t,e){let n=[];return t!=="local"&&e.key&&n.push("elevenlabs"),e.ffmpeg&&(e.mlx?n.push("mlx-whisper"):e.whisper&&n.push("whisper")),n}function ut(t,e){return t==="local"&&e.key&&!e.ffmpeg?"Speech to text is set to local, and this computer has no ffmpeg.":(e.mlx||e.whisper)&&!e.ffmpeg?"This computer has Whisper but no ffmpeg to read the recording.":"Add an ElevenLabs key on this computer, or install mlx-whisper and ffmpeg."}function ct(t,e,n=process.env.PATH??""){let i=zs(),r=[at(i,".local","bin"),"/opt/homebrew/bin","/usr/local/bin",...n.split(Rr).filter(Boolean)];for(let o of[e,...r.map(s=>at(s,t))])if(o)try{return Bs(o,Hs.X_OK),o}catch{}return null}function pu(t){return{key:t,mlx:ct("mlx_whisper",process.env.AGENTX_MLX_WHISPER),whisper:ct("whisper",process.env.AGENTX_WHISPER),ffmpeg:Xs()}}var Xs=()=>ct("ffmpeg",process.env.AGENTX_FFMPEG);async function Er(t,e){return e?Js(t,e):null}async function Js(t,e){let n=String(P.ms/1e3+5);try{let r=[...(await Ys(e,["-nostdin","-hide_banner","-t",n,"-i",t,"-f","null","-"],3e4)).matchAll(/time=(\d+):(\d+):(\d+(?:\.\d+)?)/g)],o=r[r.length-1];return o?Number(o[1])*3600+Number(o[2])*60+Number(o[3]):null}catch{return null}}async function Tr(t,e,n,i){let r=new FormData;r.set("model_id",process.env.AGENTX_STT_MODEL||"scribe_v1"),r.set("file",new Blob([Ir(t)],{type:e}),W(t));let o=await fetch("https://api.elevenlabs.io/v1/speech-to-text",{method:"POST",headers:{"xi-api-key":n},body:r,signal:i??AbortSignal.timeout(6e4)});if(!o.ok)throw new Error(`ElevenLabs ${o.status}: ${(await o.text().catch(()=>"")).slice(0,160)}`);let s=await o.json();if(typeof s.text!="string")throw new Error("ElevenLabs returned no text");return s.text.trim()}async function Pr(t,e,n,i,r){let o=t==="mlx-whisper"?["--model",process.env.AGENTX_MLX_MODEL||"mlx-community/whisper-large-v3-turbo","--output-format","txt","--output-dir",r,n]:[n,"--model",process.env.AGENTX_WHISPER_MODEL||"base","--output_format","txt","--output_dir",r,"--fp16","False"],s={...process.env,PATH:`${qs(i)}${Rr}${process.env.PATH??""}`};await Zs(e,o,12e4,s);try{return Ir(at(r,W(n,Ks(n))+".txt"),"utf8").trim()}catch{throw new Error(`${t} wrote no transcript`)}}function Ys(t,e,n){return new Promise((i,r)=>{let o=Ar(t,e,{stdio:["ignore","ignore","pipe"]}),s="",a=setTimeout(()=>{o.kill("SIGKILL"),r(new Error(`${W(t)} took too long`))},n);o.stderr.on("data",c=>{s=(s+c).slice(-8192)}),o.on("error",c=>{clearTimeout(a),r(c)}),o.on("exit",c=>{clearTimeout(a),c===0?i(s):r(new Error(`${W(t)} exited ${c}`))})})}function Zs(t,e,n,i=process.env){return new Promise((r,o)=>{let s=Ar(t,e,{stdio:["ignore","pipe","pipe"],env:i}),a="",c="",l=setTimeout(()=>{s.kill("SIGKILL"),o(new Error(`${W(t)} took longer than ${n/1e3}s`))},n);s.stdout.on("data",u=>{a.length<4096&&(a+=u)}),s.stderr.on("data",u=>{c.length<4096&&(c+=u)}),s.on("error",u=>{clearTimeout(l),o(u)}),s.on("exit",u=>{clearTimeout(l),u===0?r(a):o(new Error(`${W(t)} exited ${u}: ${c.trim().split(`
464
- `).pop()?.slice(0,160)??""}`))})})}import{mkdtemp as Qs,rm as ea,writeFile as ta}from"fs/promises";import{tmpdir as na}from"os";import{join as Lr}from"path";Br();var ra=64*1024,ia=2,dt=0;function vu(t){return t==="/voice/transcribe"||t==="/voice/speak"}async function $u(t,e,n,i){return t.method!=="POST"?b(e,405,{error:"POST"}):n==="/voice/transcribe"?oa(t,e,i):ca(t,e,i)}async function oa(t,e,n){let i=String(t.headers["content-type"]||""),r=Cr(i);if(!r)return b(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let o=_r(t.headers["x-audio-duration-ms"]);if(o)return t.resume(),b(e,o.status,{error:o.error});let s=await Mr(t,P.bytes);if(!s)return b(e,413,{error:da()});if(!s.length)return b(e,400,{error:"The recording is empty."});if(dt>=ia)return b(e,429,{error:"This computer is already writing down other recordings. Try again in a moment."});let a=n.stt(),c=n.host(),l=Dr(a,c);if(!c.ffmpeg&&!n.allowUnmeasured?.()){let d=n.nodeName?`on ${n.nodeName}`:"on this computer",p=l.length?"":" "+ut(a,c);return b(e,503,{error:"Voice input isn't set up on this computer.",hint:`Install ffmpeg ${d} for voice input from the phone.${p}`,setup:!1})}if(!l.length)return b(e,503,{error:"Voice input isn't set up on this computer.",hint:ut(a,c),setup:!1});dt++;let u;try{let d=await Qs(Lr(na(),"agentx-phone-voice-"));try{u=await sa(d,`speech.${r}`,s,i,c,l,n)}finally{await ea(d,{recursive:!0,force:!0}).catch(()=>{})}}finally{dt--}b(e,u[0],u[1])}async function sa(t,e,n,i,r,o,s){let a=Lr(t,e);if(await ta(a,n,{mode:384}),r.ffmpeg){let l=await(s.measure??Er)(a,r.ffmpeg);if(l==null)return[422,{error:"This computer couldn't read the recording. Try again."}];if(l*1e3>P.ms+2e3)return[413,{error:lt()}]}let c=[];for(let l of o)try{let u=await aa(l,a,i,r,t,s);return s.log(`[voice] phone recording transcribed with ${l} (${Math.round(n.length/1024)} KB)`),u?[200,{text:u,engine:l}]:[422,{error:"No words were heard. Hold the orb and speak, then let go.",engine:l}]}catch(u){let d=String(u?.message??u).split(`
465
- `)[0].slice(0,200);c.push(`${l}: ${d}`),s.log(`[voice] phone transcription with ${l} failed: ${d}`)}return[502,{error:"Speech to text failed on this computer.",detail:c.join("; ")}]}function aa(t,e,n,i,r,o){let s=o.engines?.[t];if(s)return s(e,n,i,r);if(t==="elevenlabs")return Tr(e,n,i.key);let a=t==="mlx-whisper"?i.mlx:i.whisper;return Pr(t,a,e,i.ffmpeg,r)}async function ca(t,e,n){let i=await Mr(t,ra);if(!i)return b(e,413,{error:"request too large"});let r;try{r=JSON.parse(i.toString("utf8")||"{}")}catch{return b(e,400,{error:"expected JSON"})}let o=typeof r?.agent=="string"?r.agent:"",s=typeof r?.peer=="string"&&r.peer?r.peer:void 0;if(!o)return b(e,400,{error:"agent is required"});let a=la(typeof r?.text=="string"?r.text:"",n.spokenMaxChars?.());if(!a)return b(e,422,{error:"Nothing in this answer can be said aloud."});let c=n.pronounce?n.pronounce(a):a,l=n.voiceOf(o,s);if(!l)return b(e,404,{error:`Unknown agent: ${o}`});let u=(p,f=200)=>b(e,f,{fallback:"browser",reason:p,text:c});if(l.provider!=="elevenlabs")return u("This agent speaks with a system voice, which only plays on the computer.");let d=n.elevenLabsKey();if(!d)return u("No ElevenLabs key is set on this computer.");try{let p=await(n.synth??ua)(d,l,c);e.writeHead(200,{"Content-Type":"audio/mpeg","Content-Length":p.length,"Cache-Control":"no-store","X-Spoken-Chars":String(c.length)}),e.end(p)}catch(p){return n.log(`[voice] phone answer synthesis failed: ${String(p?.message??p).split(`
466
- `)[0].slice(0,160)}`),u("ElevenLabs could not speak this answer.",502)}}function la(t,e){let n=er(Dt(t).text).cleanText.replace(/!\[[^\]\n]*\]\([^)\n]*\)/g,"");return kt(n,e)}async function ua(t,e,n){let i=ge(e.rate),r=await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${encodeURIComponent(e.elevenlabs)}?output_format=mp3_44100_128`,{method:"POST",headers:{"xi-api-key":t,"Content-Type":"application/json"},body:JSON.stringify({text:n,model_id:"eleven_flash_v2_5",...i?{voice_settings:{speed:i}}:{}}),signal:AbortSignal.timeout(6e4)});if(!r.ok)throw new Error(`ElevenLabs ${r.status}: ${(await r.text().catch(()=>"")).slice(0,160)}`);return Buffer.from(await r.arrayBuffer())}var da=()=>`The recording is larger than ${P.bytes/1024/1024} MB, more than ${P.ms/6e4} minutes of speech.`;function Au(t,e,n,i){if(e)return i.speakerOn(e,t,!1)?.voice??null;let r=n.agents??{};return r[t]?Fe(je(t,r,n.voice)):null}function Mr(t,e){return Number(t.headers["content-length"])>e?(t.resume(),Promise.resolve(null)):new Promise((n,i)=>{let r=[],o=0;t.on("data",s=>{if(!(o>e)){if(o+=s.length,o>e){r.length=0,n(null);return}r.push(s)}}),t.on("end",()=>{o<=e&&n(Buffer.concat(r))}),t.on("error",i)})}function b(t,e,n){t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(n))}import{existsSync as v,readFileSync as mt,writeFileSync as ht,mkdirSync as me,readdirSync as gt,rmSync as pa,statSync as I}from"fs";import{resolve as Or,relative as fa,dirname as yt,join as O,extname as J,basename as bt}from"path";var x=200*1024,Nr=new Set([".md",".markdown",".txt"]),F=new Set([".md",".markdown",".txt",".json",".jsonc",".yaml",".yml",".toml",".sh",".bash",".zsh",".py",".js",".mjs",".ts",".tsx",".jsx",".css",".html",".lock",".cfg",".ini",".env",".gitignore"]),ga=6,ma=new Set(["CLAUDE.md","SOUL.md","IDENTITY.md","PERSONA.md","AGENT.md","BOOTSTRAP.md"]);function C(t,e){if(!t)throw new Error("Agent workspace is not configured.");let n=Or(t);if(v(n)||me(n,{recursive:!0}),!e||e.startsWith("/")||e.match(/^[a-zA-Z]:/))throw new Error(`Path must be relative to the workspace: ${e}`);let i=Or(n,e);if(fa(n,i).startsWith(".."))throw new Error(`Path escapes the workspace: ${e}`);return i}function jr(t){let e=J(t).toLowerCase();if(!Nr.has(e))throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${e}).`)}function pt(t,e){let n=t.split(/\r?\n/).find(i=>i.trim().startsWith("#"));return n&&n.replace(/^#+\s*/,"").trim().slice(0,120)||e}function Cu(t){let e=C(t,"."),n=[],i=new Set,r=[];try{r=gt(e)}catch{}for(let a of ma){let c=O(e,a);if(v(c)&&I(c).isFile()){let l=I(c).size,u=l>0&&l<x?ft(c):"";n.push({path:a,title:pt(u,a),size:l,exists:!0}),i.add(a)}else n.push({path:a,title:a,size:0,exists:!1}),i.add(a)}for(let a of r){if(i.has(a))continue;let c=O(e,a);try{let l=I(c);if(!l.isFile()||!Nr.has(J(a).toLowerCase()))continue;let u=l.size>0&&l.size<x?ft(c):"";n.push({path:a,title:pt(u,a),size:l.size,exists:!0})}catch{}}let o=[],s=O(e,".claude","skills");if(v(s))try{for(let a of gt(s)){let c=O(s,a),l;try{l=I(c)}catch{continue}if(!l.isDirectory())continue;let u=O(c,"SKILL.md");if(!v(u))continue;let d=I(u),p=d.size<x?ft(u):"";o.push({slug:a,title:pt(p,a),size:d.size,path:`.claude/skills/${a}/SKILL.md`})}}catch{}return o.sort((a,c)=>a.slug.localeCompare(c.slug)),{identity:n,skills:o,workspace:e}}function ft(t){try{return mt(t,"utf-8")}catch{return""}}function Du(t,e){let n=C(t,e);if(jr(n),!v(n))return{path:e,content:""};if(I(n).size>x)throw new Error(`File is too large to edit in the admin panel (> ${x/1024} KB).`);return{path:e,content:mt(n,"utf-8")}}function Eu(t,e,n){let i=C(t,e);jr(i);let r=Buffer.from(n,"utf-8");if(r.length>x)throw new Error(`File too large (${r.length} > ${x} bytes).`);return me(yt(i),{recursive:!0}),ht(i,r),{path:e,bytes:r.length}}function Tu(t,e,n={}){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error("Skill slug must be lowercase (letters, digits, -, _) and start with a letter or digit.");let i=`.claude/skills/${e}/SKILL.md`,r=C(t,i);if(v(r))throw new Error(`Skill "${e}" already exists.`);me(yt(r),{recursive:!0});let o=n.content?.trim()?n.content:ha(e,n.title);return ht(r,o),{slug:e,path:i}}function Pu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=C(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);if(!I(n).isDirectory())throw new Error(`Skill path is not a directory: ${e}`);return pa(n,{recursive:!0,force:!0}),{slug:e}}function Lu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=C(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);let i=[];return r(n,"",0,i),i.sort((o,s)=>o.kind!==s.kind?o.kind==="dir"?-1:1:o.path.localeCompare(s.path)),i;function r(o,s,a,c){if(a>ga)return;let l=[];try{l=gt(o)}catch{return}for(let u of l){if(u==="node_modules"||u===".git")continue;let d=O(o,u),p=s?`${s}/${u}`:u,f;try{f=I(d)}catch{continue}if(f.isDirectory())c.push({path:`${p}/`,kind:"dir",size:0,editable:!1}),r(d,p,a+1,c);else if(f.isFile()){let g=J(u).toLowerCase(),h=F.has(g)||F.has(u.toLowerCase());c.push({path:p,kind:"file",size:f.size,editable:h&&f.size<x})}}}}function Mu(t,e,n){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!n||n.includes(".."))throw new Error(`Invalid file path: ${n}`);let i=C(t,`.claude/skills/${e}/${n}`);if(!v(i)||!I(i).isFile())throw new Error(`File not found: ${n}`);let r=J(i).toLowerCase(),o=bt(i).toLowerCase();if(!F.has(r)&&!F.has(o))throw new Error(`File type not editable: ${n}`);if(I(i).size>x)throw new Error(`File too large to edit (> ${x/1024} KB): ${n}`);return{path:n,content:mt(i,"utf-8")}}function Ou(t,e,n,i){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);if(!n||n.includes(".."))throw new Error(`Invalid file path: ${n}`);let r=C(t,`.claude/skills/${e}/${n}`),o=J(r).toLowerCase(),s=bt(r).toLowerCase();if(!F.has(o)&&!F.has(s))throw new Error(`File type not editable: ${n}`);let a=Buffer.from(i,"utf-8");if(a.length>x)throw new Error(`File too large (${a.length} > ${x} bytes).`);return me(yt(r),{recursive:!0}),ht(r,a),{path:n,bytes:a.length}}function Nu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=C(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);let i=r=>v(O(n,r));return i("pnpm-lock.yaml")?{manager:"pnpm",file:"pnpm-lock.yaml",command:"pnpm install"}:i("yarn.lock")?{manager:"yarn",file:"yarn.lock",command:"yarn install"}:i("package.json")?{manager:"npm",file:"package.json",command:"npm install"}:i("requirements.txt")?{manager:"pip",file:"requirements.txt",command:"pip install -r requirements.txt"}:i("Gemfile")?{manager:"bundle",file:"Gemfile",command:"bundle install"}:{manager:null,file:null,command:null}}function ha(t,e){return`# ${e?.trim()||t}
467
-
468
- Describe what this skill does and when the agent should use it. Keep it under ~5 lines \u2014 the agent reads this to decide whether to invoke the skill.
469
-
470
- ## When to use
471
- - Trigger condition 1
472
- - Trigger condition 2
473
-
474
- ## How to use
475
- Document the arguments, commands, or files the skill expects. Example:
476
-
477
- \`\`\`bash
478
- # Example invocation
479
- claude-code ${bt(t)} --arg value
480
- \`\`\`
481
- `}It();var Vr={maxPixels:12e5,timeoutMs:5e3,intervalMs:100,changeThreshold:.015,stableMs:400,regions:{},buffer:{enabled:!1,seconds:10,fps:2,region:"screen",maxPixels:3e5}};function Wr(t){return{...Vr,...t??{},regions:{...t?.regions??{}},buffer:{...Vr.buffer,...t?.buffer??{}}}}function Wu(t){try{return Wr(At(t).screen)}catch{return Wr(void 0)}}var ya=/^[a-z][\w-]*$/,Fr=["window","screen","menubar","notifications"];function Y(t,e,n,i){let r=Number(t);if(t===""||t===null||!Number.isFinite(r)||!n(r))throw new Error(`${e} must be ${i}`);return r}var he=(t,e)=>Y(t,e,n=>Number.isInteger(n)&&n>0,"a whole number above 0");function Ur(t){let e=typeof t=="string"?t.split(",").map(Number):[t?.x,t?.y,t?.width,t?.height].map(Number);if(e.length!==4||!e.every(Number.isFinite)||e[2]<=0||e[3]<=0)throw new Error("a region is x,y,width,height in screen points, with width and height above 0");return{x:e[0],y:e[1],width:e[2],height:e[3]}}function Fu(t,e){let n={...t??{}};if("maxPixels"in e&&(n.maxPixels=he(e.maxPixels,"maxPixels")),"timeoutMs"in e&&(n.timeoutMs=he(e.timeoutMs,"timeoutMs")),"intervalMs"in e&&(n.intervalMs=he(e.intervalMs,"intervalMs")),"stableMs"in e&&(n.stableMs=Y(e.stableMs,"stableMs",r=>Number.isInteger(r)&&r>=0,"a whole number, 0 or more")),"changeThreshold"in e&&(n.changeThreshold=Y(e.changeThreshold,"changeThreshold",r=>r>=0&&r<=1,"between 0 and 1")),e.regions&&typeof e.regions=="object"){let r={...n.regions??{}};for(let[o,s]of Object.entries(e.regions)){if(!ya.test(o))throw new Error(`region name "${o}" must be lowercase letters, digits, - or _`);s===null?delete r[o]:r[o]=Ur(s)}n.regions=r}if(e.buffer&&typeof e.buffer=="object"){let r=e.buffer,o={...n.buffer??{}};"enabled"in r&&(o.enabled=!!r.enabled),"seconds"in r&&(o.seconds=Y(r.seconds,"buffer.seconds",s=>s>0&&s<=120,"above 0 and at most 120")),"fps"in r&&(o.fps=Y(r.fps,"buffer.fps",s=>s>0&&s<=10,"above 0 and at most 10")),"maxPixels"in r&&(o.maxPixels=he(r.maxPixels,"buffer.maxPixels")),"region"in r&&(o.region=String(r.region).trim()),n.buffer=o}let i=n.buffer?.region;if(i!==void 0&&!Fr.includes(i)&&!n.regions?.[i])try{Ur(i)}catch{throw new Error(`buffer.region "${i}" is not a region \u2014 use ${[...Fr,...Object.keys(n.regions??{})].join(", ")}, or x,y,w,h`)}return n}export{Xt as a,ka as b,Ze as c,Fo as d,Uo as e,el as f,tl as g,nl as h,er as i,il as j,sl as k,T as l,tr as m,k as n,$a as o,Ra as p,mi as q,Pa as r,un as s,A as t,ja as u,Va as v,mn as w,za as x,z as y,oc as z,kn as A,nr as B,ll as C,pl as D,hr as E,Vl as F,Wl as G,ql as H,Ls as I,Kl as J,ac as K,cc as L,lc as M,uc as N,dc as O,pc as P,gc as Q,mc as R,$c as S,Le as T,Ac as U,Ic as V,q as W,K as X,Ws as Y,nu as Z,ru as _,iu as $,ou as aa,st as ba,su as ca,Ne as da,je as ea,de as fa,so as ga,co as ha,Ec as ia,We as ja,Fe as ka,lo as la,uo as ma,Wn as na,Hn as oa,Tc as pa,go as qa,Pc as ra,So as sa,Ao as ta,Ue as ua,Ro as va,zn as wa,P as xa,_r as ya,Cr as za,Dr as Aa,pu as Ba,Xs as Ca,Tr as Da,Pr as Ea,vu as Fa,$u as Ga,da as Ha,Au as Ia,Mr as Ja,pe as Ka,zc as La,Yn as Ma,Be as Na,Je as Oa,Zc as Pa,Cu as Qa,Du as Ra,Eu as Sa,Tu as Ta,Pu as Ua,Lu as Va,Mu as Wa,Ou as Xa,Nu as Ya,Vr as Za,Wr as _a,Wu as $a,Fr as ab,Fu as bb};
482
- //# sourceMappingURL=chunk-BWHHZJNJ.js.map