agentix-cli 0.53.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +26 -0
  2. package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +55 -3
  3. package/apps/mac-voice/Sources/AgentXVoice/main.swift +136 -13
  4. package/dist/{App-R62ZQVSF.js → App-4EM7IPB3.js} +2 -2
  5. package/dist/{ChatApp-AS567EFE.js → ChatApp-FYTEEGSU.js} +2 -2
  6. package/dist/{agent-H4NB4BUA.js → agent-RZ46ZB4W.js} +2 -2
  7. package/dist/{board-dashboard-E3MUVNVQ.js → board-dashboard-NRRYCDZW.js} +1097 -215
  8. package/dist/board-dashboard-NRRYCDZW.js.map +1 -0
  9. package/dist/chunk-2D3RYIDU.js +3 -0
  10. package/dist/chunk-2D3RYIDU.js.map +1 -0
  11. package/dist/{chunk-KB7YIM3W.js → chunk-4HEVSWO3.js} +2 -2
  12. package/dist/{chunk-7DPKPBRJ.js → chunk-6AK6WKE5.js} +2 -2
  13. package/dist/{chunk-TH5KNJLA.js → chunk-723K4SAW.js} +2 -2
  14. package/dist/{chunk-OMTRHHZJ.js → chunk-76AHNHWC.js} +44 -45
  15. package/dist/chunk-76AHNHWC.js.map +1 -0
  16. package/dist/{chunk-KJWBQZT7.js → chunk-C3VRBEJ7.js} +2 -2
  17. package/dist/{chunk-C5JXPMTW.js → chunk-CELYD5QW.js} +2 -2
  18. package/dist/{chunk-FSZXY53Z.js → chunk-D3LSPFHK.js} +2 -2
  19. package/dist/chunk-EJ5ISSWW.js +151 -0
  20. package/dist/chunk-EJ5ISSWW.js.map +1 -0
  21. package/dist/{chunk-FS4WBYY3.js → chunk-EZN2YXRY.js} +2 -2
  22. package/dist/{chunk-QU6ZUKAD.js → chunk-GSOL2LW6.js} +2 -2
  23. package/dist/{chunk-7OWXFLAM.js → chunk-JC5Q5MPI.js} +171 -164
  24. package/dist/chunk-JC5Q5MPI.js.map +1 -0
  25. package/dist/{chunk-SABOPOYX.js → chunk-K4RDE6YU.js} +211 -197
  26. package/dist/chunk-K4RDE6YU.js.map +1 -0
  27. package/dist/{ntfy-ZY2NPGBA.js → chunk-KZKDVIOE.js} +3 -3
  28. package/dist/chunk-KZKDVIOE.js.map +1 -0
  29. package/dist/{chunk-VD4TMPJI.js → chunk-LKJSPO3S.js} +2 -2
  30. package/dist/{chunk-NF52Q3TV.js → chunk-M4AG2YNX.js} +2 -2
  31. package/dist/{chunk-WKTFP3SK.js → chunk-NO2HOK4B.js} +2 -2
  32. package/dist/{chunk-KFG6WWFS.js → chunk-O3XG2NVR.js} +18 -18
  33. package/dist/{chunk-KFG6WWFS.js.map → chunk-O3XG2NVR.js.map} +1 -1
  34. package/dist/chunk-QD6IICK7.js +2 -0
  35. package/dist/chunk-QD6IICK7.js.map +1 -0
  36. package/dist/{chunk-PGJL5V6Y.js → chunk-SA23V7WX.js} +2 -2
  37. package/dist/chunk-U4H35SJS.js +15 -0
  38. package/dist/chunk-U4H35SJS.js.map +1 -0
  39. package/dist/chunk-UIVHSYCN.js +29 -0
  40. package/dist/chunk-UIVHSYCN.js.map +1 -0
  41. package/dist/{chunk-6OOK7Y4S.js → chunk-W4YMMWJL.js} +2 -2
  42. package/dist/chunk-WOMQ2VGA.js +5 -0
  43. package/dist/{chunk-OV35MJKS.js.map → chunk-WOMQ2VGA.js.map} +1 -1
  44. package/dist/chunk-WWMFNLKD.js +10 -0
  45. package/dist/chunk-WWMFNLKD.js.map +1 -0
  46. package/dist/chunk-X5C5W3E4.js +3 -0
  47. package/dist/chunk-X5C5W3E4.js.map +1 -0
  48. package/dist/{chunk-CCMM5TP4.js → chunk-XEOAKD5C.js} +2 -2
  49. package/dist/cli.js +1 -1
  50. package/dist/cli.js.map +1 -1
  51. package/dist/client-IA7ZPE56.js +2 -0
  52. package/dist/{compaction-NWPBPWY2.js → compaction-H5U32UU6.js} +2 -2
  53. package/dist/config-HPN2F7LH.js +2 -0
  54. package/dist/config-mutator-7GPTMTVB.js +2 -0
  55. package/dist/doctor-IBWQVQV4.js +2 -0
  56. package/dist/index.d.ts +273 -19
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/memory-extract-F76BE6KA.js +2 -0
  60. package/dist/ntfy-52EXHVMD.js +2 -0
  61. package/dist/program-D5TAPSIH.js +2 -0
  62. package/dist/{promote-DJFMTLRC.js → promote-T4UJROEH.js} +2 -2
  63. package/dist/push-HEDA6P3B.js +2 -0
  64. package/dist/push-HEDA6P3B.js.map +1 -0
  65. package/dist/push-keys-2DTD7YNQ.js +2 -0
  66. package/dist/push-store-LXTYULUF.js +2 -0
  67. package/dist/query-VUJC4Y5O.js +2 -0
  68. package/dist/registry-DX2RI7I7.js +2 -0
  69. package/dist/{request-planner-2H7HCUCZ.js → request-planner-B7DE7VJR.js} +2 -2
  70. package/dist/{review-candidates-U7R64OCS.js → review-candidates-4YJHIBAF.js} +2 -2
  71. package/dist/routing-MZG3UODH.js +2 -0
  72. package/dist/schedule-tool-A4OFQ4YZ.js +2 -0
  73. package/dist/scheduler-RHJW2V4M.js +2 -0
  74. package/dist/scheduler-RHJW2V4M.js.map +1 -0
  75. package/dist/seat-2PEI7JRX.js +2 -0
  76. package/dist/seat-2PEI7JRX.js.map +1 -0
  77. package/dist/{select-XGK27RPP.js → select-4KIUR27O.js} +2 -2
  78. package/dist/{set-enabled-7YGN2FAZ.js → set-enabled-SE7HQKPF.js} +2 -2
  79. package/dist/subscriptions-RYVPHVIV.js +2 -0
  80. package/dist/subscriptions-RYVPHVIV.js.map +1 -0
  81. package/dist/{tool-HKDIZ6I4.js → tool-5VMD7IE4.js} +2 -2
  82. package/dist/wiki-2QFLAH4U.js +2 -0
  83. package/dist/wiki-2QFLAH4U.js.map +1 -0
  84. package/package.json +3 -1
  85. package/dist/board-dashboard-E3MUVNVQ.js.map +0 -1
  86. package/dist/chunk-47EEUZBK.js +0 -15
  87. package/dist/chunk-47EEUZBK.js.map +0 -1
  88. package/dist/chunk-7OWXFLAM.js.map +0 -1
  89. package/dist/chunk-D4HAR3L3.js +0 -28
  90. package/dist/chunk-D4HAR3L3.js.map +0 -1
  91. package/dist/chunk-HRBKSZ34.js +0 -2
  92. package/dist/chunk-HRBKSZ34.js.map +0 -1
  93. package/dist/chunk-IDYP7G7Z.js +0 -150
  94. package/dist/chunk-IDYP7G7Z.js.map +0 -1
  95. package/dist/chunk-OMTRHHZJ.js.map +0 -1
  96. package/dist/chunk-OV35MJKS.js +0 -5
  97. package/dist/chunk-SABOPOYX.js.map +0 -1
  98. package/dist/client-XTQDYMOX.js +0 -2
  99. package/dist/config-3SW4V44Z.js +0 -2
  100. package/dist/config-mutator-H32FXUYJ.js +0 -2
  101. package/dist/doctor-J6RCHFVE.js +0 -2
  102. package/dist/memory-extract-MGGXIZTE.js +0 -2
  103. package/dist/ntfy-ZY2NPGBA.js.map +0 -1
  104. package/dist/program-SQTOPCQW.js +0 -2
  105. package/dist/query-UAZUMU4N.js +0 -2
  106. package/dist/registry-4OUBA2TY.js +0 -2
  107. package/dist/routing-LVQH6WOJ.js +0 -2
  108. package/dist/schedule-tool-2BONJVCJ.js +0 -2
  109. package/dist/scheduler-7CEXDECA.js +0 -2
  110. package/dist/seat-2KGFNCIW.js +0 -2
  111. package/dist/wiki-6YT7B5HU.js +0 -2
  112. /package/dist/{App-R62ZQVSF.js.map → App-4EM7IPB3.js.map} +0 -0
  113. /package/dist/{ChatApp-AS567EFE.js.map → ChatApp-FYTEEGSU.js.map} +0 -0
  114. /package/dist/{agent-H4NB4BUA.js.map → agent-RZ46ZB4W.js.map} +0 -0
  115. /package/dist/{chunk-KB7YIM3W.js.map → chunk-4HEVSWO3.js.map} +0 -0
  116. /package/dist/{chunk-7DPKPBRJ.js.map → chunk-6AK6WKE5.js.map} +0 -0
  117. /package/dist/{chunk-TH5KNJLA.js.map → chunk-723K4SAW.js.map} +0 -0
  118. /package/dist/{chunk-KJWBQZT7.js.map → chunk-C3VRBEJ7.js.map} +0 -0
  119. /package/dist/{chunk-C5JXPMTW.js.map → chunk-CELYD5QW.js.map} +0 -0
  120. /package/dist/{chunk-FSZXY53Z.js.map → chunk-D3LSPFHK.js.map} +0 -0
  121. /package/dist/{chunk-FS4WBYY3.js.map → chunk-EZN2YXRY.js.map} +0 -0
  122. /package/dist/{chunk-QU6ZUKAD.js.map → chunk-GSOL2LW6.js.map} +0 -0
  123. /package/dist/{chunk-VD4TMPJI.js.map → chunk-LKJSPO3S.js.map} +0 -0
  124. /package/dist/{chunk-NF52Q3TV.js.map → chunk-M4AG2YNX.js.map} +0 -0
  125. /package/dist/{chunk-WKTFP3SK.js.map → chunk-NO2HOK4B.js.map} +0 -0
  126. /package/dist/{chunk-PGJL5V6Y.js.map → chunk-SA23V7WX.js.map} +0 -0
  127. /package/dist/{chunk-6OOK7Y4S.js.map → chunk-W4YMMWJL.js.map} +0 -0
  128. /package/dist/{chunk-CCMM5TP4.js.map → chunk-XEOAKD5C.js.map} +0 -0
  129. /package/dist/{client-XTQDYMOX.js.map → client-IA7ZPE56.js.map} +0 -0
  130. /package/dist/{compaction-NWPBPWY2.js.map → compaction-H5U32UU6.js.map} +0 -0
  131. /package/dist/{config-3SW4V44Z.js.map → config-HPN2F7LH.js.map} +0 -0
  132. /package/dist/{config-mutator-H32FXUYJ.js.map → config-mutator-7GPTMTVB.js.map} +0 -0
  133. /package/dist/{doctor-J6RCHFVE.js.map → doctor-IBWQVQV4.js.map} +0 -0
  134. /package/dist/{memory-extract-MGGXIZTE.js.map → memory-extract-F76BE6KA.js.map} +0 -0
  135. /package/dist/{program-SQTOPCQW.js.map → ntfy-52EXHVMD.js.map} +0 -0
  136. /package/dist/{promote-DJFMTLRC.js.map → program-D5TAPSIH.js.map} +0 -0
  137. /package/dist/{query-UAZUMU4N.js.map → promote-T4UJROEH.js.map} +0 -0
  138. /package/dist/{registry-4OUBA2TY.js.map → push-keys-2DTD7YNQ.js.map} +0 -0
  139. /package/dist/{routing-LVQH6WOJ.js.map → push-store-LXTYULUF.js.map} +0 -0
  140. /package/dist/{schedule-tool-2BONJVCJ.js.map → query-VUJC4Y5O.js.map} +0 -0
  141. /package/dist/{scheduler-7CEXDECA.js.map → registry-DX2RI7I7.js.map} +0 -0
  142. /package/dist/{request-planner-2H7HCUCZ.js.map → request-planner-B7DE7VJR.js.map} +0 -0
  143. /package/dist/{review-candidates-U7R64OCS.js.map → review-candidates-4YJHIBAF.js.map} +0 -0
  144. /package/dist/{seat-2KGFNCIW.js.map → routing-MZG3UODH.js.map} +0 -0
  145. /package/dist/{wiki-6YT7B5HU.js.map → schedule-tool-A4OFQ4YZ.js.map} +0 -0
  146. /package/dist/{select-XGK27RPP.js.map → select-4KIUR27O.js.map} +0 -0
  147. /package/dist/{set-enabled-7YGN2FAZ.js.map → set-enabled-SE7HQKPF.js.map} +0 -0
  148. /package/dist/{tool-HKDIZ6I4.js.map → tool-5VMD7IE4.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{q as _,r as W}from"./chunk-2AXFYDWF.js";import{b as Y,c as I,d as O}from"./chunk-AQASR6KR.js";import{b as F}from"./chunk-DP7RTNDM.js";import{e as E}from"./chunk-KJWBQZT7.js";import{b as L}from"./chunk-64P4QHSZ.js";import{createHash as ee}from"crypto";import{existsSync as H,readdirSync as te,readFileSync as re,writeFileSync as ne}from"fs";import{resolve as P}from"path";function be(n,r,s,t,o,i,c=""){return Z(r,s,t,o,i,c)}function Z(n,r,s,t,o,i=""){let c=r?`
1
+ import{q as _,r as W}from"./chunk-2AXFYDWF.js";import{b as Y,c as I,d as O}from"./chunk-AQASR6KR.js";import{b as F}from"./chunk-DP7RTNDM.js";import{e as E}from"./chunk-C3VRBEJ7.js";import{b as L}from"./chunk-64P4QHSZ.js";import{createHash as ee}from"crypto";import{existsSync as H,readdirSync as te,readFileSync as re,writeFileSync as ne}from"fs";import{resolve as P}from"path";function be(n,r,s,t,o,i,c=""){return Z(r,s,t,o,i,c)}function Z(n,r,s,t,o,i=""){let c=r?`
2
2
  ## Worldview
3
3
 
4
4
  ${r}
@@ -240,4 +240,4 @@ ${g}`}var x="memory-promoter",oe=["project","reference","feedback"],K="_memory-p
240
240
  Re-emit the FULL corrected JSON object \u2014 same structure, fixed issues, valid JSON only.`:n,y=await t(`${a}/task`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agent:r.viaAgent,message:h,freshSession:s===null,context:{channel:"api",chatId:r.chatId??"memory-promote"}}),signal:i.signal});if(!y.ok){let f=await y.text().catch(()=>"");throw new Error(`agent /task ${y.status}: ${f.slice(0,500)}`)}let w=await y.json();if(w.error)throw new Error(`agent reported error: ${w.error}`);let b=String(w.content??"").trim();if(!b)throw new Error("agent returned empty content");return b}if(!r.model)throw new Error("callPromotionLlm: viaAgent or model is required");let p=process.env.ANTHROPIC_API_KEY;if(!p)throw new Error("ANTHROPIC_API_KEY not set; use --via <agentId> instead");let u=[{role:"user",content:n}];s&&(u.push({role:"assistant",content:"(previous attempt; will retry with corrections)"}),u.push({role:"user",content:`Your previous response failed validation: ${s}
241
241
  Re-emit the FULL corrected JSON object.`}));let g=await t(me,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":p,"anthropic-version":ge},body:JSON.stringify({model:r.model,max_tokens:8e3,messages:u}),signal:i.signal});if(!g.ok){let a=await g.text().catch(()=>"");throw new Error(`anthropic API ${g.status}: ${a.slice(0,500)}`)}let l=await g.json(),e=(Array.isArray(l.content)?l.content:[]).filter(a=>a?.type==="text").map(a=>a.text).join(`
242
242
  `).trim();if(!e)throw new Error("anthropic API returned no text content");return e}finally{clearTimeout(c)}}async function Se(n={}){let r=n.wikiDir??P(process.cwd(),".agentx","wiki"),s=n.memoryRoot??P(process.cwd(),".agentx"),t=n.log??(()=>{}),o=n.now??Date.now(),i={candidates:[],clusters:[],proposed:[],skipped:[],gaps:[],warnings:[],errors:[],dryRun:!n.commit},c=new E(r,(...m)=>t(m.map(String).join(" "))),p=c.rebuildIndex(),u=z(r),g=[...ce(s),...n.extraCandidates??[]];if(i.candidates=de(g,p,u,{types:n.types,sinceMs:n.sinceMs,agentFilter:n.agentFilter,now:o,max:n.max}),i.candidates.length===0)return t("no unpromoted memories in window"),i;if(i.clusters=le(i.candidates),i.dryRun)return i;let l=p.articles.map(m=>({title:m.title,path:m.path,type:m.type})),d=c.getWorldview()??"",e=n.budgetTokens??ue,a=i.clusters,h=D(x,a,l,d);for(;R(h)>e&&a.length>1;)a=a.slice(0,-1),h=D(x,a,l,d);if(R(h)>e)return i.errors.push(`judge prompt (~${R(h)} tokens) exceeds the ${e}-token budget even with one cluster`),i;a.length<i.clusters.length&&i.warnings.push(`token budget: judged ${a.length} of ${i.clusters.length} clusters; the rest wait for the next run`);let y=a.flatMap(m=>m.candidates),w=new Set(y.map(m=>m.stamp)),b=n.chatId??`memory-promote-${new Date(o).toISOString().slice(0,10)}`,f=B(await G(h,{...n,chatId:b}),w);if("error"in f&&(t(`parse failed (${f.error}) \u2014 retrying with feedback`),f=B(await G(h,{...n,chatId:b},f.error),w)),"error"in f)return i.errors.push(`LLM response unusable after retry: ${f.error}`),i;i.warnings.push(...f.warnings),i.gaps=f.gaps;let v=new Date(o).toISOString(),k=[],T=new Map(y.map(m=>[m.stamp,m]));for(let m of f.articles){let A=c.readArticle(m.path);if(A&&!c.canWrite(A.meta,x)){i.errors.push(`write denied for "${m.path}" (owned by ${A.meta.owner??"?"})`);continue}let M=fe(m.promotedFrom,T),S={id:Y(o,m.path),createdAt:v,status:"pending",article:m,evidence:M,...A?{replaces:{lastUpdated:A.meta.lastUpdated,contentHash:V(A.content)}}:{}};I(r,S),i.proposed.push({id:S.id,path:m.path,title:m.title,type:m.type,stamps:m.promotedFrom,agents:M.agents,occurrences:M.occurrences});for(let X of m.promotedFrom)k.push({stamp:X,decision:"proposed",article:m.path,proposal:S.id,at:v})}for(let m of f.skipped)k.push({stamp:m.stamp,decision:"skipped",reason:m.reason,at:v}),i.skipped.push(m);return k.length&&C(r,k),i}var ue=6e4;function R(n){return Math.ceil(n.length/4)}function V(n){return ee("sha256").update(n).digest("hex").slice(0,16)}var he=600;function ye(n){return n.startsWith("review:")?"review":n.startsWith(j)?"failure":"memory"}function fe(n,r){let s=[];for(let t of n){let o=r.get(t);o&&s.push({stamp:t,kind:ye(t),agentId:o.agentId,type:o.memory.type,name:o.memory.name,description:o.memory.description,...o.occurrences?{occurrences:o.occurrences}:{},...o.sessions?.length?{sessions:o.sessions}:{},...o.tasks?.length?{tasks:o.tasks}:{},...o.failure?{failure:o.failure}:{},...o.memory.author?{author:o.memory.author}:{},...o.memory.taskId?{taskId:o.memory.taskId}:{},updatedAt:o.memory.updatedAt,excerpt:o.memory.body.slice(0,he)})}return{agents:[...new Set(s.map(t=>t.agentId))].sort(),occurrences:Math.max(1,...s.map(t=>t.occurrences??1)),sources:s}}function Ee(n,r,s={}){let t=O(n,r);if(!t)return{ok:!1,error:`no proposal "${r}"`};if(t.status!=="pending")return{ok:!1,error:`proposal "${r}" is already ${t.status}`};let o=s.log??(()=>{}),i=new E(n,(...a)=>o(a.map(String).join(" "))),{article:c}=t,p=i.readArticle(c.path);if(!s.force){if(p&&!t.replaces)return{ok:!1,error:`"${c.path}" was created after this proposal; review it, then approve with --force`};if(p&&t.replaces&&V(p.content)!==t.replaces.contentHash)return{ok:!1,error:`"${c.path}" changed since this proposal; review it, then approve with --force`}}let u=s.now??Date.now(),g=new Date(u).toISOString().slice(0,10);if(!i.writeArticle(c.path,{title:c.title,type:L(c.type)?c.type:void 0,related:c.related,tags:c.tags,owner:x,access:"public",created:p?.meta.created??g,lastUpdated:g,sources:ae(p?.meta.sources,c.promotedFrom)},c.content,x))return{ok:!1,error:`write denied for "${c.path}" (owned by ${p?.meta.owner??"?"})`};let d=new Date(u).toISOString();C(n,c.promotedFrom.map(a=>({stamp:a,decision:"promoted",article:c.path,proposal:r,at:d}))),i.rebuildIndex();let e={...t,status:"approved",decidedBy:s.by??"operator",decidedAt:d};return I(n,e),{ok:!0,proposal:e}}function Oe(n,r,s={}){let t=O(n,r);if(!t)return{ok:!1,error:`no proposal "${r}"`};if(t.status!=="pending")return{ok:!1,error:`proposal "${r}" is already ${t.status}`};let o=new Date(s.now??Date.now()).toISOString();C(n,t.article.promotedFrom.map(c=>({stamp:c,decision:"rejected",article:t.article.path,proposal:r,reason:s.reason,at:o})));let i={...t,status:"rejected",decidedBy:s.by??"operator",decidedAt:o,...s.reason?{reason:s.reason}:{}};return I(n,i),{ok:!0,proposal:i}}export{be as a,x as b,oe as c,K as d,q as e,ie as f,$ as g,ae as h,ce as i,z as j,C as k,le as l,B as m,de as n,G as o,Se as p,R as q,ye as r,fe as s,Ee as t,Oe as u};
243
- //# sourceMappingURL=chunk-6OOK7Y4S.js.map
243
+ //# sourceMappingURL=chunk-W4YMMWJL.js.map
@@ -0,0 +1,5 @@
1
+ import{n as m,q as b}from"./chunk-U4H35SJS.js";b();function w(t){let e=typeof t.node=="string"?t.node:"",n=typeof t.token=="string"?t.token:"";if(!e||!n)try{let o=m(t.config);e||(e=o.dashboard?.daemonUrl||""),n||(n=o.dashboard?.token||"")}catch{}return e||(e="http://localhost:18800"),{baseUrl:e.replace(/\/+$/,""),token:n}}async function d(t,e,n){let o={Accept:"application/json"};t.token&&(o.Authorization=`Bearer ${t.token}`);let r=await fetch(`${t.baseUrl}${e}`,{headers:o,signal:n});if(!r.ok)throw new Error(`GET ${e} \u2192 HTTP ${r.status}`);return await r.json()}function R(t,e){return d(t,"/agents",e)}async function S(t,e){return(await d(t,"/api/processes",e)).processes??[]}function P(t,e){return d(t,"/crons",e)}async function h(t,e,n,o){let r={Accept:"application/json","Content-Type":"application/json"};t.token&&(r.Authorization=`Bearer ${t.token}`);let s=await fetch(`${t.baseUrl}${e}`,{method:"POST",headers:r,body:JSON.stringify(n),signal:o}),a=await s.text(),i;try{i=a?JSON.parse(a):{}}catch{i={raw:a}}if(!s.ok)throw new Error(i?.error||`POST ${e} \u2192 HTTP ${s.status}`);return i}function A(t,e,n="tui"){return h(t,"/api/processes/kill",{...e,reason:n})}function C(t,e,n,o){return h(t,"/task",{agent:e,message:n,context:o??{channel:"tui",chatId:"tui:operator"}})}async function $(t,e,n,o={}){let r={Accept:"text/event-stream","Content-Type":"application/json"};t.token&&(r.Authorization=`Bearer ${t.token}`);let s=await fetch(`${t.baseUrl}/task`,{method:"POST",headers:r,body:JSON.stringify({agent:e,message:n,stream:!0,context:{channel:o.channel??"chat-cli",chatId:o.chatId??"chat-cli:operator"}}),signal:o.signal});if(!s.ok||!s.body){let g=await s.text().catch(()=>"");throw new Error(`POST /task (stream) \u2192 HTTP ${s.status}${g?`: ${g.slice(0,200)}`:""}`)}let a=s.body.getReader(),i=new TextDecoder,u={content:""},c="";try{for(;;){let{done:g,value:p}=await a.read();if(g)break;c+=i.decode(p,{stream:!0});let l;for(;(l=c.indexOf(`
2
+
3
+ `))>=0;){let k=c.slice(0,l);c=c.slice(l+2);let f=x(k);f&&T(f,o,u)}}}finally{try{a.releaseLock()}catch{}}return u}function T(t,e,n){let{event:o,data:r}=t;switch(o){case"text":r?.text&&(n.content+=r.text,e.onText?.(r.text));break;case"thinking":r?.text&&e.onThinking?.(r.text);break;case"tool":e.onTool?.(r);break;case"done":typeof r?.content=="string"&&(n.content=r.content),n.usage=r?.usage,n.duration=r?.duration;break;case"error":n.error=r?.error,n.errorKind=r?.errorKind;break}}function x(t){let e="message",n="";for(let r of t.split(`
4
+ `))r.startsWith("event: ")?e=r.slice(7).trim():r.startsWith("data: ")&&(n=r.slice(6));if(!n)return null;let o;try{o=JSON.parse(n)}catch{o=n}return{event:e,data:o}}export{w as a,R as b,S as c,P as d,A as e,C as f,$ as g};
5
+ //# sourceMappingURL=chunk-WOMQ2VGA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tui/client.ts"],"sourcesContent":["import { loadDaemonConfig } from \"@/daemon/config\"\n\n// Resolved connection details for the daemon, derived from --node/--token\n// CLI flags first, then daemon config's `dashboard` block, then localhost.\nexport interface DaemonConn {\n baseUrl: string\n token: string\n}\n\nexport function resolveConn(opts: { node?: string; token?: string; config?: string }): DaemonConn {\n let baseUrl = typeof opts.node === \"string\" ? opts.node : \"\"\n let token = typeof opts.token === \"string\" ? opts.token : \"\"\n if (!baseUrl || !token) {\n try {\n const cfg = loadDaemonConfig(opts.config)\n if (!baseUrl) baseUrl = cfg.dashboard?.daemonUrl || \"\"\n if (!token) token = cfg.dashboard?.token || \"\"\n } catch {\n // No config — fall back to localhost.\n }\n }\n if (!baseUrl) baseUrl = \"http://localhost:18800\"\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), token }\n}\n\nasync function get<T>(conn: DaemonConn, path: string, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = { Accept: \"application/json\" }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, { headers, signal })\n if (!res.ok) throw new Error(`GET ${path} → HTTP ${res.status}`)\n return (await res.json()) as T\n}\n\nexport interface AgentRow {\n id: string\n name: string\n tier: string\n model?: string\n workspace: string\n active: number\n total: number\n errors: number\n lastActive?: string\n}\n\nexport interface ProcessRow {\n key: { agentId: string; channel: string; chatId: string }\n pid: number | null\n state: string\n spawnedAt: number\n lastTurnAt: number\n turnCount: number\n}\n\nexport interface CronRow {\n id: string\n enabled: boolean\n schedule: string\n agent: string\n nextRun?: string\n lastError?: string\n consecutiveErrors: number\n}\n\nexport function fetchAgents(conn: DaemonConn, signal?: AbortSignal): Promise<AgentRow[]> {\n return get<AgentRow[]>(conn, \"/agents\", signal)\n}\n\nexport async function fetchProcesses(conn: DaemonConn, signal?: AbortSignal): Promise<ProcessRow[]> {\n const r = await get<{ processes: ProcessRow[] }>(conn, \"/api/processes\", signal)\n return r.processes ?? []\n}\n\nexport function fetchCrons(conn: DaemonConn, signal?: AbortSignal): Promise<CronRow[]> {\n return get<CronRow[]>(conn, \"/crons\", signal)\n}\n\nasync function post<T>(conn: DaemonConn, path: string, body: any, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n })\n const text = await res.text()\n let parsed: any\n try { parsed = text ? JSON.parse(text) : {} } catch { parsed = { raw: text } }\n if (!res.ok) throw new Error(parsed?.error || `POST ${path} → HTTP ${res.status}`)\n return parsed as T\n}\n\nexport function killProcess(\n conn: DaemonConn,\n key: { agentId: string; channel: string; chatId: string },\n reason = \"tui\",\n): Promise<{ killed: { agentId: string; channel: string; chatId: string } }> {\n return post(conn, \"/api/processes/kill\", { ...key, reason })\n}\n\nexport interface TaskResponse {\n content?: string\n error?: string\n [k: string]: any\n}\n\nexport function sendTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n context?: { channel?: string; chatId?: string },\n): Promise<TaskResponse> {\n return post<TaskResponse>(conn, \"/task\", {\n agent: agentId,\n message,\n context: context ?? { channel: \"tui\", chatId: \"tui:operator\" },\n })\n}\n\n/** Live task events surfaced to a streaming client. Mirrors the daemon's\n * `POST /task` SSE wire (src/daemon/index.ts): `text` deltas, `thinking`\n * deltas, and `tool` badges (start/result). */\nexport interface StreamTaskHandlers {\n onText?: (text: string) => void\n onThinking?: (text: string) => void\n onTool?: (t: { status: \"start\" | \"result\"; id?: string; name?: string; error?: boolean; arg?: string }) => void\n}\n\nexport interface StreamTaskResult {\n content: string\n usage?: Record<string, number>\n duration?: number\n error?: string\n errorKind?: string\n}\n\n/**\n * Stream a task turn over SSE. POSTs `/task` with `Accept: text/event-stream`,\n * parses `event:/data:` frames, and invokes the handlers as tokens and tool\n * events arrive. Resolves with the final `done` payload (or an `error`).\n * Reuses the same (channel, chatId) warm-process semantics as sendTask.\n */\nexport async function streamTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n opts: { channel?: string; chatId?: string; signal?: AbortSignal } & StreamTaskHandlers = {},\n): Promise<StreamTaskResult> {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n\n const res = await fetch(`${conn.baseUrl}/task`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n agent: agentId,\n message,\n stream: true,\n context: { channel: opts.channel ?? \"chat-cli\", chatId: opts.chatId ?? \"chat-cli:operator\" },\n }),\n signal: opts.signal,\n })\n if (!res.ok || !res.body) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`POST /task (stream) → HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : \"\"}`)\n }\n\n const reader = res.body.getReader()\n const dec = new TextDecoder()\n const result: StreamTaskResult = { content: \"\" }\n let buf = \"\"\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let idx: number\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n const frame = buf.slice(0, idx)\n buf = buf.slice(idx + 2)\n const parsed = parseSseFrame(frame)\n if (!parsed) continue\n applyFrame(parsed, opts, result)\n }\n }\n } finally {\n try { reader.releaseLock() } catch { /* noop */ }\n }\n return result\n}\n\nfunction applyFrame(\n frame: { event: string; data: any },\n handlers: StreamTaskHandlers,\n result: StreamTaskResult,\n): void {\n const { event, data } = frame\n switch (event) {\n case \"text\":\n if (data?.text) { result.content += data.text; handlers.onText?.(data.text) }\n break\n case \"thinking\":\n if (data?.text) handlers.onThinking?.(data.text)\n break\n case \"tool\":\n handlers.onTool?.(data)\n break\n case \"done\":\n if (typeof data?.content === \"string\") result.content = data.content\n result.usage = data?.usage\n result.duration = data?.duration\n break\n case \"error\":\n result.error = data?.error\n result.errorKind = data?.errorKind\n break\n }\n}\n\n/** Parse one `event:/data:` SSE frame. Ignores comment/heartbeat lines. */\nfunction parseSseFrame(frame: string): { event: string; data: any } | null {\n let event = \"message\"\n let data = \"\"\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) event = line.slice(7).trim()\n else if (line.startsWith(\"data: \")) data = line.slice(6)\n }\n if (!data) return null\n let payload: any\n try { payload = JSON.parse(data) } catch { payload = data }\n return { event, data: payload }\n}\n"],"mappings":"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","names":["init_config","resolveConn","opts","baseUrl","token","cfg","loadDaemonConfig","get","conn","path","signal","headers","res","fetchAgents","fetchProcesses","fetchCrons","post","body","text","parsed","killProcess","key","reason","sendTask","agentId","message","context","streamTask","reader","dec","result","buf","done","value","idx","frame","parseSseFrame","applyFrame","handlers","event","data","line","payload"]}
1
+ {"version":3,"sources":["../src/tui/client.ts"],"sourcesContent":["import { loadDaemonConfig } from \"@/daemon/config\"\n\n// Resolved connection details for the daemon, derived from --node/--token\n// CLI flags first, then daemon config's `dashboard` block, then localhost.\nexport interface DaemonConn {\n baseUrl: string\n token: string\n}\n\nexport function resolveConn(opts: { node?: string; token?: string; config?: string }): DaemonConn {\n let baseUrl = typeof opts.node === \"string\" ? opts.node : \"\"\n let token = typeof opts.token === \"string\" ? opts.token : \"\"\n if (!baseUrl || !token) {\n try {\n const cfg = loadDaemonConfig(opts.config)\n if (!baseUrl) baseUrl = cfg.dashboard?.daemonUrl || \"\"\n if (!token) token = cfg.dashboard?.token || \"\"\n } catch {\n // No config — fall back to localhost.\n }\n }\n if (!baseUrl) baseUrl = \"http://localhost:18800\"\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), token }\n}\n\nasync function get<T>(conn: DaemonConn, path: string, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = { Accept: \"application/json\" }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, { headers, signal })\n if (!res.ok) throw new Error(`GET ${path} → HTTP ${res.status}`)\n return (await res.json()) as T\n}\n\nexport interface AgentRow {\n id: string\n name: string\n tier: string\n model?: string\n workspace: string\n active: number\n total: number\n errors: number\n lastActive?: string\n}\n\nexport interface ProcessRow {\n key: { agentId: string; channel: string; chatId: string }\n pid: number | null\n state: string\n spawnedAt: number\n lastTurnAt: number\n turnCount: number\n}\n\nexport interface CronRow {\n id: string\n enabled: boolean\n schedule: string\n agent: string\n nextRun?: string\n lastError?: string\n consecutiveErrors: number\n}\n\nexport function fetchAgents(conn: DaemonConn, signal?: AbortSignal): Promise<AgentRow[]> {\n return get<AgentRow[]>(conn, \"/agents\", signal)\n}\n\nexport async function fetchProcesses(conn: DaemonConn, signal?: AbortSignal): Promise<ProcessRow[]> {\n const r = await get<{ processes: ProcessRow[] }>(conn, \"/api/processes\", signal)\n return r.processes ?? []\n}\n\nexport function fetchCrons(conn: DaemonConn, signal?: AbortSignal): Promise<CronRow[]> {\n return get<CronRow[]>(conn, \"/crons\", signal)\n}\n\nasync function post<T>(conn: DaemonConn, path: string, body: any, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n })\n const text = await res.text()\n let parsed: any\n try { parsed = text ? JSON.parse(text) : {} } catch { parsed = { raw: text } }\n if (!res.ok) throw new Error(parsed?.error || `POST ${path} → HTTP ${res.status}`)\n return parsed as T\n}\n\nexport function killProcess(\n conn: DaemonConn,\n key: { agentId: string; channel: string; chatId: string },\n reason = \"tui\",\n): Promise<{ killed: { agentId: string; channel: string; chatId: string } }> {\n return post(conn, \"/api/processes/kill\", { ...key, reason })\n}\n\nexport interface TaskResponse {\n content?: string\n error?: string\n [k: string]: any\n}\n\nexport function sendTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n context?: { channel?: string; chatId?: string },\n): Promise<TaskResponse> {\n return post<TaskResponse>(conn, \"/task\", {\n agent: agentId,\n message,\n context: context ?? { channel: \"tui\", chatId: \"tui:operator\" },\n })\n}\n\n/** Live task events surfaced to a streaming client. Mirrors the daemon's\n * `POST /task` SSE wire (src/daemon/index.ts): `text` deltas, `thinking`\n * deltas, and `tool` badges (start/result). */\nexport interface StreamTaskHandlers {\n onText?: (text: string) => void\n onThinking?: (text: string) => void\n onTool?: (t: { status: \"start\" | \"result\"; id?: string; name?: string; error?: boolean; arg?: string }) => void\n}\n\nexport interface StreamTaskResult {\n content: string\n usage?: Record<string, number>\n duration?: number\n error?: string\n errorKind?: string\n}\n\n/**\n * Stream a task turn over SSE. POSTs `/task` with `Accept: text/event-stream`,\n * parses `event:/data:` frames, and invokes the handlers as tokens and tool\n * events arrive. Resolves with the final `done` payload (or an `error`).\n * Reuses the same (channel, chatId) warm-process semantics as sendTask.\n */\nexport async function streamTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n opts: { channel?: string; chatId?: string; signal?: AbortSignal } & StreamTaskHandlers = {},\n): Promise<StreamTaskResult> {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n\n const res = await fetch(`${conn.baseUrl}/task`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n agent: agentId,\n message,\n stream: true,\n context: { channel: opts.channel ?? \"chat-cli\", chatId: opts.chatId ?? \"chat-cli:operator\" },\n }),\n signal: opts.signal,\n })\n if (!res.ok || !res.body) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`POST /task (stream) → HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : \"\"}`)\n }\n\n const reader = res.body.getReader()\n const dec = new TextDecoder()\n const result: StreamTaskResult = { content: \"\" }\n let buf = \"\"\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let idx: number\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n const frame = buf.slice(0, idx)\n buf = buf.slice(idx + 2)\n const parsed = parseSseFrame(frame)\n if (!parsed) continue\n applyFrame(parsed, opts, result)\n }\n }\n } finally {\n try { reader.releaseLock() } catch { /* noop */ }\n }\n return result\n}\n\nfunction applyFrame(\n frame: { event: string; data: any },\n handlers: StreamTaskHandlers,\n result: StreamTaskResult,\n): void {\n const { event, data } = frame\n switch (event) {\n case \"text\":\n if (data?.text) { result.content += data.text; handlers.onText?.(data.text) }\n break\n case \"thinking\":\n if (data?.text) handlers.onThinking?.(data.text)\n break\n case \"tool\":\n handlers.onTool?.(data)\n break\n case \"done\":\n if (typeof data?.content === \"string\") result.content = data.content\n result.usage = data?.usage\n result.duration = data?.duration\n break\n case \"error\":\n result.error = data?.error\n result.errorKind = data?.errorKind\n break\n }\n}\n\n/** Parse one `event:/data:` SSE frame. Ignores comment/heartbeat lines. */\nfunction parseSseFrame(frame: string): { event: string; data: any } | null {\n let event = \"message\"\n let data = \"\"\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) event = line.slice(7).trim()\n else if (line.startsWith(\"data: \")) data = line.slice(6)\n }\n if (!data) return null\n let payload: any\n try { payload = JSON.parse(data) } catch { payload = data }\n return { event, data: payload }\n}\n"],"mappings":"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","names":["init_config","resolveConn","opts","baseUrl","token","cfg","loadDaemonConfig","get","conn","path","signal","headers","res","fetchAgents","fetchProcesses","fetchCrons","post","body","text","parsed","killProcess","key","reason","sendTask","agentId","message","context","streamTask","reader","dec","result","buf","done","value","idx","frame","parseSseFrame","applyFrame","handlers","event","data","line","payload"]}
@@ -0,0 +1,10 @@
1
+ var d=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS push_subscriptions (
2
+ endpoint TEXT PRIMARY KEY, p256dh TEXT NOT NULL, auth TEXT NOT NULL,
3
+ device_id TEXT NOT NULL, device_name TEXT NOT NULL, public_key TEXT NOT NULL,
4
+ created_at INTEGER NOT NULL);
5
+ CREATE INDEX IF NOT EXISTS push_subscriptions_device ON push_subscriptions(device_id);
6
+ CREATE TABLE IF NOT EXISTS push_log (
7
+ id INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL, title TEXT NOT NULL,
8
+ body TEXT NOT NULL, url TEXT, delivered INTEGER NOT NULL, device_id TEXT);`)}subscribe(e,t=Date.now()){this.db.prepare(`INSERT OR REPLACE INTO push_subscriptions
9
+ (endpoint, p256dh, auth, device_id, device_name, public_key, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`).run(e.endpoint,e.p256dh,e.auth,e.deviceId,e.deviceName,e.publicKey,t)}unsubscribe(e,t){return(t===void 0?this.db.prepare("DELETE FROM push_subscriptions WHERE endpoint = ?").run(e):this.db.prepare("DELETE FROM push_subscriptions WHERE endpoint = ? AND device_id = ?").run(e,t)).changes>0}list(e){return(e===void 0?this.db.prepare("SELECT * FROM push_subscriptions ORDER BY created_at").all():this.db.prepare("SELECT * FROM push_subscriptions WHERE device_id = ? ORDER BY created_at").all(e)).map(i=>({endpoint:i.endpoint,p256dh:i.p256dh,auth:i.auth,deviceId:i.device_id,deviceName:i.device_name,publicKey:i.public_key,createdAt:i.created_at}))}log(e,t,i=Date.now()){this.db.prepare("INSERT INTO push_log (at, title, body, url, delivered, device_id) VALUES (?, ?, ?, ?, ?, ?)").run(i,e.title,e.body,e.url,e.delivered,e.deviceId),this.db.prepare("DELETE FROM push_log WHERE id NOT IN (SELECT id FROM push_log ORDER BY id DESC LIMIT ?)").run(Math.max(0,t))}recent(e,t){let i="id, at, title, body, url, delivered, device_id AS deviceId";return t===void 0?this.db.prepare(`SELECT ${i} FROM push_log ORDER BY id DESC LIMIT ?`).all(Math.max(0,e)):this.db.prepare(`SELECT ${i} FROM push_log WHERE device_id IS NULL OR device_id = ? ORDER BY id DESC LIMIT ?`).all(t,Math.max(0,e))}};export{d as a};
10
+ //# sourceMappingURL=chunk-WWMFNLKD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/channels/push-store.ts"],"sourcesContent":["import type Database from \"better-sqlite3\"\n\n// --- Web Push subscriptions and recent pushes (SQLite) ---\n//\n// Shared by two processes on the node that hosts the phone app: the\n// dashboard writes subscriptions when a phone turns notifications on\n// (/api/app/push/*), and the daemon's PushAdapter reads them to deliver,\n// prunes the ones the push service reports gone, and logs what it sent for\n// the app's Alerts tab. Both open the same .agentx/db.sqlite; WAL lets one\n// write while the other reads.\n//\n// Tables are created here with IF NOT EXISTS rather than as a numbered\n// migration, so a branch that claims the same migration number elsewhere\n// can't make a database skip them.\n\nexport interface PushSubscriptionRow {\n endpoint: string\n p256dh: string\n auth: string\n /** Token id of the paired phone (TokenRecord.id). */\n deviceId: string\n deviceName: string\n /** VAPID public key the browser subscribed with. After\n * `agentx app push-keys --force` older rows can never be delivered. */\n publicKey: string\n createdAt: number\n}\n\nexport interface PushLogRow {\n id: number\n at: number\n title: string\n body: string\n url: string | null\n /** Phones the push service accepted it for. */\n delivered: number\n /** Set when the push was addressed to one phone; null for every phone. */\n deviceId: string | null\n}\n\nexport class PushStore {\n constructor(private db: Database.Database) {\n db.exec(`CREATE TABLE IF NOT EXISTS push_subscriptions (\n endpoint TEXT PRIMARY KEY, p256dh TEXT NOT NULL, auth TEXT NOT NULL,\n device_id TEXT NOT NULL, device_name TEXT NOT NULL, public_key TEXT NOT NULL,\n created_at INTEGER NOT NULL);\n CREATE INDEX IF NOT EXISTS push_subscriptions_device ON push_subscriptions(device_id);\n CREATE TABLE IF NOT EXISTS push_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT, at INTEGER NOT NULL, title TEXT NOT NULL,\n body TEXT NOT NULL, url TEXT, delivered INTEGER NOT NULL, device_id TEXT);`)\n }\n\n /** Adds or refreshes a subscription. A browser that re-subscribes keeps\n * its endpoint, so the row is replaced, not duplicated. */\n subscribe(row: Omit<PushSubscriptionRow, \"createdAt\">, now = Date.now()): void {\n this.db.prepare(`INSERT OR REPLACE INTO push_subscriptions\n (endpoint, p256dh, auth, device_id, device_name, public_key, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`)\n .run(row.endpoint, row.p256dh, row.auth, row.deviceId, row.deviceName, row.publicKey, now)\n }\n\n /** Removes one subscription, only if it belongs to `deviceId` when given. */\n unsubscribe(endpoint: string, deviceId?: string): boolean {\n const r = deviceId === undefined\n ? this.db.prepare(\"DELETE FROM push_subscriptions WHERE endpoint = ?\").run(endpoint)\n : this.db.prepare(\"DELETE FROM push_subscriptions WHERE endpoint = ? AND device_id = ?\").run(endpoint, deviceId)\n return r.changes > 0\n }\n\n list(deviceId?: string): PushSubscriptionRow[] {\n const rows = (deviceId === undefined\n ? this.db.prepare(\"SELECT * FROM push_subscriptions ORDER BY created_at\").all()\n : this.db.prepare(\"SELECT * FROM push_subscriptions WHERE device_id = ? ORDER BY created_at\").all(deviceId)) as any[]\n return rows.map((r) => ({\n endpoint: r.endpoint, p256dh: r.p256dh, auth: r.auth,\n deviceId: r.device_id, deviceName: r.device_name, publicKey: r.public_key, createdAt: r.created_at,\n }))\n }\n\n /** Records a sent push and keeps only the newest `keep` rows. */\n log(entry: Omit<PushLogRow, \"id\" | \"at\">, keep: number, now = Date.now()): void {\n this.db.prepare(\"INSERT INTO push_log (at, title, body, url, delivered, device_id) VALUES (?, ?, ?, ?, ?, ?)\")\n .run(now, entry.title, entry.body, entry.url, entry.delivered, entry.deviceId)\n this.db.prepare(\"DELETE FROM push_log WHERE id NOT IN (SELECT id FROM push_log ORDER BY id DESC LIMIT ?)\").run(Math.max(0, keep))\n }\n\n /** Newest first. With `deviceId`, only pushes sent to every phone or to\n * that one, so one phone never sees another's messages. */\n recent(limit: number, deviceId?: string): PushLogRow[] {\n const cols = \"id, at, title, body, url, delivered, device_id AS deviceId\"\n return (deviceId === undefined\n ? this.db.prepare(`SELECT ${cols} FROM push_log ORDER BY id DESC LIMIT ?`).all(Math.max(0, limit))\n : this.db.prepare(`SELECT ${cols} FROM push_log WHERE device_id IS NULL OR device_id = ? ORDER BY id DESC LIMIT ?`)\n .all(deviceId, Math.max(0, limit))) as PushLogRow[]\n }\n}\n"],"mappings":"AAwCO,IAAMA,EAAN,KAAgB,CACrB,YAAoBC,EAAuB,CAAvB,QAAAA,EAClBA,EAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iFAOqE,CAC/E,CAIA,UAAUC,EAA6CC,EAAM,KAAK,IAAI,EAAS,CAC7E,KAAK,GAAG,QAAQ;AAAA,4GACwF,EACrG,IAAID,EAAI,SAAUA,EAAI,OAAQA,EAAI,KAAMA,EAAI,SAAUA,EAAI,WAAYA,EAAI,UAAWC,CAAG,CAC7F,CAGA,YAAYC,EAAkBC,EAA4B,CAIxD,OAHUA,IAAa,OACnB,KAAK,GAAG,QAAQ,mDAAmD,EAAE,IAAID,CAAQ,EACjF,KAAK,GAAG,QAAQ,qEAAqE,EAAE,IAAIA,EAAUC,CAAQ,GACxG,QAAU,CACrB,CAEA,KAAKA,EAA0C,CAI7C,OAHcA,IAAa,OACvB,KAAK,GAAG,QAAQ,sDAAsD,EAAE,IAAI,EAC5E,KAAK,GAAG,QAAQ,0EAA0E,EAAE,IAAIA,CAAQ,GAChG,IAAKC,IAAO,CACtB,SAAUA,EAAE,SAAU,OAAQA,EAAE,OAAQ,KAAMA,EAAE,KAChD,SAAUA,EAAE,UAAW,WAAYA,EAAE,YAAa,UAAWA,EAAE,WAAY,UAAWA,EAAE,UAC1F,EAAE,CACJ,CAGA,IAAIC,EAAsCC,EAAcL,EAAM,KAAK,IAAI,EAAS,CAC9E,KAAK,GAAG,QAAQ,6FAA6F,EAC1G,IAAIA,EAAKI,EAAM,MAAOA,EAAM,KAAMA,EAAM,IAAKA,EAAM,UAAWA,EAAM,QAAQ,EAC/E,KAAK,GAAG,QAAQ,yFAAyF,EAAE,IAAI,KAAK,IAAI,EAAGC,CAAI,CAAC,CAClI,CAIA,OAAOC,EAAeJ,EAAiC,CACrD,IAAMK,EAAO,6DACb,OAAQL,IAAa,OACjB,KAAK,GAAG,QAAQ,UAAUK,0CAA6C,EAAE,IAAI,KAAK,IAAI,EAAGD,CAAK,CAAC,EAC/F,KAAK,GAAG,QAAQ,UAAUC,mFAAsF,EAC/G,IAAIL,EAAU,KAAK,IAAI,EAAGI,CAAK,CAAC,CACvC,CACF","names":["PushStore","db","row","now","endpoint","deviceId","r","entry","keep","limit","cols"]}
@@ -0,0 +1,3 @@
1
+ var m=50,v=20,g=10;function p(e,n,t){return n.agentId===t&&!e.agents?.includes(t)?!1:f(e,n)}function f(e,n){return!(!e.kinds.some(t=>t==="*"||t===n.kind||t===n.type)||e.agents?.length&&(!n.agentId||!e.agents.includes(n.agentId))||e.nodes?.length&&!e.nodes.includes(n.node)||e.match&&!n.summary.toLowerCase().includes(e.match.toLowerCase()))}function c(e,n){return e?.length?n==="pull"?e:e.filter(t=>(t.delivery??"pull")===n):[]}function E(e,n,t,i={}){let o=c(n,i.delivery??"pull");if(o.length===0)return[];let s=a(i.limit),l=t.filter(r=>o.some(u=>p(u,r,e)));return i.fromCursor?l.slice(0,s):l.slice(-s)}function a(e,n=20){return!e||!Number.isFinite(e)||e<1?n:Math.min(Math.floor(e),50)}function h(e,n,t){let i=c(n,"digest");if(i.length===0)return{shown:[],more:0};let o=0;for(let r=t.length-1;r>=0;r--)if(t[r].agentId===e&&t[r].type==="task:completed"){o=r+1;break}let s=t.slice(o).filter(r=>i.some(u=>p(u,r,e))),l=s.slice(-10);return{shown:l,more:s.length-l.length}}function d(e){let n=e.agentId?`${e.agentId}@${e.node}`:e.node,t=e.ref?` (ref ${e.ref})`:"";return`${e.at.slice(0,16).replace("T"," ")} ${e.type} ${n}: ${e.summary}${t}`}function y(e,n){return e.length===0?void 0:[`[Events since your last turn \u2014 ${e.length+n} matched your subscriptions${n?`, newest ${e.length} shown`:""}. Call agentx_events for details or newer ones:]`,...e.map(i=>`- ${d(i)}`)].join(`
2
+ `)}export{m as a,v as b,g as c,p as d,f as e,c as f,E as g,a as h,h as i,d as j,y as k};
3
+ //# sourceMappingURL=chunk-X5C5W3E4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/events/subscriptions.ts"],"sourcesContent":["import type { EventSubscription } from \"@/daemon/config\"\nimport type { EventEnvelope } from \"./envelope\"\n\n// --- Per-agent event subscriptions ---\n//\n// An agent lists the events it cares about in `agents.<id>.subscriptions`.\n// This module is the pure half: does an envelope match, which envelopes\n// does an agent get, and how a digest reads. Delivery lives elsewhere:\n// pull — GET /agents/:id/events, the agentx_events MCP tool and\n// `agentx events` read eventsForAgent()\n// digest — the registry injects renderDigest() into FRESH sessions only\n// wake — src/events/wake.ts starts a turn\n// Every answer is bounded: envelopes already cap their summary, and each\n// reader caps the count.\n\nexport type Delivery = EventSubscription[\"delivery\"]\n\n/** Most events one pull returns. */\nexport const PULL_MAX = 50\nexport const PULL_DEFAULT = 20\n/** Most events a fresh-session digest lists. */\nexport const DIGEST_MAX = 10\n\n/** Loose input shape: config output, or a hand-written object in tests. */\nexport type SubscriptionInput = Partial<EventSubscription> & { kinds: string[] }\n\n/** Does `e` match `sub` for `self`? An agent never matches its own events\n * unless the subscription names it in `agents` (and `wake` never does;\n * see wake.ts). */\nexport function matchesSubscription(sub: SubscriptionInput, e: EventEnvelope, self: string): boolean {\n if (e.agentId === self && !sub.agents?.includes(self)) return false\n return matchesFilters(sub, e)\n}\n\n/** The subscription's own filters, with no regard to who is asking. */\nexport function matchesFilters(sub: SubscriptionInput, e: EventEnvelope): boolean {\n if (!sub.kinds.some((k) => k === \"*\" || k === e.kind || k === e.type)) return false\n if (sub.agents?.length && (!e.agentId || !sub.agents.includes(e.agentId))) return false\n if (sub.nodes?.length && !sub.nodes.includes(e.node)) return false\n if (sub.match && !e.summary.toLowerCase().includes(sub.match.toLowerCase())) return false\n return true\n}\n\n/** Subscriptions of one delivery mode. `pull` reads every subscription:\n * digest and wake events can always be pulled too. */\nexport function subscriptionsFor(subs: SubscriptionInput[] | undefined, delivery: Delivery): SubscriptionInput[] {\n if (!subs?.length) return []\n return delivery === \"pull\" ? subs : subs.filter((s) => (s.delivery ?? \"pull\") === delivery)\n}\n\n/** Events from `events` (oldest first) that match any of `subs`. With no\n * cursor the newest `limit` are kept. When `events` was already read after\n * a cursor (`fromCursor`), the OLDEST `limit` are kept instead, so a reader\n * that passes the last returned id back as `since` pages through every\n * match without gaps. */\nexport function eventsForAgent(\n agentId: string,\n subs: SubscriptionInput[] | undefined,\n events: EventEnvelope[],\n opts: { delivery?: Delivery; limit?: number; fromCursor?: boolean } = {},\n): EventEnvelope[] {\n const active = subscriptionsFor(subs, opts.delivery ?? \"pull\")\n if (active.length === 0) return []\n const limit = clampLimit(opts.limit)\n const hits = events.filter((e) => active.some((s) => matchesSubscription(s, e, agentId)))\n return opts.fromCursor ? hits.slice(0, limit) : hits.slice(-limit)\n}\n\nexport function clampLimit(limit: number | undefined, fallback = PULL_DEFAULT): number {\n if (!limit || !Number.isFinite(limit) || limit < 1) return fallback\n return Math.min(Math.floor(limit), PULL_MAX)\n}\n\n/** The events a fresh session should hear about: digest subscriptions\n * matched since the agent's last finished turn (the whole buffer when it\n * has none), newest DIGEST_MAX. Returns the shown events and how many\n * more matched. */\nexport function digestEvents(\n agentId: string,\n subs: SubscriptionInput[] | undefined,\n events: EventEnvelope[],\n): { shown: EventEnvelope[]; more: number } {\n const active = subscriptionsFor(subs, \"digest\")\n if (active.length === 0) return { shown: [], more: 0 }\n let start = 0\n for (let i = events.length - 1; i >= 0; i--) {\n if (events[i].agentId === agentId && events[i].type === \"task:completed\") { start = i + 1; break }\n }\n const hits = events.slice(start).filter((e) => active.some((s) => matchesSubscription(s, e, agentId)))\n const shown = hits.slice(-DIGEST_MAX)\n return { shown, more: hits.length - shown.length }\n}\n\n/** One line per event: time, type, who and where, summary, ref. */\nexport function formatEventLine(e: EventEnvelope): string {\n const who = e.agentId ? `${e.agentId}@${e.node}` : e.node\n const ref = e.ref ? ` (ref ${e.ref})` : \"\"\n return `${e.at.slice(0, 16).replace(\"T\", \" \")} ${e.type} ${who}: ${e.summary}${ref}`\n}\n\n/** The context block for a fresh session, or undefined when nothing matched. */\nexport function renderDigest(shown: EventEnvelope[], more: number): string | undefined {\n if (shown.length === 0) return undefined\n const lines = [\n `[Events since your last turn — ${shown.length + more} matched your subscriptions${more ? `, newest ${shown.length} shown` : \"\"}. Call agentx_events for details or newer ones:]`,\n ...shown.map((e) => `- ${formatEventLine(e)}`),\n ]\n return lines.join(\"\\n\")\n}\n"],"mappings":"AAkBO,IAAMA,EAAW,GACXC,EAAe,GAEfC,EAAa,GAQnB,SAASC,EAAoBC,EAAwBC,EAAkBC,EAAuB,CACnG,OAAID,EAAE,UAAYC,GAAQ,CAACF,EAAI,QAAQ,SAASE,CAAI,EAAU,GACvDC,EAAeH,EAAKC,CAAC,CAC9B,CAGO,SAASE,EAAeH,EAAwBC,EAA2B,CAIhF,MAHI,GAACD,EAAI,MAAM,KAAMI,GAAMA,IAAM,KAAOA,IAAMH,EAAE,MAAQG,IAAMH,EAAE,IAAI,GAChED,EAAI,QAAQ,SAAW,CAACC,EAAE,SAAW,CAACD,EAAI,OAAO,SAASC,EAAE,OAAO,IACnED,EAAI,OAAO,QAAU,CAACA,EAAI,MAAM,SAASC,EAAE,IAAI,GAC/CD,EAAI,OAAS,CAACC,EAAE,QAAQ,YAAY,EAAE,SAASD,EAAI,MAAM,YAAY,CAAC,EAE5E,CAIO,SAASK,EAAiBC,EAAuCC,EAAyC,CAC/G,OAAKD,GAAM,OACJC,IAAa,OAASD,EAAOA,EAAK,OAAQE,IAAOA,EAAE,UAAY,UAAYD,CAAQ,EADhE,CAAC,CAE7B,CAOO,SAASE,EACdC,EACAJ,EACAK,EACAC,EAAsE,CAAC,EACtD,CACjB,IAAMC,EAASR,EAAiBC,EAAMM,EAAK,UAAY,MAAM,EAC7D,GAAIC,EAAO,SAAW,EAAG,MAAO,CAAC,EACjC,IAAMC,EAAQC,EAAWH,EAAK,KAAK,EAC7BI,EAAOL,EAAO,OAAQV,GAAMY,EAAO,KAAML,GAAMT,EAAoBS,EAAGP,EAAGS,CAAO,CAAC,CAAC,EACxF,OAAOE,EAAK,WAAaI,EAAK,MAAM,EAAGF,CAAK,EAAIE,EAAK,MAAM,CAACF,CAAK,CACnE,CAEO,SAASC,EAAWD,EAA2BG,EAAW,GAAsB,CACrF,MAAI,CAACH,GAAS,CAAC,OAAO,SAASA,CAAK,GAAKA,EAAQ,EAAUG,EACpD,KAAK,IAAI,KAAK,MAAMH,CAAK,EAAG,EAAQ,CAC7C,CAMO,SAASI,EACdR,EACAJ,EACAK,EAC0C,CAC1C,IAAME,EAASR,EAAiBC,EAAM,QAAQ,EAC9C,GAAIO,EAAO,SAAW,EAAG,MAAO,CAAE,MAAO,CAAC,EAAG,KAAM,CAAE,EACrD,IAAIM,EAAQ,EACZ,QAASC,EAAIT,EAAO,OAAS,EAAGS,GAAK,EAAGA,IACtC,GAAIT,EAAOS,CAAC,EAAE,UAAYV,GAAWC,EAAOS,CAAC,EAAE,OAAS,iBAAkB,CAAED,EAAQC,EAAI,EAAG,MAE7F,IAAMJ,EAAOL,EAAO,MAAMQ,CAAK,EAAE,OAAQlB,GAAMY,EAAO,KAAML,GAAMT,EAAoBS,EAAGP,EAAGS,CAAO,CAAC,CAAC,EAC/FW,EAAQL,EAAK,MAAM,GAAW,EACpC,MAAO,CAAE,MAAAK,EAAO,KAAML,EAAK,OAASK,EAAM,MAAO,CACnD,CAGO,SAASC,EAAgB,EAA0B,CACxD,IAAMC,EAAM,EAAE,QAAU,GAAG,EAAE,WAAW,EAAE,OAAS,EAAE,KAC/CC,EAAM,EAAE,IAAM,SAAS,EAAE,OAAS,GACxC,MAAO,GAAG,EAAE,GAAG,MAAM,EAAG,EAAE,EAAE,QAAQ,IAAK,GAAG,KAAK,EAAE,QAAQD,MAAQ,EAAE,UAAUC,GACjF,CAGO,SAASC,EAAaJ,EAAwBK,EAAkC,CACrF,OAAIL,EAAM,SAAW,EAAG,OACV,CACZ,uCAAkCA,EAAM,OAASK,+BAAkCA,EAAO,YAAYL,EAAM,eAAiB,qDAC7H,GAAGA,EAAM,IAAKpB,GAAM,KAAKqB,EAAgBrB,CAAC,GAAG,CAC/C,EACa,KAAK;AAAA,CAAI,CACxB","names":["PULL_MAX","PULL_DEFAULT","DIGEST_MAX","matchesSubscription","sub","e","self","matchesFilters","k","subscriptionsFor","subs","delivery","s","eventsForAgent","agentId","events","opts","active","limit","clampLimit","hits","fallback","digestEvents","start","i","shown","formatEventLine","who","ref","renderDigest","more"]}
@@ -1,8 +1,8 @@
1
- import{a as D,b as _}from"./chunk-RKPAVWXF.js";import{a as q,b as O,c as R,d as B,f as b,g as S,h as E,i as w,j as y}from"./chunk-PGJL5V6Y.js";import{a as T,b as C,c as I,d as x,e as P}from"./chunk-FS4WBYY3.js";import{existsSync as X,readFileSync as F}from"fs";var J=new Set(["cron","heartbeat","api","a2a","mesh"]),M=160;function s(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function A(n,e=M){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function V(n){let e=T(n);if(!X(e))throw new Error(`config not found at ${e}`);return JSON.parse(F(e,"utf-8"))}function W(n,e){return n?.agents?.[e]?.admin===!0}function Y(n,e,t){return W(n,t.agentId)||e?.createdBy===t.agentId}function Z(n,e){let t=e?.createdBy?`agent "${e.createdBy}"`:"the operator";return`Not allowed: "${n}" was created by ${t}. Agents manage only schedules they created (unless configured admin).`}function K(n,e){let t=s(n.notify);if(t!=="none"){if(t&&t!=="here"){let r=t.split(":");return r.length<2||!r[0]||!r[1]?"invalid":{channel:r[0],chatId:r.slice(1).join(":")}}if(e.channel&&e.chatId&&!J.has(e.channel))return{channel:e.channel,chatId:e.chatId,...e.accountId?{accountId:e.accountId}:{}}}}function Q(n,e,t){let r=e.timezone||"UTC",u=e.enabled&&!y(e)?w(E(e.schedule,r,t),r):"\u2014",h=e.approval?`pending ${e.approval.action} approval`:e.enabled?"active":"paused",p=[`- ${n} [${h}] ${e.schedule} \u2014 ${S(e.schedule)} (${r})`,` agent: ${e.agent}; created by: ${e.createdBy||"operator"}; next: ${u}`];return e.notify&&p.push(` notify: ${e.notify.channel} ${e.notify.chatId}`),e.command?p.push(` command: ${A(String(e.command))}`):e.prompt&&p.push(` prompt: ${A(String(e.prompt))}`),p.join(`
1
+ import{a as D,b as _}from"./chunk-RKPAVWXF.js";import{a as q,b as O,c as R,d as B,f as b,g as S,h as E,i as w,j as y}from"./chunk-SA23V7WX.js";import{a as T,b as C,c as I,d as x,e as P}from"./chunk-EZN2YXRY.js";import{existsSync as X,readFileSync as F}from"fs";var J=new Set(["cron","heartbeat","api","a2a","mesh"]),M=160;function s(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function A(n,e=M){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function V(n){let e=T(n);if(!X(e))throw new Error(`config not found at ${e}`);return JSON.parse(F(e,"utf-8"))}function W(n,e){return n?.agents?.[e]?.admin===!0}function Y(n,e,t){return W(n,t.agentId)||e?.createdBy===t.agentId}function Z(n,e){let t=e?.createdBy?`agent "${e.createdBy}"`:"the operator";return`Not allowed: "${n}" was created by ${t}. Agents manage only schedules they created (unless configured admin).`}function K(n,e){let t=s(n.notify);if(t!=="none"){if(t&&t!=="here"){let r=t.split(":");return r.length<2||!r[0]||!r[1]?"invalid":{channel:r[0],chatId:r.slice(1).join(":")}}if(e.channel&&e.chatId&&!J.has(e.channel))return{channel:e.channel,chatId:e.chatId,...e.accountId?{accountId:e.accountId}:{}}}}function Q(n,e,t){let r=e.timezone||"UTC",u=e.enabled&&!y(e)?w(E(e.schedule,r,t),r):"\u2014",h=e.approval?`pending ${e.approval.action} approval`:e.enabled?"active":"paused",p=[`- ${n} [${h}] ${e.schedule} \u2014 ${S(e.schedule)} (${r})`,` agent: ${e.agent}; created by: ${e.createdBy||"operator"}; next: ${u}`];return e.notify&&p.push(` notify: ${e.notify.channel} ${e.notify.chatId}`),e.command?p.push(` command: ${A(String(e.command))}`):e.prompt&&p.push(` prompt: ${A(String(e.prompt))}`),p.join(`
2
2
  `)}async function k(n,e,t){let r=n?.notifications?.destination;if(!r?.channel||!r?.chatId)return"No operator notification destination is configured (notifications.destination); the operator must check `agentx schedule list`.";if(!e.notifyOperator)return"Operator notification is unavailable in this context.";try{return await e.notifyOperator({channel:r.channel,chatId:r.chatId,accountId:r.accountId},t),"The operator has been notified."}catch(u){return`Could not notify the operator (${u?.message??u}); the request is still recorded.`}}async function re(n,e,t={}){let r=(s(n.action)||"list").toLowerCase(),u=t.now?t.now():new Date,h;try{h=V(t.configPath)}catch(a){return`Error: ${a.message}`}let p=h.crons||{};if(r==="list"){let a=n.mine===!0,l=Object.entries(p).filter(([,i])=>!a||e&&i?.createdBy===e.agentId);return l.length?l.map(([i,f])=>Q(i,f,u)).join(`
3
3
  `):a?"You have no schedules.":"No schedules."}if(!e?.agentId)return"Error: caller agent is unknown (AGENTX_AGENT_ID not set). Pass callerAgentId.";if(!h.agents?.[e.agentId])return`Error: caller "${e.agentId}" is not an agent on this node.`;let o=s(n.id),m=a=>C(a,{configPath:t.configPath,reload:t.reload});if(r==="create"){let a=s(n.when),l=s(n.prompt);if(!a||!l)return"Error: create needs `when` (plain English) and `prompt`.";let i=D(a);if(!i)return`Error: couldn't parse "${a}". ${O}.`;let f=s(n.agent)||e.agentId;if(!h.agents?.[f])return`Error: agent "${f}" not found on this node.`;let g=s(n.timezone)||q;if(!B(g))return`Error: unknown timezone "${g}".`;let d=o||_(i.matched,f);if(!R(d))return`Error: invalid id "${d}" (letters, digits, "-" and "_" only).`;if(p[d])return`Error: a schedule "${d}" already exists. Pick another \`id\`.`;let $=K(n,e);if($==="invalid")return'Error: `notify` must be "here", "none", or "channel:chatId".';let z={action:"create",requestedBy:e.agentId,requestedAt:u.toISOString()},L=b({parsed:i,agent:f,prompt:l,timezone:g,notify:$,enabled:!1,createdBy:e.agentId,approval:z}),v=await m(U=>I(U,`crons.${d}`,L));if(!v.success)return`Error: ${v.error}`;let N=w(E(i.cron,g,u),g),G=[`Schedule approval requested by ${e.agentId}`,`Create: ${d}`,`When: ${i.human} \u2014 cron \`${i.cron}\` (${g})`,`Next fire: ${N}`,`Agent: ${f}`,$?`Notify: ${$.channel} ${$.chatId}`:"Notify: none",`Prompt: ${A(l,400)}`,"",`Approve: agentx schedule approve ${d}`,`Reject: agentx schedule reject ${d}`].join(`
4
4
  `),H=await k(h,t,G);return[`Requested schedule "${d}": ${i.human} (cron ${i.cron}, ${g}); next fire would be ${N}.`,"It is saved DISABLED and will not run until the operator approves it.",H].join(`
5
5
  `)}if(!o)return`Error: ${r} needs \`id\`.`;let c=p[o];if(!c)return`Error: schedule "${o}" not found.`;if(!Y(h,c,e))return Z(o,c);if(r==="pause"||r==="resume"){let a=r==="resume";if(a&&y(c))return`"${o}" is still awaiting operator approval; it can't be resumed until approved.`;if(c.enabled===a)return`"${o}" is already ${a?"active":"paused"}.`;let l=await m(i=>I(i,`crons.${o}.enabled`,a));return l.success?`"${o}" ${a?"resumed":"paused"}.`:`Error: ${l.error}`}if(r==="delete"){if(y(c)&&c.approval.requestedBy===e.agentId){let d=await m($=>P($,`crons.${o}`));return d.success?`Withdrew the pending request "${o}".`:`Error: ${d.error}`}if(y(c))return`"${o}" is a creation request still awaiting approval; only its requester or the operator (\`agentx schedule reject ${o}\`) can drop it.`;if(c.approval?.action==="delete")return`Deletion of "${o}" is already awaiting approval.`;let a={action:"delete",requestedBy:e.agentId,requestedAt:u.toISOString()},l=await m(d=>{if(!x(d,`crons.${o}`))throw new Error(`schedule "${o}" not found`);I(d,`crons.${o}.approval`,a)});if(!l.success)return`Error: ${l.error}`;let i=c.timezone||"UTC",f=[`Schedule approval requested by ${e.agentId}`,`Delete: ${o}`,`When: ${S(c.schedule)} \u2014 cron \`${c.schedule}\` (${i})`,`Next fire: ${c.enabled?w(E(c.schedule,i,u),i):"\u2014 (paused)"}`,`Agent: ${c.agent}`,"",`Approve: agentx schedule approve ${o}`,`Reject: agentx schedule reject ${o}`].join(`
6
6
  `),g=await k(h,t,f);return[`Deletion of "${o}" requested. It keeps its current state until the operator approves.`,g].join(`
7
7
  `)}return`Error: unknown action "${r}". Use list, create, pause, resume or delete.`}function oe(n,e=process.env){let t=s(e.AGENTX_AGENT_ID)||s(n.callerAgentId);if(!t)return null;let r=!!(s(e.AGENTX_CHANNEL)&&s(e.AGENTX_CHAT_ID)),u=s(r?e.AGENTX_CHANNEL:n.channel),h=s(r?e.AGENTX_CHAT_ID:n.chatId),p=s(n.accountId);return{agentId:t,channel:u,chatId:h,...p?{accountId:p}:{}}}export{re as a,oe as b};
8
- //# sourceMappingURL=chunk-CCMM5TP4.js.map
8
+ //# sourceMappingURL=chunk-XEOAKD5C.js.map
package/dist/cli.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{a as n}from"./chunk-7OWXFLAM.js";import"./chunk-OV35MJKS.js";import"./chunk-OMTRHHZJ.js";import"./chunk-Z3IP66SL.js";import"./chunk-KAFO5QZR.js";import"./chunk-FSZXY53Z.js";import"./chunk-RKPAVWXF.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-SABOPOYX.js";import"./chunk-D4HAR3L3.js";import"./chunk-TH5KNJLA.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-S7CVSKOX.js";import"./chunk-6OOK7Y4S.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-L53FTKEP.js";import"./chunk-IDYP7G7Z.js";import"./chunk-C5JXPMTW.js";import"./chunk-N6EWZGIX.js";import"./chunk-WP6KLXTP.js";import"./chunk-DP7RTNDM.js";import"./chunk-7DPKPBRJ.js";import"./chunk-SFQUP3BP.js";import"./chunk-PGJL5V6Y.js";import"./chunk-KFG6WWFS.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-FS4WBYY3.js";import"./chunk-KB7YIM3W.js";import"./chunk-DWADWDMU.js";import"./chunk-WKTFP3SK.js";import"./chunk-HRBKSZ34.js";import"./chunk-VWTBHLMX.js";import"./chunk-VD4TMPJI.js";import"./chunk-KJWBQZT7.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-QU6ZUKAD.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-NF52Q3TV.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-47EEUZBK.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";var r=["SIGINT","SIGTERM"];function o(t=process){for(let i of r)t.on(i,()=>{t.listenerCount(i)<=1&&t.exit(0)})}o();async function s(){let t=await n();if(process.argv.slice(2).length===0){t.outputHelp();return}t.parse()}s();
2
+ import{a as n}from"./chunk-JC5Q5MPI.js";import"./chunk-WOMQ2VGA.js";import"./chunk-D3LSPFHK.js";import"./chunk-76AHNHWC.js";import"./chunk-Z3IP66SL.js";import"./chunk-KAFO5QZR.js";import"./chunk-RKPAVWXF.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-K4RDE6YU.js";import"./chunk-UIVHSYCN.js";import"./chunk-723K4SAW.js";import"./chunk-S7CVSKOX.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-SA23V7WX.js";import"./chunk-W4YMMWJL.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-L53FTKEP.js";import"./chunk-EJ5ISSWW.js";import"./chunk-CELYD5QW.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-O3XG2NVR.js";import"./chunk-EZN2YXRY.js";import"./chunk-6AK6WKE5.js";import"./chunk-SFQUP3BP.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-4HEVSWO3.js";import"./chunk-DWADWDMU.js";import"./chunk-NO2HOK4B.js";import"./chunk-QD6IICK7.js";import"./chunk-VWTBHLMX.js";import"./chunk-LKJSPO3S.js";import"./chunk-C3VRBEJ7.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-GSOL2LW6.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-M4AG2YNX.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-FX3D7YON.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-U4H35SJS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";var r=["SIGINT","SIGTERM"];function o(t=process){for(let i of r)t.on(i,()=>{t.listenerCount(i)<=1&&t.exit(0)})}o();async function s(){let t=await n();if(process.argv.slice(2).length===0){t.outputHelp();return}t.parse()}s();
3
3
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/signal-exit.ts","../src/cli.ts"],"sourcesContent":["// --- Ctrl-C / SIGTERM for CLI commands ---\n//\n// Short commands should exit at once when stopped. Long-running ones (the\n// daemon above all) install their own handler to finish in-flight work first.\n// The CLI's quick exit used to be registered unconditionally, before the\n// daemon's, and Node runs listeners in registration order — so every stop\n// exited the process before the daemon's drain began and killed in-flight\n// agent tasks mid-turn (#103). Now the quick exit only fires when nobody\n// else handles the signal.\n\ntype SignalTarget = Pick<NodeJS.Process, \"on\" | \"listenerCount\" | \"exit\">\n\nexport const CLI_EXIT_SIGNALS = [\"SIGINT\", \"SIGTERM\"] as const\n\nexport function installCliSignalExit(proc: SignalTarget = process): void {\n for (const sig of CLI_EXIT_SIGNALS) {\n proc.on(sig, () => {\n // This listener is always one of them; anything more means a command\n // is handling the stop itself.\n if (proc.listenerCount(sig) <= 1) proc.exit(0)\n })\n }\n}\n","#!/usr/bin/env node\nimport { buildProgram } from \"@/program\"\nimport { installCliSignalExit } from \"@/utils/signal-exit\"\n\ninstallCliSignalExit()\n\nasync function main() {\n const program = await buildProgram()\n\n const args = process.argv.slice(2)\n if (args.length === 0) {\n program.outputHelp()\n return\n }\n\n program.parse()\n}\n\nmain()\n"],"mappings":";goDAYO,IAAMA,EAAmB,CAAC,SAAU,SAAS,EAE7C,SAASC,EAAqBC,EAAqB,QAAe,CACvE,QAAWC,KAAOH,EAChBE,EAAK,GAAGC,EAAK,IAAM,CAGbD,EAAK,cAAcC,CAAG,GAAK,GAAGD,EAAK,KAAK,CAAC,CAC/C,CAAC,CAEL,CClBAE,EAAqB,EAErB,eAAeC,GAAO,CACpB,IAAMC,EAAU,MAAMC,EAAa,EAGnC,GADa,QAAQ,KAAK,MAAM,CAAC,EACxB,SAAW,EAAG,CACrBD,EAAQ,WAAW,EACnB,OAGFA,EAAQ,MAAM,CAChB,CAEAD,EAAK","names":["CLI_EXIT_SIGNALS","installCliSignalExit","proc","sig","installCliSignalExit","main","program","buildProgram"]}
1
+ {"version":3,"sources":["../src/utils/signal-exit.ts","../src/cli.ts"],"sourcesContent":["// --- Ctrl-C / SIGTERM for CLI commands ---\n//\n// Short commands should exit at once when stopped. Long-running ones (the\n// daemon above all) install their own handler to finish in-flight work first.\n// The CLI's quick exit used to be registered unconditionally, before the\n// daemon's, and Node runs listeners in registration order — so every stop\n// exited the process before the daemon's drain began and killed in-flight\n// agent tasks mid-turn (#103). Now the quick exit only fires when nobody\n// else handles the signal.\n\ntype SignalTarget = Pick<NodeJS.Process, \"on\" | \"listenerCount\" | \"exit\">\n\nexport const CLI_EXIT_SIGNALS = [\"SIGINT\", \"SIGTERM\"] as const\n\nexport function installCliSignalExit(proc: SignalTarget = process): void {\n for (const sig of CLI_EXIT_SIGNALS) {\n proc.on(sig, () => {\n // This listener is always one of them; anything more means a command\n // is handling the stop itself.\n if (proc.listenerCount(sig) <= 1) proc.exit(0)\n })\n }\n}\n","#!/usr/bin/env node\nimport { buildProgram } from \"@/program\"\nimport { installCliSignalExit } from \"@/utils/signal-exit\"\n\ninstallCliSignalExit()\n\nasync function main() {\n const program = await buildProgram()\n\n const args = process.argv.slice(2)\n if (args.length === 0) {\n program.outputHelp()\n return\n }\n\n program.parse()\n}\n\nmain()\n"],"mappings":";wrDAYO,IAAMA,EAAmB,CAAC,SAAU,SAAS,EAE7C,SAASC,EAAqBC,EAAqB,QAAe,CACvE,QAAWC,KAAOH,EAChBE,EAAK,GAAGC,EAAK,IAAM,CAGbD,EAAK,cAAcC,CAAG,GAAK,GAAGD,EAAK,KAAK,CAAC,CAC/C,CAAC,CAEL,CClBAE,EAAqB,EAErB,eAAeC,GAAO,CACpB,IAAMC,EAAU,MAAMC,EAAa,EAGnC,GADa,QAAQ,KAAK,MAAM,CAAC,EACxB,SAAW,EAAG,CACrBD,EAAQ,WAAW,EACnB,OAGFA,EAAQ,MAAM,CAChB,CAEAD,EAAK","names":["CLI_EXIT_SIGNALS","installCliSignalExit","proc","sig","installCliSignalExit","main","program","buildProgram"]}
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e,f,g}from"./chunk-WOMQ2VGA.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as fetchAgents,d as fetchCrons,c as fetchProcesses,e as killProcess,a as resolveConn,f as sendTask,g as streamTask};
2
+ //# sourceMappingURL=client-IA7ZPE56.js.map
@@ -17,7 +17,7 @@ Format as a structured summary:
17
17
  Keep it under 500 words. Prioritize actionable information over conversational flow.
18
18
  Do NOT include greetings, acknowledgments, or meta-commentary about the conversation.`;function G(t){return t.length<F?!1:t.reduce((n,e)=>n+e.content.length,0)>A}async function J(t,o,n,e){if(t.length<F)return{summary:"",compactedCount:0,keptCount:t.length,memoryFlushed:!1};let r=Math.max(0,t.length-K),s=t.slice(0,r),c=t.slice(r);if(s.length===0)return{summary:"",compactedCount:0,keptCount:c.length,memoryFlushed:!1};let a=d(s);M(o,a);let m=!1;if(n)try{await $(o,s,n,e),m=!0}catch{}let u=j(s),l=await z(u),{qualityScore:i,lostEntities:g}=B(u,l),p,x=[{role:"agent",content:l,timestamp:new Date().toISOString()}],D=d(x),h=v(o);return h&&(p=S(h,D)),{summary:l,compactedCount:s.length,keptCount:c.length,memoryFlushed:m,qualityScore:i,lostEntities:g.length>0?g:void 0,drift:p&&p.overallScore>.1?p:void 0}}function B(t,o){let n=_(t);if(n.length===0)return{qualityScore:100,lostEntities:[]};let e=o.toLowerCase(),r=[],s=[];for(let a of n)e.includes(a.toLowerCase())?r.push(a):s.push(a);return{qualityScore:Math.round(r.length/n.length*100),lostEntities:s}}function _(t){let o=[],n=new Set,e=i=>{let g=i.toLowerCase().trim();g.length<3||n.has(g)||(n.add(g),o.push(i.trim()))},r=t.match(/https?:\/\/[^\s<>)"]+/g)||[];for(let i of r)e(i.slice(0,80));let s=t.match(/(?:\/[\w.-]+){2,}/g)||[];for(let i of s)e(i);let c=t.match(/[#!]\d{2,}/g)||[];for(let i of c)e(i);let a=t.match(/[\w.-]+@[\w.-]+\.\w+/g)||[];for(let i of a)e(i);let m=t.match(/"([^"]{3,40})"/g)||[];for(let i of m)e(i.slice(1,-1));let u=t.match(/[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+/g)||[];for(let i of u)e(i);let l=t.match(/[a-f0-9]{8,}/gi)||[];for(let i of l.slice(0,5))e(i);return o.slice(0,30)}function W(t,o){if(o.compactedCount===0)return t;let n=t.slice(-o.keptCount);return[{role:"agent",name:"system",content:`[Compacted conversation summary \u2014 ${o.compactedCount} earlier messages]
19
19
 
20
- ${o.summary}`,timestamp:new Date().toISOString()},...n]}async function $(t,o,n,e){let r=[],s=[];for(let a of o)a.role==="user"?r.push(`${a.name||"User"}: ${a.content}`):s.push(a.content);if(r.length===0||s.length===0)return;let{extractMemories:c}=await import("./memory-extract-MGGXIZTE.js");await c(t,r.join(`
20
+ ${o.summary}`,timestamp:new Date().toISOString()},...n]}async function $(t,o,n,e){let r=[],s=[];for(let a of o)a.role==="user"?r.push(`${a.name||"User"}: ${a.content}`):s.push(a.content);if(r.length===0||s.length===0)return;let{extractMemories:c}=await import("./memory-extract-F76BE6KA.js");await c(t,r.join(`
21
21
  `),s.join(`
22
22
  `),{channel:e?.channel??"compaction",chatId:e?.chatId??"flush",sender:"compaction"},n)}function j(t){return t.map(o=>{let n=o.timestamp.slice(11,16),e=o.role==="user"?o.name||"User":o.name||"Agent";return`[${n}] ${e}: ${o.content}`}).join(`
23
23
 
@@ -25,4 +25,4 @@ ${o.summary}`,timestamp:new Date().toISOString()},...n]}async function $(t,o,n,e
25
25
  `).slice(-20);return`[Summary unavailable \u2014 keeping last ${s.length} lines]
26
26
  ${s.join(`
27
27
  `)}`}}export{W as applyCompaction,J as compactSession,G as needsCompaction};
28
- //# sourceMappingURL=compaction-NWPBPWY2.js.map
28
+ //# sourceMappingURL=compaction-H5U32UU6.js.map
@@ -0,0 +1,2 @@
1
+ import{i as a,j as b,k as c,l as d,m as e,n as f,o as g,q as h}from"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";h();export{a as INTEGRATION_KINDS,c as approvalsConfigSchema,d as daemonConfigSchema,b as eventSubscriptionSchema,e as expandEnvVars,f as loadDaemonConfig,g as validateWorkspaces};
2
+ //# sourceMappingURL=config-HPN2F7LH.js.map
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e}from"./chunk-EZN2YXRY.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as applyConfigMutation,a as findConfigPath,d as getAtPath,c as setAtPath,e as unsetAtPath};
2
+ //# sourceMappingURL=config-mutator-7GPTMTVB.js.map
@@ -0,0 +1,2 @@
1
+ import{b as a,c as b,d as c,e as d}from"./chunk-D3LSPFHK.js";import"./chunk-S7CVSKOX.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as doctor,a as runDoctorChecks,c as runNotificationChecks,d as runReminderChecks};
2
+ //# sourceMappingURL=doctor-IBWQVQV4.js.map