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