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