agentix-cli 0.115.0 → 0.116.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/mac-voice/Sources/AgentXVoice/AnswerView.swift +24 -2
- package/apps/mac-voice/Sources/AgentXVoice/ListenAgain.swift +26 -0
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +54 -0
- package/dist/{App-6OMMZW2M.js → App-7Z2PWARZ.js} +2 -2
- package/dist/{ChatApp-EDDROHNA.js → ChatApp-GFAIRLGZ.js} +2 -2
- package/dist/{agent-VPM3EEUB.js → agent-LXLZGVW3.js} +2 -2
- package/dist/{board-dashboard-4GQ7RTH3.js → board-dashboard-CPCSSVZE.js} +255 -224
- package/dist/board-dashboard-CPCSSVZE.js.map +1 -0
- package/dist/chunk-6LCP6SVR.js +482 -0
- package/dist/chunk-6LCP6SVR.js.map +1 -0
- package/dist/{chunk-MG5LRE5B.js → chunk-7IF3LXAU.js} +2 -2
- package/dist/{chunk-7T7IXLLA.js → chunk-AWQIUI7N.js} +2 -2
- package/dist/{chunk-5FY7PWXW.js → chunk-B65YTB3T.js} +2 -2
- package/dist/chunk-BRL3UPFW.js +2 -0
- package/dist/chunk-BRL3UPFW.js.map +1 -0
- package/dist/{chunk-EVXL6X2R.js → chunk-CCL73Z2P.js} +56 -56
- package/dist/{chunk-EVXL6X2R.js.map → chunk-CCL73Z2P.js.map} +1 -1
- package/dist/{chunk-ECBVOIIK.js → chunk-CKYSGX54.js} +171 -171
- package/dist/chunk-CKYSGX54.js.map +1 -0
- package/dist/chunk-DMHQIACQ.js +3 -0
- package/dist/chunk-DMHQIACQ.js.map +1 -0
- package/dist/{chunk-K3BG77KK.js → chunk-EKOVLUKH.js} +2 -2
- package/dist/{chunk-S4XSVAAG.js → chunk-ELWKTURG.js} +2 -2
- package/dist/chunk-EMGB23H5.js +3 -0
- package/dist/chunk-EMGB23H5.js.map +1 -0
- package/dist/{chunk-IGORU3XR.js → chunk-FBEMUCBO.js} +2 -2
- package/dist/{chunk-IGORU3XR.js.map → chunk-FBEMUCBO.js.map} +1 -1
- package/dist/chunk-GRMCAO3Q.js +2 -0
- package/dist/chunk-GRMCAO3Q.js.map +1 -0
- package/dist/{chunk-CJJULHPJ.js → chunk-HOY2GIKV.js} +4 -4
- package/dist/{chunk-YE4HKOS5.js → chunk-HSYNOMM2.js} +2 -2
- package/dist/{chunk-PITMPRVP.js → chunk-IEZ6OYFJ.js} +2 -2
- package/dist/{chunk-BXYKFWAI.js → chunk-J3SIOMDL.js} +2 -2
- package/dist/{chunk-PX2AOZ5G.js → chunk-JLCJVPRC.js} +2 -2
- package/dist/{chunk-QLB76BGE.js → chunk-KI4CIUVJ.js} +2 -2
- package/dist/{chunk-2NYP4OQU.js → chunk-LNY6N73E.js} +4 -4
- package/dist/{chunk-2NYP4OQU.js.map → chunk-LNY6N73E.js.map} +1 -1
- package/dist/{chunk-KTF4YF4M.js → chunk-R277UDDQ.js} +2 -2
- package/dist/{chunk-4STXRZZS.js → chunk-S56ZGAFM.js} +2 -2
- package/dist/{chunk-SDOSQ6TJ.js → chunk-UUMNP47Q.js} +2 -2
- package/dist/{chunk-UQX2HY5M.js → chunk-WRICEAR6.js} +2 -2
- package/dist/{chunk-J5TZ6QGD.js → chunk-Y3CZE54A.js} +2 -2
- package/dist/{chunk-BU4LE2RT.js → chunk-YMNQYODO.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-VUNPLVCG.js → client-CU5GNTKR.js} +2 -2
- package/dist/{config-HE2LGTTG.js → config-ITVBNUWW.js} +2 -2
- package/dist/config-mutator-5YRHHA2I.js +2 -0
- package/dist/doctor-MLD3XCYE.js +2 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{program-53CQJEUZ.js → program-IBOVOVZI.js} +191 -187
- package/dist/program-IBOVOVZI.js.map +1 -0
- package/dist/{promote-4PPJJ6AW.js → promote-JMJPWZI7.js} +2 -2
- package/dist/push-DID6RZYI.js +2 -0
- package/dist/push-bridge-IFUQLIMF.js +2 -0
- package/dist/push-store-L5QHMSST.js +2 -0
- package/dist/{query-ETDKC7WC.js → query-QGPVKGYY.js} +2 -2
- package/dist/{registry-AMETOJ3S.js → registry-PZNC5XYT.js} +2 -2
- package/dist/{request-planner-VFWWT5XR.js → request-planner-M4IKDZBU.js} +2 -2
- package/dist/{review-candidates-2PI4CGZO.js → review-candidates-6DNRBJZ6.js} +2 -2
- package/dist/routing-7NSB6O2S.js +2 -0
- package/dist/schedule-tool-ZP7H55EL.js +2 -0
- package/dist/scheduler-XV5UQQYH.js +2 -0
- package/dist/{seat-TVNR245I.js → seat-ZRCUQCUP.js} +2 -2
- package/dist/{select-KY7B4HAS.js → select-OLNLTEBR.js} +2 -2
- package/dist/{set-enabled-NEINY2I2.js → set-enabled-LG3ESZDC.js} +2 -2
- package/dist/token-store-AY6OBDVI.js +2 -0
- package/dist/token-store-AY6OBDVI.js.map +1 -0
- package/dist/{tool-MQQ2W5LJ.js → tool-RBXRPIBV.js} +2 -2
- package/dist/{tool-5JGMWH62.js → tool-S6U42ULD.js} +2 -2
- package/dist/wiki-XKQN5CWR.js +2 -0
- package/dist/wiki-XKQN5CWR.js.map +1 -0
- package/package.json +1 -1
- package/dist/board-dashboard-4GQ7RTH3.js.map +0 -1
- package/dist/chunk-2QSG53RN.js +0 -482
- package/dist/chunk-2QSG53RN.js.map +0 -1
- package/dist/chunk-ACFQBLPX.js +0 -3
- package/dist/chunk-ACFQBLPX.js.map +0 -1
- package/dist/chunk-ECBVOIIK.js.map +0 -1
- package/dist/config-mutator-22AVTST2.js +0 -2
- package/dist/doctor-6RDRST4G.js +0 -2
- package/dist/program-53CQJEUZ.js.map +0 -1
- package/dist/push-HEDA6P3B.js +0 -2
- package/dist/push-HEDA6P3B.js.map +0 -1
- package/dist/push-store-5VJ4FNI4.js +0 -2
- package/dist/routing-M7MDLD7Q.js +0 -2
- package/dist/schedule-tool-2EQ53IOQ.js +0 -2
- package/dist/scheduler-YGVINPZF.js +0 -2
- package/dist/token-store-YBSU2DTV.js +0 -2
- package/dist/wiki-COAUQ6TQ.js +0 -2
- /package/dist/{App-6OMMZW2M.js.map → App-7Z2PWARZ.js.map} +0 -0
- /package/dist/{ChatApp-EDDROHNA.js.map → ChatApp-GFAIRLGZ.js.map} +0 -0
- /package/dist/{agent-VPM3EEUB.js.map → agent-LXLZGVW3.js.map} +0 -0
- /package/dist/{chunk-MG5LRE5B.js.map → chunk-7IF3LXAU.js.map} +0 -0
- /package/dist/{chunk-7T7IXLLA.js.map → chunk-AWQIUI7N.js.map} +0 -0
- /package/dist/{chunk-5FY7PWXW.js.map → chunk-B65YTB3T.js.map} +0 -0
- /package/dist/{chunk-K3BG77KK.js.map → chunk-EKOVLUKH.js.map} +0 -0
- /package/dist/{chunk-S4XSVAAG.js.map → chunk-ELWKTURG.js.map} +0 -0
- /package/dist/{chunk-CJJULHPJ.js.map → chunk-HOY2GIKV.js.map} +0 -0
- /package/dist/{chunk-YE4HKOS5.js.map → chunk-HSYNOMM2.js.map} +0 -0
- /package/dist/{chunk-PITMPRVP.js.map → chunk-IEZ6OYFJ.js.map} +0 -0
- /package/dist/{chunk-BXYKFWAI.js.map → chunk-J3SIOMDL.js.map} +0 -0
- /package/dist/{chunk-PX2AOZ5G.js.map → chunk-JLCJVPRC.js.map} +0 -0
- /package/dist/{chunk-QLB76BGE.js.map → chunk-KI4CIUVJ.js.map} +0 -0
- /package/dist/{chunk-KTF4YF4M.js.map → chunk-R277UDDQ.js.map} +0 -0
- /package/dist/{chunk-4STXRZZS.js.map → chunk-S56ZGAFM.js.map} +0 -0
- /package/dist/{chunk-SDOSQ6TJ.js.map → chunk-UUMNP47Q.js.map} +0 -0
- /package/dist/{chunk-UQX2HY5M.js.map → chunk-WRICEAR6.js.map} +0 -0
- /package/dist/{chunk-J5TZ6QGD.js.map → chunk-Y3CZE54A.js.map} +0 -0
- /package/dist/{chunk-BU4LE2RT.js.map → chunk-YMNQYODO.js.map} +0 -0
- /package/dist/{client-VUNPLVCG.js.map → client-CU5GNTKR.js.map} +0 -0
- /package/dist/{config-HE2LGTTG.js.map → config-ITVBNUWW.js.map} +0 -0
- /package/dist/{config-mutator-22AVTST2.js.map → config-mutator-5YRHHA2I.js.map} +0 -0
- /package/dist/{doctor-6RDRST4G.js.map → doctor-MLD3XCYE.js.map} +0 -0
- /package/dist/{promote-4PPJJ6AW.js.map → promote-JMJPWZI7.js.map} +0 -0
- /package/dist/{push-store-5VJ4FNI4.js.map → push-DID6RZYI.js.map} +0 -0
- /package/dist/{query-ETDKC7WC.js.map → push-bridge-IFUQLIMF.js.map} +0 -0
- /package/dist/{registry-AMETOJ3S.js.map → push-store-L5QHMSST.js.map} +0 -0
- /package/dist/{routing-M7MDLD7Q.js.map → query-QGPVKGYY.js.map} +0 -0
- /package/dist/{schedule-tool-2EQ53IOQ.js.map → registry-PZNC5XYT.js.map} +0 -0
- /package/dist/{request-planner-VFWWT5XR.js.map → request-planner-M4IKDZBU.js.map} +0 -0
- /package/dist/{review-candidates-2PI4CGZO.js.map → review-candidates-6DNRBJZ6.js.map} +0 -0
- /package/dist/{scheduler-YGVINPZF.js.map → routing-7NSB6O2S.js.map} +0 -0
- /package/dist/{seat-TVNR245I.js.map → schedule-tool-ZP7H55EL.js.map} +0 -0
- /package/dist/{token-store-YBSU2DTV.js.map → scheduler-XV5UQQYH.js.map} +0 -0
- /package/dist/{wiki-COAUQ6TQ.js.map → seat-ZRCUQCUP.js.map} +0 -0
- /package/dist/{select-KY7B4HAS.js.map → select-OLNLTEBR.js.map} +0 -0
- /package/dist/{set-enabled-NEINY2I2.js.map → set-enabled-LG3ESZDC.js.map} +0 -0
- /package/dist/{tool-MQQ2W5LJ.js.map → tool-RBXRPIBV.js.map} +0 -0
- /package/dist/{tool-5JGMWH62.js.map → tool-S6U42ULD.js.map} +0 -0
package/dist/chunk-2QSG53RN.js
DELETED
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
import{q as Xt}from"./chunk-S2GAEH2F.js";import{a as Re}from"./chunk-GTJIKXDB.js";import{a as re,b as w}from"./chunk-BGG3ZSMW.js";import{t as Gt,u as Kt}from"./chunk-MG5LRE5B.js";import{d as zt,e as qt}from"./chunk-AQASR6KR.js";import{b as Jt,c as Ie,e as B,f as H,h as Yt}from"./chunk-JIT5GPTX.js";import{A as Ae,b as ve,v as Lt,x as ne,y as $e}from"./chunk-5FY7PWXW.js";import{a as Mt,b as Nt}from"./chunk-SHEUCITK.js";import{a as Ut,b as Bt,d as Ht}from"./chunk-Y4CYQV7G.js";import{g as Ot,h as jt,i as Vt,k as Wt,l as Ft}from"./chunk-J5TZ6QGD.js";import{q as Et}from"./chunk-BXYKFWAI.js";import{a as Pt,b as Tt}from"./chunk-PX2AOZ5G.js";import{A as Xr,ba as Se,ia as _t,ja as Ct,ma as Dt,n as te,o as vt,p as $t,q as qr,y as It,z as Rt}from"./chunk-IGORU3XR.js";import{f as At,n as Kr}from"./chunk-UIBUZ2N3.js";import{a as xe,h as Gr}from"./chunk-BRK6M6LA.js";import{existsSync as Jr,readdirSync as Yr,readFileSync as Zr,statSync as Qr}from"fs";import{resolve as ei}from"path";function Zt(t,e,n=Date.now(),r=7){let i=r*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(f=>n-f.at<=i),l=a.filter(f=>n-f.at>i&&n-f.at<=i*2),u=c.filter(f=>f.status==="failed").length,d=a.filter(f=>f.status==="paused").length,p=a.length?Math.max(...a.map(f=>f.at)):null,g=a.length?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:g,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 ie=new Map;function _a(t,e=1e3){if(!Jr(t))return[];let n=Yr(t).filter(s=>s.endsWith(".jsonl")).map(s=>{let o=ei(t,s);return{path:o,mtime:Qr(o).mtimeMs}}).sort((s,o)=>o.mtime-s.mtime).slice(0,e),r=new Set(n.map(s=>s.path));for(let s of ie.keys())r.has(s)||ie.delete(s);let i=[];for(let{path:s,mtime:o}of n){let a=ie.get(s);if(a&&a.mtime===o){a.summary&&i.push(a.summary);continue}let c=ti(s,o);ie.set(s,{mtime:o,summary:c}),c&&i.push(c)}return i}function ti(t,e){try{let n=Zr(t,"utf-8").split(`
|
|
2
|
-
`).filter(Boolean);if(!n.length)return null;let r=JSON.parse(n[0]),i=r.run?.workflowId;if(!i)return null;let s=r.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:i,status:s,at:e}}catch{return null}}var ni={failStreak:3,disabledDays:30,missedFires:2,graceMs:15*6e4},k={routines:200,summary:160,filters:6,filterValue:60,text:120},ri=(t,e,n)=>{try{return Et(t,e,n)}catch{return null}},Qt=864e5;function Ta(t){let e=t.now??Date.now(),n={...ni,...t.thresholds},r=t.nextFire??ri,i=[];for(let a of t.crons){let c=t.cronRuns.get(a.id)??[],l=a.timezone||"UTC",u=c.map(g=>({at:Date.parse(g.startedAt),status:g.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?_e(a.nextRun)??_e(r(a.schedule,new Date(e),l)):null,lastRun:d?{at:d.startedAt,status:d.status,summary:li(d.status==="success"?void 0:d.errorSummary,k.summary)}:null,lastSuccessAt:c.find(g=>g.status==="success")?.startedAt??null,consecutiveFailures:en(u),sampledRuns:c.length,flags:[],attention:null};p.flags=tn(p,u,a.schedule,l,null,e,n,r),i.push(nn(p))}let s=new Map(Zt(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(_=>_.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((_,ke)=>ke.at-_.at),g=p.map(_=>({at:_.at,status:oi(_.status)})),f=g[0],m=c.type==="trigger.cron",y=typeof l.spec=="string"?l.spec:"",P=typeof l.timezone=="string"?l.timezone:"UTC",j={id:`workflow:${a.id}`,source:"workflow",kind:m?"schedule":"event",name:$(a.title||a.id,k.text),trigger:m?{schedule:$(y,k.text),timezone:P}:{event:$(typeof l.event=="string"?l.event:"",k.text),filters:ci(l.filter,a)},agent:ai(a),enabled:d,state:u,nextRunAt:m&&d&&y?_e(r(y,new Date(e),P)):null,lastRun:f?{at:new Date(f.at).toISOString(),status:f.status}:null,lastSuccessAt:(()=>{let _=g.find(ke=>ke.status==="success");return _?new Date(_.at).toISOString():null})(),consecutiveFailures:en(g),sampledRuns:p.length,flags:[],attention:null},ee=Date.parse(a.updated||a.created||"");j.flags=m?tn(j,g,y,P,Number.isFinite(ee)?ee:null,e,n,r):ii(j,s.get(a.id)?.state==="dormant",Number.isFinite(ee)?ee:null,e,n),i.push(nn(j))}return i.sort(si).slice(0,k.routines)}function en(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 tn(t,e,n,r,i,s,o,a){let c=[],l=e.length?e[0].at:null;if(!t.enabled){let p=sn(l,i,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,r),!!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 ii(t,e,n,r,i){let s=[],o=t.lastRun?Date.parse(t.lastRun.at):null;if(!t.enabled){let a=sn(o,n,r,i);return a&&s.push(a),s}return t.consecutiveFailures>=i.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 sn(t,e,n,r){let i=Math.max(t??0,e??0);return i&&n-i<r.disabledDays*Qt?null:{reason:"disabled-long",detail:i?`Disabled; no activity for ${Math.floor((n-i)/Qt)} days`:"Disabled and never ran"}}function nn(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 rn={critical:0,warning:1,info:2};function si(t,e){let n=t.attention?rn[t.attention]:3,r=e.attention?rn[e.attention]:3;return n-r||Number(e.enabled)-Number(t.enabled)||t.name.localeCompare(e.name)}function oi(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 ai(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 ci(t,e){let n=[],r=e?.project;if(r&&n.push($(`project=${r}`,k.filterValue)),t&&typeof t=="object"&&!Array.isArray(t))for(let[i,s]of Object.entries(t)){let o=Array.isArray(s)?s.map(String):s==null?[]:[String(s)];o.length&&n.push($(`${i}=${o.join(",")}`,k.filterValue))}return n.slice(0,k.filters)}function _e(t){if(!t)return null;let e=t instanceof Date?t:new Date(t);return Number.isFinite(e.getTime())?e.toISOString():null}function $(t,e){return t.length<=e?t:t.slice(0,e-3)+"..."}function li(t,e){return t===void 0?void 0:$(t,e)}import{existsSync as ae,readdirSync as Ri,readFileSync as _i}from"fs";import{resolve as T}from"path";import{randomBytes as cn}from"crypto";import{existsSync as di,mkdirSync as pi,readdirSync as gi,readFileSync as fi,renameSync as ln,unlinkSync as mi,writeFileSync as hi}from"fs";import{resolve as un}from"path";function on(t){return[...t.account?["--account",t.account]:[],...t.store?["--store",t.store]:[]]}var ui=t=>t.trim().split(`
|
|
3
|
-
`).pop()?.slice(0,300)||"no output";async function an(t,e,n,r=Re){let i=await r(t.bin,[...on(t),"send","text","--to",e,"--message",n,"--no-preview"],{timeoutMs:6e4});return i.code===0?{ok:!0}:{ok:!1,error:`wacli send failed: ${ui(i.stderr||i.stdout)}`}}async function Ma(t,e,n,r,i=Re){return(await i(t.bin,[...on(t),"--read-only","media","download","--chat",e,"--id",n,"--output",r],{timeoutMs:12e4})).code===0}var yi=2e3,bi=t=>an(t.wacli,t.to,t.text);function Ce(t){return un(t,".agentx","whatsapp-triage","drafts")}var wi=t=>/^[a-z0-9-]{8,64}$/.test(t),se=(t,e)=>un(Ce(t),`${e}.json`);function dn(t,e){pi(Ce(t),{recursive:!0});let n=se(t,e.id),r=`${n}.${process.pid}.tmp`;hi(r,JSON.stringify(e,null,2)+`
|
|
4
|
-
`,{mode:384}),ln(r,n)}function Fa(t,e,n=Date.now()){let r=e.text.trim().slice(0,yi);if(!r)throw new Error("empty draft");let i={...e,text:r,id:`${n.toString(36)}-${cn(4).toString("hex")}`,status:"pending",created_at:new Date(n).toISOString()};return dn(t,i),i}function oe(t,e){if(!wi(e))return null;try{return JSON.parse(fi(se(t,e),"utf-8"))}catch{return null}}function pn(t,e){let n=Ce(t);return di(n)?gi(n).filter(r=>r.endsWith(".json")).map(r=>oe(t,r.slice(0,-5))).filter(r=>!!r&&(!e||r.status===e)).sort((r,i)=>r.created_at.localeCompare(i.created_at)):[]}async function gn(t,e,n,r={}){let i=oe(t,e);if(!i||i.status!=="pending")return{ok:!1,error:`no reply draft "${e}" is waiting`};let s=`${se(t,e)}.${process.pid}.${cn(3).toString("hex")}.claim`;try{ln(se(t,e),s)}catch{return{ok:!1,error:`reply draft "${e}" is already being decided`}}let o={...i,decided_by:r.by??"operator",decided_at:new Date(r.now??Date.now()).toISOString()};if(n==="no")o.status="rejected";else{let a=await(r.send??bi)(i).catch(c=>({ok:!1,error:String(c?.message??c)}));a.ok?o.status="sent":(o.status="failed",o.error=a.error)}dn(t,o);try{mi(s)}catch{}return o.status==="failed"?{ok:!1,error:o.error??"send failed"}:{ok:!0,draft:o}}import{mkdirSync as ki,readFileSync as xi,renameSync as Si,writeFileSync as vi}from"fs";import{resolve as $i}from"path";function fn(t){return $i(Ie(t),"_state.json")}function A(t){try{let e=JSON.parse(xi(fn(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 z(t,e){ki(Ie(t),{recursive:!0});let n=fn(t),r=`${n}.${process.pid}.tmp`;vi(r,JSON.stringify(e,null,2)+`
|
|
5
|
-
`),Si(r,n)}function mn(t,e,n,r=Date.now()){let i=A(t),s={};for(let[o,a]of Object.entries(i.snoozed))Date.parse(a)>r&&(s[o]=a);s[e]=n.toISOString(),z(t,{...i,snoozed:s})}function qa(t,e){z(t,{...A(t),lastDigest:e})}function hn(t,e,n,r=Date.now()){let i=A(t),s=new Set(n),o={};for(let[c,l]of Object.entries(i.popped??{}))s.has(c)&&(o[c]=l);o[e]=new Date(r).toISOString();let a=(i.wanted??[]).filter(c=>c!==e&&s.has(c));z(t,{...i,popped:o,wanted:a})}function yn(t,e){let n=A(t);z(t,{...n,wanted:[...(n.wanted??[]).filter(r=>r!==e),e]})}function Ga(t,e=Date.now()){z(t,{...A(t),popped:{},passAt:new Date(e).toISOString()})}Kr();Xr();import{existsSync as Ai,readFileSync as Ii}from"fs";Dt();Gr();function bn(t){let e=Pt(t),n={};if(Ai(e))try{n=_t(JSON.parse(Ii(e,"utf-8")))}catch{n={}}let r=Se.safeParse(n?.requests);return r.success?r.data:Se.parse(void 0)}async function Qa(t,e={}){let n=(t.channels??[]).filter(r=>!xe.has(r.toLowerCase().split("@")[0]));return n.length?{success:!1,error:`unknown channel ${n.map(r=>`"${r}"`).join(", ")}: use ${[...xe].join(", ")}`}:Tt(r=>{let i=r.requests??={};for(let s of["enabled","channels","from","staleAfterHours","retentionDays"])t[s]!==void 0&&(i[s]=t[s])},{configPath:e.configPath,reload:e.reload})}var kn=["card","schedule","memory","wiki","whatsapp","request"],Ci=280;function M(t,e=Ci){let n=t.replace(/\s+/g," ").trim();return n.length>e?`${n.slice(0,e-1)}\u2026`:n}function De(t){if(t.configPath)return T(t.configPath);let e=[T(t.root,"agentx.json"),T(t.root,".agentx","config.json")];return e.find(n=>ae(n))??e[0]}function Pe(t){return t.wikiDir?T(t.wikiDir):T(t.root,".agentx","wiki")}function Di(t){return H(t.root,"pending").map(Pi)}function Pi(t){return{key:`card:${t.id}`,kind:"card",title:t.title,ask:t.ask,yes:`tell ${t.raised_by} yes`,no:`tell ${t.raised_by} no`,recommend:t.recommend,if_silent:t.if_silent,expires:t.expires,...t.source?{source:t.source}:{},raised_by:t.raised_by,...t.node?{node:t.node}:{},created_at:t.created_at,...t.choices?{choices:t.choices,more:`agentx approvals popup card:${t.id}`}:{},...t.context||t.draft?{detail:M([t.context,t.draft?`Suggested message: ${t.draft}`:""].filter(Boolean).join(" \xB7 "))}:{}}}function Ti(t){let e=De(t);if(!ae(e))return[];let n;try{n=JSON.parse(_i(e,"utf-8"))}catch{return[]}let r=new Date(t.now??Date.now()),i=[];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?Ot(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";i.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:M(`${d}${p&&o.schedule?` \xB7 first run ${Vt(jt(o.schedule,c,r),c)}`:""}`),more:"agentx schedule list"})}return i}function xn(t){let e=T(t,".agentx","memory");return ae(e)?Ri(e).filter(n=>n.endsWith(".jsonl")).map(n=>n.slice(0,-6)).sort():[]}function Ei(t){let e=xn(t.root);if(e.length===0)return[];let n=new ve(t.root),r=[];for(let i of e)for(let s of n.held(i))r.push({key:`memory:${i}/${s.id}`,kind:"memory",title:`Fact ${i} learned from ${s.source.channel}`,ask:`Let ${i} use this fact in its prompts?`,yes:"use it",no:"keep it out for good",raised_by:i,created_at:s.createdAt,detail:M(s.content),more:`agentx memory facts held --agent ${i}`});return r}function Li(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 Mi(t){return qt(Pe(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:M(`${Li(n)} ${e.article.content}`),more:`agentx wiki proposals show ${e.id}`}})}function Ni(t){return pn(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:M(`${e.triage}: ${e.summary}`),more:"agentx whatsapp triage log"}))}function q(t){if(t.requests)return t.requests;if(T(t.root)!==process.cwd()||!ae(T(t.root,".agentx","db.sqlite")))return null;let e=At({quiet:!0});if(!e)return null;let n=wn.get(e);return!n&&!It(e)?null:(n||wn.set(e,n=new Rt(e)),n)}var wn=new WeakMap;function Oi(t){let e=q(t);return e?e.listByState("needs_attention").map(n=>({key:`request:${n.id}`,kind:"request",title:`Request not finished: ${M(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:M(`${n.attentionReason??"It needs attention"}. Asked on ${n.channel}: ${n.text}`),more:`agentx requests show ${n.id}`})):[]}var Sn={card:Di,schedule:Ti,memory:Ei,wiki:Mi,whatsapp:Ni,request:Oi};function ji(t,e){let n=t.expires?Date.parse(t.expires):1/0,r=e.expires?Date.parse(e.expires):1/0;return n!==r?n-r:(Date.parse(t.created_at)||0)-(Date.parse(e.created_at)||0)}function gc(t,e={}){let n=t.now??Date.now(),{snoozed:r}=A(t.root),i=[],s=[],o=0;for(let a of e.kinds??kn){let c;try{c=Sn[a](t)}catch(l){s.push({kind:a,error:String(l?.message??l).slice(0,200)});continue}for(let l of c){let u=r[l.key];if(u&&Date.parse(u)>n){if(!e.includeSnoozed){o++;continue}l.snoozed_until=u}i.push(l)}}return i.sort(ji),{items:i,snoozed:o,errors:s}}function Vi(t){let e=t.indexOf(":");if(e<=0)return null;let n=t.slice(0,e),r=t.slice(e+1);return!kn.includes(n)||!r?null:{kind:n,ref:r}}function Wi(t,e,n){switch(e){case"card":return B(t.root,n)?.status==="pending";case"wiki":return zt(Pe(t),n)?.status==="pending";case"whatsapp":return oe(t.root,n)?.status==="pending";default:return Sn[e](t).some(r=>r.key===`${e}:${n}`)}}async function vn(t,e,n,r={}){let i=Vi(e);if(!i)return{ok:!1,error:`unknown item "${e}": use a key from \`agentx approvals list\``};let{kind:s,ref:o}=i,a=t.now??Date.now(),c=r.by??"operator";if(n==="later"){if(!Wi(t,s,o))return{ok:!1,error:`nothing waiting for "${e}"`};let u=r.laterHours&&r.laterHours>0?r.laterHours:24,d=new Date(a+u*36e5);return mn(t.root,e,d,a),{ok:!0,message:`${e} put off until ${d.toISOString()}`}}let l=n==="yes";switch(s){case"card":{let u=Yt(t.root,o,l?"yes":"no",{by:c,note:r.note,now:a,choice:r.choice,text:r.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?Wt:Ft)(o,{configPath:De(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(!xn(t.root).includes(d))return{ok:!1,error:`no memory for agent "${d}"`};let g=new ve(t.root);return g.held(d).some(f=>f.id===p)?(g.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=Pe(t),d=l?Gt(u,o,{by:c,force:r.force,now:a}):Kt(u,o,{by:c,reason:r.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 gn(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=q(t),d=u?.get(o);return!u||!d||d.state!=="needs_attention"?{ok:!1,error:`nothing waiting for "${e}"`}:l?bn(De(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",r.note?.trim()||`dropped by ${c}`,a),{ok:!0,message:`${e}: dropped`})}}}var $n=new Set(["127.0.0.1","::1","::ffff:127.0.0.1"]);function mc(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 hc(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 yc(t){return $n.has(t)}function bc(t){if(t.foreignBrowser)return{allowed:!1,reason:"foreign-browser-origin"};if(t.enforcementDisabled)return{allowed:!0,reason:"disabled"};if($n.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 wc(t,e=process.env){let n=new Set;e.MESH_TOKEN&&n.add(e.MESH_TOKEN);for(let r of t.mesh?.peers||[])r.token&&n.add(r.token);return n}function kc(t,e,n=process.env){let r=s=>s.replace(/\/+$/,"");return(e===r(t.daemonUrl)?t.token:t.daemons.find(s=>r(s.url)===e)?.token)||n.MESH_TOKEN||void 0}function ce(t){return(Array.isArray(t)?t[0]:t)?.trim()??""}function Fi(t){try{return new URL(t).host.toLowerCase()}catch{return null}}function Ui(t=process.env){return new Set((t.AGENTX_ALLOWED_ORIGINS||"").split(",").map(e=>e.trim().replace(/\/+$/,"").toLowerCase()).filter(Boolean))}function Sc(t,e=Ui()){let n=ce(t.origin);if(n){if(e.has(n.replace(/\/+$/,"").toLowerCase()))return"same-origin";let i=Fi(n),s=[ce(t.host),ce(t["x-forwarded-host"])].filter(Boolean).map(o=>o.toLowerCase());return i&&s.includes(i)?"same-origin":"foreign"}let r=ce(t["sec-fetch-site"]).toLowerCase();return r==="cross-site"||r==="same-site"?"foreign":"none"}function vc(t){let e=(t||"GET").toUpperCase();return e!=="GET"&&e!=="HEAD"}import{existsSync as Xn,mkdirSync as ys,readFileSync as bs,renameSync as ws,writeFileSync as ks}from"fs";import{homedir as xs}from"os";import{dirname as Ss,join as vs}from"path";import{execFile as Qi,execFileSync as es}from"child_process";import{execFileSync as Bi}from"child_process";import{existsSync as In,mkdirSync as Hi,readdirSync as zi,readFileSync as Rn,renameSync as qi,writeFileSync as Gi}from"fs";import{homedir as _n}from"os";import{join as Ee}from"path";var S="siri:",Cn="com.apple.ttsbundle.gryphon-neural_",Dn=t=>!!t&&t.startsWith(Cn),Ki=["/usr/bin/say","/usr/bin/defaults","/usr/bin/plutil"],Xi=()=>{try{return Bi("/usr/bin/defaults",["read","com.apple.Accessibility"],{stdio:"ignore",timeout:5e3}),!0}catch{return!1}},Te;function Le(t={}){let e=t.platform!==void 0||t.exists!==void 0||t.prefDomain!==void 0;if(!e&&Te!==void 0)return Te;let{platform:n=process.platform,exists:r=In,prefDomain:i=Xi}=t,s=n==="darwin"&&Ki.every(o=>r(o))&&i();return e||(Te=s),s}var Pn=["/System/Library/AssetsV2/com_apple_MobileAsset_Trial_Siri_SiriTextToSpeech/purpose_auto","/System/Library/AssetsV2/com_apple_MobileAsset_UAF_Siri_TextToSpeech/purpose_auto"],Tn={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"},Me=t=>Tn[t.toLowerCase()]??null;function le(t){let e=/^com\.apple\.ttsbundle\.gryphon-neural_([a-z]+)_([a-z]{2}-[A-Z]{2})_premium$/.exec(t);return e?{name:e[1],locale:e[2]}:null}var Ji=/com\.apple\.siri\.tts\.voice\.([a-z]{2})_([A-Z]{2})\.([a-z]+)\.neural\.premium/g;function Yi(t){let e=new Map;for(let n of t)for(let[,r,i,s]of n.matchAll(Ji)){let o=`${r}-${i}`,a=`${Cn}${s}_${o}_premium`;e.has(a)||e.set(a,{id:a,name:s[0].toUpperCase()+s.slice(1),locale:o,quality:"premium",gender:Tn[s]??null,siri:!0})}return[...e.values()]}function ue(t=Pn,e={}){if(!Le(e))return[];let n=[];for(let r of t){let i;try{i=zi(r)}catch{continue}for(let s of i)try{n.push(Rn(Ee(r,s,"Info.plist"),"latin1"))}catch{}}return Yi(n)}var An=`#!/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:-"${Pn.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
|
-
`,Zi=(t=_n())=>Ee(t,".agentx","voice","siri-say.sh");function En(t=_n()){let e=Zi(t);return In(e)&&Rn(e,"utf8")===An||(Hi(Ee(t,".agentx","voice"),{recursive:!0}),Gi(`${e}.tmp`,An,{mode:493}),qi(`${e}.tmp`,e)),e}var Ln=`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")`,ts=new Set(["Fred","Kathy","Ralph","Junior"]),ns={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 Mn(t){let e=[];for(let n of t.split(`
|
|
117
|
-
`)){let[r,i,s,o,a]=n.split(" ");!r||!i||!s||r.includes(".siri_")||r.startsWith("com.apple.speech.synthesis.voice.")&&!ts.has(i)||e.push({id:r,name:i,locale:s,quality:o==="3"?"premium":o==="2"?"enhanced":"standard",gender:a==="1"?"male":a==="2"?"female":ns[i]??null})}return e}var rs=10*60*1e3,Tc=60*1e3,V=null,Ne=!1;function Oe(t=Date.now(),e=rs){if(process.platform!=="darwin")return[];if(V)t-V.at>e&&!Ne&&(Ne=!0,Qi("osascript",["-l","JavaScript","-e",Ln],{timeout:1e4},(n,r)=>{Ne=!1,n||(V={at:Date.now(),voices:[...Mn(String(r)),...ue()]})}));else try{V={at:t,voices:[...Mn(es("osascript",["-l","JavaScript","-e",Ln],{encoding:"utf8",timeout:1e4})),...ue()]}}catch(n){je(`[voice] could not list system voices: ${String(n?.message??n).split(`
|
|
118
|
-
`)[0]}`),V={at:t,voices:ue()}}return V.voices}var je=t=>process.stderr.write(t+`
|
|
119
|
-
`),de=new Set;function Ec(t){je=t}function N(t,e){de.has(t)||(de.add(t),je(e))}function jn(t){for(let e of de)t(e)&&de.delete(e)}var Vn=()=>{};function Lc(t){Vn=t}function Wn(t){try{Vn(t)}catch(e){N("missing-hook",`[voice] missing-voice check failed: ${e?.message??e}`)}}var is={premium:3,enhanced:2,standard:1},ss=new Set(["Grandma","Grandpa"]);function Nn(t){let e=t.id.startsWith("com.apple.voice.")?2:t.id.startsWith("com.apple.eloquence.")&&!ss.has(t.name)?1:0;return is[t.quality]*10+e}var W=t=>t.toLowerCase().split(/[-_]/)[0],On=t=>t.id.startsWith("com.apple.voice.");function Ve(t,e,n,r=new Set){let i=G(t.filter(a=>!a.siri&&W(a.locale)===W(e)),e);if(i.some(On)&&(i=i.filter(On)),n==="female"||n==="male"){let a=i.filter(c=>c.gender===n);a.length&&(i=a)}if(!i.length)return null;let s=i.filter(a=>a.quality===i[0].quality),o=new Set([...r].map(a=>a.toLowerCase()));return s.find(a=>!o.has(a.name.toLowerCase()))??s[0]}function G(t,e="en"){let n=e.toLowerCase().replace("_","-"),r=W(e),i=t.filter(s=>W(s.locale)===r);return(i.length?i:t).slice().sort((s,o)=>Nn(o)-Nn(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 r=t.trim();if(!r)return null;let i=e.find(l=>l.id===r);if(i)return i;if(r.toLowerCase().startsWith(S)){let l=r.slice(S.length).trim().toLowerCase(),u=G(e.filter(p=>p.siri&&p.name.toLowerCase()===l),n)[0];if(u||!l)return u??null;let d=K(l,e.filter(p=>W(p.locale)===W(n)),n);return d&&N(`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(r),o=(s?s[1]:r.replace(/\s*\(.*\)\s*$/,"")).trim().toLowerCase(),a=G(e.filter(l=>l.name.toLowerCase()===o),n);return(s?a.find(l=>l.quality===s[2].toLowerCase()):void 0)??a[0]??null}function Fn(t,e,n=new Set){let r=new Map;if(!e.length)return r;let i=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=>!i.has(d.name.toLowerCase())),u=l.find(d=>d.gender===c)??(a?e.find(d=>d.gender===c):void 0)??l[0]??e[r.size%e.length];r.set(o.id,u),i.add(u.name.toLowerCase()),a||(s=s==="female"?"male":"female")}return r}vt();var We="system",os=t=>t.trim().toLowerCase()===We,as="21m00Tcm4TlvDq8ikWAM";function Fe(t,e,n={},r=Oe()){let i=e[t],s=i?.name||t,o=i?.voice,a=Be(e,n,r).get(t)??null,c=ds(t,o?.system,o?.gender,n,r);return{agentId:t,name:s,provider:o?.provider??n.provider??"system",elevenlabsVoiceId:o?.elevenlabsVoiceId||null,systemVoice:a?.id??null,systemVoiceName:a?ge(a):null,systemByLanguage:c,fallback:(n.fallback??"system")==="system",gender:o?.gender??null,style:o?.style||null,intro:o?.intro||gs(s,i?.systemPrompt),...o?.rate?{rate:o.rate}:{},...o?.priority?{priority:o.priority}:{}}}var ge=t=>`${t.name}${t.siri?" (Siri)":t.quality==="standard"?"":` (${t.quality[0].toUpperCase()}${t.quality.slice(1)})`} ${t.locale}`;function cs(t,e,n,r){if(!e||!n.length)return null;let i=K(e,n,r);return i||(N(`${t}:${e}`,`[voice] ${t}: system voice "${e}" is not installed; using the next choice. Run \`agentx voice list\` to see installed voices.`),Wn(e)),i}function zn(t,e){let n=t.trim();if(n.toLowerCase().startsWith(S))return{locale:e,gender:Me(n.slice(S.length).trim())};let r=le(n);return r?{locale:r.locale,gender:Me(r.name)}:{locale:/^com\.apple\.voice\.[a-z]+\.([a-z]{2}-[A-Z]{2})\./.exec(n)?.[1]??e,gender:null}}var qn=t=>t.toLowerCase().split(/[-_]/)[0],Un=(t,e)=>typeof t=="string"?t:t?.[qn(e)];function pe(t,e,n,r){if(e!==void 0)return os(e)?null:cs(t,e,n,r)??void 0}var Ue=(t,e)=>!t||!t.gender||t.gender==="neutral"||!e||e==="neutral"||t.gender===e;function ls(t,e,n,r=new Set){let i=e.locale??"en",s=new Map,o=[],a=pe("voice.system",Un(e.system,i),n,i),c=()=>new Set([...r,...[...s.values()].flatMap(u=>u?[u.name]:[])]);for(let u of t){let d=Un(u.system,i),p=pe(u.id,d,n,i),g=p!==void 0?p:d!==void 0&&n.length?us(u,d,i,a,n,c()):a!==void 0&&Ue(a,u.gender)?a:void 0;g!==void 0?s.set(u.id,g):o.push({id:u.id,gender:u.gender??null})}let l=c();for(let[u,d]of Fn(o,G(n.filter(p=>!p.siri),i),l))s.set(u,d);return s}function us(t,e,n,r,i,s){for(let a of t.fallbacks??[]){let c=pe(`${t.id}.fallbacks`,a,i,n);if(c!==void 0)return c}if(r!==void 0&&Ue(r,t.gender))return r;let o=zn(e,n);return Ve(i,o.locale,t.gender??o.gender,s)??void 0}function ds(t,e,n,r,i){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=pe(`${a}.${u}`,d,i,u);p===void 0&&i.length&&(p=Ve(i,u,n??zn(d,u).gender)??void 0),p!==void 0&&l(p)&&(s[qn(u)]=p)}};return o("voice.system",r.system,a=>Ue(a,n)),o(t,e,()=>!0),s}function Vc(t,e){let n=e?te(e):null;if(!n||!(n in t.systemByLanguage))return t;let r=t.systemByLanguage[n];return{...t,systemVoice:r?.id??null,systemVoiceName:r?ge(r):null}}function Be(t,e={},n=Oe()){let r=Object.entries(t).map(([i,s])=>({id:i,system:s.voice?.system,gender:s.voice?.gender,fallbacks:s.voice?.fallbacks}));return ls(r,e,n)}function He(t,e){let n={provider:t.provider,elevenlabs:ps(e,t.elevenlabsVoiceId),system:t.systemVoice,fallback:t.fallback},r=Object.entries(t.systemByLanguage??{});return r.length&&(n.languages=Object.fromEntries(r.map(([i,s])=>[i,s?.id??null]))),t.rate&&t.rate!==1&&(n.rate=t.rate),t.priority&&t.priority!=="normal"&&(n.priority=t.priority),n}function ps(t,e){return t||e||process.env.AGENTX_VOICE_ID||as}function gs(t,e){let n=(e??"").split(/(?<=\.)\s/)[0]??"",r=/^You are (.+?)\.?$/i.exec(n.trim());if(!r)return`Hello, this is ${t}.`;let i=r[1].replace(/\s*\([^)]*\)/g,"").trim(),[s,...o]=i.split(/,\s*/),a=o.join(", ");return a&&s.toLowerCase()===t.toLowerCase()?`Hello, this is ${t}, ${a}.`:!/^an? /i.test(i)&&i.toLowerCase().includes(t.toLowerCase())?`Hello, this is ${i}.`:`Hello, this is ${t}, ${i}.`}var fs=8*60*60*1e3,ms=500,Bn=class{constructor(e=fs){this.gapMs=e}lastSpoke=new Map;needsIntro(e,n,r=Date.now()){let i=this.lastSpoke.get(Hn(e,n));return i===void 0||r-i>this.gapMs}spoke(e,n,r=Date.now()){let i=Hn(e,n);this.lastSpoke.delete(i),this.lastSpoke.set(i,r),this.lastSpoke.size>ms&&this.lastSpoke.delete(this.lastSpoke.keys().next().value)}},Hn=(t,e)=>`${t}\0${e}`;function Gn(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 Wc(t,e,n,r={}){let i=e[t],s=Fe(t,e,r),o=(i?.systemPrompt??"").split(/\n\s*\n/)[0].slice(0,600).trim();return{agentId:t,name:s.name,voice:He(s),persona:o||`You are ${s.name}.`,introLine:Gn(s,n)}}var hs="[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 Fc(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):"",r=n(e.voice.intro),i={agentId:"",name:"",provider:"system",elevenlabsVoiceId:null,systemVoice:null,systemVoiceName:null,systemByLanguage:{},fallback:!0,gender:null,style:n(e.voice.style)||null,intro:r||"Hello."};return`${hs}
|
|
120
|
-
${Gn(i,e.voice.introduce===!0&&!!r)}`}var $s="System Settings \u203A Accessibility \u203A Spoken Content \u203A System voice \u203A Manage Voices",Jn=(t=xs())=>vs(t,".agentx","voice","health.json");function As(t,e,n){let r=t.trim();if(!r||r.toLowerCase()===We)return!0;if(r.toLowerCase().startsWith(S)){let i=r.slice(S.length).trim().toLowerCase();return e.some(s=>s.siri&&s.name.toLowerCase()===i)}return K(r,e,n)!==null}function Is(t){let e=t.voice?.locale??"en",n=[],r=(i,s)=>{if(typeof s=="string")n.push({owner:i,name:s,locale:e,perLanguage:!1});else for(let[o,a]of Object.entries(s??{}))n.push({owner:i,name:a,locale:o,perLanguage:!0})};r("voice.system",t.voice?.system);for(let[i,s]of Object.entries(t.agents))(s.voice?.provider??t.voice?.provider??"system")!=="system"&&t.voice?.fallback==="none"||r(i,s.voice?.system);return n}function Rs(t,e){if(!e.length)return[];let n=new Map,r;for(let{owner:i,name:s,locale:o,perLanguage:a}of Is(t)){if(As(s,e,o))continue;r??=Be(t.agents,t.voice,e);let c=n.get(s)??{voice:s,agents:[],speaksWith:{}};c.agents.includes(i)||c.agents.push(i);let l=r.get(i);i!=="voice.system"&&!a&&(c.speaksWith[i]=l?ge(l):"the OS default voice"),n.set(s,c)}return[...n.values()]}function ze(t){let e=le(t);if(e)return`Siri ${e.name[0].toUpperCase()}${e.name.slice(1)} (${e.locale})`;if(t.toLowerCase().startsWith(S)){let n=t.slice(S.length).trim();return`Siri ${n[0]?.toUpperCase()??""}${n.slice(1)}`}return t}function _s(t){let e=t.map(n=>{let r=n.agents.map(i=>n.speaksWith[i]?`${i} (now ${n.speaksWith[i]})`:i).join(", ");return`\u2022 ${ze(n.voice)}: ${r}`});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 ${$s}. Agents switch back on their own once it is installed.`}}function Cs(t=Jn()){if(!Xn(t))return null;try{let e=JSON.parse(bs(t,"utf8"));return e&&Array.isArray(e.missing)?e:null}catch{return null}}function Ds(t,e){ys(Ss(t),{recursive:!0}),ks(`${t}.tmp`,JSON.stringify(e,null,2)+`
|
|
123
|
-
`),ws(`${t}.tmp`,t)}var Kn=class{constructor(e){this.deps=e}running=!1;missingNow=!1;hasMissing(){return this.missingNow}async check(e,n,r=new Date){if(this.running||!n.length)return null;this.running=!0;try{let i=this.deps.file??Jn(),s=new Map((Cs(i)?.missing??[]).map(d=>[d.voice,d])),o=Rs(e,n),a=o.map(d=>({...d,since:s.get(d.voice)?.since??r.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] ${ze(d)} is installed again; its agents speak with it again`);c.length&&jn(d=>c.some(p=>d===p||d.endsWith(`:${p}`)));let l=a.filter(d=>!d.notifiedAt);if(l.length){let{title:d,message:p}=_s(l);try{await this.deps.notify(d,p);for(let g of l)g.notifiedAt=r.toISOString();this.deps.log(`[voice] told the owner: ${l.map(g=>ze(g.voice)).join(", ")} not installed`)}catch(g){this.deps.log(`[voice] could not send the missing-voice notice: ${g?.message??g}`)}}this.missingNow=a.length>0;let u={checkedAt:r.toISOString(),missing:a};return(!Xn(i)||JSON.stringify(a)!==JSON.stringify([...s.values()]))&&Ds(i,u),u}finally{this.running=!1}}};import{readFileSync as Ge,writeFileSync as nr,existsSync as Ke,readdirSync as Vs,statSync as Ws}from"fs";import{resolve as Xe,join as Fs}from"path";import{existsSync as Yn,mkdirSync as Ps,readFileSync as Ts,writeFileSync as Zn}from"fs";import{dirname as Es,resolve as Qn}from"path";import{z as h}from"zod";var Ls=h.object({type:h.enum(["gitlab","github"]),host:h.string().optional(),project:h.string(),iid:h.number().int().positive(),url:h.string()}),Ms=h.object({id:h.string(),title:h.string(),description:h.string().optional(),assignee:h.string().optional(),labels:h.array(h.string()).default([]),milestone:h.string().optional(),status:h.enum(["todo","doing","blocked","done"]).default("todo"),priority:h.number().int().optional(),estimatedSeconds:h.number().int().optional(),source:Ls.optional(),importedAt:h.string().optional(),createdAt:h.string(),updatedAt:h.string(),blocker:h.string().optional(),doneNote:h.string().optional()}),Ns=h.object({version:h.literal(1),items:h.array(Ms).default([])}),fe=class{constructor(e){this.path=e}jsonPath(){return Qn(process.cwd(),this.path).replace(/\.md$/i,".json")}mdPath(){return Qn(process.cwd(),this.path).replace(/\.json$/i,".md")}exists(){return Yn(this.jsonPath())}load(){let e=this.jsonPath();if(!Yn(e))return{version:1,items:[]};let n=Ts(e,"utf-8");try{return Ns.parse(JSON.parse(n))}catch(r){throw new Error(`Backlog file invalid (${e}): ${r.message}`)}}save(e){let n=this.jsonPath();Ps(Es(n),{recursive:!0}),Zn(n,JSON.stringify(e,null,2)+`
|
|
124
|
-
`),Zn(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 r=new Date().toISOString(),i={...e,labels:e.labels??[],status:e.status??"todo",createdAt:e.createdAt??r,updatedAt:r};return n.items.push(i),this.save(n),i}addMany(e){let n=this.load(),r=new Set(n.items.map(o=>o.id)),i=new Date().toISOString(),s=[];for(let o of e){if(r.has(o.id))continue;let a={...o,labels:o.labels??[],status:o.status??"todo",createdAt:o.createdAt??i,updatedAt:i};n.items.push(a),s.push(a),r.add(a.id)}return s.length&&this.save(n),s}update(e,n){let r=this.load(),i=r.items.findIndex(o=>o.id===e);if(i<0)throw new Error(`backlog item ${e} not found`);let s={...r.items[i],...n,id:r.items[i].id,createdAt:r.items[i].createdAt,updatedAt:new Date().toISOString()};return r.items[i]=s,this.save(r),s}remove(e){let n=this.load(),r=n.items.length;return n.items=n.items.filter(i=>i.id!==e),n.items.length===r?!1:(this.save(n),!0)}toMarkdown(e){let n=["# Backlog","","_Generated from `backlog.json`. Do not edit by hand \u2014 use `agentx backlog` commands._",""],r={doing:[],blocked:[],todo:[],done:[]};for(let s of e.items)r[s.status].push(s);let i=[["doing","Doing"],["blocked","Blocked"],["todo","To Do"],["done","Done"]];for(let[s,o]of i)if(r[s].length){n.push(`## ${o}`,"");for(let a of r[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 Qc(t){return`${t.type}:${t.project}:${t.iid}`}function er(t,e,n){let r=[];if(e.type==="gitlab"){let i=n.channels.gitlab?.agentMappings??[];for(let s of t){let o=i.find(a=>a.agentId===s);o?.gitlabUsernames?.length?r.push(o.gitlabUsernames[0]):r.push(s)}}else if(e.type==="github"){let i=n.channels.github?.agentMappings??[];for(let s of t){let o=i.find(a=>a.agentId===s);o?.githubUsernames?.length?r.push(o.githubUsernames[0]):r.push(s)}}return r}async function qe(t,e,n,r=()=>{}){return t.source?t.source.type==="gitlab"?Os(t.source,e,n,r):t.source.type==="github"?js(t.source,e,n,r):{ok:!1,error:`unknown source.type ${t.source.type}`,attempts:[]}:{ok:!0,attempts:[]}}async function Os(t,e,n,r){let i=n.channels.gitlab,s=i?.token,o=i?.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(g,f={})=>fetch(`${o}/api/v4${g}`,{...f,headers:{"PRIVATE-TOKEN":s,"Content-Type":"application/json",...f.headers||{}}}),l=encodeURIComponent(t.project),u;e.assigneeUsernames!==void 0&&(u=(await Promise.all(e.assigneeUsernames.map(async f=>{try{let m=await fetch(`${o}/api/v4/users?username=${encodeURIComponent(f)}`,{headers:{"PRIVATE-TOKEN":s}});if(!m.ok)return null;let y=await m.json();return Array.isArray(y)&&y[0]?.id?y[0].id:null}catch{return null}}))).filter(f=>typeof f=="number"));let d;if(e.milestoneTitle!==void 0)if(e.milestoneTitle===null||e.milestoneTitle==="")d=0;else try{let g=await c(`/projects/${l}/milestones?title=${encodeURIComponent(e.milestoneTitle)}`);if(g.ok){let f=await g.json();Array.isArray(f)&&f[0]?.id&&(d=f[0].id)}}catch(g){r(`[backlog-sync] milestone lookup failed: ${g.message}`)}let p={};if(e.title!==void 0&&(p.title=e.title),e.description!==void 0&&(p.description=e.description),e.labels!==void 0&&(p.labels=e.labels.join(",")),e.addLabels?.length&&(p.add_labels=e.addLabels.join(",")),e.removeLabels?.length&&(p.remove_labels=e.removeLabels.join(",")),u!==void 0&&(p.assignee_ids=u),d!==void 0&&(p.milestone_id=d),e.state&&(p.state_event=e.state==="closed"?"close":"reopen"),Object.keys(p).length)try{let g=await c(`/projects/${l}/issues/${t.iid}`,{method:"PUT",body:JSON.stringify(p)});if(a.push({kind:"PUT issue",ok:g.ok,status:g.status}),!g.ok){let f=await g.text().catch(()=>"");return{ok:!1,attempts:a,error:`PUT issue ${g.status}: ${f.slice(0,200)}`,url:t.url}}}catch(g){return a.push({kind:"PUT issue",ok:!1,error:g.message}),{ok:!1,attempts:a,error:g.message,url:t.url}}if(e.note)try{let g=await c(`/projects/${l}/issues/${t.iid}/notes`,{method:"POST",body:JSON.stringify({body:e.note})});a.push({kind:"POST note",ok:g.ok,status:g.status})}catch(g){a.push({kind:"POST note",ok:!1,error:g.message})}return{ok:a.every(g=>g.ok),attempts:a,url:t.url}}async function js(t,e,n,r){let s=n.channels.github?.token;if(!s)return{ok:!1,error:"github token not configured",attempts:[]};let o=[],a=async(p,g={})=>fetch(`https://api.github.com${p}`,{...g,headers:{Authorization:`Bearer ${s}`,Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2022-11-28",...g.headers||{}}}),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 g=await p.json(),f=Array.isArray(g)?g.find(m=>m.title===e.milestoneTitle):null;f?.number&&(l=f.number)}}catch(p){r(`[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 g=await p.json(),f=Array.isArray(g.labels)?g.labels.map(y=>typeof y=="string"?y:y.name):[],m=new Set([...f,...e.addLabels??[]]);for(let y of e.removeLabels??[])m.delete(y);u=[...m]}}catch(p){r(`[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 g=await p.text().catch(()=>"");return{ok:!1,attempts:o,error:`PATCH issue ${p.status}: ${g.slice(0,200)}`,url:t.url}}}catch(p){return o.push({kind:"PATCH issue",ok:!1,error:p.message}),{ok:!1,attempts:o,error:p.message,url:t.url}}if(e.note)try{let p=await a(`/repos/${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 Je=/^(\s*)-\s*\[( |x|X)\]\s*(.*)$/,me=/@([a-z0-9_-]+)/i,tr=/\[time:\s*([0-9hm\s]+)\]/i;function Us(t){let e=t.match(/(\d+)\s*h/i),n=t.match(/(\d+)\s*m/i);return(e?parseInt(e[1],10)*3600:0)+(n?parseInt(n[1],10)*60:0)}var Ye=class{constructor(e,n,r=()=>{}){this.path=e;this.daemon=n;this.log=r;this.store=new fe(this.path)}type="backlog";capabilities={listAll:!0,create:!1,transition:!1,labels:!0,search:!1};store;getStore(){return this.store}readMd(){let e=Xe(process.cwd(),this.path);return Ke(e)?Ge(e,"utf-8").split(`
|
|
126
|
-
`):[]}writeMd(e){let n=Xe(process.cwd(),this.path);nr(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(),r=[];for(let i=0;i<n.length;i++){let s=n[i].match(Je);if(!s||s[2].toLowerCase()==="x")continue;let a=s[3],c=a.match(me);if(c&&c[1].toLowerCase()!==e.toLowerCase())continue;let l=a.match(tr),u=a.replace(me,"").replace(tr,"").trim();r.push({id:`backlog:${i}`,title:u||`Task at line ${i+1}`,assignee:c?c[1]:void 0,estimatedSeconds:l?Us(l[1]):void 0,priority:i})}return r}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 r=this.store.findById(n);if(!r)return;let i=this.store.update(n,{assignee:r.assignee||e,status:"doing"});if(i.source&&this.daemon){let s=er([i.assignee||e],i.source,this.daemon);qe(i,{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&&qe(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 r=parseInt(e.slice(8),10),i=this.readMd(),s=i[r];if(!s)throw new Error(`backlog line ${r} missing`);if(!s.match(Je))throw new Error(`backlog line ${r} not a checkbox`);if(n.status==="done"){i[r]=s.replace(/- \[ \]/,"- [x]");let a=n.timeSeconds?` <!-- done by agent, ${Math.round(n.timeSeconds/60)}m -->`:" <!-- done by agent -->";i.splice(r+1,0,a)}else n.status==="blocked"?i.splice(r+1,0,` <!-- BLOCKED: ${n.blocker||n.note||"?"} -->`):n.note&&i.splice(r+1,0,` <!-- ${n.note.replace(/-->/g,"\u2014 >")} -->`);this.writeMd(i)}toWorkItem(e){let n={todo:"todo",doing:"doing",blocked:"onhold",done:"done"}[e.status];return{id:e.id,title:e.title,description:e.description,assignee:e.assignee,estimatedSeconds:e.estimatedSeconds,priority:e.priority,labels:e.labels,stage:n,milestone:e.milestone,url:e.source?.url,updatedAt:e.updatedAt,state:e.status==="done"?"closed":"opened"}}},Ze=class{constructor(e,n){this.root=e;this.glob=n}type="wiki";capabilities={listAll:!1,create:!1,transition:!1,labels:!1,search:!1};walk(e,n){if(Ke(e))for(let r of Vs(e)){let i=Fs(e,r);Ws(i).isDirectory()?this.walk(i,n):r.endsWith(".md")&&n.push(i)}}async listOpen(e){let n=[];this.walk(Xe(process.cwd(),this.root),n);let r=[];for(let i of n){let s=Ge(i,"utf-8").split(`
|
|
128
|
-
`);for(let o=0;o<s.length;o++){let a=s[o].match(Je);if(!a||a[2].toLowerCase()==="x")continue;let c=a[3].match(me);!c||c[1].toLowerCase()!==e.toLowerCase()||r.push({id:`wiki:${i}:${o}`,title:a[3].replace(me,"").trim(),assignee:c[1],priority:o})}}return r}async claim(){}async report(e,n){let r=e.split(":"),i=parseInt(r[r.length-1],10),s=r.slice(1,-1).join(":");if(!Ke(s))return;let o=Ge(s,"utf-8").split(`
|
|
129
|
-
`);n.status==="done"&&o[i]&&(o[i]=o[i].replace(/- \[ \]/,"- [x]"),nr(s,o.join(`
|
|
130
|
-
`)))}},Qe=class{constructor(e,n,r,i,s){this.host=e;this.token=n;this.projects=r;this.agentUsernames=i;this.log=s}type="gitlab";capabilities={listAll:!0,create:!0,transition:!0,labels:!0,search:!0};usernameToAgent(e){for(let[n,r]of Object.entries(this.agentUsernames))if(r.some(i=>i.toLowerCase()===e.toLowerCase()))return n}mapIssue(e,n){let r=e.references?.full?.split("#")[0]||n,i=[],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})),i=s.map(l=>l.name)):i=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:${r}: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:i,labelDetails:s,updatedAt:e.updated_at,state:e.state==="closed"?"closed":"opened",milestone:e.milestone?.title||void 0}}async api(e,n={}){let r=await fetch(`${this.host}/api/v4${e}`,{...n,headers:{"PRIVATE-TOKEN":this.token,"Content-Type":"application/json",...n.headers||{}}});if(!r.ok)throw new Error(`GitLab ${r.status}: ${await r.text().catch(()=>"")}`);return r.json()}async listOpen(e){let n=this.agentUsernames[e]||[];if(!n.length)return[];let r=[],i=this.projects.length?this.projects:["__ALL__"];for(let s of n)for(let o of i)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,r.push(d)}}catch(a){this.log(`[business] GitLab listOpen failed for ${s} on ${o}: ${a.message}`)}return r}async claim(e,n){let{project:r,iid:i,type:s}=this.parseId(n),o=`/projects/${encodeURIComponent(r)}/${s==="issue"?"issues":"merge_requests"}/${i}?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:r,iid:i,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(r)}/${o}/${i}/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(r)}/${o}/${i}?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(r)}/${o}/${i}?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(r)}/${o}/${i}/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,r=new Date(Date.now()-n*24*36e5).toISOString(),i=new URLSearchParams,s=e.state??"opened";i.set("state",s),i.set("updated_after",r),i.set("scope","all"),i.set("per_page","100"),i.set("with_labels_details","true"),i.set("order_by","updated_at"),i.set("sort","desc"),e.labels?.length&&i.set("labels",e.labels.join(",")),e.milestone&&i.set("milestone",e.milestone),e.search&&i.set("search",e.search);let o=this.projects.length?this.projects:["__ALL__"],a=[];for(let l of o)try{let u=l==="__ALL__"?`/issues?${i.toString()}`:`/projects/${encodeURIComponent(l)}/issues?${i.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:r,iid:i,type:s}=this.parseId(e),o=s==="issue"?"issues":"merge_requests";await this.api(`/projects/${encodeURIComponent(r)}/${o}/${i}?state_event=${n}`,{method:"PUT"})}async getItem(e){let{project:n,iid:r}=this.parseId(e);try{let i=await this.api(`/projects/${encodeURIComponent(n)}/issues/${r}?with_labels_details=true`);return{...this.mapIssue(i,n),descriptionHtml:i.description_html||void 0,createdAt:i.created_at,author:i.author?{username:i.author.username,name:i.author.name,avatarUrl:i.author.avatar_url}:void 0,allLabels:Array.isArray(i.labels)?typeof i.labels[0]=="object"?i.labels.map(o=>o.name):i.labels:[]}}catch(i){return this.log(`[board] GitLab getItem failed for ${e}: ${i.message}`),null}}async updateItem(e,n){let{project:r,iid:i}=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(r)}/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(r)}/issues/${i}`,{method:"PUT",body:JSON.stringify(a)});return this.mapIssue(c,r)}async listMembers(){let e=new Map;for(let n of this.projects)try{let r=await this.api(`/projects/${encodeURIComponent(n)}/members/all?per_page=100`);for(let i of r)i.username&&!e.has(i.username)&&e.set(i.username,{username:i.username,name:i.name,avatarUrl:i.avatar_url})}catch(r){this.log(`[board] listMembers failed for ${n}: ${r.message}`)}return[...e.values()].sort((n,r)=>n.username.localeCompare(r.username))}async listMilestones(){let e=new Map;for(let r of this.projects)try{let i=await this.api(`/projects/${encodeURIComponent(r)}/milestones?per_page=100`);for(let s of i)s.title&&!e.has(s.title)&&e.set(s.title,{id:s.id,title:s.title,state:s.state,dueDate:s.due_date})}catch(i){this.log(`[board] listMilestones failed for ${r}: ${i.message}`)}let n=[...e.values()];return n.sort((r,i)=>r.state!==i.state?r.state==="active"?-1:1:r.title.localeCompare(i.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 r,i=e.assigneeUsernames?.length?e.assigneeUsernames:e.assignee?(this.agentUsernames[e.assignee]||[]).slice(0,1):[];i.length&&(r=(await Promise.all(i.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(",")};r?.length&&(o.assignee_ids=r),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,r){await this.transitionMany(e,n?[n]:[],r?[r]:[])}async transitionMany(e,n,r){let{project:i,iid:s,type:o}=this.parseId(e),a=o==="issue"?"issues":"merge_requests",c=new URLSearchParams;n.length&&c.set("add_labels",n.join(",")),r.length&&c.set("remove_labels",r.join(",")),c.toString()&&await this.api(`/projects/${encodeURIComponent(i)}/${a}/${s}?${c.toString()}`,{method:"PUT"})}parseId(e){let r=e.replace(/^gitlab:/,"").split(":"),i=r.pop(),s=r.pop()==="mr"?"mr":"issue";return{project:r.join(":"),type:s,iid:i}}};function ol(t,e,n){let r=t.workSource;switch(r.type){case"backlog":return new Ye(r.path,e,n);case"wiki":return new Ze(r.path,r.glob);case"gitlab":{let i=e.channels.gitlab;if(!i?.token)throw new Error("business.workSource.type=gitlab requires channels.gitlab.token");let s={};for(let a of i.agentMappings)a.gitlabUsernames.length&&(s[a.agentId]=a.gitlabUsernames);let o=r.projects.length?r.projects:i.routes.map(a=>a.project);return new Qe(i.host,i.token,o,s,n)}}}var et="unmapped";function tt(t,e=[]){if(!t)return et;let n=e.find(i=>i.id===t);if(n?.client)return n.client;let r=t.indexOf("/");return r>0?t.slice(0,r):t}function Bs(t){let e=new Map,n=t.projects??[],r=t.orgChart??{};for(let s of n)s.pm&&(e.has(s.pm)||e.set(s.pm,tt(s.id,n)));let i=(s,o=new Set)=>{if(e.has(s))return e.get(s);if(o.has(s))return;o.add(s);let a=r[s]?.reportsTo;if(!a)return;let c=i(a,o);return c&&e.set(s,c),c};for(let s of Object.keys(r))i(s);return e}function Hs(t,e,n=[]){if(!n.length)return;let r=n.filter(i=>!i.channel||i.channel===t);return r.find(i=>i.chatId&&e.chatId&&i.chatId===e.chatId)??r.find(i=>i.username&&e.username&&i.username===e.username)??r.find(i=>i.senderId&&e.senderId&&i.senderId===e.senderId)??r.find(i=>i.channel&&!i.chatId&&!i.username&&!i.senderId)}function cl(t,e){let n=Hs(t.channel,{chatId:t.chatId,username:t.username},e.contactMap);if(n)return n.client;if(t.project)return tt(t.project,e.projects);if(t.agentId){let r=Bs(e).get(t.agentId);if(r)return r}return et}function ll(t,e){let n=String(t||"").split(":");if(n.length<3)return{agentId:e};let[r,i,...s]=n,o=s.join(":"),a={agentId:e||r,channel:i};return i==="gitlab"||i==="github"?a.project=o.split(":")[0]:i==="cron"||i==="api"||(a.chatId=o.split("@")[0]),a}var zs=t=>t===et?"internal":"client";function qs(t,e){let n=e.clients?.[t];return{id:t,name:n?.name||t,kind:n?.kind??zs(t),respondWithinMinutes:Gs(n?.respondWithin),standing:n?.standing??[],declared:!!n}}function ul(t){let e=new Set;for(let n of t.projects??[])e.add(tt(n.id,t.projects));for(let n of t.contactMap??[])e.add(n.client);for(let n of Object.keys(t.clients??{}))e.add(n);return[...e].sort().map(n=>qs(n,t))}function Gs(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 Ks=/(^|\n)[ \t]*```[ \t]*agentx:ui[ \t]*\r?\n/i,Xs=/(^|\n)[ \t]*```[ \t]*agentx:ui[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```[ \t]*(?=\n|$)/gi;function rr(t){if(!t||!t.includes("agentx:ui"))return{cleanText:t};let e=[...t.matchAll(Xs)];if(e.length===0)return{cleanText:t};let n=e[e.length-1],r=n[2],i=Js(r);if(!i)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:i}}function pl(t){if(!t||!t.includes("agentx:ui"))return t;let e=Ks.exec(t);return e?t.slice(0,e.index).trimEnd():t}function Js(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 r=[],i=[],s=[];for(let o of e.buttons)!o||typeof o.label!="string"||(typeof o.url=="string"&&/^https?:\/\//i.test(o.url)?r.push({label:o.label,url:o.url}):typeof o.reply=="string"&&o.reply.trim()?i.push({label:o.label,reply:o.reply.trim()}):o.action!=null&&s.push(o.label));r.length&&(n.buttons=r),i.length&&(n.replies=i),s.length&&(n.skippedActions=s)}if(e.poll&&typeof e.poll=="object"){let r=e.poll.question,i=e.poll.options;typeof r=="string"&&r.trim()&&Array.isArray(i)&&i.filter(s=>typeof s=="string").length>=2&&(n.poll={question:r,options:i.filter(s=>typeof s=="string"),multiple:e.poll.multiple===!0})}if(e.media&&typeof e.media=="object"){let{type:r,url:i,caption:s}=e.media;["image","document","audio","video"].includes(r)&&typeof i=="string"&&i&&(n.media={type:r,url:i,...typeof s=="string"?{caption:s}:{}})}if(Array.isArray(e.quickReplies)){let r=e.quickReplies.filter(i=>typeof i=="string"&&i.trim()).map(i=>i.trim());r.length&&(n.quickReplies=r)}return!n.buttons&&!n.poll&&!n.media&&!n.quickReplies&&!n.replies&&!n.skippedActions?null:n}function fl(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 Ys=5*6e4;function E(t){return t.toLowerCase().replace(/[^a-z0-9]/g,"")}var ir=class{subs=new Set;log;forwarder;localName;allowedCallers;pending=new Map;cleanupTimer;ringHandler;recentRings=new Map;constructor(e,n=[],r=console.error.bind(console,"[webrtc]")){this.localName=e,this.allowedCallers=new Set(n.map(E)),this.log=r,this.cleanupTimer=setInterval(()=>this.cleanupExpired(),1e4)}pendingKey(e,n){return`${e}|${E(n)}`}cleanupExpired(){let e=Date.now();for(let[n,r]of this.pending){let i=r.filter(s=>s.expiresAt>e);i.length===0?this.pending.delete(n):i.length!==r.length&&this.pending.set(n,i)}for(let[n,r]of this.recentRings)r<=e&&this.recentRings.delete(n)}setForwarder(e){this.forwarder=e}setRingHandler(e){this.ringHandler=e}subscribe(e,n,r){return this.addSubscriber(e,n,{kind:"sse",res:r})}subscribeInternal(e,n,r){return this.addSubscriber(e,n,{kind:"callback",deliver:r})}addSubscriber(e,n,r){let i={callId:e,recipient:n,sink:r};this.subs.add(i);let s=r.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(i,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(i),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=E(e.to);if(n===E(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 i=await this.forwarder(e.to,e);return i?{ok:i}:{ok:!1,error:`forward to "${e.to}" failed`}}hasSubscriberFor(e,n){for(let r of this.subs)if(r.callId===e&&E(r.recipient)===n)return!0;return!1}handleIncoming(e){if((e.kind==="offer"||e.kind==="ring")&&this.allowedCallers.size>0&&!this.allowedCallers.has(E(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 r=Date.now(),i=this.recentRings.get(e.callId);if(i&&i>r)return this.log(`dedup ring for call=${e.callId} (already notified)`),{ok:!0};if(this.recentRings.set(e.callId,r+Ys),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 r=this.pendingKey(e.callId,e.to),i=this.pending.get(r)||[];i.push({signal:e,expiresAt:Date.now()+3e4}),this.pending.set(r,i),this.log(`buffered ${e.kind} for call=${e.callId} to=${e.to} (no subscriber yet, ${i.length} pending)`)}return{ok:!0}}fanOut(e){let n=0,r=E(e.to);for(let i of this.subs)i.callId===e.callId&&E(i.recipient)===r&&(this.deliverTo(i,e)?n++:this.subs.delete(i));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()}};function he(t,e=160){if(!t)return t;let n=t.replace(/\s+/g," ").trim();return n.length>e?n.slice(0,e-1)+"\u2026":n}function Zs(t){let e=new Map;for(let r of t.cronRuns??[]){let i=e.get(r.jobId);(!i||i.startedAt<r.startedAt)&&e.set(r.jobId,r)}let n={success:0,failed:0};for(let r of t.cronRuns??[])r.status==="success"?n.success++:n.failed++;return{id:t.id,name:t.name,url:t.url,reachable:t.reachable,error:he(t.error),uptimeSec:t.uptimeSec,inflight:t.inflight,restart:t.restart?.state&&t.restart.state!=="none"?t.restart:void 0,agents:t.agents.map(r=>({id:r.id,name:r.name,tier:r.tier,active:r.active,errors:r.errors,lastActive:r.lastActive,last:r.lastSummary?{text:he(r.lastSummary.text),at:r.lastSummary.at,ok:r.lastSummary.ok}:void 0})),crons:{today:n,items:(t.crons??[]).map(r=>{let i=e.get(r.id);return{id:r.id,enabled:r.enabled,schedule:r.schedule,agent:r.agent,nextRun:r.nextRun,consecutiveErrors:r.consecutiveErrors,last:i?{status:i.status,at:i.startedAt,text:he(i.status==="success"?i.responseSummary:i.errorSummary)}:void 0}})}}}function Qs(t){let e=[];for(let n of t)for(let r of n.agents)for(let i of r.runningTasks??[])e.push({node:n.url,nodeName:n.name,agentId:r.id,agentName:r.name,taskId:i.id,preview:he(i.messagePreview),channel:i.channel,startedAt:i.startedAt});return e.sort((n,r)=>n.startedAt<r.startedAt?1:-1)}var eo=/^\/api\/app\/tasks\/(cancel|followup)$/;async function hl(t,e,n,r,i,s){let o=new URL(t.url||n,"http://localhost");if(r==="GET"&&(n==="/api/app/fleet"||n==="/api/app/activity")){let g=to(o.searchParams.get("timezone")),f=await s.snapshot({date:no(g),timezone:g});return n==="/api/app/activity"?I(e,200,{ts:f.ts,tasks:Qs(f.nodes)}):I(e,200,{ts:f.ts,nodes:f.nodes.map(Zs)})}if(r==="GET"&&n==="/api/app/approvals")return I(e,200,{nodes:await s.approvals()});if(r!=="POST")return!1;let a=n.match(eo);if(!(a||["/api/app/nodes/restart","/api/app/nodes/reload","/api/app/crons/toggle","/api/app/approvals/decide"].includes(n)))return!1;let l;try{l=await nt(t)}catch(g){return I(e,400,{error:g.message})}let u=X(l.node);if(!u)return I(e,400,{error:"node is required"});let d=`operator (phone: ${i})`,p;if(a){let g=X(l.taskId);if(!g)return I(e,400,{error:"taskId is required"});let f=`/api/tasks/${encodeURIComponent(g)}/${a[1]}`;if(a[1]==="cancel")p=await s.nodePost(u,f,{reason:`cancelled by ${d}`});else{let m=X(l.message);if(!m)return I(e,400,{error:"message is required"});p=await s.nodePost(u,f,{message:m,sender:d})}}else if(n==="/api/app/nodes/restart")p=await s.nodePost(u,l.cancel===!0?"/daemon/restart/cancel":"/daemon/restart",{});else if(n==="/api/app/nodes/reload")p=await s.nodePost(u,"/reload",{});else if(n==="/api/app/crons/toggle"){let g=X(l.cronId);if(!g||typeof l.enabled!="boolean")return I(e,400,{error:"cronId and enabled (true or false) are required"});p=await s.nodePost(u,`/crons/${encodeURIComponent(g)}/enabled`,{enabled:l.enabled})}else{let g=X(l.key),f=l.action;if(!g||f!=="yes"&&f!=="no"&&f!=="later")return I(e,400,{error:"key and action (yes, no or later) are required"});p=await s.decide(u,g,f,d)}return I(e,p.status,p.body)}function X(t){return typeof t=="string"?t.trim():""}function to(t){if(!t)return"UTC";try{return new Intl.DateTimeFormat("en-US",{timeZone:t}),t}catch{return"UTC"}}function no(t,e=new Date){return new Intl.DateTimeFormat("en-CA",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit"}).format(e)}async function nt(t,e=16*1024){let n=0,r=[];for await(let o of t){if(n+=o.length,n>e)throw new Error("body too large");r.push(o)}let i=Buffer.concat(r).toString("utf-8").trim();if(!i)return{};let s=JSON.parse(i);if(!s||typeof s!="object"||Array.isArray(s))throw new Error("expected a JSON object");return s}function I(t,e,n){return t.writeHead(e,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify(n)),!0}var ro={perClient:5,global:10,windowMs:10*60*1e3,lockoutMs:5*60*1e3},sr=class{constructor(e=ro,n=Date.now){this.opts=e;this.now=n}clients=new Map;all={failures:[],lockedUntil:0};retryAfter(e){let n=this.now(),r=Math.max(this.all.lockedUntil,this.clients.get(e)?.lockedUntil??0);return r>n?Math.ceil((r-n)/1e3):0}fail(e){let n=this.clients.get(e);n||this.clients.set(e,n={failures:[],lockedUntil:0}),this.bump(n,this.opts.perClient),this.bump(this.all,this.opts.global)}succeed(e){this.clients.delete(e)}bump(e,n){let r=this.now();e.failures=e.failures.filter(i=>r-i<this.opts.windowMs),e.failures.push(r),e.failures.length>=n&&(e.lockedUntil=r+this.opts.lockoutMs)}},io="That code didn't work. Check it, or run agentx app pair for a new one.",so=400;async function wl(t,e){let n=Date.now(),r=e.log??(l=>console.log(l)),i=t.socket.remoteAddress||"unknown",s=e.limiter.retryAfter(i);if(s>0)return r(`[app] pair-code refused from ${i}: locked out for ${s}s more`),{status:429,body:{error:"too many attempts",retryAfter:s},retryAfter:s};let o=null;try{o=(await nt(t,1024)).code}catch{}let a=e.codes.redeem(o),c=a?e.verify(a.token):null;return await oo(n,e.minMs??so),!a||!c?(e.limiter.fail(i),r(`[app] pair-code failed from ${i}`),{status:401,body:{error:io}}):(e.limiter.succeed(i),r(`[app] pair-code paired ${a.tokenId} (${c}) from ${i}`),{status:200,body:{device:c},token:a.token})}async function oo(t,e){let n=t+e-Date.now();n>0&&await new Promise(r=>setTimeout(r,n))}var ao=200,or=4e3;function co(t){return t.replace(/```[\s\S]*?```/g," ").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^\s{0,3}(#{1,6}|>|[-*+]|\d+[.)])\s+/gm,"").replace(/[*_~`]+/g,"").replace(/\s+/g," ").trim()}function rt(t,e=ao){let n=co(t);if(n.length<=e)return n;let r=n.slice(0,e),i=Math.max(r.lastIndexOf(". "),r.lastIndexOf("? "),r.lastIndexOf("! "));return i>e/2?r.slice(0,i+1):`${r.slice(0,e-1).trimEnd()}\u2026`}function Sl(t,e){let n=e.lastAnswer(t.id),r=n&&n.text.length>or?`${n.text.slice(0,or)}
|
|
134
|
-
|
|
135
|
-
\u2026`:n?.text;return{...t,summary:rt(t.text),textHtml:re(t.text),why:t.state==="waiting_owner"?t.question:t.state==="needs_attention"?t.attentionReason:null,ownerNoteHtml:t.ownerNote?re(t.ownerNote):null,lastAnswer:n?{agentId:n.agentId,at:n.at,html:re(r)}:null}}import{execFile as Ro}from"child_process";import{mkdtempSync as ko,rmSync as xo,writeFileSync as So}from"fs";import{tmpdir as vo}from"os";import{join as dr}from"path";import{randomBytes as lo}from"crypto";var C={top:8,side:32,bottom:60},it={height:56,keep:52},ar=`
|
|
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: ${C.top}px ${C.side}px ${C.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 - ${C.top+C.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 cr=t=>t.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"}),lr=t=>`${t.getDate()} ${t.toLocaleDateString("en-US",{month:"short"})}`;function uo(t,e){let n=new Date(t);return Number.isNaN(n.getTime())?"":`since ${n.toDateString()===new Date(e).toDateString()?cr(n):lr(n)}`}function po(t,e){let n=new Date(t),r=n.getTime()-e<6*864e5;return[n.toLocaleDateString("en-US",{weekday:"short"}),...r?[]:[lr(n)],cr(n)].join(" ")}function go(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 fo(t){let e=(t.recommend??"").trim(),n=e.toLowerCase(),r=t.choices??[],i=-1;if(r.forEach((o,a)=>{!n.startsWith(o.toLowerCase())||!/^\s*($|[:,.;–—-](\s|$))/.test(e.slice(o.length))||(i<0||o.length>r[i].length)&&(i=a)}),i<0)return{index:i,why:e};let s=e.slice(r[i].length).replace(/^[\s:,.;–—-]+/,"");return{index:i,why:s.slice(0,1).toUpperCase()+s.slice(1)}}function mo(t){return t.origin?.kind==="request"?"Hand it back":t.draft?"Send":t.choices?.length?"Choose":"Yes"}var st=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>`,ho=st('<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>'),yo=st('<path d="m6 15 6-6 6 6"/>'),bo=st('<rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>');function ur(t,e={}){let n=e.now??Date.now(),r=e.from||t.raised_by,i=lo(12).toString("base64"),s=t.choices??[],o=t.origin?.kind==="reminder",a=t.origin?.kind==="request",c=fo(t),l=s.map((p,g)=>`<button class="opt" role="radio" aria-checked="false" data-i="${g}"><span class="n">${g+1}</span><span class="t">${w(p)}</span>${g===c.index?'<i class="dot"></i>':""}</button>`).join(""),u=t.recommend?`<span class="rec"><i class="dot"></i>${w(r)} recommends</span>`:"",d={choices:s,draft:t.draft??"",placeholder:Bt,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-${i}'">
|
|
267
|
-
<title>AgentX</title>
|
|
268
|
-
<style>${ar}</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(go(r))}</span>
|
|
271
|
-
<div class="who"><b>${w(r)}</b><span>${w(uo(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">${yo}</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>${ho}<span>${a?"It stays in Open requests on the Approvals page until you close it.":`If you don't answer by ${w(po(t.expires,n))}: ${w(t.if_silent)}.`}</span></div>
|
|
283
|
-
<div>${bo}<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">${mo(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="${i}">${wo}</script>
|
|
290
|
-
</body></html>`}var wo=`
|
|
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 $o=440,Ao=`
|
|
380
|
-
ObjC.import("Cocoa"); ObjC.import("WebKit")
|
|
381
|
-
function run(argv) {
|
|
382
|
-
var path = argv[0], side = ${C.side}, gripTop = ${C.top}, gripEnd = ${C.top+it.height}, keep = ${it.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 Io(t,e){let n=t.trim().split(`
|
|
453
|
-
`).pop()??"",r;try{r=JSON.parse(n)}catch{return{action:"dismiss"}}if(r?.action==="no")return{action:"no"};if(r?.action==="dismiss"&&gr.includes(r.why))return{action:"dismiss",why:r.why};if(r?.action!=="yes")return{action:"dismiss"};let i=e.choices??[],s;if(i.length){if(typeof r.choice!="string"||!i.includes(r.choice))return{action:"dismiss"};s=r.choice}let o;return e.draft&&(o=typeof r.text=="string"?r.text.replace(/\r\n?/g,`
|
|
454
|
-
`).trim():"",!o||o.length>Ut.text)?{action:"dismiss"}:{action:"yes",...s?{choice:s}:{},...o?{text:o}:{}}}async function pr(t,e,n){let r=Math.max(10,Math.round(e.timeoutSeconds)),i=ko(dr(vo(),"agentx-card-"));try{let s=dr(i,"card.html");So(s,ur(t,{...e,still:!!e.capture}),{mode:384});let o=["-l","JavaScript","-e",Ao,s,String($o),String(r),...e.capture?[e.capture]:[]],a=await n("/usr/bin/osascript",o,(r+10)*1e3);return a.ok?Io(a.stdout,t):null}finally{xo(i,{recursive:!0,force:!0})}}var gr=["not now","timed out","closed"],_o=(t,e,n)=>new Promise(r=>{try{Ro(t,e,{timeout:n},(i,s)=>r({ok:!i,stdout:String(s??"")}))}catch{r({ok:!1,stdout:""})}}),fr=160,ot=15e3;function mr(t){let e=(t.say||t.title).replace(/\s+/g," ").trim();return e.length>fr?e.slice(0,fr):e}async function Co(t,e,n,r,i){let s=e.sound==="chime"?r?"":"Glass":e.sound,o=s?Xt(s):null;if(o&&await n("/usr/bin/afplay",["-v",String(Math.min(1,Math.max(0,e.volume))),o],ot),!!e.speak)if(i){let a;await Promise.race([i(mr(t)),new Promise(c=>{a=setTimeout(c,ot)})]),clearTimeout(a)}else{let a=e.voice&&/^[\w .()-]+$/.test(e.voice)?["-v",e.voice]:[];await n("/usr/bin/say",[...a,"--",mr(t)],ot)}}function br(t,e){return[...t.flatMap(n=>["-e",n]),...e]}function Do(t,e,n){return br(["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 hr(t,e,n,r,i){return br(["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(r),...i!==void 0?[i]:[]])}function yr(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 at(t){return[t.ask,t.recommend?`Recommended: ${t.recommend}`:"",`From ${t.raised_by}`].filter(Boolean).join(`
|
|
457
|
-
|
|
458
|
-
`)}async function wr(t,e,n={}){let r=n.run??_o,i=(e.style??"card")==="card",s=Co(t,e,r,i,n.speak).catch(()=>{});if(i){let o=await pr(t,{timeoutSeconds:e.timeoutSeconds,sound:e.sound,volume:e.volume,theme:e.theme,from:n.from,capture:n.capture,pick:n.pick},r).catch(()=>null);if(o)return o}return await s,Po(t,e,r)}async function Po(t,e,n){let r=Math.max(10,Math.round(e.timeoutSeconds)),i=(r+5)*1e3,s=`${t.raised_by}: ${t.title}`,o;if(t.choices?.length){let l=await n("/usr/bin/osascript",Do(s,at(t),t.choices),i);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):`:`${at(t)}
|
|
461
|
-
|
|
462
|
-
Message (edit it if you like):`,d=await n("/usr/bin/osascript",hr(s,l,o?["Cancel","Send"]:["Not now","No","Send"],r,Ht(t.draft,o)),i),p=d.ok?yr(d.stdout):null;if(p?.button==="Send"){let g=p.text.trim();return g?{action:"yes",...o?{choice:o}:{},text:g}:{action:"dismiss"}}return p?.button==="No"?{action:"no"}:{action:"dismiss"}}let a=await n("/usr/bin/osascript",hr(s,at(t),["Not now","No","Yes"],r),i),c=a.ok?yr(a.stdout):null;return c?.button==="Yes"?{action:"yes"}:c?.button==="No"?{action:"no"}:{action:"dismiss"}}var lt=24*36e5,ct=!1,To=10*6e4,kr=-1/0;function xr(t){let e=t.now??Date.now(),{popped:n={},snoozed:r,passAt:i,wanted:s=[]}=A(t.root),o=i?Date.parse(i):NaN,a=H(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=r[u];if(d&&Date.parse(d)>e)continue;let p=Date.parse(l.created_at);if(!(e-p>lt&&!(p<=o)))return l}return null}function Sr(t){try{return q(t)?.listByState("needs_attention")??[]}catch{return[]}}function Eo(t){let e=t.now??Date.now(),{popped:n={},snoozed:r}=A(t.root);return Sr(t).find(i=>{let s=`request:${i.id}`,o=r[s];return!n[s]&&!(o&&Date.parse(o)>e)&&e-i.updatedAt<=lt})??null}function Lo(t,e){return{id:t.id,title:rt(t.text,Jt.title),context:t.attentionReason??"It is not finished and nothing is retrying it.",ask:`Hand it back to ${t.agentId}, or drop it?`,say:"A request you made is not finished.",recommend:"",if_silent:"keep",expires:new Date(e+lt).toISOString(),raised_by:t.agentId,created_at:new Date(t.createdAt).toISOString(),status:"pending",origin:{kind:"request",id:t.id}}}async function Xl(t){let{ctx:e,settings:n,log:r}=t;if(!n.enabled||(t.platform??process.platform)!=="darwin")return"off";if(ct)return"busy";let i=xr(e)?null:Eo(e),s=i?Lo(i,e.now??Date.now()):xr(e);if(!s)return"none";let o=(t.focus??Mt)();if(o.active)return"held";ct=!0;let a=`${i?"request":"card"}:${s.id}`;try{let c=[...H(e.root,"pending").map(m=>`card:${m.id}`),...Sr(e).map(m=>`request:${m.id}`)];hn(e.root,a,c,e.now),r(`[approvals] popup: showing ${a} from ${s.raised_by}`);let l=e.now??Date.now(),u=!!i&&l-kr<To;i&&n.speak&&(kr=l);let d=t.agentName?.(s.raised_by)??(s.node?`${s.raised_by} on ${s.node}`:void 0),p=await(t.show??wr)(s,u?{...n,speak:!1}:n,{from:d,speak:t.speak});if(p.action==="dismiss")return r(`[approvals] popup: ${a} left waiting: ${p.why??"no answer"} (${Nt(o)} when shown)`),"shown";if(!(i?q(e)?.get(i.id)?.state==="needs_attention":B(e.root,s.id)?.status==="pending"))return r(`[approvals] popup: ${a} was answered elsewhere; popup answer ignored`),"shown";let f=await vn(e,a,p.action,{by:"operator (popup)",...p.action==="yes"?{choice:p.choice,text:p.text}:{}});return r(f.ok?`[approvals] popup: ${f.message}`:`[approvals] popup: ${a} not recorded: ${f.error}`),"shown"}catch(c){return r(`[approvals] popup failed for ${a}: ${c?.message??c}`),"shown"}finally{ct=!1}}function Jl(t,e,n){if(!n)return{ok:!1,error:"the Mac popup is off; turn it on with `agentx approvals settings --popup on`"};let r=e.startsWith("card:")?B(t.root,e.slice(5)):null;return r?r.status!=="pending"?{ok:!1,error:`${e} is already ${r.status}`}:(yn(t.root,e),{ok:!0,message:`${e} will show on the Mac within a minute`}):{ok:!1,error:`no card "${e}"; the popup shows decision cards only`}}import{closeSync as J,createReadStream as Mo,fstatSync as No,openSync as Oo,realpathSync as vr}from"fs";import{isAbsolute as jo,resolve as $r,sep as Ar}from"path";var nu="/app-files",Vo=/^[A-Za-z0-9_.:-]{1,64}$/;function Wo(t,e,n=process.cwd()){if(!e||e.length>ne.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 ${Ae}/ first`};if(!$e(e))return{ok:!1,status:415,error:"this type of file is not served"};let r;try{r=vr($r(n,t))}catch{return{ok:!1,status:404,error:"the agent's workspace is missing"}}let i;try{i=vr(jo(e)?e:$r(r,e))}catch{return{ok:!1,status:404,error:"file not found"}}if(!i.startsWith(r+Ar))return{ok:!1,status:403,error:`the file is outside the agent's workspace: copy it into ${Ae}/ first`};let s=$e(i);return s?{ok:!0,path:i,...s}:{ok:!1,status:415,error:"this type of file is not served"}}function Fo(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 Uo(t,e,n){return{"Content-Type":t,"Content-Disposition":Fo(e,n),"X-Content-Type-Options":"nosniff","Content-Security-Policy":"default-src 'none'; img-src 'self'; media-src 'self'; sandbox","Cache-Control":"private, max-age=3600","Accept-Ranges":"bytes"}}function Bo(t,e){let n=/^bytes=(\d*)-(\d*)$/.exec(String(t||"").trim());if(!n||!n[1]&&!n[2])return null;let r,i;return n[1]?(r=Number(n[1]),i=n[2]?Math.min(Number(n[2]),e-1):e-1):(r=Math.max(0,e-Number(n[2])),i=e-1),r>i||r>=e?"unsatisfiable":{start:r,end:i}}function ru(t,e,n,r){let i=(P,j)=>{e.writeHead(P,{"Content-Type":"application/json","Cache-Control":"no-store","X-Content-Type-Options":"nosniff"}),e.end(JSON.stringify(j))};if(t.method!=="GET"&&t.method!=="HEAD")return i(405,{error:"GET only"});let s=n.searchParams.get("agent")||"",o=n.searchParams.get("file")||"";if(!Vo.test(s))return i(400,{error:"bad agent id"});let a=r.workspaceOf(s);if(!a)return i(404,{error:`no agent "${s}" on this computer`});let c=Wo(a,o,r.cwd);if(!c.ok)return r.log?.(`[app-files] refused ${JSON.stringify(o.slice(0,200))} from ${s}: ${c.error}`),i(c.status,{error:c.error});let l;try{l=Oo(c.path,"r")}catch{return i(404,{error:"file not found"})}let u;try{let P=No(l);if(!P.isFile())return J(l),i(404,{error:"not a file"});u=P.size}catch{return J(l),i(404,{error:"file not found"})}if(u>ne.bytes)return J(l),i(413,{error:`the file is larger than ${ne.bytes/1024/1024} MB`});let d=c.path.split(Ar).pop()||"file",p=Uo(c.mime,d,c.kind),g=Bo(t.headers.range,u);if(g==="unsatisfiable"){J(l),e.writeHead(416,{...p,"Content-Range":`bytes */${u}`}),e.end();return}let{start:f,end:m}=g??{start:0,end:u-1};if(e.writeHead(g?206:200,{...p,"Content-Length":String(u?m-f+1:0),...g?{"Content-Range":`bytes ${f}-${m}/${u}`}:{}}),t.method==="HEAD"||u===0){J(l),e.end();return}let y=Mo("",{fd:l,start:f,end:m,autoClose:!0});y.on("error",()=>e.destroy()),e.on("close",()=>y.destroy()),y.pipe(e)}import{spawn as Y}from"child_process";import{readFileSync as Ho,writeFileSync as zo}from"fs";import{tmpdir as qo}from"os";import{join as Go}from"path";vt();var Ir=t=>t&&t!==1?Math.round(175*t):null,ye=t=>t&&t!==1?Math.min(1.2,Math.max(.7,t)):null;function Ko(){if(process.env.ELEVENLABS_API_KEY)return process.env.ELEVENLABS_API_KEY;for(let t of[`${process.env.HOME}/.elevenlabs/key`,`${process.env.HOME}/.agentx/elevenlabs-key.txt`])try{let e=Ho(t,"utf8").trim();if(e)return e}catch{}return null}function pu(t=Ko()){let e=0;return async(n,r)=>{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 i=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",...ye(n.voice.rate)?{voice_settings:{speed:ye(n.voice.rate)}}:{}}),signal:r});if(!i.ok)throw new Error(`ElevenLabs ${i.status}: ${(await i.text()).slice(0,160)}`);let s=Go(qo(),`agentx-say-${process.pid}-${++e}.mp3`);return zo(s,Buffer.from(await i.arrayBuffer())),s}catch(i){if(r.aborted||!n.voice.fallback)throw i;return N(`elevenlabs:${String(i?.message??i).slice(0,40)}`,`[voice] ElevenLabs failed (${String(i?.message??i).slice(0,160)}); speaking with the system voice`),null}}}function Rr(t,e){let n=t.languages&&te(e);return n&&t.languages&&n in t.languages?t.languages[n]:t.system}var Xo=(t,e="")=>{let n=Rr(t,e),r=Ir(t.rate);return[...n&&!Dn(n)?["-v",n]:[],...r?["-r",String(r)]:[]]};function Jo(t,e,n){if(!n)return["say",Xo(t,e)];let r=Rr(t,e);return["/bin/sh",[n,...r?[r]:[]]]}function gu(t){let e=t.split(/\s+/).filter(Boolean).length;return Math.min(300,5+Math.floor(e*6/10))*1e3}function fu(t=ut()){if(t)try{Y("/bin/sh",[t,"--stop"],{stdio:"ignore"}).on("error",()=>{})}catch{}}function mu(t=ut()){if(t)try{Y("/bin/sh",[t,"--restore"],{stdio:"ignore"}).on("error",()=>{})}catch{}}function ut(t={},e){if(!Le(t))return null;try{return En(e)}catch(n){return N("siri-say",`[voice] could not write the Siri voice script (${String(n?.message??n).split(`
|
|
463
|
-
`)[0]}); Siri voices will not switch`),null}}var hu=(t,e)=>{if(!t){let[n,r]=Jo(e.voice,e.text,ut()),i=Ir(e.voice.rate),s=i?{...process.env,AGENTX_SAY_RATE:String(i)}:process.env,o=Y(n,r,{stdio:["pipe","ignore","ignore"],env:s});return o.stdin?.on("error",()=>{}),o.stdin?.end(e.text),o}return process.platform==="darwin"?Y("afplay",[t],{stdio:"ignore"}):Y("mpg123",["-q",t],{stdio:"ignore"})};import{spawn as _r}from"child_process";import{accessSync as Yo,constants as Zo,readFileSync as Cr}from"fs";import{homedir as Qo}from"os";import{basename as F,delimiter as Dr,dirname as ea,extname as ta,join as dt}from"path";var L={ms:2*60*1e3,bitsPerSecond:64e3,bytes:2*1024*1024};function Pr(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)>L.ms+2e3?{status:413,error:gt()}:null}var gt=()=>`The recording is longer than ${L.ms/6e4} minutes.`,na={"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 Tr(t){let e=String(t||"").split(";")[0].trim().toLowerCase();return na[e]??null}function Er(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 ft(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 pt(t,e,n=process.env.PATH??""){let r=Qo(),i=[dt(r,".local","bin"),"/opt/homebrew/bin","/usr/local/bin",...n.split(Dr).filter(Boolean)];for(let s of[e,...i.map(o=>dt(o,t))])if(s)try{return Yo(s,Zo.X_OK),s}catch{}return null}function Su(t){return{key:t,mlx:pt("mlx_whisper",process.env.AGENTX_MLX_WHISPER),whisper:pt("whisper",process.env.AGENTX_WHISPER),ffmpeg:ra()}}var ra=()=>pt("ffmpeg",process.env.AGENTX_FFMPEG);async function Lr(t,e){return e?ia(t,e):null}async function ia(t,e){let n=String(L.ms/1e3+5);try{let i=[...(await sa(e,["-nostdin","-hide_banner","-t",n,"-i",t,"-f","null","-"],3e4)).matchAll(/time=(\d+):(\d+):(\d+(?:\.\d+)?)/g)],s=i[i.length-1];return s?Number(s[1])*3600+Number(s[2])*60+Number(s[3]):null}catch{return null}}async function Mr(t,e,n,r){let i=new FormData;i.set("model_id",process.env.AGENTX_STT_MODEL||"scribe_v1"),i.set("file",new Blob([Cr(t)],{type:e}),F(t));let s=await fetch("https://api.elevenlabs.io/v1/speech-to-text",{method:"POST",headers:{"xi-api-key":n},body:i,signal:r??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 Nr(t,e,n,r,i){let s=t==="mlx-whisper"?["--model",process.env.AGENTX_MLX_MODEL||"mlx-community/whisper-large-v3-turbo","--output-format","txt","--output-dir",i,n]:[n,"--model",process.env.AGENTX_WHISPER_MODEL||"base","--output_format","txt","--output_dir",i,"--fp16","False"],o={...process.env,PATH:`${ea(r)}${Dr}${process.env.PATH??""}`};await oa(e,s,12e4,o);try{return Cr(dt(i,F(n,ta(n))+".txt"),"utf8").trim()}catch{throw new Error(`${t} wrote no transcript`)}}function sa(t,e,n){return new Promise((r,i)=>{let s=_r(t,e,{stdio:["ignore","ignore","pipe"]}),o="",a=setTimeout(()=>{s.kill("SIGKILL"),i(new Error(`${F(t)} took too long`))},n);s.stderr.on("data",c=>{o=(o+c).slice(-8192)}),s.on("error",c=>{clearTimeout(a),i(c)}),s.on("exit",c=>{clearTimeout(a),c===0?r(o):i(new Error(`${F(t)} exited ${c}`))})})}function oa(t,e,n,r=process.env){return new Promise((i,s)=>{let o=_r(t,e,{stdio:["ignore","pipe","pipe"],env:r}),a="",c="",l=setTimeout(()=>{o.kill("SIGKILL"),s(new Error(`${F(t)} took longer than ${n/1e3}s`))},n);o.stdout.on("data",u=>{a.length<4096&&(a+=u)}),o.stderr.on("data",u=>{c.length<4096&&(c+=u)}),o.on("error",u=>{clearTimeout(l),s(u)}),o.on("exit",u=>{clearTimeout(l),u===0?i(a):s(new Error(`${F(t)} exited ${u}: ${c.trim().split(`
|
|
464
|
-
`).pop()?.slice(0,160)??""}`))})})}import{mkdtemp as aa,rm as ca,writeFile as la}from"fs/promises";import{tmpdir as ua}from"os";import{join as Or}from"path";qr();var da=64*1024,pa=2,mt=0;function Eu(t){return t==="/voice/transcribe"||t==="/voice/speak"}async function Lu(t,e,n,r){return t.method!=="POST"?b(e,405,{error:"POST"}):n==="/voice/transcribe"?ga(t,e,r):ha(t,e,r)}async function ga(t,e,n){let r=String(t.headers["content-type"]||""),i=Tr(r);if(!i)return b(e,415,{error:"Send the recording as audio (webm, mp4, ogg, mp3 or wav)."});let s=Pr(t.headers["x-audio-duration-ms"]);if(s)return t.resume(),b(e,s.status,{error:s.error});let o=await jr(t,L.bytes);if(!o)return b(e,413,{error:wa()});if(!o.length)return b(e,400,{error:"The recording is empty."});if(mt>=pa)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=Er(a,c);if(!c.ffmpeg&&!n.allowUnmeasured?.()){let d=n.nodeName?`on ${n.nodeName}`:"on this computer",p=l.length?"":" "+ft(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:ft(a,c),setup:!1});mt++;let u;try{let d=await aa(Or(ua(),"agentx-phone-voice-"));try{u=await fa(d,`speech.${i}`,o,r,c,l,n)}finally{await ca(d,{recursive:!0,force:!0}).catch(()=>{})}}finally{mt--}b(e,u[0],u[1])}async function fa(t,e,n,r,i,s,o){let a=Or(t,e);if(await la(a,n,{mode:384}),i.ffmpeg){let l=await(o.measure??Lr)(a,i.ffmpeg);if(l==null)return[422,{error:"This computer couldn't read the recording. Try again."}];if(l*1e3>L.ms+2e3)return[413,{error:gt()}]}let c=[];for(let l of s)try{let u=await ma(l,a,r,i,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 ma(t,e,n,r,i,s){let o=s.engines?.[t];if(o)return o(e,n,r,i);if(t==="elevenlabs")return Mr(e,n,r.key);let a=t==="mlx-whisper"?r.mlx:r.whisper;return Nr(t,a,e,r.ffmpeg,i)}async function ha(t,e,n){let r=await jr(t,da);if(!r)return b(e,413,{error:"request too large"});let i;try{i=JSON.parse(r.toString("utf8")||"{}")}catch{return b(e,400,{error:"expected JSON"})}let s=typeof i?.agent=="string"?i.agent:"",o=typeof i?.peer=="string"&&i.peer?i.peer:void 0;if(!s)return b(e,400,{error:"agent is required"});let a=ya(typeof i?.text=="string"?i.text:"",n.spokenMaxChars?.());if(!a)return b(e,422,{error:"Nothing in this answer can be said aloud."});let c=n.pronounce?n.pronounce(a):a,l=n.voiceOf(s,o);if(!l)return b(e,404,{error:`Unknown agent: ${s}`});let u=(p,g=200)=>b(e,g,{fallback:"browser",reason:p,text:c});if(l.provider!=="elevenlabs")return u("This agent speaks with a system voice, which only plays on the computer.");let d=n.elevenLabsKey();if(!d)return u("No ElevenLabs key is set on this computer.");try{let p=await(n.synth??ba)(d,l,c);e.writeHead(200,{"Content-Type":"audio/mpeg","Content-Length":p.length,"Cache-Control":"no-store","X-Spoken-Chars":String(c.length)}),e.end(p)}catch(p){return n.log(`[voice] phone answer synthesis failed: ${String(p?.message??p).split(`
|
|
466
|
-
`)[0].slice(0,160)}`),u("ElevenLabs could not speak this answer.",502)}}function ya(t,e){let n=rr(Lt(t).text).cleanText.replace(/!\[[^\]\n]*\]\([^)\n]*\)/g,"");return $t(n,e)}async function ba(t,e,n){let r=ye(e.rate),i=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",...r?{voice_settings:{speed:r}}:{}}),signal:AbortSignal.timeout(6e4)});if(!i.ok)throw new Error(`ElevenLabs ${i.status}: ${(await i.text().catch(()=>"")).slice(0,160)}`);return Buffer.from(await i.arrayBuffer())}var wa=()=>`The recording is larger than ${L.bytes/1024/1024} MB, more than ${L.ms/6e4} minutes of speech.`;function Mu(t,e,n,r){if(e)return r.speakerOn(e,t,!1)?.voice??null;let i=n.agents??{};return i[t]?He(Fe(t,i,n.voice)):null}function jr(t,e){return Number(t.headers["content-length"])>e?(t.resume(),Promise.resolve(null)):new Promise((n,r)=>{let i=[],s=0;t.on("data",o=>{if(!(s>e)){if(s+=o.length,s>e){i.length=0,n(null);return}i.push(o)}}),t.on("end",()=>{s<=e&&n(Buffer.concat(i))}),t.on("error",r)})}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 wt,writeFileSync as kt,mkdirSync as be,readdirSync as bt,rmSync as ka,statSync as R}from"fs";import{resolve as Vr,relative as xa,dirname as xt,join as O,extname as Z,basename as St}from"path";var x=200*1024,Wr=new Set([".md",".markdown",".txt"]),U=new Set([".md",".markdown",".txt",".json",".jsonc",".yaml",".yml",".toml",".sh",".bash",".zsh",".py",".js",".mjs",".ts",".tsx",".jsx",".css",".html",".lock",".cfg",".ini",".env",".gitignore"]),Sa=6,va=new Set(["CLAUDE.md","SOUL.md","IDENTITY.md","PERSONA.md","AGENT.md","BOOTSTRAP.md"]);function D(t,e){if(!t)throw new Error("Agent workspace is not configured.");let n=Vr(t);if(v(n)||be(n,{recursive:!0}),!e||e.startsWith("/")||e.match(/^[a-zA-Z]:/))throw new Error(`Path must be relative to the workspace: ${e}`);let r=Vr(n,e);if(xa(n,r).startsWith(".."))throw new Error(`Path escapes the workspace: ${e}`);return r}function Fr(t){let e=Z(t).toLowerCase();if(!Wr.has(e))throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${e}).`)}function ht(t,e){let n=t.split(/\r?\n/).find(r=>r.trim().startsWith("#"));return n&&n.replace(/^#+\s*/,"").trim().slice(0,120)||e}function Vu(t){let e=D(t,"."),n=[],r=new Set,i=[];try{i=bt(e)}catch{}for(let a of va){let c=O(e,a);if(v(c)&&R(c).isFile()){let l=R(c).size,u=l>0&&l<x?yt(c):"";n.push({path:a,title:ht(u,a),size:l,exists:!0}),r.add(a)}else n.push({path:a,title:a,size:0,exists:!1}),r.add(a)}for(let a of i){if(r.has(a))continue;let c=O(e,a);try{let l=R(c);if(!l.isFile()||!Wr.has(Z(a).toLowerCase()))continue;let u=l.size>0&&l.size<x?yt(c):"";n.push({path:a,title:ht(u,a),size:l.size,exists:!0})}catch{}}let s=[],o=O(e,".claude","skills");if(v(o))try{for(let a of bt(o)){let c=O(o,a),l;try{l=R(c)}catch{continue}if(!l.isDirectory())continue;let u=O(c,"SKILL.md");if(!v(u))continue;let d=R(u),p=d.size<x?yt(u):"";s.push({slug:a,title:ht(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 yt(t){try{return wt(t,"utf-8")}catch{return""}}function Wu(t,e){let n=D(t,e);if(Fr(n),!v(n))return{path:e,content:""};if(R(n).size>x)throw new Error(`File is too large to edit in the admin panel (> ${x/1024} KB).`);return{path:e,content:wt(n,"utf-8")}}function Fu(t,e,n){let r=D(t,e);Fr(r);let i=Buffer.from(n,"utf-8");if(i.length>x)throw new Error(`File too large (${i.length} > ${x} bytes).`);return be(xt(r),{recursive:!0}),kt(r,i),{path:e,bytes:i.length}}function Uu(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 r=`.claude/skills/${e}/SKILL.md`,i=D(t,r);if(v(i))throw new Error(`Skill "${e}" already exists.`);be(xt(i),{recursive:!0});let s=n.content?.trim()?n.content:$a(e,n.title);return kt(i,s),{slug:e,path:r}}function Bu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=D(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);if(!R(n).isDirectory())throw new Error(`Skill path is not a directory: ${e}`);return ka(n,{recursive:!0,force:!0}),{slug:e}}function Hu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=D(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);let r=[];return i(n,"",0,r),r.sort((s,o)=>s.kind!==o.kind?s.kind==="dir"?-1:1:s.path.localeCompare(o.path)),r;function i(s,o,a,c){if(a>Sa)return;let l=[];try{l=bt(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,g;try{g=R(d)}catch{continue}if(g.isDirectory())c.push({path:`${p}/`,kind:"dir",size:0,editable:!1}),i(d,p,a+1,c);else if(g.isFile()){let f=Z(u).toLowerCase(),m=U.has(f)||U.has(u.toLowerCase());c.push({path:p,kind:"file",size:g.size,editable:m&&g.size<x})}}}}function zu(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 r=D(t,`.claude/skills/${e}/${n}`);if(!v(r)||!R(r).isFile())throw new Error(`File not found: ${n}`);let i=Z(r).toLowerCase(),s=St(r).toLowerCase();if(!U.has(i)&&!U.has(s))throw new Error(`File type not editable: ${n}`);if(R(r).size>x)throw new Error(`File too large to edit (> ${x/1024} KB): ${n}`);return{path:n,content:wt(r,"utf-8")}}function qu(t,e,n,r){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=D(t,`.claude/skills/${e}/${n}`),s=Z(i).toLowerCase(),o=St(i).toLowerCase();if(!U.has(s)&&!U.has(o))throw new Error(`File type not editable: ${n}`);let a=Buffer.from(r,"utf-8");if(a.length>x)throw new Error(`File too large (${a.length} > ${x} bytes).`);return be(xt(i),{recursive:!0}),kt(i,a),{path:n,bytes:a.length}}function Gu(t,e){if(!/^[a-z0-9][a-z0-9_-]*$/.test(e))throw new Error(`Invalid skill slug: ${e}`);let n=D(t,`.claude/skills/${e}`);if(!v(n))throw new Error(`Skill "${e}" not found.`);let r=i=>v(O(n,i));return r("pnpm-lock.yaml")?{manager:"pnpm",file:"pnpm-lock.yaml",command:"pnpm install"}:r("yarn.lock")?{manager:"yarn",file:"yarn.lock",command:"yarn install"}:r("package.json")?{manager:"npm",file:"package.json",command:"npm install"}:r("requirements.txt")?{manager:"pip",file:"requirements.txt",command:"pip install -r requirements.txt"}:r("Gemfile")?{manager:"bundle",file:"Gemfile",command:"bundle install"}:{manager:null,file:null,command:null}}function $a(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 ${St(t)} --arg value
|
|
480
|
-
\`\`\`
|
|
481
|
-
`}Dt();var Ur={maxPixels:12e5,timeoutMs:5e3,intervalMs:100,changeThreshold:.015,stableMs:400,regions:{},buffer:{enabled:!1,seconds:10,fps:2,region:"screen",maxPixels:3e5}};function Br(t){return{...Ur,...t??{},regions:{...t?.regions??{}},buffer:{...Ur.buffer,...t?.buffer??{}}}}function Ju(t){try{return Br(Ct(t).screen)}catch{return Br(void 0)}}var Aa=/^[a-z][\w-]*$/,Hr=["window","screen","menubar","notifications"];function Q(t,e,n,r){let i=Number(t);if(t===""||t===null||!Number.isFinite(i)||!n(i))throw new Error(`${e} must be ${r}`);return i}var we=(t,e)=>Q(t,e,n=>Number.isInteger(n)&&n>0,"a whole number above 0");function zr(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 Yu(t,e){let n={...t??{}};if("maxPixels"in e&&(n.maxPixels=we(e.maxPixels,"maxPixels")),"timeoutMs"in e&&(n.timeoutMs=we(e.timeoutMs,"timeoutMs")),"intervalMs"in e&&(n.intervalMs=we(e.intervalMs,"intervalMs")),"stableMs"in e&&(n.stableMs=Q(e.stableMs,"stableMs",i=>Number.isInteger(i)&&i>=0,"a whole number, 0 or more")),"changeThreshold"in e&&(n.changeThreshold=Q(e.changeThreshold,"changeThreshold",i=>i>=0&&i<=1,"between 0 and 1")),e.regions&&typeof e.regions=="object"){let i={...n.regions??{}};for(let[s,o]of Object.entries(e.regions)){if(!Aa.test(s))throw new Error(`region name "${s}" must be lowercase letters, digits, - or _`);o===null?delete i[s]:i[s]=zr(o)}n.regions=i}if(e.buffer&&typeof e.buffer=="object"){let i=e.buffer,s={...n.buffer??{}};"enabled"in i&&(s.enabled=!!i.enabled),"seconds"in i&&(s.seconds=Q(i.seconds,"buffer.seconds",o=>o>0&&o<=120,"above 0 and at most 120")),"fps"in i&&(s.fps=Q(i.fps,"buffer.fps",o=>o>0&&o<=10,"above 0 and at most 10")),"maxPixels"in i&&(s.maxPixels=we(i.maxPixels,"buffer.maxPixels")),"region"in i&&(s.region=String(i.region).trim()),n.buffer=s}let r=n.buffer?.region;if(r!==void 0&&!Hr.includes(r)&&!n.regions?.[r])try{zr(r)}catch{throw new Error(`buffer.region "${r}" is not a region \u2014 use ${[...Hr,...Object.keys(n.regions??{})].join(", ")}, or x,y,w,h`)}return n}export{Zt as a,_a as b,tt as c,Bs as d,Hs as e,cl as f,ll as g,ul as h,rr as i,pl as j,fl as k,E as l,ir as m,k as n,Ta as o,Ma as p,bi as q,Fa as r,gn as s,A as t,qa as u,Ga as v,bn as w,Qa as x,q as y,gc as z,vn as A,hl as B,nt as C,sr as D,wl as E,Sl as F,wr as G,Xl as H,Jl as I,nu as J,Uo as K,ru as L,mc as M,hc as N,yc as O,bc as P,wc as Q,kc as R,Sc as S,vc as T,Tc as U,Oe as V,Ec as W,Lc as X,G as Y,K as Z,Ko as _,pu as $,gu as aa,fu as ba,mu as ca,ut as da,hu as ea,We as fa,Fe as ga,ge as ha,ls as ia,ds as ja,Vc as ka,Be as la,He as ma,ps as na,gs as oa,Bn as pa,Gn as qa,Wc as ra,hs as sa,Fc as ta,$s as ua,Rs as va,ze as wa,Cs as xa,Kn as ya,L as za,Pr as Aa,Tr as Ba,Er as Ca,Su as Da,ra as Ea,Mr as Fa,Nr as Ga,Eu as Ha,Lu as Ia,wa as Ja,Mu as Ka,jr as La,fe as Ma,Qc as Na,er as Oa,qe as Pa,Qe as Qa,ol as Ra,Vu as Sa,Wu as Ta,Fu as Ua,Uu as Va,Bu as Wa,Hu as Xa,zu as Ya,qu as Za,Gu as _a,Ur as $a,Br as ab,Ju as bb,Hr as cb,Yu as db};
|
|
482
|
-
//# sourceMappingURL=chunk-2QSG53RN.js.map
|