agentix-cli 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +29 -0
  2. package/apps/mac-voice/Sources/AgentXVoice/Config.swift +7 -0
  3. package/apps/mac-voice/Sources/AgentXVoice/Orb.swift +311 -0
  4. package/apps/mac-voice/Sources/AgentXVoice/OrbMath.swift +57 -0
  5. package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +14 -1
  6. package/apps/mac-voice/Sources/AgentXVoice/ResultCard.swift +33 -1
  7. package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +74 -3
  8. package/apps/mac-voice/Sources/AgentXVoice/main.swift +197 -14
  9. package/apps/mac-voice/build.sh +1 -1
  10. package/dist/{App-VRTLAPRF.js → App-4EM7IPB3.js} +2 -2
  11. package/dist/{ChatApp-YENWPZT4.js → ChatApp-FYTEEGSU.js} +2 -2
  12. package/dist/{agent-HVUGHYBF.js → agent-RZ46ZB4W.js} +2 -2
  13. package/dist/{board-dashboard-3XJVYDB3.js → board-dashboard-NRRYCDZW.js} +826 -180
  14. package/dist/board-dashboard-NRRYCDZW.js.map +1 -0
  15. package/dist/{chunk-M67AN4J7.js → chunk-4HEVSWO3.js} +2 -2
  16. package/dist/{chunk-KLDGJSR5.js → chunk-6AK6WKE5.js} +2 -2
  17. package/dist/{chunk-ENRJ2QEH.js → chunk-723K4SAW.js} +2 -2
  18. package/dist/{chunk-UYMK3XNB.js → chunk-76AHNHWC.js} +2 -2
  19. package/dist/{chunk-XWU7O3S5.js → chunk-C3VRBEJ7.js} +2 -2
  20. package/dist/{chunk-HQMISQ7L.js → chunk-CELYD5QW.js} +2 -2
  21. package/dist/{chunk-33QV5O6P.js → chunk-D3LSPFHK.js} +2 -2
  22. package/dist/chunk-EJ5ISSWW.js +151 -0
  23. package/dist/chunk-EJ5ISSWW.js.map +1 -0
  24. package/dist/{chunk-4HNHHKJF.js → chunk-EZN2YXRY.js} +2 -2
  25. package/dist/{chunk-BKDUCPZ3.js → chunk-GSOL2LW6.js} +2 -2
  26. package/dist/{chunk-TLFJVLVQ.js → chunk-IL2XLW4H.js} +152 -151
  27. package/dist/chunk-IL2XLW4H.js.map +1 -0
  28. package/dist/{chunk-WLRHL2P7.js → chunk-LKJSPO3S.js} +2 -2
  29. package/dist/{chunk-37EABIOJ.js → chunk-M4AG2YNX.js} +2 -2
  30. package/dist/{chunk-ZOJUHPD5.js → chunk-O3XG2NVR.js} +18 -18
  31. package/dist/{chunk-ZOJUHPD5.js.map → chunk-O3XG2NVR.js.map} +1 -1
  32. package/dist/{chunk-QYHABRLM.js → chunk-SA23V7WX.js} +2 -2
  33. package/dist/chunk-U4H35SJS.js +15 -0
  34. package/dist/chunk-U4H35SJS.js.map +1 -0
  35. package/dist/{chunk-3RCFUIYR.js → chunk-UIVHSYCN.js} +9 -9
  36. package/dist/chunk-UIVHSYCN.js.map +1 -0
  37. package/dist/{chunk-3W2KMI5O.js → chunk-W4YMMWJL.js} +2 -2
  38. package/dist/{chunk-6JHA3ZE6.js → chunk-WKMTT2UY.js} +211 -197
  39. package/dist/chunk-WKMTT2UY.js.map +1 -0
  40. package/dist/chunk-WOMQ2VGA.js +5 -0
  41. package/dist/{chunk-QX4R5WY7.js.map → chunk-WOMQ2VGA.js.map} +1 -1
  42. package/dist/chunk-X5C5W3E4.js +3 -0
  43. package/dist/chunk-X5C5W3E4.js.map +1 -0
  44. package/dist/{chunk-2TJYZF4E.js → chunk-XEOAKD5C.js} +2 -2
  45. package/dist/cli.js +1 -1
  46. package/dist/cli.js.map +1 -1
  47. package/dist/client-IA7ZPE56.js +2 -0
  48. package/dist/config-HPN2F7LH.js +2 -0
  49. package/dist/config-mutator-7GPTMTVB.js +2 -0
  50. package/dist/doctor-IBWQVQV4.js +2 -0
  51. package/dist/index.d.ts +185 -19
  52. package/dist/index.js +1 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/program-G6DIFJUF.js +2 -0
  55. package/dist/{promote-H6ZHJXTY.js → promote-T4UJROEH.js} +2 -2
  56. package/dist/query-VUJC4Y5O.js +2 -0
  57. package/dist/registry-DX2RI7I7.js +2 -0
  58. package/dist/{request-planner-ABD4WIGM.js → request-planner-B7DE7VJR.js} +2 -2
  59. package/dist/{review-candidates-B6574GOJ.js → review-candidates-4YJHIBAF.js} +2 -2
  60. package/dist/routing-MZG3UODH.js +2 -0
  61. package/dist/schedule-tool-A4OFQ4YZ.js +2 -0
  62. package/dist/scheduler-RHJW2V4M.js +2 -0
  63. package/dist/seat-2PEI7JRX.js +2 -0
  64. package/dist/{select-Y7SBUCGJ.js → select-4KIUR27O.js} +2 -2
  65. package/dist/{set-enabled-ARKMDLXN.js → set-enabled-SE7HQKPF.js} +2 -2
  66. package/dist/subscriptions-RYVPHVIV.js +2 -0
  67. package/dist/{tool-5EVYUN2G.js → tool-5VMD7IE4.js} +2 -2
  68. package/dist/wiki-2QFLAH4U.js +2 -0
  69. package/dist/wiki-2QFLAH4U.js.map +1 -0
  70. package/package.json +1 -1
  71. package/dist/board-dashboard-3XJVYDB3.js.map +0 -1
  72. package/dist/chunk-3RCFUIYR.js.map +0 -1
  73. package/dist/chunk-4FFWNPFX.js +0 -15
  74. package/dist/chunk-4FFWNPFX.js.map +0 -1
  75. package/dist/chunk-6JHA3ZE6.js.map +0 -1
  76. package/dist/chunk-BMSPRUEJ.js +0 -150
  77. package/dist/chunk-BMSPRUEJ.js.map +0 -1
  78. package/dist/chunk-QX4R5WY7.js +0 -5
  79. package/dist/chunk-TLFJVLVQ.js.map +0 -1
  80. package/dist/client-N4XQEAVL.js +0 -2
  81. package/dist/config-KHKIY6LI.js +0 -2
  82. package/dist/config-mutator-ZZKFQ7HJ.js +0 -2
  83. package/dist/doctor-QICAXIQB.js +0 -2
  84. package/dist/program-ZWNGK3RB.js +0 -2
  85. package/dist/query-FTE4FLYK.js +0 -2
  86. package/dist/registry-HDOFVNRK.js +0 -2
  87. package/dist/routing-BGKZOHOA.js +0 -2
  88. package/dist/schedule-tool-UDHXTKWV.js +0 -2
  89. package/dist/scheduler-NQM3HVUY.js +0 -2
  90. package/dist/seat-VGST5AQB.js +0 -2
  91. package/dist/wiki-GREI2TSP.js +0 -2
  92. /package/dist/{App-VRTLAPRF.js.map → App-4EM7IPB3.js.map} +0 -0
  93. /package/dist/{ChatApp-YENWPZT4.js.map → ChatApp-FYTEEGSU.js.map} +0 -0
  94. /package/dist/{agent-HVUGHYBF.js.map → agent-RZ46ZB4W.js.map} +0 -0
  95. /package/dist/{chunk-M67AN4J7.js.map → chunk-4HEVSWO3.js.map} +0 -0
  96. /package/dist/{chunk-KLDGJSR5.js.map → chunk-6AK6WKE5.js.map} +0 -0
  97. /package/dist/{chunk-ENRJ2QEH.js.map → chunk-723K4SAW.js.map} +0 -0
  98. /package/dist/{chunk-UYMK3XNB.js.map → chunk-76AHNHWC.js.map} +0 -0
  99. /package/dist/{chunk-XWU7O3S5.js.map → chunk-C3VRBEJ7.js.map} +0 -0
  100. /package/dist/{chunk-HQMISQ7L.js.map → chunk-CELYD5QW.js.map} +0 -0
  101. /package/dist/{chunk-33QV5O6P.js.map → chunk-D3LSPFHK.js.map} +0 -0
  102. /package/dist/{chunk-4HNHHKJF.js.map → chunk-EZN2YXRY.js.map} +0 -0
  103. /package/dist/{chunk-BKDUCPZ3.js.map → chunk-GSOL2LW6.js.map} +0 -0
  104. /package/dist/{chunk-WLRHL2P7.js.map → chunk-LKJSPO3S.js.map} +0 -0
  105. /package/dist/{chunk-37EABIOJ.js.map → chunk-M4AG2YNX.js.map} +0 -0
  106. /package/dist/{chunk-QYHABRLM.js.map → chunk-SA23V7WX.js.map} +0 -0
  107. /package/dist/{chunk-3W2KMI5O.js.map → chunk-W4YMMWJL.js.map} +0 -0
  108. /package/dist/{chunk-2TJYZF4E.js.map → chunk-XEOAKD5C.js.map} +0 -0
  109. /package/dist/{client-N4XQEAVL.js.map → client-IA7ZPE56.js.map} +0 -0
  110. /package/dist/{config-KHKIY6LI.js.map → config-HPN2F7LH.js.map} +0 -0
  111. /package/dist/{config-mutator-ZZKFQ7HJ.js.map → config-mutator-7GPTMTVB.js.map} +0 -0
  112. /package/dist/{doctor-QICAXIQB.js.map → doctor-IBWQVQV4.js.map} +0 -0
  113. /package/dist/{program-ZWNGK3RB.js.map → program-G6DIFJUF.js.map} +0 -0
  114. /package/dist/{promote-H6ZHJXTY.js.map → promote-T4UJROEH.js.map} +0 -0
  115. /package/dist/{query-FTE4FLYK.js.map → query-VUJC4Y5O.js.map} +0 -0
  116. /package/dist/{registry-HDOFVNRK.js.map → registry-DX2RI7I7.js.map} +0 -0
  117. /package/dist/{request-planner-ABD4WIGM.js.map → request-planner-B7DE7VJR.js.map} +0 -0
  118. /package/dist/{review-candidates-B6574GOJ.js.map → review-candidates-4YJHIBAF.js.map} +0 -0
  119. /package/dist/{routing-BGKZOHOA.js.map → routing-MZG3UODH.js.map} +0 -0
  120. /package/dist/{schedule-tool-UDHXTKWV.js.map → schedule-tool-A4OFQ4YZ.js.map} +0 -0
  121. /package/dist/{scheduler-NQM3HVUY.js.map → scheduler-RHJW2V4M.js.map} +0 -0
  122. /package/dist/{seat-VGST5AQB.js.map → seat-2PEI7JRX.js.map} +0 -0
  123. /package/dist/{select-Y7SBUCGJ.js.map → select-4KIUR27O.js.map} +0 -0
  124. /package/dist/{set-enabled-ARKMDLXN.js.map → set-enabled-SE7HQKPF.js.map} +0 -0
  125. /package/dist/{wiki-GREI2TSP.js.map → subscriptions-RYVPHVIV.js.map} +0 -0
  126. /package/dist/{tool-5EVYUN2G.js.map → tool-5VMD7IE4.js.map} +0 -0
@@ -0,0 +1,5 @@
1
+ import{n as m,q as b}from"./chunk-U4H35SJS.js";b();function w(t){let e=typeof t.node=="string"?t.node:"",n=typeof t.token=="string"?t.token:"";if(!e||!n)try{let o=m(t.config);e||(e=o.dashboard?.daemonUrl||""),n||(n=o.dashboard?.token||"")}catch{}return e||(e="http://localhost:18800"),{baseUrl:e.replace(/\/+$/,""),token:n}}async function d(t,e,n){let o={Accept:"application/json"};t.token&&(o.Authorization=`Bearer ${t.token}`);let r=await fetch(`${t.baseUrl}${e}`,{headers:o,signal:n});if(!r.ok)throw new Error(`GET ${e} \u2192 HTTP ${r.status}`);return await r.json()}function R(t,e){return d(t,"/agents",e)}async function S(t,e){return(await d(t,"/api/processes",e)).processes??[]}function P(t,e){return d(t,"/crons",e)}async function h(t,e,n,o){let r={Accept:"application/json","Content-Type":"application/json"};t.token&&(r.Authorization=`Bearer ${t.token}`);let s=await fetch(`${t.baseUrl}${e}`,{method:"POST",headers:r,body:JSON.stringify(n),signal:o}),a=await s.text(),i;try{i=a?JSON.parse(a):{}}catch{i={raw:a}}if(!s.ok)throw new Error(i?.error||`POST ${e} \u2192 HTTP ${s.status}`);return i}function A(t,e,n="tui"){return h(t,"/api/processes/kill",{...e,reason:n})}function C(t,e,n,o){return h(t,"/task",{agent:e,message:n,context:o??{channel:"tui",chatId:"tui:operator"}})}async function $(t,e,n,o={}){let r={Accept:"text/event-stream","Content-Type":"application/json"};t.token&&(r.Authorization=`Bearer ${t.token}`);let s=await fetch(`${t.baseUrl}/task`,{method:"POST",headers:r,body:JSON.stringify({agent:e,message:n,stream:!0,context:{channel:o.channel??"chat-cli",chatId:o.chatId??"chat-cli:operator"}}),signal:o.signal});if(!s.ok||!s.body){let g=await s.text().catch(()=>"");throw new Error(`POST /task (stream) \u2192 HTTP ${s.status}${g?`: ${g.slice(0,200)}`:""}`)}let a=s.body.getReader(),i=new TextDecoder,u={content:""},c="";try{for(;;){let{done:g,value:p}=await a.read();if(g)break;c+=i.decode(p,{stream:!0});let l;for(;(l=c.indexOf(`
2
+
3
+ `))>=0;){let k=c.slice(0,l);c=c.slice(l+2);let f=x(k);f&&T(f,o,u)}}}finally{try{a.releaseLock()}catch{}}return u}function T(t,e,n){let{event:o,data:r}=t;switch(o){case"text":r?.text&&(n.content+=r.text,e.onText?.(r.text));break;case"thinking":r?.text&&e.onThinking?.(r.text);break;case"tool":e.onTool?.(r);break;case"done":typeof r?.content=="string"&&(n.content=r.content),n.usage=r?.usage,n.duration=r?.duration;break;case"error":n.error=r?.error,n.errorKind=r?.errorKind;break}}function x(t){let e="message",n="";for(let r of t.split(`
4
+ `))r.startsWith("event: ")?e=r.slice(7).trim():r.startsWith("data: ")&&(n=r.slice(6));if(!n)return null;let o;try{o=JSON.parse(n)}catch{o=n}return{event:e,data:o}}export{w as a,R as b,S as c,P as d,A as e,C as f,$ as g};
5
+ //# sourceMappingURL=chunk-WOMQ2VGA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tui/client.ts"],"sourcesContent":["import { loadDaemonConfig } from \"@/daemon/config\"\n\n// Resolved connection details for the daemon, derived from --node/--token\n// CLI flags first, then daemon config's `dashboard` block, then localhost.\nexport interface DaemonConn {\n baseUrl: string\n token: string\n}\n\nexport function resolveConn(opts: { node?: string; token?: string; config?: string }): DaemonConn {\n let baseUrl = typeof opts.node === \"string\" ? opts.node : \"\"\n let token = typeof opts.token === \"string\" ? opts.token : \"\"\n if (!baseUrl || !token) {\n try {\n const cfg = loadDaemonConfig(opts.config)\n if (!baseUrl) baseUrl = cfg.dashboard?.daemonUrl || \"\"\n if (!token) token = cfg.dashboard?.token || \"\"\n } catch {\n // No config — fall back to localhost.\n }\n }\n if (!baseUrl) baseUrl = \"http://localhost:18800\"\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), token }\n}\n\nasync function get<T>(conn: DaemonConn, path: string, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = { Accept: \"application/json\" }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, { headers, signal })\n if (!res.ok) throw new Error(`GET ${path} → HTTP ${res.status}`)\n return (await res.json()) as T\n}\n\nexport interface AgentRow {\n id: string\n name: string\n tier: string\n model?: string\n workspace: string\n active: number\n total: number\n errors: number\n lastActive?: string\n}\n\nexport interface ProcessRow {\n key: { agentId: string; channel: string; chatId: string }\n pid: number | null\n state: string\n spawnedAt: number\n lastTurnAt: number\n turnCount: number\n}\n\nexport interface CronRow {\n id: string\n enabled: boolean\n schedule: string\n agent: string\n nextRun?: string\n lastError?: string\n consecutiveErrors: number\n}\n\nexport function fetchAgents(conn: DaemonConn, signal?: AbortSignal): Promise<AgentRow[]> {\n return get<AgentRow[]>(conn, \"/agents\", signal)\n}\n\nexport async function fetchProcesses(conn: DaemonConn, signal?: AbortSignal): Promise<ProcessRow[]> {\n const r = await get<{ processes: ProcessRow[] }>(conn, \"/api/processes\", signal)\n return r.processes ?? []\n}\n\nexport function fetchCrons(conn: DaemonConn, signal?: AbortSignal): Promise<CronRow[]> {\n return get<CronRow[]>(conn, \"/crons\", signal)\n}\n\nasync function post<T>(conn: DaemonConn, path: string, body: any, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n })\n const text = await res.text()\n let parsed: any\n try { parsed = text ? JSON.parse(text) : {} } catch { parsed = { raw: text } }\n if (!res.ok) throw new Error(parsed?.error || `POST ${path} → HTTP ${res.status}`)\n return parsed as T\n}\n\nexport function killProcess(\n conn: DaemonConn,\n key: { agentId: string; channel: string; chatId: string },\n reason = \"tui\",\n): Promise<{ killed: { agentId: string; channel: string; chatId: string } }> {\n return post(conn, \"/api/processes/kill\", { ...key, reason })\n}\n\nexport interface TaskResponse {\n content?: string\n error?: string\n [k: string]: any\n}\n\nexport function sendTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n context?: { channel?: string; chatId?: string },\n): Promise<TaskResponse> {\n return post<TaskResponse>(conn, \"/task\", {\n agent: agentId,\n message,\n context: context ?? { channel: \"tui\", chatId: \"tui:operator\" },\n })\n}\n\n/** Live task events surfaced to a streaming client. Mirrors the daemon's\n * `POST /task` SSE wire (src/daemon/index.ts): `text` deltas, `thinking`\n * deltas, and `tool` badges (start/result). */\nexport interface StreamTaskHandlers {\n onText?: (text: string) => void\n onThinking?: (text: string) => void\n onTool?: (t: { status: \"start\" | \"result\"; id?: string; name?: string; error?: boolean; arg?: string }) => void\n}\n\nexport interface StreamTaskResult {\n content: string\n usage?: Record<string, number>\n duration?: number\n error?: string\n errorKind?: string\n}\n\n/**\n * Stream a task turn over SSE. POSTs `/task` with `Accept: text/event-stream`,\n * parses `event:/data:` frames, and invokes the handlers as tokens and tool\n * events arrive. Resolves with the final `done` payload (or an `error`).\n * Reuses the same (channel, chatId) warm-process semantics as sendTask.\n */\nexport async function streamTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n opts: { channel?: string; chatId?: string; signal?: AbortSignal } & StreamTaskHandlers = {},\n): Promise<StreamTaskResult> {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n\n const res = await fetch(`${conn.baseUrl}/task`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n agent: agentId,\n message,\n stream: true,\n context: { channel: opts.channel ?? \"chat-cli\", chatId: opts.chatId ?? \"chat-cli:operator\" },\n }),\n signal: opts.signal,\n })\n if (!res.ok || !res.body) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`POST /task (stream) → HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : \"\"}`)\n }\n\n const reader = res.body.getReader()\n const dec = new TextDecoder()\n const result: StreamTaskResult = { content: \"\" }\n let buf = \"\"\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let idx: number\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n const frame = buf.slice(0, idx)\n buf = buf.slice(idx + 2)\n const parsed = parseSseFrame(frame)\n if (!parsed) continue\n applyFrame(parsed, opts, result)\n }\n }\n } finally {\n try { reader.releaseLock() } catch { /* noop */ }\n }\n return result\n}\n\nfunction applyFrame(\n frame: { event: string; data: any },\n handlers: StreamTaskHandlers,\n result: StreamTaskResult,\n): void {\n const { event, data } = frame\n switch (event) {\n case \"text\":\n if (data?.text) { result.content += data.text; handlers.onText?.(data.text) }\n break\n case \"thinking\":\n if (data?.text) handlers.onThinking?.(data.text)\n break\n case \"tool\":\n handlers.onTool?.(data)\n break\n case \"done\":\n if (typeof data?.content === \"string\") result.content = data.content\n result.usage = data?.usage\n result.duration = data?.duration\n break\n case \"error\":\n result.error = data?.error\n result.errorKind = data?.errorKind\n break\n }\n}\n\n/** Parse one `event:/data:` SSE frame. Ignores comment/heartbeat lines. */\nfunction parseSseFrame(frame: string): { event: string; data: any } | null {\n let event = \"message\"\n let data = \"\"\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) event = line.slice(7).trim()\n else if (line.startsWith(\"data: \")) data = line.slice(6)\n }\n if (!data) return null\n let payload: any\n try { payload = JSON.parse(data) } catch { payload = data }\n return { event, data: payload }\n}\n"],"mappings":"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","names":["init_config","resolveConn","opts","baseUrl","token","cfg","loadDaemonConfig","get","conn","path","signal","headers","res","fetchAgents","fetchProcesses","fetchCrons","post","body","text","parsed","killProcess","key","reason","sendTask","agentId","message","context","streamTask","reader","dec","result","buf","done","value","idx","frame","parseSseFrame","applyFrame","handlers","event","data","line","payload"]}
1
+ {"version":3,"sources":["../src/tui/client.ts"],"sourcesContent":["import { loadDaemonConfig } from \"@/daemon/config\"\n\n// Resolved connection details for the daemon, derived from --node/--token\n// CLI flags first, then daemon config's `dashboard` block, then localhost.\nexport interface DaemonConn {\n baseUrl: string\n token: string\n}\n\nexport function resolveConn(opts: { node?: string; token?: string; config?: string }): DaemonConn {\n let baseUrl = typeof opts.node === \"string\" ? opts.node : \"\"\n let token = typeof opts.token === \"string\" ? opts.token : \"\"\n if (!baseUrl || !token) {\n try {\n const cfg = loadDaemonConfig(opts.config)\n if (!baseUrl) baseUrl = cfg.dashboard?.daemonUrl || \"\"\n if (!token) token = cfg.dashboard?.token || \"\"\n } catch {\n // No config — fall back to localhost.\n }\n }\n if (!baseUrl) baseUrl = \"http://localhost:18800\"\n return { baseUrl: baseUrl.replace(/\\/+$/, \"\"), token }\n}\n\nasync function get<T>(conn: DaemonConn, path: string, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = { Accept: \"application/json\" }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, { headers, signal })\n if (!res.ok) throw new Error(`GET ${path} → HTTP ${res.status}`)\n return (await res.json()) as T\n}\n\nexport interface AgentRow {\n id: string\n name: string\n tier: string\n model?: string\n workspace: string\n active: number\n total: number\n errors: number\n lastActive?: string\n}\n\nexport interface ProcessRow {\n key: { agentId: string; channel: string; chatId: string }\n pid: number | null\n state: string\n spawnedAt: number\n lastTurnAt: number\n turnCount: number\n}\n\nexport interface CronRow {\n id: string\n enabled: boolean\n schedule: string\n agent: string\n nextRun?: string\n lastError?: string\n consecutiveErrors: number\n}\n\nexport function fetchAgents(conn: DaemonConn, signal?: AbortSignal): Promise<AgentRow[]> {\n return get<AgentRow[]>(conn, \"/agents\", signal)\n}\n\nexport async function fetchProcesses(conn: DaemonConn, signal?: AbortSignal): Promise<ProcessRow[]> {\n const r = await get<{ processes: ProcessRow[] }>(conn, \"/api/processes\", signal)\n return r.processes ?? []\n}\n\nexport function fetchCrons(conn: DaemonConn, signal?: AbortSignal): Promise<CronRow[]> {\n return get<CronRow[]>(conn, \"/crons\", signal)\n}\n\nasync function post<T>(conn: DaemonConn, path: string, body: any, signal?: AbortSignal): Promise<T> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n const res = await fetch(`${conn.baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal,\n })\n const text = await res.text()\n let parsed: any\n try { parsed = text ? JSON.parse(text) : {} } catch { parsed = { raw: text } }\n if (!res.ok) throw new Error(parsed?.error || `POST ${path} → HTTP ${res.status}`)\n return parsed as T\n}\n\nexport function killProcess(\n conn: DaemonConn,\n key: { agentId: string; channel: string; chatId: string },\n reason = \"tui\",\n): Promise<{ killed: { agentId: string; channel: string; chatId: string } }> {\n return post(conn, \"/api/processes/kill\", { ...key, reason })\n}\n\nexport interface TaskResponse {\n content?: string\n error?: string\n [k: string]: any\n}\n\nexport function sendTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n context?: { channel?: string; chatId?: string },\n): Promise<TaskResponse> {\n return post<TaskResponse>(conn, \"/task\", {\n agent: agentId,\n message,\n context: context ?? { channel: \"tui\", chatId: \"tui:operator\" },\n })\n}\n\n/** Live task events surfaced to a streaming client. Mirrors the daemon's\n * `POST /task` SSE wire (src/daemon/index.ts): `text` deltas, `thinking`\n * deltas, and `tool` badges (start/result). */\nexport interface StreamTaskHandlers {\n onText?: (text: string) => void\n onThinking?: (text: string) => void\n onTool?: (t: { status: \"start\" | \"result\"; id?: string; name?: string; error?: boolean; arg?: string }) => void\n}\n\nexport interface StreamTaskResult {\n content: string\n usage?: Record<string, number>\n duration?: number\n error?: string\n errorKind?: string\n}\n\n/**\n * Stream a task turn over SSE. POSTs `/task` with `Accept: text/event-stream`,\n * parses `event:/data:` frames, and invokes the handlers as tokens and tool\n * events arrive. Resolves with the final `done` payload (or an `error`).\n * Reuses the same (channel, chatId) warm-process semantics as sendTask.\n */\nexport async function streamTask(\n conn: DaemonConn,\n agentId: string,\n message: string,\n opts: { channel?: string; chatId?: string; signal?: AbortSignal } & StreamTaskHandlers = {},\n): Promise<StreamTaskResult> {\n const headers: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n }\n if (conn.token) headers[\"Authorization\"] = `Bearer ${conn.token}`\n\n const res = await fetch(`${conn.baseUrl}/task`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n agent: agentId,\n message,\n stream: true,\n context: { channel: opts.channel ?? \"chat-cli\", chatId: opts.chatId ?? \"chat-cli:operator\" },\n }),\n signal: opts.signal,\n })\n if (!res.ok || !res.body) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`POST /task (stream) → HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : \"\"}`)\n }\n\n const reader = res.body.getReader()\n const dec = new TextDecoder()\n const result: StreamTaskResult = { content: \"\" }\n let buf = \"\"\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let idx: number\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n const frame = buf.slice(0, idx)\n buf = buf.slice(idx + 2)\n const parsed = parseSseFrame(frame)\n if (!parsed) continue\n applyFrame(parsed, opts, result)\n }\n }\n } finally {\n try { reader.releaseLock() } catch { /* noop */ }\n }\n return result\n}\n\nfunction applyFrame(\n frame: { event: string; data: any },\n handlers: StreamTaskHandlers,\n result: StreamTaskResult,\n): void {\n const { event, data } = frame\n switch (event) {\n case \"text\":\n if (data?.text) { result.content += data.text; handlers.onText?.(data.text) }\n break\n case \"thinking\":\n if (data?.text) handlers.onThinking?.(data.text)\n break\n case \"tool\":\n handlers.onTool?.(data)\n break\n case \"done\":\n if (typeof data?.content === \"string\") result.content = data.content\n result.usage = data?.usage\n result.duration = data?.duration\n break\n case \"error\":\n result.error = data?.error\n result.errorKind = data?.errorKind\n break\n }\n}\n\n/** Parse one `event:/data:` SSE frame. Ignores comment/heartbeat lines. */\nfunction parseSseFrame(frame: string): { event: string; data: any } | null {\n let event = \"message\"\n let data = \"\"\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\"event: \")) event = line.slice(7).trim()\n else if (line.startsWith(\"data: \")) data = line.slice(6)\n }\n if (!data) return null\n let payload: any\n try { payload = JSON.parse(data) } catch { payload = data }\n return { event, data: payload }\n}\n"],"mappings":"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","names":["init_config","resolveConn","opts","baseUrl","token","cfg","loadDaemonConfig","get","conn","path","signal","headers","res","fetchAgents","fetchProcesses","fetchCrons","post","body","text","parsed","killProcess","key","reason","sendTask","agentId","message","context","streamTask","reader","dec","result","buf","done","value","idx","frame","parseSseFrame","applyFrame","handlers","event","data","line","payload"]}
@@ -0,0 +1,3 @@
1
+ var m=50,v=20,g=10;function p(e,n,t){return n.agentId===t&&!e.agents?.includes(t)?!1:f(e,n)}function f(e,n){return!(!e.kinds.some(t=>t==="*"||t===n.kind||t===n.type)||e.agents?.length&&(!n.agentId||!e.agents.includes(n.agentId))||e.nodes?.length&&!e.nodes.includes(n.node)||e.match&&!n.summary.toLowerCase().includes(e.match.toLowerCase()))}function c(e,n){return e?.length?n==="pull"?e:e.filter(t=>(t.delivery??"pull")===n):[]}function E(e,n,t,i={}){let o=c(n,i.delivery??"pull");if(o.length===0)return[];let s=a(i.limit),l=t.filter(r=>o.some(u=>p(u,r,e)));return i.fromCursor?l.slice(0,s):l.slice(-s)}function a(e,n=20){return!e||!Number.isFinite(e)||e<1?n:Math.min(Math.floor(e),50)}function h(e,n,t){let i=c(n,"digest");if(i.length===0)return{shown:[],more:0};let o=0;for(let r=t.length-1;r>=0;r--)if(t[r].agentId===e&&t[r].type==="task:completed"){o=r+1;break}let s=t.slice(o).filter(r=>i.some(u=>p(u,r,e))),l=s.slice(-10);return{shown:l,more:s.length-l.length}}function d(e){let n=e.agentId?`${e.agentId}@${e.node}`:e.node,t=e.ref?` (ref ${e.ref})`:"";return`${e.at.slice(0,16).replace("T"," ")} ${e.type} ${n}: ${e.summary}${t}`}function y(e,n){return e.length===0?void 0:[`[Events since your last turn \u2014 ${e.length+n} matched your subscriptions${n?`, newest ${e.length} shown`:""}. Call agentx_events for details or newer ones:]`,...e.map(i=>`- ${d(i)}`)].join(`
2
+ `)}export{m as a,v as b,g as c,p as d,f as e,c as f,E as g,a as h,h as i,d as j,y as k};
3
+ //# sourceMappingURL=chunk-X5C5W3E4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/events/subscriptions.ts"],"sourcesContent":["import type { EventSubscription } from \"@/daemon/config\"\nimport type { EventEnvelope } from \"./envelope\"\n\n// --- Per-agent event subscriptions ---\n//\n// An agent lists the events it cares about in `agents.<id>.subscriptions`.\n// This module is the pure half: does an envelope match, which envelopes\n// does an agent get, and how a digest reads. Delivery lives elsewhere:\n// pull — GET /agents/:id/events, the agentx_events MCP tool and\n// `agentx events` read eventsForAgent()\n// digest — the registry injects renderDigest() into FRESH sessions only\n// wake — src/events/wake.ts starts a turn\n// Every answer is bounded: envelopes already cap their summary, and each\n// reader caps the count.\n\nexport type Delivery = EventSubscription[\"delivery\"]\n\n/** Most events one pull returns. */\nexport const PULL_MAX = 50\nexport const PULL_DEFAULT = 20\n/** Most events a fresh-session digest lists. */\nexport const DIGEST_MAX = 10\n\n/** Loose input shape: config output, or a hand-written object in tests. */\nexport type SubscriptionInput = Partial<EventSubscription> & { kinds: string[] }\n\n/** Does `e` match `sub` for `self`? An agent never matches its own events\n * unless the subscription names it in `agents` (and `wake` never does;\n * see wake.ts). */\nexport function matchesSubscription(sub: SubscriptionInput, e: EventEnvelope, self: string): boolean {\n if (e.agentId === self && !sub.agents?.includes(self)) return false\n return matchesFilters(sub, e)\n}\n\n/** The subscription's own filters, with no regard to who is asking. */\nexport function matchesFilters(sub: SubscriptionInput, e: EventEnvelope): boolean {\n if (!sub.kinds.some((k) => k === \"*\" || k === e.kind || k === e.type)) return false\n if (sub.agents?.length && (!e.agentId || !sub.agents.includes(e.agentId))) return false\n if (sub.nodes?.length && !sub.nodes.includes(e.node)) return false\n if (sub.match && !e.summary.toLowerCase().includes(sub.match.toLowerCase())) return false\n return true\n}\n\n/** Subscriptions of one delivery mode. `pull` reads every subscription:\n * digest and wake events can always be pulled too. */\nexport function subscriptionsFor(subs: SubscriptionInput[] | undefined, delivery: Delivery): SubscriptionInput[] {\n if (!subs?.length) return []\n return delivery === \"pull\" ? subs : subs.filter((s) => (s.delivery ?? \"pull\") === delivery)\n}\n\n/** Events from `events` (oldest first) that match any of `subs`. With no\n * cursor the newest `limit` are kept. When `events` was already read after\n * a cursor (`fromCursor`), the OLDEST `limit` are kept instead, so a reader\n * that passes the last returned id back as `since` pages through every\n * match without gaps. */\nexport function eventsForAgent(\n agentId: string,\n subs: SubscriptionInput[] | undefined,\n events: EventEnvelope[],\n opts: { delivery?: Delivery; limit?: number; fromCursor?: boolean } = {},\n): EventEnvelope[] {\n const active = subscriptionsFor(subs, opts.delivery ?? \"pull\")\n if (active.length === 0) return []\n const limit = clampLimit(opts.limit)\n const hits = events.filter((e) => active.some((s) => matchesSubscription(s, e, agentId)))\n return opts.fromCursor ? hits.slice(0, limit) : hits.slice(-limit)\n}\n\nexport function clampLimit(limit: number | undefined, fallback = PULL_DEFAULT): number {\n if (!limit || !Number.isFinite(limit) || limit < 1) return fallback\n return Math.min(Math.floor(limit), PULL_MAX)\n}\n\n/** The events a fresh session should hear about: digest subscriptions\n * matched since the agent's last finished turn (the whole buffer when it\n * has none), newest DIGEST_MAX. Returns the shown events and how many\n * more matched. */\nexport function digestEvents(\n agentId: string,\n subs: SubscriptionInput[] | undefined,\n events: EventEnvelope[],\n): { shown: EventEnvelope[]; more: number } {\n const active = subscriptionsFor(subs, \"digest\")\n if (active.length === 0) return { shown: [], more: 0 }\n let start = 0\n for (let i = events.length - 1; i >= 0; i--) {\n if (events[i].agentId === agentId && events[i].type === \"task:completed\") { start = i + 1; break }\n }\n const hits = events.slice(start).filter((e) => active.some((s) => matchesSubscription(s, e, agentId)))\n const shown = hits.slice(-DIGEST_MAX)\n return { shown, more: hits.length - shown.length }\n}\n\n/** One line per event: time, type, who and where, summary, ref. */\nexport function formatEventLine(e: EventEnvelope): string {\n const who = e.agentId ? `${e.agentId}@${e.node}` : e.node\n const ref = e.ref ? ` (ref ${e.ref})` : \"\"\n return `${e.at.slice(0, 16).replace(\"T\", \" \")} ${e.type} ${who}: ${e.summary}${ref}`\n}\n\n/** The context block for a fresh session, or undefined when nothing matched. */\nexport function renderDigest(shown: EventEnvelope[], more: number): string | undefined {\n if (shown.length === 0) return undefined\n const lines = [\n `[Events since your last turn — ${shown.length + more} matched your subscriptions${more ? `, newest ${shown.length} shown` : \"\"}. Call agentx_events for details or newer ones:]`,\n ...shown.map((e) => `- ${formatEventLine(e)}`),\n ]\n return lines.join(\"\\n\")\n}\n"],"mappings":"AAkBO,IAAMA,EAAW,GACXC,EAAe,GAEfC,EAAa,GAQnB,SAASC,EAAoBC,EAAwBC,EAAkBC,EAAuB,CACnG,OAAID,EAAE,UAAYC,GAAQ,CAACF,EAAI,QAAQ,SAASE,CAAI,EAAU,GACvDC,EAAeH,EAAKC,CAAC,CAC9B,CAGO,SAASE,EAAeH,EAAwBC,EAA2B,CAIhF,MAHI,GAACD,EAAI,MAAM,KAAMI,GAAMA,IAAM,KAAOA,IAAMH,EAAE,MAAQG,IAAMH,EAAE,IAAI,GAChED,EAAI,QAAQ,SAAW,CAACC,EAAE,SAAW,CAACD,EAAI,OAAO,SAASC,EAAE,OAAO,IACnED,EAAI,OAAO,QAAU,CAACA,EAAI,MAAM,SAASC,EAAE,IAAI,GAC/CD,EAAI,OAAS,CAACC,EAAE,QAAQ,YAAY,EAAE,SAASD,EAAI,MAAM,YAAY,CAAC,EAE5E,CAIO,SAASK,EAAiBC,EAAuCC,EAAyC,CAC/G,OAAKD,GAAM,OACJC,IAAa,OAASD,EAAOA,EAAK,OAAQE,IAAOA,EAAE,UAAY,UAAYD,CAAQ,EADhE,CAAC,CAE7B,CAOO,SAASE,EACdC,EACAJ,EACAK,EACAC,EAAsE,CAAC,EACtD,CACjB,IAAMC,EAASR,EAAiBC,EAAMM,EAAK,UAAY,MAAM,EAC7D,GAAIC,EAAO,SAAW,EAAG,MAAO,CAAC,EACjC,IAAMC,EAAQC,EAAWH,EAAK,KAAK,EAC7BI,EAAOL,EAAO,OAAQV,GAAMY,EAAO,KAAML,GAAMT,EAAoBS,EAAGP,EAAGS,CAAO,CAAC,CAAC,EACxF,OAAOE,EAAK,WAAaI,EAAK,MAAM,EAAGF,CAAK,EAAIE,EAAK,MAAM,CAACF,CAAK,CACnE,CAEO,SAASC,EAAWD,EAA2BG,EAAW,GAAsB,CACrF,MAAI,CAACH,GAAS,CAAC,OAAO,SAASA,CAAK,GAAKA,EAAQ,EAAUG,EACpD,KAAK,IAAI,KAAK,MAAMH,CAAK,EAAG,EAAQ,CAC7C,CAMO,SAASI,EACdR,EACAJ,EACAK,EAC0C,CAC1C,IAAME,EAASR,EAAiBC,EAAM,QAAQ,EAC9C,GAAIO,EAAO,SAAW,EAAG,MAAO,CAAE,MAAO,CAAC,EAAG,KAAM,CAAE,EACrD,IAAIM,EAAQ,EACZ,QAASC,EAAIT,EAAO,OAAS,EAAGS,GAAK,EAAGA,IACtC,GAAIT,EAAOS,CAAC,EAAE,UAAYV,GAAWC,EAAOS,CAAC,EAAE,OAAS,iBAAkB,CAAED,EAAQC,EAAI,EAAG,MAE7F,IAAMJ,EAAOL,EAAO,MAAMQ,CAAK,EAAE,OAAQlB,GAAMY,EAAO,KAAML,GAAMT,EAAoBS,EAAGP,EAAGS,CAAO,CAAC,CAAC,EAC/FW,EAAQL,EAAK,MAAM,GAAW,EACpC,MAAO,CAAE,MAAAK,EAAO,KAAML,EAAK,OAASK,EAAM,MAAO,CACnD,CAGO,SAASC,EAAgB,EAA0B,CACxD,IAAMC,EAAM,EAAE,QAAU,GAAG,EAAE,WAAW,EAAE,OAAS,EAAE,KAC/CC,EAAM,EAAE,IAAM,SAAS,EAAE,OAAS,GACxC,MAAO,GAAG,EAAE,GAAG,MAAM,EAAG,EAAE,EAAE,QAAQ,IAAK,GAAG,KAAK,EAAE,QAAQD,MAAQ,EAAE,UAAUC,GACjF,CAGO,SAASC,EAAaJ,EAAwBK,EAAkC,CACrF,OAAIL,EAAM,SAAW,EAAG,OACV,CACZ,uCAAkCA,EAAM,OAASK,+BAAkCA,EAAO,YAAYL,EAAM,eAAiB,qDAC7H,GAAGA,EAAM,IAAKpB,GAAM,KAAKqB,EAAgBrB,CAAC,GAAG,CAC/C,EACa,KAAK;AAAA,CAAI,CACxB","names":["PULL_MAX","PULL_DEFAULT","DIGEST_MAX","matchesSubscription","sub","e","self","matchesFilters","k","subscriptionsFor","subs","delivery","s","eventsForAgent","agentId","events","opts","active","limit","clampLimit","hits","fallback","digestEvents","start","i","shown","formatEventLine","who","ref","renderDigest","more"]}
@@ -1,8 +1,8 @@
1
- import{a as D,b as _}from"./chunk-RKPAVWXF.js";import{a as q,b as O,c as R,d as B,f as b,g as S,h as E,i as w,j as y}from"./chunk-QYHABRLM.js";import{a as T,b as C,c as I,d as x,e as P}from"./chunk-4HNHHKJF.js";import{existsSync as X,readFileSync as F}from"fs";var J=new Set(["cron","heartbeat","api","a2a","mesh"]),M=160;function s(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function A(n,e=M){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function V(n){let e=T(n);if(!X(e))throw new Error(`config not found at ${e}`);return JSON.parse(F(e,"utf-8"))}function W(n,e){return n?.agents?.[e]?.admin===!0}function Y(n,e,t){return W(n,t.agentId)||e?.createdBy===t.agentId}function Z(n,e){let t=e?.createdBy?`agent "${e.createdBy}"`:"the operator";return`Not allowed: "${n}" was created by ${t}. Agents manage only schedules they created (unless configured admin).`}function K(n,e){let t=s(n.notify);if(t!=="none"){if(t&&t!=="here"){let r=t.split(":");return r.length<2||!r[0]||!r[1]?"invalid":{channel:r[0],chatId:r.slice(1).join(":")}}if(e.channel&&e.chatId&&!J.has(e.channel))return{channel:e.channel,chatId:e.chatId,...e.accountId?{accountId:e.accountId}:{}}}}function Q(n,e,t){let r=e.timezone||"UTC",u=e.enabled&&!y(e)?w(E(e.schedule,r,t),r):"\u2014",h=e.approval?`pending ${e.approval.action} approval`:e.enabled?"active":"paused",p=[`- ${n} [${h}] ${e.schedule} \u2014 ${S(e.schedule)} (${r})`,` agent: ${e.agent}; created by: ${e.createdBy||"operator"}; next: ${u}`];return e.notify&&p.push(` notify: ${e.notify.channel} ${e.notify.chatId}`),e.command?p.push(` command: ${A(String(e.command))}`):e.prompt&&p.push(` prompt: ${A(String(e.prompt))}`),p.join(`
1
+ import{a as D,b as _}from"./chunk-RKPAVWXF.js";import{a as q,b as O,c as R,d as B,f as b,g as S,h as E,i as w,j as y}from"./chunk-SA23V7WX.js";import{a as T,b as C,c as I,d as x,e as P}from"./chunk-EZN2YXRY.js";import{existsSync as X,readFileSync as F}from"fs";var J=new Set(["cron","heartbeat","api","a2a","mesh"]),M=160;function s(n){return typeof n=="string"&&n.trim()?n.trim():void 0}function A(n,e=M){let t=n.replace(/\s+/g," ").trim();return t.length>e?`${t.slice(0,e-1)}\u2026`:t}function V(n){let e=T(n);if(!X(e))throw new Error(`config not found at ${e}`);return JSON.parse(F(e,"utf-8"))}function W(n,e){return n?.agents?.[e]?.admin===!0}function Y(n,e,t){return W(n,t.agentId)||e?.createdBy===t.agentId}function Z(n,e){let t=e?.createdBy?`agent "${e.createdBy}"`:"the operator";return`Not allowed: "${n}" was created by ${t}. Agents manage only schedules they created (unless configured admin).`}function K(n,e){let t=s(n.notify);if(t!=="none"){if(t&&t!=="here"){let r=t.split(":");return r.length<2||!r[0]||!r[1]?"invalid":{channel:r[0],chatId:r.slice(1).join(":")}}if(e.channel&&e.chatId&&!J.has(e.channel))return{channel:e.channel,chatId:e.chatId,...e.accountId?{accountId:e.accountId}:{}}}}function Q(n,e,t){let r=e.timezone||"UTC",u=e.enabled&&!y(e)?w(E(e.schedule,r,t),r):"\u2014",h=e.approval?`pending ${e.approval.action} approval`:e.enabled?"active":"paused",p=[`- ${n} [${h}] ${e.schedule} \u2014 ${S(e.schedule)} (${r})`,` agent: ${e.agent}; created by: ${e.createdBy||"operator"}; next: ${u}`];return e.notify&&p.push(` notify: ${e.notify.channel} ${e.notify.chatId}`),e.command?p.push(` command: ${A(String(e.command))}`):e.prompt&&p.push(` prompt: ${A(String(e.prompt))}`),p.join(`
2
2
  `)}async function k(n,e,t){let r=n?.notifications?.destination;if(!r?.channel||!r?.chatId)return"No operator notification destination is configured (notifications.destination); the operator must check `agentx schedule list`.";if(!e.notifyOperator)return"Operator notification is unavailable in this context.";try{return await e.notifyOperator({channel:r.channel,chatId:r.chatId,accountId:r.accountId},t),"The operator has been notified."}catch(u){return`Could not notify the operator (${u?.message??u}); the request is still recorded.`}}async function re(n,e,t={}){let r=(s(n.action)||"list").toLowerCase(),u=t.now?t.now():new Date,h;try{h=V(t.configPath)}catch(a){return`Error: ${a.message}`}let p=h.crons||{};if(r==="list"){let a=n.mine===!0,l=Object.entries(p).filter(([,i])=>!a||e&&i?.createdBy===e.agentId);return l.length?l.map(([i,f])=>Q(i,f,u)).join(`
3
3
  `):a?"You have no schedules.":"No schedules."}if(!e?.agentId)return"Error: caller agent is unknown (AGENTX_AGENT_ID not set). Pass callerAgentId.";if(!h.agents?.[e.agentId])return`Error: caller "${e.agentId}" is not an agent on this node.`;let o=s(n.id),m=a=>C(a,{configPath:t.configPath,reload:t.reload});if(r==="create"){let a=s(n.when),l=s(n.prompt);if(!a||!l)return"Error: create needs `when` (plain English) and `prompt`.";let i=D(a);if(!i)return`Error: couldn't parse "${a}". ${O}.`;let f=s(n.agent)||e.agentId;if(!h.agents?.[f])return`Error: agent "${f}" not found on this node.`;let g=s(n.timezone)||q;if(!B(g))return`Error: unknown timezone "${g}".`;let d=o||_(i.matched,f);if(!R(d))return`Error: invalid id "${d}" (letters, digits, "-" and "_" only).`;if(p[d])return`Error: a schedule "${d}" already exists. Pick another \`id\`.`;let $=K(n,e);if($==="invalid")return'Error: `notify` must be "here", "none", or "channel:chatId".';let z={action:"create",requestedBy:e.agentId,requestedAt:u.toISOString()},L=b({parsed:i,agent:f,prompt:l,timezone:g,notify:$,enabled:!1,createdBy:e.agentId,approval:z}),v=await m(U=>I(U,`crons.${d}`,L));if(!v.success)return`Error: ${v.error}`;let N=w(E(i.cron,g,u),g),G=[`Schedule approval requested by ${e.agentId}`,`Create: ${d}`,`When: ${i.human} \u2014 cron \`${i.cron}\` (${g})`,`Next fire: ${N}`,`Agent: ${f}`,$?`Notify: ${$.channel} ${$.chatId}`:"Notify: none",`Prompt: ${A(l,400)}`,"",`Approve: agentx schedule approve ${d}`,`Reject: agentx schedule reject ${d}`].join(`
4
4
  `),H=await k(h,t,G);return[`Requested schedule "${d}": ${i.human} (cron ${i.cron}, ${g}); next fire would be ${N}.`,"It is saved DISABLED and will not run until the operator approves it.",H].join(`
5
5
  `)}if(!o)return`Error: ${r} needs \`id\`.`;let c=p[o];if(!c)return`Error: schedule "${o}" not found.`;if(!Y(h,c,e))return Z(o,c);if(r==="pause"||r==="resume"){let a=r==="resume";if(a&&y(c))return`"${o}" is still awaiting operator approval; it can't be resumed until approved.`;if(c.enabled===a)return`"${o}" is already ${a?"active":"paused"}.`;let l=await m(i=>I(i,`crons.${o}.enabled`,a));return l.success?`"${o}" ${a?"resumed":"paused"}.`:`Error: ${l.error}`}if(r==="delete"){if(y(c)&&c.approval.requestedBy===e.agentId){let d=await m($=>P($,`crons.${o}`));return d.success?`Withdrew the pending request "${o}".`:`Error: ${d.error}`}if(y(c))return`"${o}" is a creation request still awaiting approval; only its requester or the operator (\`agentx schedule reject ${o}\`) can drop it.`;if(c.approval?.action==="delete")return`Deletion of "${o}" is already awaiting approval.`;let a={action:"delete",requestedBy:e.agentId,requestedAt:u.toISOString()},l=await m(d=>{if(!x(d,`crons.${o}`))throw new Error(`schedule "${o}" not found`);I(d,`crons.${o}.approval`,a)});if(!l.success)return`Error: ${l.error}`;let i=c.timezone||"UTC",f=[`Schedule approval requested by ${e.agentId}`,`Delete: ${o}`,`When: ${S(c.schedule)} \u2014 cron \`${c.schedule}\` (${i})`,`Next fire: ${c.enabled?w(E(c.schedule,i,u),i):"\u2014 (paused)"}`,`Agent: ${c.agent}`,"",`Approve: agentx schedule approve ${o}`,`Reject: agentx schedule reject ${o}`].join(`
6
6
  `),g=await k(h,t,f);return[`Deletion of "${o}" requested. It keeps its current state until the operator approves.`,g].join(`
7
7
  `)}return`Error: unknown action "${r}". Use list, create, pause, resume or delete.`}function oe(n,e=process.env){let t=s(e.AGENTX_AGENT_ID)||s(n.callerAgentId);if(!t)return null;let r=!!(s(e.AGENTX_CHANNEL)&&s(e.AGENTX_CHAT_ID)),u=s(r?e.AGENTX_CHANNEL:n.channel),h=s(r?e.AGENTX_CHAT_ID:n.chatId),p=s(n.accountId);return{agentId:t,channel:u,chatId:h,...p?{accountId:p}:{}}}export{re as a,oe as b};
8
- //# sourceMappingURL=chunk-2TJYZF4E.js.map
8
+ //# sourceMappingURL=chunk-XEOAKD5C.js.map
package/dist/cli.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{a as n}from"./chunk-TLFJVLVQ.js";import"./chunk-QX4R5WY7.js";import"./chunk-33QV5O6P.js";import"./chunk-UYMK3XNB.js";import"./chunk-Z3IP66SL.js";import"./chunk-KAFO5QZR.js";import"./chunk-RKPAVWXF.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-6JHA3ZE6.js";import"./chunk-3RCFUIYR.js";import"./chunk-ENRJ2QEH.js";import"./chunk-S7CVSKOX.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-3W2KMI5O.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-L53FTKEP.js";import"./chunk-BMSPRUEJ.js";import"./chunk-HQMISQ7L.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-KLDGJSR5.js";import"./chunk-SFQUP3BP.js";import"./chunk-QYHABRLM.js";import"./chunk-ZOJUHPD5.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-4HNHHKJF.js";import"./chunk-M67AN4J7.js";import"./chunk-DWADWDMU.js";import"./chunk-NO2HOK4B.js";import"./chunk-QD6IICK7.js";import"./chunk-VWTBHLMX.js";import"./chunk-WLRHL2P7.js";import"./chunk-XWU7O3S5.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-BKDUCPZ3.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-37EABIOJ.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-4FFWNPFX.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";var r=["SIGINT","SIGTERM"];function o(t=process){for(let i of r)t.on(i,()=>{t.listenerCount(i)<=1&&t.exit(0)})}o();async function s(){let t=await n();if(process.argv.slice(2).length===0){t.outputHelp();return}t.parse()}s();
2
+ import{a as n}from"./chunk-IL2XLW4H.js";import"./chunk-WOMQ2VGA.js";import"./chunk-D3LSPFHK.js";import"./chunk-76AHNHWC.js";import"./chunk-Z3IP66SL.js";import"./chunk-KAFO5QZR.js";import"./chunk-RKPAVWXF.js";import"./chunk-GV7S5BAX.js";import"./chunk-GSX4NK2N.js";import"./chunk-SZDACK6O.js";import"./chunk-WKMTT2UY.js";import"./chunk-UIVHSYCN.js";import"./chunk-723K4SAW.js";import"./chunk-S7CVSKOX.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-SA23V7WX.js";import"./chunk-W4YMMWJL.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-L53FTKEP.js";import"./chunk-EJ5ISSWW.js";import"./chunk-CELYD5QW.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import"./chunk-O3XG2NVR.js";import"./chunk-EZN2YXRY.js";import"./chunk-6AK6WKE5.js";import"./chunk-SFQUP3BP.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-4HEVSWO3.js";import"./chunk-DWADWDMU.js";import"./chunk-NO2HOK4B.js";import"./chunk-QD6IICK7.js";import"./chunk-VWTBHLMX.js";import"./chunk-LKJSPO3S.js";import"./chunk-C3VRBEJ7.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-GSOL2LW6.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import"./chunk-M4AG2YNX.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-FX3D7YON.js";import"./chunk-QOYAX2FT.js";import"./chunk-SZJMS7K4.js";import"./chunk-7I7IEX4S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-U4H35SJS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";var r=["SIGINT","SIGTERM"];function o(t=process){for(let i of r)t.on(i,()=>{t.listenerCount(i)<=1&&t.exit(0)})}o();async function s(){let t=await n();if(process.argv.slice(2).length===0){t.outputHelp();return}t.parse()}s();
3
3
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/signal-exit.ts","../src/cli.ts"],"sourcesContent":["// --- Ctrl-C / SIGTERM for CLI commands ---\n//\n// Short commands should exit at once when stopped. Long-running ones (the\n// daemon above all) install their own handler to finish in-flight work first.\n// The CLI's quick exit used to be registered unconditionally, before the\n// daemon's, and Node runs listeners in registration order — so every stop\n// exited the process before the daemon's drain began and killed in-flight\n// agent tasks mid-turn (#103). Now the quick exit only fires when nobody\n// else handles the signal.\n\ntype SignalTarget = Pick<NodeJS.Process, \"on\" | \"listenerCount\" | \"exit\">\n\nexport const CLI_EXIT_SIGNALS = [\"SIGINT\", \"SIGTERM\"] as const\n\nexport function installCliSignalExit(proc: SignalTarget = process): void {\n for (const sig of CLI_EXIT_SIGNALS) {\n proc.on(sig, () => {\n // This listener is always one of them; anything more means a command\n // is handling the stop itself.\n if (proc.listenerCount(sig) <= 1) proc.exit(0)\n })\n }\n}\n","#!/usr/bin/env node\nimport { buildProgram } from \"@/program\"\nimport { installCliSignalExit } from \"@/utils/signal-exit\"\n\ninstallCliSignalExit()\n\nasync function main() {\n const program = await buildProgram()\n\n const args = process.argv.slice(2)\n if (args.length === 0) {\n program.outputHelp()\n return\n }\n\n program.parse()\n}\n\nmain()\n"],"mappings":";4pDAYO,IAAMA,EAAmB,CAAC,SAAU,SAAS,EAE7C,SAASC,EAAqBC,EAAqB,QAAe,CACvE,QAAWC,KAAOH,EAChBE,EAAK,GAAGC,EAAK,IAAM,CAGbD,EAAK,cAAcC,CAAG,GAAK,GAAGD,EAAK,KAAK,CAAC,CAC/C,CAAC,CAEL,CClBAE,EAAqB,EAErB,eAAeC,GAAO,CACpB,IAAMC,EAAU,MAAMC,EAAa,EAGnC,GADa,QAAQ,KAAK,MAAM,CAAC,EACxB,SAAW,EAAG,CACrBD,EAAQ,WAAW,EACnB,OAGFA,EAAQ,MAAM,CAChB,CAEAD,EAAK","names":["CLI_EXIT_SIGNALS","installCliSignalExit","proc","sig","installCliSignalExit","main","program","buildProgram"]}
1
+ {"version":3,"sources":["../src/utils/signal-exit.ts","../src/cli.ts"],"sourcesContent":["// --- Ctrl-C / SIGTERM for CLI commands ---\n//\n// Short commands should exit at once when stopped. Long-running ones (the\n// daemon above all) install their own handler to finish in-flight work first.\n// The CLI's quick exit used to be registered unconditionally, before the\n// daemon's, and Node runs listeners in registration order — so every stop\n// exited the process before the daemon's drain began and killed in-flight\n// agent tasks mid-turn (#103). Now the quick exit only fires when nobody\n// else handles the signal.\n\ntype SignalTarget = Pick<NodeJS.Process, \"on\" | \"listenerCount\" | \"exit\">\n\nexport const CLI_EXIT_SIGNALS = [\"SIGINT\", \"SIGTERM\"] as const\n\nexport function installCliSignalExit(proc: SignalTarget = process): void {\n for (const sig of CLI_EXIT_SIGNALS) {\n proc.on(sig, () => {\n // This listener is always one of them; anything more means a command\n // is handling the stop itself.\n if (proc.listenerCount(sig) <= 1) proc.exit(0)\n })\n }\n}\n","#!/usr/bin/env node\nimport { buildProgram } from \"@/program\"\nimport { installCliSignalExit } from \"@/utils/signal-exit\"\n\ninstallCliSignalExit()\n\nasync function main() {\n const program = await buildProgram()\n\n const args = process.argv.slice(2)\n if (args.length === 0) {\n program.outputHelp()\n return\n }\n\n program.parse()\n}\n\nmain()\n"],"mappings":";wrDAYO,IAAMA,EAAmB,CAAC,SAAU,SAAS,EAE7C,SAASC,EAAqBC,EAAqB,QAAe,CACvE,QAAWC,KAAOH,EAChBE,EAAK,GAAGC,EAAK,IAAM,CAGbD,EAAK,cAAcC,CAAG,GAAK,GAAGD,EAAK,KAAK,CAAC,CAC/C,CAAC,CAEL,CClBAE,EAAqB,EAErB,eAAeC,GAAO,CACpB,IAAMC,EAAU,MAAMC,EAAa,EAGnC,GADa,QAAQ,KAAK,MAAM,CAAC,EACxB,SAAW,EAAG,CACrBD,EAAQ,WAAW,EACnB,OAGFA,EAAQ,MAAM,CAChB,CAEAD,EAAK","names":["CLI_EXIT_SIGNALS","installCliSignalExit","proc","sig","installCliSignalExit","main","program","buildProgram"]}
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e,f,g}from"./chunk-WOMQ2VGA.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as fetchAgents,d as fetchCrons,c as fetchProcesses,e as killProcess,a as resolveConn,f as sendTask,g as streamTask};
2
+ //# sourceMappingURL=client-IA7ZPE56.js.map
@@ -0,0 +1,2 @@
1
+ import{i as a,j as b,k as c,l as d,m as e,n as f,o as g,q as h}from"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";h();export{a as INTEGRATION_KINDS,c as approvalsConfigSchema,d as daemonConfigSchema,b as eventSubscriptionSchema,e as expandEnvVars,f as loadDaemonConfig,g as validateWorkspaces};
2
+ //# sourceMappingURL=config-HPN2F7LH.js.map
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e}from"./chunk-EZN2YXRY.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as applyConfigMutation,a as findConfigPath,d as getAtPath,c as setAtPath,e as unsetAtPath};
2
+ //# sourceMappingURL=config-mutator-7GPTMTVB.js.map
@@ -0,0 +1,2 @@
1
+ import{b as a,c as b,d as c,e as d}from"./chunk-D3LSPFHK.js";import"./chunk-S7CVSKOX.js";import"./chunk-U4H35SJS.js";import"./chunk-QIJLFPWE.js";export{b as doctor,a as runDoctorChecks,c as runNotificationChecks,d as runReminderChecks};
2
+ //# sourceMappingURL=doctor-IBWQVQV4.js.map
package/dist/index.d.ts CHANGED
@@ -1635,6 +1635,35 @@ declare const agentConfigSchema: z.ZodObject<{
1635
1635
  * agents or by the operator. It never approves anything: approval of a
1636
1636
  * create/delete request stays operator-only (`agentx schedule approve`). */
1637
1637
  admin: z.ZodOptional<z.ZodBoolean>;
1638
+ /** Events on the bus this agent wants to hear about (issue #165). */
1639
+ subscriptions: z.ZodDefault<z.ZodArray<z.ZodObject<{
1640
+ /** Envelope `kind` ("agent", "run") or `type` ("task:completed"); "*" matches all. */
1641
+ kinds: z.ZodArray<z.ZodString, "many">;
1642
+ /** Only events published for these agent ids. */
1643
+ agents: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1644
+ /** Only events published by these nodes (`node.name`). */
1645
+ nodes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1646
+ /** Only events whose summary contains this text (case-insensitive). */
1647
+ match: z.ZodOptional<z.ZodString>;
1648
+ delivery: z.ZodDefault<z.ZodEnum<["pull", "digest", "wake"]>>;
1649
+ /** wake only: no wake when the agent was already woken this many times
1650
+ * in the past hour. */
1651
+ maxPerHour: z.ZodDefault<z.ZodNumber>;
1652
+ }, "strip", z.ZodTypeAny, {
1653
+ kinds: string[];
1654
+ delivery: "pull" | "digest" | "wake";
1655
+ maxPerHour: number;
1656
+ match?: string | undefined;
1657
+ agents?: string[] | undefined;
1658
+ nodes?: string[] | undefined;
1659
+ }, {
1660
+ kinds: string[];
1661
+ match?: string | undefined;
1662
+ agents?: string[] | undefined;
1663
+ nodes?: string[] | undefined;
1664
+ delivery?: "pull" | "digest" | "wake" | undefined;
1665
+ maxPerHour?: number | undefined;
1666
+ }>, "many">>;
1638
1667
  /** Per-agent third-party integrations registry. Declares which services
1639
1668
  * this agent has credentials for (telegram-bot, hubspot, gitlab-user,
1640
1669
  * gmail, etc.). Secrets stay in env vars / keyring; this block holds
@@ -1802,6 +1831,14 @@ declare const agentConfigSchema: z.ZodObject<{
1802
1831
  intervalMinutes: number;
1803
1832
  };
1804
1833
  access: "private" | "public";
1834
+ subscriptions: {
1835
+ kinds: string[];
1836
+ delivery: "pull" | "digest" | "wake";
1837
+ maxPerHour: number;
1838
+ match?: string | undefined;
1839
+ agents?: string[] | undefined;
1840
+ nodes?: string[] | undefined;
1841
+ }[];
1805
1842
  integrations: {
1806
1843
  enabled: boolean;
1807
1844
  credentials: {
@@ -1890,6 +1927,14 @@ declare const agentConfigSchema: z.ZodObject<{
1890
1927
  } | undefined;
1891
1928
  access?: "private" | "public" | undefined;
1892
1929
  admin?: boolean | undefined;
1930
+ subscriptions?: {
1931
+ kinds: string[];
1932
+ match?: string | undefined;
1933
+ agents?: string[] | undefined;
1934
+ nodes?: string[] | undefined;
1935
+ delivery?: "pull" | "digest" | "wake" | undefined;
1936
+ maxPerHour?: number | undefined;
1937
+ }[] | undefined;
1893
1938
  integrations?: {
1894
1939
  label: string;
1895
1940
  kind: string;
@@ -2357,6 +2402,35 @@ declare const daemonConfigSchema: z.ZodObject<{
2357
2402
  * agents or by the operator. It never approves anything: approval of a
2358
2403
  * create/delete request stays operator-only (`agentx schedule approve`). */
2359
2404
  admin: z.ZodOptional<z.ZodBoolean>;
2405
+ /** Events on the bus this agent wants to hear about (issue #165). */
2406
+ subscriptions: z.ZodDefault<z.ZodArray<z.ZodObject<{
2407
+ /** Envelope `kind` ("agent", "run") or `type` ("task:completed"); "*" matches all. */
2408
+ kinds: z.ZodArray<z.ZodString, "many">;
2409
+ /** Only events published for these agent ids. */
2410
+ agents: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
2411
+ /** Only events published by these nodes (`node.name`). */
2412
+ nodes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
2413
+ /** Only events whose summary contains this text (case-insensitive). */
2414
+ match: z.ZodOptional<z.ZodString>;
2415
+ delivery: z.ZodDefault<z.ZodEnum<["pull", "digest", "wake"]>>;
2416
+ /** wake only: no wake when the agent was already woken this many times
2417
+ * in the past hour. */
2418
+ maxPerHour: z.ZodDefault<z.ZodNumber>;
2419
+ }, "strip", z.ZodTypeAny, {
2420
+ kinds: string[];
2421
+ delivery: "pull" | "digest" | "wake";
2422
+ maxPerHour: number;
2423
+ match?: string | undefined;
2424
+ agents?: string[] | undefined;
2425
+ nodes?: string[] | undefined;
2426
+ }, {
2427
+ kinds: string[];
2428
+ match?: string | undefined;
2429
+ agents?: string[] | undefined;
2430
+ nodes?: string[] | undefined;
2431
+ delivery?: "pull" | "digest" | "wake" | undefined;
2432
+ maxPerHour?: number | undefined;
2433
+ }>, "many">>;
2360
2434
  /** Per-agent third-party integrations registry. Declares which services
2361
2435
  * this agent has credentials for (telegram-bot, hubspot, gitlab-user,
2362
2436
  * gmail, etc.). Secrets stay in env vars / keyring; this block holds
@@ -2524,6 +2598,14 @@ declare const daemonConfigSchema: z.ZodObject<{
2524
2598
  intervalMinutes: number;
2525
2599
  };
2526
2600
  access: "private" | "public";
2601
+ subscriptions: {
2602
+ kinds: string[];
2603
+ delivery: "pull" | "digest" | "wake";
2604
+ maxPerHour: number;
2605
+ match?: string | undefined;
2606
+ agents?: string[] | undefined;
2607
+ nodes?: string[] | undefined;
2608
+ }[];
2527
2609
  integrations: {
2528
2610
  enabled: boolean;
2529
2611
  credentials: {
@@ -2612,6 +2694,14 @@ declare const daemonConfigSchema: z.ZodObject<{
2612
2694
  } | undefined;
2613
2695
  access?: "private" | "public" | undefined;
2614
2696
  admin?: boolean | undefined;
2697
+ subscriptions?: {
2698
+ kinds: string[];
2699
+ match?: string | undefined;
2700
+ agents?: string[] | undefined;
2701
+ nodes?: string[] | undefined;
2702
+ delivery?: "pull" | "digest" | "wake" | undefined;
2703
+ maxPerHour?: number | undefined;
2704
+ }[] | undefined;
2615
2705
  integrations?: {
2616
2706
  label: string;
2617
2707
  kind: string;
@@ -3967,10 +4057,6 @@ declare const daemonConfigSchema: z.ZodObject<{
3967
4057
  } | undefined;
3968
4058
  }>>;
3969
4059
  }, "strip", z.ZodTypeAny, {
3970
- defaultExpiryDays: number;
3971
- maxExpiryDays: number;
3972
- laterHours: number;
3973
- notifyAgent: boolean;
3974
4060
  digest: {
3975
4061
  enabled: boolean;
3976
4062
  time: string;
@@ -3981,11 +4067,11 @@ declare const daemonConfigSchema: z.ZodObject<{
3981
4067
  accountId?: string | undefined;
3982
4068
  } | undefined;
3983
4069
  };
4070
+ defaultExpiryDays: number;
4071
+ maxExpiryDays: number;
4072
+ laterHours: number;
4073
+ notifyAgent: boolean;
3984
4074
  }, {
3985
- defaultExpiryDays?: number | undefined;
3986
- maxExpiryDays?: number | undefined;
3987
- laterHours?: number | undefined;
3988
- notifyAgent?: boolean | undefined;
3989
4075
  digest?: {
3990
4076
  enabled?: boolean | undefined;
3991
4077
  timezone?: string | undefined;
@@ -3996,6 +4082,10 @@ declare const daemonConfigSchema: z.ZodObject<{
3996
4082
  accountId?: string | undefined;
3997
4083
  } | undefined;
3998
4084
  } | undefined;
4085
+ defaultExpiryDays?: number | undefined;
4086
+ maxExpiryDays?: number | undefined;
4087
+ laterHours?: number | undefined;
4088
+ notifyAgent?: boolean | undefined;
3999
4089
  }>>;
4000
4090
  /** What happens to runs a restart cuts off (agents/resume). Chat messages
4001
4091
  * are resumed in their chat; scheduled jobs never are (the next run
@@ -4209,6 +4299,19 @@ declare const daemonConfigSchema: z.ZodObject<{
4209
4299
  timeout?: number | undefined;
4210
4300
  interval?: number | undefined;
4211
4301
  }>>;
4302
+ /** Peer event feed (#166): follow each healthy peer's /events and merge
4303
+ * its own events into this node's bus. `skipTypes` are left out on the
4304
+ * peer's side; per-step agent activity is too chatty to cross the mesh. */
4305
+ feed: z.ZodDefault<z.ZodObject<{
4306
+ enabled: z.ZodDefault<z.ZodBoolean>;
4307
+ skipTypes: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
4308
+ }, "strip", z.ZodTypeAny, {
4309
+ enabled: boolean;
4310
+ skipTypes: string[];
4311
+ }, {
4312
+ enabled?: boolean | undefined;
4313
+ skipTypes?: string[] | undefined;
4314
+ }>>;
4212
4315
  }, "strip", z.ZodTypeAny, {
4213
4316
  enabled: boolean;
4214
4317
  peers: {
@@ -4226,6 +4329,10 @@ declare const daemonConfigSchema: z.ZodObject<{
4226
4329
  timeout: number;
4227
4330
  interval: number;
4228
4331
  };
4332
+ feed: {
4333
+ enabled: boolean;
4334
+ skipTypes: string[];
4335
+ };
4229
4336
  }, {
4230
4337
  enabled?: boolean | undefined;
4231
4338
  peers?: {
@@ -4243,6 +4350,10 @@ declare const daemonConfigSchema: z.ZodObject<{
4243
4350
  timeout?: number | undefined;
4244
4351
  interval?: number | undefined;
4245
4352
  } | undefined;
4353
+ feed?: {
4354
+ enabled?: boolean | undefined;
4355
+ skipTypes?: string[] | undefined;
4356
+ } | undefined;
4246
4357
  }>>;
4247
4358
  /** Voices for agents on mesh peers, keyed by remote agent id. The Mac
4248
4359
  * speaks for them, so their nodes need no ElevenLabs key. Unset fields
@@ -5607,6 +5718,14 @@ declare const daemonConfigSchema: z.ZodObject<{
5607
5718
  intervalMinutes: number;
5608
5719
  };
5609
5720
  access: "private" | "public";
5721
+ subscriptions: {
5722
+ kinds: string[];
5723
+ delivery: "pull" | "digest" | "wake";
5724
+ maxPerHour: number;
5725
+ match?: string | undefined;
5726
+ agents?: string[] | undefined;
5727
+ nodes?: string[] | undefined;
5728
+ }[];
5610
5729
  integrations: {
5611
5730
  enabled: boolean;
5612
5731
  credentials: {
@@ -5683,6 +5802,10 @@ declare const daemonConfigSchema: z.ZodObject<{
5683
5802
  timeout: number;
5684
5803
  interval: number;
5685
5804
  };
5805
+ feed: {
5806
+ enabled: boolean;
5807
+ skipTypes: string[];
5808
+ };
5686
5809
  };
5687
5810
  voice: {
5688
5811
  provider: "system" | "elevenlabs";
@@ -5932,10 +6055,6 @@ declare const daemonConfigSchema: z.ZodObject<{
5932
6055
  } | undefined;
5933
6056
  };
5934
6057
  approvals: {
5935
- defaultExpiryDays: number;
5936
- maxExpiryDays: number;
5937
- laterHours: number;
5938
- notifyAgent: boolean;
5939
6058
  digest: {
5940
6059
  enabled: boolean;
5941
6060
  time: string;
@@ -5946,6 +6065,10 @@ declare const daemonConfigSchema: z.ZodObject<{
5946
6065
  accountId?: string | undefined;
5947
6066
  } | undefined;
5948
6067
  };
6068
+ defaultExpiryDays: number;
6069
+ maxExpiryDays: number;
6070
+ laterHours: number;
6071
+ notifyAgent: boolean;
5949
6072
  };
5950
6073
  reminders: {
5951
6074
  enabled: boolean;
@@ -6247,6 +6370,14 @@ declare const daemonConfigSchema: z.ZodObject<{
6247
6370
  } | undefined;
6248
6371
  access?: "private" | "public" | undefined;
6249
6372
  admin?: boolean | undefined;
6373
+ subscriptions?: {
6374
+ kinds: string[];
6375
+ match?: string | undefined;
6376
+ agents?: string[] | undefined;
6377
+ nodes?: string[] | undefined;
6378
+ delivery?: "pull" | "digest" | "wake" | undefined;
6379
+ maxPerHour?: number | undefined;
6380
+ }[] | undefined;
6250
6381
  integrations?: {
6251
6382
  label: string;
6252
6383
  kind: string;
@@ -6307,6 +6438,10 @@ declare const daemonConfigSchema: z.ZodObject<{
6307
6438
  timeout?: number | undefined;
6308
6439
  interval?: number | undefined;
6309
6440
  } | undefined;
6441
+ feed?: {
6442
+ enabled?: boolean | undefined;
6443
+ skipTypes?: string[] | undefined;
6444
+ } | undefined;
6310
6445
  } | undefined;
6311
6446
  voice?: {
6312
6447
  system?: string | Record<string, string> | undefined;
@@ -6550,10 +6685,6 @@ declare const daemonConfigSchema: z.ZodObject<{
6550
6685
  } | undefined;
6551
6686
  } | undefined;
6552
6687
  approvals?: {
6553
- defaultExpiryDays?: number | undefined;
6554
- maxExpiryDays?: number | undefined;
6555
- laterHours?: number | undefined;
6556
- notifyAgent?: boolean | undefined;
6557
6688
  digest?: {
6558
6689
  enabled?: boolean | undefined;
6559
6690
  timezone?: string | undefined;
@@ -6564,6 +6695,10 @@ declare const daemonConfigSchema: z.ZodObject<{
6564
6695
  accountId?: string | undefined;
6565
6696
  } | undefined;
6566
6697
  } | undefined;
6698
+ defaultExpiryDays?: number | undefined;
6699
+ maxExpiryDays?: number | undefined;
6700
+ laterHours?: number | undefined;
6701
+ notifyAgent?: boolean | undefined;
6567
6702
  } | undefined;
6568
6703
  reminders?: {
6569
6704
  enabled?: boolean | undefined;
@@ -6994,6 +7129,9 @@ declare class A2AMesh {
6994
7129
  senderAgentId?: string;
6995
7130
  freshSession?: boolean;
6996
7131
  context?: Record<string, unknown>;
7132
+ /** Aborts the peer call; the peer's /task treats it as a disconnect
7133
+ * and interrupts the run. */
7134
+ signal?: AbortSignal;
6997
7135
  }): AsyncGenerator<{
6998
7136
  event: string;
6999
7137
  data: any;
@@ -7233,6 +7371,10 @@ declare class TypedEventBus {
7233
7371
  private envelopeListeners;
7234
7372
  private ring;
7235
7373
  private node;
7374
+ /** Envelopes taken in from mesh peers, keyed `${node}:${id}`, so the
7375
+ * live stream and a catch-up read never deliver one event twice. Map
7376
+ * insertion order makes the oldest key the first to drop. */
7377
+ private seen;
7236
7378
  constructor();
7237
7379
  /** Set the publishing node name and ring size (daemon boot / reload). */
7238
7380
  configure(opts: {
@@ -7244,6 +7386,19 @@ declare class TypedEventBus {
7244
7386
  emit<E extends EventName>(event: E, payload: AgentXEvents[E]): boolean;
7245
7387
  /** The single publish API. Returns the envelope as delivered. */
7246
7388
  publish(input: PublishInput): EventEnvelope;
7389
+ /** Name this bus publishes under. An envelope whose `node` differs came
7390
+ * from a mesh peer (see ingest). */
7391
+ get nodeName(): string;
7392
+ /** True for envelopes this node published itself. */
7393
+ isLocal(e: EventEnvelope): boolean;
7394
+ /** Take in an envelope published on a mesh peer. It keeps its id, node
7395
+ * and root, lands in the ring and reaches `subscribe` listeners, but
7396
+ * never the typed `on` listeners: the peer records its own traces.
7397
+ * Returns false for an event already taken in, or one that claims to
7398
+ * come from this node (an echo). */
7399
+ ingest(input: EventEnvelope): boolean;
7400
+ /** Whether an event id is still in this node's ring buffer. */
7401
+ hasRecent(id: string): boolean;
7247
7402
  /** Receive every envelope. Returns an unsubscribe function. */
7248
7403
  subscribe(fn: EnvelopeListener): () => void;
7249
7404
  recent(q?: RecentQuery): EventEnvelope[];
@@ -7363,6 +7518,7 @@ declare class AgentXDaemon {
7363
7518
  private hooks;
7364
7519
  private landscape;
7365
7520
  private heartbeat;
7521
+ private stopEventWaker?;
7366
7522
  private business?;
7367
7523
  private httpServer?;
7368
7524
  private attachSweep?;
@@ -7405,6 +7561,8 @@ declare class AgentXDaemon {
7405
7561
  * dashboard) filter by kind / workflow / actor. Created eagerly so
7406
7562
  * early boot events don't fall through. */
7407
7563
  readonly events: EventBus;
7564
+ /** Follows each healthy peer's event feed into the local bus (#166). */
7565
+ private peerFeed?;
7408
7566
  private log;
7409
7567
  private sseClients;
7410
7568
  private configPath?;
@@ -9790,6 +9948,13 @@ declare class AgentRegistry {
9790
9948
  * on WorkflowDispatcher. */
9791
9949
  private workflowAutoRunner?;
9792
9950
  private messageQueue;
9951
+ /**
9952
+ * Voice chats a waiting question has claimed between its wait ending and
9953
+ * the chat being marked running (the rate limiter awaits in between).
9954
+ * Without the claim, two questions waiting on one chat could both see it
9955
+ * free and run at once.
9956
+ */
9957
+ private voiceClaims;
9793
9958
  /** Intent Knowledge Graph classifier. Null when graph.enabled=false. */
9794
9959
  private classifier?;
9795
9960
  private graphStore?;
@@ -10011,6 +10176,9 @@ declare class AgentRegistry {
10011
10176
  channel: string;
10012
10177
  chatId: string;
10013
10178
  } | null;
10179
+ /** Stop every in-flight run of `agentId` in one chat. Used when a streaming
10180
+ * caller disconnects (the phone app's Stop). Returns how many it aborted. */
10181
+ cancelChatTasks(agentId: string, channel: string, chatId: string, reason?: string): number;
10014
10182
  /**
10015
10183
  * Queue a follow-up correction/update for an in-flight task. The message
10016
10184
  * lands in the per-session MessageQueue and is dispatched after the
@@ -10076,9 +10244,7 @@ declare class AgentRegistry {
10076
10244
  byAgent: Record<string, {
10077
10245
  tasks: number;
10078
10246
  input: number;
10079
- output: number; /** Mesh handle. When set, `execute` falls back to a peer that advertises
10080
- * the requested agent before returning "Unknown agent". Duck-typed so
10081
- * we don't create a circular import with src/a2a/mesh.ts. */
10247
+ output: number;
10082
10248
  cacheRead: number;
10083
10249
  cacheCreate: number;
10084
10250
  total: number;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{a as L}from"./chunk-Y57CULGE.js";import{a as St,b as kt,c as vt,d as xt,e as $t,f as Ct,g as Pt,la as bt,ma as Tt,na as Mt}from"./chunk-6JHA3ZE6.js";import"./chunk-3RCFUIYR.js";import"./chunk-ENRJ2QEH.js";import"./chunk-S7CVSKOX.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-3W2KMI5O.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-L53FTKEP.js";import{O as yt,l as lt,m as ct,n as dt,o as mt,p as pt}from"./chunk-BMSPRUEJ.js";import"./chunk-HQMISQ7L.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import{A as D,B as z,C as V,a as ye,b as we,c as Se,d as Ae,e as Ie,f as Oe,g as Ne,h as He,i as je,j as Ue,k as _e,l as I,m as q,n as Be,o as qe,p as Ye,q as O,r as ze,s as Ve,t as Xe,u as x,v as Y,w as Qe,x as Ze,y as et,z as wt}from"./chunk-KLDGJSR5.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-QYHABRLM.js";import{s as ut}from"./chunk-ZOJUHPD5.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-4HNHHKJF.js";import"./chunk-M67AN4J7.js";import"./chunk-DWADWDMU.js";import"./chunk-NO2HOK4B.js";import"./chunk-QD6IICK7.js";import"./chunk-VWTBHLMX.js";import"./chunk-WLRHL2P7.js";import{a as gt,b as ft,e as ht}from"./chunk-XWU7O3S5.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-BKDUCPZ3.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-37EABIOJ.js";import"./chunk-72SZI2UW.js";import"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import{a as ke,b as ve,c as xe,d as $e,e as Ce,f as Pe,g as be,h as Te,i as Me,j as Re,l as Ee,m as Ge,o as T,p as W}from"./chunk-SZJMS7K4.js";import{a as m,b as G}from"./chunk-7I7IEX4S.js";import{a as Fe,b as Le,c as A,d as De}from"./chunk-VDMYBPYB.js";import{a as Ke,b as Je,e as We}from"./chunk-DSYKYZMT.js";import{k as tt,m as st,n as ot,p as nt}from"./chunk-4FFWNPFX.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";W();G();import{execa as Rt}from"execa";import{existsSync as se,promises as X}from"fs";import S from"path";import ie from"node-fetch";async function Et(o,e){let t=o.split("/");if(t.length<2)throw new Error(`Invalid skill package ID: ${o}. Expected format: owner/repo`);let s=t[0],i=t[1],n=t[2];try{let a=n?`${s}/${i}/${n}`:`${s}/${i}`;await Rt("npx",["-y","skills","add",a],{cwd:e,stdio:"pipe"}),m.success(`Installed skill package: ${o}`);let r=S.resolve(e,".skills",`${s}_${i}`);if(se(r))return await ne(r,o);let d=S.resolve(e,".skills");return se(d)?await ne(d,o):[]}catch{return m.info(`Fetching skills directly from GitHub: ${s}/${i}`),await Gt(s,i,n,e)}}async function Gt(o,e,t,s){let i=[];try{let n=`https://api.github.com/repos/${o}/${e}/git/trees/main?recursive=1`,a=await ie(n);if(!a.ok)throw new Error(`GitHub API error: ${a.status}`);let d=(await a.json()).tree.filter(p=>p.type==="blob"&&p.path.endsWith("SKILL.md"));if(t){let p=d.find(f=>f.path.includes(`/${t}/`)||f.path===`${t}/SKILL.md`);if(p){let f=await oe(o,e,p.path,s);f&&i.push(f)}}else for(let p of d){let f=await oe(o,e,p.path,s);f&&i.push(f)}}catch(n){m.error(`Failed to fetch skills from GitHub: ${n.message}`)}return i}async function oe(o,e,t,s){try{let i=`https://raw.githubusercontent.com/${o}/${e}/main/${t}`,n=await ie(i);if(!n.ok)return null;let a=await n.text(),r=A(a);if(r){r.source="remote",r.packageId=`${o}/${e}`;let d=S.dirname(t),p=S.resolve(s,".skills",`${o}_${e}`,d);await X.mkdir(p,{recursive:!0}),await X.writeFile(S.resolve(p,"SKILL.md"),a),r.path=S.resolve(p,"SKILL.md")}return r}catch{return null}}async function ne(o,e){let t=[],{default:s}=await import("fast-glob"),i=await s.glob("**/SKILL.md",{cwd:o,deep:5});for(let n of i)try{let a=S.resolve(o,n),r=await X.readFile(a,"utf8"),d=A(r);d&&(d.source="remote",d.path=a,d.packageId=e,t.push(d))}catch{}return t}async function At(o,e,t,s,i){let n=["---",`name: ${o}`,`description: ${e}`];if(s?.length){n.push("tags:");for(let a of s)n.push(` - ${a}`)}if(i?.length){n.push("globs:");for(let a of i)n.push(` - ${a}`)}return n.push("---"),`${n.join(`
1
+ import{a as L}from"./chunk-Y57CULGE.js";import{a as St,b as kt,c as vt,d as xt,e as $t,f as Ct,g as Pt,la as bt,ma as Tt,na as Mt}from"./chunk-WKMTT2UY.js";import"./chunk-UIVHSYCN.js";import"./chunk-723K4SAW.js";import"./chunk-S7CVSKOX.js";import"./chunk-LQRBGQIR.js";import"./chunk-ZVP6GB4G.js";import"./chunk-SA23V7WX.js";import"./chunk-W4YMMWJL.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-2D3RYIDU.js";import"./chunk-L53FTKEP.js";import{S as yt,l as lt,m as ct,n as dt,o as mt,p as pt}from"./chunk-EJ5ISSWW.js";import"./chunk-CELYD5QW.js";import"./chunk-WP6KLXTP.js";import"./chunk-N6EWZGIX.js";import"./chunk-DP7RTNDM.js";import{s as ut}from"./chunk-O3XG2NVR.js";import"./chunk-EZN2YXRY.js";import{A as D,B as z,C as V,a as ye,b as we,c as Se,d as Ae,e as Ie,f as Oe,g as Ne,h as He,i as je,j as Ue,k as _e,l as I,m as q,n as Be,o as qe,p as Ye,q as O,r as ze,s as Ve,t as Xe,u as x,v as Y,w as Qe,x as Ze,y as et,z as wt}from"./chunk-6AK6WKE5.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import"./chunk-X5C5W3E4.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import"./chunk-4HEVSWO3.js";import"./chunk-DWADWDMU.js";import"./chunk-NO2HOK4B.js";import"./chunk-QD6IICK7.js";import"./chunk-VWTBHLMX.js";import"./chunk-LKJSPO3S.js";import{a as gt,b as ft,e as ht}from"./chunk-C3VRBEJ7.js";import"./chunk-PNWNVOEZ.js";import"./chunk-64P4QHSZ.js";import"./chunk-GSOL2LW6.js";import"./chunk-TFVUOC2C.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-M4AG2YNX.js";import"./chunk-72SZI2UW.js";import"./chunk-FCPTN6NF.js";import"./chunk-FX3D7YON.js";import"./chunk-QOYAX2FT.js";import{a as ke,b as ve,c as xe,d as $e,e as Ce,f as Pe,g as be,h as Te,i as Me,j as Re,l as Ee,m as Ge,o as T,p as W}from"./chunk-SZJMS7K4.js";import{a as m,b as G}from"./chunk-7I7IEX4S.js";import{a as Fe,b as Le,c as A,d as De}from"./chunk-VDMYBPYB.js";import{a as Ke,b as Je,e as We}from"./chunk-DSYKYZMT.js";import{l as tt,n as st,o as ot,q as nt}from"./chunk-U4H35SJS.js";import"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";W();G();import{execa as Rt}from"execa";import{existsSync as se,promises as X}from"fs";import S from"path";import ie from"node-fetch";async function Et(o,e){let t=o.split("/");if(t.length<2)throw new Error(`Invalid skill package ID: ${o}. Expected format: owner/repo`);let s=t[0],i=t[1],n=t[2];try{let a=n?`${s}/${i}/${n}`:`${s}/${i}`;await Rt("npx",["-y","skills","add",a],{cwd:e,stdio:"pipe"}),m.success(`Installed skill package: ${o}`);let r=S.resolve(e,".skills",`${s}_${i}`);if(se(r))return await ne(r,o);let d=S.resolve(e,".skills");return se(d)?await ne(d,o):[]}catch{return m.info(`Fetching skills directly from GitHub: ${s}/${i}`),await Gt(s,i,n,e)}}async function Gt(o,e,t,s){let i=[];try{let n=`https://api.github.com/repos/${o}/${e}/git/trees/main?recursive=1`,a=await ie(n);if(!a.ok)throw new Error(`GitHub API error: ${a.status}`);let d=(await a.json()).tree.filter(p=>p.type==="blob"&&p.path.endsWith("SKILL.md"));if(t){let p=d.find(f=>f.path.includes(`/${t}/`)||f.path===`${t}/SKILL.md`);if(p){let f=await oe(o,e,p.path,s);f&&i.push(f)}}else for(let p of d){let f=await oe(o,e,p.path,s);f&&i.push(f)}}catch(n){m.error(`Failed to fetch skills from GitHub: ${n.message}`)}return i}async function oe(o,e,t,s){try{let i=`https://raw.githubusercontent.com/${o}/${e}/main/${t}`,n=await ie(i);if(!n.ok)return null;let a=await n.text(),r=A(a);if(r){r.source="remote",r.packageId=`${o}/${e}`;let d=S.dirname(t),p=S.resolve(s,".skills",`${o}_${e}`,d);await X.mkdir(p,{recursive:!0}),await X.writeFile(S.resolve(p,"SKILL.md"),a),r.path=S.resolve(p,"SKILL.md")}return r}catch{return null}}async function ne(o,e){let t=[],{default:s}=await import("fast-glob"),i=await s.glob("**/SKILL.md",{cwd:o,deep:5});for(let n of i)try{let a=S.resolve(o,n),r=await X.readFile(a,"utf8"),d=A(r);d&&(d.source="remote",d.path=a,d.packageId=e,t.push(d))}catch{}return t}async function At(o,e,t,s,i){let n=["---",`name: ${o}`,`description: ${e}`];if(s?.length){n.push("tags:");for(let a of s)n.push(` - ${a}`)}if(i?.length){n.push("globs:");for(let a of i)n.push(` - ${a}`)}return n.push("---"),`${n.join(`
2
2
  `)}
3
3
 
4
4
  ${t}`}async function It(o){let{loadLocalSkills:e}=await import("./loader-EVHZ2R73.js");return e(o)}async function Ot(o,e,t,s,i){let a=[{role:"system",content:`You are a skill author for the Agent Skills ecosystem (skills.sh).