agentix-cli 0.151.0 → 0.153.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/dist/{App-WAWZFD66.js → App-2SWSYFED.js} +2 -2
- package/dist/{ChatApp-TRJIS3O4.js → ChatApp-NYTNFLIB.js} +2 -2
- package/dist/{absorb-eval-CFWLHUTB.js → absorb-eval-SYX5QN4H.js} +2 -2
- package/dist/agent-UCYQELAQ.js +2 -0
- package/dist/{board-dashboard-5V6RHW3E.js → board-dashboard-OZJSS6EM.js} +405 -241
- package/dist/board-dashboard-OZJSS6EM.js.map +1 -0
- package/dist/{chunk-X6C6U4GL.js → chunk-24QMHUU2.js} +5 -5
- package/dist/{chunk-X6C6U4GL.js.map → chunk-24QMHUU2.js.map} +1 -1
- package/dist/{chunk-4GXJMHSA.js → chunk-2J2OES2S.js} +2 -2
- package/dist/{chunk-LVS5ESTS.js → chunk-3LU2ZQZJ.js} +2 -2
- package/dist/{chunk-IMITYHBT.js → chunk-3OPW64OM.js} +2 -2
- package/dist/{chunk-O7SYQXKS.js → chunk-5DPN2HIR.js} +8 -8
- package/dist/{chunk-L6IW6HWE.js → chunk-5VPU5FHB.js} +24 -21
- package/dist/chunk-5VPU5FHB.js.map +1 -0
- package/dist/{chunk-ETBDN5WX.js → chunk-BFONYVOM.js} +2 -2
- package/dist/{chunk-X3T2GCSI.js → chunk-CFPRIE6F.js} +2 -2
- package/dist/{chunk-PUSBK2OQ.js → chunk-D6U37WO3.js} +47 -47
- package/dist/chunk-D6U37WO3.js.map +1 -0
- package/dist/{chunk-FGJNSYHM.js → chunk-DPSHY7GN.js} +3 -3
- package/dist/{chunk-EJTKLVIW.js → chunk-FVRREIVV.js} +2 -2
- package/dist/{chunk-ALE354ZC.js → chunk-GDLO7FC7.js} +2 -2
- package/dist/{chunk-Q5NLNLD5.js → chunk-HVNWI63Z.js} +2 -2
- package/dist/{chunk-C5UTFHPB.js → chunk-I45WFYGM.js} +2 -2
- package/dist/{chunk-6LFOX6Q5.js → chunk-IJQ2UUMZ.js} +289 -272
- package/dist/chunk-IJQ2UUMZ.js.map +1 -0
- package/dist/{chunk-UG2OF2EI.js → chunk-IVBCCSDR.js} +2 -2
- package/dist/{chunk-2PJKGZWP.js → chunk-JNG3P5V2.js} +2 -2
- package/dist/chunk-JNG3P5V2.js.map +1 -0
- package/dist/{chunk-DWXCZRBJ.js → chunk-JPZBWHNZ.js} +2 -2
- package/dist/{chunk-XVJXXELY.js → chunk-LH3GOBZP.js} +2 -2
- package/dist/{chunk-UALK4F3W.js → chunk-MM3ABEOW.js} +2 -2
- package/dist/chunk-MOCDP7Q3.js +36 -0
- package/dist/chunk-MOCDP7Q3.js.map +1 -0
- package/dist/{chunk-TZZBGWLX.js → chunk-MWYPW5XP.js} +6 -6
- package/dist/{chunk-V3VWYIJ3.js → chunk-P24P43ZB.js} +2 -2
- package/dist/{chunk-DFGANY25.js → chunk-R4R7EYY3.js} +2 -2
- package/dist/{chunk-DJQIJF4R.js → chunk-RJCHFDF3.js} +2 -2
- package/dist/{chunk-XD7HTMOP.js → chunk-RUQMUDSX.js} +2 -2
- package/dist/{chunk-YGDJV4ZZ.js → chunk-S5FRIHWM.js} +2 -2
- package/dist/chunk-SW6HCRLU.js +862 -0
- package/dist/chunk-SW6HCRLU.js.map +1 -0
- package/dist/{chunk-Y5MFVVTM.js → chunk-U23LVMMZ.js} +2 -2
- package/dist/{chunk-RGJZV5RY.js → chunk-UUVJX6WD.js} +2 -2
- package/dist/{chunk-2GJQDJBF.js → chunk-Z2KGUEB6.js} +2 -2
- package/dist/{chunk-CTQ25CUL.js → chunk-ZQONMM3B.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-VT7GT3SK.js → client-PBIUMGDL.js} +2 -2
- package/dist/{compaction-FS6XNRLM.js → compaction-PFXWL4H7.js} +3 -3
- package/dist/{config-NZS2UTHI.js → config-VLH5DJTH.js} +2 -2
- package/dist/{config-mutate-LINLC354.js → config-mutate-G7HW2R6H.js} +2 -2
- package/dist/config-mutator-XWWW3PSV.js +2 -0
- package/dist/{context-planner-3JDA7FNR.js → context-planner-DJB6CKY6.js} +2 -2
- package/dist/{contributions-67B3BYLV.js → contributions-GZVKJXSJ.js} +2 -2
- package/dist/{doctor-FOKX4K2G.js → doctor-UT32WKCP.js} +2 -2
- package/dist/{follow-up-tool-JOIOYOON.js → follow-up-tool-PTKDMFA7.js} +2 -2
- package/dist/{grants-QXF7N6SS.js → grants-HSLB62EG.js} +2 -2
- package/dist/heal-RGM7X2ZG.js +2 -0
- package/dist/hub-BHCBRQZP.js +2 -0
- package/dist/index.d.ts +341 -7
- package/dist/index.js +1 -1
- package/dist/memory-extract-GHLBXV4H.js +2 -0
- package/dist/{program-XFZBG3EI.js → program-NU6QIXJJ.js} +239 -233
- package/dist/program-NU6QIXJJ.js.map +1 -0
- package/dist/{promote-WNYNTGKC.js → promote-73ZGTRDV.js} +2 -2
- package/dist/{providers-55NC2SFN.js → providers-BDJXGHEY.js} +2 -2
- package/dist/{query-ZU2DDCEH.js → query-KHW4AERR.js} +2 -2
- package/dist/{query-settings-BXRIJWWO.js → query-settings-P6RUUEFO.js} +2 -2
- package/dist/{registry-7BITIEQ2.js → registry-RQBXAPUZ.js} +2 -2
- package/dist/{request-planner-DLQP2NV6.js → request-planner-EUIMJ7R3.js} +2 -2
- package/dist/{review-candidates-3BMHLIBW.js → review-candidates-KKGDAZIB.js} +2 -2
- package/dist/routing-FQNGOTMV.js +2 -0
- package/dist/schedule-tool-2OWGAK4H.js +2 -0
- package/dist/{scheduler-SYI5MZ3H.js → scheduler-JXZBVPOS.js} +2 -2
- package/dist/{seat-6JF7BYM7.js → seat-DZB3NSZ7.js} +2 -2
- package/dist/{select-JT4I3JOH.js → select-YD4CA7FP.js} +2 -2
- package/dist/{set-enabled-JRGFKA3S.js → set-enabled-UK4SE5MZ.js} +2 -2
- package/dist/tool-2PA2USUG.js +6 -0
- package/dist/tool-2PA2USUG.js.map +1 -0
- package/dist/{tool-P6GVYNDO.js → tool-DIJN4XBY.js} +2 -2
- package/dist/wiki-CQBXLZ2Y.js +2 -0
- package/dist/wiki-enrich-PA6JS2YN.js +2 -0
- package/package.json +1 -1
- package/dist/agent-6KCTPI7E.js +0 -2
- package/dist/board-dashboard-5V6RHW3E.js.map +0 -1
- package/dist/chunk-2PJKGZWP.js.map +0 -1
- package/dist/chunk-5I7NJMK6.js +0 -35
- package/dist/chunk-5I7NJMK6.js.map +0 -1
- package/dist/chunk-6LFOX6Q5.js.map +0 -1
- package/dist/chunk-CBML7UCP.js +0 -861
- package/dist/chunk-CBML7UCP.js.map +0 -1
- package/dist/chunk-L6IW6HWE.js.map +0 -1
- package/dist/chunk-PUSBK2OQ.js.map +0 -1
- package/dist/config-mutator-FUMSW5HD.js +0 -2
- package/dist/heal-U67X6NIN.js +0 -2
- package/dist/hub-QETWDYPD.js +0 -2
- package/dist/memory-extract-ATD6YLRK.js +0 -2
- package/dist/program-XFZBG3EI.js.map +0 -1
- package/dist/routing-FVZCQJ6T.js +0 -2
- package/dist/schedule-tool-TDVJHRQX.js +0 -2
- package/dist/tool-UDOUNWQT.js +0 -6
- package/dist/tool-UDOUNWQT.js.map +0 -1
- package/dist/wiki-MTZHDFHK.js +0 -2
- package/dist/wiki-enrich-CHR4RCRE.js +0 -2
- /package/dist/{App-WAWZFD66.js.map → App-2SWSYFED.js.map} +0 -0
- /package/dist/{ChatApp-TRJIS3O4.js.map → ChatApp-NYTNFLIB.js.map} +0 -0
- /package/dist/{absorb-eval-CFWLHUTB.js.map → absorb-eval-SYX5QN4H.js.map} +0 -0
- /package/dist/{agent-6KCTPI7E.js.map → agent-UCYQELAQ.js.map} +0 -0
- /package/dist/{chunk-4GXJMHSA.js.map → chunk-2J2OES2S.js.map} +0 -0
- /package/dist/{chunk-LVS5ESTS.js.map → chunk-3LU2ZQZJ.js.map} +0 -0
- /package/dist/{chunk-IMITYHBT.js.map → chunk-3OPW64OM.js.map} +0 -0
- /package/dist/{chunk-O7SYQXKS.js.map → chunk-5DPN2HIR.js.map} +0 -0
- /package/dist/{chunk-ETBDN5WX.js.map → chunk-BFONYVOM.js.map} +0 -0
- /package/dist/{chunk-X3T2GCSI.js.map → chunk-CFPRIE6F.js.map} +0 -0
- /package/dist/{chunk-FGJNSYHM.js.map → chunk-DPSHY7GN.js.map} +0 -0
- /package/dist/{chunk-EJTKLVIW.js.map → chunk-FVRREIVV.js.map} +0 -0
- /package/dist/{chunk-ALE354ZC.js.map → chunk-GDLO7FC7.js.map} +0 -0
- /package/dist/{chunk-Q5NLNLD5.js.map → chunk-HVNWI63Z.js.map} +0 -0
- /package/dist/{chunk-C5UTFHPB.js.map → chunk-I45WFYGM.js.map} +0 -0
- /package/dist/{chunk-UG2OF2EI.js.map → chunk-IVBCCSDR.js.map} +0 -0
- /package/dist/{chunk-DWXCZRBJ.js.map → chunk-JPZBWHNZ.js.map} +0 -0
- /package/dist/{chunk-XVJXXELY.js.map → chunk-LH3GOBZP.js.map} +0 -0
- /package/dist/{chunk-UALK4F3W.js.map → chunk-MM3ABEOW.js.map} +0 -0
- /package/dist/{chunk-TZZBGWLX.js.map → chunk-MWYPW5XP.js.map} +0 -0
- /package/dist/{chunk-V3VWYIJ3.js.map → chunk-P24P43ZB.js.map} +0 -0
- /package/dist/{chunk-DFGANY25.js.map → chunk-R4R7EYY3.js.map} +0 -0
- /package/dist/{chunk-DJQIJF4R.js.map → chunk-RJCHFDF3.js.map} +0 -0
- /package/dist/{chunk-XD7HTMOP.js.map → chunk-RUQMUDSX.js.map} +0 -0
- /package/dist/{chunk-YGDJV4ZZ.js.map → chunk-S5FRIHWM.js.map} +0 -0
- /package/dist/{chunk-Y5MFVVTM.js.map → chunk-U23LVMMZ.js.map} +0 -0
- /package/dist/{chunk-RGJZV5RY.js.map → chunk-UUVJX6WD.js.map} +0 -0
- /package/dist/{chunk-2GJQDJBF.js.map → chunk-Z2KGUEB6.js.map} +0 -0
- /package/dist/{chunk-CTQ25CUL.js.map → chunk-ZQONMM3B.js.map} +0 -0
- /package/dist/{client-VT7GT3SK.js.map → client-PBIUMGDL.js.map} +0 -0
- /package/dist/{compaction-FS6XNRLM.js.map → compaction-PFXWL4H7.js.map} +0 -0
- /package/dist/{config-NZS2UTHI.js.map → config-VLH5DJTH.js.map} +0 -0
- /package/dist/{config-mutate-LINLC354.js.map → config-mutate-G7HW2R6H.js.map} +0 -0
- /package/dist/{config-mutator-FUMSW5HD.js.map → config-mutator-XWWW3PSV.js.map} +0 -0
- /package/dist/{context-planner-3JDA7FNR.js.map → context-planner-DJB6CKY6.js.map} +0 -0
- /package/dist/{contributions-67B3BYLV.js.map → contributions-GZVKJXSJ.js.map} +0 -0
- /package/dist/{doctor-FOKX4K2G.js.map → doctor-UT32WKCP.js.map} +0 -0
- /package/dist/{follow-up-tool-JOIOYOON.js.map → follow-up-tool-PTKDMFA7.js.map} +0 -0
- /package/dist/{grants-QXF7N6SS.js.map → grants-HSLB62EG.js.map} +0 -0
- /package/dist/{heal-U67X6NIN.js.map → heal-RGM7X2ZG.js.map} +0 -0
- /package/dist/{hub-QETWDYPD.js.map → hub-BHCBRQZP.js.map} +0 -0
- /package/dist/{memory-extract-ATD6YLRK.js.map → memory-extract-GHLBXV4H.js.map} +0 -0
- /package/dist/{promote-WNYNTGKC.js.map → promote-73ZGTRDV.js.map} +0 -0
- /package/dist/{providers-55NC2SFN.js.map → providers-BDJXGHEY.js.map} +0 -0
- /package/dist/{query-ZU2DDCEH.js.map → query-KHW4AERR.js.map} +0 -0
- /package/dist/{query-settings-BXRIJWWO.js.map → query-settings-P6RUUEFO.js.map} +0 -0
- /package/dist/{registry-7BITIEQ2.js.map → registry-RQBXAPUZ.js.map} +0 -0
- /package/dist/{request-planner-DLQP2NV6.js.map → request-planner-EUIMJ7R3.js.map} +0 -0
- /package/dist/{review-candidates-3BMHLIBW.js.map → review-candidates-KKGDAZIB.js.map} +0 -0
- /package/dist/{routing-FVZCQJ6T.js.map → routing-FQNGOTMV.js.map} +0 -0
- /package/dist/{schedule-tool-TDVJHRQX.js.map → schedule-tool-2OWGAK4H.js.map} +0 -0
- /package/dist/{scheduler-SYI5MZ3H.js.map → scheduler-JXZBVPOS.js.map} +0 -0
- /package/dist/{seat-6JF7BYM7.js.map → seat-DZB3NSZ7.js.map} +0 -0
- /package/dist/{select-JT4I3JOH.js.map → select-YD4CA7FP.js.map} +0 -0
- /package/dist/{set-enabled-JRGFKA3S.js.map → set-enabled-UK4SE5MZ.js.map} +0 -0
- /package/dist/{tool-P6GVYNDO.js.map → tool-DIJN4XBY.js.map} +0 -0
- /package/dist/{wiki-MTZHDFHK.js.map → wiki-CQBXLZ2Y.js.map} +0 -0
- /package/dist/{wiki-enrich-CHR4RCRE.js.map → wiki-enrich-PA6JS2YN.js.map} +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import{a as N}from"./chunk-IMLAPB7G.js";import{k as y}from"./chunk-24QMHUU2.js";import{b as V}from"./chunk-KP7KDLZ2.js";import{I as B,J,K as X,L as K,P as k,T as Pe}from"./chunk-5VPU5FHB.js";import{existsSync as z,readFileSync as $e}from"node:fs";import{dirname as b,join as h}from"node:path";import{fileURLToPath as Oe}from"node:url";import{homedir as Ee}from"node:os";var M="tn.acme.agentx.voice",dt="AgentX Desktop.app",Y="AgentX Helper.app";function mt(e,t,n){return e!=="darwin"||t!=="arm64"||Number(n.split(".")[0])<23?"AgentX Desktop currently requires Apple Silicon and macOS 14 or newer.":null}function ft(e,t){if(t&&!Object.hasOwn(e,t))throw new Error(`Unknown agent: ${t}. Run agentx agent list.`);let n=t||Object.keys(e)[0];if(!n)throw new Error("No agents configured. Run agentx setup first.");return n}function I(e){return`'${e.replace(/'/g,"'\\''")}'`}var Z="/usr/bin:/bin:/usr/sbin:/sbin";function gt(e,t){return t||[...new Set([...e?[b(e)]:[],...Z.split(":")])].join(":")}function A(e){let t={amp:"&",lt:"<",gt:">",quot:'"',apos:"'"};return e.replace(/&(amp|lt|gt|quot|apos);/g,(n,r)=>t[r])}function yt(e){let t=e.match(/<key>PATH<\/key>\s*<string>([^<]*)<\/string>/);return t?A(t[1]):Z}var ht=e=>/agentx\.voice.*\.plist$/.test(e);function wt(e,t){let n=null,r=[];for(let{file:o,plist:i}of[...t].sort((s,u)=>s.file<u.file?-1:1)){let s=i.match(/<key>Label<\/key>\s*<string>([^<]*)<\/string>/)?.[1],u=i.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/)?.[1];!s||!u||!A(u).endsWith("/Contents/MacOS/AgentXVoice")||(n?r.push({file:o,label:A(s)}):n={file:o,label:A(s)})}return{keep:n??{file:h(e,`${M}.plist`),label:M},remove:r}}function Q(e,t,n){for(let r of t.split(":"))if(r&&n(h(r,e)))return h(r,e);return null}function St(e){let t=r=>r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),n={PATH:e.path,...e.agent?{AGENTX_VOICE_AGENT:e.agent}:{},AGENTX_DAEMON_URL:e.url,AGENTX_MAC_HELPER:e.helper,AGENTX_PASTE_COMMAND:`cd ${I(e.cwd)} && ${I(e.node)} ${I(e.cli)} paste`};return`<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0"><dict>
|
|
4
|
+
<key>Label</key><string>${t(e.label??M)}</string>
|
|
5
|
+
<key>ProgramArguments</key><array><string>${t(e.executable)}</string></array>
|
|
6
|
+
<key>WorkingDirectory</key><string>${t(e.cwd)}</string>
|
|
7
|
+
<key>EnvironmentVariables</key><dict>${Object.entries(n).map(([r,o])=>`<key>${r}</key><string>${t(o)}</string>`).join("")}</dict>
|
|
8
|
+
<key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
|
|
9
|
+
<key>ProcessType</key><string>Interactive</string>
|
|
10
|
+
<key>StandardErrorPath</key><string>${t(e.log)}</string>
|
|
11
|
+
</dict></plist>
|
|
12
|
+
`}function xt(e){return e?["--icon",e]:[]}function Ce(e){return h(e,"Applications",Y,"Contents/MacOS/agentx-mac-helper")}function Te(e=b(Oe(import.meta.url))){for(let t=e;;t=b(t)){try{if(JSON.parse($e(h(t,"package.json"),"utf8")).name==="agentix-cli")return t}catch{}if(b(t)===t)return null}}function Ie(e,t,n){if(n)return n;let r=Ce(t);return z(r)||!e?r:h(e,"apps/mac-helper/build",Y,"Contents/MacOS/agentx-mac-helper")}function _(){let e=Ie(Te(),Ee(),process.env.AGENTX_MAC_HELPER);return z(e)?e:null}import{accessSync as Fe,constants as He}from"fs";import{execFile as L}from"child_process";var ee=5e3,R=(e,t)=>new Promise(n=>{try{L(e,t,{timeout:ee},r=>n(!r))}catch{n(!1)}}),P=(e,t)=>new Promise(n=>{try{L(e,t,{timeout:ee},(r,o)=>n(r?null:String(o)))}catch{n(null)}}),$=(e,t)=>new Promise((n,r)=>{L(e,t,{timeout:3e4,maxBuffer:8*1024*1024},(o,i,s)=>{o?r(new Error(`${e} ${t[0]}: ${(s||o.message).trim()}`)):n(i)})});var te=e=>e.helper===void 0?_():e.helper;async function Me(e,t=P){if(!e)return"missing";let n=await t(e,["notify-status"]),r=null;try{r=n?JSON.parse(n):null}catch{r=null}return r?r.authorization==="notDetermined"?"not-asked":r.authorization==="denied"?"not-allowed":r.alertStyle==="none"?"hidden":"ready":"outdated"}function ne(e={}){let t=e.run??R;return{async post({title:n,message:r}){let o=te(e);return o&&await t(o,["notify","--title",n,"--message",r])||await t("/usr/bin/osascript",["-e","on run argv","-e","display notification (item 2 of argv) with title (item 1 of argv)","-e","end run",n,r])?"posted":"failed"},status:()=>Me(te(e),e.capture)}}var _e=`
|
|
13
|
+
function run(argv) {
|
|
14
|
+
var folderName = argv[0], title = argv[1], body = argv[2]
|
|
15
|
+
var Notes = Application("Notes")
|
|
16
|
+
var esc = function (s) { return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") }
|
|
17
|
+
var folder = Notes.folders.whose({ name: folderName })()[0]
|
|
18
|
+
if (!folder) {
|
|
19
|
+
folder = Notes.Folder({ name: folderName })
|
|
20
|
+
Notes.folders.push(folder)
|
|
21
|
+
folder = Notes.folders.whose({ name: folderName })()[0]
|
|
22
|
+
}
|
|
23
|
+
var lines = body.split("\\n").map(function (l) { return "<div>" + (l ? esc(l) : "<br>") + "</div>" })
|
|
24
|
+
// Notes takes the title from the first line: a name as well would show it twice.
|
|
25
|
+
var note = Notes.Note({ body: "<div><h1>" + esc(title) + "</h1></div>" + lines.join("") })
|
|
26
|
+
folder.notes.push(note)
|
|
27
|
+
return note.id()
|
|
28
|
+
}
|
|
29
|
+
`;function re(e=$){return{async add({folder:t,title:n,body:r}){let i=(await e("/usr/bin/osascript",["-l","JavaScript","-e",_e,t,n,r])).trim();if(!i)throw new Error("Notes did not return the new note's id");return{id:i}}}}import{existsSync as Le,readdirSync as De}from"fs";var oe="/System/Library/Sounds";function ie(e){if(!/^[\w -]+$/.test(e))return null;let t=`${oe}/${e}.aiff`;return Le(t)?t:null}function se(e={}){let t=e.run??R;return{async play(n,r){let o=ie(n);o&&await t("/usr/bin/afplay",["-v",String(Math.min(1,Math.max(0,r))),o])},has:n=>ie(n)!==null,async names(){try{return De(oe).filter(n=>n.endsWith(".aiff")).map(n=>n.slice(0,-5)).sort()}catch{return[]}}}}var ae={say:"a spoken line (say)",afplay:"a sound playing (afplay)"};function qe(e,t,n=process.pid){for(let r of e.split(`
|
|
30
|
+
`)){let o=r.trim().match(/^(\d+)\s+(\d+)\s+(\S+)/);if(!o)continue;let[i,s,u]=[Number(o[1]),Number(o[2]),o[3]],l=u.slice(u.lastIndexOf("/")+1);if(!(!(l in ae)||i===n||t.includes(s)))return ae[l]}return null}function ue(e={}){let t=e.capture??P;return{async othersSpeaking(n={}){let r=await t("/bin/ps",["-axo","pid=,ppid=,comm="]);return r?qe(r,n.exceptParents??[]):null}}}var pe="\u200B";function O(e){return e.startsWith("-")?pe+e:e}var le=e=>e?.startsWith(pe+"-")?e.slice(1):e;function D(e){if(!e.trim()||e.startsWith("-"))throw new Error(`Reminders list name "${e}" is not usable: it must not be empty or start with "-"`);return e}var ce=e=>new Date(Math.floor(e.getTime()/6e4)*6e4).toISOString().replace(/\.\d{3}Z$/,"Z");function de(e="remindctl",t=$){return{async ensureList(n){let r=await t(e,["list","--json","--no-input"]),o=JSON.parse(r.trim()||"[]");if(!Array.isArray(o))throw new Error(`${e} list: expected a JSON array`);o.some(i=>i?.title===n)||await t(e,["list",D(n),"--create","--json","--no-input"])},async listOpen(n){let r=await t(e,["show","all","--list",D(n),"--json","--no-input"]),o=JSON.parse(r.trim()||"[]");if(!Array.isArray(o))throw new Error(`${e} show: expected a JSON array`);return o.filter(i=>i&&typeof i.id=="string"&&!i.isCompleted).map(i=>({...i,title:le(i.title)??"",...i.notes!==void 0?{notes:le(i.notes)}:{}}))},async add({list:n,title:r,notes:o,due:i,priority:s}){let u=["add","--title",O(r),"--list",D(n),"--notes",O(o)];i&&u.push("--due",ce(i)),s&&s!=="none"&&u.push("--priority",s);let l=await t(e,[...u,"--json","--no-input"]),p;try{p=JSON.parse(l.trim())?.id}catch{p=void 0}if(typeof p!="string"||!p)throw new Error(`${e} add: no reminder id in its answer`);return{id:p}},async update(n,r){let o=["edit",n];r.title!==void 0&&o.push("--title",O(r.title)),r.notes!==void 0&&o.push("--notes",O(r.notes)),r.due===null?o.push("--clear-due"):r.due&&o.push("--due",ce(r.due)),o.length!==2&&await t(e,[...o,"--json","--no-input"])},async complete(n){await t(e,["complete",n,"--json","--no-input"])},async remove(n){await t(e,["delete",n,"--force","--json","--no-input"])}}}var We=e=>{try{return Fe(e,He.X_OK),!0}catch{return!1}},je={async active(){let e=V();return e.active?!0:e.reason==="no active Focus assertion"?!1:null}};function me(e={},t={}){let n=e.reminders?.command||"remindctl";return{os:"macos",tasks:de(n,t.output),notes:re(t.output),banner:ne(t),sound:se(t),focus:je,speech:ue(t),async describe(){let r=[],o=t.isExecutable??We;return(n.includes("/")?o(n):!!Q(n,process.env.PATH||"",o))||r.push(`Reminders: ${n} not found (brew install steipete/tap/remindctl, or set reminders.command).`),{os:"macos",tasks:!0,notes:!0,banner:!0,sound:!0,focus:!0,problems:r}}}}function E(e){return{os:"none",async describe(){return{os:"none",tasks:!1,notes:!1,banner:!1,sound:!1,focus:!1,problems:[e]}}}}var Ue={darwin:me};function q(e={},t={}){if(e.native?.adapter==="none")return E('Turned off: native.adapter is "none".');let n=t.platform??process.platform,r=(t.factories??Ue)[n];return r?r(e,t.io??{}):E(`AgentX has no native adapter for ${n} yet.`)}import{existsSync as Ge}from"fs";import{homedir as Be}from"os";import{isAbsolute as Je}from"path";var fe={banner:!0,sound:!0,soundName:"Glass",volume:.4,quietWaitSeconds:15};function tn(e){return{...fe,...e??{}}}function nn(e,t={}){let n=q({native:t.native},{platform:t.platform,io:{run:t.run,capture:t.capture,helper:t.helper}});return async(r,o)=>{let i=[];if(e.banner&&n.banner&&i.push(n.banner.post({title:r,message:o})),e.sound&&n.sound){let s=n.sound;i.push(Xe(n.speech,(e.quietWaitSeconds??fe.quietWaitSeconds)*1e3,t.pollMs??500).then(u=>u?s.play(e.soundName,e.volume):void 0))}await Promise.all(i)}}async function Xe(e,t,n){if(!e||t<=0)return!0;let r=Date.now()+t;for(;;){if(!await e.othersSpeaking())return!0;if(Date.now()>=r)return!1;await new Promise(o=>setTimeout(o,n))}}function rn(e,t,n=process.platform){let r={...e??{}},o=q({},{platform:n});if("banner"in t&&(r.banner=!!t.banner),"sound"in t&&(r.sound=!!t.sound),"soundName"in t){let i=String(t.soundName).trim();if(!(o.sound?o.sound.has(i):/^[\w -]+$/.test(i)))throw new Error(`no system sound named "${i}" on this machine`);r.soundName=i}if("icon"in t){let i=String(t.icon??"").trim().replace(/^~(?=\/)/,Be());if(!i)delete r.icon;else{if(!Je(i)||!/\.(png|jpe?g|icns)$/i.test(i))throw new Error("icon must be the full path to a .png, .jpg or .icns file");if(o.banner&&!Ge(i))throw new Error(`no icon file at ${i}`);r.icon=i}}if("volume"in t){let i=Number(t.volume);if(!Number.isFinite(i)||i<0||i>1)throw new Error("volume must be between 0 and 1");r.volume=i}return r}import{existsSync as Ze,mkdirSync as Qe,readFileSync as et,renameSync as tt,writeFileSync as nt}from"fs";import{dirname as xe,resolve as rt}from"path";X();Pe();X();var ln=["owner","agent","person"],Ke=36e5,Ve=e=>K.includes(e.state);function ge(e){return t=>!e||e.get(t)?.state!=="active"?null:e.steps(t).find(n=>n.state==="active")?.agentId??null}function F(e,t){return e.state==="waiting_owner"?{group:"owner",who:k}:e.promise&&e.owedTo&&e.owedTo!==k&&!t.isAgent(e.owedTo)?{group:"person",who:e.owedTo}:e.state==="needs_attention"?{group:"owner",who:k}:{group:"agent",who:t.activeStepAgent?.(e.id)??e.agentId}}function H(e,t,n){return Ve(e)?e.state==="needs_attention"?e.attentionReason??"needs attention":e.dueAt!==null?n>e.dueAt?`past its due time (${ze(e.dueAt)})`:null:n-e.updatedAt>t*Ke?`no activity for ${t} h or more`:null:null}function cn(e,t,n,r){let o={owner:[],agent:[],person:[]};for(let i of e){let s=H(i,t,n);if(!s)continue;let{group:u,who:l}=F(i,r);o[u].push({request:i,group:u,who:l,why:s})}return o}function pn(e,t){return e==="owner"?"you":e==="agent"?`agent ${t}`:`${t} (outside person)`}var ze=e=>new Date(e).toISOString().slice(0,16).replace("T"," ")+" UTC";function dn(e){if(e==null||e==="")return;let t=typeof e=="number"?e:typeof e=="string"?Date.parse(e.trim()):NaN;return!Number.isFinite(t)||t<=0?"due must be an ISO date (2030-01-31T17:00:00Z) or epoch milliseconds":t}function mn(e){return t=>B(t,e())}var Ye=10;async function fn(e,t,n){let r=e.dueForCheck(n.now-n.everyMinutes*6e4,Ye),o=0;return await Promise.all(r.map(async i=>{e.markChecked(i.id,i.verifyState,i.verifyDetail??"",n.now);let s=await t(i.closeWhen,i).catch(u=>({verdict:"unverifiable",detail:String(u?.message??u)}));if(s.verdict==="met"){e.closeVerified(i.id,s.detail,n.now)&&(o++,n.log(`[requests] ${i.id} closed by its check: ${s.detail}`));return}e.markChecked(i.id,s.verdict==="unverifiable"?"unverified":i.verifyState==="failed"?"failed":null,s.detail,n.now)})),{checked:r.length,closed:o}}var we=200,ye=4e3,he="Nothing, just so you know.";function W(e,t=we){let n=e.headline?e.headline.length>t?`${e.headline.slice(0,t-1)}\u2026`:e.headline:f(e.text,t),r=e.state==="needs_attention"?`Hand it back to ${e.agentId}, or drop it.`:e.state==="waiting_owner"?e.need??(e.question?`Answer: ${f(e.question,150)}`:"Your answer."):e.state==="candidate"||e.state==="in_progress"||e.state==="waiting_other"?e.need??he:he;return{headline:n,need:r,said:Se(e.text)}}function Se(e){return e.replace(/```[\s\S]*?```/g," ").replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/^\s{0,3}(#{1,6}|>|[-*+]|\d+[.)])\s+/gm,"").replace(/[*_~`]+/g,"").replace(/\s+/g," ").trim()}function f(e,t=we){let n=Se(e);if(n.length<=t)return n;let r=n.slice(0,t),o=Math.max(r.lastIndexOf(". "),r.lastIndexOf("? "),r.lastIndexOf("! "));return o>t/2?r.slice(0,o+1):`${r.slice(0,t-1).trimEnd()}\u2026`}function Sn(e,t,n,r){let o=n?.get(e.id),i=r?H(e,r.staleAfterHours,r.now):null,s=t.lastAnswer(e.id),u=s&&s.text.length>ye?`${s.text.slice(0,ye)}
|
|
31
|
+
|
|
32
|
+
\u2026`:s?.text,l=W(e);return{...e,summary:l.headline,needed:l.need,textHtml:N(e.text),why:e.state==="waiting_owner"?e.question:e.state==="needs_attention"?e.attentionReason:null,ownerNoteHtml:e.ownerNote?N(e.ownerNote):null,lastAnswer:s?{agentId:s.agentId,at:s.at,html:N(u)}:null,loop:e.promise||e.dueAt!==null||e.closeWhen?{owedTo:e.owedTo,promise:e.promise,dueAt:e.dueAt,check:e.closeWhen?J(e.closeWhen):null,verifyState:e.verifyState,verifyDetail:e.verifyDetail}:null,stall:r&&i?{...F(e,{isAgent:r.isAgent,activeStepAgent:ge(n)}),why:i}:null,plan:o?{state:o.state,steps:n.steps(e.id).map(p=>({idx:p.idx,name:p.name,kind:p.kind,agentId:p.agentId,state:p.state,approval:p.needsApproval?p.approval:null,evidence:p.evidence,note:p.note,nudges:p.nudges}))}:null}}var j=3,it=30*24*36e5;function ke(e){return rt(e,".agentx","native-mirror.json")}function Ne(e){try{let t=JSON.parse(et(ke(e),"utf-8"));return{...t,items:t?.items&&typeof t.items=="object"?t.items:{}}}catch{return{items:{}}}}function ve(e,t){let n=ke(e);Ze(xe(n))||Qe(xe(n),{recursive:!0});let r=`${n}.${process.pid}.tmp`;nt(r,JSON.stringify(t,null,2)+`
|
|
33
|
+
`),tt(r,n)}var ot=5*6e4;function An(e,t,n=Date.now()){let r=Ne(e),o=r.checkedAt?Date.parse(r.checkedAt):NaN;return!r.cards||!(n-o<=ot)?!1:r.items[`card:${t}`]?.state!=="failed"}var U=24*36e5;function be(e,t,n){let r=e+t.dueAfterMinutes*6e4;return new Date(n!==void 0&&Number.isFinite(n)?Math.max(e,Math.min(r,n)):r)}function st(e,t,n,r){let o=Date.parse(e.expires),i=[f(e.ask,y.ask)];return e.choices?.length&&i.push(...e.choices.map((s,u)=>`${u+1}. ${s}`)),e.recommend&&i.push(`Recommended: ${f(e.recommend,y.recommend)}`),i.push(`Answer: ${n}`,`agentx: card=${e.id}`),{key:`card:${e.id}`,title:f(e.title,y.title),notes:i.join(`
|
|
34
|
+
`),due:be(r,t,o),priority:Number.isFinite(o)&&o-r<=U?"high":"none"}}function at(e,t,n,r){let o=[f(e.question||e.text,y.ask),`Asked of ${e.agentId}.`,`Answer: ${n}`,`agentx: request=${e.id}`],i=e.dueAt??void 0;return{key:`request:${e.id}`,title:W(e,y.title).headline,notes:o.join(`
|
|
35
|
+
`),due:be(r,t,i),priority:i!==void 0&&i-r<=U?"high":"none"}}async function Rn(e){let{root:t,settings:n,tasks:r,log:o}=e,i=e.now??Date.now(),s=new Date(i).toISOString(),u={created:0,completed:0,dismissed:0,failed:0},l=Ne(t);delete l.lastError;let p=a=>{l.lastError={at:s,message:a}},w=new Map;try{if(n.include.includes("card"))for(let a of e.cards())a.status==="pending"&&Date.parse(a.expires)>i&&w.set(`card:${a.id}`,st(a,n,e.answerUrl,i));if(n.include.includes("request"))for(let a of e.requests())a.state==="waiting_owner"&&w.set(`request:${a.id}`,at(a,n,e.answerUrl,i))}catch(a){return o(`[mirror] could not read what is waiting: ${a?.message??a}`),p(String(a?.message??a)),ve(t,l),u}let G=!0,x=new Map,Ae=async a=>{if(!x.has(a))try{x.set(a,new Set((await r.listOpen(a)).map(c=>c.id)))}catch(c){o(`[mirror] could not read list "${a}": ${c?.message??c}`),p(String(c?.message??c)),x.set(a,null),G=!1}return x.get(a)};for(let[a,c]of Object.entries(l.items)){if(c.state!=="open"||!c.id)continue;let d=await Ae(c.list);if(d)if(w.has(a))d.has(c.id)||(l.items[a]={...c,state:"dismissed",at:s},u.dismissed++,o(`[mirror] ${a}: its task was ticked off or deleted; it stays on the Desk and is not mirrored again`));else{if(d.has(c.id))try{await r.complete(c.id)}catch(g){o(`[mirror] ${a}: could not complete its task: ${g?.message??g}`),p(String(g?.message??g));continue}l.items[a]={...c,state:"completed",at:s},u.completed++}}let C=null,S=[];for(let[a,c]of w){let d=l.items[a];if(d&&(d.state==="open"||d.state==="dismissed")||d?.state==="failed"&&d.failures>=j)continue;if(C===null)try{await r.ensureList(n.list),C=!0}catch(m){o(`[mirror] could not make list "${n.list}": ${m?.message??m}`),p(String(m?.message??m)),C=!1}let g=d?.state==="failed"?d.failures:0;try{let{id:m}=await r.add({list:n.list,title:c.title,notes:c.notes,due:c.due,priority:c.priority});l.items[a]={id:m,list:n.list,state:"open",at:s,failures:0},u.created++}catch(m){let v=String(m?.message??m),T=g+1;l.items[a]={list:n.list,state:"failed",at:s,failures:T,lastError:v},p(v),u.failed++,o(`[mirror] ${a}: could not add to Reminders (${T}/${j}): ${v}`),T===j&&S.push({title:c.title,message:v})}}let Re=l.failureToldAt?Date.parse(l.failureToldAt):NaN;if(S.length&&!(i-Re<U)){let a=S[0],c=S.length>1?` (and ${S.length-1} more)`:"";try{await e.notify("Could not add to Reminders",`${a.title}${c}: ${f(a.message,200)}. Still on the Desk.`),l.failureToldAt=s}catch(d){o(`[mirror] could not tell the owner: ${d?.message??d}`)}}G&&(l.checkedAt=s,l.cards=n.include.includes("card"));for(let[a,c]of Object.entries(l.items))c.state!=="open"&&!w.has(a)&&i-Date.parse(c.at)>it&&delete l.items[a];return ve(t,l),u}export{ln as a,ge as b,F as c,cn as d,pn as e,ze as f,dn as g,mn as h,fn as i,W as j,Sn as k,dt as l,Y as m,mt as n,ft as o,gt as p,yt as q,ht as r,wt as s,Q as t,St as u,xt as v,Ce as w,Te as x,Ie as y,_ as z,ie as A,q as B,fe as C,tn as D,nn as E,rn as F,Ne as G,An as H,Rn as I};
|
|
36
|
+
//# sourceMappingURL=chunk-MOCDP7Q3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/desktop/install.ts","../src/native/macos/index.ts","../src/native/macos/run.ts","../src/native/macos/banner.ts","../src/native/macos/notes.ts","../src/native/macos/sound.ts","../src/native/macos/speech.ts","../src/native/macos/tasks.ts","../src/native/none.ts","../src/native/index.ts","../src/notify/local.ts","../src/approvals/mirror.ts","../src/requests/card-view.ts","../src/requests/loops.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { homedir } from 'node:os'\n\nexport const DESKTOP_LABEL = 'tn.acme.agentx.voice'\nexport const DESKTOP_APP = 'AgentX Desktop.app'\nexport const HELPER_APP = 'AgentX Helper.app'\nexport function desktopPlatformError(platform: string, arch: string, release: string): string | null {\n if (platform !== 'darwin' || arch !== 'arm64' || Number(release.split('.')[0]) < 23)\n return 'AgentX Desktop currently requires Apple Silicon and macOS 14 or newer.'\n return null\n}\nexport function selectDesktopAgent(agents: Record<string, unknown>, requested?: string): string {\n if (requested && !Object.hasOwn(agents, requested)) throw new Error(`Unknown agent: ${requested}. Run agentx agent list.`)\n const id = requested || Object.keys(agents)[0]\n if (!id) throw new Error('No agents configured. Run agentx setup first.')\n return id\n}\nexport function shellQuote(value: string): string { return `'${value.replace(/'/g, \"'\\\\''\")}'` }\n/** launchd's default PATH, which is all a login item gets unless the plist sets one. */\nexport const LAUNCHD_PATH = '/usr/bin:/bin:/usr/sbin:/sbin'\n/** PATH for the login item: AGENTX_VOICE_PATH when set, else the folder of\n * the ffmpeg found at install time (mlx_whisper needs it) ahead of launchd's default. */\nexport function desktopPath(ffmpeg: string | null, override?: string): string {\n if (override) return override\n return [...new Set([...(ffmpeg ? [dirname(ffmpeg)] : []), ...LAUNCHD_PATH.split(':')])].join(':')\n}\nfunction unxml(s: string): string {\n const ents: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '\"', apos: \"'\" }\n return s.replace(/&(amp|lt|gt|quot|apos);/g, (_, e) => ents[e])\n}\n/** The PATH a login item plist sets, or launchd's default when it sets none. */\nexport function plistPathEnv(plist: string): string {\n const m = plist.match(/<key>PATH<\\/key>\\s*<string>([^<]*)<\\/string>/)\n return m ? unxml(m[1]) : LAUNCHD_PATH\n}\n/** Login item files the voice app may have been installed under. */\nexport const isVoiceLoginItemFile = (name: string) => /agentx\\.voice.*\\.plist$/.test(name)\nexport type LoginItem = { file: string; label: string }\n/** One login item per Mac. The label was renamed once and\n * apps/mac-voice/install.sh writes its own, so adopt the first existing\n * `*agentx.voice*` item that runs the voice app (any bundle name) and\n * retire the others; with none, use DESKTOP_LABEL. Plists are XML text. */\nexport function adoptLoginItem(dir: string, items: { file: string; plist: string }[]): { keep: LoginItem; remove: LoginItem[] } {\n let keep: LoginItem | null = null\n const remove: LoginItem[] = []\n for (const { file, plist } of [...items].sort((a, b) => (a.file < b.file ? -1 : 1))) {\n const label = plist.match(/<key>Label<\\/key>\\s*<string>([^<]*)<\\/string>/)?.[1]\n const program = plist.match(/<key>ProgramArguments<\\/key>\\s*<array>\\s*<string>([^<]*)<\\/string>/)?.[1]\n if (!label || !program || !unxml(program).endsWith('/Contents/MacOS/AgentXVoice')) continue\n if (keep) remove.push({ file, label: unxml(label) })\n else keep = { file, label: unxml(label) }\n }\n return { keep: keep ?? { file: join(dir, `${DESKTOP_LABEL}.plist`), label: DESKTOP_LABEL }, remove }\n}\n/** The file that a process with this PATH would run, or null. */\nexport function findOnPath(bin: string, path: string, isExecutable: (file: string) => boolean): string | null {\n for (const dir of path.split(':')) if (dir && isExecutable(join(dir, bin))) return join(dir, bin)\n return null\n}\n/** Without `agent` the app talks to the agent picked in its menu-bar\n * icon; with it, that agent is pinned and the menu cannot switch. */\nexport function desktopPlist(opts: { label?: string; executable: string; cwd: string; agent?: string; url: string; helper: string; cli: string; node: string; log: string; path: string }): string {\n const xml = (s: string) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"').replace(/'/g, ''')\n const env = {\n PATH: opts.path,\n ...(opts.agent ? { AGENTX_VOICE_AGENT: opts.agent } : {}),\n AGENTX_DAEMON_URL: opts.url,\n AGENTX_MAC_HELPER: opts.helper,\n AGENTX_PASTE_COMMAND: `cd ${shellQuote(opts.cwd)} && ${shellQuote(opts.node)} ${shellQuote(opts.cli)} paste`,\n }\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\"><dict>\n<key>Label</key><string>${xml(opts.label ?? DESKTOP_LABEL)}</string>\n<key>ProgramArguments</key><array><string>${xml(opts.executable)}</string></array>\n<key>WorkingDirectory</key><string>${xml(opts.cwd)}</string>\n<key>EnvironmentVariables</key><dict>${Object.entries(env).map(([k,v]) => `<key>${k}</key><string>${xml(v)}</string>`).join('')}</dict>\n<key>RunAtLoad</key><true/><key>KeepAlive</key><true/>\n<key>ProcessType</key><string>Interactive</string>\n<key>StandardErrorPath</key><string>${xml(opts.log)}</string>\n</dict></plist>\\n`\n}\n/** build.sh arguments for the helper: the banner icon from\n * notifications.local.icon, or none for the bundled AgentX logo. */\nexport function helperBuildArgs(icon?: string): string[] {\n return icon ? ['--icon', icon] : []\n}\nexport function installedHelper(home: string): string {\n return join(home, 'Applications', HELPER_APP, 'Contents/MacOS/agentx-mac-helper')\n}\n/** The AgentX package folder, found by walking up from this file (dist/\n * when installed, src/ in a checkout) — never from the caller's cwd, so\n * `agentx notify` finds a repo-built helper from any folder. */\nexport function packageRoot(from = dirname(fileURLToPath(import.meta.url))): string | null {\n for (let dir = from; ; dir = dirname(dir)) {\n try {\n if (JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).name === 'agentix-cli') return dir\n } catch { /* no package.json here — keep walking up */ }\n if (dirname(dir) === dir) return null\n }\n}\n/** The helper to run: an explicit path, else the one `agentx desktop\n * install` put in ~/Applications, else one built in the package. */\nexport function resolveHelper(root: string | null, home: string, override?: string): string {\n if (override) return override\n const installed = installedHelper(home)\n if (existsSync(installed) || !root) return installed\n return join(root, 'apps/mac-helper/build', HELPER_APP, 'Contents/MacOS/agentx-mac-helper')\n}\n/** The AgentX Helper binary when one is built or installed, else null.\n * AGENTX_MAC_HELPER points at a helper somewhere else. */\nexport function findHelper(): string | null {\n const path = resolveHelper(packageRoot(), homedir(), process.env.AGENTX_MAC_HELPER)\n return existsSync(path) ? path : null\n}\n","import { accessSync, constants } from \"fs\"\nimport { findOnPath } from \"@/desktop/install\"\nimport { readSystemFocus } from \"@/notify/focus\"\nimport type { NativeAdapter, NativeFocus } from \"../types\"\nimport { macosBanner } from \"./banner\"\nimport { macosNotes } from \"./notes\"\nimport type { Capture, Output, Run } from \"./run\"\nimport { macosSound } from \"./sound\"\nimport { macosSpeech } from \"./speech\"\nimport { macosTasks } from \"./tasks\"\n\n/** Programs the adapter runs, so tests can stand in for them. */\nexport interface MacosIo {\n run?: Run\n capture?: Capture\n output?: Output\n /** The AgentX Helper binary; null means none. Unset: looked up on use. */\n helper?: string | null\n /** Is this file an executable? Used to find remindctl. */\n isExecutable?: (file: string) => boolean\n}\n\nconst executable = (file: string): boolean => {\n try { accessSync(file, constants.X_OK); return true } catch { return false }\n}\n\n/** System Focus from the private Focus database (notify/focus.ts). That\n * reader answers \"not in Focus\" when it can't read the file, so here\n * anything but a clean answer is null: the OS could not tell. */\nconst focus: NativeFocus = {\n async active() {\n const s = readSystemFocus()\n if (s.active) return true\n return s.reason === \"no active Focus assertion\" ? false : null\n },\n}\n\nexport function macosAdapter(cfg: { reminders?: { command?: string } } = {}, io: MacosIo = {}): NativeAdapter {\n const command = cfg.reminders?.command || \"remindctl\"\n return {\n os: \"macos\",\n tasks: macosTasks(command, io.output),\n notes: macosNotes(io.output),\n banner: macosBanner(io),\n sound: macosSound(io),\n focus,\n speech: macosSpeech(io),\n async describe() {\n const problems: string[] = []\n const isExec = io.isExecutable ?? executable\n const found = command.includes(\"/\") ? isExec(command) : !!findOnPath(command, process.env.PATH || \"\", isExec)\n if (!found) problems.push(`Reminders: ${command} not found (brew install steipete/tap/remindctl, or set reminders.command).`)\n return { os: \"macos\", tasks: true, notes: true, banner: true, sound: true, focus: true, problems }\n },\n }\n}\n","import { execFile } from \"child_process\"\n\n/** Runs a program; resolves true when it exited 0. Never rejects. */\nexport type Run = (file: string, args: string[]) => Promise<boolean>\n\n/** Runs a program; resolves its stdout, or rejects with its stderr. */\nexport type Output = (file: string, args: string[]) => Promise<string>\n\n/** Runs a program; resolves its stdout, or null when it failed. */\nexport type Capture = (file: string, args: string[]) => Promise<string | null>\n\n/** A banner or a sound may not hold a caller hostage: afplay on a long\n * custom sound, or osascript stuck on a permission prompt, is cut off. */\nconst STEP_TIMEOUT_MS = 5_000\n\nexport const run: Run = (file, args) =>\n new Promise((done) => {\n try {\n execFile(file, args, { timeout: STEP_TIMEOUT_MS }, (err) => done(!err))\n } catch {\n done(false) // the program is not on this machine: not worth reporting\n }\n })\n\nexport const capture: Capture = (file, args) =>\n new Promise((done) => {\n try {\n execFile(file, args, { timeout: STEP_TIMEOUT_MS }, (err, stdout) => done(err ? null : String(stdout)))\n } catch {\n done(null)\n }\n })\n\nexport const output: Output = (file, args) =>\n new Promise((resolve, reject) => {\n execFile(file, args, { timeout: 30_000, maxBuffer: 8 * 1024 * 1024 }, (err, stdout, stderr) => {\n if (err) reject(new Error(`${file} ${args[0]}: ${(stderr || err.message).trim()}`))\n else resolve(stdout)\n })\n })\n","import { findHelper } from \"@/desktop/install\"\nimport type { BannerStatus, NativeBanner } from \"../types\"\nimport { capture as defaultCapture, run as defaultRun, type Capture, type Run } from \"./run\"\n\n// The banner is posted by the AgentX Helper app when it is installed, so it\n// carries the helper's icon (the AgentX logo by default). Without the\n// helper, or before macOS has allowed it to notify, osascript posts it, and\n// macOS shows it as coming from Script Editor.\n\nexport interface BannerIo {\n run?: Run\n capture?: Capture\n /** The helper binary; null means none. Unset: looked up on each use. */\n helper?: string | null\n}\n\nconst helperOf = (io: BannerIo): string | null => (io.helper === undefined ? findHelper() : io.helper)\n\n/** What the helper reports about its notification permission. Never shows\n * the macOS \"allow notifications\" prompt and never posts a banner. */\nexport async function helperBannerStatus(path: string | null, capture: Capture = defaultCapture): Promise<BannerStatus> {\n if (!path) return \"missing\"\n const out = await capture(path, [\"notify-status\"])\n let status: { authorization?: string; alertStyle?: string } | null = null\n try { status = out ? JSON.parse(out) : null } catch { status = null }\n if (!status) return \"outdated\"\n if (status.authorization === \"notDetermined\") return \"not-asked\"\n if (status.authorization === \"denied\") return \"not-allowed\"\n if (status.alertStyle === \"none\") return \"hidden\"\n return \"ready\"\n}\n\nexport function macosBanner(io: BannerIo = {}): NativeBanner {\n const exec = io.run ?? defaultRun\n return {\n async post({ title, message }) {\n const helper = helperOf(io)\n // A non-zero exit is usually \"not allowed to notify yet\" (the first\n // banner asks), so this one goes through osascript instead.\n if (helper && await exec(helper, [\"notify\", \"--title\", title, \"--message\", message])) return \"posted\"\n // Title and message travel as argv, never spliced into the script,\n // so a quote in either cannot turn into AppleScript.\n const ok = await exec(\"/usr/bin/osascript\", [\n \"-e\", \"on run argv\",\n \"-e\", \"display notification (item 2 of argv) with title (item 1 of argv)\",\n \"-e\", \"end run\",\n title, message,\n ])\n return ok ? \"posted\" : \"failed\"\n },\n status: () => helperBannerStatus(helperOf(io), io.capture),\n }\n}\n","import type { NativeNotes } from \"../types\"\nimport { output as defaultOutput, type Output } from \"./run\"\n\n// Apple Notes through JXA (osascript -l JavaScript). The folder, title\n// and body travel as argv and are read by the script, never spliced into\n// it, so nothing in them can run as code. Notes stores a body as HTML:\n// the script escapes the text and keeps its line breaks. The first call\n// from the daemon's process asks for the macOS Automation permission\n// (System Settings › Privacy & Security › Automation › Notes).\n\nexport const NOTES_SCRIPT = `\nfunction run(argv) {\n var folderName = argv[0], title = argv[1], body = argv[2]\n var Notes = Application(\"Notes\")\n var esc = function (s) { return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\") }\n var folder = Notes.folders.whose({ name: folderName })()[0]\n if (!folder) {\n folder = Notes.Folder({ name: folderName })\n Notes.folders.push(folder)\n folder = Notes.folders.whose({ name: folderName })()[0]\n }\n var lines = body.split(\"\\\\n\").map(function (l) { return \"<div>\" + (l ? esc(l) : \"<br>\") + \"</div>\" })\n // Notes takes the title from the first line: a name as well would show it twice.\n var note = Notes.Note({ body: \"<div><h1>\" + esc(title) + \"</h1></div>\" + lines.join(\"\") })\n folder.notes.push(note)\n return note.id()\n}\n`\n\nexport function macosNotes(exec: Output = defaultOutput): NativeNotes {\n return {\n async add({ folder, title, body }) {\n const raw = await exec(\"/usr/bin/osascript\", [\"-l\", \"JavaScript\", \"-e\", NOTES_SCRIPT, folder, title, body])\n const id = raw.trim()\n if (!id) throw new Error(\"Notes did not return the new note's id\")\n return { id }\n },\n }\n}\n","import { existsSync, readdirSync } from \"fs\"\nimport type { NativeSound } from \"../types\"\nimport { run as defaultRun, type Run } from \"./run\"\n\nconst SOUNDS = \"/System/Library/Sounds\"\n\n/** The system sound file for a name, or null when there is none. Names\n * only: a path in the config must not reach afplay. */\nexport function soundPath(name: string): string | null {\n if (!/^[\\w -]+$/.test(name)) return null\n const path = `${SOUNDS}/${name}.aiff`\n return existsSync(path) ? path : null\n}\n\nexport function macosSound(io: { run?: Run } = {}): NativeSound {\n const exec = io.run ?? defaultRun\n return {\n async play(name, volume) {\n const path = soundPath(name)\n if (!path) return\n await exec(\"/usr/bin/afplay\", [\"-v\", String(Math.min(1, Math.max(0, volume))), path])\n },\n has: (name) => soundPath(name) !== null,\n async names() {\n try {\n return readdirSync(SOUNDS).filter((f) => f.endsWith(\".aiff\")).map((f) => f.slice(0, -5)).sort()\n } catch {\n return []\n }\n },\n }\n}\n","import type { NativeSpeech } from \"../types\"\nimport { capture as defaultCapture, type Capture } from \"./run\"\n\n// --- Is something else speaking on this Mac? (#1126) ---\n//\n// A script that narrates with `say`, or plays a recording with `afplay`,\n// talks to the person at this Mac without going through AgentX's speaking\n// queue. Before AgentX speaks or chimes, it looks at the process list:\n// one such program running, not started by AgentX itself, means wait.\n\n/** Programs that speak or play sound, and how the owner would say it. */\nconst SPEAKERS: Record<string, string> = { say: \"a spoken line (say)\", afplay: \"a sound playing (afplay)\" }\n\n/** \"pid ppid command\" lines from ps, the speakers among them. */\nexport function speakersIn(ps: string, exceptParents: number[], self = process.pid): string | null {\n for (const line of ps.split(\"\\n\")) {\n const m = line.trim().match(/^(\\d+)\\s+(\\d+)\\s+(\\S+)/)\n if (!m) continue\n const [pid, ppid, comm] = [Number(m[1]), Number(m[2]), m[3]]\n const name = comm.slice(comm.lastIndexOf(\"/\") + 1)\n if (!(name in SPEAKERS) || pid === self || exceptParents.includes(ppid)) continue\n return SPEAKERS[name]\n }\n return null\n}\n\nexport function macosSpeech(io: { capture?: Capture } = {}): NativeSpeech {\n const capture = io.capture ?? defaultCapture\n return {\n async othersSpeaking(opts = {}) {\n const ps = await capture(\"/bin/ps\", [\"-axo\", \"pid=,ppid=,comm=\"])\n return ps ? speakersIn(ps, opts.exceptParents ?? []) : null\n },\n }\n}\n","import type { NativeTask, NativeTasks } from \"../types\"\nimport { output as defaultOutput, type Output } from \"./run\"\n\n// Apple Reminders through remindctl (Homebrew). It is the same tool the\n// mac-pim skill uses, so the daemon and the skill see the same lists. The\n// first call from the daemon's process triggers the macOS Reminders\n// permission prompt.\n//\n// Every value travels as its own argv entry, never through a shell, so\n// quotes and newlines arrive as typed. remindctl 0.1.1 reads any value\n// that starts with \"-\" as an option (and a value equal to --help or\n// --version runs that), and has no \"--opt=value\" form, so such a value\n// gets an invisible zero-width space in front. Reminders keeps that\n// character; listOpen takes it off again. A list name is a lookup key and\n// cannot carry it, so a list name that starts with \"-\" is refused.\n//\n// Reminders keeps a due time to the minute, in this Mac's time zone:\n// seconds are dropped.\n\nconst ZWSP = \"\\u200b\"\n\n/** A value remindctl takes literally. */\nexport function argValue(v: string): string {\n return v.startsWith(\"-\") ? ZWSP + v : v\n}\n\nconst unArg = (v: string | undefined): string | undefined => (v?.startsWith(ZWSP + \"-\") ? v.slice(1) : v)\n\nfunction listName(list: string): string {\n if (!list.trim() || list.startsWith(\"-\")) throw new Error(`Reminders list name \"${list}\" is not usable: it must not be empty or start with \"-\"`)\n return list\n}\n\n/** ISO to the minute, which is all Reminders keeps. */\nconst isoDue = (d: Date): string => new Date(Math.floor(d.getTime() / 60_000) * 60_000).toISOString().replace(/\\.\\d{3}Z$/, \"Z\")\n\nexport function macosTasks(command = \"remindctl\", exec: Output = defaultOutput): NativeTasks {\n return {\n async ensureList(list) {\n const raw = await exec(command, [\"list\", \"--json\", \"--no-input\"])\n const lists = JSON.parse(raw.trim() || \"[]\")\n if (!Array.isArray(lists)) throw new Error(`${command} list: expected a JSON array`)\n if (lists.some((l: { title?: string }) => l?.title === list)) return\n await exec(command, [\"list\", listName(list), \"--create\", \"--json\", \"--no-input\"])\n },\n async listOpen(list) {\n const raw = await exec(command, [\"show\", \"all\", \"--list\", listName(list), \"--json\", \"--no-input\"])\n const items = JSON.parse(raw.trim() || \"[]\")\n if (!Array.isArray(items)) throw new Error(`${command} show: expected a JSON array`)\n return items\n .filter((r: NativeTask) => r && typeof r.id === \"string\" && !r.isCompleted)\n .map((r: NativeTask) => ({ ...r, title: unArg(r.title) ?? \"\", ...(r.notes !== undefined ? { notes: unArg(r.notes) } : {}) }))\n },\n async add({ list, title, notes, due, priority }) {\n const args = [\"add\", \"--title\", argValue(title), \"--list\", listName(list), \"--notes\", argValue(notes)]\n if (due) args.push(\"--due\", isoDue(due))\n if (priority && priority !== \"none\") args.push(\"--priority\", priority)\n const raw = await exec(command, [...args, \"--json\", \"--no-input\"])\n let id: unknown\n try { id = JSON.parse(raw.trim())?.id } catch { id = undefined }\n if (typeof id !== \"string\" || !id) throw new Error(`${command} add: no reminder id in its answer`)\n return { id }\n },\n async update(id, patch) {\n const args = [\"edit\", id]\n if (patch.title !== undefined) args.push(\"--title\", argValue(patch.title))\n if (patch.notes !== undefined) args.push(\"--notes\", argValue(patch.notes))\n if (patch.due === null) args.push(\"--clear-due\")\n else if (patch.due) args.push(\"--due\", isoDue(patch.due))\n // remindctl refuses an edit that changes nothing; so does this.\n if (args.length === 2) return\n await exec(command, [...args, \"--json\", \"--no-input\"])\n },\n async complete(id) {\n await exec(command, [\"complete\", id, \"--json\", \"--no-input\"])\n },\n async remove(id) {\n await exec(command, [\"delete\", id, \"--force\", \"--json\", \"--no-input\"])\n },\n }\n}\n","import type { NativeAdapter } from \"./types\"\n\n/** The adapter for a machine AgentX has no OS layer for, or where the owner\n * turned it off. Every capability is absent; describe() says why. */\nexport function noneAdapter(reason: string): NativeAdapter {\n return {\n os: \"none\",\n async describe() {\n return { os: \"none\", tasks: false, notes: false, banner: false, sound: false, focus: false, problems: [reason] }\n },\n }\n}\n","import { macosAdapter, type MacosIo } from \"./macos\"\nimport { noneAdapter } from \"./none\"\nimport type { NativeAdapter } from \"./types\"\n\nexport * from \"./types\"\nexport { noneAdapter } from \"./none\"\n\nexport type NativeAdapterChoice = \"auto\" | \"none\"\n\nexport type NativeConfig = { native?: { adapter?: NativeAdapterChoice }; reminders?: { command?: string } }\n\n/** Programs an adapter runs, so tests can stand in for them. */\nexport type NativeIo = MacosIo\n\n/** Builds the adapter for one OS. Each OS adapter registers here. */\nexport type NativeAdapterFactory = (cfg: NativeConfig, io: NativeIo) => NativeAdapter\n\nconst FACTORIES: Partial<Record<NodeJS.Platform, NativeAdapterFactory>> = {\n darwin: macosAdapter,\n}\n\n/** The adapter for this machine. `native.adapter: \"none\"` forces none on\n * any OS; \"auto\" (the default) picks by platform. */\nexport function loadNativeAdapter(\n cfg: NativeConfig = {},\n opts: { platform?: NodeJS.Platform; factories?: Partial<Record<NodeJS.Platform, NativeAdapterFactory>>; io?: NativeIo } = {},\n): NativeAdapter {\n if (cfg.native?.adapter === \"none\") return noneAdapter(\"Turned off: native.adapter is \\\"none\\\".\")\n const platform = opts.platform ?? process.platform\n const make = (opts.factories ?? FACTORIES)[platform]\n return make ? make(cfg, opts.io ?? {}) : noneAdapter(`AgentX has no native adapter for ${platform} yet.`)\n}\n","import { existsSync } from \"fs\"\nimport { homedir } from \"os\"\nimport { isAbsolute } from \"path\"\nimport { loadNativeAdapter, type NativeConfig, type NativeIo, type NativeSpeech } from \"@/native\"\n\nexport { findHelper } from \"@/desktop/install\"\n\n// What happens on THIS machine when a notification is delivered: a banner\n// on screen and a short sound. The push goes to the phone; these are for\n// the person sitting at the computer that raised the event. Both go\n// through the native adapter (src/native); a machine without one skips\n// them.\n//\n// Both are awaited rather than fired and forgotten. A caller that exits\n// straight after notifying — a `launchctl submit` job that removes itself,\n// a cron one-liner — used to take the sound down with it before it\n// played. Waiting costs about a second and makes the step reliable.\n//\n// Never fatal: a notification whose banner failed still arrived, and no\n// caller should have to handle an audio error to say a build finished.\n\nexport interface LocalSettings {\n /** Show a desktop banner (macOS only; other platforms skip it). */\n banner: boolean\n /** Play a sound (macOS only). */\n sound: boolean\n /** A system sound, by name (on a Mac, one of the sounds in System Settings › Sound). */\n soundName: string\n /** 0 (silent) … 1 (full). */\n volume: number\n /** Seconds the sound waits while something else speaks on this machine\n * (#1126). Still speaking after that: no sound, the banner is enough.\n * 0: never wait. */\n quietWaitSeconds?: number\n /** Image for the helper's app icon, which macOS puts on its banners.\n * Unset: the AgentX logo. Applied when `agentx desktop install` builds\n * the helper, since macOS reads the icon from the app, not the banner. */\n icon?: string\n}\n\n/** Glass is the gentlest system sound that is still audible over a\n * keyboard — Basso and Sosumi are alerts, Funk and Frog are jokes, and\n * Ping is the one every other app already uses. */\nexport const DEFAULT_LOCAL: LocalSettings = { banner: true, sound: true, soundName: \"Glass\", volume: 0.4, quietWaitSeconds: 15 }\n\n/** Shows the banner and plays the sound for one delivered notification. */\nexport type LocalAlert = (title: string, message: string) => Promise<void>\n\n/** Fill gaps in a partial `notifications.local` block with the defaults. */\nexport function localSettings(cfg: Partial<LocalSettings> | undefined): LocalSettings {\n return { ...DEFAULT_LOCAL, ...(cfg ?? {}) }\n}\n\nexport function localAlert(\n settings: LocalSettings,\n deps: {\n run?: NativeIo[\"run\"]; capture?: NativeIo[\"capture\"]; platform?: NodeJS.Platform; helper?: string | null; native?: NativeConfig[\"native\"]\n /** For tests: the poll between two looks at who is speaking. */\n pollMs?: number\n } = {},\n): LocalAlert {\n const native = loadNativeAdapter({ native: deps.native }, { platform: deps.platform, io: { run: deps.run, capture: deps.capture, helper: deps.helper } })\n return async (title, message) => {\n const steps: Promise<unknown>[] = []\n if (settings.banner && native.banner) steps.push(native.banner.post({ title, message }))\n if (settings.sound && native.sound) {\n const sound = native.sound\n // A chime over someone speaking is the collision #1126 is about:\n // the banner goes up at once, the sound waits for quiet.\n steps.push(quiet(native.speech, (settings.quietWaitSeconds ?? DEFAULT_LOCAL.quietWaitSeconds!) * 1000, deps.pollMs ?? 500)\n .then((ok) => (ok ? sound.play(settings.soundName, settings.volume) : undefined)))\n }\n await Promise.all(steps)\n }\n}\n\n/** True once nothing else speaks on this machine, false when something\n * still does after `waitMs`. Without a way to tell, true at once. The\n * daemon's own speech counts too (no `exceptParents` here, unlike the\n * speaking queue): a chime over a spoken reply is the same interruption,\n * so it waits, and past the wait the banner shows without the sound. */\nasync function quiet(speech: NativeSpeech | undefined, waitMs: number, pollMs: number): Promise<boolean> {\n if (!speech || waitMs <= 0) return true\n const until = Date.now() + waitMs\n for (;;) {\n if (!(await speech.othersSpeaking())) return true\n if (Date.now() >= until) return false\n await new Promise((r) => setTimeout(r, pollMs))\n }\n}\n\n/**\n * Apply a change to a stored `notifications.local` block, the one rule\n * both the CLI and the dashboard write through. Returns the new block;\n * throws on a value that would not load. Only a machine with a native\n * adapter has sounds to check a name against; elsewhere the setting is\n * inert, so it need only be well-formed.\n */\nexport function patchLocal(\n current: Partial<LocalSettings> | undefined,\n patch: Record<string, unknown>,\n platform: NodeJS.Platform = process.platform,\n): Partial<LocalSettings> {\n const next = { ...(current ?? {}) }\n const native = loadNativeAdapter({}, { platform })\n if (\"banner\" in patch) next.banner = Boolean(patch.banner)\n if (\"sound\" in patch) next.sound = Boolean(patch.sound)\n if (\"soundName\" in patch) {\n const name = String(patch.soundName).trim()\n const ok = native.sound ? native.sound.has(name) : /^[\\w -]+$/.test(name)\n if (!ok) throw new Error(`no system sound named \"${name}\" on this machine`)\n next.soundName = name\n }\n if (\"icon\" in patch) {\n const icon = String(patch.icon ?? \"\").trim().replace(/^~(?=\\/)/, homedir())\n if (!icon) delete next.icon\n else {\n if (!isAbsolute(icon) || !/\\.(png|jpe?g|icns)$/i.test(icon)) throw new Error(\"icon must be the full path to a .png, .jpg or .icns file\")\n if (native.banner && !existsSync(icon)) throw new Error(`no icon file at ${icon}`)\n next.icon = icon\n }\n }\n if (\"volume\" in patch) {\n const v = Number(patch.volume)\n if (!Number.isFinite(v) || v < 0 || v > 1) throw new Error(\"volume must be between 0 and 1\")\n next.volume = v\n }\n return next\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport type { NativePriority, NativeTasks } from \"@/native\"\nimport { cardWords, summarize } from \"@/requests/card-view\"\nimport type { RequestRecord } from \"@/requests/store\"\nimport { CARD_LIMITS, type DecisionCard } from \"./cards\"\n\n// --- The Reminders mirror (#1062 step 5) ---\n//\n// Each pending decision card, and each request waiting on the owner,\n// becomes one task in the OS task app (Apple Reminders on a Mac) with a due\n// time. Calendar shows it, and the system alert comes back when it falls\n// due. Answering stays on the Desk, the Approvals page or the CLI: a task\n// cannot carry choices or a draft.\n//\n// Runs once a minute beside the approvals sweep, on the node that holds the\n// cards (forwarded cards live on the owner's node, so that is where they\n// are mirrored). Off by default.\n//\n// Rules:\n// - one task per card or request, created once;\n// - the card is answered, expires or is closed, or the request stops\n// waiting on the owner: the task is completed;\n// - the owner ticks the task off or deletes it while the item still\n// waits: the item stays on the Desk and is never mirrored again.\n// Ticking a task is not an answer;\n// - three failed adds for one item: the owner is told once and that\n// item is not tried again;\n// - every task ends with `agentx: card=<id>` or `agentx: request=<id>`,\n// which check-ins and the reminders hand-back skip, so a mirrored\n// task never turns back into a card or an agent's job.\n//\n// State lives in its own file, written only by the daemon, not in the card\n// files that the CLI and the dashboard also write.\n\nexport interface MirrorSettings {\n enabled: boolean\n list: string\n dueAfterMinutes: number\n include: (\"card\" | \"request\")[]\n /** Where the owner answers. Unset: the local dashboard's Approvals page. */\n answerUrl?: string\n}\n\nexport type MirrorState = \"open\" | \"completed\" | \"dismissed\" | \"failed\"\n\nexport interface MirrorEntry {\n /** The task's id in the OS task app, once added. */\n id?: string\n list: string\n state: MirrorState\n /** ISO time of the last change. */\n at: string\n failures: number\n lastError?: string\n}\n\nexport interface MirrorFile {\n /** Keyed `card:<id>` or `request:<id>`, the inbox's keys. */\n items: Record<string, MirrorEntry>\n /** ISO time of the last pass that read every list it needed. Stale\n * (the mirror was turned off, or the list can't be read) means the\n * mirror no longer covers anything, and the Mac popup is back. */\n checkedAt?: string\n /** That pass mirrored cards (include has \"card\"). */\n cards?: boolean\n /** ISO time the owner was last told adds are failing: once a day. */\n failureToldAt?: string\n /** The latest pass's last error, for doctor. */\n lastError?: { at: string; message: string }\n}\n\nexport const MAX_ADD_FAILURES = 3\n/** Closed entries are kept this long, then forgotten. */\nconst KEEP_CLOSED_MS = 30 * 24 * 3_600_000\n\nexport function mirrorPath(root: string): string {\n return resolve(root, \".agentx\", \"native-mirror.json\")\n}\n\nexport function readMirror(root: string): MirrorFile {\n try {\n const parsed = JSON.parse(readFileSync(mirrorPath(root), \"utf-8\"))\n return { ...parsed, items: parsed?.items && typeof parsed.items === \"object\" ? parsed.items : {} }\n } catch {\n return { items: {} }\n }\n}\n\nfunction writeMirror(root: string, file: MirrorFile): void {\n const path = mirrorPath(root)\n if (!existsSync(dirname(path))) mkdirSync(dirname(path), { recursive: true })\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(file, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\n/** A pass older than this means the mirror is not running. */\nexport const MIRROR_FRESH_MS = 5 * 60_000\n\n/** True when the mirror is running and covers this card: it has a task,\n * or gets one on the next pass, or the owner ticked its task off. The Mac\n * popup then leaves it alone, so the owner is not alerted twice. A card\n * whose task could not be added is not covered. */\nexport function mirrorCovers(root: string, cardId: string, now = Date.now()): boolean {\n const file = readMirror(root)\n const checked = file.checkedAt ? Date.parse(file.checkedAt) : NaN\n if (!file.cards || !(now - checked <= MIRROR_FRESH_MS)) return false\n return file.items[`card:${cardId}`]?.state !== \"failed\"\n}\n\n/** What one task says. */\nexport interface MirrorItem {\n key: string\n title: string\n notes: string\n due: Date\n priority: NativePriority\n}\n\nconst DAY_MS = 24 * 3_600_000\n\nfunction dueFor(now: number, settings: MirrorSettings, limit?: number): Date {\n const due = now + settings.dueAfterMinutes * 60_000\n return new Date(limit !== undefined && Number.isFinite(limit) ? Math.max(now, Math.min(due, limit)) : due)\n}\n\nexport function cardItem(card: DecisionCard, settings: MirrorSettings, answerUrl: string, now: number): MirrorItem {\n const expires = Date.parse(card.expires)\n const lines = [summarize(card.ask, CARD_LIMITS.ask)]\n if (card.choices?.length) lines.push(...card.choices.map((c, i) => `${i + 1}. ${c}`))\n if (card.recommend) lines.push(`Recommended: ${summarize(card.recommend, CARD_LIMITS.recommend)}`)\n lines.push(`Answer: ${answerUrl}`, `agentx: card=${card.id}`)\n return {\n key: `card:${card.id}`,\n title: summarize(card.title, CARD_LIMITS.title),\n notes: lines.join(\"\\n\"),\n due: dueFor(now, settings, expires),\n priority: Number.isFinite(expires) && expires - now <= DAY_MS ? \"high\" : \"none\",\n }\n}\n\nexport function requestItem(r: RequestRecord, settings: MirrorSettings, answerUrl: string, now: number): MirrorItem {\n const lines = [summarize(r.question || r.text, CARD_LIMITS.ask), `Asked of ${r.agentId}.`, `Answer: ${answerUrl}`, `agentx: request=${r.id}`]\n const dueAt = r.dueAt ?? undefined\n return {\n key: `request:${r.id}`,\n title: cardWords(r, CARD_LIMITS.title).headline,\n notes: lines.join(\"\\n\"),\n due: dueFor(now, settings, dueAt),\n priority: dueAt !== undefined && dueAt - now <= DAY_MS ? \"high\" : \"none\",\n }\n}\n\nexport interface MirrorDeps {\n root: string\n settings: MirrorSettings\n tasks: NativeTasks\n /** Pending cards on this node. */\n cards: () => DecisionCard[]\n /** Requests in waiting_owner. */\n requests: () => RequestRecord[]\n answerUrl: string\n /** Tell the owner, through the usual notification. */\n notify: (title: string, message: string) => Promise<void>\n log: (msg: string) => void\n now?: number\n}\n\nexport interface MirrorResult {\n created: number\n completed: number\n dismissed: number\n failed: number\n}\n\n/** One pass of the mirror. Never throws. */\nexport async function runMirror(deps: MirrorDeps): Promise<MirrorResult> {\n const { root, settings, tasks, log } = deps\n const now = deps.now ?? Date.now()\n const at = new Date(now).toISOString()\n const result: MirrorResult = { created: 0, completed: 0, dismissed: 0, failed: 0 }\n const file = readMirror(root)\n // lastError says how the latest pass went: a clean pass clears it.\n delete file.lastError\n const fail = (message: string) => { file.lastError = { at, message } }\n\n const waiting = new Map<string, MirrorItem>()\n try {\n if (settings.include.includes(\"card\")) {\n for (const c of deps.cards()) if (c.status === \"pending\" && Date.parse(c.expires) > now) waiting.set(`card:${c.id}`, cardItem(c, settings, deps.answerUrl, now))\n }\n if (settings.include.includes(\"request\")) {\n for (const r of deps.requests()) if (r.state === \"waiting_owner\") waiting.set(`request:${r.id}`, requestItem(r, settings, deps.answerUrl, now))\n }\n } catch (e: any) {\n log(`[mirror] could not read what is waiting: ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n writeMirror(root, file)\n return result\n }\n\n // Close or notice dismissal for what is already mirrored. The open list\n // is read once per list; when it can't be read, nothing is closed or\n // dismissed this pass, so a hiccup never loses a task.\n let allRead = true\n const openIds = new Map<string, Set<string> | null>()\n const openIn = async (list: string): Promise<Set<string> | null> => {\n if (!openIds.has(list)) {\n try {\n openIds.set(list, new Set((await tasks.listOpen(list)).map((t) => t.id)))\n } catch (e: any) {\n log(`[mirror] could not read list \"${list}\": ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n openIds.set(list, null)\n allRead = false\n }\n }\n return openIds.get(list)!\n }\n\n for (const [key, entry] of Object.entries(file.items)) {\n if (entry.state !== \"open\" || !entry.id) continue\n const open = await openIn(entry.list)\n if (!open) continue\n if (!waiting.has(key)) {\n if (open.has(entry.id)) {\n try {\n await tasks.complete(entry.id)\n } catch (e: any) {\n log(`[mirror] ${key}: could not complete its task: ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n continue\n }\n }\n file.items[key] = { ...entry, state: \"completed\", at }\n result.completed++\n } else if (!open.has(entry.id)) {\n file.items[key] = { ...entry, state: \"dismissed\", at }\n result.dismissed++\n log(`[mirror] ${key}: its task was ticked off or deleted; it stays on the Desk and is not mirrored again`)\n }\n }\n\n let listReady: boolean | null = null\n const gaveUp: { title: string; message: string }[] = []\n for (const [key, item] of waiting) {\n const entry = file.items[key]\n if (entry && (entry.state === \"open\" || entry.state === \"dismissed\")) continue\n if (entry?.state === \"failed\" && entry.failures >= MAX_ADD_FAILURES) continue\n // The list is made on the first add of a pass, when it is missing.\n if (listReady === null) {\n try {\n await tasks.ensureList(settings.list)\n listReady = true\n } catch (e: any) {\n log(`[mirror] could not make list \"${settings.list}\": ${e?.message ?? e}`)\n fail(String(e?.message ?? e))\n listReady = false\n }\n }\n const failures = entry?.state === \"failed\" ? entry.failures : 0\n try {\n const { id } = await tasks.add({ list: settings.list, title: item.title, notes: item.notes, due: item.due, priority: item.priority })\n file.items[key] = { id, list: settings.list, state: \"open\", at, failures: 0 }\n result.created++\n } catch (e: any) {\n const message = String(e?.message ?? e)\n const n = failures + 1\n file.items[key] = { list: settings.list, state: \"failed\", at, failures: n, lastError: message }\n fail(message)\n result.failed++\n log(`[mirror] ${key}: could not add to Reminders (${n}/${MAX_ADD_FAILURES}): ${message}`)\n if (n === MAX_ADD_FAILURES) gaveUp.push({ title: item.title, message })\n }\n }\n\n // One notification a day at most, however many items gave up: a missing\n // permission fails every card the same way.\n const told = file.failureToldAt ? Date.parse(file.failureToldAt) : NaN\n if (gaveUp.length && !(now - told < DAY_MS)) {\n const first = gaveUp[0]\n const more = gaveUp.length > 1 ? ` (and ${gaveUp.length - 1} more)` : \"\"\n try {\n await deps.notify(\"Could not add to Reminders\", `${first.title}${more}: ${summarize(first.message, 200)}. Still on the Desk.`)\n file.failureToldAt = at\n } catch (err: any) {\n log(`[mirror] could not tell the owner: ${err?.message ?? err}`)\n }\n }\n\n if (allRead) {\n file.checkedAt = at\n file.cards = settings.include.includes(\"card\")\n }\n\n for (const [key, entry] of Object.entries(file.items)) {\n if (entry.state !== \"open\" && !waiting.has(key) && now - Date.parse(entry.at) > KEEP_CLOSED_MS) delete file.items[key]\n }\n writeMirror(root, file)\n return result\n}\n","import { markdownToHtml } from \"@/utils/markdown-html\"\nimport type { RequestRecord, RequestStore } from \"./store\"\nimport type { PlanState, PlanStore, StepState } from \"./plan-store\"\nimport { describeCloseWhen } from \"./checkers\"\nimport { activeStepAgentOf, stalledWhy, waitsOn, type StallGroup } from \"./loops\"\n\n// --- One open request as a card the owner can read in seconds (#459) ---\n//\n// The Approvals page shows each open request as a card: a short plain\n// summary, where it stands and why it is not finished, then the words the\n// owner used and the agent's last answer, both rendered. markdownToHtml\n// escapes before it marks up, so nothing an agent or a channel wrote\n// reaches the page as HTML. The summary is the request's headline (#1126);\n// a request without one yet falls back to the start of its own words,\n// without the markdown marks.\n\nexport const SUMMARY_MAX = 200\n/** An answer of pages is cut: the card is for reading quickly. */\nexport const ANSWER_MAX = 4000\n\n/** What a request needs from the owner when nothing does. */\nexport const NOTHING_NEEDED = \"Nothing, just so you know.\"\n\n/** A request as every surface titles it (#1126): what it is, the one\n * thing needed from the owner, and the owner's own words. The need\n * follows where it stands: a request that needs attention or waits on\n * the owner's answer says so, whatever the agent wrote earlier. */\nexport function cardWords(\n r: Pick<RequestRecord, \"text\" | \"headline\" | \"need\" | \"state\" | \"question\" | \"agentId\">,\n max = SUMMARY_MAX,\n): { headline: string; need: string; said: string } {\n const headline = r.headline ? (r.headline.length > max ? `${r.headline.slice(0, max - 1)}…` : r.headline) : summarize(r.text, max)\n const need = r.state === \"needs_attention\" ? `Hand it back to ${r.agentId}, or drop it.`\n : r.state === \"waiting_owner\" ? (r.need ?? (r.question ? `Answer: ${summarize(r.question, 150)}` : \"Your answer.\"))\n : r.state === \"candidate\" || r.state === \"in_progress\" || r.state === \"waiting_other\" ? (r.need ?? NOTHING_NEEDED)\n : NOTHING_NEEDED\n return { headline, need, said: plain(r.text) }\n}\n\nexport interface RequestCard extends RequestRecord {\n summary: string\n /** The one thing needed from the owner, in words: the agent's `need`\n * or what follows from where the request stands (cardWords). */\n needed: string\n /** The request in the owner's words (the transcript, when spoken). */\n textHtml: string\n /** Why it is not finished, or what is being asked. Null: work is under way. */\n why: string | null\n ownerNoteHtml: string | null\n lastAnswer: { agentId: string; at: number; html: string } | null\n /** The open loop (#1039): who it is owed to, when it is due, what\n * closes it. Null on a request with none of it. */\n loop: {\n owedTo: string | null\n promise: boolean\n dueAt: number | null\n /** What its check waits for, in words. */\n check: string | null\n verifyState: string | null\n verifyDetail: string | null\n } | null\n /** Stalled, and what it waits on. Null: not stalled, or not asked. */\n stall: { group: StallGroup; who: string; why: string } | null\n /** Its tracked plan (#788), step by step. Null: no plan. */\n plan: {\n state: PlanState\n steps: Array<{ idx: number; name: string; kind: string; agentId: string; state: StepState; approval: string | null; evidence: string | null; note: string | null; nudges: number }>\n } | null\n}\n\n/** Markdown to the words alone, on one line. */\nexport function plain(md: string): string {\n return md\n .replace(/```[\\s\\S]*?```/g, \" \")\n .replace(/!?\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/^\\s{0,3}(#{1,6}|>|[-*+]|\\d+[.)])\\s+/gm, \"\")\n .replace(/[*_~`]+/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n}\n\n/** The start of the request, cut at a sentence when one ends in reach. */\nexport function summarize(md: string, max = SUMMARY_MAX): string {\n const text = plain(md)\n if (text.length <= max) return text\n const cut = text.slice(0, max)\n const end = Math.max(cut.lastIndexOf(\". \"), cut.lastIndexOf(\"? \"), cut.lastIndexOf(\"! \"))\n return end > max / 2 ? cut.slice(0, end + 1) : `${cut.slice(0, max - 1).trimEnd()}…`\n}\n\n/** What the stall view needs: the quiet time, the clock, and which ids are agents. */\nexport interface StallLookup { staleAfterHours: number; now: number; isAgent: (id: string) => boolean }\n\nexport function requestCard(\n r: RequestRecord,\n store: Pick<RequestStore, \"lastAnswer\">,\n plans?: Pick<PlanStore, \"get\" | \"steps\"> | null,\n stall?: StallLookup,\n): RequestCard {\n const plan = plans?.get(r.id)\n const why = stall ? stalledWhy(r, stall.staleAfterHours, stall.now) : null\n const answer = store.lastAnswer(r.id)\n const cutAnswer = answer && answer.text.length > ANSWER_MAX ? `${answer.text.slice(0, ANSWER_MAX)}\\n\\n…` : answer?.text\n const words = cardWords(r)\n return {\n ...r,\n summary: words.headline,\n needed: words.need,\n textHtml: markdownToHtml(r.text),\n why: r.state === \"waiting_owner\" ? r.question : r.state === \"needs_attention\" ? r.attentionReason : null,\n ownerNoteHtml: r.ownerNote ? markdownToHtml(r.ownerNote) : null,\n lastAnswer: answer ? { agentId: answer.agentId, at: answer.at, html: markdownToHtml(cutAnswer!) } : null,\n loop: r.promise || r.dueAt !== null || r.closeWhen ? {\n owedTo: r.owedTo, promise: r.promise, dueAt: r.dueAt, check: r.closeWhen ? describeCloseWhen(r.closeWhen) : null,\n verifyState: r.verifyState, verifyDetail: r.verifyDetail,\n } : null,\n stall: stall && why ? { ...waitsOn(r, { isAgent: stall.isAgent, activeStepAgent: activeStepAgentOf(plans) }), why } : null,\n plan: plan ? {\n state: plan.state,\n steps: plans!.steps(r.id).map((s) => ({\n idx: s.idx, name: s.name, kind: s.kind, agentId: s.agentId, state: s.state,\n approval: s.needsApproval ? s.approval : null, evidence: s.evidence, note: s.note, nudges: s.nudges,\n })),\n } : null,\n }\n}\n","import { OPEN_STATES, OWED_TO_OWNER, type RequestRecord, type RequestStore } from \"./store\"\nimport { runCheck, type CheckContext, type CheckResult, type CloseWhen } from \"./checkers\"\n\n// --- Open loops: who each one waits on, and when it is stalled (#1039) ---\n//\n// A loop is an open request: one the owner asked for, or one an agent\n// promised (action promise). It is stalled when it is past its due time,\n// or, without one, when nothing has happened for staleAfterHours. A loop\n// that needs attention is stalled too: nothing is retrying it.\n//\n// Stalled loops are grouped by what they wait on:\n// owner the owner's answer (waiting_owner), or the owner's decision\n// on one that needs attention\n// agent an agent: the one that has it, a plan step's agent, or the\n// agent it is owed to\n// person an outside person: a promise owed to a known person\n// The requests panel, `agentx requests --stalled` and the sweep's notice\n// all use this one grouping.\n\nexport const STALL_GROUPS = [\"owner\", \"agent\", \"person\"] as const\nexport type StallGroup = (typeof STALL_GROUPS)[number]\n\nexport interface StalledLoop {\n request: RequestRecord\n group: StallGroup\n /** Who it waits on: \"owner\", an agent id or a person id. */\n who: string\n /** Why it counts as stalled, in words. */\n why: string\n}\n\nexport interface LoopLookups {\n isAgent: (id: string) => boolean\n /** The agent of the active step of the request's plan, if it has one. */\n activeStepAgent?: (requestId: string) => string | null\n}\n\nconst HOUR = 3_600_000\nconst isOpen = (r: RequestRecord) => (OPEN_STATES as readonly string[]).includes(r.state)\n\n/** The agent of each request's active plan step, from the plan store. */\nexport function activeStepAgentOf(plans: { get(id: string): { state: string } | null; steps(id: string): Array<{ state: string; agentId: string }> } | null | undefined) {\n return (requestId: string): string | null => {\n if (!plans || plans.get(requestId)?.state !== \"active\") return null\n return plans.steps(requestId).find((s) => s.state === \"active\")?.agentId ?? null\n }\n}\n\n/** What an open loop waits on. */\nexport function waitsOn(r: RequestRecord, look: LoopLookups): { group: StallGroup; who: string } {\n if (r.state === \"waiting_owner\") return { group: \"owner\", who: OWED_TO_OWNER }\n if (r.promise && r.owedTo && r.owedTo !== OWED_TO_OWNER && !look.isAgent(r.owedTo)) return { group: \"person\", who: r.owedTo }\n if (r.state === \"needs_attention\") return { group: \"owner\", who: OWED_TO_OWNER }\n const step = look.activeStepAgent?.(r.id)\n return { group: \"agent\", who: step ?? r.agentId }\n}\n\n/** Why an open loop is stalled, or null when it is not. */\nexport function stalledWhy(r: RequestRecord, staleAfterHours: number, now: number): string | null {\n if (!isOpen(r)) return null\n if (r.state === \"needs_attention\") return r.attentionReason ?? \"needs attention\"\n if (r.dueAt !== null) return now > r.dueAt ? `past its due time (${when(r.dueAt)})` : null\n return now - r.updatedAt > staleAfterHours * HOUR ? `no activity for ${staleAfterHours} h or more` : null\n}\n\n/** Stalled loops among `items`, oldest first, grouped. */\nexport function stalledLoops(items: RequestRecord[], staleAfterHours: number, now: number, look: LoopLookups): Record<StallGroup, StalledLoop[]> {\n const out: Record<StallGroup, StalledLoop[]> = { owner: [], agent: [], person: [] }\n for (const r of items) {\n const why = stalledWhy(r, staleAfterHours, now)\n if (!why) continue\n const { group, who } = waitsOn(r, look)\n out[group].push({ request: r, group, who, why })\n }\n return out\n}\n\n/** The group, in words, for people. */\nexport function waitsOnWords(group: StallGroup, who: string): string {\n return group === \"owner\" ? \"you\" : group === \"agent\" ? `agent ${who}` : `${who} (outside person)`\n}\n\nexport const when = (ms: number) => new Date(ms).toISOString().slice(0, 16).replace(\"T\", \" \") + \" UTC\"\n\n/** A due time an agent or the owner gave: epoch ms, or an ISO date.\n * Undefined when absent, a string when it is not a time. */\nexport function parseDue(v: unknown): number | undefined | string {\n if (v === undefined || v === null || v === \"\") return undefined\n const at = typeof v === \"number\" ? v : typeof v === \"string\" ? Date.parse(v.trim()) : NaN\n if (!Number.isFinite(at) || at <= 0) return \"due must be an ISO date (2030-01-31T17:00:00Z) or epoch milliseconds\"\n return at\n}\n\n// ── Running the checkers from the requests check ─────────────────────────\n\n/** Runs a loop's checker. The daemon's own; tests give their own. */\nexport type LoopChecker = (spec: CloseWhen, request: RequestRecord) => Promise<CheckResult>\n\nexport function loopChecker(ctx: () => CheckContext): LoopChecker {\n return (spec) => runCheck(spec, ctx())\n}\n\n/** How many checkers run at once, and how many loops one check takes on. */\nconst CHECK_BATCH = 10\n\n/** Run the checker of every open loop whose last check is older than\n * `everyMinutes`. Met closes it as done with the checker's evidence;\n * unverifiable marks it unverified; not met leaves it as it is. */\nexport async function checkLoops(\n store: RequestStore,\n check: LoopChecker,\n opts: { everyMinutes: number; now: number; log: (msg: string) => void },\n): Promise<{ checked: number; closed: number }> {\n const due = store.dueForCheck(opts.now - opts.everyMinutes * 60_000, CHECK_BATCH)\n let closed = 0\n await Promise.all(due.map(async (r) => {\n // Marked before the call: a check that hangs is not started again\n // at the next minute.\n store.markChecked(r.id, r.verifyState, r.verifyDetail ?? \"\", opts.now)\n const res = await check(r.closeWhen!, r).catch((e: any): CheckResult => ({ verdict: \"unverifiable\", detail: String(e?.message ?? e) }))\n if (res.verdict === \"met\") {\n if (store.closeVerified(r.id, res.detail, opts.now)) {\n closed++\n opts.log(`[requests] ${r.id} closed by its check: ${res.detail}`)\n }\n return\n }\n // A refused done stays \"failed\" until the check says otherwise.\n store.markChecked(r.id, res.verdict === \"unverifiable\" ? \"unverified\" : r.verifyState === \"failed\" ? \"failed\" : null, res.detail, opts.now)\n }))\n return { checked: due.length, closed }\n}\n"],"mappings":"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","names":["existsSync","readFileSync","dirname","join","fileURLToPath","homedir","DESKTOP_LABEL","DESKTOP_APP","HELPER_APP","desktopPlatformError","platform","arch","release","selectDesktopAgent","agents","requested","id","shellQuote","value","LAUNCHD_PATH","desktopPath","ffmpeg","override","unxml","s","ents","_","e","plistPathEnv","plist","m","isVoiceLoginItemFile","name","adoptLoginItem","dir","items","keep","remove","file","a","b","label","program","findOnPath","bin","path","isExecutable","desktopPlist","opts","xml","env","k","v","helperBuildArgs","icon","installedHelper","home","packageRoot","from","resolveHelper","root","installed","findHelper","accessSync","constants","execFile","STEP_TIMEOUT_MS","run","file","args","done","err","capture","stdout","output","resolve","reject","stderr","helperOf","io","findHelper","helperBannerStatus","path","capture","out","status","macosBanner","exec","run","title","message","helper","NOTES_SCRIPT","macosNotes","exec","output","folder","title","body","id","existsSync","readdirSync","SOUNDS","soundPath","name","path","existsSync","macosSound","io","exec","run","volume","readdirSync","f","SPEAKERS","speakersIn","ps","exceptParents","self","line","m","pid","ppid","comm","name","macosSpeech","io","capture","opts","ZWSP","argValue","v","unArg","listName","list","isoDue","d","macosTasks","command","exec","output","raw","lists","l","items","r","title","notes","due","priority","args","id","patch","executable","file","accessSync","constants","focus","s","readSystemFocus","macosAdapter","cfg","io","command","macosTasks","macosNotes","macosBanner","macosSound","macosSpeech","problems","isExec","findOnPath","noneAdapter","reason","FACTORIES","macosAdapter","loadNativeAdapter","cfg","opts","noneAdapter","platform","make","existsSync","homedir","isAbsolute","DEFAULT_LOCAL","localSettings","cfg","localAlert","settings","deps","native","loadNativeAdapter","title","message","steps","sound","quiet","ok","speech","waitMs","pollMs","until","r","patchLocal","current","patch","platform","next","name","icon","homedir","isAbsolute","existsSync","v","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","init_checkers","init_store","init_checkers","STALL_GROUPS","HOUR","isOpen","r","OPEN_STATES","activeStepAgentOf","plans","requestId","s","waitsOn","look","OWED_TO_OWNER","stalledWhy","staleAfterHours","now","when","stalledLoops","items","out","why","group","who","waitsOnWords","ms","parseDue","v","at","loopChecker","ctx","spec","runCheck","CHECK_BATCH","checkLoops","store","check","opts","due","closed","res","e","SUMMARY_MAX","ANSWER_MAX","NOTHING_NEEDED","cardWords","r","max","headline","summarize","need","plain","md","text","cut","end","requestCard","store","plans","stall","plan","why","stalledWhy","answer","cutAnswer","words","markdownToHtml","describeCloseWhen","waitsOn","activeStepAgentOf","s","MAX_ADD_FAILURES","KEEP_CLOSED_MS","mirrorPath","root","resolve","readMirror","parsed","readFileSync","writeMirror","file","path","existsSync","dirname","mkdirSync","tmp","writeFileSync","renameSync","MIRROR_FRESH_MS","mirrorCovers","cardId","now","checked","DAY_MS","dueFor","settings","limit","due","cardItem","card","answerUrl","expires","lines","summarize","CARD_LIMITS","c","i","requestItem","r","dueAt","cardWords","runMirror","deps","tasks","log","at","result","fail","message","waiting","e","allRead","openIds","openIn","list","t","key","entry","open","listReady","gaveUp","item","failures","id","n","told","first","more","err"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as Ge,b as Fe,c as Se}from"./chunk-SFQUP3BP.js";import{b as Te,c as Ce}from"./chunk-QOYAX2FT.js";import{a as Q,c as Ne,e as we,f as ke,g as be,i as xe,k as gt,o as ve,p as ht}from"./chunk-
|
|
1
|
+
import{a as Ge,b as Fe,c as Se}from"./chunk-SFQUP3BP.js";import{b as Te,c as Ce}from"./chunk-QOYAX2FT.js";import{a as Q,c as Ne,e as we,f as ke,g as be,i as xe,k as gt,o as ve,p as ht}from"./chunk-JNG3P5V2.js";import{a as R,b as ye}from"./chunk-7I7IEX4S.js";import{b as Le,e as _e}from"./chunk-JHCI6XCJ.js";import{e as b}from"./chunk-DSYKYZMT.js";import{z as $}from"zod";var qe=$.object({provider:$.enum(["claude-code","claude","openai","deepseek","ollama","demo","custom"]).default("claude-code"),model:$.string().optional(),apiKey:$.string().optional(),skills:$.array($.string()).default([]),output:$.object({dir:$.string().default("./generated")}).default({}),context7:$.object({enabled:$.boolean().default(!0),apiKey:$.string().optional()}).default({}),agentic:$.object({maxIterations:$.number().default(20),enabledTools:$.array($.string()).default(["create_files","ask_user","read_file","search_files","list_directory","run_command","edit_file"]),disabledTools:$.array($.string()).default([])}).default({})}),Vt=["component","page","api","website","document","script","config","skill","media","report","test","workflow","schema","email","diagram","auto"],Yt={component:"UI component (any framework)",page:"Full page or screen",api:"API endpoint, route handler, or service",website:"Multi-page website or app",document:"Markdown, documentation, or specification",script:"Standalone script or utility",config:"Configuration file or setup",skill:"Agent skill (SKILL.md format for skills.sh)",media:"Media generation prompt (image/audio/video description)",report:"Analysis report or audit",test:"Test suite, test fixtures, or test data",workflow:"CI/CD pipeline, GitHub Actions, or automation",schema:"Database schema, Zod validators, or GraphQL types",email:"Email template (React Email, MJML, HTML)",diagram:"Mermaid, D2, or PlantUML diagram",auto:"Auto-detect the best output type"};ht();ke();ke();import{existsSync as yt,promises as wt}from"fs";import K from"path";import kt from"fast-glob";var Be={"prisma/schema.prisma":{type:"prisma",category:"database"},"drizzle/schema.ts":{type:"drizzle",category:"database"},"schema.graphql":{type:"graphql",category:"api"},"schema.gql":{type:"graphql",category:"api"},"openapi.yaml":{type:"openapi",category:"api"},"openapi.json":{type:"openapi",category:"api"},"swagger.yaml":{type:"openapi",category:"api"},"swagger.json":{type:"openapi",category:"api"}};async function We(r){let e={},t=await kt.glob("**/*",{cwd:r,deep:4,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/.next/**","**/target/**","**/__pycache__/**","**/vendor/**","**/.git/**"],onlyFiles:!0});for(let[s,i]of Object.entries(Be)){let c=t.find(a=>a.endsWith(s)||a===s);if(c&&i.category==="database"){let a=await Z(K.resolve(r,c));if(a){e.database={type:i.type,content:ce(a,3e3),tables:bt(a,i.type)};break}}}for(let[s,i]of Object.entries(Be)){let c=t.find(a=>a.endsWith(s)||a===s);if(c&&i.category==="api"){let a=await Z(K.resolve(r,c));if(a){e.api={type:i.type,content:ce(a,3e3)};break}}}if(!e.api){let s=t.find(i=>i.includes("trpc")&&(i.endsWith("router.ts")||i.endsWith("router.js")));if(s){let i=await Z(K.resolve(r,s));i&&(e.api={type:"trpc",content:ce(i,3e3)})}}let o=t.find(s=>s===".env.example"||s===".env.local.example"||s===".env.template");if(o){let s=await Z(K.resolve(r,o));s&&(e.env=xt(s))}let n=t.filter(s=>(s.includes("models")||s.includes("types")||s.includes("schemas"))&&(s.endsWith(".ts")||s.endsWith(".py")||s.endsWith(".rs")||s.endsWith(".go")));if(n.length){e.models=[];for(let s of n.slice(0,5)){let i=await Z(K.resolve(r,s));i&&e.models.push({path:s,content:ce(i,2e3),type:K.extname(s).slice(1)})}}return e}function bt(r,e){if(e==="prisma"){let t=r.match(/model\s+(\w+)\s*\{/g);return t?t.map(o=>o.replace(/model\s+/,"").replace(/\s*\{/,"")):[]}return[]}function xt(r){return{variables:r.split(`
|
|
2
2
|
`).filter(o=>o.trim()&&!o.trim().startsWith("#")).map(o=>{let[n]=o.split("="),s=n.trim(),i=o.includes("=")&&o.split("=")[1]?.trim().length>0;return{key:s,required:!i}})}}async function Z(r){try{return yt(r)?await wt.readFile(r,"utf8"):null}catch{return null}}function ce(r,e){return r.length<=e?r:r.slice(0,e)+`
|
|
3
3
|
... (truncated)`}function ze(r){let e=[];if(r.database&&e.push(`## Database Schema (${r.database.type})
|
|
4
4
|
`+(r.database.tables?.length?`Tables: ${r.database.tables.join(", ")}
|
|
@@ -18,7 +18,7 @@ ${s.join(`
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
`)}`:""}var Ye={component:{type:"component",baseDir:"src/components",filePatterns:["*.tsx","*.vue","*.svelte","*.jsx","*.ts"],description:"UI component"},page:{type:"page",baseDir:"src/app",filePatterns:["*.tsx","*.vue","*.svelte","*.jsx","*.astro"],description:"Page or screen"},api:{type:"api",baseDir:"src/api",filePatterns:["*.ts","*.js","*.py","*.go","*.rs"],description:"API route or endpoint"},website:{type:"website",baseDir:".",filePatterns:["*"],description:"Multi-file website"},document:{type:"document",baseDir:"docs",filePatterns:["*.md","*.mdx","*.txt","*.rst"],description:"Documentation"},script:{type:"script",baseDir:"scripts",filePatterns:["*.ts","*.js","*.py","*.sh","*.go"],description:"Standalone script"},config:{type:"config",baseDir:".",filePatterns:["*.json","*.yaml","*.yml","*.toml","*.env"],description:"Configuration file"},skill:{type:"skill",baseDir:".skills",filePatterns:["SKILL.md"],description:"Agent skill (SKILL.md)"},media:{type:"media",baseDir:"media",filePatterns:["*.md","*.json","*.txt"],description:"Media generation prompt/description"},report:{type:"report",baseDir:"reports",filePatterns:["*.md","*.html","*.json"],description:"Analysis report"},test:{type:"test",baseDir:"src",filePatterns:["*.test.ts","*.test.tsx","*.spec.ts","*.test.js","*.test.py","*.test.go"],description:"Test suite or fixture"},workflow:{type:"workflow",baseDir:".github/workflows",filePatterns:["*.yml","*.yaml"],description:"CI/CD pipeline or automation"},schema:{type:"schema",baseDir:"src",filePatterns:["*.ts","*.prisma","*.graphql","*.gql","*.py"],description:"Database schema, validators, or types"},email:{type:"email",baseDir:"src/emails",filePatterns:["*.tsx","*.jsx","*.html","*.mjml"],description:"Email template"},diagram:{type:"diagram",baseDir:"docs",filePatterns:["*.md","*.mmd","*.d2","*.puml"],description:"Architecture or data diagram"}};function Pe(r,e){if(r&&r!=="auto")return r;let t=e.toLowerCase(),o=[[/\b(component|button|card|modal|dialog|form|input|dropdown|nav|sidebar|header|footer|widget|ui)\b/i,"component"],[/\b(page|screen|view|route|layout|dashboard|landing)\b/i,"page"],[/\b(api|endpoint|route handler|rest|graphql|webhook|middleware|server)\b/i,"api"],[/\b(website|site|web app|landing page|portfolio|blog)\b/i,"website"],[/\b(document|doc|readme|guide|tutorial|specification|spec|changelog)\b/i,"document"],[/\b(script|cli|command|tool|utility|migration|seed|cron)\b/i,"script"],[/\b(config|configuration|setup|env|settings)\b/i,"config"],[/\b(skill|agent skill|skill\.md)\b/i,"skill"],[/\b(video|audio|image|media|animation|thumbnail|podcast)\b/i,"media"],[/\b(report|audit|analysis|review|assessment|benchmark)\b/i,"report"],[/\b(test|spec|unit test|integration test|e2e|coverage|fixture|mock)\b/i,"test"],[/\b(workflow|ci|cd|pipeline|github action|deploy|automation|ci\/cd)\b/i,"workflow"],[/\b(schema|model|migration|prisma|drizzle|zod|validator|graphql type)\b/i,"schema"],[/\b(email|newsletter|transactional|invite|welcome email|notification email)\b/i,"email"],[/\b(diagram|erd|flowchart|architecture diagram|sequence diagram|mermaid|plantuml|d2)\b/i,"diagram"]];for(let[n,s]of o)if(n.test(t))return s;return"component"}import{existsSync as It,promises as ot}from"fs";import ue from"path";import{execa as Ct}from"execa";import{z as N}from"zod";var ee=["pre:generate","post:generate","pre:file-write","post:file-write","pre:prompt","post:response","pre:command","on:error","pre:tool-call","post:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run","post:cron-run","on:gitlab-pipeline","on:gitlab-issue","on:gitlab-mr","on:gitlab-note","on:github-issue","on:github-pr","on:github-push","on:n8n","on:stripe-event","on:sentry-issue","on:vercel-deployment","on:odoo-event","on:hubspot-event"],Re=["pre:generate","pre:file-write","pre:prompt","post:response","pre:command","pre:tool-call","pre:channel-message","post:channel-message","pre:a2a-task","pre:cron-run"],Xe=N.object({name:N.string(),type:N.enum(["command","prompt","script"]),command:N.string().optional(),prompt:N.string().optional(),provider:N.enum(["claude-code","claude","openai","deepseek","ollama","custom"]).optional(),model:N.string().optional(),script:N.string().optional(),priority:N.number().default(100),enabled:N.boolean().default(!0)});ye();var Qe={"claude-sonnet":{input:3,output:15},"claude-opus":{input:15,output:75},"claude-haiku":{input:.25,output:1.25}};function St(r){let e=r.toLowerCase();return e.includes("opus")?"claude-opus":e.includes("haiku")?"claude-haiku":"claude-sonnet"}var le=class{steps=[];models=new Map;recordStep(e,t,o,n){let s=St(t),i=Qe[s]||Qe["claude-sonnet"],c=o/1e6*i.input+n/1e6*i.output;this.steps.push({step:e,model:t,inputTokens:o,outputTokens:n,cost:c,timestamp:Date.now()});let a=this.models.get(t)||{inputTokens:0,outputTokens:0,cost:0,steps:0};a.inputTokens+=o,a.outputTokens+=n,a.cost+=c,a.steps++,this.models.set(t,a)}getSummary(){let e=0,t=0,o=0;for(let s of this.steps)e+=s.inputTokens,t+=s.outputTokens,o+=s.cost;let n={};for(let[s,i]of this.models)n[s]={...i};return{totalInputTokens:e,totalOutputTokens:t,totalTokens:e+t,totalCost:o,steps:[...this.steps],models:n}}reset(){this.steps=[],this.models.clear()}},te=new le;function Tt(r,e){let t=[];if(t.push(`# Session: ${r.id}`),t.push(""),t.push(`- **Created**: ${r.createdAt}`),t.push(`- **Updated**: ${r.updatedAt}`),t.push(`- **CWD**: ${r.cwd}`),t.push(`- **Messages**: ${r.messages.length}`),t.push(`- **Tokens**: ${r.tokensUsed.toLocaleString()}`),t.push(""),r.filesGenerated.length){t.push("## Files Generated"),t.push("");for(let o of r.filesGenerated)t.push(`- \`${o}\``);t.push("")}if(r.messages.length){t.push("## Conversation"),t.push("");for(let o of r.messages){if(o.role==="system")continue;let n=o.role==="user"?"**User**":"**Assistant**";t.push(`### ${n}`),t.push(""),o.role,t.push(o.content),t.push("")}}if(e){if(t.push("## Cost Summary"),t.push(""),t.push(`- **Total tokens**: ${e.totalTokens.toLocaleString()}`),t.push(` - Input: ${e.totalInputTokens.toLocaleString()}`),t.push(` - Output: ${e.totalOutputTokens.toLocaleString()}`),t.push(`- **Total cost**: $${e.totalCost.toFixed(4)}`),t.push(""),Object.keys(e.models).length){t.push("### Per Model"),t.push(""),t.push("| Model | Input | Output | Cost | Steps |"),t.push("|-------|-------|--------|------|-------|");for(let[o,n]of Object.entries(e.models))t.push(`| ${o} | ${n.inputTokens.toLocaleString()} | ${n.outputTokens.toLocaleString()} | $${n.cost.toFixed(4)} | ${n.steps} |`);t.push("")}if(e.steps.length){t.push("### Per Step"),t.push(""),t.push("| Step | Model | Input | Output | Cost |"),t.push("|------|-------|-------|--------|------|");for(let o of e.steps)t.push(`| ${o.step} | ${o.model} | ${o.inputTokens.toLocaleString()} | ${o.outputTokens.toLocaleString()} | $${o.cost.toFixed(4)} |`);t.push("")}}return t.join(`
|
|
21
|
-
`)}ke();var oe=class{hooks=new Map;register(e,t){if(!t.enabled)return;let o=this.createHandler(t),n={event:e,definition:t,handler:o},s=this.hooks.get(e)||[];s.push(n),s.sort((i,c)=>i.definition.priority-c.definition.priority),this.hooks.set(e,s)}async execute(e,t){let o=this.hooks.get(e);if(!o?.length)return{};let n=Re.includes(e),s={};for(let i of o){let c=Date.now();try{let a=await i.handler({...t,...s}),p=Date.now()-c;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return b.hook(i.definition.name,p,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};b.hook(i.definition.name,p,"ok")}catch(a){let p=Date.now()-c;if(b.hook(i.definition.name,p,`error: ${a.message}`),R.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}registerHandler(e,t,o,n=100){let i={event:e,definition:{name:t,type:"script",priority:n,enabled:!0},handler:o},c=this.hooks.get(e)||[];c.push(i),c.sort((a,p)=>a.definition.priority-p.definition.priority),this.hooks.set(e,c)}has(e){return!!this.hooks.get(e)?.length}clear(){this.hooks.clear()}size(){let e=0;for(let t of this.hooks.values())e+=t.length;return e}createHandler(e){switch(e.type){case"command":return this.createCommandHandler(e);case"script":return this.createScriptHandler(e);case"prompt":return this.createPromptHandler(e);default:throw new Error(`Unknown hook type: ${e.type}`)}}createCommandHandler(e){return async t=>{if(!e.command)return{};let o=e.command;o=o.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(t[i]??""));let n=await Ct("sh",["-c",o],{cwd:t.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${e.name}" failed`}:{}}}createScriptHandler(e){return async t=>{if(!e.script)return{};let n=await import(e.script.startsWith("/")?e.script:`${t.cwd||process.cwd()}/${e.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(t):{}}}createPromptHandler(e){return async t=>{if(!e.prompt)return{};let o=e.provider||Q()?.provider||"claude-code",n=Ne();if(!n&&o!=="claude-code")return R.warn(`Prompt hook "${e.name}" skipped: no credentials available for provider "${o}"`),{};try{let{createProvider:s}=await import("./providers-
|
|
21
|
+
`)}ke();var oe=class{hooks=new Map;register(e,t){if(!t.enabled)return;let o=this.createHandler(t),n={event:e,definition:t,handler:o},s=this.hooks.get(e)||[];s.push(n),s.sort((i,c)=>i.definition.priority-c.definition.priority),this.hooks.set(e,s)}async execute(e,t){let o=this.hooks.get(e);if(!o?.length)return{};let n=Re.includes(e),s={};for(let i of o){let c=Date.now();try{let a=await i.handler({...t,...s}),p=Date.now()-c;if(a.modified&&(s={...s,...a.modified}),n&&a.blocked)return b.hook(i.definition.name,p,"blocked"),{blocked:!0,message:a.message||`Blocked by hook: ${i.definition.name}`,modified:s};b.hook(i.definition.name,p,"ok")}catch(a){let p=Date.now()-c;if(b.hook(i.definition.name,p,`error: ${a.message}`),R.warn(`Hook "${i.definition.name}" failed: ${a.message}`),n)return{blocked:!0,message:`Hook "${i.definition.name}" errored: ${a.message}`}}}return{modified:Object.keys(s).length?s:void 0}}registerHandler(e,t,o,n=100){let i={event:e,definition:{name:t,type:"script",priority:n,enabled:!0},handler:o},c=this.hooks.get(e)||[];c.push(i),c.sort((a,p)=>a.definition.priority-p.definition.priority),this.hooks.set(e,c)}has(e){return!!this.hooks.get(e)?.length}clear(){this.hooks.clear()}size(){let e=0;for(let t of this.hooks.values())e+=t.length;return e}createHandler(e){switch(e.type){case"command":return this.createCommandHandler(e);case"script":return this.createScriptHandler(e);case"prompt":return this.createPromptHandler(e);default:throw new Error(`Unknown hook type: ${e.type}`)}}createCommandHandler(e){return async t=>{if(!e.command)return{};let o=e.command;o=o.replace(/\{\{(\w+)\}\}/g,(s,i)=>String(t[i]??""));let n=await Ct("sh",["-c",o],{cwd:t.cwd||process.cwd(),reject:!1,timeout:6e4,env:process.env});return n.exitCode!==0?{blocked:!0,message:n.stderr||n.stdout||`Command hook "${e.name}" failed`}:{}}}createScriptHandler(e){return async t=>{if(!e.script)return{};let n=await import(e.script.startsWith("/")?e.script:`${t.cwd||process.cwd()}/${e.script}`),s=n.default||n.handler||n;return typeof s=="function"?await s(t):{}}}createPromptHandler(e){return async t=>{if(!e.prompt)return{};let o=e.provider||Q()?.provider||"claude-code",n=Ne();if(!n&&o!=="claude-code")return R.warn(`Prompt hook "${e.name}" skipped: no credentials available for provider "${o}"`),{};try{let{createProvider:s}=await import("./providers-BDJXGHEY.js"),i=s(o,n?.token),c=e.prompt;c=c.replace(/\{\{(\w+)\}\}/g,(m,I)=>String(t[I]??""));let a=`You are a hook validator for agentx. Analyze the following context and respond with ONLY a JSON object (no markdown, no code fences).
|
|
22
22
|
|
|
23
23
|
Response format:
|
|
24
24
|
{"action": "allow", "message": "optional explanation"}
|
|
@@ -48,7 +48,7 @@ The "modified" field is optional and can contain updated values to pass forward.
|
|
|
48
48
|
... (output truncated)`:i;return s.exitCode!==0?{tool_use_id:e.id,content:`Command exited with code ${s.exitCode}:
|
|
49
49
|
${c}`,is_error:!0}:{tool_use_id:e.id,content:c||"(no output)"}}async editFile(e){let t=String(e.input.path||""),o=e.input.edits,n=ge.resolve(this.cwd,t);if(!o||o.length===0)return{tool_use_id:e.id,content:"No edits provided.",is_error:!0};let s=await W.checkFileWrite(t);if(s==="deny")return{tool_use_id:e.id,content:`File write blocked by permissions: ${t}`,is_error:!0};if(s==="skip")return{tool_use_id:e.id,content:`File write skipped (plan mode): ${t}`};if(f.has("pre:file-write")){let a=await f.execute("pre:file-write",{event:"pre:file-write",file:n,cwd:this.cwd});if(a.blocked)return{tool_use_id:e.id,content:a.message||`File edit blocked by pre:file-write hook: ${t}`,is_error:!0}}let i=await re.readFile(n,"utf8"),c=[];for(let a of o)i.includes(a.old_text)?(i=i.replace(a.old_text,a.new_text),c.push(`Replaced: "${a.old_text.slice(0,40)}..."`)):c.push(`Not found: "${a.old_text.slice(0,40)}..."`);return this.options.dryRun||await re.writeFile(n,i,"utf8"),f.has("post:file-write")&&await f.execute("post:file-write",{event:"post:file-write",file:n,fileContent:i,cwd:this.cwd}),{tool_use_id:e.id,content:`Edited ${t}:
|
|
50
50
|
${c.join(`
|
|
51
|
-
`)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-XY5N7TUU.js"),{getGlobalRegistry:i}=await import("./registry-
|
|
51
|
+
`)}`}}async createFiles(e){let t=e.input,o=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${o.length} file(s) for creation.`,files:o}}async spawnAgent(e){let t=String(e.input.agent_id||""),o=String(e.input.prompt||""),n=Number(e.input.timeout_seconds)||300;if(!t||!o)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-XY5N7TUU.js"),{getGlobalRegistry:i}=await import("./registry-RQBXAPUZ.js"),c=i();if(!c)return{tool_use_id:e.id,content:"Sub-agent spawning requires the daemon to be running.",is_error:!0};let p=await new s(c).spawn({targetAgentId:t,prompt:o,parentAgentId:"orchestrator",timeout:n*1e3});return p.success?{tool_use_id:e.id,content:`Sub-agent "${t}" completed (${Math.round(p.duration/1e3)}s):
|
|
52
52
|
|
|
53
53
|
${p.content}`}:{tool_use_id:e.id,content:`Sub-agent "${t}" failed: ${p.error}`,is_error:!0}}catch(s){return{tool_use_id:e.id,content:`Failed to spawn sub-agent: ${s.message}`,is_error:!0}}}async askUser(e){let t=String(e.input.question||""),o=e.input.options,n=t;return o?.length&&(n+=`
|
|
54
54
|
Options: ${o.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",followUp:n}}};async function Ae(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,cwd:s,maxIterations:i=20,enabledTools:c,interactive:a=!0,overwrite:p=!1,dryRun:l=!1,onProgress:d,abortSignal:u}=r,m=u?{...n,abortSignal:u}:n;if(!e.generateRaw)return dt(r);let I=new se(s,{interactive:a,overwrite:p,dryRun:l,acmeContext:r.acmeContext,abortSignal:u}),D=be(c);if(r.acmeContext)for(let g of at)D.push({name:g.name,description:g.description,input_schema:g.input_schema});let E=new Set;if(r.mcpTools?.length)for(let g of r.mcpTools)D.push({name:g.name,description:g.description,input_schema:g.input_schema}),E.add(g.name);let C=o.filter(g=>g.role!=="system").map(g=>({role:g.role,content:g.content})),B=[],G=0,F=0,A=0,O="",j,_=0;for(;_<i;){if(_++,u?.aborted)throw new Error("cancelled");d?.({type:"iteration_start",iteration:_}),b.step(_,`Agentic loop iteration (${D.length} tools available)`);let g,M=!!e.generateRawStream&&!!d;try{if(M){let T=null,U=null,v="";for await(let x of e.generateRawStream(C,t,D,m))x.type==="text_delta"?(v+=x.text,d?.({type:"text_delta",text:x.text})):x.type==="thinking_delta"?d?.({type:"thinking_delta",text:x.text}):x.type==="raw_result"?T=x.result:x.type==="error"&&(U=x.error);if(U&&!T)throw new Error(U);if(!T)throw new Error("generateRawStream returned no raw_result event");g=T,g._streamedText=v}else g=await e.generateRaw(C,t,D,m)}catch(T){if(T.message?.includes("not available"))return dt(r);throw T}G+=g.usage.input_tokens+g.usage.output_tokens,F+=g.usage.input_tokens,A+=g.usage.output_tokens;let P=g._streamedText;for(let T of g.content)T.type==="text"&&(O+=T.text,P===void 0&&d?.({type:"text_delta",text:T.text}));if(P!==void 0&&delete g._streamedText,g.stop_reason==="end_turn"||g.stop_reason==="max_tokens")break;if(g.stop_reason==="tool_use"){let T=g.content.filter(v=>v.type==="tool_use");if(T.length===0)break;C.push({role:"assistant",content:g.content});let U=[];for(let v of T){d?.({type:"tool_call",name:v.name,id:v.id,input:v.input}),b.step(_,`Tool call: ${v.name}`);let x;if(E.has(v.name)&&r.mcpDispatch){let h=await r.mcpDispatch(v.name,v.input);x={tool_use_id:v.id,content:h.content,is_error:h.isError}}else x=await I.execute({name:v.name,id:v.id,input:v.input});d?.({type:"tool_result",name:v.name,id:v.id,content:x.content.slice(0,200),is_error:x.is_error}),x.files?.length&&(B.push(...x.files),d?.({type:"files_created",files:x.files})),x.followUp&&(j=x.followUp),U.push({type:"tool_result",tool_use_id:x.tool_use_id,content:x.content,is_error:x.is_error})}if(C.push({role:"user",content:U}),j)break;continue}break}return d?.({type:"complete",iterations:_,totalTokens:G}),{files:B,content:O,followUp:j,tokensUsed:G,inputTokens:F||void 0,outputTokens:A||void 0,iterations:_}}async function dt(r){let{provider:e,systemPrompt:t,messages:o,providerOptions:n,maxIterations:s=5}=r,c=[{role:"system",content:t+`
|
|
@@ -65,7 +65,7 @@ ${D}`:"")}),c.push({role:"user",content:"Continue generating the remaining files
|
|
|
65
65
|
`))>=0;){let a=n.slice(0,c);n=n.slice(c+2);let p=[];for(let u of a.split(`
|
|
66
66
|
`)){let m=u.replace(/\r$/,"");m.startsWith("data:")&&p.push(m.slice(5).trim())}if(!p.length)continue;let l=p.join(`
|
|
67
67
|
`);if(!l||l==="[DONE]")continue;let d;try{d=JSON.parse(l)}catch{continue}if(d&&d.id===e)return d}}}finally{try{t.cancel().catch(()=>{})}catch{}}throw new Error(`SSE stream ended without a response for id=${e}`)}var Ue=class{constructor(e,t){this.name=e;this.transport=Wt(t)?new Ie(e,t):new je(e,t)}transport;async initialize(){await this.transport.request("initialize",{protocolVersion:Lt,capabilities:{},clientInfo:{name:"agentx-orchestrator",version:"0.1.0"}},ut),this.transport.notify("notifications/initialized")}async listTools(){return((await this.transport.request("tools/list",{},ut)).tools??[]).map(t=>({name:t.name,description:t.description??"",input_schema:t.inputSchema??{type:"object",properties:{}}}))}async callTool(e,t){let o=await this.transport.request("tools/call",{name:e,arguments:t??{}},qt),n=[];for(let s of o.content??[])s?.type==="text"&&typeof s.text=="string"?n.push(s.text):n.push(JSON.stringify(s));return{content:n.join(`
|
|
68
|
-
`)||"(no output)",isError:o.isError}}close(){this.transport.close()}};async function He(r){let e=new Map,t=[],o=new Map;for(let[n,s]of Object.entries(r)){let i=new Ue(n,s);try{await i.initialize();let c=await i.listTools();for(let a of c){let p=`${Bt}${n}__${a.name}`;t.push({name:p,description:a.description||`${n}.${a.name}`,input_schema:a.input_schema}),o.set(p,{client:i,remote:a.name})}e.set(n,i)}catch(c){b.context("mcp",`${n}: skipped \u2014 ${c.message}`),i.close()}}return{tools:t,async dispatch(n,s){let i=o.get(n);if(!i)return{content:`Unknown MCP tool: ${n}`,isError:!0};try{return await i.client.callTool(i.remote,s)}catch(c){return{content:`MCP call failed: ${c.message}`,isError:!0}}},close(){for(let n of e.values())n.close()}}}var he=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function mt(r,e,t){let o=qe.parse(t||{}),n=new ne(r);await n.load();let[s,i,c]=await Promise.all([Ge(r),We(r),Le(r)]),a="";if(o.context7.enabled)try{a=await Ve(s,e,o.context7.apiKey)}catch{}let p=n.buildMemoryContext(e),l=Ee(r);return b.context("memory",p?"loaded":"empty"),b.context("instructions",l?"loaded from project":"none"),{techStack:s,schemas:i,skills:c,docs:a,config:o,memoryContext:p,projectInstructions:l}}async function Zn(r){let{task:e,cwd:t,overwrite:o=!1,dryRun:n=!1,provider:s="claude-code",model:i,apiKey:c,context7:a=!0,interactive:p=!0}=r,l=e;if(f.has("pre:prompt")){let h=await f.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by pre:prompt hook");h.modified?.task&&(l=String(h.modified.task))}if(f.has("pre:generate")){let h=await f.execute("pre:generate",{event:"pre:generate",task:l,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by pre:generate hook")}R.info("Analyzing project...");let d=await mt(t,l,{provider:s,context7:{enabled:a,apiKey:c}}),u=Pe(r.outputType,l);R.info(`Output type: ${u}`);let m=_e(d.skills,l,u);m.length&&R.info(`Loaded ${m.length} relevant skill(s): ${m.map(h=>h.skill.frontmatter.name).join(", ")}`);let I=ft(d,u,m.map(h=>h.skill));if(!await we(c))throw new Error("No credentials configured. Run `agentx model` to set up.");let E=ve(s,c,r.providerOpts||{}),C=i||Q()?.model,B=[...r.sessionMessages||[],{role:"user",content:l}];R.info("Generating...");let G=Oe(E),F=r.maxSteps??(G?20:5),A=r.mcpServers&&Object.keys(r.mcpServers).length>0?await He(r.mcpServers):void 0,O;try{O=await Ae({provider:E,systemPrompt:I,messages:[{role:"system",content:I},...B],providerOptions:{model:C,maxTokens:8192},cwd:t,maxIterations:F,enabledTools:d.config.agentic.enabledTools.filter(h=>!d.config.agentic.disabledTools.includes(h)),interactive:p,overwrite:o,dryRun:n,acmeContext:r.acmeContext,abortSignal:r.abortSignal,mcpTools:A?.tools,mcpDispatch:A?A.dispatch.bind(A):void 0,onProgress:h=>{h.type==="iteration_start"&&h.iteration>1&&R.info(`Step ${h.iteration}/${F}...`),h.type==="tool_call"&&b.step(0,`Tool: ${h.name}`)}})}finally{A?.close()}if(O.tokensUsed){let h=C||"claude-sonnet-4-20250514",V=Math.round(O.tokensUsed*.3),Y=O.tokensUsed-V;te.recordStep(1,h,V,Y)}let{content:j}=O,{followUp:_,tokensUsed:g,inputTokens:M,outputTokens:P}=O;if(O.iterations>1&&R.info(`Completed in ${O.iterations} step(s)`),f.has("post:response")){let h=await f.execute("post:response",{event:"post:response",content:j,task:l,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by post:response hook");h.modified?.content&&(j=String(h.modified.content))}if(_&&p)return{files:{written:[],skipped:[],errors:[]},content:j,outputType:u,followUp:_,tokensUsed:g,inputTokens:M,outputTokens:P};let T=new Map;for(let h of O.files)T.set(h.path,h);let U=fe(u,d.techStack,r.outputDir),v=await me(Array.from(T.values()),{cwd:t,overwrite:o,dryRun:n,outputDir:U}),x;if(r.heal!==!1&&!n&&v.written.length>0){let{HealEngine:h}=await import("./heal-
|
|
68
|
+
`)||"(no output)",isError:o.isError}}close(){this.transport.close()}};async function He(r){let e=new Map,t=[],o=new Map;for(let[n,s]of Object.entries(r)){let i=new Ue(n,s);try{await i.initialize();let c=await i.listTools();for(let a of c){let p=`${Bt}${n}__${a.name}`;t.push({name:p,description:a.description||`${n}.${a.name}`,input_schema:a.input_schema}),o.set(p,{client:i,remote:a.name})}e.set(n,i)}catch(c){b.context("mcp",`${n}: skipped \u2014 ${c.message}`),i.close()}}return{tools:t,async dispatch(n,s){let i=o.get(n);if(!i)return{content:`Unknown MCP tool: ${n}`,isError:!0};try{return await i.client.callTool(i.remote,s)}catch(c){return{content:`MCP call failed: ${c.message}`,isError:!0}}},close(){for(let n of e.values())n.close()}}}var he=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function mt(r,e,t){let o=qe.parse(t||{}),n=new ne(r);await n.load();let[s,i,c]=await Promise.all([Ge(r),We(r),Le(r)]),a="";if(o.context7.enabled)try{a=await Ve(s,e,o.context7.apiKey)}catch{}let p=n.buildMemoryContext(e),l=Ee(r);return b.context("memory",p?"loaded":"empty"),b.context("instructions",l?"loaded from project":"none"),{techStack:s,schemas:i,skills:c,docs:a,config:o,memoryContext:p,projectInstructions:l}}async function Zn(r){let{task:e,cwd:t,overwrite:o=!1,dryRun:n=!1,provider:s="claude-code",model:i,apiKey:c,context7:a=!0,interactive:p=!0}=r,l=e;if(f.has("pre:prompt")){let h=await f.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by pre:prompt hook");h.modified?.task&&(l=String(h.modified.task))}if(f.has("pre:generate")){let h=await f.execute("pre:generate",{event:"pre:generate",task:l,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by pre:generate hook")}R.info("Analyzing project...");let d=await mt(t,l,{provider:s,context7:{enabled:a,apiKey:c}}),u=Pe(r.outputType,l);R.info(`Output type: ${u}`);let m=_e(d.skills,l,u);m.length&&R.info(`Loaded ${m.length} relevant skill(s): ${m.map(h=>h.skill.frontmatter.name).join(", ")}`);let I=ft(d,u,m.map(h=>h.skill));if(!await we(c))throw new Error("No credentials configured. Run `agentx model` to set up.");let E=ve(s,c,r.providerOpts||{}),C=i||Q()?.model,B=[...r.sessionMessages||[],{role:"user",content:l}];R.info("Generating...");let G=Oe(E),F=r.maxSteps??(G?20:5),A=r.mcpServers&&Object.keys(r.mcpServers).length>0?await He(r.mcpServers):void 0,O;try{O=await Ae({provider:E,systemPrompt:I,messages:[{role:"system",content:I},...B],providerOptions:{model:C,maxTokens:8192},cwd:t,maxIterations:F,enabledTools:d.config.agentic.enabledTools.filter(h=>!d.config.agentic.disabledTools.includes(h)),interactive:p,overwrite:o,dryRun:n,acmeContext:r.acmeContext,abortSignal:r.abortSignal,mcpTools:A?.tools,mcpDispatch:A?A.dispatch.bind(A):void 0,onProgress:h=>{h.type==="iteration_start"&&h.iteration>1&&R.info(`Step ${h.iteration}/${F}...`),h.type==="tool_call"&&b.step(0,`Tool: ${h.name}`)}})}finally{A?.close()}if(O.tokensUsed){let h=C||"claude-sonnet-4-20250514",V=Math.round(O.tokensUsed*.3),Y=O.tokensUsed-V;te.recordStep(1,h,V,Y)}let{content:j}=O,{followUp:_,tokensUsed:g,inputTokens:M,outputTokens:P}=O;if(O.iterations>1&&R.info(`Completed in ${O.iterations} step(s)`),f.has("post:response")){let h=await f.execute("post:response",{event:"post:response",content:j,task:l,cwd:t});if(h.blocked)throw new Error(h.message||"Blocked by post:response hook");h.modified?.content&&(j=String(h.modified.content))}if(_&&p)return{files:{written:[],skipped:[],errors:[]},content:j,outputType:u,followUp:_,tokensUsed:g,inputTokens:M,outputTokens:P};let T=new Map;for(let h of O.files)T.set(h.path,h);let U=fe(u,d.techStack,r.outputDir),v=await me(Array.from(T.values()),{cwd:t,overwrite:o,dryRun:n,outputDir:U}),x;if(r.heal!==!1&&!n&&v.written.length>0){let{HealEngine:h}=await import("./heal-RGM7X2ZG.js");x=await new h(t,{enabled:!0,testCommand:r.healConfig?.testCommand,buildCommand:r.healConfig?.buildCommand,lintCommand:r.healConfig?.lintCommand,maxAttempts:r.healConfig?.maxAttempts??3,provider:s,model:C,apiKey:c}).detectAndHeal(v.written,l),!x.healed&&x.error&&await f.execute("on:error",{event:"on:error",error:new Error(x.error),task:l,cwd:t})}return f.has("post:generate")&&await f.execute("post:generate",{event:"post:generate",task:l,content:j,cwd:t}),{files:v,content:j,outputType:u,tokensUsed:g,inputTokens:M,outputTokens:P,healResult:x}}async function*er(r){let{task:e,cwd:t,overwrite:o=!1,dryRun:n=!1,provider:s="claude-code",model:i,apiKey:c,context7:a=!0,interactive:p=!0}=r,l=e;if(f.has("pre:prompt")){let y=await f.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(y.blocked){yield{type:"error",error:y.message||"Blocked by pre:prompt hook"};return}y.modified?.task&&(l=String(y.modified.task))}if(f.has("pre:generate")){let y=await f.execute("pre:generate",{event:"pre:generate",task:l,cwd:t});if(y.blocked){yield{type:"error",error:y.message||"Blocked by pre:generate hook"};return}}let d=await mt(t,l,{provider:s,context7:{enabled:a,apiKey:c}}),u=Pe(r.outputType,l);yield{type:"context_ready",outputType:u};let m=_e(d.skills,l,u),I=ft(d,u,m.map(y=>y.skill));if(!await we(c)){yield{type:"error",error:"No credentials configured. Run `agentx model` to set up."};return}let E=ve(s,c,r.providerOpts||{}),C=i||Q()?.model,B=Oe(E),G=r.maxSteps??(B?20:5),F=[...r.sessionMessages||[],{role:"user",content:l}];if(B){let y=new he,S,k,H;if(r.mcpServers&&Object.keys(r.mcpServers).length>0)try{H=await He(r.mcpServers)}catch(w){yield{type:"error",error:`MCP pool startup failed: ${w.message}`};return}let ie=(async()=>{try{S=await Ae({provider:E,systemPrompt:I,messages:[{role:"system",content:I},...F],providerOptions:{model:C,maxTokens:8192},cwd:t,maxIterations:G,abortSignal:r.abortSignal,enabledTools:d.config.agentic.enabledTools.filter(w=>!d.config.agentic.disabledTools.includes(w)),interactive:p,overwrite:o,dryRun:n,acmeContext:r.acmeContext,mcpTools:H?.tools,mcpDispatch:H?H.dispatch.bind(H):void 0,onProgress:w=>{w.type==="text_delta"&&y.push({type:"text_delta",text:w.text}),w.type==="thinking_delta"&&y.push({type:"thinking_delta",text:w.text}),w.type==="iteration_start"&&y.push({type:"iteration",iteration:w.iteration}),w.type==="tool_call"&&y.push({type:"tool_call",name:w.name,id:w.id}),w.type==="tool_result"&&y.push({type:"tool_result",name:w.name,id:w.id,is_error:w.is_error}),w.type==="files_created"&&y.push({type:"step_complete",step:0,filesCount:w.files.length})}})}catch(w){k=w}finally{H?.close(),y.close()}})();for await(let w of y)yield w;if(await ie,k){yield{type:"error",error:k instanceof Error?k.message:String(k)};return}if(!S){yield{type:"error",error:"Agentic loop failed without a result"};return}yield{type:"done",result:{content:S.content,files:S.files,tokensUsed:S.tokensUsed,followUp:S.followUp}};let{content:L}=S;if(f.has("post:response")){let w=await f.execute("post:response",{event:"post:response",content:L,task:l,cwd:t});if(w.blocked){yield{type:"error",error:w.message||"Blocked by post:response hook"};return}w.modified?.content&&(L=String(w.modified.content))}if(S.followUp&&p){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:L,outputType:u,followUp:S.followUp,tokensUsed:S.tokensUsed,inputTokens:S.inputTokens,outputTokens:S.outputTokens}};return}let ae=new Map;for(let w of S.files)ae.set(w.path,w);let De=fe(u,d.techStack,r.outputDir),z=await me(Array.from(ae.values()),{cwd:t,overwrite:o,dryRun:n,outputDir:De}),J;if(r.heal!==!1&&!n&&z.written.length>0){let{HealEngine:w}=await import("./heal-RGM7X2ZG.js");J=await new w(t,{enabled:!0,testCommand:r.healConfig?.testCommand,buildCommand:r.healConfig?.buildCommand,lintCommand:r.healConfig?.lintCommand,maxAttempts:r.healConfig?.maxAttempts??3,provider:s,model:C,apiKey:c}).detectAndHeal(z.written,l)}f.has("post:generate")&&await f.execute("post:generate",{event:"post:generate",task:l,content:L,cwd:t}),yield{type:"generate_result",result:{files:z,content:L,outputType:u,tokensUsed:S.tokensUsed,inputTokens:S.inputTokens,outputTokens:S.outputTokens,healResult:J}};return}let A=[{role:"system",content:I},...F],O=[],j=0,_="",g,M=0;M++,b.step(M,`Starting generation (model: ${C||"default"})`);let P;if(E.stream){let y="",S;for await(let k of E.stream(A,{model:C,maxTokens:8192}))yield k,k.type==="text_delta"&&(y+=k.text),k.type==="done"&&(S=k.result);P=S||{content:y,files:[],tokensUsed:0}}else{let y=await E.generate(A,{model:C,maxTokens:8192});y.content&&(yield{type:"text_delta",text:y.content}),yield{type:"done",result:y},P=y}j+=P.tokensUsed||0,_=P.content;let T=P.tokensUsed||0,U=C||"claude-sonnet-4-20250514",v=Math.round(T*.3),x=T-v;if(te.recordStep(M,U,v,x),b.api("generate",U,T),b.step(M,`Generated ${P.files.length} file(s), ${T} tokens`),P.files.length&&O.push(...P.files),P.followUp&&(g=P.followUp),yield{type:"step_complete",step:M,filesCount:P.files.length},!g&&(_.includes("[CONTINUE]")||_.includes("Next, I'll")||_.includes("Now let me")||_.includes("I'll also generate"))&&P.files.length>0){let S=P.files.map(k=>`Created: ${k.path}${k.description?` \u2014 ${k.description}`:""}`).join(`
|
|
69
69
|
`);for(A.push({role:"assistant",content:_+(S?`
|
|
70
70
|
|
|
71
71
|
Files created:
|
|
@@ -73,7 +73,7 @@ ${S}`:"")}),A.push({role:"user",content:"Continue generating the remaining files
|
|
|
73
73
|
`);A.push({role:"assistant",content:k.content+(z?`
|
|
74
74
|
|
|
75
75
|
Files created:
|
|
76
|
-
${z}`:"")}),A.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(f.has("post:response")){let y=await f.execute("post:response",{event:"post:response",content:_,task:l,cwd:t});if(y.blocked){yield{type:"error",error:y.message||"Blocked by post:response hook"};return}y.modified?.content&&(_=String(y.modified.content))}if(g&&p){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:_,outputType:u,followUp:g,tokensUsed:j}};return}let h=new Map;for(let y of O)h.set(y.path,y);let V=fe(u,d.techStack,r.outputDir),Y=await me(Array.from(h.values()),{cwd:t,overwrite:o,dryRun:n,outputDir:V}),X;if(r.heal!==!1&&!n&&Y.written.length>0){let{HealEngine:y}=await import("./heal-
|
|
76
|
+
${z}`:"")}),A.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(f.has("post:response")){let y=await f.execute("post:response",{event:"post:response",content:_,task:l,cwd:t});if(y.blocked){yield{type:"error",error:y.message||"Blocked by post:response hook"};return}y.modified?.content&&(_=String(y.modified.content))}if(g&&p){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:_,outputType:u,followUp:g,tokensUsed:j}};return}let h=new Map;for(let y of O)h.set(y.path,y);let V=fe(u,d.techStack,r.outputDir),Y=await me(Array.from(h.values()),{cwd:t,overwrite:o,dryRun:n,outputDir:V}),X;if(r.heal!==!1&&!n&&Y.written.length>0){let{HealEngine:y}=await import("./heal-RGM7X2ZG.js");X=await new y(t,{enabled:!0,testCommand:r.healConfig?.testCommand,buildCommand:r.healConfig?.buildCommand,lintCommand:r.healConfig?.lintCommand,maxAttempts:r.healConfig?.maxAttempts??3,provider:s,model:C,apiKey:c}).detectAndHeal(Y.written,l),!X.healed&&X.error&&await f.execute("on:error",{event:"on:error",error:new Error(X.error),task:l,cwd:t})}f.has("post:generate")&&await f.execute("post:generate",{event:"post:generate",task:l,content:_,cwd:t}),yield{type:"generate_result",result:{files:Y,content:_,outputType:u,tokensUsed:j,healResult:X}}}function ft(r,e,t){let o=[];o.push(`You are agentx, an agentic code generation tool. You generate high-quality, production-ready output for any tech stack.
|
|
77
77
|
|
|
78
78
|
Your primary tool is \`create_files\` \u2014 use it to output all generated code, documents, and configs as files.
|
|
79
79
|
If the request is ambiguous or you need critical information to proceed correctly, use \`ask_user\` to ask a clarifying question.
|
|
@@ -123,4 +123,4 @@ ${r.projectInstructions}`),r.memoryContext&&o.push(r.memoryContext),o.push(`# Ou
|
|
|
123
123
|
Generate output appropriate for: ${e}. Use the \`create_files\` tool to output all files.`),o.join(`
|
|
124
124
|
|
|
125
125
|
`)}export{qe as a,Vt as b,Yt as c,We as d,ze as e,Ve as f,Ye as g,Pe as h,ee as i,Re as j,le as k,te as l,Tt as m,oe as n,Mt as o,f as p,et as q,tt as r,Me as s,de as t,W as u,ne as v,it as w,Ee as x,$e as y,se as z,mt as A,Zn as B,er as C};
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-MWYPW5XP.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{B as k,D as O,G as I,q as R,t as x,z as N}from"./chunk-
|
|
1
|
+
import{B as k,D as O,G as I,q as R,t as x,z as N}from"./chunk-MOCDP7Q3.js";import{a as E}from"./chunk-OSH2PEBH.js";import{La as j,Ua as F}from"./chunk-5VPU5FHB.js";F();import{Command as X}from"commander";import f from"chalk";import{execFileSync as m}from"child_process";import{accessSync as W,constants as M,existsSync as w,readFileSync as b,readdirSync as C,statSync as B}from"fs";import{join as H,resolve as y}from"path";import{homedir as z}from"os";import{createRequire as G}from"module";var T="Open System Settings \u203A Notifications \u203A AgentX Helper, turn on Allow notifications and choose Banners.";async function P(t={}){let n=t.helper===void 0?N():t.helper,e=k({},{platform:t.platform,io:{capture:t.run,helper:n}}).banner;if(!e)return{state:"unsupported",message:"Desktop banners are only shown on a Mac."};let i=await e.status();return i==="missing"?{state:"missing",message:"AgentX Helper is not installed, so banners come from Script Editor and show its icon.",fix:'Run agentx desktop install, then run agentx notify "Hello" --title "Test" and click Allow.'}:i==="outdated"?{state:"outdated",path:n,message:"AgentX Helper is too old to report whether it may notify.",fix:"Run agentx desktop install to update it."}:i==="not-asked"?{state:"not-asked",path:n,message:"macOS has not asked yet whether AgentX Helper may notify; banners show the Script Editor icon until it does.",fix:'Run agentx notify "Hello" --title "Test" and click Allow when macOS asks.'}:i==="not-allowed"?{state:"not-allowed",path:n,message:"macOS does not allow AgentX Helper to notify, so banners show the Script Editor icon.",fix:T}:i==="hidden"?{state:"hidden",path:n,message:"AgentX Helper may notify, but its banner style is None, so nothing appears on screen.",fix:T}:{state:"ready",path:n,message:"AgentX Helper posts banners with the AgentX icon."}}async function Z(t={}){let n=[];await Q(n),Y(n);let e=ee(n);return e&&te(n,e),e&&se(n,e),e&&re(n,e),e&&ae(n,e),e&&ie(n,e),e&&ce(n,e),e&&await J(n,e),e&&U(n,e),e&&await K(n,e),e&&V(n,e),t.running!==!1&&e&&await de(n,e),{checks:n,summary:D(n)}}var Ne=new X().name("doctor").description("pre-flight health check: Node, config, credentials, daemon").option("--no-running","skip the live daemon probe").option("--json","emit machine-readable JSON (stable shape for CI)").action(async t=>{let{checks:n,summary:e}=await Z({running:t.running!==!1});t.json?process.stdout.write(JSON.stringify({checks:n,summary:e},null,2)+`
|
|
2
2
|
`):ue(n),process.exit(e.errors>0?1:0)});async function J(t,n,e=P){if(!O(n.notifications?.local).banner)return;let i=await e();i.state!=="unsupported"&&t.push({severity:i.state==="ready"?"ok":"warn",group:"Notifications",title:i.message,detail:i.path,fix:i.fix})}async function K(t,n,e){let i;try{i=await(e??k(n)).describe()}catch(s){t.push({severity:"warn",group:"Native",title:"Native apps: could not be read",detail:s?.message??String(s)});return}let o=["tasks","notes","banner","sound","focus"].filter(s=>i[s]);t.push({severity:"ok",group:"Native",title:i.os==="none"?"Native apps: none on this machine":`Native apps (${i.os}): ${o.join(", ")||"nothing available"}`,detail:i.problems.join(" ")||void 0})}function V(t,n,e=process.cwd(),i=k(n)){let o=n.native?.mirror;if(!o?.enabled)return;if(!i.tasks){t.push({severity:"warn",group:"Native",title:"Reminders mirror is on, but this machine has no task app",detail:"native.mirror.enabled is set; nothing is mirrored here.",fix:"Turn it on on the machine that holds the owner's cards (the Mac), or set native.mirror.enabled to false here."});return}let s=I(e),a=Object.values(s.items),l=a.filter(g=>g.state==="open").length,u=a.filter(g=>g.state==="failed").length;t.push({severity:s.lastError||u?"warn":"ok",group:"Native",title:`Reminders mirror: ${l} open in "${o.list}"${u?`, ${u} could not be added`:""}`,detail:s.lastError?`Last error ${s.lastError.at}: ${s.lastError.message}`:void 0,fix:s.lastError?"Run remindctl status, and allow Reminders for the app that runs the daemon in System Settings \u203A Privacy & Security \u203A Reminders.":void 0})}function U(t,n,e=process.platform,i=o=>{try{return W(o,M.X_OK),!0}catch{return!1}}){let o=n.reminders;if(!o?.enabled)return;if(e!=="darwin"){t.push({severity:"warn",group:"Reminders",title:"Reminders hand-back unavailable on this machine",detail:"reminders.enabled is set, but Apple Reminders exists only on macOS. The daemon starts without it.",fix:"Set reminders.enabled to false here, or enable it on the Mac node instead."});return}let s=o.command||"remindctl",a=s.includes("/")?i(s)?s:null:x(s,process.env.PATH||"",i);t.push(a?{severity:"ok",group:"Reminders",title:`Watching ${(o.lists||[]).join(", ")} for due reminders`,detail:a}:{severity:"fail",group:"Reminders",title:`${s} not found`,detail:"The daemon reads Apple Reminders through remindctl.",fix:"brew install steipete/tap/remindctl, or set reminders.command to its full path."})}async function Q(t){let n=E(process.versions.node);t.push({severity:n?"ok":"fail",group:"Environment",title:`Node.js ${process.versions.node}`,detail:n?void 0:"AgentX requires Node 22.19 or newer, up to Node 26.",fix:n?void 0:"Install Node 22 (nvm install 22 && nvm use 22)"});let e=l=>{try{return m(process.platform==="win32"?"where":"which",[l],{encoding:"utf-8"}).trim().split(`
|
|
3
3
|
`)[0]}catch{return null}},i=e("npm");t.push({severity:i?"ok":"fail",group:"Environment",title:i?"npm on PATH":"npm not found",detail:i||void 0});let o=e("claude");if(o){let l;try{l=m("claude",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}t.push({severity:"ok",group:"Environment",title:`claude CLI ${l||"installed"}`,detail:o})}else t.push({severity:"warn",group:"Environment",title:"claude CLI not on PATH",detail:"Only required for agents on the claude-code tier.",fix:"See https://docs.anthropic.com/en/docs/claude-code"});let s=e("codex");if(s){let l;try{l=m("codex",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}t.push({severity:"ok",group:"Environment",title:`codex CLI ${l||"installed"}`,detail:s})}else t.push({severity:"warn",group:"Environment",title:"codex CLI not on PATH",detail:"Only required for agents on the codex-cli tier.",fix:"Install with `npm i -g @openai/codex`."});let a=e("opencode");if(a){let l;try{l=m("opencode",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}t.push({severity:"ok",group:"Environment",title:`opencode CLI ${l||"installed"}`,detail:a})}else t.push({severity:"warn",group:"Environment",title:"opencode CLI not on PATH",detail:"Only required for agents on the opencode tier.",fix:"Install from https://opencode.ai/docs/."});try{G(import.meta.url)("better-sqlite3"),t.push({severity:"ok",group:"Environment",title:`better-sqlite3 loads for Node ${process.version}`,detail:`NODE_MODULE_VERSION ${process.versions.modules}`})}catch(l){t.push({severity:"fail",group:"Environment",title:"better-sqlite3 native binding does not load",detail:l?.message??String(l),fix:`Run "pnpm rebuild better-sqlite3" with the same Node used by the daemon (${process.version}, modules ${process.versions.modules}).`})}}function Y(t){if(process.platform!=="darwin")return;let n=H(z(),"Library/LaunchAgents"),e=[];try{e=C(n).filter(o=>/agentx\.voice.*\.plist$/.test(o))}catch{return}let i=o=>{try{return W(o,M.X_OK),!0}catch{return!1}};for(let o of e){let s=R(b(H(n,o),"utf-8")),a=x("ffmpeg",s,i);t.push(a?{severity:"ok",group:"Desktop",title:"ffmpeg reachable by the desktop app",detail:`${a} (${o})`}:{severity:"warn",group:"Desktop",title:"ffmpeg not reachable by the desktop app",detail:`Local Whisper transcription fails without it. ${o} sets PATH to ${s}.`,fix:"Install ffmpeg (brew install ffmpeg), then rerun agentx desktop install."})}}function ee(t){let n=y(process.cwd(),"agentx.json");if(!w(n))return t.push({severity:"fail",group:"Config",title:"agentx.json not found",detail:`Looked in ${n}`,fix:"Run `agentx setup` to create one via the web wizard."}),null;let e;try{e=JSON.parse(b(n,"utf-8"))}catch(a){return t.push({severity:"fail",group:"Config",title:"agentx.json is not valid JSON",detail:a.message}),null}try{j(n),t.push({severity:"ok",group:"Config",title:`agentx.json valid (${Object.keys(e.agents||{}).length} agents, ${Object.keys(e.crons||{}).length} schedules)`})}catch(a){t.push({severity:"fail",group:"Config",title:"agentx.json failed schema validation",detail:a.message,fix:"Open /admin \u2192 Advanced tab to edit and re-save."})}let i=Object.entries(e.agents||{}).filter(([,a])=>a.tier==="claude-code");i.length>0&&((()=>{try{return m(process.platform==="win32"?"where":"which",["claude"],{stdio:"ignore"}),!0}catch{return!1}})()||t.push({severity:"fail",group:"Config",title:`${i.length} agent(s) use claude-code tier but claude CLI is missing`,detail:i.map(([l])=>l).join(", "),fix:"Install Claude Code (https://docs.anthropic.com/en/docs/claude-code) or switch these agents to tier=sdk."}));let o=Object.entries(e.agents||{}).filter(([,a])=>a.tier==="codex-cli");o.length>0&&((()=>{try{return m(process.platform==="win32"?"where":"which",["codex"],{stdio:"ignore"}),!0}catch{return!1}})()||t.push({severity:"fail",group:"Config",title:`${o.length} agent(s) use codex-cli tier but codex CLI is missing`,detail:o.map(([l])=>l).join(", "),fix:"Install Codex CLI with `npm i -g @openai/codex` or switch these agents to tier=claude-code."}));let s=Object.entries(e.agents||{}).filter(([,a])=>a.tier==="opencode");return s.length>0&&((()=>{try{return m(process.platform==="win32"?"where":"which",["opencode"],{stdio:"ignore"}),!0}catch{return!1}})()||t.push({severity:"fail",group:"Config",title:`${s.length} agent(s) use opencode tier but OpenCode CLI is missing`,detail:s.map(([l])=>l).join(", "),fix:"Install OpenCode from https://opencode.ai/docs/ or switch these agents to another tier."})),e}function te(t,n){let e=new Set;if(A(n,e),e.size===0){t.push({severity:"ok",group:"Secrets",title:"No ${VAR} references in agentx.json"});return}let i=_(),o=[],s=[];for(let a of e){let l=process.env[a]??i[a];l===void 0?o.push(a):(!l.trim()||/^["']?\s*["']?$/.test(l))&&s.push(a)}o.length===0&&s.length===0?t.push({severity:"ok",group:"Secrets",title:`${e.size} env reference(s) resolved`}):(o.length>0&&t.push({severity:"fail",group:"Secrets",title:`${o.length} env var(s) referenced in agentx.json but missing`,detail:o.join(", "),fix:`Add to .env \u2014 e.g. ${o[0]}=<value>`}),s.length>0&&t.push({severity:"warn",group:"Secrets",title:`${s.length} env var(s) set but empty`,detail:s.join(", ")}))}function _(){let t=y(process.cwd(),".env"),n={};if(w(t))for(let e of b(t,"utf-8").split(/\r?\n/)){let i=e.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/i);i&&(n[i[1]]=i[2])}return n}function ne(t,n){let e="With a shared token this node cannot tell which peer is calling. For example, closing an approval card forwarded from that peer is refused, and its stop/resume signals are judged as the owner's.",i="Give this pair a token of its own: set the same new value as mesh.peers[].token here and on the peer.",o=[];for(let s of t){let a=(s.token??"").trim();a?n&&a===n&&o.push({severity:"warn",group:"Mesh",title:`mesh peer "${s.name}" uses this node's own MESH_TOKEN`,detail:e,fix:i}):o.push({severity:"warn",group:"Mesh",title:`mesh peer "${s.name}" has no token; calls to it use the shared MESH_TOKEN`,detail:e,fix:i})}return t.length>0&&o.length===0&&o.push({severity:"ok",group:"Mesh",title:`${t.length} mesh peer(s), each with a token of its own`}),o}function ie(t,n){t.push(...oe(n))}function oe(t,n=process.env,e=_()){let i=a=>(n[a]||e[a]||"").trim(),o=a=>typeof a=="string"?a.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/gi,(l,u)=>i(u)):void 0,s=(t.mesh?.peers??[]).filter(a=>typeof a?.name=="string").map(a=>({name:a.name,token:o(a.token)}));return ne(s,i("MESH_TOKEN")||void 0)}function A(t,n){if(typeof t=="string")for(let e of t.matchAll(/\$\{([A-Z_][A-Z0-9_]*)\}/g))n.add(e[1]);else if(Array.isArray(t))for(let e of t)A(e,n);else if(t&&typeof t=="object")for(let e of Object.values(t))A(e,n)}function se(t,n){let e=[];for(let[i,o]of Object.entries(n.agents||{})){if(!o.workspace)continue;let s=o.workspace.startsWith("/")?o.workspace:y(process.cwd(),o.workspace);try{B(s).isDirectory()||e.push(`${i}: ${s} (exists but not a directory)`)}catch{e.push(`${i}: ${s}`)}}e.length===0?t.push({severity:"ok",group:"Workspaces",title:"All agent workspace folders exist"}):t.push({severity:"warn",group:"Workspaces",title:`${e.length} agent workspace(s) missing`,detail:e.join(`
|
|
4
4
|
`),fix:"The daemon will create missing folders on first task, but you won't see CLAUDE.md / skills until you populate them."})}function re(t,n){let e=/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g,i=[];for(let[o,s]of Object.entries(n.agents||{})){if(!s.workspace)continue;let a=s.workspace.startsWith("/")?s.workspace:y(process.cwd(),s.workspace);for(let l of["settings.json","settings.local.json"]){let u=y(a,".claude",l);if(!w(u))continue;let g;try{g=JSON.parse(b(u,"utf-8"))}catch(c){i.push({severity:"fail",agent:o,msg:`${l}: JSON parse error \u2014 ${c.message}`});continue}let $=g.env||{};for(let[c,h]of Object.entries($)){if(typeof h!="string")continue;let p=h.match(e);p&&i.push({severity:"fail",agent:o,msg:`${l} env.${c} contains unexpanded ${[...new Set(p)].join(",")} \u2014 Claude Code does NOT expand \${VAR} in settings.json (use a fully-literal value)`})}let r=$.PATH;if(typeof r=="string"){let c=r.split(":").filter(Boolean);c.includes("/usr/bin")||i.push({severity:"fail",agent:o,msg:`${l} env.PATH missing /usr/bin \u2014 cat/head/sh/which will fail`}),c.includes("/bin")||i.push({severity:"fail",agent:o,msg:`${l} env.PATH missing /bin \u2014 ls/cp/mv will fail`})}let d=g.permissions;if(d&&typeof d=="object"&&"allow"in d){let c=d.allow,h=d.deny;Array.isArray(c)&&c.length===0&&Array.isArray(h)&&h.length>0&&i.push({severity:"warn",agent:o,msg:`${l} permissions.allow is explicitly [] with ${h.length} deny rules \u2014 agent may be locked out (omit the key to use defaults instead)`})}}}if(i.length===0){t.push({severity:"ok",group:"Workspace settings",title:`All ${Object.keys(n.agents||{}).length} agent .claude/settings.json files clean`});return}for(let o of i)t.push({severity:o.severity,group:"Workspace settings",title:`${o.agent}: ${o.msg}`,fix:o.severity==="fail"?"Edit .claude/settings.json \u2014 replace ${VAR} with the literal value or omit the key to inherit.":"Either remove the empty allow list or populate it."})}function ae(t,n){let e=n.webhooks??[],i=[],o=y(process.cwd(),n.workflows?.dir||".agentx/workflows"),s=new Set;try{if(w(o))for(let r of C(o))r.endsWith(".json")&&!r.startsWith("_")&&!r.endsWith(".disabled.json")&&s.add(r.replace(/\.json$/,""))}catch{}let a=new Set(["github","gitlab"]);for(let r of e){if(!r.enabled||!a.has(r.source))continue;!(r.triggers&&Object.keys(r.triggers).length>0)&&!r.defaultWorkflow&&i.push({severity:"warn",title:`webhook "${r.id}" (${r.source} -> ${r.agentId}) has no triggers map; every event-type collapses to the bound agent`,fix:'Add a triggers map: { "issues.opened": "wf-id", "pull_request.synchronize": "wf-id" } \u2014 or set defaultWorkflow.'})}for(let r of e)if(!(!r.enabled||!r.triggers)){for(let[d,c]of Object.entries(r.triggers))s.size>0&&!s.has(c)&&i.push({severity:"fail",title:`webhook "${r.id}".triggers["${d}"] -> "${c}" \u2014 no such workflow under ${n.workflows?.dir||".agentx/workflows"}`,fix:"Create the workflow file or fix the id in agentx.json"});r.defaultWorkflow&&s.size>0&&!s.has(r.defaultWorkflow)&&i.push({severity:"fail",title:`webhook "${r.id}".defaultWorkflow -> "${r.defaultWorkflow}" \u2014 no such workflow`,fix:"Create the workflow file or fix the id in agentx.json"})}try{if(w(o)){for(let r of C(o))if(!(!r.endsWith(".json")||r.startsWith("_")||r.endsWith(".disabled.json")))try{let d=JSON.parse(b(y(o,r),"utf-8"));d?.status==="active"&&d?.state==="quarantined"&&i.push({severity:"warn",title:`workflow "${d.id??r}" is status=active but state=quarantined \u2014 it looks live but will never dispatch`,fix:'Resolve the conflict the detector flagged, then set state back to "active" (or set status to "review" while parked).'})}catch{}}}catch{}let l=new Set((n.mesh?.peers??[]).map(r=>r.name));for(let r of e)!r.enabled||!r.node||l.has(r.node)||i.push({severity:"fail",title:`webhook "${r.id}" routes to mesh peer "${r.node}" which is not in mesh.peers`,fix:"Add the peer to mesh.peers or remove the node field on the webhook."});let u=new Map;for(let r of e){if(!r.enabled)continue;let d=`${r.source}:${r.agentId}`,c=u.get(d);c?i.push({severity:"warn",title:`webhook entries "${c}" and "${r.id}" both enabled for ${r.source} -> ${r.agentId}; only the first is dispatched`,fix:"Disable one entry, or merge their triggers maps into a single entry."}):u.set(d,r.id)}let g=new Set(Object.keys(n.agents??{}));for(let r of n.channels?.gitlab?.agentMappings??[])if(r?.agentId){if(r.node){l.has(r.node)||i.push({severity:"fail",title:`gitlab.agentMappings entry agentId="${r.agentId}" routes to mesh peer "${r.node}" which is not in mesh.peers`,fix:"Add the peer to mesh.peers or drop the node field on the mapping."});continue}g.has(r.agentId)||i.push({severity:"warn",title:`gitlab.agentMappings entry agentId="${r.agentId}" \u2014 no such agent in agents.* (and no node field, so it's not a cross-mesh route)`,fix:'Add the agent to agents.*, set node:"<peer>" if the agent lives remotely, or remove the mapping.'})}for(let[r,d]of Object.entries(n.channels?.telegram?.accounts??{}))d.agentBinding?g.has(d.agentBinding)||i.push({severity:"fail",title:`telegram account "${r}".agentBinding -> "${d.agentBinding}" \u2014 no such agent in agents.*`,fix:"Fix the agentBinding or define the agent in agents.*."}):i.push({severity:"fail",title:`telegram account "${r}" has no agentBinding; every DM to this bot will drop`,fix:"Set agentBinding to a valid agent id."});let $=new Set(["telegram-bot","whatsapp","slack-bot","discord-bot","gitlab-user","github-user","gmail","hotmail","smtp","hubspot","salesforce","pipedrive","odoo","trello","linear","asana","jira","notion","stripe","sentry","vercel","twilio","custom"]);for(let[r,d]of Object.entries(n.agents??{})){let c=d.integrations??[];if(!c.length)continue;let h=new Set;for(let p of c){let S=`${p.kind}::${p.label}`;h.has(S)&&i.push({severity:"warn",title:`agents.${r}.integrations: duplicate (${p.kind}, ${p.label})`,fix:"Remove the duplicate or rename one. (kind, label) must be unique per agent."}),h.add(S),$.has(p.kind)||i.push({severity:"warn",title:`agents.${r}.integrations: unknown kind "${p.kind}" on integration "${p.label}"`,fix:'Use a canonical kind from INTEGRATION_KINDS, or "custom" for ad-hoc services.'});let L=p.credentials||{};for(let[q,v]of Object.entries(L))typeof v=="string"&&/^[A-Z][A-Z0-9_]*$/.test(v)&&!process.env[v]&&i.push({severity:"warn",title:`agents.${r}.integrations[${p.kind}/${p.label}].${q} -> $${v} but env var is unset (in this shell)`,fix:`Set ${v} on the daemon environment. The daemon's process.env is what matters; this warning fires from your local shell.`})}}if(i.length===0){t.push({severity:"ok",group:"Routing",title:`${e.length} webhook(s), ${Object.keys(n.channels?.telegram?.accounts??{}).length} telegram account(s) \u2014 all routing references resolve`});return}for(let r of i)t.push({severity:r.severity,group:"Routing",title:r.title,fix:r.fix})}function le(t){return typeof t?.canMeasure!="boolean"?null:t.canMeasure?{severity:"ok",group:"Runtime",title:"Daemon finds ffmpeg to measure phone recordings"}:{severity:"warn",group:"Runtime",title:t.allowUnmeasured?"Daemon can't find ffmpeg: phone recordings go unmeasured (voice.allowUnmeasured)":"Daemon can't find ffmpeg: phone voice input is refused",fix:"Install ffmpeg (brew install ffmpeg / sudo apt install ffmpeg), or set AGENTX_FFMPEG in the service's environment. The daemon's PATH is shorter than your shell's."}}async function de(t,n){let e=n.dashboard?.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800",i={};n.dashboard?.token&&(i.Authorization=`Bearer ${n.dashboard.token}`);try{let o=new AbortController,s=setTimeout(()=>o.abort(),2e3),a=await fetch(e+"/health",{headers:i,signal:o.signal});if(clearTimeout(s),!a.ok){t.push({severity:"warn",group:"Runtime",title:`Daemon responded ${a.status}`,detail:e});return}let l=await a.json();t.push({severity:"ok",group:"Runtime",title:`Daemon healthy \u2014 ${l.agents?.length??0} agents live, uptime ${Math.round((l.uptime??0)/60)}m`,detail:e});let u=le(l.voice);u&&t.push(u)}catch{t.push({severity:"warn",group:"Runtime",title:"Daemon not reachable (not running?)",detail:e,fix:"Run `agentx daemon start`. Skip this check with `agentx doctor --no-running`."})}}function ce(t,n){let e=Object.entries(n.agents||{}).filter(([,o])=>o?.codegraph===!0&&(o.tier==="claude-code"||o.tier==="codex-cli"));if(e.length===0)return;let i=null;try{i=m(process.platform==="win32"?"where":"which",["codegraph"],{encoding:"utf-8"}).trim().split(`
|
|
5
5
|
`)[0]||null}catch{i=null}if(i){let o;try{o=m("codegraph",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}t.push({severity:"ok",group:"CodeGraph",title:`codegraph CLI ${o||"installed"}`,detail:i})}else t.push({severity:"fail",group:"CodeGraph",title:"codegraph CLI not on PATH",detail:`${e.length} agent(s) have codegraph:true but the binary isn't available.`,fix:"Install with `npm i -g @colbymchenry/codegraph`."});for(let[o,s]of e){if(!s.workspace||!w(s.workspace)){t.push({severity:"warn",group:"CodeGraph",title:`${o}: workspace missing`,detail:`Workspace path ${s.workspace} does not exist \u2014 codegraph will skip this agent.`});continue}let a=y(s.workspace,".codegraph","codegraph.db");w(a)?t.push({severity:"ok",group:"CodeGraph",title:`${o}: index present`,detail:a}):t.push({severity:"warn",group:"CodeGraph",title:`${o}: index not built yet`,detail:".codegraph/ missing \u2014 daemon will background-index this workspace on next boot.",fix:`Run \`codegraph init --index ${s.workspace}\` to build it now.`})}}function D(t){return{errors:t.filter(n=>n.severity==="fail").length,warnings:t.filter(n=>n.severity==="warn").length,ok:t.filter(n=>n.severity==="ok").length}}function ue(t){console.log(),console.log(f.bold(" agentx doctor")),console.log();let n=new Map;for(let i of t)n.has(i.group)||n.set(i.group,[]),n.get(i.group).push(i);for(let[i,o]of n){console.log(f.bold(" "+i));for(let s of o){let a=s.severity==="ok"?f.green("\u2713"):s.severity==="warn"?f.yellow("!"):f.red("\u2717");console.log(` ${a} ${s.title}`),s.detail&&console.log(f.dim(" "+s.detail.replace(/\n/g,`
|
|
6
6
|
`))),s.fix&&console.log(f.dim(" \u2192 "+s.fix))}console.log()}let e=D(t);e.errors>0?console.log(f.red.bold(` ${e.errors} error${e.errors===1?"":"s"}`)+(e.warnings?f.yellow(`, ${e.warnings} warning${e.warnings===1?"":"s"}`):"")+`. Fix the error${e.errors===1?"":"s"} and rerun.`):e.warnings>0?console.log(f.yellow.bold(` ${e.warnings} warning${e.warnings===1?"":"s"}.`)+f.dim(" Review but not blocking.")):console.log(f.green.bold(` All checks passed (${e.ok}).`)),console.log()}export{P as a,Z as b,Ne as c,J as d,K as e,V as f,U as g,ne as h,oe as i,le as j};
|
|
7
|
-
//# sourceMappingURL=chunk-
|
|
7
|
+
//# sourceMappingURL=chunk-P24P43ZB.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as x,p as A}from"./chunk-24QMHUU2.js";import{a as w,e as D}from"./chunk-2QNT5JDS.js";D();var h="guest:",b="guests",P=7,y=365,T=400;function I(e){let t=e.scopes.find(n=>n.startsWith(h));return t?t.slice(h.length):null}function _(e){return`g-${e.toString(36)}-${Math.random().toString(36).slice(2,6)}`}var l=e=>(Array.isArray(e)?e:typeof e=="string"?e.split(","):[]).map(t=>String(t).trim()).filter(Boolean).slice(0,50);function M(e,t){let n=(e.now??Date.now)(),o=String(t.name??"").trim().slice(0,120),s=String(t.guest??"").trim().slice(0,80);if(!o)return{ok:!1,error:'name is required: what you call this grant, e.g. "Support session for company X"'};if(!s)return{ok:!1,error:"guest is required: the other organisation's name"};if(!t.agentId||!e.hasAgent(t.agentId))return{ok:!1,error:`agent must be an agent on this node, got "${t.agentId??""}"`};let a=w.safeParse(t.level??"propose");if(!a.success)return{ok:!1,error:"level must be report, propose or act"};let r=t.days===void 0?P:Number(t.days);if(!Number.isFinite(r)||r<1||r>y)return{ok:!1,error:`days must be between 1 and ${y}`};let d=_(n),{token:u,record:g}=e.tokens.create({name:`guest ${s} (${o})`,scopes:[`${h}${d}`],expiresInDays:Math.ceil(r)}),{code:i,expiresAt:p}=e.codes.create({token:u,tokenId:g.id,name:d}),c={id:d,name:o,guest:s,agentId:t.agentId,folders:l(t.folders),skills:l(t.skills),commands:l(t.commands),level:a.data,state:"pending",tokenId:g.id,createdAt:new Date(n).toISOString(),expiresAt:new Date(n+r*864e5).toISOString(),usage:{turns:0,tokens:0}};return e.guests.add(c),e.guests.log({grant:d,event:"invited",detail:`${s}: ${o}`}),{ok:!0,code:i,codeExpiresAt:p,grant:c}}var j="That code didn't work. Ask the host for a new one.";async function Y(e,t,n){let o=Date.now(),s=n.now??Date.now,a=n.log??(f=>console.log(f)),r=n.limiter.retryAfter(t);if(r>0)return a(`[guests] join refused from ${t}: locked out for ${r}s more`),{status:429,body:{error:"too many attempts",retryAfter:r},retryAfter:r};let d=n.codes.redeem(e.code),u=d?n.tokens.verify(d.token):null,g=u?I(u):null,i=g?n.guests.get(g):null;if(await L(o,n.minMs??T),!d||!u||!i||i.tokenId!==u.id||i.state==="ended")return n.limiter.fail(t),a(`[guests] join failed from ${t}`),{status:401,body:{error:j}};n.limiter.succeed(t);let p=e.node&&typeof e.node=="object"?e.node:{},c=(f,S)=>typeof f=="string"&&f.trim()?f.replace(/\s+/g," ").trim().slice(0,S):void 0,m={id:c(p.id,80),name:c(p.name,80),address:t},$=i.expiresAt.slice(0,10),k=A(n.root,{title:`Guest mesh: ${i.guest} wants to join`,ask:`Let "${m.name??m.id??"a node"}" at ${t} use ${i.agentId} inside "${i.name}" (${i.level}, until ${$})?`,recommend:`Yes if ${i.guest} told you they are joining now. No if you did not expect it.`,if_silent:"discard",raised_by:b},{now:s()});return k.ok?(n.guests.update(i.id,{guestNode:m,cardId:k.card.id}),n.guests.log({grant:i.id,event:"joined",address:t,detail:m.name??m.id}),a(`[guests] ${i.id}: ${i.guest} joined from ${t}; waiting for the owner (card ${k.card.id})`),{status:200,body:{grant:i.id,name:i.name,agentId:i.agentId,level:i.level,expiresAt:i.expiresAt,state:"pending"},token:d.token}):(a(`[guests] ${i.id}: join from ${t} could not raise a card: ${k.error}`),{status:403,body:{error:"The host cannot take a join right now. Try again later."}})}var G="no grant opens this",R="waiting for the host to approve the join",O="the host paused this grant";function N(e,t){let n=e.now??Date.now,o=e.log??(r=>console.log(r));if(t.state==="ended")return t;if(Date.parse(t.expiresAt)<=n())return o(`[guests] ${t.id}: expired`),v({tokens:e.tokens,guests:e.guests,now:n},t.id,"expired")??t;if(t.state!=="pending")return t;let s=t.cardId?x(e.root,t.cardId):null,a=s?s.status==="decided"?s.verdict:s.status==="expired"?"no":null:null;if(a==="yes"){let r=e.guests.update(t.id,{state:"active",approvedAt:new Date(n()).toISOString()})??t;return e.guests.log({grant:t.id,event:"approved",detail:s?.decided_by}),o(`[guests] ${t.id}: join approved`),r}if(a==="no"){let r=s?.status==="expired"?"the host did not answer in time":"the host said no",d=v({tokens:e.tokens,guests:e.guests,now:n},t.id,r)??t;return e.guests.log({grant:t.id,event:"refused",detail:r}),o(`[guests] ${t.id}: join refused: ${r}`),d}return t}function J(e,t){let n=e?t.tokens.verify(e):null,o=n?I(n):null,s=o?t.guests.get(o):null;if(!n||!s||s.tokenId!==n.id)return{ok:!1,status:401,error:G};let a=N(t,s);return a.state==="ended"?{ok:!1,status:401,error:G}:a.state==="pending"?{ok:!1,status:403,error:R,waiting:!0}:a.state==="paused"?{ok:!1,status:403,error:O,paused:!0}:{ok:!0,grant:a}}function C(e){let t=(o,s)=>o.length?o.join(", "):`none named: do not touch ${s} unless the owner's own instructions already allow it for this work`,n=e.level==="report"?"report: read and answer only; change nothing":e.level==="propose"?"propose: you may prepare changes and open a merge request or draft; never merge, deploy or delete":"act: you may act inside the grant without asking";return[`[Guest mesh] You are working for a guest organisation, "${e.guest}", under the grant "${e.name}" that the owner of this node opened.`,`Stay inside it. Folders: ${t(e.folders,"files")}. Skills: ${t(e.skills,"skills")}. Commands: ${t(e.commands,"commands")}. Freedom: ${n}. The grant ends on ${e.expiresAt.slice(0,10)}.`,"Anything outside the grant: say it is not covered and stop. The guest sees only your answers: never reveal other chats, agents, people or files of this node."].join(`
|
|
2
2
|
`)}function q(e,t){return{agentId:e.agentId,message:t,context:{channel:"guest",chatId:`guest:${e.id}`,sender:`guest:${e.guest}`},systemPromptAppend:C(e),...e.level==="act"?{}:{autonomy:e.level}}}function B(e,t){let n=e.guests.get(t);if(!n||n.state!=="active")return null;let o=e.guests.update(t,{state:"paused",pausedAt:new Date((e.now??Date.now)()).toISOString()});return e.guests.log({grant:t,event:"paused"}),o}function U(e,t){let n=e.guests.get(t);if(!n||n.state!=="paused")return null;let o=e.guests.update(t,{state:"active",pausedAt:void 0});return e.guests.log({grant:t,event:"resumed"}),o}function v(e,t,n="ended by the host"){let o=e.guests.get(t);if(!o||o.state==="ended")return null;e.tokens.revoke(o.tokenId);let s=e.guests.update(t,{state:"ended",endedAt:new Date((e.now??Date.now)()).toISOString(),endedReason:n});return e.guests.log({grant:t,event:n==="expired"?"expired":"ended",detail:n}),s}function X(e,t,n){let o=e.guests.get(t);if(!o||o.state==="ended")return{ok:!1,error:`no open grant "${t}"`};let s={};if(n.folders!==void 0&&(s.folders=l(n.folders)),n.skills!==void 0&&(s.skills=l(n.skills)),n.commands!==void 0&&(s.commands=l(n.commands)),n.level!==void 0){let u=w.safeParse(n.level);if(!u.success)return{ok:!1,error:"level must be report, propose or act"};s.level=u.data}if(n.days!==void 0){let u=Number(n.days);if(!Number.isFinite(u)||u<1||u>y)return{ok:!1,error:`days must be between 1 and ${y}`};s.expiresAt=new Date((e.now??Date.now)()+u*864e5).toISOString()}let a=e.guests.update(t,s),r=["report","propose","act"],d=s.level&&r.indexOf(s.level)>r.indexOf(o.level)||s.folders&&s.folders.length>o.folders.length||s.skills&&s.skills.length>o.skills.length||s.commands&&s.commands.length>o.commands.length||s.expiresAt&&s.expiresAt>o.expiresAt;return e.guests.log({grant:t,event:d?"widened":"narrowed",detail:Object.keys(s).join(", ")}),{ok:!0,grant:a}}function W(e){return{grant:e.id,name:e.name,agentId:e.agentId,level:e.level,folders:e.folders,skills:e.skills,commands:e.commands,state:e.state,expiresAt:e.expiresAt,usage:e.usage}}async function L(e,t){let n=e+t-Date.now();n>0&&await new Promise(o=>setTimeout(o,n))}export{h as a,b,P as c,y as d,I as e,_ as f,M as g,j as h,Y as i,G as j,R as k,O as l,N as m,J as n,C as o,q as p,B as q,U as r,v as s,X as t,W as u};
|
|
3
|
-
//# sourceMappingURL=chunk-
|
|
3
|
+
//# sourceMappingURL=chunk-R4R7EYY3.js.map
|