agentix-cli 0.80.1 → 0.81.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/CallModel.swift +11 -0
  2. package/apps/mac-voice/Sources/AgentXVoice/Calls.swift +7 -4
  3. package/apps/mac-voice/Sources/AgentXVoice/main.swift +15 -3
  4. package/dist/{App-KVH5POXZ.js → App-HF6W6CV2.js} +2 -2
  5. package/dist/{App-KVH5POXZ.js.map → App-HF6W6CV2.js.map} +1 -1
  6. package/dist/ChatApp-74VBWP7R.js +7 -0
  7. package/dist/{ChatApp-LD4TXJWP.js.map → ChatApp-74VBWP7R.js.map} +1 -1
  8. package/dist/{agent-FUMJM6OW.js → agent-75URYGWI.js} +2 -2
  9. package/dist/{board-dashboard-OS5J3F73.js → board-dashboard-TWEF5XVE.js} +186 -169
  10. package/dist/board-dashboard-TWEF5XVE.js.map +1 -0
  11. package/dist/{chunk-MYRSNJJ4.js → chunk-3FCYKGU6.js} +2 -2
  12. package/dist/{chunk-R42S57G6.js → chunk-4KJ3PCAI.js} +2 -2
  13. package/dist/{chunk-PE55MMLK.js → chunk-5GXCOHDM.js} +2 -2
  14. package/dist/{chunk-PE55MMLK.js.map → chunk-5GXCOHDM.js.map} +1 -1
  15. package/dist/{chunk-BJPIRNP6.js → chunk-74FSHUB3.js} +2 -2
  16. package/dist/{chunk-H7253EHW.js → chunk-ATXE3EMV.js} +2 -2
  17. package/dist/{chunk-TEFMZY6B.js → chunk-BB3ESU74.js} +2 -2
  18. package/dist/{chunk-XESESMKN.js → chunk-BDM4VTBR.js} +39 -39
  19. package/dist/{chunk-XESESMKN.js.map → chunk-BDM4VTBR.js.map} +1 -1
  20. package/dist/chunk-BYD5B3P3.js +9 -0
  21. package/dist/{chunk-Z3IP66SL.js.map → chunk-BYD5B3P3.js.map} +1 -1
  22. package/dist/chunk-ES7Z64Z5.js +22 -0
  23. package/dist/chunk-ES7Z64Z5.js.map +1 -0
  24. package/dist/{chunk-WP6KLXTP.js → chunk-GLQLCBJS.js} +4 -4
  25. package/dist/chunk-GLQLCBJS.js.map +1 -0
  26. package/dist/{chunk-UB63NQQL.js → chunk-GUAJNZIX.js} +2 -2
  27. package/dist/{chunk-UXSYVMPK.js → chunk-HUQRPEDP.js} +2 -2
  28. package/dist/chunk-JG3O5GL6.js +5 -0
  29. package/dist/{chunk-MOQNLS5Z.js.map → chunk-JG3O5GL6.js.map} +1 -1
  30. package/dist/chunk-JXF54PT7.js +2 -0
  31. package/dist/chunk-JXF54PT7.js.map +1 -0
  32. package/dist/chunk-LLNPKE7H.js +11 -0
  33. package/dist/chunk-LLNPKE7H.js.map +1 -0
  34. package/dist/chunk-LTHQXWZN.js +51 -0
  35. package/dist/chunk-LTHQXWZN.js.map +1 -0
  36. package/dist/{chunk-ZR3NZLJL.js → chunk-LUL4ILAQ.js} +2 -2
  37. package/dist/{chunk-N6EWZGIX.js → chunk-PN6XHTG5.js} +6 -6
  38. package/dist/{chunk-N6EWZGIX.js.map → chunk-PN6XHTG5.js.map} +1 -1
  39. package/dist/{chunk-BEHC3X42.js → chunk-R64DAHBH.js} +242 -211
  40. package/dist/chunk-R64DAHBH.js.map +1 -0
  41. package/dist/{chunk-7IGSJGXI.js → chunk-TW4L6RP2.js} +2 -2
  42. package/dist/chunk-UCKKAWLZ.js +2 -0
  43. package/dist/chunk-UCKKAWLZ.js.map +1 -0
  44. package/dist/chunk-V4GXHBOH.js +152 -0
  45. package/dist/chunk-V4GXHBOH.js.map +1 -0
  46. package/dist/{chunk-3UN6CXRL.js → chunk-VVW4JYV6.js} +24 -24
  47. package/dist/chunk-VVW4JYV6.js.map +1 -0
  48. package/dist/{chunk-BVZFYBBP.js → chunk-WWU2D65N.js} +2 -2
  49. package/dist/chunk-XF65CDNS.js +5 -0
  50. package/dist/{chunk-UR3ZIDMA.js.map → chunk-XF65CDNS.js.map} +1 -1
  51. package/dist/{chunk-YCI3KUYF.js → chunk-XQ7MVPWP.js} +7 -7
  52. package/dist/chunk-XQ7MVPWP.js.map +1 -0
  53. package/dist/{chunk-Z3XUGXPD.js → chunk-ZUAV3PTL.js} +2 -2
  54. package/dist/cli.js +1 -1
  55. package/dist/cli.js.map +1 -1
  56. package/dist/client-JDY2FZUF.js +2 -0
  57. package/dist/config-JCETBKWT.js +2 -0
  58. package/dist/config-mutator-YQWTY47O.js +2 -0
  59. package/dist/doctor-6EWW7NC2.js +2 -0
  60. package/dist/{facts-U7BUYRXN.js → facts-5T5GRUTG.js} +6 -6
  61. package/dist/{facts-U7BUYRXN.js.map → facts-5T5GRUTG.js.map} +1 -1
  62. package/dist/{failure-candidates-RIXA3Y6D.js → failure-candidates-PBPF45GN.js} +2 -2
  63. package/dist/index.d.ts +619 -499
  64. package/dist/index.js +1 -1
  65. package/dist/index.js.map +1 -1
  66. package/dist/{chunk-AF46YOLU.js → program-7UH4FCA3.js} +194 -184
  67. package/dist/program-7UH4FCA3.js.map +1 -0
  68. package/dist/promote-ZZWMGVO2.js +2 -0
  69. package/dist/query-OQBB7EFS.js +2 -0
  70. package/dist/registry-MDWD7EAO.js +2 -0
  71. package/dist/request-planner-HX44G2SX.js +2 -0
  72. package/dist/{request-planner-H74KHFGJ.js.map → request-planner-HX44G2SX.js.map} +1 -1
  73. package/dist/review-candidates-FBDLPU6H.js +4 -0
  74. package/dist/{review-candidates-IPJWEXR2.js.map → review-candidates-FBDLPU6H.js.map} +1 -1
  75. package/dist/routing-3SZHWHUA.js +2 -0
  76. package/dist/schedule-tool-5FULSHWJ.js +2 -0
  77. package/dist/scheduler-ITOKSMYT.js +2 -0
  78. package/dist/seat-2HJG3UNW.js +2 -0
  79. package/dist/select-UKAOL7QB.js +2 -0
  80. package/dist/{select-BUWOD47K.js.map → select-UKAOL7QB.js.map} +1 -1
  81. package/dist/set-enabled-ADFSNG5A.js +2 -0
  82. package/dist/{set-enabled-XWSFTICB.js.map → set-enabled-ADFSNG5A.js.map} +1 -1
  83. package/dist/signal-exit-WL7G3EEZ.js +2 -0
  84. package/dist/signal-exit-WL7G3EEZ.js.map +1 -0
  85. package/dist/{surface-usage-HVVP22SA.js → surface-usage-O5L4KLGS.js} +2 -2
  86. package/dist/{tool-VOA4HSVP.js → tool-GPCJM7U5.js} +2 -2
  87. package/dist/{tool-VOA4HSVP.js.map → tool-GPCJM7U5.js.map} +1 -1
  88. package/dist/{tool-GUINJ2BQ.js → tool-VKQIDEG7.js} +2 -2
  89. package/dist/{tool-GUINJ2BQ.js.map → tool-VKQIDEG7.js.map} +1 -1
  90. package/dist/wiki-QUVWB4IN.js +2 -0
  91. package/package.json +1 -1
  92. package/dist/ChatApp-LD4TXJWP.js +0 -7
  93. package/dist/board-dashboard-OS5J3F73.js.map +0 -1
  94. package/dist/chunk-3UN6CXRL.js.map +0 -1
  95. package/dist/chunk-42Y3BXXS.js +0 -15
  96. package/dist/chunk-42Y3BXXS.js.map +0 -1
  97. package/dist/chunk-6JJ3GODZ.js +0 -57
  98. package/dist/chunk-6JJ3GODZ.js.map +0 -1
  99. package/dist/chunk-AF46YOLU.js.map +0 -1
  100. package/dist/chunk-API4IZZG.js +0 -2
  101. package/dist/chunk-API4IZZG.js.map +0 -1
  102. package/dist/chunk-BEHC3X42.js.map +0 -1
  103. package/dist/chunk-MOQNLS5Z.js +0 -5
  104. package/dist/chunk-NOAAK2XI.js +0 -152
  105. package/dist/chunk-NOAAK2XI.js.map +0 -1
  106. package/dist/chunk-OVN5LVJY.js +0 -11
  107. package/dist/chunk-OVN5LVJY.js.map +0 -1
  108. package/dist/chunk-UR3ZIDMA.js +0 -5
  109. package/dist/chunk-WP6KLXTP.js.map +0 -1
  110. package/dist/chunk-YCI3KUYF.js.map +0 -1
  111. package/dist/chunk-Z3IP66SL.js +0 -9
  112. package/dist/client-TJ5YZOEE.js +0 -2
  113. package/dist/config-4WZ7Y34V.js +0 -2
  114. package/dist/config-mutator-5Z7EEB5N.js +0 -2
  115. package/dist/doctor-7K3NRBNN.js +0 -2
  116. package/dist/program-KMQNX6YK.js +0 -2
  117. package/dist/promote-NDC3X54P.js +0 -2
  118. package/dist/query-F7BD3JPE.js +0 -2
  119. package/dist/registry-5NBHBVY3.js +0 -2
  120. package/dist/request-planner-H74KHFGJ.js +0 -2
  121. package/dist/review-candidates-IPJWEXR2.js +0 -4
  122. package/dist/routing-3RSG7SKW.js +0 -2
  123. package/dist/schedule-tool-7NYAK43U.js +0 -2
  124. package/dist/scheduler-24O7PADJ.js +0 -2
  125. package/dist/seat-TOM2WHQR.js +0 -2
  126. package/dist/select-BUWOD47K.js +0 -2
  127. package/dist/set-enabled-XWSFTICB.js +0 -2
  128. package/dist/wiki-VFME4T2H.js +0 -2
  129. package/dist/wiki-VFME4T2H.js.map +0 -1
  130. /package/dist/{agent-FUMJM6OW.js.map → agent-75URYGWI.js.map} +0 -0
  131. /package/dist/{chunk-MYRSNJJ4.js.map → chunk-3FCYKGU6.js.map} +0 -0
  132. /package/dist/{chunk-R42S57G6.js.map → chunk-4KJ3PCAI.js.map} +0 -0
  133. /package/dist/{chunk-BJPIRNP6.js.map → chunk-74FSHUB3.js.map} +0 -0
  134. /package/dist/{chunk-H7253EHW.js.map → chunk-ATXE3EMV.js.map} +0 -0
  135. /package/dist/{chunk-TEFMZY6B.js.map → chunk-BB3ESU74.js.map} +0 -0
  136. /package/dist/{chunk-UB63NQQL.js.map → chunk-GUAJNZIX.js.map} +0 -0
  137. /package/dist/{chunk-UXSYVMPK.js.map → chunk-HUQRPEDP.js.map} +0 -0
  138. /package/dist/{chunk-ZR3NZLJL.js.map → chunk-LUL4ILAQ.js.map} +0 -0
  139. /package/dist/{chunk-7IGSJGXI.js.map → chunk-TW4L6RP2.js.map} +0 -0
  140. /package/dist/{chunk-BVZFYBBP.js.map → chunk-WWU2D65N.js.map} +0 -0
  141. /package/dist/{chunk-Z3XUGXPD.js.map → chunk-ZUAV3PTL.js.map} +0 -0
  142. /package/dist/{client-TJ5YZOEE.js.map → client-JDY2FZUF.js.map} +0 -0
  143. /package/dist/{config-4WZ7Y34V.js.map → config-JCETBKWT.js.map} +0 -0
  144. /package/dist/{config-mutator-5Z7EEB5N.js.map → config-mutator-YQWTY47O.js.map} +0 -0
  145. /package/dist/{doctor-7K3NRBNN.js.map → doctor-6EWW7NC2.js.map} +0 -0
  146. /package/dist/{failure-candidates-RIXA3Y6D.js.map → failure-candidates-PBPF45GN.js.map} +0 -0
  147. /package/dist/{program-KMQNX6YK.js.map → promote-ZZWMGVO2.js.map} +0 -0
  148. /package/dist/{promote-NDC3X54P.js.map → query-OQBB7EFS.js.map} +0 -0
  149. /package/dist/{query-F7BD3JPE.js.map → registry-MDWD7EAO.js.map} +0 -0
  150. /package/dist/{registry-5NBHBVY3.js.map → routing-3SZHWHUA.js.map} +0 -0
  151. /package/dist/{routing-3RSG7SKW.js.map → schedule-tool-5FULSHWJ.js.map} +0 -0
  152. /package/dist/{schedule-tool-7NYAK43U.js.map → scheduler-ITOKSMYT.js.map} +0 -0
  153. /package/dist/{scheduler-24O7PADJ.js.map → seat-2HJG3UNW.js.map} +0 -0
  154. /package/dist/{seat-TOM2WHQR.js.map → surface-usage-O5L4KLGS.js.map} +0 -0
  155. /package/dist/{surface-usage-HVVP22SA.js.map → wiki-QUVWB4IN.js.map} +0 -0
@@ -1,11 +0,0 @@
1
- import{a as h,b as m}from"./chunk-SHEUCITK.js";import{randomUUID as y}from"crypto";var A=["ringing","answered","later"],p=`id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,
2
- ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,
3
- ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`,f=class{constructor(e){this.db=e;e.exec(`CREATE TABLE IF NOT EXISTS calls (
4
- id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,
5
- urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,
6
- ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,
7
- ring_again_at INTEGER, note TEXT, summary TEXT);
8
- CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`);let s=new Set(e.prepare("PRAGMA table_info(calls)").all().map(t=>t.name));s.has("kind")||e.exec("ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'"),s.has("channel")||e.exec("ALTER TABLE calls ADD COLUMN channel TEXT"),s.has("chat_id")||e.exec("ALTER TABLE calls ADD COLUMN chat_id TEXT")}insert(e){this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,
9
- answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(e.id,e.agentId,e.kind,e.reason,e.urgency,e.status,e.createdAt,e.ringingSince,e.answeredAt,e.endedAt,e.ringAgainAt,e.note,e.summary,e.channel,e.chatId)}get(e){return this.db.prepare(`SELECT ${p} FROM calls WHERE id=?`).get(e)}update(e,s){let t={reason:"reason",urgency:"urgency",status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},n=Object.keys(s).filter(r=>r in t);if(n.length){let r=n.map(a=>`${t[a]}=?`).join(", ");this.db.prepare(`UPDATE calls SET ${r} WHERE id=?`).run(...n.map(a=>s[a]??null),e)}return this.get(e)}transition(e,s,t){let n=Array.isArray(s)?s:[s],r={status:"status",ringingSince:"ringing_since",answeredAt:"answered_at",endedAt:"ended_at",ringAgainAt:"ring_again_at",note:"note",summary:"summary"},a=Object.keys(t).filter(o=>o in r),l=a.map(o=>`${r[o]}=?`).join(", "),g=n.map(()=>"?").join(",");return this.db.prepare(`UPDATE calls SET ${l} WHERE id=? AND status IN (${g})`).run(...a.map(o=>t[o]??null),e,...n).changes?this.get(e):void 0}list(e={}){let s=Math.min(Math.max(e.limit??50,1),200),t=[],n=[];e.status?.length&&(t.push(`status IN (${e.status.map(()=>"?").join(",")})`),n.push(...e.status)),e.kind&&(t.push("kind=?"),n.push(e.kind));let r=t.length?`WHERE ${t.join(" AND ")}`:"";return this.db.prepare(`SELECT ${p} FROM calls ${r} ORDER BY created_at DESC, rowid DESC LIMIT ?`).all(...n,s)}countSince(e,s){return this.db.prepare("SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?").get(e,s).n}};var w=200,k=1e4,S=10,E=240;function b(i=process.env){return i.AGENTX_TASK_ID?{"X-AgentX-Task":i.AGENTX_TASK_ID}:i.AGENTX_CHANNEL&&i.AGENTX_CHAT_ID?{"X-AgentX-Channel":i.AGENTX_CHANNEL,"X-AgentX-Chat":i.AGENTX_CHAT_ID}:{}}function _(i){return`[Call answered] The owner just picked up the voice call you asked for. You called because: "${i.reason}". Speak first: greet them in a few words and say why you called, then let them answer.`}var v="[Call ended] The owner hung up. In two or three plain sentences, summarise what was said and decided on this call, for your records. Reply with the summary only.",T=class{constructor(e){this.deps=e}widgetSeenAt=0;now(){return this.deps.now?.()??Date.now()}name(e){return this.deps.agentName(e)??e}async request(e,s={}){let t=String(e.agentId??"").trim(),n=String(e.reason??"").replace(/\s+/g," ").trim(),r=e.urgency==="urgent"?"urgent":"normal",a=e.kind==="camera"?"camera":"voice";if(e.kind!==void 0&&e.kind!=="voice"&&e.kind!=="camera")return{ok:!1,status:400,error:"kind must be voice or camera"};if(!t||!n)return{ok:!1,status:400,error:"Required: agentId and reason"};if(n.length>w)return{ok:!1,status:413,error:`reason is over ${w} characters; keep it to one line`};if(this.deps.agentName(t)===null)return{ok:!1,status:404,error:`Unknown agent: ${t}`};if(!this.deps.isRunningTurn(t,s))return{ok:!1,status:403,error:`No running turn of ${t} placed this call. An agent calls from inside its own run.`};let l=this.deps.config();if(!l.allow.includes("*")&&!l.allow.includes(t))return{ok:!1,status:403,error:`${t} ${a==="camera"?"may not ask to see through the owner's camera":"may not call the owner"}. Add it to calls.allow in agentx.json (or: agentx call allow ${t}).`};if(await this.sweep(),this.deps.store.list({status:A,limit:200}).some(c=>c.agentId===t))return{ok:!1,status:409,error:`${t} already has a call in progress`};let g=this.now();if(this.deps.store.countSince(t,g-36e5)>=l.maxPerHour)return{ok:!1,status:429,error:`${t} has placed ${l.maxPerHour} calls in the last hour (calls.maxPerHour)`};let d=a==="camera"?this.deps.turnSession?.(t,s)??s:{},o={id:`call-${y().slice(0,8)}`,agentId:t,kind:a,reason:n,urgency:r,status:"ringing",createdAt:g,ringingSince:g,answeredAt:null,endedAt:null,ringAgainAt:null,note:null,summary:null,channel:d.channel&&d.chatId?d.channel:null,chatId:d.channel&&d.chatId?d.chatId:null};this.deps.store.insert(o),this.deps.log?.(`[calls] ${t} asks ${a==="camera"?"to see":"for a call"} (${r}): ${n}`);let C=await this.ring(o);return{ok:!0,call:this.deps.store.get(o.id),rang:C}}async ring(e){let s=(this.deps.focus??h)();return s.active&&e.urgency!=="urgent"?(this.deps.store.transition(e.id,"ringing",{status:"missed",ringingSince:null,note:m(s)})&&await this.notice(e,this.missedTitle(e)),!1):e.kind==="camera"?(await this.notice(e,`${this.name(e.agentId)} wants to see through your camera`,`Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`),"notify"):this.widgetAlive()?"widget":(await this.notice(e,`${this.name(e.agentId)} is calling`,`Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`),"notify")}async notice(e,s,t){try{await this.deps.alert({title:s,message:t?`${e.reason}
10
- ${t}`:e.reason,urgent:e.urgency==="urgent",from:e.agentId})}catch(n){this.deps.log?.(`[calls] notice for ${e.id} failed: ${n?.message??n}`)}}missedTitle(e){return e.kind==="camera"?`${this.name(e.agentId)} asked to see through your camera`:`Missed call from ${this.name(e.agentId)}`}widgetAlive(){return this.now()-this.widgetSeenAt<k}async ringing(){return this.widgetSeenAt=this.now(),await this.sweep(),this.deps.store.list({status:["ringing"],kind:"voice",limit:20}).reverse()}async asking(){return await this.sweep(),this.deps.store.list({status:["ringing"],kind:"camera",limit:20}).reverse()}async sweep(){let e=this.now(),s=this.deps.config().ringSeconds*1e3,t=this.deps.config().maxCallMinutes*6e4;for(let n of this.deps.store.list({status:["ringing","later","answered"],limit:200}))if(n.status==="ringing"&&n.ringingSince!==null&&e-n.ringingSince>=s){if(!this.deps.store.transition(n.id,"ringing",{status:"missed",ringingSince:null,note:"not answered"}))continue;this.deps.log?.(`[calls] ${n.id} from ${n.agentId} missed`),await this.notice(n,this.missedTitle(n))}else if(n.status==="answered"&&n.answeredAt!==null&&e-n.answeredAt>=t){if(!this.deps.store.transition(n.id,"answered",{status:"ended",endedAt:e,note:"no hang-up"}))continue;this.deps.log?.(`[calls] ${n.id} from ${n.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)}else if(n.status==="later"&&n.ringAgainAt!==null&&e>=n.ringAgainAt){let r=this.deps.store.transition(n.id,"later",{status:"ringing",ringingSince:e,ringAgainAt:null});r&&await this.ring(r)}}answer(e){let s=this.deps.store.get(e);if(!s)return u(e);let t=this.deps.store.transition(e,"ringing",{status:"answered",answeredAt:this.now(),ringingSince:null});return t?(this.deps.log?.(`[calls] ${e} answered (${s.agentId})`),t.kind==="camera"?{ok:!0,call:t}:{ok:!0,call:t,opener:_(t)}):{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}, not ringing`}}decline(e){if(!this.deps.store.get(e))return u(e);let t=this.deps.store.transition(e,["ringing","later"],{status:"declined",endedAt:this.now(),ringingSince:null,ringAgainAt:null});return t?{ok:!0,call:t}:{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}`}}later(e,s){if(!this.deps.store.get(e))return u(e);let n=s===void 0?S:Number(s);if(!Number.isInteger(n)||n<1||n>E)return{ok:!1,status:400,error:`minutes must be a whole number from 1 to ${E}`};let r=this.deps.store.transition(e,"ringing",{status:"later",ringingSince:null,ringAgainAt:this.now()+n*6e4});return r?{ok:!0,call:r}:{ok:!1,status:409,error:`call is ${this.deps.store.get(e)?.status}, not ringing`}}hangup(e){let s=this.deps.store.get(e);if(!s)return u(e);let t=this.deps.store.transition(e,"answered",{status:"ended",endedAt:this.now()});if(!t)return{ok:!1,status:409,error:`call is ${s.status}, not answered`};this.deps.log?.(`[calls] ${e} ended (${s.agentId})`);let n=this.deps.summarize;if(t.kind==="camera"||!this.deps.config().summary||!n)return{ok:!0,call:t};let r=(async()=>{try{let a=(await n(t))?.trim();if(!a)return;let l=this.deps.store.update(e,{summary:a});this.deps.file?.(l,a)}catch(a){this.deps.log?.(`[calls] summary for ${e} failed: ${a?.message??a}`)}})();return{ok:!0,call:t,summarized:r}}endCamera(e,s){let t=this.deps.store.get(e);if(!t||t.kind!=="camera")return!1;let n=this.deps.store.transition(e,"answered",{status:"ended",endedAt:this.now(),note:s??null});return n&&this.deps.log?.(`[calls] ${e} ended (${t.agentId}): ${s??"share over"}`),!!n}get(e){return this.deps.store.get(e)}list(e={}){return this.deps.store.list(e)}},u=i=>({ok:!1,status:404,error:`No such call: ${i}`});export{f as a,b,v as c,T as d};
11
- //# sourceMappingURL=chunk-OVN5LVJY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/calls/service.ts","../src/calls/store.ts"],"sourcesContent":["// --- An agent rings the owner (#321) ---\n//\n// An agent that needs the owner directly asks for a call. It rings on the\n// desktop widget (AgentX Voice), which polls `ringing()`. Answering starts\n// the widget's hands-free conversation with that agent, which opens with\n// its reason. When the widget is not running, `notify` stands in.\n//\n// Checked before anything rings, in this order:\n// 0. the caller is that agent: a turn of it is running now, named by its\n// task id or by its channel and chat (see CallerProof),\n// 1. the owner allows this agent (calls.allow; empty allows nobody),\n// 2. the agent has no other call in progress,\n// 3. it is under calls.maxPerHour,\n// 4. Focus: a non-urgent call does not ring. It becomes a missed call,\n// and its notice goes through notify, which holds it until Focus\n// ends. Urgent calls ring through, as `notify --urgent` does.\n//\n// A camera ask (#325 phase 3, kind \"camera\") goes through the same checks\n// and the same table. It never rings the widget: the notice goes to the\n// phone through notify, and the phone app polls `asking()` to show a\n// Show / Decline bar. Answering it is the owner tapping Show; the camera\n// opens only then, and the share ends the ask (see camera-api.ts).\n\nimport { randomUUID } from \"crypto\"\nimport { focusLabel, readFocus, type FocusState } from \"@/notify/focus\"\nimport type { CallsConfig } from \"@/daemon/config\"\nimport { LIVE, type Call, type CallKind, type CallStore, type CallUrgency } from \"./store\"\n\nexport const REASON_MAX = 200\n/** The widget polls every 2 s; missing this long means it is not running. */\nexport const WIDGET_FRESH_MS = 10_000\nexport const LATER_DEFAULT_MINUTES = 10\nexport const LATER_MAX_MINUTES = 240\n\nexport type CallResult =\n | { ok: true; call: Call }\n | { ok: false; status: number; error: string }\n\n/** What the request says about the turn placing it: the run's\n * AGENTX_TASK_ID, or, for a warm process that has none, its\n * AGENTX_CHANNEL and AGENTX_CHAT_ID. Loopback is not an identity. */\nexport interface CallerProof {\n taskId?: string\n channel?: string\n chatId?: string\n}\n\n/** The proof headers for a call placed from inside an agent's run. */\nexport function callerHeaders(env: NodeJS.ProcessEnv = process.env): Record<string, string> {\n if (env.AGENTX_TASK_ID) return { \"X-AgentX-Task\": env.AGENTX_TASK_ID }\n if (env.AGENTX_CHANNEL && env.AGENTX_CHAT_ID) {\n return { \"X-AgentX-Channel\": env.AGENTX_CHANNEL, \"X-AgentX-Chat\": env.AGENTX_CHAT_ID }\n }\n return {}\n}\n\nexport interface CallDeps {\n store: CallStore\n config: () => CallsConfig\n /** The agent's display name, or null when there is no such agent here. */\n agentName: (agentId: string) => string | null\n /** True when `proof` names a running turn of `agentId`. */\n isRunningTurn: (agentId: string, proof: CallerProof) => boolean\n /** The channel and chat of that running turn, when it has one, so a\n * camera ask is answered where it was asked. Unset: only a proof that\n * names them itself is kept. */\n turnSession?: (agentId: string, proof: CallerProof) => { channel?: string; chatId?: string } | null\n /** Tell the owner through notify. `urgent` passes Focus, like notify --urgent. */\n alert: (notice: { title: string; message: string; urgent: boolean; from: string }) => Promise<void>\n /** Ask the agent, in its voice session, to summarise the call. */\n summarize?: (call: Call) => Promise<string | null>\n /** File a finished summary where the dashboard shows it. */\n file?: (call: Call, summary: string) => void\n focus?: () => FocusState\n now?: () => number\n log?: (m: string) => void\n}\n\n/** What the widget sends through /ask when the owner answers, so the\n * agent speaks first and says why it called. */\nexport function openerPrompt(call: Pick<Call, \"reason\">): string {\n return \"[Call answered] The owner just picked up the voice call you asked for. \" +\n `You called because: \"${call.reason}\". Speak first: greet them in a few words ` +\n \"and say why you called, then let them answer.\"\n}\n\nexport const SUMMARY_PROMPT =\n \"[Call ended] The owner hung up. In two or three plain sentences, summarise what \" +\n \"was said and decided on this call, for your records. Reply with the summary only.\"\n\nexport class CallService {\n private widgetSeenAt = 0\n\n constructor(private deps: CallDeps) {}\n\n private now(): number { return this.deps.now?.() ?? Date.now() }\n private name(agentId: string): string { return this.deps.agentName(agentId) ?? agentId }\n\n /** An agent asks for a call, or to see (kind \"camera\"). 201 ringing,\n * 202 held as missed (Focus). */\n async request(input: { agentId?: unknown; reason?: unknown; urgency?: unknown; kind?: unknown }, proof: CallerProof = {}): Promise<CallResult & { rang?: \"widget\" | \"notify\" | false }> {\n const agentId = String(input.agentId ?? \"\").trim()\n const reason = String(input.reason ?? \"\").replace(/\\s+/g, \" \").trim()\n const urgency: CallUrgency = input.urgency === \"urgent\" ? \"urgent\" : \"normal\"\n const kind: CallKind = input.kind === \"camera\" ? \"camera\" : \"voice\"\n if (input.kind !== undefined && input.kind !== \"voice\" && input.kind !== \"camera\") return { ok: false, status: 400, error: \"kind must be voice or camera\" }\n if (!agentId || !reason) return { ok: false, status: 400, error: \"Required: agentId and reason\" }\n if (reason.length > REASON_MAX) return { ok: false, status: 413, error: `reason is over ${REASON_MAX} characters; keep it to one line` }\n if (this.deps.agentName(agentId) === null) return { ok: false, status: 404, error: `Unknown agent: ${agentId}` }\n if (!this.deps.isRunningTurn(agentId, proof)) {\n return { ok: false, status: 403, error: `No running turn of ${agentId} placed this call. An agent calls from inside its own run.` }\n }\n\n const cfg = this.deps.config()\n if (!cfg.allow.includes(\"*\") && !cfg.allow.includes(agentId)) {\n const verb = kind === \"camera\" ? \"may not ask to see through the owner's camera\" : \"may not call the owner\"\n return { ok: false, status: 403, error: `${agentId} ${verb}. Add it to calls.allow in agentx.json (or: agentx call allow ${agentId}).` }\n }\n await this.sweep()\n if (this.deps.store.list({ status: LIVE, limit: 200 }).some((c) => c.agentId === agentId)) {\n return { ok: false, status: 409, error: `${agentId} already has a call in progress` }\n }\n const now = this.now()\n if (this.deps.store.countSince(agentId, now - 3_600_000) >= cfg.maxPerHour) {\n return { ok: false, status: 429, error: `${agentId} has placed ${cfg.maxPerHour} calls in the last hour (calls.maxPerHour)` }\n }\n\n // Where the ask came from, for kind \"camera\": the turn's own chat, or\n // the one the proof names. A task run has neither.\n const session: { channel?: string; chatId?: string } = kind === \"camera\" ? (this.deps.turnSession?.(agentId, proof) ?? proof) : {}\n const call: Call = {\n id: `call-${randomUUID().slice(0, 8)}`, agentId, kind, reason, urgency, status: \"ringing\", createdAt: now,\n ringingSince: now, answeredAt: null, endedAt: null, ringAgainAt: null, note: null, summary: null,\n channel: session.channel && session.chatId ? session.channel : null,\n chatId: session.channel && session.chatId ? session.chatId : null,\n }\n this.deps.store.insert(call)\n this.deps.log?.(`[calls] ${agentId} asks ${kind === \"camera\" ? \"to see\" : \"for a call\"} (${urgency}): ${reason}`)\n const rang = await this.ring(call)\n const saved = this.deps.store.get(call.id)!\n return { ok: true, call: saved, rang }\n }\n\n /** Ring now, or hold as missed in Focus. Returns how it rang. */\n private async ring(call: Call): Promise<\"widget\" | \"notify\" | false> {\n const focus = (this.deps.focus ?? readFocus)()\n if (focus.active && call.urgency !== \"urgent\") {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: focusLabel(focus) })) return false\n await this.notice(call, this.missedTitle(call))\n return false\n }\n // A camera ask is answered on the phone, never on the widget.\n if (call.kind === \"camera\") {\n await this.notice(call, `${this.name(call.agentId)} wants to see through your camera`,\n `Open the phone app and tap Show within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n if (this.widgetAlive()) return \"widget\"\n await this.notice(call, `${this.name(call.agentId)} is calling`,\n `Open AgentX Voice to answer within ${this.deps.config().ringSeconds} s.`)\n return \"notify\"\n }\n\n private async notice(call: Call, title: string, extra?: string): Promise<void> {\n try {\n await this.deps.alert({\n title, message: extra ? `${call.reason}\\n${extra}` : call.reason,\n urgent: call.urgency === \"urgent\", from: call.agentId,\n })\n } catch (e: any) {\n this.deps.log?.(`[calls] notice for ${call.id} failed: ${e?.message ?? e}`)\n }\n }\n\n private missedTitle(call: Call): string {\n return call.kind === \"camera\" ? `${this.name(call.agentId)} asked to see through your camera` : `Missed call from ${this.name(call.agentId)}`\n }\n\n /** True when the widget polled recently. */\n widgetAlive(): boolean {\n return this.now() - this.widgetSeenAt < WIDGET_FRESH_MS\n }\n\n /** The widget's poll: voice calls ringing now, oldest first. Marks it alive. */\n async ringing(): Promise<Call[]> {\n this.widgetSeenAt = this.now()\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"voice\", limit: 20 }).reverse()\n }\n\n /** The phone app's poll: camera asks waiting for the owner, oldest first.\n * Does not count as the widget being up. */\n async asking(): Promise<Call[]> {\n await this.sweep()\n return this.deps.store.list({ status: [\"ringing\"], kind: \"camera\", limit: 20 }).reverse()\n }\n\n /** Unanswered calls become missed; \"later\" calls that came due ring\n * again; answered calls nobody hung up end after calls.maxCallMinutes. */\n async sweep(): Promise<void> {\n const now = this.now()\n const ringFor = this.deps.config().ringSeconds * 1000\n const talkFor = this.deps.config().maxCallMinutes * 60_000\n for (const call of this.deps.store.list({ status: [\"ringing\", \"later\", \"answered\"], limit: 200 })) {\n // The list was read before any await below: each move re-checks the\n // status in the store, so a call answered meanwhile is left alone.\n if (call.status === \"ringing\" && call.ringingSince !== null && now - call.ringingSince >= ringFor) {\n if (!this.deps.store.transition(call.id, \"ringing\", { status: \"missed\", ringingSince: null, note: \"not answered\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} missed`)\n await this.notice(call, this.missedTitle(call))\n } else if (call.status === \"answered\" && call.answeredAt !== null && now - call.answeredAt >= talkFor) {\n if (!this.deps.store.transition(call.id, \"answered\", { status: \"ended\", endedAt: now, note: \"no hang-up\" })) continue\n this.deps.log?.(`[calls] ${call.id} from ${call.agentId} ended: no hang-up in ${this.deps.config().maxCallMinutes} min`)\n } else if (call.status === \"later\" && call.ringAgainAt !== null && now >= call.ringAgainAt) {\n const again = this.deps.store.transition(call.id, \"later\", { status: \"ringing\", ringingSince: now, ringAgainAt: null })\n if (again) await this.ring(again)\n }\n }\n }\n\n /** The owner picked up, or tapped Show. Returns the call and, for a\n * voice call, the opener for /ask. */\n answer(id: string): CallResult & { opener?: string } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const answered = this.deps.store.transition(id, \"ringing\", { status: \"answered\", answeredAt: this.now(), ringingSince: null })\n if (!answered) return { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n this.deps.log?.(`[calls] ${id} answered (${call.agentId})`)\n return answered.kind === \"camera\" ? { ok: true, call: answered } : { ok: true, call: answered, opener: openerPrompt(answered) }\n }\n\n decline(id: string): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const declined = this.deps.store.transition(id, [\"ringing\", \"later\"], { status: \"declined\", endedAt: this.now(), ringingSince: null, ringAgainAt: null })\n return declined ? { ok: true, call: declined } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}` }\n }\n\n /** \"Call back in N min\": it rings again then. */\n later(id: string, minutes?: unknown): CallResult {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const n = minutes === undefined ? LATER_DEFAULT_MINUTES : Number(minutes)\n if (!Number.isInteger(n) || n < 1 || n > LATER_MAX_MINUTES) {\n return { ok: false, status: 400, error: `minutes must be a whole number from 1 to ${LATER_MAX_MINUTES}` }\n }\n const later = this.deps.store.transition(id, \"ringing\", { status: \"later\", ringingSince: null, ringAgainAt: this.now() + n * 60_000 })\n return later ? { ok: true, call: later } : { ok: false, status: 409, error: `call is ${this.deps.store.get(id)?.status}, not ringing` }\n }\n\n /** End an answered call. The summary is written in the background;\n * `summarized` settles when it is filed (tests wait on it). */\n hangup(id: string): CallResult & { summarized?: Promise<void> } {\n const call = this.deps.store.get(id)\n if (!call) return unknown(id)\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now() })\n if (!ended) return { ok: false, status: 409, error: `call is ${call.status}, not answered` }\n this.deps.log?.(`[calls] ${id} ended (${call.agentId})`)\n const summarize = this.deps.summarize\n // What the agent saw is already its answer; only a voice call is summarised.\n if (ended.kind === \"camera\" || !this.deps.config().summary || !summarize) return { ok: true, call: ended }\n const summarized = (async () => {\n try {\n const text = (await summarize(ended))?.trim()\n if (!text) return\n const done = this.deps.store.update(id, { summary: text })!\n this.deps.file?.(done, text)\n } catch (e: any) {\n this.deps.log?.(`[calls] summary for ${id} failed: ${e?.message ?? e}`)\n }\n })()\n return { ok: true, call: ended, summarized }\n }\n\n /** A camera ask ends when the share ends; no summary. Only an answered\n * ask ends this way, so a stop before Show leaves it ringing. */\n endCamera(id: string, note?: string): boolean {\n const call = this.deps.store.get(id)\n if (!call || call.kind !== \"camera\") return false\n const ended = this.deps.store.transition(id, \"answered\", { status: \"ended\", endedAt: this.now(), note: note ?? null })\n if (ended) this.deps.log?.(`[calls] ${id} ended (${call.agentId}): ${note ?? \"share over\"}`)\n return !!ended\n }\n\n get(id: string): Call | undefined { return this.deps.store.get(id) }\n\n list(opts: Parameters<CallStore[\"list\"]>[0] = {}): Call[] { return this.deps.store.list(opts) }\n}\n\nconst unknown = (id: string): CallResult => ({ ok: false, status: 404, error: `No such call: ${id}` })\n","// --- Calls an agent placed to the owner, kept in SQLite ---\n//\n// One row per call, so a missed call is still there after a restart and\n// the dashboard can list them. Nothing else reads this table. A camera\n// ask (#325 phase 3: \"show me\") is a call of kind \"camera\": same\n// allowlist, same hourly limit, same lifecycle, answered on the phone\n// instead of the voice widget.\n\nimport type Database from \"better-sqlite3\"\n\nexport type CallStatus = \"ringing\" | \"answered\" | \"ended\" | \"declined\" | \"missed\" | \"later\"\nexport type CallUrgency = \"normal\" | \"urgent\"\n/** \"voice\": a live voice call on the widget. \"camera\": the agent asks to see through the phone camera. */\nexport type CallKind = \"voice\" | \"camera\"\n\nexport interface Call {\n id: string\n agentId: string\n kind: CallKind\n reason: string\n urgency: CallUrgency\n status: CallStatus\n /** The channel and chat the asking turn ran in, so what the agent sees\n * is answered there; null when the turn had none (a task run). */\n channel: string | null\n chatId: string | null\n /** When the agent asked, ms since the epoch. */\n createdAt: number\n /** When it last started ringing: at the request, or when \"later\" came due. */\n ringingSince: number | null\n answeredAt: number | null\n endedAt: number | null\n /** Status \"later\": when it rings again. */\n ringAgainAt: number | null\n /** Why it ended the way it did, in a few words (\"in Focus\", \"not answered\"). */\n note: string | null\n /** The agent's own summary, written after hang-up. */\n summary: string | null\n}\n\n/** Calls still in progress: an agent has at most one of these. */\nexport const LIVE: CallStatus[] = [\"ringing\", \"answered\", \"later\"]\n\nconst COLUMNS = `id, agent_id AS agentId, kind, reason, urgency, status, created_at AS createdAt,\n ringing_since AS ringingSince, answered_at AS answeredAt, ended_at AS endedAt,\n ring_again_at AS ringAgainAt, note, summary, channel, chat_id AS chatId`\n\nexport class CallStore {\n constructor(private db: Database.Database) {\n db.exec(`CREATE TABLE IF NOT EXISTS calls (\n id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, reason TEXT NOT NULL,\n urgency TEXT NOT NULL, status TEXT NOT NULL, created_at INTEGER NOT NULL,\n ringing_since INTEGER, answered_at INTEGER, ended_at INTEGER,\n ring_again_at INTEGER, note TEXT, summary TEXT);\n CREATE INDEX IF NOT EXISTS calls_recent ON calls(created_at DESC);`)\n // Columns added since the table first shipped (#325 phase 3). A row\n // from before is a voice call from a turn whose chat was not kept.\n const have = new Set((db.prepare(\"PRAGMA table_info(calls)\").all() as Array<{ name: string }>).map((c) => c.name))\n if (!have.has(\"kind\")) db.exec(\"ALTER TABLE calls ADD COLUMN kind TEXT NOT NULL DEFAULT 'voice'\")\n if (!have.has(\"channel\")) db.exec(\"ALTER TABLE calls ADD COLUMN channel TEXT\")\n if (!have.has(\"chat_id\")) db.exec(\"ALTER TABLE calls ADD COLUMN chat_id TEXT\")\n }\n\n insert(call: Call): void {\n this.db.prepare(`INSERT INTO calls (id, agent_id, kind, reason, urgency, status, created_at, ringing_since,\n answered_at, ended_at, ring_again_at, note, summary, channel, chat_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(\n call.id, call.agentId, call.kind, call.reason, call.urgency, call.status, call.createdAt,\n call.ringingSince, call.answeredAt, call.endedAt, call.ringAgainAt, call.note, call.summary, call.channel, call.chatId)\n }\n\n get(id: string): Call | undefined {\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls WHERE id=?`).get(id) as Call | undefined\n }\n\n /** Write the changed fields of one call. */\n update(id: string, patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const cols: Record<string, string> = {\n reason: \"reason\", urgency: \"urgency\", status: \"status\", ringingSince: \"ringing_since\",\n answeredAt: \"answered_at\", endedAt: \"ended_at\", ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n if (keys.length) {\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \")\n this.db.prepare(`UPDATE calls SET ${set} WHERE id=?`).run(...keys.map((k) => (patch as any)[k] ?? null), id)\n }\n return this.get(id)\n }\n\n /** Change a call only if it is still `from`: the check and the write are\n * one statement, so two sweeps, or a sweep and the owner answering,\n * cannot both move the same call. Undefined when it had moved on. */\n transition(id: string, from: CallStatus | CallStatus[], patch: Partial<Omit<Call, \"id\" | \"agentId\" | \"createdAt\">>): Call | undefined {\n const statuses = Array.isArray(from) ? from : [from]\n const cols: Record<string, string> = {\n status: \"status\", ringingSince: \"ringing_since\", answeredAt: \"answered_at\", endedAt: \"ended_at\",\n ringAgainAt: \"ring_again_at\", note: \"note\", summary: \"summary\",\n }\n const keys = Object.keys(patch).filter((k) => k in cols)\n const set = keys.map((k) => `${cols[k]}=?`).join(\", \")\n const marks = statuses.map(() => \"?\").join(\",\")\n const changed = this.db.prepare(`UPDATE calls SET ${set} WHERE id=? AND status IN (${marks})`)\n .run(...keys.map((k) => (patch as any)[k] ?? null), id, ...statuses).changes\n return changed ? this.get(id) : undefined\n }\n\n /** Newest first; only these statuses, and only this kind, when given. */\n list(opts: { status?: CallStatus[]; kind?: CallKind; limit?: number } = {}): Call[] {\n const limit = Math.min(Math.max(opts.limit ?? 50, 1), 200)\n const where: string[] = []\n const args: unknown[] = []\n if (opts.status?.length) {\n where.push(`status IN (${opts.status.map(() => \"?\").join(\",\")})`)\n args.push(...opts.status)\n }\n if (opts.kind) { where.push(\"kind=?\"); args.push(opts.kind) }\n const filter = where.length ? `WHERE ${where.join(\" AND \")}` : \"\"\n return this.db.prepare(`SELECT ${COLUMNS} FROM calls ${filter} ORDER BY created_at DESC, rowid DESC LIMIT ?`)\n .all(...args, limit) as Call[]\n }\n\n /** Calls this agent placed after `since` (ms), for the hourly limit. */\n countSince(agentId: string, since: number): number {\n return (this.db.prepare(\"SELECT COUNT(*) AS n FROM calls WHERE agent_id=? AND created_at>?\")\n .get(agentId, since) as { n: number }).n\n }\n}\n"],"mappings":"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","names":["randomUUID","LIVE","COLUMNS","CallStore","db","have","c","call","id","patch","cols","keys","k","set","from","statuses","marks","opts","limit","where","args","filter","agentId","since","REASON_MAX","WIDGET_FRESH_MS","LATER_DEFAULT_MINUTES","LATER_MAX_MINUTES","callerHeaders","env","openerPrompt","call","SUMMARY_PROMPT","CallService","deps","agentId","input","proof","reason","urgency","kind","cfg","LIVE","now","session","randomUUID","rang","focus","readFocus","focusLabel","title","extra","e","ringFor","talkFor","again","id","unknown","answered","declined","minutes","later","ended","summarize","summarized","text","done","note","opts"]}
@@ -1,5 +0,0 @@
1
- import{D as m,E as $,I as x}from"./chunk-42Y3BXXS.js";x();import{readFileSync as S,writeFileSync as P,existsSync as b}from"fs";import{resolve as f}from"path";function w(r){if(r)return f(r);let e=[f(process.cwd(),"agentx.json"),f(process.cwd(),".agentx/config.json")];for(let n of e)if(b(n))return n;return e[0]}function v(r){return JSON.parse(JSON.stringify(r))}async function O(r){try{let e=await fetch(`${r.replace(/\/$/,"")}/reload`,{method:"POST",signal:AbortSignal.timeout(3e3)});return e.ok?{ok:!0}:{ok:!1,reason:`HTTP ${e.status}`}}catch(e){return{ok:!1,reason:e?.cause?.code||e?.message||"unreachable"}}}async function J(r,e={}){let{validate:n=!0,dryRun:t=!1,reload:s=!0,configPath:u,daemonUrl:c}=e,o=w(u);if(!b(o))return{success:!1,path:o,error:`Config not found at ${o}. Run \`agentx init\` first.`};let d;try{d=S(o,"utf-8")}catch(a){return{success:!1,path:o,error:`Cannot read ${o}: ${a.message}`}}let g;try{g=JSON.parse(d)}catch(a){return{success:!1,path:o,error:`Invalid JSON in ${o}: ${a.message}`}}let i=v(g);try{await r(i)}catch(a){return{success:!1,path:o,error:`Mutator threw: ${a.message}`}}if(n){let a=$(i),l=m.safeParse(a);if(!l.success){let k=l.error.issues.map(y=>` ${y.path.join(".")||"<root>"}: ${y.message}`).join(`
2
- `);return{success:!1,path:o,error:`Validation failed:
3
- ${k}`,after:i}}}if(t)return{success:!0,path:o,after:i,dryRun:!0};try{P(o,JSON.stringify(i,null,2)+`
4
- `)}catch(a){return{success:!1,path:o,error:`Write failed: ${a.message}`,after:i}}let p=!1,h;if(s){let a=c||R(i),l=await O(a);l.ok?p=!0:h=l.reason}return{success:!0,path:o,after:i,reloaded:p,reloadSkipped:h}}function R(r){let e=r?.node?.bind;if(!e)return"http://127.0.0.1:18800";let[n,t]=e.split(":");return`http://${n==="0.0.0.0"||n==="::"?"127.0.0.1":n}:${t}`}function N(r,e,n){let t=e.split("."),s=r;for(let u=0;u<t.length-1;u++){let c=t[u];(s[c]===void 0||s[c]===null)&&(s[c]={}),s=s[c]}s[t[t.length-1]]=n}function j(r,e){let n=e.split("."),t=r;for(let s of n){if(t==null)return;t=t[s]}return t}function A(r,e){let n=e.split("."),t=r;for(let s=0;s<n.length-1;s++){if(t==null)return;t=t[n[s]]}t!=null&&delete t[n[n.length-1]]}export{w as a,J as b,N as c,j as d,A as e};
5
- //# sourceMappingURL=chunk-UR3ZIDMA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/agents/injected-context.ts","../src/storage/traces.ts"],"sourcesContent":["import type { InjectedContext } from \"@/storage/traces\"\n\n// --- Injected lessons per task (#98) ---\n//\n// Which memory facts, procedures and wiki catalog actually reached the\n// prompt. Candidates are not enough: the request-context selector can drop\n// a whole layer, and the layer budgets in buildAgentContext can cut a layer\n// short. So a lesson counts as injected only when its text is in the\n// assembled context. Only ids are recorded, never content, and the lists\n// are capped, so the trace row stays small.\n\nexport const MAX_INJECTED_IDS = 20\nconst MAX_ID_LENGTH = 80\n\nexport interface InjectionCandidates {\n memory?: Array<{ id: string; content: string }>\n procedures?: Array<{ id: string; title: string }>\n /** The wiki catalog block offered to the prompt, if any. */\n wikiContext?: string\n}\n\n/** The first line of the wiki catalog block; see buildWikiContext. */\nconst WIKI_MARKER = \"[Institutional Wiki\"\n\nfunction capIds(ids: string[]): string[] {\n return [...new Set(ids)].slice(0, MAX_INJECTED_IDS).map((id) => id.slice(0, MAX_ID_LENGTH))\n}\n\nexport function injectedContextOf(assembled: string, candidates: InjectionCandidates): InjectedContext {\n const text = assembled ?? \"\"\n return {\n memory: capIds((candidates.memory ?? []).filter((m) => m.content && text.includes(m.content)).map((m) => m.id)),\n procedures: capIds(\n (candidates.procedures ?? []).filter((p) => text.includes(`[Known procedure: ${p.title}]`)).map((p) => p.id),\n ),\n wiki: Boolean(candidates.wikiContext) && text.includes(WIKI_MARKER),\n }\n}\n\n/** Clamp an InjectedContext from any source to the recorded bounds. */\nexport function boundInjectedContext(ctx: InjectedContext): InjectedContext {\n return { memory: capIds(ctx.memory), procedures: capIds(ctx.procedures), wiki: ctx.wiki === true }\n}\n","import type Database from \"better-sqlite3\"\nimport { newEventId } from \"@/intent/ulid\"\nimport { boundInjectedContext } from \"@/agents/injected-context\"\n\n// --- Task trace store ---\n//\n// Improvement plan #2 — per-task observability backed by SQLite. One\n// task_traces row per executeTask invocation, an append-only stream of\n// task_trace_steps inside it. The store is intentionally dumb: it stores\n// what callers give it. Callers (capture sites in src/agents/runtime.ts)\n// are responsible for byte-capping large step payloads so the daemon\n// memory stays bounded under tool-heavy turns.\n//\n// Why a separate store layer (vs writing inline in runtime.ts)?\n// - Tests can exercise the trace lifecycle against a temp SQLite without\n// spinning up the agent runtime.\n// - The HTTP endpoints (GET /task/:id/trace) read through the same\n// functions producers write through, so there's a single source of\n// truth on field names + semantics.\n// - Future capture sites (sdk tier, orchestrator tier) reuse this API\n// without copying SQL.\n//\n// Why ULID for task_id?\n// - URL-safe in HTTP routes (GET /task/:id/trace).\n// - Time-sortable, so listTraces ORDER BY started_at and ORDER BY\n// task_id agree without an explicit timestamp column index.\n// - Already in-tree (src/intent/ulid.ts); no new dep.\n//\n// Cross-DB FK note:\n// intent_event_id and intent_decided_by are logical foreign keys into\n// the intent ledger at .agentx/intent/ledger.sqlite. better-sqlite3\n// doesn't enforce cross-database FKs and we don't ATTACH the ledger\n// here on purpose — the rescue plan's append-only contract on the\n// ledger is honoured by routing all writes through src/intent/ledger.ts.\n// Joins happen at the HTTP / CLI layer when needed.\n\nexport interface TraceStartInput {\n agentId: string\n channel?: string | null\n chatId?: string | null\n messagePreview?: string | null\n /** Full untruncated user message — used by `agentx trace replay <taskId>`\n * to re-fire a recorded task against the current agent config. NULL on\n * rows from before migration v8, in which case replay falls back to\n * messagePreview (which is capped at 200 chars). */\n originalMessage?: string | null\n workflowRunId?: string | null\n workflowId?: string | null\n workflowNodeId?: string | null\n intentEventId?: string | null\n intentDecidedBy?: string | null\n resumeSessionId?: string | null\n model?: string | null\n /** How to re-enter this run after a restart (JSON, see agents/resume). */\n resumeOrigin?: string | null\n /** 0 for a fresh run; n for the n-th resume of a cut-off run. */\n resumeAttempt?: number | null\n /** The cut-off run this one continues. */\n resumedFrom?: string | null\n}\n\nexport interface TraceEndInput {\n status: \"ok\" | \"error\" | \"timeout\"\n finalSessionId?: string | null\n inputTokens?: number | null\n outputTokens?: number | null\n cacheReadTokens?: number | null\n cacheCreateTokens?: number | null\n tier2InputTokens?: number | null\n tier2OutputTokens?: number | null\n tier2CacheReadTokens?: number | null\n tier2CacheCreateTokens?: number | null\n /** Whether the turn continued a provider session. The resume decision\n * is made after task:started, so it is recorded at the end. Omitted\n * leaves both resumed and resume_session_id untouched. */\n resumed?: boolean | null\n resumeSessionId?: string | null\n /** Request-gate experiment arm: \"treatment\" | \"holdout\". */\n jevArm?: string | null\n /** Runtime-reported turn count (Claude `num_turns`). */\n numTurns?: number | null\n /** Lessons injected into the prompt. See InjectedContext. */\n injectedContext?: InjectedContext | null\n error?: string | null\n /** The agent's final reply text. Stored verbatim so `replay --diff`\n * can compare original output vs the new run's output without\n * reconstructing it from the step ledger. NULL when the response\n * wasn't captured (older rows or non-text outputs). */\n finalResponse?: string | null\n}\n\n/** Ids of the lessons injected into one task's prompt. Memory facts and\n * procedures are matched per message, so their ids are recorded; the wiki\n * is injected as a whole catalog, so only its presence is. */\nexport interface InjectedContext {\n memory: string[]\n procedures: string[]\n wiki: boolean\n}\n\nexport interface TraceStepInput {\n /** Coarse step kind. Conventional values: \"tool_use\" | \"tool_result\" |\n * \"llm_message\" | \"session_rotation\" | \"error\" | \"preflight\". Free-form\n * strings allowed so future capture sites don't need a schema bump. */\n name: string\n /** Fine-grained name within the kind. For \"tool_use\", this is the tool\n * name (e.g. \"Bash\", \"Edit\"). Optional. */\n action?: string | null\n status?: \"ok\" | \"error\" | \"in-flight\" | null\n /** JSON-stringified input or human-readable summary. Caller-byte-capped. */\n inputSummary?: string | null\n outputSummary?: string | null\n error?: string | null\n /** Step duration when known. Optional — many step kinds are point-in-time. */\n ms?: number | null\n}\n\nexport interface TraceRecord {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n workflowRunId: string | null\n workflowId: string | null\n workflowNodeId: string | null\n intentEventId: string | null\n intentDecidedBy: string | null\n resumeSessionId: string | null\n finalSessionId: string | null\n model: string | null\n status: string\n startedAt: number\n finishedAt: number | null\n durationMs: number | null\n inputTokens: number | null\n outputTokens: number | null\n cacheReadTokens: number | null\n cacheCreateTokens: number | null\n tier2InputTokens: number | null\n tier2OutputTokens: number | null\n tier2CacheReadTokens: number | null\n tier2CacheCreateTokens: number | null\n /** NULL on rows recorded before migration v12. */\n resumed: boolean | null\n /** NULL when the request gate was not active (or before migration v13). */\n jevArm: string | null\n /** NULL on rows recorded before lesson-impact capture (#98) or when the\n * runtime does not report a turn count. */\n numTurns: number | null\n /** NULL on rows recorded before lesson-impact capture (#98). */\n injectedContext: InjectedContext | null\n error: string | null\n messagePreview: string | null\n /** Full untruncated user message — populated for traces from migration v8\n * onward. NULL on older rows; consumers should fall back to messagePreview. */\n originalMessage: string | null\n /** Agent's final reply text — populated for traces from migration v8\n * onward when the executor records it on end. */\n finalResponse: string | null\n}\n\nexport interface TraceStepRecord {\n taskId: string\n seq: number\n name: string\n action: string | null\n status: string | null\n inputSummary: string | null\n outputSummary: string | null\n error: string | null\n ms: number | null\n startedAt: number\n}\n\nexport interface ListTracesFilters {\n agentId?: string\n channel?: string\n chatId?: string\n workflowRunId?: string\n status?: string\n /** ms epoch */\n since?: number\n /** ms epoch */\n until?: number\n /** Default 100, capped at 1000. */\n limit?: number\n}\n\n/**\n * Insert an in-flight trace row and return its ULID. Callers thread the\n * returned id through the executor and call recordTraceEnd at finish time.\n *\n * `taskId` is optional — when supplied, the caller has already allocated\n * a ULID upstream (e.g. registry.execute generating it before the bus\n * event so the runtime can capture per-step rows under the same id).\n * When omitted, a fresh ULID is allocated here.\n */\nexport function recordTraceStart(\n db: Database.Database,\n input: TraceStartInput,\n taskId: string = newEventId(),\n): string {\n db.prepare(`\n INSERT INTO task_traces (\n task_id, agent_id, channel, chat_id, workflow_run_id, workflow_id,\n workflow_node_id, intent_event_id, intent_decided_by, resume_session_id,\n model, status, started_at, message_preview, original_message,\n resume_origin, resume_attempt, resumed_from\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'in-flight', ?, ?, ?, ?, ?, ?)\n `).run(\n taskId,\n input.agentId,\n input.channel ?? null,\n input.chatId ?? null,\n input.workflowRunId ?? null,\n input.workflowId ?? null,\n input.workflowNodeId ?? null,\n input.intentEventId ?? null,\n input.intentDecidedBy ?? null,\n input.resumeSessionId ?? null,\n input.model ?? null,\n Date.now(),\n input.messagePreview ?? null,\n input.originalMessage ?? null,\n input.resumeOrigin ?? null,\n input.resumeAttempt ?? 0,\n input.resumedFrom ?? null,\n )\n return taskId\n}\n\n/**\n * Finalize a trace. duration_ms is computed from finished_at - started_at\n * inside the UPDATE so the two columns can never disagree. Idempotent —\n * calling twice on the same task_id overwrites the prior end values; the\n * second call's status wins. (Soft-overwrite is intentional: timeout\n * handlers may write before a late stream-completion arrives.)\n */\nexport function recordTraceEnd(db: Database.Database, taskId: string, input: TraceEndInput): void {\n const finishedAt = Date.now()\n db.prepare(`\n UPDATE task_traces SET\n status = ?,\n final_session_id = ?,\n input_tokens = ?,\n output_tokens = ?,\n cache_read_tokens = ?,\n cache_create_tokens = ?,\n tier2_input_tokens = ?,\n tier2_output_tokens = ?,\n tier2_cache_read_tokens = ?,\n tier2_cache_create_tokens = ?,\n resumed = COALESCE(?, resumed),\n resume_session_id = COALESCE(?, resume_session_id),\n jev_arm = COALESCE(?, jev_arm),\n num_turns = COALESCE(?, num_turns),\n injected_context = COALESCE(?, injected_context),\n error = ?,\n final_response = COALESCE(?, final_response),\n finished_at = ?,\n duration_ms = ? - started_at\n WHERE task_id = ?\n `).run(\n input.status,\n input.finalSessionId ?? null,\n input.inputTokens ?? null,\n input.outputTokens ?? null,\n input.cacheReadTokens ?? null,\n input.cacheCreateTokens ?? null,\n input.tier2InputTokens ?? null,\n input.tier2OutputTokens ?? null,\n input.tier2CacheReadTokens ?? null,\n input.tier2CacheCreateTokens ?? null,\n input.resumed == null ? null : input.resumed ? 1 : 0,\n input.resumeSessionId ?? null,\n input.jevArm ?? null,\n input.numTurns ?? null,\n input.injectedContext ? JSON.stringify(boundInjectedContext(input.injectedContext)) : null,\n input.error ?? null,\n input.finalResponse ?? null,\n finishedAt,\n finishedAt,\n taskId,\n )\n}\n\n/**\n * Append a step. seq is auto-allocated as MAX(seq)+1 within a transaction\n * so concurrent step writes for the same task_id can't collide. Returns\n * the assigned seq, useful for downstream correlation.\n */\nexport function recordTraceStep(db: Database.Database, taskId: string, input: TraceStepInput): number {\n const startedAt = Date.now()\n const allocateAndInsert = db.transaction((): number => {\n const row = db\n .prepare(\"SELECT MAX(seq) AS max_seq FROM task_trace_steps WHERE task_id = ?\")\n .get(taskId) as { max_seq: number | null } | undefined\n const seq = ((row?.max_seq ?? -1) as number) + 1\n db.prepare(`\n INSERT INTO task_trace_steps (\n task_id, seq, name, action, status, input_summary, output_summary, error, ms, started_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n taskId,\n seq,\n input.name,\n input.action ?? null,\n input.status ?? null,\n input.inputSummary ?? null,\n input.outputSummary ?? null,\n input.error ?? null,\n input.ms ?? null,\n startedAt,\n )\n return seq\n })\n return allocateAndInsert()\n}\n\nexport function parseInjectedContext(raw: unknown): InjectedContext | null {\n if (typeof raw !== \"string\") return null\n try {\n const v = JSON.parse(raw)\n if (!v || typeof v !== \"object\") return null\n const ids = (x: unknown) => (Array.isArray(x) ? x.filter((i): i is string => typeof i === \"string\") : [])\n return { memory: ids(v.memory), procedures: ids(v.procedures), wiki: v.wiki === true }\n } catch {\n return null\n }\n}\n\nfunction rowToTrace(row: Record<string, unknown>): TraceRecord {\n return {\n taskId: row.task_id as string,\n agentId: row.agent_id as string,\n channel: (row.channel as string) ?? null,\n chatId: (row.chat_id as string) ?? null,\n workflowRunId: (row.workflow_run_id as string) ?? null,\n workflowId: (row.workflow_id as string) ?? null,\n workflowNodeId: (row.workflow_node_id as string) ?? null,\n intentEventId: (row.intent_event_id as string) ?? null,\n intentDecidedBy: (row.intent_decided_by as string) ?? null,\n resumeSessionId: (row.resume_session_id as string) ?? null,\n finalSessionId: (row.final_session_id as string) ?? null,\n model: (row.model as string) ?? null,\n status: row.status as string,\n startedAt: row.started_at as number,\n finishedAt: (row.finished_at as number) ?? null,\n durationMs: (row.duration_ms as number) ?? null,\n inputTokens: (row.input_tokens as number) ?? null,\n outputTokens: (row.output_tokens as number) ?? null,\n cacheReadTokens: (row.cache_read_tokens as number) ?? null,\n cacheCreateTokens: (row.cache_create_tokens as number) ?? null,\n tier2InputTokens: (row.tier2_input_tokens as number) ?? null,\n tier2OutputTokens: (row.tier2_output_tokens as number) ?? null,\n tier2CacheReadTokens: (row.tier2_cache_read_tokens as number) ?? null,\n tier2CacheCreateTokens: (row.tier2_cache_create_tokens as number) ?? null,\n resumed: row.resumed == null ? null : row.resumed === 1,\n jevArm: (row.jev_arm as string) ?? null,\n numTurns: (row.num_turns as number) ?? null,\n injectedContext: parseInjectedContext(row.injected_context),\n error: (row.error as string) ?? null,\n messagePreview: (row.message_preview as string) ?? null,\n originalMessage: (row.original_message as string) ?? null,\n finalResponse: (row.final_response as string) ?? null,\n }\n}\n\nfunction rowToStep(row: Record<string, unknown>): TraceStepRecord {\n return {\n taskId: row.task_id as string,\n seq: row.seq as number,\n name: row.name as string,\n action: (row.action as string) ?? null,\n status: (row.status as string) ?? null,\n inputSummary: (row.input_summary as string) ?? null,\n outputSummary: (row.output_summary as string) ?? null,\n error: (row.error as string) ?? null,\n ms: (row.ms as number) ?? null,\n startedAt: row.started_at as number,\n }\n}\n\n/** Fetch a trace + its ordered steps. Returns null if no such task_id. */\nexport function getTrace(\n db: Database.Database,\n taskId: string,\n): { task: TraceRecord; steps: TraceStepRecord[] } | null {\n const row = db.prepare(\"SELECT * FROM task_traces WHERE task_id = ?\").get(taskId) as\n | Record<string, unknown>\n | undefined\n if (!row) return null\n const stepRows = db\n .prepare(\"SELECT * FROM task_trace_steps WHERE task_id = ? ORDER BY seq\")\n .all(taskId) as Record<string, unknown>[]\n return { task: rowToTrace(row), steps: stepRows.map(rowToStep) }\n}\n\n/**\n * Cancel any in-flight trace rows left over from a previous daemon\n * lifetime. Mirrors the intent ledger's startup cleanup (rescue plan\n * Phase 1 commit a8514d9): a hard-killed daemon never gets to fire\n * task:completed, so the row sits \"in-flight\" forever and contaminates\n * triage queries (`agentx trace list --status in-flight`) with stale\n * orphans. Run once at daemon boot before subscribers attach.\n *\n * Returns the number of rows updated. duration_ms is intentionally NOT\n * computed — we don't know when the task actually ended; preserving\n * NULL there is more honest than backdating to \"now\".\n */\nexport function cleanupOrphanedTraces(db: Database.Database): number {\n const now = Date.now()\n const r = db.prepare(`\n UPDATE task_traces\n SET status = 'canceled',\n error = 'daemon-restart (orphaned in-flight)',\n finished_at = ?\n WHERE status = 'in-flight'\n `).run(now)\n return (r.changes ?? 0) as number\n}\n\n// --- Resume after restart (#103) -------------------------------------------\n\n/** A run that was still going when the previous daemon stopped. */\nexport interface InterruptedRun {\n taskId: string\n agentId: string\n channel: string | null\n chatId: string | null\n workflowRunId: string | null\n startedAt: number\n originalMessage: string | null\n resumeOrigin: string | null\n resumeAttempt: number\n /** Tool calls it had made, in order, for the resume note. */\n toolCalls: Array<{ action: string | null; inputSummary: string | null }>\n}\n\n/** Close every run left in flight by the previous daemon, marking it\n * `interrupted` for the resume planner, and return them. One transaction,\n * so a second process booting on the same database gets nothing. */\nexport function takeInterruptedRuns(db: Database.Database, now = Date.now()): InterruptedRun[] {\n const take = db.transaction(() => {\n const rows = db.prepare(`\n SELECT task_id, agent_id, channel, chat_id, workflow_run_id, started_at,\n original_message, resume_origin, resume_attempt\n FROM task_traces WHERE status = 'in-flight' ORDER BY started_at\n `).all() as Array<Record<string, any>>\n db.prepare(`\n UPDATE task_traces\n SET status = 'canceled', error = 'daemon-restart (interrupted)',\n finished_at = ?, resume_decision = 'interrupted'\n WHERE status = 'in-flight'\n `).run(now)\n return rows\n })\n const steps = db.prepare(`\n SELECT action, input_summary FROM task_trace_steps\n WHERE task_id = ? AND name = 'tool_use' ORDER BY seq\n `)\n return take().map((r) => ({\n taskId: r.task_id,\n agentId: r.agent_id,\n channel: r.channel ?? null,\n chatId: r.chat_id ?? null,\n workflowRunId: r.workflow_run_id ?? null,\n startedAt: r.started_at,\n originalMessage: r.original_message ?? null,\n resumeOrigin: r.resume_origin ?? null,\n resumeAttempt: r.resume_attempt ?? 0,\n toolCalls: (steps.all(r.task_id) as Array<Record<string, any>>).map((s) => ({\n action: s.action ?? null, inputSummary: s.input_summary ?? null,\n })),\n }))\n}\n\n/** Claim an interrupted run before deciding what to do with it. Returns\n * false when another process already claimed or decided it, so a run is\n * never resumed — or its chat told — twice. */\nexport function claimResume(db: Database.Database, taskId: string): boolean {\n const r = db.prepare(`\n UPDATE task_traces SET resume_decision = 'deciding'\n WHERE task_id = ? AND resume_decision = 'interrupted'\n `).run(taskId)\n return (r.changes ?? 0) === 1\n}\n\nexport type ResumeDecision = \"resumed\" | \"reported\" | \"skipped\" | \"resume-failed\"\n\nexport function recordResumeDecision(\n db: Database.Database, taskId: string, decision: ResumeDecision, reason: string,\n): void {\n db.prepare(\"UPDATE task_traces SET resume_decision = ?, resume_reason = ? WHERE task_id = ?\")\n .run(decision, reason.slice(0, 500), taskId)\n}\n\n/** Triage / dashboard surface — list traces newest-first, filtered. */\nexport function listTraces(db: Database.Database, filters: ListTracesFilters = {}): TraceRecord[] {\n const where: string[] = []\n const params: unknown[] = []\n if (filters.agentId) { where.push(\"agent_id = ?\"); params.push(filters.agentId) }\n if (filters.channel) { where.push(\"channel = ?\"); params.push(filters.channel) }\n if (filters.chatId) { where.push(\"chat_id = ?\"); params.push(filters.chatId) }\n if (filters.workflowRunId) { where.push(\"workflow_run_id = ?\"); params.push(filters.workflowRunId) }\n if (filters.status) { where.push(\"status = ?\"); params.push(filters.status) }\n if (filters.since !== undefined) { where.push(\"started_at >= ?\"); params.push(filters.since) }\n if (filters.until !== undefined) { where.push(\"started_at <= ?\"); params.push(filters.until) }\n\n const limit = Math.max(1, Math.min(filters.limit ?? 100, 1000))\n const sql = `\n SELECT * FROM task_traces\n ${where.length > 0 ? \"WHERE \" + where.join(\" AND \") : \"\"}\n ORDER BY started_at DESC\n LIMIT ?\n `\n params.push(limit)\n return (db.prepare(sql).all(...params) as Record<string, unknown>[]).map(rowToTrace)\n}\n"],"mappings":"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","names":["WIKI_MARKER","capIds","ids","id","injectedContextOf","assembled","candidates","text","m","p","boundInjectedContext","ctx","init_ulid","recordTraceStart","db","input","taskId","newEventId","recordTraceEnd","finishedAt","boundInjectedContext","recordTraceStep","startedAt","seq","parseInjectedContext","raw","v","ids","x","i","rowToTrace","row","rowToStep","getTrace","stepRows","cleanupOrphanedTraces","now","takeInterruptedRuns","take","rows","steps","r","s","claimResume","recordResumeDecision","decision","reason","listTraces","filters","where","params","limit","sql"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/doctor.ts","../src/notify/helper-status.ts"],"sourcesContent":["import { Command } from \"commander\"\nimport chalk from \"chalk\"\nimport { execFileSync } from \"child_process\"\nimport { accessSync, constants, existsSync, readFileSync, readdirSync, statSync } from \"fs\"\nimport { join, resolve } from \"path\"\nimport { homedir } from \"os\"\nimport { createRequire } from \"module\"\nimport { loadDaemonConfig } from \"@/daemon/config\"\nimport { findOnPath, plistPathEnv } from \"@/desktop/install\"\nimport { localSettings } from \"@/notify/local\"\nimport { helperStatus } from \"@/notify/helper-status\"\n\n// --- agentx doctor ---\n//\n// Pre-flight health check. Catches the common \"why isn't it working\" reasons\n// before the operator hits them at runtime:\n// - wrong Node version\n// - invalid / missing agentx.json\n// - agents with claude-code tier but no claude CLI installed\n// - ${FOO} references in agentx.json that have no matching env var\n// - agent workspace dirs that don't exist\n// - daemon reachable? (when --check-running, default true)\n//\n// Exit code: 0 if clean, 1 if any error, 0 if only warnings (so CI won't block\n// on advisory checks).\n\nexport type Severity = \"ok\" | \"warn\" | \"fail\"\n\nexport interface Check {\n severity: Severity\n group: string\n title: string\n detail?: string\n fix?: string\n}\n\n/** Run every preflight check and return the result as data. Exposed so\n * the dashboard's /admin/doctor route can render the same checks the\n * `agentx doctor` CLI prints — without spawning a child process. */\nexport async function runDoctorChecks(\n opts: { running?: boolean } = {},\n): Promise<{ checks: Check[]; summary: { errors: number; warnings: number; ok: number } }> {\n const checks: Check[] = []\n await runEnvChecks(checks)\n runDesktopChecks(checks)\n const cfg = runConfigChecks(checks)\n if (cfg) runReferenceChecks(checks, cfg)\n if (cfg) runWorkspaceChecks(checks, cfg)\n if (cfg) runWorkspaceSettingsChecks(checks, cfg)\n if (cfg) runRoutingChecks(checks, cfg)\n if (cfg) runCodegraphChecks(checks, cfg)\n if (cfg) await runNotificationChecks(checks, cfg)\n if (cfg) runReminderChecks(checks, cfg)\n if (opts.running !== false && cfg) await runRuntimeChecks(checks, cfg)\n return { checks, summary: summarize(checks) }\n}\n\nexport const doctor = new Command()\n .name(\"doctor\")\n .description(\"pre-flight health check: Node, config, credentials, daemon\")\n .option(\"--no-running\", \"skip the live daemon probe\")\n .option(\"--json\", \"emit machine-readable JSON (stable shape for CI)\")\n .action(async (opts) => {\n const { checks, summary } = await runDoctorChecks({ running: opts.running !== false })\n if (opts.json) {\n process.stdout.write(JSON.stringify({ checks, summary }, null, 2) + \"\\n\")\n } else {\n printHumanReport(checks)\n }\n process.exit(summary.errors > 0 ? 1 : 0)\n })\n\n// ---------------------------------------------------------------------------\n// Checks\n// ---------------------------------------------------------------------------\n\n/** On a Mac with banners on: can AgentX Helper post them with its icon? */\nexport async function runNotificationChecks(checks: Check[], cfg: any, status = helperStatus): Promise<void> {\n if (!localSettings(cfg.notifications?.local).banner) return\n const helper = await status()\n if (helper.state === \"unsupported\") return\n checks.push({\n severity: helper.state === \"ready\" ? \"ok\" : \"warn\",\n group: \"Notifications\",\n title: helper.message,\n detail: helper.path,\n fix: helper.fix,\n })\n}\n\n/** reminders.enabled: macOS only, and the daemon needs remindctl. */\nexport function runReminderChecks(\n checks: Check[],\n cfg: any,\n platform: NodeJS.Platform = process.platform,\n isExecutable: (file: string) => boolean = (file) => { try { accessSync(file, constants.X_OK); return true } catch { return false } },\n): void {\n const r = cfg.reminders\n if (!r?.enabled) return\n if (platform !== \"darwin\") {\n checks.push({\n severity: \"warn\",\n group: \"Reminders\",\n title: \"Reminders hand-back unavailable on this machine\",\n detail: \"reminders.enabled is set, but Apple Reminders exists only on macOS. The daemon starts without it.\",\n fix: \"Set reminders.enabled to false here, or enable it on the Mac node instead.\",\n })\n return\n }\n const command = r.command || \"remindctl\"\n const found = command.includes(\"/\") ? (isExecutable(command) ? command : null) : findOnPath(command, process.env.PATH || \"\", isExecutable)\n checks.push(found\n ? { severity: \"ok\", group: \"Reminders\", title: `Watching ${(r.lists || []).join(\", \")} for due reminders`, detail: found }\n : {\n severity: \"fail\",\n group: \"Reminders\",\n title: `${command} not found`,\n detail: \"The daemon reads Apple Reminders through remindctl.\",\n fix: \"brew install steipete/tap/remindctl, or set reminders.command to its full path.\",\n })\n}\n\n// Keep in step with package.json \"engines\": undici 8 needs 22.19, and\n// better-sqlite3 ships prebuilt binaries up to Node 26.\nexport function nodeVersionSupported(version: string): boolean {\n const [major, minor] = version.split(\".\").map(Number)\n return (major === 22 && minor >= 19) || (major >= 23 && major <= 26)\n}\n\nasync function runEnvChecks(checks: Check[]): Promise<void> {\n const supported = nodeVersionSupported(process.versions.node)\n checks.push({\n severity: supported ? \"ok\" : \"fail\",\n group: \"Environment\",\n title: `Node.js ${process.versions.node}`,\n detail: supported ? undefined : \"AgentX requires Node 22.19 or newer, up to Node 26.\",\n fix: supported ? undefined : \"Install Node 22 (nvm install 22 && nvm use 22)\",\n })\n\n const which = (bin: string): string | null => {\n try { return execFileSync(process.platform === \"win32\" ? \"where\" : \"which\", [bin], { encoding: \"utf-8\" }).trim().split(\"\\n\")[0] }\n catch { return null }\n }\n const npmPath = which(\"npm\")\n checks.push({\n severity: npmPath ? \"ok\" : \"fail\",\n group: \"Environment\",\n title: npmPath ? \"npm on PATH\" : \"npm not found\",\n detail: npmPath || undefined,\n })\n\n // Claude CLI is only required if the config references claude-code agents;\n // we report it advisory here and promote to fail in the config step below.\n const claudePath = which(\"claude\")\n if (claudePath) {\n let ver: string | undefined\n try { ver = execFileSync(\"claude\", [\"--version\"], { encoding: \"utf-8\", timeout: 3000 }).trim() } catch { /* */ }\n checks.push({ severity: \"ok\", group: \"Environment\", title: `claude CLI ${ver || \"installed\"}`, detail: claudePath })\n } else {\n checks.push({\n severity: \"warn\",\n group: \"Environment\",\n title: \"claude CLI not on PATH\",\n detail: \"Only required for agents on the claude-code tier.\",\n fix: \"See https://docs.anthropic.com/en/docs/claude-code\",\n })\n }\n\n const codexPath = which(\"codex\")\n if (codexPath) {\n let ver: string | undefined\n try { ver = execFileSync(\"codex\", [\"--version\"], { encoding: \"utf-8\", timeout: 3000 }).trim() } catch { /* */ }\n checks.push({ severity: \"ok\", group: \"Environment\", title: `codex CLI ${ver || \"installed\"}`, detail: codexPath })\n } else {\n checks.push({\n severity: \"warn\",\n group: \"Environment\",\n title: \"codex CLI not on PATH\",\n detail: \"Only required for agents on the codex-cli tier.\",\n fix: \"Install with `npm i -g @openai/codex`.\",\n })\n }\n\n const openCodePath = which(\"opencode\")\n if (openCodePath) {\n let ver: string | undefined\n try { ver = execFileSync(\"opencode\", [\"--version\"], { encoding: \"utf-8\", timeout: 3000 }).trim() } catch { /* */ }\n checks.push({ severity: \"ok\", group: \"Environment\", title: `opencode CLI ${ver || \"installed\"}`, detail: openCodePath })\n } else {\n checks.push({\n severity: \"warn\",\n group: \"Environment\",\n title: \"opencode CLI not on PATH\",\n detail: \"Only required for agents on the opencode tier.\",\n fix: \"Install from https://opencode.ai/docs/.\",\n })\n }\n\n try {\n createRequire(import.meta.url)(\"better-sqlite3\")\n checks.push({\n severity: \"ok\",\n group: \"Environment\",\n title: `better-sqlite3 loads for Node ${process.version}`,\n detail: `NODE_MODULE_VERSION ${process.versions.modules}`,\n })\n } catch (e: any) {\n checks.push({\n severity: \"fail\",\n group: \"Environment\",\n title: \"better-sqlite3 native binding does not load\",\n detail: e?.message ?? String(e),\n fix: `Run \"pnpm rebuild better-sqlite3\" with the same Node used by the daemon (${process.version}, modules ${process.versions.modules}).`,\n })\n }\n}\n\n/** The desktop app's login item runs with only the PATH its plist sets, so\n * check that local Whisper's ffmpeg is reachable there, not in this shell. */\nfunction runDesktopChecks(checks: Check[]): void {\n if (process.platform !== \"darwin\") return\n // Older installs used another label; apps/mac-voice/install.sh keeps it.\n const agents = join(homedir(), \"Library/LaunchAgents\")\n let names: string[] = []\n try { names = readdirSync(agents).filter(n => /agentx\\.voice.*\\.plist$/.test(n)) } catch { return }\n const isExecutable = (file: string) => { try { accessSync(file, constants.X_OK); return true } catch { return false } }\n for (const name of names) {\n const path = plistPathEnv(readFileSync(join(agents, name), \"utf-8\"))\n const ffmpeg = findOnPath(\"ffmpeg\", path, isExecutable)\n checks.push(ffmpeg\n ? { severity: \"ok\", group: \"Desktop\", title: \"ffmpeg reachable by the desktop app\", detail: `${ffmpeg} (${name})` }\n : {\n severity: \"warn\",\n group: \"Desktop\",\n title: \"ffmpeg not reachable by the desktop app\",\n detail: `Local Whisper transcription fails without it. ${name} sets PATH to ${path}.`,\n fix: \"Install ffmpeg (brew install ffmpeg), then rerun agentx desktop install.\",\n })\n }\n}\n\nfunction runConfigChecks(checks: Check[]): any {\n const cfgPath = resolve(process.cwd(), \"agentx.json\")\n if (!existsSync(cfgPath)) {\n checks.push({\n severity: \"fail\",\n group: \"Config\",\n title: \"agentx.json not found\",\n detail: `Looked in ${cfgPath}`,\n fix: \"Run `agentx setup` to create one via the web wizard.\",\n })\n return null\n }\n let cfg: any\n try { cfg = JSON.parse(readFileSync(cfgPath, \"utf-8\")) }\n catch (e: any) {\n checks.push({ severity: \"fail\", group: \"Config\", title: \"agentx.json is not valid JSON\", detail: e.message })\n return null\n }\n try {\n // Full schema validation — catches missing required fields.\n loadDaemonConfig(cfgPath)\n checks.push({ severity: \"ok\", group: \"Config\", title: `agentx.json valid (${Object.keys(cfg.agents || {}).length} agents, ${Object.keys(cfg.crons || {}).length} schedules)` })\n } catch (e: any) {\n checks.push({\n severity: \"fail\",\n group: \"Config\",\n title: \"agentx.json failed schema validation\",\n detail: e.message,\n fix: \"Open /admin → Advanced tab to edit and re-save.\",\n })\n }\n const claudeCodeAgents = Object.entries(cfg.agents || {}).filter(([, a]: [string, any]) => a.tier === \"claude-code\")\n if (claudeCodeAgents.length > 0) {\n const hasClaude = (() => {\n try { execFileSync(process.platform === \"win32\" ? \"where\" : \"which\", [\"claude\"], { stdio: \"ignore\" }); return true } catch { return false }\n })()\n if (!hasClaude) {\n checks.push({\n severity: \"fail\",\n group: \"Config\",\n title: `${claudeCodeAgents.length} agent(s) use claude-code tier but claude CLI is missing`,\n detail: claudeCodeAgents.map(([id]) => id).join(\", \"),\n fix: \"Install Claude Code (https://docs.anthropic.com/en/docs/claude-code) or switch these agents to tier=sdk.\",\n })\n }\n }\n const codexCliAgents = Object.entries(cfg.agents || {}).filter(([, a]: [string, any]) => a.tier === \"codex-cli\")\n if (codexCliAgents.length > 0) {\n const hasCodex = (() => {\n try { execFileSync(process.platform === \"win32\" ? \"where\" : \"which\", [\"codex\"], { stdio: \"ignore\" }); return true } catch { return false }\n })()\n if (!hasCodex) {\n checks.push({\n severity: \"fail\",\n group: \"Config\",\n title: `${codexCliAgents.length} agent(s) use codex-cli tier but codex CLI is missing`,\n detail: codexCliAgents.map(([id]) => id).join(\", \"),\n fix: \"Install Codex CLI with `npm i -g @openai/codex` or switch these agents to tier=claude-code.\",\n })\n }\n }\n const openCodeAgents = Object.entries(cfg.agents || {}).filter(([, a]: [string, any]) => a.tier === \"opencode\")\n if (openCodeAgents.length > 0) {\n const hasOpenCode = (() => {\n try { execFileSync(process.platform === \"win32\" ? \"where\" : \"which\", [\"opencode\"], { stdio: \"ignore\" }); return true } catch { return false }\n })()\n if (!hasOpenCode) {\n checks.push({\n severity: \"fail\",\n group: \"Config\",\n title: `${openCodeAgents.length} agent(s) use opencode tier but OpenCode CLI is missing`,\n detail: openCodeAgents.map(([id]) => id).join(\", \"),\n fix: \"Install OpenCode from https://opencode.ai/docs/ or switch these agents to another tier.\",\n })\n }\n }\n return cfg\n}\n\nfunction runReferenceChecks(checks: Check[], cfg: any): void {\n // Parse ${VAR} references out of the config (recursively) and verify each\n // one has a matching value in .env or process.env.\n const refs = new Set<string>()\n collectEnvRefs(cfg, refs)\n if (refs.size === 0) {\n checks.push({ severity: \"ok\", group: \"Secrets\", title: \"No ${VAR} references in agentx.json\" })\n return\n }\n const envFile = resolve(process.cwd(), \".env\")\n const envFromFile: Record<string, string> = {}\n if (existsSync(envFile)) {\n for (const line of readFileSync(envFile, \"utf-8\").split(/\\r?\\n/)) {\n const m = line.match(/^\\s*([A-Z_][A-Z0-9_]*)\\s*=\\s*(.*)$/i)\n if (m) envFromFile[m[1]] = m[2]\n }\n }\n const missing: string[] = []\n const empty: string[] = []\n for (const name of refs) {\n const raw = process.env[name] ?? envFromFile[name]\n if (raw === undefined) missing.push(name)\n else if (!raw.trim() || /^[\"']?\\s*[\"']?$/.test(raw)) empty.push(name)\n }\n if (missing.length === 0 && empty.length === 0) {\n checks.push({ severity: \"ok\", group: \"Secrets\", title: `${refs.size} env reference(s) resolved` })\n } else {\n if (missing.length > 0) {\n checks.push({\n severity: \"fail\",\n group: \"Secrets\",\n title: `${missing.length} env var(s) referenced in agentx.json but missing`,\n detail: missing.join(\", \"),\n fix: `Add to .env — e.g. ${missing[0]}=<value>`,\n })\n }\n if (empty.length > 0) {\n checks.push({\n severity: \"warn\",\n group: \"Secrets\",\n title: `${empty.length} env var(s) set but empty`,\n detail: empty.join(\", \"),\n })\n }\n }\n}\n\nfunction collectEnvRefs(node: unknown, into: Set<string>): void {\n if (typeof node === \"string\") {\n for (const m of node.matchAll(/\\$\\{([A-Z_][A-Z0-9_]*)\\}/g)) into.add(m[1])\n } else if (Array.isArray(node)) {\n for (const item of node) collectEnvRefs(item, into)\n } else if (node && typeof node === \"object\") {\n for (const v of Object.values(node)) collectEnvRefs(v, into)\n }\n}\n\nfunction runWorkspaceChecks(checks: Check[], cfg: any): void {\n const missing: string[] = []\n for (const [id, a] of Object.entries(cfg.agents || {}) as [string, any][]) {\n if (!a.workspace) continue\n const abs = a.workspace.startsWith(\"/\") ? a.workspace : resolve(process.cwd(), a.workspace)\n try {\n const st = statSync(abs)\n if (!st.isDirectory()) missing.push(`${id}: ${abs} (exists but not a directory)`)\n } catch { missing.push(`${id}: ${abs}`) }\n }\n if (missing.length === 0) {\n checks.push({ severity: \"ok\", group: \"Workspaces\", title: \"All agent workspace folders exist\" })\n } else {\n checks.push({\n severity: \"warn\",\n group: \"Workspaces\",\n title: `${missing.length} agent workspace(s) missing`,\n detail: missing.join(\"\\n \"),\n fix: \"The daemon will create missing folders on first task, but you won't see CLAUDE.md / skills until you populate them.\",\n })\n }\n}\n\n// Audit each agent's .claude/settings.json for known traps:\n// - unexpanded ${VAR} literals in env values (Claude Code does NOT expand them)\n// - env.PATH missing /usr/bin or /bin (basic utils unreachable)\n// - JSON syntax errors\n// - permissions.allow: [] explicitly empty alongside non-empty deny\n// Each finding is FAIL severity for the ${VAR} / PATH cases (these break the\n// agent's Bash tool entirely), WARN for the lockdown case.\nfunction runWorkspaceSettingsChecks(checks: Check[], cfg: any): void {\n const VAR_RE = /\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}/g\n const findings: Array<{ severity: Severity; agent: string; msg: string }> = []\n\n for (const [agentId, a] of Object.entries(cfg.agents || {}) as [string, any][]) {\n if (!a.workspace) continue\n const wsAbs = a.workspace.startsWith(\"/\") ? a.workspace : resolve(process.cwd(), a.workspace)\n for (const fname of [\"settings.json\", \"settings.local.json\"]) {\n const p = resolve(wsAbs, \".claude\", fname)\n if (!existsSync(p)) continue\n let data: any\n try {\n data = JSON.parse(readFileSync(p, \"utf-8\"))\n } catch (e: any) {\n findings.push({ severity: \"fail\", agent: agentId, msg: `${fname}: JSON parse error — ${e.message}` })\n continue\n }\n const env = (data.env || {}) as Record<string, unknown>\n for (const [k, v] of Object.entries(env)) {\n if (typeof v !== \"string\") continue\n const unexpanded = v.match(VAR_RE)\n if (unexpanded) {\n findings.push({\n severity: \"fail\",\n agent: agentId,\n msg: `${fname} env.${k} contains unexpanded ${[...new Set(unexpanded)].join(\",\")} — Claude Code does NOT expand \\${VAR} in settings.json (use a fully-literal value)`,\n })\n }\n }\n const pathVal = env.PATH\n if (typeof pathVal === \"string\") {\n const parts = pathVal.split(\":\").filter(Boolean)\n if (!parts.includes(\"/usr/bin\")) {\n findings.push({ severity: \"fail\", agent: agentId, msg: `${fname} env.PATH missing /usr/bin — cat/head/sh/which will fail` })\n }\n if (!parts.includes(\"/bin\")) {\n findings.push({ severity: \"fail\", agent: agentId, msg: `${fname} env.PATH missing /bin — ls/cp/mv will fail` })\n }\n }\n const perms = data.permissions\n if (perms && typeof perms === \"object\" && \"allow\" in perms) {\n const allow = perms.allow\n const deny = perms.deny\n if (Array.isArray(allow) && allow.length === 0 && Array.isArray(deny) && deny.length > 0) {\n findings.push({\n severity: \"warn\",\n agent: agentId,\n msg: `${fname} permissions.allow is explicitly [] with ${deny.length} deny rules — agent may be locked out (omit the key to use defaults instead)`,\n })\n }\n }\n }\n }\n\n if (findings.length === 0) {\n checks.push({ severity: \"ok\", group: \"Workspace settings\", title: `All ${Object.keys(cfg.agents || {}).length} agent .claude/settings.json files clean` })\n return\n }\n for (const f of findings) {\n checks.push({\n severity: f.severity,\n group: \"Workspace settings\",\n title: `${f.agent}: ${f.msg}`,\n fix: f.severity === \"fail\" ? \"Edit .claude/settings.json — replace ${VAR} with the literal value or omit the key to inherit.\" : \"Either remove the empty allow list or populate it.\",\n })\n }\n}\n\n// Surface routing / dispatch fragilities the recurring-patches plan\n// cataloged: webhook entries that route many event-types to a single\n// handler (github, gitlab), trigger maps pointing at workflow ids that\n// don't exist, mesh `node` fields naming peers that aren't configured,\n// gitlab agentMappings referencing unknown agents, and the very common\n// \"I edited agentx.json but didn't reload\" pitfall.\nfunction runRoutingChecks(checks: Check[], cfg: any): void {\n const webhooks = (cfg.webhooks ?? []) as Array<{\n id: string\n source: string\n agentId: string\n enabled: boolean\n node?: string\n secretEnv?: string\n triggers?: Record<string, string>\n defaultWorkflow?: string\n }>\n const findings: Array<{ severity: Severity; title: string; fix?: string }> = []\n\n // Build the set of known workflow ids. Workflows live as JSON files under\n // `workflows.dir` (default .agentx/workflows/). The id is the filename\n // sans extension; we don't need to parse the contents for this check.\n const workflowDir = resolve(process.cwd(), cfg.workflows?.dir || \".agentx/workflows\")\n const knownWorkflows = new Set<string>()\n try {\n if (existsSync(workflowDir)) {\n for (const f of readdirSync(workflowDir)) {\n if (f.endsWith(\".json\") && !f.startsWith(\"_\") && !f.endsWith(\".disabled.json\")) {\n knownWorkflows.add(f.replace(/\\.json$/, \"\"))\n }\n }\n }\n } catch { /* directory not yet populated; checks below tolerate empty set */ }\n\n // 1. Multi-event-type sources (github, gitlab) without a triggers map.\n // Without it, every inbound event hits the same agent and the\n // duplicate-firing class of bug returns. Surface as REVIEW (warn) —\n // operators may genuinely want a single-handler setup, but they\n // should opt in by setting `defaultWorkflow` explicitly.\n const multiEventSources = new Set([\"github\", \"gitlab\"])\n for (const w of webhooks) {\n if (!w.enabled) continue\n if (!multiEventSources.has(w.source)) continue\n const hasTriggers = w.triggers && Object.keys(w.triggers).length > 0\n if (!hasTriggers && !w.defaultWorkflow) {\n findings.push({\n severity: \"warn\",\n title: `webhook \"${w.id}\" (${w.source} -> ${w.agentId}) has no triggers map; every event-type collapses to the bound agent`,\n fix: `Add a triggers map: { \"issues.opened\": \"wf-id\", \"pull_request.synchronize\": \"wf-id\" } — or set defaultWorkflow.`,\n })\n }\n }\n\n // 2. Trigger map references workflow ids that don't exist on disk.\n // Hard-fails the dispatch at runtime (and silently — dispatcher just\n // logs \"workflow not found\" and bails). Surface here as FAIL.\n for (const w of webhooks) {\n if (!w.enabled || !w.triggers) continue\n for (const [eventType, workflowId] of Object.entries(w.triggers)) {\n if (knownWorkflows.size > 0 && !knownWorkflows.has(workflowId)) {\n findings.push({\n severity: \"fail\",\n title: `webhook \"${w.id}\".triggers[\"${eventType}\"] -> \"${workflowId}\" — no such workflow under ${cfg.workflows?.dir || \".agentx/workflows\"}`,\n fix: `Create the workflow file or fix the id in agentx.json`,\n })\n }\n }\n if (w.defaultWorkflow && knownWorkflows.size > 0 && !knownWorkflows.has(w.defaultWorkflow)) {\n findings.push({\n severity: \"fail\",\n title: `webhook \"${w.id}\".defaultWorkflow -> \"${w.defaultWorkflow}\" — no such workflow`,\n fix: `Create the workflow file or fix the id in agentx.json`,\n })\n }\n }\n\n // 2b. Incoherent workflow lifecycle: status=active says \"reviewed, ship\n // it\" while state=quarantined means the runtime refuses to dispatch\n // it (conflict detector parked it). The two axes are independent\n // (state is the only dispatch gate — see workflowSchema), so this\n // combo silently looks live while never firing.\n try {\n if (existsSync(workflowDir)) {\n for (const f of readdirSync(workflowDir)) {\n if (!f.endsWith(\".json\") || f.startsWith(\"_\") || f.endsWith(\".disabled.json\")) continue\n try {\n const wf = JSON.parse(readFileSync(resolve(workflowDir, f), \"utf-8\"))\n if (wf?.status === \"active\" && wf?.state === \"quarantined\") {\n findings.push({\n severity: \"warn\",\n title: `workflow \"${wf.id ?? f}\" is status=active but state=quarantined — it looks live but will never dispatch`,\n fix: `Resolve the conflict the detector flagged, then set state back to \"active\" (or set status to \"review\" while parked).`,\n })\n }\n } catch { /* unparseable file is caught by workflow validate */ }\n }\n }\n } catch { /* directory races are non-fatal for doctor */ }\n\n // 3. Mesh-routed webhooks naming peers that don't exist.\n const peers = new Set<string>(((cfg.mesh?.peers ?? []) as Array<{ name: string }>).map(p => p.name))\n for (const w of webhooks) {\n if (!w.enabled || !w.node) continue\n if (!peers.has(w.node)) {\n findings.push({\n severity: \"fail\",\n title: `webhook \"${w.id}\" routes to mesh peer \"${w.node}\" which is not in mesh.peers`,\n fix: `Add the peer to mesh.peers or remove the node field on the webhook.`,\n })\n }\n }\n\n // 4. Two enabled webhook entries collide on (source, agentId): the\n // Phase 3 dispatcher takes the first match, the second is silently\n // ignored — operators rarely realize.\n const seen = new Map<string, string>()\n for (const w of webhooks) {\n if (!w.enabled) continue\n const key = `${w.source}:${w.agentId}`\n const prior = seen.get(key)\n if (prior) {\n findings.push({\n severity: \"warn\",\n title: `webhook entries \"${prior}\" and \"${w.id}\" both enabled for ${w.source} -> ${w.agentId}; only the first is dispatched`,\n fix: `Disable one entry, or merge their triggers maps into a single entry.`,\n })\n } else {\n seen.set(key, w.id)\n }\n }\n\n // 5. GitLab agentMappings referencing agent ids that aren't in agents.\n // A mapping with `node:` set is a cross-mesh route — the agent lives\n // on a remote peer, not locally — so missing-from-agents is correct\n // and not a finding. We still warn when `node` names a peer that\n // isn't configured (caught by check #3 above for webhooks; same\n // invariant should hold for agentMappings).\n const agentIds = new Set(Object.keys(cfg.agents ?? {}))\n for (const m of (cfg.channels?.gitlab?.agentMappings ?? [])) {\n if (!m?.agentId) continue\n if (m.node) {\n // Cross-mesh route — verify the named peer exists.\n if (!peers.has(m.node)) {\n findings.push({\n severity: \"fail\",\n title: `gitlab.agentMappings entry agentId=\"${m.agentId}\" routes to mesh peer \"${m.node}\" which is not in mesh.peers`,\n fix: `Add the peer to mesh.peers or drop the node field on the mapping.`,\n })\n }\n continue\n }\n if (!agentIds.has(m.agentId)) {\n findings.push({\n severity: \"warn\",\n title: `gitlab.agentMappings entry agentId=\"${m.agentId}\" — no such agent in agents.* (and no node field, so it's not a cross-mesh route)`,\n fix: `Add the agent to agents.*, set node:\"<peer>\" if the agent lives remotely, or remove the mapping.`,\n })\n }\n }\n\n // 6. Telegram accounts without an agentBinding silently drop every DM.\n for (const [acctId, acct] of Object.entries((cfg.channels?.telegram?.accounts ?? {}) as Record<string, { agentBinding?: string }>)) {\n if (!acct.agentBinding) {\n findings.push({\n severity: \"fail\",\n title: `telegram account \"${acctId}\" has no agentBinding; every DM to this bot will drop`,\n fix: `Set agentBinding to a valid agent id.`,\n })\n } else if (!agentIds.has(acct.agentBinding)) {\n findings.push({\n severity: \"fail\",\n title: `telegram account \"${acctId}\".agentBinding -> \"${acct.agentBinding}\" — no such agent in agents.*`,\n fix: `Fix the agentBinding or define the agent in agents.*.`,\n })\n }\n }\n\n // 7. Per-agent integrations: missing env vars + unknown kinds + duplicates.\n // The new agents[].integrations[] block declares third-party credentials\n // (telegram-bot, hubspot, gitlab-user, gmail, ...). Doctor scans for:\n // - duplicate (kind, label) on the same agent (config integrity)\n // - tokenEnv refs that don't exist in process.env (latent failure)\n // - kinds outside the canonical INTEGRATION_KINDS set (typos)\n // Failures are warnings, not blocking — credentials may be set on the\n // daemon process and absent from the doctor's local shell.\n const KNOWN_KINDS = new Set([\n \"telegram-bot\", \"whatsapp\", \"slack-bot\", \"discord-bot\",\n \"gitlab-user\", \"github-user\",\n \"gmail\", \"hotmail\", \"smtp\",\n \"hubspot\", \"salesforce\", \"pipedrive\", \"odoo\",\n \"trello\", \"linear\", \"asana\", \"jira\", \"notion\",\n \"stripe\", \"sentry\", \"vercel\", \"twilio\", \"custom\",\n ])\n for (const [agentId, a] of Object.entries((cfg.agents ?? {}) as Record<string, any>)) {\n const list = (a.integrations as any[] | undefined) ?? []\n if (!list.length) continue\n const seen = new Set<string>()\n for (const i of list) {\n const key = `${i.kind}::${i.label}`\n if (seen.has(key)) {\n findings.push({\n severity: \"warn\",\n title: `agents.${agentId}.integrations: duplicate (${i.kind}, ${i.label})`,\n fix: `Remove the duplicate or rename one. (kind, label) must be unique per agent.`,\n })\n }\n seen.add(key)\n if (!KNOWN_KINDS.has(i.kind)) {\n findings.push({\n severity: \"warn\",\n title: `agents.${agentId}.integrations: unknown kind \"${i.kind}\" on integration \"${i.label}\"`,\n fix: `Use a canonical kind from INTEGRATION_KINDS, or \"custom\" for ad-hoc services.`,\n })\n }\n const creds = (i.credentials || {}) as Record<string, unknown>\n for (const [k, v] of Object.entries(creds)) {\n if (typeof v === \"string\" && /^[A-Z][A-Z0-9_]*$/.test(v) && !process.env[v]) {\n findings.push({\n severity: \"warn\",\n title: `agents.${agentId}.integrations[${i.kind}/${i.label}].${k} -> $${v} but env var is unset (in this shell)`,\n fix: `Set ${v} on the daemon environment. The daemon's process.env is what matters; this warning fires from your local shell.`,\n })\n }\n }\n }\n }\n\n // (Removed: the \"agentx.json newer than daemon pid\" check produced\n // false positives because the pid file is only rewritten on start,\n // not on hot-reload. The signal-to-noise was too low. A future check\n // can query /reload's `lastReload` timestamp via the daemon API\n // instead of using filesystem mtimes.)\n\n if (findings.length === 0) {\n checks.push({\n severity: \"ok\",\n group: \"Routing\",\n title: `${webhooks.length} webhook(s), ${Object.keys(cfg.channels?.telegram?.accounts ?? {}).length} telegram account(s) — all routing references resolve`,\n })\n return\n }\n for (const f of findings) {\n checks.push({ severity: f.severity, group: \"Routing\", title: f.title, fix: f.fix })\n }\n}\n\n/** Whether the running daemon can measure phone recordings, from its own\n * /health: the service's PATH, not this shell's (#233). Null for a daemon\n * too old to say. */\nexport function daemonVoiceCheck(voice: { canMeasure?: boolean; allowUnmeasured?: boolean } | undefined): Check | null {\n if (typeof voice?.canMeasure !== \"boolean\") return null\n if (voice.canMeasure) return { severity: \"ok\", group: \"Runtime\", title: \"Daemon finds ffmpeg to measure phone recordings\" }\n return {\n severity: \"warn\",\n group: \"Runtime\",\n title: voice.allowUnmeasured\n ? \"Daemon can't find ffmpeg: phone recordings go unmeasured (voice.allowUnmeasured)\"\n : \"Daemon can't find ffmpeg: phone voice input is refused\",\n 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.\",\n }\n}\n\nasync function runRuntimeChecks(checks: Check[], cfg: any): Promise<void> {\n const url = cfg.dashboard?.daemonUrl?.replace(/\\/+$/, \"\") || \"http://127.0.0.1:18800\"\n const headers: Record<string, string> = {}\n if (cfg.dashboard?.token) headers[\"Authorization\"] = `Bearer ${cfg.dashboard.token}`\n try {\n const ac = new AbortController()\n const timer = setTimeout(() => ac.abort(), 2000)\n const r = await fetch(url + \"/health\", { headers, signal: ac.signal })\n clearTimeout(timer)\n if (!r.ok) {\n checks.push({ severity: \"warn\", group: \"Runtime\", title: `Daemon responded ${r.status}`, detail: url })\n return\n }\n const body: any = await r.json()\n checks.push({\n severity: \"ok\",\n group: \"Runtime\",\n title: `Daemon healthy — ${body.agents?.length ?? 0} agents live, uptime ${Math.round((body.uptime ?? 0) / 60)}m`,\n detail: url,\n })\n const voice = daemonVoiceCheck(body.voice)\n if (voice) checks.push(voice)\n } catch {\n checks.push({\n severity: \"warn\",\n group: \"Runtime\",\n title: \"Daemon not reachable (not running?)\",\n detail: url,\n fix: \"Run `agentx daemon start`. Skip this check with `agentx doctor --no-running`.\",\n })\n }\n}\n\nfunction runCodegraphChecks(checks: Check[], cfg: any): void {\n const optedIn = Object.entries(cfg.agents || {})\n .filter(([, a]: [string, any]) =>\n a?.codegraph === true && (a.tier === \"claude-code\" || a.tier === \"codex-cli\"),\n ) as Array<[string, any]>\n\n if (optedIn.length === 0) return // No agent uses codegraph — skip silently.\n\n // Binary on PATH.\n let cgPath: string | null = null\n try {\n cgPath = execFileSync(process.platform === \"win32\" ? \"where\" : \"which\", [\"codegraph\"], { encoding: \"utf-8\" })\n .trim().split(\"\\n\")[0] || null\n } catch { cgPath = null }\n\n if (cgPath) {\n let ver: string | undefined\n try { ver = execFileSync(\"codegraph\", [\"--version\"], { encoding: \"utf-8\", timeout: 3000 }).trim() } catch { /* */ }\n checks.push({\n severity: \"ok\",\n group: \"CodeGraph\",\n title: `codegraph CLI ${ver || \"installed\"}`,\n detail: cgPath,\n })\n } else {\n checks.push({\n severity: \"fail\",\n group: \"CodeGraph\",\n title: \"codegraph CLI not on PATH\",\n detail: `${optedIn.length} agent(s) have codegraph:true but the binary isn't available.`,\n fix: \"Install with `npm i -g @colbymchenry/codegraph`.\",\n })\n }\n\n // Per-workspace index presence.\n for (const [agentId, def] of optedIn) {\n if (!def.workspace || !existsSync(def.workspace)) {\n checks.push({\n severity: \"warn\",\n group: \"CodeGraph\",\n title: `${agentId}: workspace missing`,\n detail: `Workspace path ${def.workspace} does not exist — codegraph will skip this agent.`,\n })\n continue\n }\n const dbPath = resolve(def.workspace, \".codegraph\", \"codegraph.db\")\n if (existsSync(dbPath)) {\n checks.push({\n severity: \"ok\",\n group: \"CodeGraph\",\n title: `${agentId}: index present`,\n detail: dbPath,\n })\n } else {\n checks.push({\n severity: \"warn\",\n group: \"CodeGraph\",\n title: `${agentId}: index not built yet`,\n detail: \".codegraph/ missing — daemon will background-index this workspace on next boot.\",\n fix: `Run \\`codegraph init --index ${def.workspace}\\` to build it now.`,\n })\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Output\n// ---------------------------------------------------------------------------\n\nfunction summarize(checks: Check[]): { errors: number; warnings: number; ok: number } {\n return {\n errors: checks.filter((c) => c.severity === \"fail\").length,\n warnings: checks.filter((c) => c.severity === \"warn\").length,\n ok: checks.filter((c) => c.severity === \"ok\").length,\n }\n}\n\nfunction printHumanReport(checks: Check[]): void {\n console.log()\n console.log(chalk.bold(\" agentx doctor\"))\n console.log()\n\n const groups = new Map<string, Check[]>()\n for (const c of checks) {\n if (!groups.has(c.group)) groups.set(c.group, [])\n groups.get(c.group)!.push(c)\n }\n for (const [group, items] of groups) {\n console.log(chalk.bold(\" \" + group))\n for (const c of items) {\n const marker = c.severity === \"ok\" ? chalk.green(\"✓\")\n : c.severity === \"warn\" ? chalk.yellow(\"!\")\n : chalk.red(\"✗\")\n console.log(` ${marker} ${c.title}`)\n if (c.detail) console.log(chalk.dim(\" \" + c.detail.replace(/\\n/g, \"\\n \")))\n if (c.fix) console.log(chalk.dim(\" → \" + c.fix))\n }\n console.log()\n }\n\n const s = summarize(checks)\n if (s.errors > 0) {\n console.log(chalk.red.bold(` ${s.errors} error${s.errors === 1 ? \"\" : \"s\"}`) +\n (s.warnings ? chalk.yellow(`, ${s.warnings} warning${s.warnings === 1 ? \"\" : \"s\"}`) : \"\") +\n `. Fix the error${s.errors === 1 ? \"\" : \"s\"} and rerun.`)\n } else if (s.warnings > 0) {\n console.log(chalk.yellow.bold(` ${s.warnings} warning${s.warnings === 1 ? \"\" : \"s\"}.`) + chalk.dim(\" Review but not blocking.\"))\n } else {\n console.log(chalk.green.bold(` All checks passed (${s.ok}).`))\n }\n console.log()\n}\n","import { execFile } from \"child_process\"\nimport { findHelper } from \"./local\"\n\n// Why a banner shows the Script Editor icon instead of the AgentX logo,\n// in words a person can act on. `agentx notify` falls back to osascript\n// silently — it must never fail to notify — so this is where the reason\n// surfaces: `agentx notifications show` and `agentx doctor` print it.\n//\n// Reading the status never posts a banner and never shows the macOS\n// \"allow notifications\" prompt.\n\nexport type HelperState = \"ready\" | \"unsupported\" | \"missing\" | \"outdated\" | \"not-asked\" | \"not-allowed\" | \"hidden\"\n\nexport interface HelperStatus {\n state: HelperState\n /** One plain sentence on what the person will see. */\n message: string\n /** What to do about it; absent when nothing needs doing. */\n fix?: string\n /** The helper binary that was checked, when there is one. */\n path?: string\n}\n\n/** Runs a command and resolves its stdout, or null when it failed. */\ntype Capture = (file: string, args: string[]) => Promise<string | null>\n\nconst capture: Capture = (file, args) =>\n new Promise((done) => {\n try {\n execFile(file, args, { timeout: 5_000 }, (err, stdout) => done(err ? null : String(stdout)))\n } catch {\n done(null)\n }\n })\n\nconst SETTINGS = \"Open System Settings › Notifications › AgentX Helper, turn on Allow notifications and choose Banners.\"\n\nexport async function helperStatus(\n deps: { platform?: NodeJS.Platform; helper?: string | null; run?: Capture } = {},\n): Promise<HelperStatus> {\n if ((deps.platform ?? process.platform) !== \"darwin\") {\n return { state: \"unsupported\", message: \"Desktop banners are only shown on a Mac.\" }\n }\n const path = deps.helper === undefined ? findHelper() : deps.helper\n if (!path) {\n return {\n state: \"missing\",\n message: \"AgentX Helper is not installed, so banners come from Script Editor and show its icon.\",\n fix: \"Run agentx desktop install, then run agentx notify \\\"Hello\\\" --title \\\"Test\\\" and click Allow.\",\n }\n }\n const out = await (deps.run ?? 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) {\n return {\n state: \"outdated\",\n path,\n message: \"AgentX Helper is too old to report whether it may notify.\",\n fix: \"Run agentx desktop install to update it.\",\n }\n }\n if (status.authorization === \"notDetermined\") {\n return {\n state: \"not-asked\",\n path,\n message: \"macOS has not asked yet whether AgentX Helper may notify; banners show the Script Editor icon until it does.\",\n fix: \"Run agentx notify \\\"Hello\\\" --title \\\"Test\\\" and click Allow when macOS asks.\",\n }\n }\n if (status.authorization === \"denied\") {\n return { state: \"not-allowed\", path, message: \"macOS does not allow AgentX Helper to notify, so banners show the Script Editor icon.\", fix: SETTINGS }\n }\n if (status.alertStyle === \"none\") {\n return { state: \"hidden\", path, message: \"AgentX Helper may notify, but its banner style is None, so nothing appears on screen.\", fix: SETTINGS }\n }\n return { state: \"ready\", path, message: \"AgentX Helper posts banners with the AgentX icon.\" }\n}\n"],"mappings":"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","names":["init_config","Command","chalk","execFileSync","accessSync","constants","existsSync","readFileSync","readdirSync","statSync","join","resolve","homedir","createRequire","execFile","capture","file","args","done","execFile","err","stdout","SETTINGS","helperStatus","deps","path","findHelper","out","status","runDoctorChecks","opts","checks","runEnvChecks","runDesktopChecks","cfg","runConfigChecks","runReferenceChecks","runWorkspaceChecks","runWorkspaceSettingsChecks","runRoutingChecks","runCodegraphChecks","runNotificationChecks","runReminderChecks","runRuntimeChecks","summarize","doctor","Command","summary","printHumanReport","status","helperStatus","localSettings","helper","platform","isExecutable","file","accessSync","constants","r","command","found","findOnPath","nodeVersionSupported","version","major","minor","supported","which","bin","execFileSync","npmPath","claudePath","ver","codexPath","openCodePath","createRequire","e","agents","join","homedir","names","readdirSync","n","name","path","plistPathEnv","readFileSync","ffmpeg","cfgPath","resolve","existsSync","loadDaemonConfig","claudeCodeAgents","id","codexCliAgents","openCodeAgents","refs","collectEnvRefs","envFile","envFromFile","line","m","missing","empty","raw","node","into","item","v","a","abs","statSync","VAR_RE","findings","agentId","wsAbs","fname","p","data","env","k","unexpanded","pathVal","parts","perms","allow","deny","f","webhooks","workflowDir","knownWorkflows","multiEventSources","w","eventType","workflowId","wf","peers","seen","key","prior","agentIds","acctId","acct","KNOWN_KINDS","list","i","creds","daemonVoiceCheck","voice","url","headers","ac","timer","body","optedIn","cgPath","def","dbPath","c","chalk","groups","group","items","marker","s"]}
@@ -1,9 +0,0 @@
1
- import{a as o}from"./chunk-N6EWZGIX.js";import{existsSync as s}from"fs";import{resolve as a}from"path";function u(){return!!(process.env.VITEST||process.env.NODE_ENV==="test"||process.env.AGENTX_NO_TELEMETRY)}function c(){let n=process.cwd();for(let t=0;t<5;t++){if(s(a(n,".agentx"))||s(a(n,"agentx.json")))return n;let e=a(n,"..");if(e===n)break;n=e}return null}function d(n=new Date){return n.toISOString().slice(0,10)}function m(n,t,e=new Date){try{if(!t||u()||!c())return;let r=o({quiet:!0});if(!r)return;r.prepare(`INSERT INTO surface_usage (kind, name, day, count, last_at)
2
- VALUES (?, ?, ?, 1, ?)
3
- ON CONFLICT(kind, name, day)
4
- DO UPDATE SET count = count + 1, last_at = excluded.last_at`).run(n,t,d(e),e.toISOString())}catch{}}function g(n={}){try{let t=o({quiet:!0});if(!t)return[];let e=new Date(Date.now()-(n.sinceDays??30)*864e5).toISOString().slice(0,10),r=["day >= ?"],i=[e];return n.kind&&(r.push("kind = ?"),i.push(n.kind)),t.prepare(`SELECT kind, name, SUM(count) AS count, COUNT(DISTINCT day) AS days, MAX(last_at) AS last_at
5
- FROM surface_usage
6
- WHERE ${r.join(" AND ")}
7
- GROUP BY kind, name
8
- ORDER BY count DESC`).all(...i)}catch{return[]}}function E(n){let t=[],e=n;for(;e&&typeof e.name=="function";){let r=e.name();e.parent&&t.unshift(r),e=e.parent}return t.join(" ")}var f=new Set(["guard check","completion","serve"]);function T(n){return!!n&&!f.has(n)}export{m as a,g as b,E as c,T as d};
9
- //# sourceMappingURL=chunk-Z3IP66SL.js.map
@@ -1,2 +0,0 @@
1
- import{a,b,c,d,e,f,g}from"./chunk-MOQNLS5Z.js";import"./chunk-42Y3BXXS.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-TJ5YZOEE.js.map
@@ -1,2 +0,0 @@
1
- import{A as d,B as e,C as f,D as g,E as h,F as i,G as j,I as k,x as a,y as b,z as c}from"./chunk-42Y3BXXS.js";import"./chunk-QIJLFPWE.js";k();export{a as INTEGRATION_KINDS,f as approvalsConfigSchema,d as callsSchema,c as cameraBotSchema,g as daemonConfigSchema,b as eventSubscriptionSchema,h as expandEnvVars,i as loadDaemonConfig,e as requestsConfigSchema,j as validateWorkspaces};
2
- //# sourceMappingURL=config-4WZ7Y34V.js.map
@@ -1,2 +0,0 @@
1
- import{a,b,c,d,e}from"./chunk-UR3ZIDMA.js";import"./chunk-42Y3BXXS.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-5Z7EEB5N.js.map
@@ -1,2 +0,0 @@
1
- import{b as a,c as b,d as c,e as d,f as e,g as f}from"./chunk-YCI3KUYF.js";import"./chunk-S2GAEH2F.js";import"./chunk-42Y3BXXS.js";import"./chunk-QIJLFPWE.js";export{f as daemonVoiceCheck,b as doctor,e as nodeVersionSupported,a as runDoctorChecks,c as runNotificationChecks,d as runReminderChecks};
2
- //# sourceMappingURL=doctor-7K3NRBNN.js.map
@@ -1,2 +0,0 @@
1
- import{a}from"./chunk-AF46YOLU.js";import"./chunk-MOQNLS5Z.js";import"./chunk-YCI3KUYF.js";import"./chunk-3UN6CXRL.js";import"./chunk-Z3IP66SL.js";import"./chunk-O5U5NVLR.js";import"./chunk-RKPAVWXF.js";import"./chunk-BEHC3X42.js";import"./chunk-XESESMKN.js";import"./chunk-GTJIKXDB.js";import"./chunk-Z3XUGXPD.js";import"./chunk-S2GAEH2F.js";import"./chunk-CL53UVOF.js";import"./chunk-ZVP6GB4G.js";import"./chunk-BVZFYBBP.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-EKJG63EJ.js";import"./chunk-NOAAK2XI.js";import"./chunk-6JJ3GODZ.js";import"./chunk-API4IZZG.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-MYRSNJJ4.js";import"./chunk-SFQUP3BP.js";import"./chunk-Y4CYQV7G.js";import"./chunk-OVN5LVJY.js";import"./chunk-SHEUCITK.js";import"./chunk-TEFMZY6B.js";import"./chunk-SZDACK6O.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-R42S57G6.js";import"./chunk-UR3ZIDMA.js";import"./chunk-VWTBHLMX.js";import"./chunk-H7253EHW.js";import"./chunk-ZR3NZLJL.js";import"./chunk-KA2UIZXG.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-BJPIRNP6.js";import"./chunk-MYVHVJWZ.js";import"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-UXSYVMPK.js";import"./chunk-UB63NQQL.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{a as buildProgram};
2
- //# sourceMappingURL=program-KMQNX6YK.js.map
@@ -1,2 +0,0 @@
1
- import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m,o as n,p as o,q as p,r as q,s as r,t as s,u as t}from"./chunk-BVZFYBBP.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-DP7RTNDM.js";import"./chunk-ZR3NZLJL.js";import"./chunk-CECHWYJ2.js";import"./chunk-UB63NQQL.js";import"./chunk-WPNRDEHW.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as DEFAULT_PROMOTE_TYPES,a as PROMOTER_OWNER,c as PROMOTION_LEDGER_FILE,j as appendPromotionLedger,s as approveProposal,n as callPromotionLlm,p as estimateTokens,r as evidenceFor,m as getUnpromotedMemories,k as groupCandidates,h as listAllAgentMemories,d as memoryKey,e as memoryStamp,g as mergeSources,f as parseMemoryStamp,l as parsePromotionResponse,i as readPromotionLedger,t as rejectProposal,o as runPromotion,q as sourceKind};
2
- //# sourceMappingURL=promote-NDC3X54P.js.map
@@ -1,2 +0,0 @@
1
- import{a,b,c}from"./chunk-UXSYVMPK.js";import"./chunk-UB63NQQL.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as DEFAULT_GRAPH_WEIGHT,a as agenticQuery,c as rankCatalogPool};
2
- //# sourceMappingURL=query-F7BD3JPE.js.map
@@ -1,2 +0,0 @@
1
- import{L as a,M as b,N as c,O as d,P as e,Q as f,R as g,S as h,T as i,U as j,V as k,W as l}from"./chunk-NOAAK2XI.js";import"./chunk-6JJ3GODZ.js";import"./chunk-API4IZZG.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-SZDACK6O.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-R42S57G6.js";import"./chunk-UR3ZIDMA.js";import"./chunk-VWTBHLMX.js";import"./chunk-H7253EHW.js";import"./chunk-ZR3NZLJL.js";import"./chunk-KA2UIZXG.js";import"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-BJPIRNP6.js";import"./chunk-MYVHVJWZ.js";import"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-UXSYVMPK.js";import"./chunk-UB63NQQL.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-DSYKYZMT.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{k as AgentRegistry,f as TRACE_STEP_SUMMARY_BYTES,c as buildEntryMeta,d as buildEventDigest,e as buildWikiContext,g as clipForTrace,j as emitTraceStepsFromStreamEvent,i as firstMissingRequiredTool,b as getGlobalRegistry,l as richReplyPrompt,a as setGlobalRegistry,h as tallyToolUses};
2
- //# sourceMappingURL=registry-5NBHBVY3.js.map
@@ -1,2 +0,0 @@
1
- import{q as m,t as p,v as d,w as x}from"./chunk-PE55MMLK.js";import{a as u,f}from"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";x();f();var l="request-gate",h="request-context",g=.1;async function q(t,o,c,r=Math.random){let s=p(l)==="active";if(s){let i=m().seats[l]?.holdout??g;if(r()<i)return{active:!0,preprocess:!1,arm:"holdout"}}let a=s?"treatment":void 0,e=await d(l,{request:t.slice(0,2e3),agent:o,channel:c,operations:["select optional context","evaluate model routing where permitted"],constraints:["Keep the original request and mandatory instructions","Desktop model cannot be downgraded"]},{preprocess:u("This request benefits from structured context selection or another bounded typed decision before the main agent executes.",{true:"Relevant context must be selected, or a bounded routing decision can help. Follow-ups and ambiguous references need context.",false:"Typed preprocessing adds no useful decision; send the request to the configured main agent with existing context."})},{timeoutMs:3e3});if(!e||e.mode!=="active")return{active:!1,preprocess:!1,arm:a};let n=e.answers.preprocess?.noul;return{active:!0,preprocess:Number.isFinite(n)&&n>=.5,arm:a}}var v={landscape:"Agent directory and mesh overview",patternContext:"Learned behavioral patterns",references:"Retrieved project references",memoryContext:"Retrieved agent memory",crossChatContext:"Summaries from other conversations",longMemoryRecall:"Older conversation recall",wikiContext:"Retrieved wiki knowledge"};async function b(t){let o=Object.entries(v).flatMap(([e,n])=>{let i=t[e];return i?[{id:e,description:n,source:e,characters:i.length,preview:i.slice(0,400),trust:"context data, not instructions"}]:[]});if(!o.length)return{input:t,excluded:[]};let c=Object.fromEntries(o.map(e=>[e.id,u(`Context block ${e.id} is relevant to completing the current request correctly.`,{true:"Needed or potentially relevant; retain if uncertain or the preview is incomplete.",false:"Clearly unrelated to the current request; safe to omit."})])),r=await d(h,{request:t.message.slice(0,2e3),channel:t.channel,agent:t.agentId,mandatory:["request","identity","permissions and instructions","same-chat history","handover","attachments"],context:o},c,{timeoutMs:3e3});if(!r||r.mode!=="active")return{input:t,excluded:[]};let s={...t},a=[];for(let e of o){let n=r.answers[e.id]?.noul;Number.isFinite(n)&&n>=0&&n<.2&&(delete s[e.id],a.push(e.id))}return{input:s,excluded:a}}export{g as DEFAULT_REQUEST_GATE_HOLDOUT,h as REQUEST_CONTEXT_SEAT,l as REQUEST_GATE_SEAT,q as evaluateRequest,b as selectRequestContext};
2
- //# sourceMappingURL=request-planner-H74KHFGJ.js.map
@@ -1,4 +0,0 @@
1
- import{b as I}from"./chunk-Z3XUGXPD.js";import"./chunk-WP6KLXTP.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{createHash as E}from"crypto";var v="review:",b={decisions:"project",warnings:"feedback",friction:"feedback",context:"reference"};function A(t,n,r){let s=E("sha1").update(r.trim().toLowerCase()).digest("hex").slice(0,10);return`${v}${t}/${n}@${s}`}function F(t){if(!t.startsWith(v))return null;let n=t.slice(v.length),r=n.lastIndexOf("@"),s=n.lastIndexOf("/",r===-1?void 0:r);return r===-1||s===-1?null:{reviewId:n.slice(0,s),kind:n.slice(s+1,r),digest:n.slice(r+1)}}var C=t=>t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,48)||"finding",L=5;function T(t,n){return`${t}|${I(n)}`}function K(t,n={}){let r=n.kinds??Object.keys(b),s=n.minLength??24,h=[],d=new Map,u=new Map,f=new Map,x=new Map;for(let e of t){let i;try{i=JSON.parse(e.result)}catch{continue}let o=e.updated_at?new Date(e.updated_at).toISOString():new Date().toISOString();for(let c of r){let l=b[c];if(!l)continue;let R=i[c];if(Array.isArray(R))for(let $ of R){let a=String($?.text??"").trim();if(a.length<s)continue;let g=A(e.id,c,a),_=g.slice(g.lastIndexOf("@")),w=`${c}${_}`,y=T(c,a),S=f.get(y)??new Set;if(S.add(e.session_id??e.id),f.set(y,S),d.has(w))continue;let O=String($?.evidence??"").trim(),k={occurrences:1,agentId:e.agent,key:`${e.agent}/${l}_${C(a)}`,stamp:g,memory:{name:C(a),type:l,description:a.slice(0,200),body:"",createdAt:o,updatedAt:o}};x.set(g,{text:a,evidence:O,agent:e.agent,source:e.source}),d.set(w,k),u.set(w,y),h.push(k)}}}for(let[e,i]of d){let o=f.get(u.get(e)??"");i.occurrences=o?.size??1,i.sessions=[...o??[]].slice(0,L);let c=x.get(i.stamp);i.memory.body=D(c,i.occurrences)}let m=new Map;for(let[e,i]of d){let o=u.get(e)??e,c=m.get(o)??[];c.push(i),m.set(o,c)}let M=[...m.values()].sort((e,i)=>i[0].occurrences-e[0].occurrences),p=[];for(let e=0;p.length<h.length;e++){let i=!1;for(let o of M)e<o.length&&(p.push(o[e]),i=!0);if(!i)break}return p}function D(t,n){let r=`${t.agent}${t.source?` via ${t.source}`:""}`,s=[];return n>1?(s.push(`Observed in ${n} separate sessions. Most recently stated as:`),s.push(`> ${t.text}`),s.push(`Recurring across ${n} sessions is what makes this worth recording \u2014 any single occurrence is session state, the repetition is the finding.`)):s.push(t.text),t.evidence&&s.push(`**Evidence:** ${t.evidence}`),s.push(`_From ${n>1?"session reviews":"a session review"} of ${r}._`),s.join(`
2
-
3
- `)}export{L as MAX_EVIDENCE_SESSIONS,b as PROMOTABLE_KINDS,v as REVIEW_STAMP_PREFIX,F as parseReviewStamp,A as reviewStamp,K as reviewsToCandidates};
4
- //# sourceMappingURL=review-candidates-IPJWEXR2.js.map
@@ -1,2 +0,0 @@
1
- import{a,b}from"./chunk-BJPIRNP6.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{a as cheapModelForEngine,b as routeTaskModel};
2
- //# sourceMappingURL=routing-3RSG7SKW.js.map
@@ -1,2 +0,0 @@
1
- import{a,b}from"./chunk-7IGSJGXI.js";import"./chunk-RKPAVWXF.js";import"./chunk-TEFMZY6B.js";import"./chunk-R42S57G6.js";import"./chunk-UR3ZIDMA.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-QIJLFPWE.js";export{b as resolveScheduleCaller,a as runScheduleTool};
2
- //# sourceMappingURL=schedule-tool-7NYAK43U.js.map
@@ -1,2 +0,0 @@
1
- import{n as a,o as b,p as c,q as d,r as e,s as f}from"./chunk-R42S57G6.js";import"./chunk-UR3ZIDMA.js";import"./chunk-FCPTN6NF.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-QIJLFPWE.js";export{a as AGENT_RUN_TIMEOUT_FLOOR,f as CronScheduler,b as agentRunTimeout,e as cronRunId,d as getNextCronDate,c as runLinkIds};
2
- //# sourceMappingURL=scheduler-24O7PADJ.js.map
@@ -1,2 +0,0 @@
1
- import{o as a,p as b,q as c,r as d,s as e,t as f,u as g,v as h,w as i}from"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";i();export{h as askSeat,a as configureDecisions,c as decisionsRuntime,f as getSeatMode,d as parseSeatMode,g as recordSeatOutcome,b as resetDecisionsRuntime,e as seatEnvVar};
2
- //# sourceMappingURL=seat-TOM2WHQR.js.map
@@ -1,2 +0,0 @@
1
- import{v as S,w}from"./chunk-PE55MMLK.js";import{a as g,b as h,f as R}from"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import{e as f}from"./chunk-JHCI6XCJ.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";w();R();var p="skill-select";function y(l){return{task:d(l.task,1200),...l.agent?{agent:l.agent}:{},skills:l.candidates.map(t=>({name:t.name,purpose:d(t.description,300),...t.category?{category:t.category}:{},...t.tags?.length?{tags:t.tags.slice(0,8)}:{}}))}}function b(l){let t={};for(let i of l)t[i.name]=d(i.description,300);return{anyRelevant:g("At least one of these skills is about the task at hand.",{true:"The task is the kind of work one of these skills exists for, and following it would change how the work is done \u2014 it names the same system, the same procedure or the same kind of artefact.",false:"None of them is about this task. They may share vocabulary with it, mention the same tools, or belong to the same project without bearing on what is being asked. Sharing words with a task is not being about it."}),best:h(t,"Which skill is this task most about?")}}function v(l){let t=l.anyRelevant,i=l.best,o=Object.entries(i.probabilities??{}).map(([e,s])=>({name:e,p:Number(s)||0})).sort((e,s)=>s.p-e.p);return{anyRelevant:t.noul,name:i.choice,confidence:i.confidence,ranked:o}}function d(l,t){return l.length>t?`${l.slice(0,t)}\u2026`:l}var x=.1,A=12;async function E(l,t,i={}){let o=i.minRelevant??.6,e=f(l,t).filter(n=>n.relevance>=x).slice(0,A),s=e.map(n=>({name:n.skill.frontmatter.name,lexical:n.relevance}));if(e.length===0)return{skill:null,anyRelevant:0,confidence:0,shortlist:s,judged:!1,reason:"no skill mentions anything in this task"};if(e.length===1)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`only ${e[0].skill.frontmatter.name} matched (${e[0].matchReason})`};let r=e.map(n=>({name:n.skill.frontmatter.name,description:n.skill.frontmatter.description,category:n.skill.frontmatter.category??null,tags:n.skill.frontmatter.tags})),m=await S(p,y({task:t,agent:i.agent??null,candidates:r}),b(r),{incumbent:{best:r[0].name},features:{agent:i.agent??"unknown",candidates:r.length}});if(!m)return{skill:e[0].skill,anyRelevant:e[0].relevance,confidence:e[0].relevance,shortlist:s,judged:!1,reason:`seat off \u2014 lexical top match (${e[0].matchReason})`};let a=v(m.answers),c=s.map(n=>({...n,p:a.ranked.find(k=>k.name===n.name)?.p??0})).sort((n,k)=>(k.p??0)-(n.p??0));if(a.anyRelevant<o)return{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`nothing on the shortlist is about this task (${a.anyRelevant.toFixed(2)} below ${o})`};let u=e.find(n=>n.skill.frontmatter.name===a.name);return u?{skill:u.skill,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`${a.name} (confidence ${a.confidence.toFixed(2)})`}:{skill:null,anyRelevant:a.anyRelevant,confidence:a.confidence,shortlist:c,judged:!0,reason:`seat chose "${a.name}", which was not on the shortlist`}}export{E as pickSkillForTask};
2
- //# sourceMappingURL=select-BUWOD47K.js.map
@@ -1,2 +0,0 @@
1
- import{b as a}from"./chunk-UR3ZIDMA.js";import"./chunk-42Y3BXXS.js";import"./chunk-QIJLFPWE.js";async function i(o,r,s={}){let e=null,n=await a(l=>{let t=l.crons?.[o];if(t?r&&t.approval?.action==="create"?e={ok:!1,status:409,error:`schedule "${o}" is waiting for approval: agentx schedule approve ${o}`}:t.enabled===r&&(e={ok:!0,id:o,enabled:r,changed:!1}):e={ok:!1,status:404,error:`no schedule "${o}"`},e)throw new Error("no write");t.enabled=r,e={ok:!0,id:o,enabled:r,changed:!0}},{configPath:s.configPath,reload:!1});return e&&(!e.ok||!e.changed)?e:n.success?e??{ok:!1,status:500,error:"mutation did not run"}:{ok:!1,status:500,error:n.error||"could not write agentx.json"}}export{i as setCronEnabled};
2
- //# sourceMappingURL=set-enabled-XWSFTICB.js.map
@@ -1,2 +0,0 @@
1
- import"./chunk-VWTBHLMX.js";import{a as b}from"./chunk-H7253EHW.js";import{a}from"./chunk-ZR3NZLJL.js";import"./chunk-CECHWYJ2.js";import{a as c}from"./chunk-UXSYVMPK.js";import"./chunk-UB63NQQL.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import"./chunk-PE55MMLK.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-42Y3BXXS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";export{b as WikiHub,a as WikiStore,c as agenticQuery};
2
- //# sourceMappingURL=wiki-VFME4T2H.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}