agentix-cli 0.87.0 → 0.89.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.
@@ -236,7 +236,7 @@ var d={};function g(r){d=r}function v(){return d}var w=`<link rel="preconnect" h
236
236
  <span class="name">${t(p.name)}</span>
237
237
  <span class="chev">\u25BE</span>
238
238
  <div class="ax-mesh-menu" role="menu">${x}</div>
239
- </div>`,h=[{name:"Mesh",tabs:[{id:"live",label:"Live",href:"/live"},{id:"mesh",label:"Operations",href:"/mesh"},{id:"monitor",label:"Monitor",href:"/monitor"},{id:"approvals",label:"Approvals",href:"/approvals"},{id:"activity",label:"Activity",href:"/activity"},{id:"workflows",label:"Workflows",href:"/workflows"},{id:"admin",label:"Settings",href:"/admin"}]}].map(e=>{let n=e.tabs.map(o=>{let i=o.id===r.activeTab?"ax-topbar__tab is-active":"ax-topbar__tab",s=o.external?' target="_blank" rel="noopener"':"",l=o.external?' <span style="font-size:9px;opacity:0.6">\u2197</span>':"";return`<a href="${o.href}" class="${i}"${s}>${o.label}${l}</a>`}).join("");return`<div class="ax-topbar__group" title="${t(e.name)} tier"><span class="ax-topbar__group-label">${t(e.name)}</span>${n}</div>`}).join("");return`<header class="ax-topbar">
239
+ </div>`,h=[{name:"Mesh",tabs:[{id:"live",label:"Live",href:"/live"},{id:"mesh",label:"Operations",href:"/mesh"},{id:"monitor",label:"Monitor",href:"/monitor"},{id:"approvals",label:"Approvals",href:"/approvals"},{id:"people",label:"People",href:"/people"},{id:"activity",label:"Activity",href:"/activity"},{id:"workflows",label:"Workflows",href:"/workflows"},{id:"admin",label:"Settings",href:"/admin"}]}].map(e=>{let n=e.tabs.map(o=>{let i=o.id===r.activeTab?"ax-topbar__tab is-active":"ax-topbar__tab",s=o.external?' target="_blank" rel="noopener"':"",l=o.external?' <span style="font-size:9px;opacity:0.6">\u2197</span>':"";return`<a href="${o.href}" class="${i}"${s}>${o.label}${l}</a>`}).join("");return`<div class="ax-topbar__group" title="${t(e.name)} tier"><span class="ax-topbar__group-label">${t(e.name)}</span>${n}</div>`}).join("");return`<header class="ax-topbar">
240
240
  <div class="ax-topbar__left">
241
241
  <div class="ax-brand">
242
242
  <span class="ax-brand__mark">AX</span>
@@ -254,4 +254,4 @@ var d={};function g(r){d=r}function v(){return d}var w=`<link rel="preconnect" h
254
254
  </div>
255
255
  </div>
256
256
  </header>${r.subheader?`<div class="ax-subheader">${r.subheader}</div>`:""}`}function t(r){return String(r||"").replace(/[&<>"']/g,a=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[a])}function E(r){return String(r??"").replace(/[&<>"']/g,a=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[a])}export{E as a,g as b,v as c,w as d,y as e,k as f,_ as g};
257
- //# sourceMappingURL=chunk-CL53UVOF.js.map
257
+ //# sourceMappingURL=chunk-DWZYVYZS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/daemon/topbar.ts","../src/daemon/ui/util.ts"],"sourcesContent":["// --- Shared top-chrome for every dashboard surface ---\n//\n// Four pages render in different files (live + kanban + glossary in\n// board-dashboard.ts, settings in admin-panel.ts) but must share: design\n// tokens, fonts, theme switcher, brand, primary tab nav, and a mesh-node\n// selector. This module exports the CSS + HTML snippets so each page\n// composes exactly the same chrome and we never drift them again.\n//\n// Nothing here is page-specific — callers pass in { activeTab, subtitle,\n// subheader? } and compose their own <main> below.\n\nexport type TopbarTab = \"monitor\" | \"activity\" | \"live\" | \"mesh\" | \"boards\" | \"admin\" | \"graph\" | \"glossary\" | \"workflows\" | \"health\" | \"cost\" | \"wiki\" | \"procedures\" | \"inbox\" | \"projects\" | \"approvals\" | \"people\"\n\nexport interface TopbarPeer {\n /** Stable id: primary node id, or URL for configured daemons */\n id: string\n name: string\n /** Absolute URL of the peer's dashboard (http://host:port) — selector\n * navigates to <url>/admin when switched. */\n dashboardUrl: string\n /** True for the node hosting this dashboard (locks the default). */\n primary?: boolean\n /** Optional; shown in the dropdown as \"managing via token\" hint. */\n tokenScope?: string\n}\n\nexport interface TopbarFeatures {\n /** Show the Team/Business Settings sub-tabs — config.business.enabled. */\n business?: boolean\n}\n\n// Set once at server start (board-dashboard + daemon both call it).\n//\n// This used to carry `boards` and `workflows` flags that gated top-level\n// tabs. The nav is now fixed (Live, Operations, Settings), so those flags had\n// nothing left to gate and were removed rather than left describing chrome\n// that no longer exists.\nlet topbarFeatures: TopbarFeatures = {}\n\nexport function setTopbarFeatures(features: TopbarFeatures): void {\n topbarFeatures = features\n}\n\nexport function getTopbarFeatures(): TopbarFeatures {\n return topbarFeatures\n}\n\nexport interface TopbarOpts {\n activeTab: TopbarTab\n /** Text after the brand, e.g. \"Live\" / \"Settings\" / \"Boards\". */\n subtitle: string\n /** Optional HTML inserted as a second row under the topbar. */\n subheader?: string\n /** Peers to list in the mesh selector. */\n peers?: TopbarPeer[]\n /** id of the peer currently being managed — defaults to the primary. */\n currentPeerId?: string\n /** Optional right-side HTML added before the theme switcher (clocks,\n * connection dots, etc.). */\n rightExtras?: string\n}\n\n/**\n * Font link tags + tiny inline bootstrap script. Callers drop this in <head>.\n */\n// Fonts degrade to the system stack when the box is offline or air-gapped —\n// the tokens list real fallbacks, so a failed font fetch costs typography,\n// never layout.\n//\n// The theme bootstrap runs before first paint to avoid a flash. A stored\n// \"crt\" from before that theme was removed falls back to dark rather than\n// leaving data-theme set to a value no stylesheet defines.\nexport const TOPBAR_HEAD = `<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=Roboto+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\">\n<script>(function(){try{var t=localStorage.getItem('ax-theme');if(t!=='light'&&t!=='dark'){t='dark';localStorage.setItem('ax-theme',t)}document.documentElement.setAttribute('data-theme',t)}catch(e){document.documentElement.setAttribute('data-theme','dark')}})();</script>`\n\n/**\n * CSS for topbar + subheader + theme switch + mesh selector. No token\n * definitions — those are per-page because each page's CSS block owns its\n * own :root overrides.\n */\nexport const TOPBAR_CSS = `\n.ax-topbar{display:flex;align-items:center;justify-content:space-between;\n padding:8px 18px;border-bottom:1px solid var(--ax-border);\n background:var(--ax-bg-elev);position:sticky;top:0;z-index:20;gap:10px;flex-wrap:nowrap}\n.ax-topbar__left{display:flex;align-items:center;gap:18px;min-width:0}\n.ax-brand{display:flex;align-items:center;gap:10px;font-weight:600;letter-spacing:-0.01em;flex-shrink:0}\n.ax-brand__mark{font-family:var(--ax-mono);font-size:12px;padding:2px 8px;\n border:1px solid var(--ax-border-2);color:var(--ax-accent);border-radius:4px}\n.ax-brand__name{font-size:14px}\n.ax-brand__subtitle{font-size:11px;color:var(--ax-muted);\n border-left:1px solid var(--ax-border);padding-left:12px;margin-left:4px}\n.ax-topbar__tabs{display:flex;gap:14px;min-width:0;overflow-x:auto;align-items:center}\n/* Tier groups (System / Processes / Procedures) — visual separators\n * mirror the docs/architecture/three-tier.md hierarchy. */\n.ax-topbar__group{display:flex;align-items:center;gap:0;padding:0 4px;\n border-left:1px solid var(--ax-border);position:relative}\n.ax-topbar__group:first-child{border-left:none;padding-left:0}\n.ax-topbar__group-label{font:inherit;font-family:var(--ax-mono);font-size:9px;\n letter-spacing:0.08em;text-transform:uppercase;color:var(--ax-muted);\n padding:0 8px;white-space:nowrap;opacity:0.7}\n.ax-topbar__tab{background:transparent;border:none;color:var(--ax-text-2);\n padding:8px 12px;font:inherit;cursor:pointer;font-size:12px;text-decoration:none;\n border-bottom:2px solid transparent;letter-spacing:-0.005em;white-space:nowrap}\n.ax-topbar__tab:hover{color:var(--ax-text)}\n.ax-topbar__tab.is-active{color:var(--ax-text);border-bottom-color:var(--ax-accent)}\n.ax-topbar__right{display:flex;align-items:center;gap:10px;font-size:11px;\n color:var(--ax-muted);flex-shrink:0}\n.ax-topbar__right .ax-mono{color:var(--ax-text-2)}\n\n/* Mesh selector */\n.ax-mesh-sel{position:relative;display:inline-flex;align-items:center;gap:6px;\n padding:4px 10px;border:1px solid var(--ax-border-2);border-radius:4px;\n background:var(--ax-surface);cursor:pointer;font:inherit;font-size:11px;\n color:var(--ax-text-2);white-space:nowrap}\n.ax-mesh-sel:hover{border-color:var(--ax-accent);color:var(--ax-text)}\n.ax-mesh-sel.is-proxy{background:color-mix(in oklch,var(--ax-accent) 14%,var(--ax-surface));\n border-color:color-mix(in oklch,var(--ax-accent) 45%,var(--ax-border-2));color:var(--ax-accent)}\n.ax-mesh-sel .lbl{font-size:9px;letter-spacing:0.06em;text-transform:uppercase;color:var(--ax-muted);margin-right:2px}\n.ax-mesh-sel .name{font-weight:500;color:var(--ax-text)}\n.ax-mesh-sel .chev{font-size:9px;opacity:0.6;margin-left:2px}\n.ax-mesh-menu{position:absolute;top:calc(100% + 4px);right:0;min-width:240px;\n background:var(--ax-surface);border:1px solid var(--ax-border-2);\n border-radius:6px;box-shadow:0 8px 24px rgba(0,0,0,0.4);padding:4px;z-index:30;display:none}\n.ax-mesh-sel.is-open .ax-mesh-menu{display:block}\n.ax-mesh-menu a{display:block;padding:7px 10px;border-radius:4px;text-decoration:none;\n color:var(--ax-text-2);font-size:12px}\n.ax-mesh-menu a:hover{background:var(--ax-surface-2);color:var(--ax-text)}\n.ax-mesh-menu a.is-current{background:color-mix(in oklch,var(--ax-accent) 12%,var(--ax-surface));\n color:var(--ax-accent);border:1px solid color-mix(in oklch,var(--ax-accent) 30%,var(--ax-border-2))}\n.ax-mesh-menu a .row{display:flex;align-items:center;gap:8px}\n.ax-mesh-menu a .row .dot{width:6px;height:6px;border-radius:50%;background:var(--ax-accent)}\n.ax-mesh-menu a.is-offline .row .dot{background:var(--ax-border-2)}\n.ax-mesh-menu a .url{font-family:var(--ax-mono);font-size:10px;color:var(--ax-muted);margin-top:2px}\n\n/* Theme switcher segmented control */\n.ax-theme-switch{display:inline-flex;border:1px solid var(--ax-border-2);\n border-radius:4px;overflow:hidden}\n.ax-theme-switch button{background:transparent;border:none;color:var(--ax-muted);\n padding:3px 9px;font:inherit;font-size:10px;cursor:pointer;letter-spacing:0.04em;\n text-transform:uppercase;font-family:var(--ax-mono);border-right:1px solid var(--ax-border-2)}\n.ax-theme-switch button:last-child{border-right:none}\n.ax-theme-switch button:hover{color:var(--ax-text);background:var(--ax-surface-2,var(--ax-surface))}\n.ax-theme-switch button.is-active{color:var(--ax-accent);\n background:color-mix(in oklch,var(--ax-accent) 12%,var(--ax-surface))}\n\n/* Subheader — page-specific toolbar below the main topbar. Kanban uses it\n * for the board picker + search + filters; others can use it for context\n * bars if they want. */\n.ax-subheader{display:flex;align-items:center;gap:10px;padding:10px 18px;\n background:var(--ax-bg-elev);border-bottom:1px solid var(--ax-border);\n flex-wrap:wrap}\n.ax-subheader > * {flex-shrink:0}\n.ax-subheader .spacer{flex:1}`\n\n/**\n * Shared click wiring for the theme switcher + mesh selector. Safe to call\n * multiple times — only binds once per element.\n */\nexport const TOPBAR_SCRIPT = `<script>\n(function(){\n function wireTheme(){\n var sw = document.querySelectorAll('[data-theme-opt]');\n if (!sw.length) return;\n var current = document.documentElement.getAttribute('data-theme') || 'dark';\n sw.forEach(function(b){\n if (b.dataset.wired) return; b.dataset.wired = '1';\n if (b.getAttribute('data-theme-opt') === current) b.classList.add('is-active');\n b.addEventListener('click', function(){\n var t = b.getAttribute('data-theme-opt');\n document.documentElement.setAttribute('data-theme', t);\n try { localStorage.setItem('ax-theme', t); } catch (e) {}\n sw.forEach(function(x){ x.classList.toggle('is-active', x === b); });\n });\n });\n }\n function currentPeer(){\n try { return localStorage.getItem('ax-peer') || 'primary'; } catch { return 'primary'; }\n }\n function setCurrentPeer(id){\n try {\n if (id && id !== 'primary') localStorage.setItem('ax-peer', id);\n else localStorage.removeItem('ax-peer');\n } catch {}\n }\n function reflectPeerPill(){\n var sel = document.querySelector('.ax-mesh-sel');\n if (!sel) return;\n var cur = currentPeer();\n sel.classList.toggle('is-proxy', cur !== 'primary');\n // If a proxy is active, update the visible pill label + highlight.\n var picked = null;\n sel.querySelectorAll('.ax-mesh-menu a').forEach(function(a){\n a.classList.toggle('is-current', a.getAttribute('data-peer-id') === cur || (cur === 'primary' && a.getAttribute('data-peer-id') === 'primary'));\n if (a.getAttribute('data-peer-id') === cur) picked = a;\n });\n if (picked) {\n var name = picked.querySelector('span'); // first <span> inside .row\n var visibleName = sel.querySelector('.name');\n if (name && visibleName) visibleName.textContent = name.textContent.replace(/ · primary/, '');\n }\n }\n function wireMesh(){\n var sel = document.querySelector('.ax-mesh-sel');\n if (!sel || sel.dataset.wired) return; sel.dataset.wired = '1';\n sel.addEventListener('click', function(e){\n var link = e.target.closest('.ax-mesh-menu a[data-peer-action=\"proxy\"]');\n if (link) {\n e.preventDefault();\n setCurrentPeer(link.getAttribute('data-peer-id'));\n reflectPeerPill();\n sel.classList.remove('is-open');\n // Reload so the admin panel re-reads state from the selected peer.\n location.reload();\n return;\n }\n if (e.target.closest('.ax-mesh-menu a')) return; // plain navigate anchor\n sel.classList.toggle('is-open');\n });\n document.addEventListener('click', function(e){\n if (!sel.contains(e.target)) sel.classList.remove('is-open');\n });\n reflectPeerPill();\n }\n function wireHostRewrite(){\n try {\n var h = location.hostname || 'localhost';\n document.querySelectorAll('.ax-topbar__tab[href*=\"__HOST__\"]').forEach(function(a){\n a.href = a.getAttribute('href').replace(/__HOST__/g, h);\n });\n } catch (e) {}\n }\n /**\n * Make the topbar peer selector actually drive page content. When the\n * operator picks a non-primary peer, every /api/admin/* request gets an\n * X-Agentx-Peer header (and every EventSource on that path gets a ?peer=\n * query, since EventSource can't set headers). The dashboard's existing\n * proxy handler picks it up and forwards to the chosen peer.\n *\n * Without this hook, the activity-graph (and other admin pages) silently\n * keep showing only the local node's data even after the operator picks\n * a different peer in the topbar.\n */\n function wirePeerProxy(){\n if (window.__axPeerWired) return; window.__axPeerWired = true;\n // Path-prefix allowlist for the peer-proxy interceptor. Extend here\n // when a new admin-side surface needs to follow the mesh selector.\n // /api/workflows is the workflow dashboard's read/write API — it\n // lives outside /api/admin for legacy reasons, but the page is part\n // of the admin surface and should proxy when a non-primary peer is\n // selected (otherwise the workflows page on Mac shows local-only\n // YAMLs while the runtime lives on peer).\n function shouldProxy(url){\n if (!url) return false;\n // Admin-side surfaces that follow the mesh selector. Each entry\n // is a path-prefix match. Extend when a new admin surface lands\n // outside /api/admin/* but should still proxy when the operator\n // picks a non-primary peer.\n // /api/admin/ — original admin surface (activity, ledger, …)\n // /api/workflows — workflow editor + observability page\n // /api/agents — agent dropdowns inside the workflow editor +\n // anywhere else the page asks \"which agents\n // exist on the selected node?\"\n return url.indexOf('/api/admin/') >= 0\n || url.indexOf('/api/workflows') >= 0\n || url.indexOf('/api/agents') >= 0;\n }\n var origFetch = window.fetch.bind(window);\n window.fetch = function(input, init){\n try {\n var peer = currentPeer();\n if (peer && peer !== 'primary') {\n var url = typeof input === 'string' ? input : (input && input.url) || '';\n if (shouldProxy(url)) {\n init = init || {};\n init.headers = new Headers(init.headers || {});\n init.headers.set('X-Agentx-Peer', peer);\n }\n }\n } catch (e) {}\n return origFetch(input, init);\n };\n var OrigES = window.EventSource;\n if (OrigES) {\n window.EventSource = function(url, cfg){\n try {\n var peer = currentPeer();\n if (peer && peer !== 'primary' && typeof url === 'string' && shouldProxy(url)) {\n url += (url.indexOf('?') >= 0 ? '&' : '?') + 'peer=' + encodeURIComponent(peer);\n }\n } catch (e) {}\n return new OrigES(url, cfg);\n };\n window.EventSource.prototype = OrigES.prototype;\n window.EventSource.CONNECTING = OrigES.CONNECTING;\n window.EventSource.OPEN = OrigES.OPEN;\n window.EventSource.CLOSED = OrigES.CLOSED;\n }\n }\n // wirePeerProxy() is synchronous and DOM-independent — it just wraps\n // window.fetch + window.EventSource. Fire it IMMEDIATELY (before\n // DOMContentLoaded) so deferred page bundles that issue their first\n // fetch on bundle-parse (e.g. the workflow editor's React useEffect)\n // see the wrapped fetch and pick up the X-Agentx-Peer header. Without\n // this, the workflow editor's load on Mac:4202 hit local /api/workflows\n // (instead of proxying to the selected peer), got a 404, and silently\n // fell back to blank-graph state — looking like a \"new workflow\".\n wirePeerProxy();\n function wire(){ wireHostRewrite(); wireTheme(); wireMesh(); /* wirePeerProxy already ran */ }\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', wire);\n } else { wire(); }\n})();\n</script>`\n\n/**\n * Render the topbar element. Caller places this at the start of <body>.\n * Emits a matching .ax-subheader row only when `subheader` HTML is provided.\n */\nexport function renderTopbar(opts: TopbarOpts): string {\n const peers = opts.peers && opts.peers.length > 0 ? opts.peers : [{ id: \"local\", name: \"this daemon\", dashboardUrl: \"\", primary: true }]\n const currentId = opts.currentPeerId || peers.find((p) => p.primary)?.id || peers[0].id\n const current = peers.find((p) => p.id === currentId) || peers[0]\n\n const meshMenu = peers.map((p) => {\n const isCurrent = p.id === currentId\n const primaryMark = p.primary ? ' <span style=\"color:var(--ax-muted);font-size:10px\">· primary</span>' : \"\"\n const proxyable = !!p.tokenScope && !p.primary\n // Proxyable peers: use data-peer-id so the click handler switches locally\n // via localStorage + reload. Un-proxyable (no token): legacy navigate.\n const href = proxyable\n ? \"#\"\n : p.dashboardUrl\n ? `${p.dashboardUrl.replace(/\\/+$/, \"\")}/admin`\n : \"#\"\n const dataAttr = proxyable ? ` data-peer-id=\"${esc(p.id)}\" data-peer-action=\"proxy\"` : p.primary ? ` data-peer-id=\"primary\" data-peer-action=\"proxy\"` : \"\"\n const hint = proxyable\n ? '<div class=\"url\" style=\"color:var(--ax-accent)\">manage from this dashboard ✓</div>'\n : p.tokenScope\n ? `<div class=\"url\">${esc(p.tokenScope)}</div>`\n : p.dashboardUrl\n ? '<div class=\"url\" style=\"color:var(--ax-muted)\">(open peer dashboard ↗)</div>'\n : \"\"\n return `<a href=\"${esc(href)}\" class=\"${isCurrent ? \"is-current\" : \"\"}\"${dataAttr}>\n <div class=\"row\"><span class=\"dot\"></span><span>${esc(p.name)}${primaryMark}</span></div>\n ${p.dashboardUrl ? `<div class=\"url\">${esc(p.dashboardUrl)}</div>` : \"\"}\n ${hint}\n </a>`\n }).join(\"\")\n\n const meshSelector = `<div class=\"ax-mesh-sel\" aria-haspopup=\"menu\">\n <span class=\"lbl\">managing</span>\n <span class=\"name\">${esc(current.name)}</span>\n <span class=\"chev\">▾</span>\n <div class=\"ax-mesh-menu\" role=\"menu\">${meshMenu}</div>\n </div>`\n\n // Minimal, mesh-first nav. The primary group answers the four ops\n // questions in order: who's alive and what are they doing (Live),\n // what happened (Ledger), what did it cost (Cost), how is it wired\n // (Settings). A second \"Work\" group appears only when the operator\n // actually configured that surface (boards / workflows) — flags are\n // set once per process via setTopbarFeatures().\n //\n // Deliberately NOT in the nav (all still routable by URL):\n // /admin/ledger /admin/cost what happened, what it cost\n // /workflows /inbox BPM surfaces\n // / (boards) Kanban\n // /admin/health /admin/graph /admin/projects\n // /procedures /admin/wiki /glossary /processes\n //\n // The nav is the set of surfaces an operator opens on purpose, not a site\n // map. Workflows earned its way back: automation that stops running reports\n // nothing anywhere else, so it needs somewhere to be found. Every page still\n // listed above is one link away from Live or Settings, and none of them is\n // where an operator starts their day —\n // \"who is alive and what are they doing\" (Live) and \"how is this wired\"\n // (Settings) are. A tab bar that lists every surface an app HAS is a site\n // map, not navigation; it makes the two answers people actually want\n // harder to find, which is the opposite of what chrome is for.\n //\n // Removing a tab does not remove the page. If view counts later show a\n // surface earning its place, adding a tab back is one line.\n type Tab = { id: TopbarTab; label: string; href: string; external?: boolean }\n const groups: Array<{ name: string; tabs: Tab[] }> = [\n {\n name: \"Mesh\",\n tabs: [\n { id: \"live\", label: \"Live\", href: \"/live\" },\n { id: \"mesh\", label: \"Operations\", href: \"/mesh\" },\n { id: \"monitor\", label: \"Monitor\", href: \"/monitor\" },\n { id: \"approvals\", label: \"Approvals\", href: \"/approvals\" },\n { id: \"people\", label: \"People\", href: \"/people\" },\n { id: \"activity\", label: \"Activity\", href: \"/activity\" },\n { id: \"workflows\", label: \"Workflows\", href: \"/workflows\" },\n { id: \"admin\", label: \"Settings\", href: \"/admin\" },\n ],\n },\n ]\n\n const tabs = groups.map((g) => {\n const inner = g.tabs.map((t) => {\n const cls = t.id === opts.activeTab ? \"ax-topbar__tab is-active\" : \"ax-topbar__tab\"\n const extAttrs = t.external ? ` target=\"_blank\" rel=\"noopener\"` : \"\"\n const extGlyph = t.external ? ' <span style=\"font-size:9px;opacity:0.6\">↗</span>' : \"\"\n return `<a href=\"${t.href}\" class=\"${cls}\"${extAttrs}>${t.label}${extGlyph}</a>`\n }).join(\"\")\n return `<div class=\"ax-topbar__group\" title=\"${esc(g.name)} tier\"><span class=\"ax-topbar__group-label\">${esc(g.name)}</span>${inner}</div>`\n }).join(\"\")\n\n const header = `<header class=\"ax-topbar\">\n <div class=\"ax-topbar__left\">\n <div class=\"ax-brand\">\n <span class=\"ax-brand__mark\">AX</span>\n <span class=\"ax-brand__name\">AgentX</span>\n <span class=\"ax-brand__subtitle\">${esc(opts.subtitle)}</span>\n </div>\n <nav class=\"ax-topbar__tabs\">${tabs}</nav>\n </div>\n <div class=\"ax-topbar__right\">\n ${opts.rightExtras || \"\"}\n ${meshSelector}\n <div class=\"ax-theme-switch\" role=\"tablist\" aria-label=\"Theme\">\n <button data-theme-opt=\"dark\">Dark</button>\n <button data-theme-opt=\"light\">Light</button>\n </div>\n </div>\n</header>${opts.subheader ? `<div class=\"ax-subheader\">${opts.subheader}</div>` : \"\"}`\n return header\n}\n\nfunction esc(s: string): string {\n return String(s || \"\").replace(/[&<>\"']/g, (c) => ({ \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" }[c] as string))\n}\n","// Shared small utilities for UI renderers.\n\n/**\n * HTML-escape a string so it's safe to interpolate inside attributes or text\n * content. Every page used to ship its own `esc` / `escapeHtml` / `safe` —\n * this is the canonical one.\n */\nexport function esc(s: unknown): string {\n return String(s ?? \"\").replace(/[&<>\"']/g, (c) => ({\n \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\",\n }[c] as string))\n}\n\n/** Join class names, dropping falsy values. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \")\n}\n"],"mappings":"AAqCA,IAAIA,EAAiC,CAAC,EAE/B,SAASC,EAAkBC,EAAgC,CAChEF,EAAiBE,CACnB,CAEO,SAASC,GAAoC,CAClD,OAAOH,CACT,CA2BO,IAAMI,EAAc;AAAA;AAAA;AAAA,iRAUdC,EAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BA8EbC,EAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAgKtB,SAASC,EAAaC,EAA0B,CACrD,IAAMC,EAAQD,EAAK,OAASA,EAAK,MAAM,OAAS,EAAIA,EAAK,MAAQ,CAAC,CAAE,GAAI,QAAS,KAAM,cAAe,aAAc,GAAI,QAAS,EAAK,CAAC,EACjIE,EAAYF,EAAK,eAAiBC,EAAM,KAAME,GAAMA,EAAE,OAAO,GAAG,IAAMF,EAAM,CAAC,EAAE,GAC/EG,EAAUH,EAAM,KAAME,GAAMA,EAAE,KAAOD,CAAS,GAAKD,EAAM,CAAC,EAE1DI,EAAWJ,EAAM,IAAKE,GAAM,CAChC,IAAMG,EAAYH,EAAE,KAAOD,EACrBK,EAAcJ,EAAE,QAAU,0EAAyE,GACnGK,EAAY,CAAC,CAACL,EAAE,YAAc,CAACA,EAAE,QAGjCM,EAAOD,EACT,IACAL,EAAE,aACA,GAAGA,EAAE,aAAa,QAAQ,OAAQ,EAAE,UACpC,IACAO,EAAWF,EAAY,kBAAkBG,EAAIR,EAAE,EAAE,8BAAgCA,EAAE,QAAU,mDAAqD,GAClJS,EAAOJ,EACT,0FACAL,EAAE,WACA,oBAAoBQ,EAAIR,EAAE,UAAU,UACpCA,EAAE,aACA,oFACA,GACR,MAAO,YAAYQ,EAAIF,CAAI,aAAaH,EAAY,aAAe,MAAMI;AAAA,wDACrBC,EAAIR,EAAE,IAAI,IAAII;AAAA,QAC9DJ,EAAE,aAAe,oBAAoBQ,EAAIR,EAAE,YAAY,UAAY;AAAA,QACnES;AAAA,SAEN,CAAC,EAAE,KAAK,EAAE,EAEJC,EAAe;AAAA;AAAA,yBAEEF,EAAIP,EAAQ,IAAI;AAAA;AAAA,4CAEGC;AAAA,UA8CpCS,EAhB+C,CACnD,CACE,KAAM,OACN,KAAM,CACJ,CAAE,GAAI,OAAQ,MAAO,OAAQ,KAAM,OAAQ,EAC3C,CAAE,GAAI,OAAQ,MAAO,aAAc,KAAM,OAAQ,EACjD,CAAE,GAAI,UAAW,MAAO,UAAW,KAAM,UAAW,EACpD,CAAE,GAAI,YAAa,MAAO,YAAa,KAAM,YAAa,EAC1D,CAAE,GAAI,SAAU,MAAO,SAAU,KAAM,SAAU,EACjD,CAAE,GAAI,WAAY,MAAO,WAAY,KAAM,WAAY,EACvD,CAAE,GAAI,YAAa,MAAO,YAAa,KAAM,YAAa,EAC1D,CAAE,GAAI,QAAS,MAAO,WAAY,KAAM,QAAS,CACnD,CACF,CACF,EAEoB,IAAKC,GAAM,CAC7B,IAAMC,EAAQD,EAAE,KAAK,IAAKE,GAAM,CAC9B,IAAMC,EAAMD,EAAE,KAAOjB,EAAK,UAAY,2BAA6B,iBAC7DmB,EAAWF,EAAE,SAAW,kCAAoC,GAC5DG,EAAWH,EAAE,SAAW,yDAAsD,GACpF,MAAO,YAAYA,EAAE,gBAAgBC,KAAOC,KAAYF,EAAE,QAAQG,OACpE,CAAC,EAAE,KAAK,EAAE,EACV,MAAO,wCAAwCT,EAAII,EAAE,IAAI,gDAAgDJ,EAAII,EAAE,IAAI,WAAWC,SAChI,CAAC,EAAE,KAAK,EAAE,EAoBV,MAlBe;AAAA;AAAA;AAAA;AAAA;AAAA,yCAKwBL,EAAIX,EAAK,QAAQ;AAAA;AAAA,mCAEvBc;AAAA;AAAA;AAAA,MAG7Bd,EAAK,aAAe;AAAA,MACpBa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAMKb,EAAK,UAAY,6BAA6BA,EAAK,kBAAoB,IAElF,CAEA,SAASW,EAAIU,EAAmB,CAC9B,OAAO,OAAOA,GAAK,EAAE,EAAE,QAAQ,WAAaC,IAAO,CAAE,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,OAAQ,GAAEA,CAAC,CAAY,CAC1I,CC3aO,SAASC,EAAIC,EAAoB,CACtC,OAAO,OAAOA,GAAK,EAAE,EAAE,QAAQ,WAAaC,IAAO,CACjD,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,OAC9D,GAAEA,CAAC,CAAY,CACjB","names":["topbarFeatures","setTopbarFeatures","features","getTopbarFeatures","TOPBAR_HEAD","TOPBAR_CSS","TOPBAR_SCRIPT","renderTopbar","opts","peers","currentId","p","current","meshMenu","isCurrent","primaryMark","proxyable","href","dataAttr","esc","hint","meshSelector","tabs","g","inner","t","cls","extAttrs","extGlyph","s","c","esc","s","c"]}
@@ -1,4 +1,4 @@
1
- import{a as t,d as u,e as v,f,g as w}from"./chunk-CL53UVOF.js";var h=`:root {
1
+ import{a as t,d as u,e as v,f,g as w}from"./chunk-DWZYVYZS.js";var h=`:root {
2
2
  /* --- Brand (agentina) --------------------------------------------- */
3
3
  --ax-blue: #2979FF;
4
4
  --ax-blue-d: #1B5FD9;
@@ -2021,4 +2021,4 @@ ${a.noAssistant?"":`<script>${$({markdownToHtml:z})}${y}</script>`}
2021
2021
  const card = btn.closest('.ax-row-card');
2022
2022
  if (card) card.classList.toggle('is-open');
2023
2023
  };`;export{h as a,$ as b,z as c,T as d,A as e,H as f,O as g,j as h,I as i,L as j,F as k,B as l,P as m,M as n,E as o,N as p};
2024
- //# sourceMappingURL=chunk-O5U5NVLR.js.map
2024
+ //# sourceMappingURL=chunk-OAA7TNB6.js.map
@@ -1,4 +1,4 @@
1
- import{a as Se}from"./chunk-GTJIKXDB.js";import{a as w}from"./chunk-CL53UVOF.js";import{q as Wt}from"./chunk-S2GAEH2F.js";import{t as jt,u as Vt}from"./chunk-7QDAGGOD.js";import{d as Ot,e as Nt}from"./chunk-AQASR6KR.js";import{c as xe,e as B,f as U,h as Ft}from"./chunk-XIYWXCNU.js";import{A as ke,b as be,v as At,x as Q,y as we}from"./chunk-KIXDJEGA.js";import{a as Pt,b as Lt,d as Mt}from"./chunk-Y4CYQV7G.js";import{a as It,b as Rt}from"./chunk-SHEUCITK.js";import{g as _t,h as Ct,i as Dt,k as Et,l as Tt}from"./chunk-BOENB3IK.js";import{q as $t}from"./chunk-HQWMWSSE.js";import{a as St,b as vt}from"./chunk-I6HCIQCQ.js";import{X as ye,ca as wt,da as kt,ga as xt,m as Z,n as gt,o as mt,p as Tr,u as yt,v as bt,w as Mr}from"./chunk-54VYZE7A.js";import{a as ht,i as Lr}from"./chunk-PN6XHTG5.js";import{a as he,h as Pr}from"./chunk-BRK6M6LA.js";import{existsSync as Or,readdirSync as Nr,readFileSync as jr,statSync as Vr}from"fs";import{resolve as Wr}from"path";function Bt(t,e,n=Date.now(),i=7){let r=i*864e5,s=new Map;for(let o of e){let a=s.get(o.workflowId);a?a.push(o):s.set(o.workflowId,[o])}return t.map(o=>{let a=s.get(o.id)??[],c=a.filter(g=>n-g.at<=r),l=a.filter(g=>n-g.at>r&&n-g.at<=r*2),u=c.filter(g=>g.status==="failed").length,d=a.filter(g=>g.status==="paused").length,p=a.length?Math.max(...a.map(g=>g.at)):null,f=a.length?l.length>0&&c.length===0?"dormant":c.length>0&&u*2>=c.length?"failing":c.length>0?"active":"quiet":"never";return{id:o.id,name:o.name||o.id,state:f,lastRunAt:p,recent:c.length,prior:l.length,failed:u,paused:d}}).sort((o,a)=>{let c={dormant:0,failing:1,active:2,quiet:3,never:4};return c[o.state]-c[a.state]||(a.lastRunAt??0)-(o.lastRunAt??0)})}var ee=new Map;function ra(t,e=1e3){if(!Or(t))return[];let n=Nr(t).filter(s=>s.endsWith(".jsonl")).map(s=>{let o=Wr(t,s);return{path:o,mtime:Vr(o).mtimeMs}}).sort((s,o)=>o.mtime-s.mtime).slice(0,e),i=new Set(n.map(s=>s.path));for(let s of ee.keys())i.has(s)||ee.delete(s);let r=[];for(let{path:s,mtime:o}of n){let a=ee.get(s);if(a&&a.mtime===o){a.summary&&r.push(a.summary);continue}let c=Fr(s,o);ee.set(s,{mtime:o,summary:c}),c&&r.push(c)}return r}function Fr(t,e){try{let n=jr(t,"utf-8").split(`
1
+ import{a as Se}from"./chunk-GTJIKXDB.js";import{a as w}from"./chunk-DWZYVYZS.js";import{q as Wt}from"./chunk-S2GAEH2F.js";import{t as jt,u as Vt}from"./chunk-7QDAGGOD.js";import{d as Ot,e as Nt}from"./chunk-AQASR6KR.js";import{c as xe,e as B,f as U,h as Ft}from"./chunk-XIYWXCNU.js";import{A as ke,b as be,v as At,x as Q,y as we}from"./chunk-KIXDJEGA.js";import{a as Pt,b as Lt,d as Mt}from"./chunk-Y4CYQV7G.js";import{a as It,b as Rt}from"./chunk-SHEUCITK.js";import{g as _t,h as Ct,i as Dt,k as Et,l as Tt}from"./chunk-BOENB3IK.js";import{q as $t}from"./chunk-HQWMWSSE.js";import{a as St,b as vt}from"./chunk-I6HCIQCQ.js";import{X as ye,ca as wt,da as kt,ga as xt,m as Z,n as gt,o as mt,p as Tr,u as yt,v as bt,w as Mr}from"./chunk-54VYZE7A.js";import{a as ht,i as Lr}from"./chunk-PN6XHTG5.js";import{a as he,h as Pr}from"./chunk-BRK6M6LA.js";import{existsSync as Or,readdirSync as Nr,readFileSync as jr,statSync as Vr}from"fs";import{resolve as Wr}from"path";function Bt(t,e,n=Date.now(),i=7){let r=i*864e5,s=new Map;for(let o of e){let a=s.get(o.workflowId);a?a.push(o):s.set(o.workflowId,[o])}return t.map(o=>{let a=s.get(o.id)??[],c=a.filter(g=>n-g.at<=r),l=a.filter(g=>n-g.at>r&&n-g.at<=r*2),u=c.filter(g=>g.status==="failed").length,d=a.filter(g=>g.status==="paused").length,p=a.length?Math.max(...a.map(g=>g.at)):null,f=a.length?l.length>0&&c.length===0?"dormant":c.length>0&&u*2>=c.length?"failing":c.length>0?"active":"quiet":"never";return{id:o.id,name:o.name||o.id,state:f,lastRunAt:p,recent:c.length,prior:l.length,failed:u,paused:d}}).sort((o,a)=>{let c={dormant:0,failing:1,active:2,quiet:3,never:4};return c[o.state]-c[a.state]||(a.lastRunAt??0)-(o.lastRunAt??0)})}var ee=new Map;function ra(t,e=1e3){if(!Or(t))return[];let n=Nr(t).filter(s=>s.endsWith(".jsonl")).map(s=>{let o=Wr(t,s);return{path:o,mtime:Vr(o).mtimeMs}}).sort((s,o)=>o.mtime-s.mtime).slice(0,e),i=new Set(n.map(s=>s.path));for(let s of ee.keys())i.has(s)||ee.delete(s);let r=[];for(let{path:s,mtime:o}of n){let a=ee.get(s);if(a&&a.mtime===o){a.summary&&r.push(a.summary);continue}let c=Fr(s,o);ee.set(s,{mtime:o,summary:c}),c&&r.push(c)}return r}function Fr(t,e){try{let n=jr(t,"utf-8").split(`
2
2
  `).filter(Boolean);if(!n.length)return null;let i=JSON.parse(n[0]),r=i.run?.workflowId;if(!r)return null;let s=i.run?.status??"unknown";for(let o=n.length-1;o>=0;o--){let a=JSON.parse(n[o]),c=a.status??a.run?.status;if(c){s=c;break}}return{workflowId:r,status:s,at:e}}catch{return null}}var Br={failStreak:3,disabledDays:30,missedFires:2,graceMs:15*6e4},k={routines:200,summary:160,filters:6,filterValue:60,text:120},Ur=(t,e,n)=>{try{return $t(t,e,n)}catch{return null}},Ut=864e5;function aa(t){let e=t.now??Date.now(),n={...Br,...t.thresholds},i=t.nextFire??Ur,r=[];for(let a of t.crons){let c=t.cronRuns.get(a.id)??[],l=a.timezone||"UTC",u=c.map(f=>({at:Date.parse(f.startedAt),status:f.status})),d=c[0],p={id:`cron:${a.id}`,source:"cron",kind:"schedule",name:$(a.id,k.text),trigger:{schedule:$(a.schedule,k.text),timezone:l},agent:a.agent||null,enabled:a.enabled,state:a.enabled?"enabled":"disabled",nextRunAt:a.enabled?ve(a.nextRun)??ve(i(a.schedule,new Date(e),l)):null,lastRun:d?{at:d.startedAt,status:d.status,summary:Xr(d.status==="success"?void 0:d.errorSummary,k.summary)}:null,lastSuccessAt:c.find(f=>f.status==="success")?.startedAt??null,consecutiveFailures:zt(u),sampledRuns:c.length,flags:[],attention:null};p.flags=Ht(p,u,a.schedule,l,null,e,n,i),r.push(qt(p))}let s=new Map(Bt(t.workflows.map(a=>({id:a.id,name:a.title})),t.workflowRuns,e).map(a=>[a.id,a])),o=new Map;for(let a of t.workflowRuns){let c=o.get(a.workflowId);c?c.push(a):o.set(a.workflowId,[a])}for(let a of t.workflows){let c=a.nodes.find(I=>I.type.startsWith("trigger."));if(!c||c.type!=="trigger.cron"&&c.type!=="trigger.hook")continue;let l=c.config??{},u=a.state||"active",d=u==="active",p=(o.get(a.id)??[]).slice().sort((I,me)=>me.at-I.at),f=p.map(I=>({at:I.at,status:qr(I.status)})),g=f[0],h=c.type==="trigger.cron",y=typeof l.spec=="string"?l.spec:"",D=typeof l.timezone=="string"?l.timezone:"UTC",N={id:`workflow:${a.id}`,source:"workflow",kind:h?"schedule":"event",name:$(a.title||a.id,k.text),trigger:h?{schedule:$(y,k.text),timezone:D}:{event:$(typeof l.event=="string"?l.event:"",k.text),filters:Gr(l.filter,a)},agent:Kr(a),enabled:d,state:u,nextRunAt:h&&d&&y?ve(i(y,new Date(e),D)):null,lastRun:g?{at:new Date(g.at).toISOString(),status:g.status}:null,lastSuccessAt:(()=>{let I=f.find(me=>me.status==="success");return I?new Date(I.at).toISOString():null})(),consecutiveFailures:zt(f),sampledRuns:p.length,flags:[],attention:null},Y=Date.parse(a.updated||a.created||"");N.flags=h?Ht(N,f,y,D,Number.isFinite(Y)?Y:null,e,n,i):zr(N,s.get(a.id)?.state==="dormant",Number.isFinite(Y)?Y:null,e,n),r.push(qt(N))}return r.sort(Hr).slice(0,k.routines)}function zt(t){let e=0;for(let n of t)if(!(n.status==="running"||n.status==="paused"||n.status==="unknown"))if(n.status==="failed"||n.status==="timeout")e++;else break;return e}function Ht(t,e,n,i,r,s,o,a){let c=[],l=e.length?e[0].at:null;if(!t.enabled){let p=Gt(l,r,s,o);return p&&c.push(p),c}if(t.consecutiveFailures>=o.failStreak&&c.push({reason:"failing",detail:`${t.consecutiveFailures} failed attempts in a row`}),l===null)return c.push({reason:"never-ran",detail:"No persisted attempt"}),c;let u=new Date(l),d=null;for(let p=0;p<o.missedFires&&(d=a(n,u,i),!!d);p++)u=d;return d&&s>d.getTime()+o.graceMs&&c.push({reason:"overdue",detail:`No attempt since ${new Date(l).toISOString()}; ${o.missedFires} scheduled fires missed`}),c}function zr(t,e,n,i,r){let s=[],o=t.lastRun?Date.parse(t.lastRun.at):null;if(!t.enabled){let a=Gt(o,n,i,r);return a&&s.push(a),s}return t.consecutiveFailures>=r.failStreak&&s.push({reason:"failing",detail:`${t.consecutiveFailures} failed runs in a row`}),o===null?s.push({reason:"never-ran",detail:"No run recorded for this trigger"}):e&&s.push({reason:"dormant",detail:"Fired in the prior week, silent in the last one"}),s}function Gt(t,e,n,i){let r=Math.max(t??0,e??0);return r&&n-r<i.disabledDays*Ut?null:{reason:"disabled-long",detail:r?`Disabled; no activity for ${Math.floor((n-r)/Ut)} days`:"Disabled and never ran"}}function qt(t){let e=new Set(t.flags.map(n=>n.reason));return t.attention=e.has("failing")?"critical":e.has("overdue")||e.has("dormant")||e.has("never-ran")?"warning":e.has("disabled-long")?"info":null,t}var Kt={critical:0,warning:1,info:2};function Hr(t,e){let n=t.attention?Kt[t.attention]:3,i=e.attention?Kt[e.attention]:3;return n-i||Number(e.enabled)-Number(t.enabled)||t.name.localeCompare(e.name)}function qr(t){switch(t){case"completed":case"ok":return"success";case"failed":return"failed";case"timeout":return"timeout";case"canceled":return"canceled";case"running":return"running";case"paused":return"paused";default:return"unknown"}}function Kr(t){if(t.ownerAgent)return $(t.ownerAgent,k.text);let e=t.nodes.find(n=>n.type==="agent"&&typeof n.config?.agentId=="string"&&n.config.agentId);return e?$(String(e.config.agentId),k.text):null}function Gr(t,e){let n=[],i=e?.project;if(i&&n.push($(`project=${i}`,k.filterValue)),t&&typeof t=="object"&&!Array.isArray(t))for(let[r,s]of Object.entries(t)){let o=Array.isArray(s)?s.map(String):s==null?[]:[String(s)];o.length&&n.push($(`${r}=${o.join(",")}`,k.filterValue))}return n.slice(0,k.filters)}function ve(t){if(!t)return null;let e=t instanceof Date?t:new Date(t);return Number.isFinite(e.getTime())?e.toISOString():null}function $(t,e){return t.length<=e?t:t.slice(0,e-3)+"..."}function Xr(t,e){return t===void 0?void 0:$(t,e)}import{existsSync as re,readdirSync as fi,readFileSync as gi}from"fs";import{resolve as E}from"path";import{randomBytes as Yt}from"crypto";import{existsSync as Yr,mkdirSync as Zr,readdirSync as Qr,readFileSync as ei,renameSync as Zt,unlinkSync as ti,writeFileSync as ni}from"fs";import{resolve as Qt}from"path";function Xt(t){return[...t.account?["--account",t.account]:[],...t.store?["--store",t.store]:[]]}var Jr=t=>t.trim().split(`
3
3
  `).pop()?.slice(0,300)||"no output";async function Jt(t,e,n,i=Se){let r=await i(t.bin,[...Xt(t),"send","text","--to",e,"--message",n,"--no-preview"],{timeoutMs:6e4});return r.code===0?{ok:!0}:{ok:!1,error:`wacli send failed: ${Jr(r.stderr||r.stdout)}`}}async function ua(t,e,n,i,r=Se){return(await r(t.bin,[...Xt(t),"--read-only","media","download","--chat",e,"--id",n,"--output",i],{timeoutMs:12e4})).code===0}var ri=2e3,ii=t=>Jt(t.wacli,t.to,t.text);function $e(t){return Qt(t,".agentx","whatsapp-triage","drafts")}var si=t=>/^[a-z0-9-]{8,64}$/.test(t),te=(t,e)=>Qt($e(t),`${e}.json`);function en(t,e){Zr($e(t),{recursive:!0});let n=te(t,e.id),i=`${n}.${process.pid}.tmp`;ni(i,JSON.stringify(e,null,2)+`
4
4
  `,{mode:384}),Zt(i,n)}function ha(t,e,n=Date.now()){let i=e.text.trim().slice(0,ri);if(!i)throw new Error("empty draft");let r={...e,text:i,id:`${n.toString(36)}-${Yt(4).toString("hex")}`,status:"pending",created_at:new Date(n).toISOString()};return en(t,r),r}function ne(t,e){if(!si(e))return null;try{return JSON.parse(ei(te(t,e),"utf-8"))}catch{return null}}function tn(t,e){let n=$e(t);return Yr(n)?Qr(n).filter(i=>i.endsWith(".json")).map(i=>ne(t,i.slice(0,-5))).filter(i=>!!i&&(!e||i.status===e)).sort((i,r)=>i.created_at.localeCompare(r.created_at)):[]}async function nn(t,e,n,i={}){let r=ne(t,e);if(!r||r.status!=="pending")return{ok:!1,error:`no reply draft "${e}" is waiting`};let s=`${te(t,e)}.${process.pid}.${Yt(3).toString("hex")}.claim`;try{Zt(te(t,e),s)}catch{return{ok:!1,error:`reply draft "${e}" is already being decided`}}let o={...r,decided_by:i.by??"operator",decided_at:new Date(i.now??Date.now()).toISOString()};if(n==="no")o.status="rejected";else{let a=await(i.send??ii)(r).catch(c=>({ok:!1,error:String(c?.message??c)}));a.ok?o.status="sent":(o.status="failed",o.error=a.error)}en(t,o);try{ti(s)}catch{}return o.status==="failed"?{ok:!1,error:o.error??"send failed"}:{ok:!0,draft:o}}import{mkdirSync as oi,readFileSync as ai,renameSync as ci,writeFileSync as li}from"fs";import{resolve as ui}from"path";function rn(t){return ui(xe(t),"_state.json")}function R(t){try{let e=JSON.parse(ai(rn(t),"utf-8"));return{snoozed:e&&typeof e.snoozed=="object"&&e.snoozed?e.snoozed:{},...typeof e?.lastDigest=="string"?{lastDigest:e.lastDigest}:{},...e?.popped&&typeof e.popped=="object"?{popped:e.popped}:{},...typeof e?.passAt=="string"?{passAt:e.passAt}:{},...Array.isArray(e?.wanted)?{wanted:e.wanted.filter(n=>typeof n=="string")}:{}}}catch{return{snoozed:{}}}}function z(t,e){oi(xe(t),{recursive:!0});let n=rn(t),i=`${n}.${process.pid}.tmp`;li(i,JSON.stringify(e,null,2)+`
@@ -477,4 +477,4 @@ Document the arguments, commands, or files the skill expects. Example:
477
477
  claude-code ${ft(t)} --arg value
478
478
  \`\`\`
479
479
  `}xt();var _r={maxPixels:12e5,timeoutMs:5e3,intervalMs:100,changeThreshold:.015,stableMs:400,regions:{},buffer:{enabled:!1,seconds:10,fps:2,region:"screen",maxPixels:3e5}};function Cr(t){return{..._r,...t??{},regions:{...t?.regions??{}},buffer:{..._r.buffer,...t?.buffer??{}}}}function hu(t){try{return Cr(kt(t).screen)}catch{return Cr(void 0)}}var ea=/^[a-z][\w-]*$/,Dr=["window","screen","menubar","notifications"];function J(t,e,n,i){let r=Number(t);if(t===""||t===null||!Number.isFinite(r)||!n(r))throw new Error(`${e} must be ${i}`);return r}var ge=(t,e)=>J(t,e,n=>Number.isInteger(n)&&n>0,"a whole number above 0");function Er(t){let e=typeof t=="string"?t.split(",").map(Number):[t?.x,t?.y,t?.width,t?.height].map(Number);if(e.length!==4||!e.every(Number.isFinite)||e[2]<=0||e[3]<=0)throw new Error("a region is x,y,width,height in screen points, with width and height above 0");return{x:e[0],y:e[1],width:e[2],height:e[3]}}function yu(t,e){let n={...t??{}};if("maxPixels"in e&&(n.maxPixels=ge(e.maxPixels,"maxPixels")),"timeoutMs"in e&&(n.timeoutMs=ge(e.timeoutMs,"timeoutMs")),"intervalMs"in e&&(n.intervalMs=ge(e.intervalMs,"intervalMs")),"stableMs"in e&&(n.stableMs=J(e.stableMs,"stableMs",r=>Number.isInteger(r)&&r>=0,"a whole number, 0 or more")),"changeThreshold"in e&&(n.changeThreshold=J(e.changeThreshold,"changeThreshold",r=>r>=0&&r<=1,"between 0 and 1")),e.regions&&typeof e.regions=="object"){let r={...n.regions??{}};for(let[s,o]of Object.entries(e.regions)){if(!ea.test(s))throw new Error(`region name "${s}" must be lowercase letters, digits, - or _`);o===null?delete r[s]:r[s]=Er(o)}n.regions=r}if(e.buffer&&typeof e.buffer=="object"){let r=e.buffer,s={...n.buffer??{}};"enabled"in r&&(s.enabled=!!r.enabled),"seconds"in r&&(s.seconds=J(r.seconds,"buffer.seconds",o=>o>0&&o<=120,"above 0 and at most 120")),"fps"in r&&(s.fps=J(r.fps,"buffer.fps",o=>o>0&&o<=10,"above 0 and at most 10")),"maxPixels"in r&&(s.maxPixels=ge(r.maxPixels,"buffer.maxPixels")),"region"in r&&(s.region=String(r.region).trim()),n.buffer=s}let i=n.buffer?.region;if(i!==void 0&&!Dr.includes(i)&&!n.regions?.[i])try{Er(i)}catch{throw new Error(`buffer.region "${i}" is not a region \u2014 use ${[...Dr,...Object.keys(n.regions??{})].join(", ")}, or x,y,w,h`)}return n}export{Bt as a,ra as b,Je as c,Cs as d,Ds as e,Nc as f,jc as g,Vc as h,Gn as i,Fc as j,Uc as k,T as l,Xn as m,k as n,aa as o,ua as p,ii as q,ha as r,nn as s,R as t,xa as u,Sa as v,cn as w,_a as x,pn as y,Ba as z,gn as A,cr as B,ml as C,hl as D,Sl as E,yo as F,vl as G,za as H,Ha as I,qa as J,Ka as K,Ga as L,Xa as M,Ya as N,Za as O,ac as P,Te as Q,cc as R,lc as S,H as T,q as U,vo as V,Tl as W,Pl as X,Ll as Y,Ml as Z,tt as _,Ol as $,Me as aa,Oe as ba,le as ca,Xi as da,Yi as ea,gc as fa,je as ga,Ve as ha,Zi as ia,Qi as ja,Ln as ka,jn as la,mc as ma,ns as na,hc as oa,us as pa,fs as qa,We as ra,ms as sa,Vn as ta,P as ua,yr as va,br as wa,wr as xa,Bl as ya,To as za,xr as Aa,Sr as Ba,Ql as Ca,eu as Da,Go as Ea,tu as Fa,$r as Ga,ue as Ha,_c as Ia,Hn as Ja,Fe as Ka,Ge as La,Mc as Ma,su as Na,ou as Oa,au as Pa,cu as Qa,lu as Ra,uu as Sa,du as Ta,pu as Ua,fu as Va,_r as Wa,Cr as Xa,hu as Ya,Dr as Za,yu as _a};
480
- //# sourceMappingURL=chunk-RKHIVWFE.js.map
480
+ //# sourceMappingURL=chunk-X2F3AVGR.js.map
package/dist/cli.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{b as o}from"./chunk-JXF54PT7.js";import"./chunk-QIJLFPWE.js";var s=o(process.versions.node);s&&(console.error(s),process.exit(1));var{buildProgram:r}=await import("./program-KGILRYLG.js"),{installCliSignalExit:i}=await import("./signal-exit-WL7G3EEZ.js");i();var e=await r();process.argv.slice(2).length===0?e.outputHelp():e.parse();
2
+ import{b as o}from"./chunk-JXF54PT7.js";import"./chunk-QIJLFPWE.js";var s=o(process.versions.node);s&&(console.error(s),process.exit(1));var{buildProgram:r}=await import("./program-QKXRASTV.js"),{installCliSignalExit:i}=await import("./signal-exit-WL7G3EEZ.js");i();var e=await r();process.argv.slice(2).length===0?e.outputHelp():e.parse();
3
3
  //# sourceMappingURL=cli.js.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{a as St,b as kt,c as vt,ca as Tt,d as xt,da as Mt,e as $t,f as Ct,g as Pt,h as bt}from"./chunk-UBU7DBAG.js";import"./chunk-RKHIVWFE.js";import"./chunk-GTJIKXDB.js";import"./chunk-C3VCIEZS.js";import"./chunk-CL53UVOF.js";import"./chunk-ZVP6GB4G.js";import"./chunk-S2GAEH2F.js";import"./chunk-VZLIBDLH.js";import"./chunk-EKJG63EJ.js";import"./chunk-7QDAGGOD.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-ACFQBLPX.js";import"./chunk-LQE73AZR.js";import"./chunk-2D3RYIDU.js";import"./chunk-4L244AW4.js";import"./chunk-XIYWXCNU.js";import"./chunk-PPUN7YHA.js";import{V as yt,m as lt,n as ct,o as dt,p as mt,q as pt}from"./chunk-TNR7AI4H.js";import"./chunk-KIXDJEGA.js";import"./chunk-GLQLCBJS.js";import"./chunk-DP7RTNDM.js";import{a as L}from"./chunk-C245D4BZ.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-XVDASTUX.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-Y4CYQV7G.js";import"./chunk-LLNPKE7H.js";import"./chunk-SHEUCITK.js";import"./chunk-BOENB3IK.js";import"./chunk-SZDACK6O.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{s as ut}from"./chunk-HQWMWSSE.js";import"./chunk-I6HCIQCQ.js";import"./chunk-VWTBHLMX.js";import"./chunk-N4HFUAPN.js";import{a as ht}from"./chunk-7OEFPYQJ.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-2FLVU2QW.js";import"./chunk-MYVHVJWZ.js";import"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-7ADEEHZQ.js";import{f as gt,g as ft}from"./chunk-HOXHUFZB.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-ECCPLASB.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-5MUJZODV.js";import{a as m,b as G}from"./chunk-7I7IEX4S.js";import{b as Fe,c as Le,d as A,e as De}from"./chunk-JHCI6XCJ.js";import{a as Ke,b as Je,e as We}from"./chunk-DSYKYZMT.js";import{ba as tt,da as st,ea as ot,ga as nt}from"./chunk-54VYZE7A.js";import"./chunk-PN6XHTG5.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.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 St,b as kt,c as vt,ca as Tt,d as xt,da as Mt,e as $t,f as Ct,g as Pt,h as bt}from"./chunk-3CHAPGUX.js";import"./chunk-X2F3AVGR.js";import"./chunk-GTJIKXDB.js";import"./chunk-C3VCIEZS.js";import"./chunk-DWZYVYZS.js";import"./chunk-ZVP6GB4G.js";import"./chunk-S2GAEH2F.js";import"./chunk-VZLIBDLH.js";import"./chunk-EKJG63EJ.js";import"./chunk-7QDAGGOD.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-ACFQBLPX.js";import"./chunk-LQE73AZR.js";import"./chunk-2D3RYIDU.js";import"./chunk-4L244AW4.js";import"./chunk-XIYWXCNU.js";import"./chunk-PPUN7YHA.js";import{V as yt,m as lt,n as ct,o as dt,p as mt,q as pt}from"./chunk-TNR7AI4H.js";import"./chunk-KIXDJEGA.js";import"./chunk-GLQLCBJS.js";import"./chunk-DP7RTNDM.js";import{a as L}from"./chunk-C245D4BZ.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-XVDASTUX.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-Y4CYQV7G.js";import"./chunk-LLNPKE7H.js";import"./chunk-SHEUCITK.js";import"./chunk-BOENB3IK.js";import"./chunk-SZDACK6O.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{s as ut}from"./chunk-HQWMWSSE.js";import"./chunk-I6HCIQCQ.js";import"./chunk-VWTBHLMX.js";import"./chunk-N4HFUAPN.js";import{a as ht}from"./chunk-7OEFPYQJ.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-2FLVU2QW.js";import"./chunk-MYVHVJWZ.js";import"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-7ADEEHZQ.js";import{f as gt,g as ft}from"./chunk-HOXHUFZB.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-ECCPLASB.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-5MUJZODV.js";import{a as m,b as G}from"./chunk-7I7IEX4S.js";import{b as Fe,c as Le,d as A,e as De}from"./chunk-JHCI6XCJ.js";import{a as Ke,b as Je,e as We}from"./chunk-DSYKYZMT.js";import{ba as tt,da as st,ea as ot,ga as nt}from"./chunk-54VYZE7A.js";import"./chunk-PN6XHTG5.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.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-YFVSSYSL.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).
@@ -0,0 +1,2 @@
1
+ import{a}from"./chunk-BFY4D4RH.js";import"./chunk-OAA7TNB6.js";import"./chunk-DWZYVYZS.js";import"./chunk-QIJLFPWE.js";export{a as renderProcessesPage};
2
+ //# sourceMappingURL=processes-TXEWMXXJ.js.map
@@ -1,4 +1,4 @@
1
- import{a as Yl,b as Ts,g as Vl}from"./chunk-7K5SJJUI.js";import{a as to,b as Il,f as _t,g as _l,h as Dl,i as Pl,j as Ml,k as Ll,l as ql,p as Ul,q as Fl,r as Ki,s as Wl,v as Xi,w as Gl,y as zl}from"./chunk-F7LZTO6I.js";import{a as Bl,c as Jl,d as Hl}from"./chunk-BYD5B3P3.js";import"./chunk-O5U5NVLR.js";import{a as Nl,c as Rl}from"./chunk-EUXF2GJY.js";import{a as Di,b as rc}from"./chunk-RKPAVWXF.js";import{$ as Es,A as sl,B as il,C as rl,D as al,E as cl,F as fl,G as Ct,H as xs,I as Ji,J as hl,K as yl,L as wl,M as $l,N as bl,O as kl,P as It,Q as Nt,R as vl,S as xl,T as Me,U as Ss,V as An,W as Hi,X as Sl,Y as Tl,Z as Yi,_ as Ol,a as uc,aa as Rt,b as fc,ba as As,ca as Vi,da as Cl,h as ms,i as $c,j as xn,k as ps,l as vc,m as xc,n as Dc,o as Pc,p as $s,q as Mi,r as Wc,s as Vc,t as Qc,u as Zc,v as el,w as ol,x as tl,y as qi,z as nl}from"./chunk-UBU7DBAG.js";import{A as bs,B as Yc,Ha as El,Ia as Gi,Ja as Al,Ka as zi,Q as Sn,T as Ui,U as ks,V as ll,Ya as ko,_a as jl,aa as Uo,ba as dl,ca as Fi,ea as Wi,ga as gl,ha as ml,ia as En,ma as vs,pa as pl,qa as ul,ra as Bi,w as Li,x as Gc,z as zc}from"./chunk-RKHIVWFE.js";import"./chunk-GTJIKXDB.js";import{a as hc,d as yc,e as wc}from"./chunk-C3VCIEZS.js";import"./chunk-CL53UVOF.js";import"./chunk-ZVP6GB4G.js";import{a as us,b as fs,c as Sc,d as Ec,e as Ac,g as Tc,h as jc,j as Oc,k as Cc,l as Ic,m as Nc,p as hs,s as Rc,t as _c}from"./chunk-S2GAEH2F.js";import"./chunk-VZLIBDLH.js";import{a as Kc,b as Xc}from"./chunk-EKJG63EJ.js";import{a as bc,p as kc}from"./chunk-7QDAGGOD.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as oo}from"./chunk-ACFQBLPX.js";import{c as Mc,e as ys,g as ws}from"./chunk-LQE73AZR.js";import{a as Lc,b as qc,c as Uc,d as Fc}from"./chunk-2D3RYIDU.js";import"./chunk-4L244AW4.js";import{a as Bc,e as Jc,g as Hc}from"./chunk-XIYWXCNU.js";import"./chunk-PPUN7YHA.js";import{E as qo,K as oc,V as nc,g as qa,r as Ua,y as Ni,z as Ja}from"./chunk-TNR7AI4H.js";import{b as St,g as At,h as ds,i as gs,j as Tt,k as Ha,l as st,m as kn,u as tc}from"./chunk-KIXDJEGA.js";import{e as Xa,f as _i,k as Qa}from"./chunk-GLQLCBJS.js";import{b as Et}from"./chunk-DP7RTNDM.js";import"./chunk-XVDASTUX.js";import"./chunk-SFQUP3BP.js";import"./chunk-Y4CYQV7G.js";import{b as vn}from"./chunk-LLNPKE7H.js";import{a as sc,b as ic}from"./chunk-SHEUCITK.js";import{a as Pi,e as ac,f as cc,h as lc,i as dc,k as gc,l as mc,m as pc}from"./chunk-BOENB3IK.js";import{c as za}from"./chunk-SZDACK6O.js";import{f as Ya,g as Va,h as Ri}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as Wa,k as Ka}from"./chunk-HQWMWSSE.js";import{a as Za,b as ie,c as Ie,d as Ot,e as ec}from"./chunk-I6HCIQCQ.js";import"./chunk-VWTBHLMX.js";import{a as Ci}from"./chunk-N4HFUAPN.js";import"./chunk-7OEFPYQJ.js";import"./chunk-KA2UIZXG.js";import{a as Ii,b as Fa}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as Ba}from"./chunk-X5C5W3E4.js";import{a as jt}from"./chunk-GV7S5BAX.js";import{e as Ga}from"./chunk-GSX4NK2N.js";import"./chunk-2FLVU2QW.js";import"./chunk-MYVHVJWZ.js";import{h as La}from"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-7ADEEHZQ.js";import{g as Lo,i as ls}from"./chunk-HOXHUFZB.js";import"./chunk-WPNRDEHW.js";import{b as xt,d as Ma}from"./chunk-2GIDVZ4H.js";import{a as Ti,b as ba,c as jp,d as rs,e as ka,f as Ia,g as Rp,h as Na,i as _p,m as vt,n as _a,o as Da,s as Pa,v as bo,w as bn}from"./chunk-ECCPLASB.js";import{a as jo,b as kt,e as ja,f as $n}from"./chunk-72SZI2UW.js";import{a as Ra,b as Dp}from"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-5MUJZODV.js";import{a as To,b as Tp}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{J as ji,L as Oi,S as Ip,ba as Aa,ca as Ta,da as T,ea as cs,ga as oe,h as va,i as xa,k as Sa,l as Op,v as Ea,w as Cp}from"./chunk-54VYZE7A.js";import{a as Mo,i as as}from"./chunk-PN6XHTG5.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import{g as Oa,k as Ca,l as Np}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as Pp}from"commander";var Kl=new Pp().name("a2a").description("start an A2A (Agent-to-Agent) protocol server for external agent integration").option("--port <port>","server port","3171").option("--host <host>","server host","0.0.0.0").option("-p, --provider <provider>","AI provider","claude-code").option("-m, --model <model>","model to use").option("--api-key <key>","API key for the provider").option("-c, --cwd <cwd>","working directory",process.cwd()).option("--no-cors","disable CORS headers").action(async e=>{await new fc({port:parseInt(e.port,10),host:e.host,provider:e.provider,model:e.model,apiKey:e.apiKey,cwd:e.cwd,cors:e.cors!==!1}).start()});oe();import{Command as Mp}from"commander";import{execFileSync as io}from"node:child_process";import{cpSync as Xl,existsSync as er,mkdirSync as Qi,mkdtempSync as Lp,readdirSync as qp,rmSync as Ql,writeFileSync as Zl}from"node:fs";import{dirname as ed,join as qe}from"node:path";import{homedir as js,release as Up,tmpdir as Fp}from"node:os";import{setTimeout as Wp}from"node:timers/promises";function Os(){let e=Sc(process.platform,process.arch,Up());if(e)throw new Error(e)}function Cs(){let e=qe(js(),"Library/LaunchAgents"),o=[];try{o=qp(e).filter(Tc)}catch{}let t=o.flatMap(n=>{let s=qe(e,n);try{return[{file:s,plist:io("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return jc(e,t)}function Tn(e){return`gui/${process.getuid()}/${e.label}`}async function Zi(e){try{io("launchctl",["bootout",Tn(e)],{stdio:"pipe"})}catch{}for(let o=0;o<30;o++){try{io("launchctl",["print",Tn(e)],{stdio:"pipe"})}catch{return}await Wp(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function od(e){if(!er(e.file))throw new Error("Run agentx desktop install first.");let o=!0;try{io("launchctl",["print",Tn(e)],{stdio:"pipe"})}catch{o=!1}o||io("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),io("launchctl",["kickstart",Tn(e)],{stdio:"pipe"})}function Bp(){let e=Nc();if(e&&er(qe(e,"apps/mac-voice/build.sh")))return e;throw new Error("Desktop sources are missing from this installation. Update AgentX to a release containing apps/mac-voice and apps/mac-helper.")}var Dt=new Mp("desktop").description("install and control the macOS desktop assistant");Dt.command("install").description("build, install, and start voice and computer-use helpers at login").option("--agent <id>","pin this agent; without it, pick the agent from the menu-bar icon").option("--dry-run","show the installation plan without building or changing login items").action(async e=>{Os();let o=T(),t=Ec(o.agents,e.agent),n=e.agent,s=o.dashboard?.daemonUrl||`http://${o.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:")}`,i=Bp(),r=qe(js(),"Applications"),{keep:a,remove:c}=Cs();if(console.log(`Desktop assistant \u2192 ${qe(r,us)}
1
+ import{a as Yl,b as Ts,g as Vl}from"./chunk-7K5SJJUI.js";import{A as zl,a as to,b as Il,f as _t,g as _l,h as Dl,i as Pl,j as Ml,l as Ll,m as ql,r as Ul,s as Fl,t as Ki,u as Wl,x as Xi,y as Gl}from"./chunk-BUELCBBV.js";import{a as Bl,c as Jl,d as Hl}from"./chunk-BYD5B3P3.js";import"./chunk-OAA7TNB6.js";import{a as Nl,c as Rl}from"./chunk-EUXF2GJY.js";import{a as Di,b as rc}from"./chunk-RKPAVWXF.js";import{$ as Es,A as sl,B as il,C as rl,D as al,E as cl,F as fl,G as Ct,H as xs,I as Ji,J as hl,K as yl,L as wl,M as $l,N as bl,O as kl,P as It,Q as Nt,R as vl,S as xl,T as Me,U as Ss,V as An,W as Hi,X as Sl,Y as Tl,Z as Yi,_ as Ol,a as uc,aa as Rt,b as fc,ba as As,ca as Vi,da as Cl,h as ms,i as $c,j as xn,k as ps,l as vc,m as xc,n as Dc,o as Pc,p as $s,q as Mi,r as Wc,s as Vc,t as Qc,u as Zc,v as el,w as ol,x as tl,y as qi,z as nl}from"./chunk-3CHAPGUX.js";import{A as bs,B as Yc,Ha as El,Ia as Gi,Ja as Al,Ka as zi,Q as Sn,T as Ui,U as ks,V as ll,Ya as ko,_a as jl,aa as Uo,ba as dl,ca as Fi,ea as Wi,ga as gl,ha as ml,ia as En,ma as vs,pa as pl,qa as ul,ra as Bi,w as Li,x as Gc,z as zc}from"./chunk-X2F3AVGR.js";import"./chunk-GTJIKXDB.js";import{a as hc,d as yc,e as wc}from"./chunk-C3VCIEZS.js";import"./chunk-DWZYVYZS.js";import"./chunk-ZVP6GB4G.js";import{a as us,b as fs,c as Sc,d as Ec,e as Ac,g as Tc,h as jc,j as Oc,k as Cc,l as Ic,m as Nc,p as hs,s as Rc,t as _c}from"./chunk-S2GAEH2F.js";import"./chunk-VZLIBDLH.js";import{a as Kc,b as Xc}from"./chunk-EKJG63EJ.js";import{a as bc,p as kc}from"./chunk-7QDAGGOD.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as oo}from"./chunk-ACFQBLPX.js";import{c as Mc,e as ys,g as ws}from"./chunk-LQE73AZR.js";import{a as Lc,b as qc,c as Uc,d as Fc}from"./chunk-2D3RYIDU.js";import"./chunk-4L244AW4.js";import{a as Bc,e as Jc,g as Hc}from"./chunk-XIYWXCNU.js";import"./chunk-PPUN7YHA.js";import{E as qo,K as oc,V as nc,g as qa,r as Ua,y as Ni,z as Ja}from"./chunk-TNR7AI4H.js";import{b as St,g as At,h as ds,i as gs,j as Tt,k as Ha,l as st,m as kn,u as tc}from"./chunk-KIXDJEGA.js";import{e as Xa,f as _i,k as Qa}from"./chunk-GLQLCBJS.js";import{b as Et}from"./chunk-DP7RTNDM.js";import"./chunk-XVDASTUX.js";import"./chunk-SFQUP3BP.js";import"./chunk-Y4CYQV7G.js";import{b as vn}from"./chunk-LLNPKE7H.js";import{a as sc,b as ic}from"./chunk-SHEUCITK.js";import{a as Pi,e as ac,f as cc,h as lc,i as dc,k as gc,l as mc,m as pc}from"./chunk-BOENB3IK.js";import{c as za}from"./chunk-SZDACK6O.js";import{f as Ya,g as Va,h as Ri}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as Wa,k as Ka}from"./chunk-HQWMWSSE.js";import{a as Za,b as ie,c as Ie,d as Ot,e as ec}from"./chunk-I6HCIQCQ.js";import"./chunk-VWTBHLMX.js";import{a as Ci}from"./chunk-N4HFUAPN.js";import"./chunk-7OEFPYQJ.js";import"./chunk-KA2UIZXG.js";import{a as Ii,b as Fa}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as Ba}from"./chunk-X5C5W3E4.js";import{a as jt}from"./chunk-GV7S5BAX.js";import{e as Ga}from"./chunk-GSX4NK2N.js";import"./chunk-2FLVU2QW.js";import"./chunk-MYVHVJWZ.js";import{h as La}from"./chunk-DWADWDMU.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-7ADEEHZQ.js";import{g as Lo,i as ls}from"./chunk-HOXHUFZB.js";import"./chunk-WPNRDEHW.js";import{b as xt,d as Ma}from"./chunk-2GIDVZ4H.js";import{a as Ti,b as ba,c as jp,d as rs,e as ka,f as Ia,g as Rp,h as Na,i as _p,m as vt,n as _a,o as Da,s as Pa,v as bo,w as bn}from"./chunk-ECCPLASB.js";import{a as jo,b as kt,e as ja,f as $n}from"./chunk-72SZI2UW.js";import{a as Ra,b as Dp}from"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-5MUJZODV.js";import{a as To,b as Tp}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{J as ji,L as Oi,S as Ip,ba as Aa,ca as Ta,da as T,ea as cs,ga as oe,h as va,i as xa,k as Sa,l as Op,v as Ea,w as Cp}from"./chunk-54VYZE7A.js";import{a as Mo,i as as}from"./chunk-PN6XHTG5.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import{g as Oa,k as Ca,l as Np}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as Pp}from"commander";var Kl=new Pp().name("a2a").description("start an A2A (Agent-to-Agent) protocol server for external agent integration").option("--port <port>","server port","3171").option("--host <host>","server host","0.0.0.0").option("-p, --provider <provider>","AI provider","claude-code").option("-m, --model <model>","model to use").option("--api-key <key>","API key for the provider").option("-c, --cwd <cwd>","working directory",process.cwd()).option("--no-cors","disable CORS headers").action(async e=>{await new fc({port:parseInt(e.port,10),host:e.host,provider:e.provider,model:e.model,apiKey:e.apiKey,cwd:e.cwd,cors:e.cors!==!1}).start()});oe();import{Command as Mp}from"commander";import{execFileSync as io}from"node:child_process";import{cpSync as Xl,existsSync as er,mkdirSync as Qi,mkdtempSync as Lp,readdirSync as qp,rmSync as Ql,writeFileSync as Zl}from"node:fs";import{dirname as ed,join as qe}from"node:path";import{homedir as js,release as Up,tmpdir as Fp}from"node:os";import{setTimeout as Wp}from"node:timers/promises";function Os(){let e=Sc(process.platform,process.arch,Up());if(e)throw new Error(e)}function Cs(){let e=qe(js(),"Library/LaunchAgents"),o=[];try{o=qp(e).filter(Tc)}catch{}let t=o.flatMap(n=>{let s=qe(e,n);try{return[{file:s,plist:io("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return jc(e,t)}function Tn(e){return`gui/${process.getuid()}/${e.label}`}async function Zi(e){try{io("launchctl",["bootout",Tn(e)],{stdio:"pipe"})}catch{}for(let o=0;o<30;o++){try{io("launchctl",["print",Tn(e)],{stdio:"pipe"})}catch{return}await Wp(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function od(e){if(!er(e.file))throw new Error("Run agentx desktop install first.");let o=!0;try{io("launchctl",["print",Tn(e)],{stdio:"pipe"})}catch{o=!1}o||io("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),io("launchctl",["kickstart",Tn(e)],{stdio:"pipe"})}function Bp(){let e=Nc();if(e&&er(qe(e,"apps/mac-voice/build.sh")))return e;throw new Error("Desktop sources are missing from this installation. Update AgentX to a release containing apps/mac-voice and apps/mac-helper.")}var Dt=new Mp("desktop").description("install and control the macOS desktop assistant");Dt.command("install").description("build, install, and start voice and computer-use helpers at login").option("--agent <id>","pin this agent; without it, pick the agent from the menu-bar icon").option("--dry-run","show the installation plan without building or changing login items").action(async e=>{Os();let o=T(),t=Ec(o.agents,e.agent),n=e.agent,s=o.dashboard?.daemonUrl||`http://${o.node.bind.replace(/^0\.0\.0\.0:/,"127.0.0.1:")}`,i=Bp(),r=qe(js(),"Applications"),{keep:a,remove:c}=Cs();if(console.log(`Desktop assistant \u2192 ${qe(r,us)}
2
2
  Computer-use helper \u2192 ${qe(r,fs)}
3
3
  Agent \u2192 ${n?`${t} (pinned)`:"picked from the menu-bar icon"}
4
4
  Daemon \u2192 ${s}
@@ -448,7 +448,7 @@ return aid ?? null`}function Ph(e,o){if(e.kind==="path"){let s=e.pts,i=s[Math.fl
448
448
  Latest runs (${s.length})`),s.length===0&&console.log(G.dim(" nothing recorded yet"));for(let r of s){let a=r.status==="ok"?G.green("ok"):r.status==="in-flight"?G.yellow("running"):G.red(r.status);console.log(` ${G.dim(em(r.startedAt))} ${(r.channel??"?").padEnd(9)} ${r.agentId} ${a} ${om(r.messagePreview)}`)}console.log()});as();Cp();import{Command as Jy}from"commander";import{existsSync as Hy}from"fs";import he from"chalk";var Qt=new Jy("requests").description("what you asked agents for that is not finished, oldest first"),rm={in_progress:"in progress",waiting_owner:"waiting on you",waiting_other:"waiting on another agent",needs_attention:"needs attention",done:"done",declined:"declined",dropped:"dropped"};function Ur(){if(!Hy(Za()))return console.error(he.red(" no agentx.json here: run this from the install folder, the one that holds agentx.json")),process.exitCode=1,null;let e=Mo();return e?new Ea(e):(process.exitCode=1,null)}var ni=e=>new Date(e).toISOString().slice(0,16).replace("T"," ")+" UTC";function am(e){let o=e.state==="needs_attention"?he.red:e.state==="waiting_owner"?he.yellow:he.dim;console.log(` ${he.cyan(e.id)} ${o(`[${rm[e.state]??e.state}]`)} ${he.dim(`${ni(e.createdAt)} \xB7 ${e.channel} \xB7 ${e.agentId}`)}`),console.log(` ${e.text.replace(/\s+/g," ").trim().slice(0,240)}`),e.state==="waiting_owner"&&e.question&&console.log(he.yellow(` Question: ${e.question}`)),e.state==="needs_attention"&&e.attentionReason&&console.log(he.red(` ${e.attentionReason}`)),e.evidence&&console.log(he.green(` Evidence: ${e.evidence}`)),e.closeReason&&console.log(he.dim(` Reason: ${e.closeReason}`))}Qt.command("list",{isDefault:!0}).alias("ls").description("open requests, oldest first").option("--json","machine-readable output").action(e=>{let o=Ur();if(!o)return;let t=o.listOpen();if(e.json){console.log(JSON.stringify(t,null,2));return}if(Li().enabled||console.log(he.dim(" requests are off: turn them on with `agentx requests settings --enabled on`")),t.length===0){console.log(he.dim(" no open requests"));return}for(let n of t)am(n);console.log(he.dim(`
449
449
  ${t.length} open. Close one: agentx requests done <id> --evidence <link> \xB7 agentx requests drop <id>`))});Qt.command("show <id>").description("one request and the runs, delegations and cards linked to it").action(e=>{let o=Ur();if(!o)return;let t=o.get(e);if(!t||t.state==="candidate"){console.error(he.red(` no request "${e}"`)),process.exitCode=1;return}am(t),console.log(he.dim(` Last activity ${ni(t.updatedAt)}${t.closedAt?` \xB7 closed ${ni(t.closedAt)}`:""}`));for(let n of o.links(e))console.log(he.dim(` ${n.kind} ${n.ref} (${ni(n.at)})`))});function cm(e,o,t,n){Qt.command(`${e} <id>`).description(o).option(t,e==="done"?"link to the proof: PR, issue, message, deploy":"why it is dropped").action((s,i)=>{let r=Ur();if(!r)return;let a=e==="done"?i.evidence:i.reason??"dropped by the owner";if(!a){console.error(he.red(` ${n}`)),process.exitCode=1;return}let c=r.get(s);if(!c||c.state==="candidate"){console.error(he.red(` no request "${s}"`)),process.exitCode=1;return}if(!r.close(s,e==="done"?"done":"dropped",a,Date.now())){console.error(he.red(` ${s} is already closed (${rm[c.state]??c.state})`)),process.exitCode=1;return}console.log(he.green(` \u2713 ${s} ${e==="done"?"closed as done":"dropped"}`))})}cm("done","close a request as finished, with a link to the evidence","--evidence <link>","a finished request needs --evidence <link>");cm("drop","drop a request you no longer want","--reason <text>","");Qt.command("settings").description("show or change the requests settings").option("--enabled <on|off>","record and follow your requests").option("--from <id,...>",'who counts as you on channels other people can reach, as channel:id (your login on GitLab and GitHub, your sender id elsewhere); "none" to clear').option("--channels <name,...>",'channels to record on; "all" for every channel a person writes on').option("--stale-hours <n>","hours without activity before an open request comes back to you").option("--retention-days <n>","days a closed request is kept").action(async e=>{let o={};try{let n=(i,r)=>{if(r===void 0)return;let a=Number(r);if(!(a>0))throw new Error(`${i} must be a positive number`);return a},s=(i,r)=>i===void 0?void 0:i===r?[]:i.split(",").map(a=>a.trim()).filter(Boolean);if(e.enabled!==void 0){if(e.enabled!=="on"&&e.enabled!=="off")throw new Error("--enabled takes on or off");o.enabled=e.enabled==="on"}o.from=s(e.from,"none"),o.channels=s(e.channels,"all"),o.staleAfterHours=n("--stale-hours",e.staleHours),o.retentionDays=n("--retention-days",e.retentionDays)}catch(n){console.error(he.red(` ${n.message}`)),process.exitCode=1;return}if(Object.values(o).some(n=>n!==void 0)){let n=await Gc(o);if(!n.success){console.error(he.red(` ${n.error}`)),process.exitCode=1;return}console.log(he.green(" \u2713 saved")+(n.reloaded?he.dim(" (daemon reloaded)"):""))}let t=Li();console.log(` Requests ${t.enabled?"on":"off"}`),console.log(` Channels ${t.channels.length?t.channels.join(", "):"every channel a person writes on"}`),console.log(` Counts as you ${t.from.length?t.from.join(", "):"only voice, the app and the dashboard on this machine"}`),console.log(` Comes back after ${t.staleAfterHours} hour(s) without activity`),console.log(` Closed requests kept ${t.retentionDays} day(s)`)});import{Command as Gy}from"commander";import Zt from"chalk";oe();var lm=new Gy("request-status").description("show each person the state of their request in the thread where they asked (GitLab, GitHub)").argument("[channel]",Ki.join(" or ")).argument("[state]","on or off").action(async(e,o)=>{if(e!==void 0){o!=="on"&&o!=="off"&&(console.error(Zt.red("\u2717 say on or off, for example: agentx request-status gitlab on")),process.exit(1));let n="",s=await ie(i=>{n=Wl(i,e,o==="on")});s.success||(console.error(Zt.red(`\u2717 ${s.error}`)),process.exit(1)),console.log(Zt.green(`\u2713 ${n}`)),s.reloaded&&console.log(Zt.dim(" daemon hot-reloaded"))}let t=T().requestStatus.channels.map(n=>n.toLowerCase());for(let n of Ki)console.log(` ${n.padEnd(8)} ${t.includes(n)?Zt.green("on"):Zt.dim("off")}`)});import{Command as fw}from"commander";import en from"chalk";import ae from"chalk";import Gn from"prompts";import{readFileSync as zy,writeFileSync as Yy,existsSync as Vy}from"fs";import{resolve as dm}from"path";var Ky=/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;function Xy(e){let o=e.trim();return o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'")?o.slice(1,-1):o}function Fr(e){return/[\s#"'\\]/.test(e)||e===""?JSON.stringify(e):e}function gm(e=".env"){let o=dm(e);if(!Vy(o))return[];let t=zy(o,"utf-8"),n=[];for(let s of t.split(/\r?\n/)){if(s.trim()===""){n.push({kind:"blank",raw:s});continue}if(s.trim().startsWith("#")){n.push({kind:"comment",raw:s});continue}let i=s.match(Ky);i?n.push({kind:"kv",key:i[1],value:Xy(i[2]),raw:s}):n.push({kind:"comment",raw:s})}return n.length&&n[n.length-1].kind==="blank"&&n.pop(),n}function Qy(e){return e.map(o=>o.kind==="kv"?`${o.key}=${Fr(o.value)}`:o.raw).join(`
450
450
  `)+`
451
- `}function Hn(e,o,t=".env"){let n=dm(t),s=gm(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${Fr(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${Fr(o)}`})),Yy(n,Qy(s))}function Wr(e,o=".env"){return gm(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var mm="https://t.me/BotFather";async function Zy(e){try{let o=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!o.ok)return null;let t=await o.json();return t?.ok?t.result:null}catch{return null}}async function ew(e,o){let t=Date.now()+o,n=0;try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();i?.result?.length&&(n=i.result[0].update_id+1)}catch{}for(;Date.now()<t;)try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let r of i?.result||[]){n=Math.max(n,r.update_id+1);let a=r.message||r.edited_message||r.channel_post;if(a?.chat?.id)return{chatId:a.chat.id,chatTitle:a.chat.title||a.chat.username||a.chat.first_name,from:a.from?.first_name||a.from?.username||"unknown"}}}catch{}return null}async function pm(e={}){console.log(),console.log(ae.bold(" Connect Telegram")),console.log(),console.log(ae.dim(` 1. Open ${mm}`)),console.log(ae.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ae.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:o}=await Gn({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});o&&rt(mm);let{token:t}=await Gn({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:b=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(b.trim())||"That doesn't look like a Telegram token"});t||(console.log(ae.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await Zy(t.trim());n||(console.log(ae.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ae.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:i}=await import("fs"),{resolve:r}=await import("path"),a=e.configPath||r(process.cwd(),"agentx.json");i(a)||(console.log(ae.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),l=Object.keys(c.agents||{});l.length===0&&(console.log(ae.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await Gn({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map($=>({title:$,value:$})),initial:0})).agent),g||(console.log(ae.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},u=e.account||g;d[u]&&d[u].agentBinding!==g&&(u=(await Gn({type:"text",name:"account",message:`Account "${u}" is already in use. Pick a different label:`,initial:`${g}-2`,validate:$=>/^[a-z0-9-]+$/i.test($)||"lowercase letters, digits, hyphens only"})).account),u||(console.log(ae.red(" Aborted")),process.exit(1));let f=`TG_${u.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Hn(f,t.trim()),process.env[f]=t.trim();let p=await ie(b=>{Ie(b,"channels.telegram.enabled",!0),Ie(b,`channels.telegram.accounts.${u}`,{token:`\${${f}}`,agentBinding:g});let $=Ot(b,`agents.${g}.mentions`)||[],E=`@${n.username}`;$.includes(E)||($.push(E),Ie(b,`agents.${g}.mentions`,$))},{configPath:e.configPath});if(p.success||(console.log(ae.red(` \u2717 ${p.error}`)),process.exit(1)),console.log(),console.log(ae.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ae.dim(` Token stored in .env as ${f}`)),console.log(ae.dim(` Mentions updated to include @${n.username}`)),p.reloaded?console.log(ae.dim(" Daemon hot-reloaded.")):console.log(ae.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:y}=await Gn({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!y)return;console.log(),console.log(ae.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ae.dim(" Waiting up to 90s..."));let w=await ew(t.trim(),9e4);if(!w){console.log(ae.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ae.dim(" agentx config set notifications.destination.channel telegram")),console.log(ae.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ae.dim(` agentx config set notifications.destination.accountId ${u}`));return}let k=await ie(b=>{Ie(b,"notifications.destination",{channel:"telegram",chatId:String(w.chatId),accountId:u})},{configPath:e.configPath});if(!k.success){console.log(ae.red(` \u2717 failed to save destination: ${k.error}`));return}console.log(ae.green(" \u2713 Default --notify target set")),console.log(ae.dim(` Chat: ${w.chatTitle||w.chatId} (from ${w.from})`)),console.log(ae.dim(" From now on, --notify me resolves to this chat.")),k.reloaded&&console.log(ae.dim(" Daemon hot-reloaded."))}import ve from"chalk";import Br from"prompts";import{existsSync as Hr,mkdirSync as ow,readdirSync as tw,readFileSync as um}from"fs";import{resolve as Jr}from"path";var nw=".agentx/whatsapp-sessions";function sw(){let e=Jr(process.cwd(),".agentx/daemon.pid");if(!Hr(e))return!1;try{let o=parseInt(um(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function iw(e){if(!Hr(e))return!1;try{return tw(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function rw(e,o){let t;try{t=await import("@whiskeysockets/baileys")}catch{return o(ve.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),o(ve.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=t.default||t;ow(e,{recursive:!0});let{state:i,saveCreds:r}=await s(e),a;try{a=(await t.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},l=n({auth:{creds:i.creds,keys:t.makeCacheableSignalKeyStore?t.makeCacheableSignalKeyStore(i.keys,c):i.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return l.ev.on("creds.update",r),await new Promise(g=>{let u=setTimeout(()=>{o(ve.yellow(" Timed out waiting for scan (2min)."));try{l.end(void 0)}catch{}g(!1)},12e4);l.ev.on("connection.update",async f=>{if(f.qr){o(ve.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),o("");try{let{default:p}=await import("qrcode-terminal");p.generate(f.qr,{small:!0})}catch{o(` QR: ${f.qr}`)}o("")}if(f.connection==="open"){clearTimeout(u),o(ve.green(" \u2713 Paired"));try{l.end(void 0)}catch{}g(!0)}f.connection==="close"&&!f.qr&&f.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(u),o(ve.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function fm(e={}){if(console.log(),console.log(ve.bold(" Connect WhatsApp")),console.log(),sw()){console.log(ve.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(ve.dim(" agentx daemon stop")),console.log();let{cont:l}=await Br({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(ve.red(" Aborted")),process.exit(1))}let o=e.configPath||Jr(process.cwd(),"agentx.json");Hr(o)||(console.log(ve.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(um(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||nw,s=Jr(process.cwd(),n),i=Object.keys(t.agents||{});i.length===0&&(console.log(ve.red(" No agents configured. Run: agentx agent add")),process.exit(1));let r=e.agent;r||(r=(await Br({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:i.map(g=>({title:g,value:g})),initial:0})).agent),r||(console.log(ve.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(iw(s)&&a){let{keep:l}=await Br({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!l,l&&console.log(ve.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await rw(s,g=>console.log(g))||(console.log(ve.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await ie(l=>{Ie(l,"channels.whatsapp.enabled",!0),Ie(l,"channels.whatsapp.sessionDir",n),Ie(l,"channels.whatsapp.defaultAgent",r)},{configPath:e.configPath});c.success||(console.log(ve.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(ve.green(` \u2713 WhatsApp bound to agent "${r}"`)),console.log(ve.dim(` Session: ${n}`)),console.log(ve.dim(" Start the daemon to begin receiving:")),console.log(ve.dim(" agentx daemon start")),console.log(ve.dim(" Add routes later with:")),console.log(ve.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${r}"}]'`)),console.log()}import{randomBytes as aw}from"crypto";import je from"chalk";import hm from"prompts";var si="agentx-mesh:",ii="//join/";function cw(e){return Buffer.from(e,"utf-8").toString("base64url")}function lw(e){return Buffer.from(e,"base64url").toString("utf-8")}function dw(e){return`${si}${ii}${cw(JSON.stringify(e))}`}function gw(e){if(!e.startsWith(`${si}${ii}`))throw new Error(`Not a mesh invite link \u2014 expected ${si}${ii}\u2026`);let o=e.slice(si.length+ii.length),t=JSON.parse(lw(o));if(t.version!==1)throw new Error(`Unsupported invite version: ${t.version}`);if(typeof t.url!="string"||typeof t.token!="string"||typeof t.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return t}function mw(){return aw(32).toString("hex")}function pw(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function uw(e){return e?.node?.name||e?.node?.id||"node"}async function ym(e){let{readFileSync:o,existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");t(s)||(console.log(je.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let i=JSON.parse(o(s,"utf-8")),r=Wr("MESH_TOKEN");r||(r=mw(),Hn("MESH_TOKEN",r),console.log(je.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||pw(i);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:d}=await hm({type:"text",name:"url",message:"This node's URL as peers should reach it (e.g. http://100.x.x.x:18800):",initial:a,validate:u=>/^https?:\/\//.test(u)||"must start with http:// or https://"});d||(console.log(je.red(" Aborted")),process.exit(1)),a=d}let l=await ie(d=>{Ie(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(je.red(` \u2717 ${l.error}`)),process.exit(1));let g=dw({url:a,token:r,name:uw(i),version:1});console.log(),console.log(je.bold(" Mesh invite")),console.log(),console.log(` ${je.cyan(g)}`),console.log(),console.log(je.dim(" Run on the other node:")),console.log(je.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log(je.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function wm(e,o={}){let t;try{t=gw(e)}catch(i){console.log(je.red(` \u2717 ${i.message}`)),process.exit(1)}let n=Wr("MESH_TOKEN");if(n&&n!==t.token){let{overwrite:i}=await hm({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});i||(console.log(je.red(" Aborted (keeping existing .env)")),process.exit(1))}Hn("MESH_TOKEN",t.token);let s=await ie(i=>{Ie(i,"mesh.enabled",!0);let r=Ot(i,"mesh.peers")||[],a=r.findIndex(l=>l.name===t.name),c={name:t.name,url:t.url,token:"${MESH_TOKEN}"};a>=0?r[a]=c:r.push(c),Ie(i,"mesh.peers",r)},{configPath:o.configPath});s.success||(console.log(je.red(` \u2717 ${s.error}`)),process.exit(1)),console.log(je.green(" \u2713 Joined mesh")),console.log(je.dim(` Peer: ${t.name} @ ${t.url}`)),console.log(je.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log(je.dim(" Daemon hot-reloaded.")):console.log(je.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let i=await fetch(`${t.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(i.ok){let r=await i.json(),a=Array.isArray(r.agents)?r.agents.length:"?";console.log(je.dim(` Reachable \u2014 ${t.name} exposes ${a} agents`))}else console.log(je.yellow(` Peer returned HTTP ${i.status} \u2014 double-check the URL`))}catch(i){console.log(je.yellow(` Could not reach ${t.url} right now (${i?.cause?.code||i.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var on=new fw().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");on.command("telegram").description("pair a Telegram bot \u2014 persists token in .env, binds to an agent, auto-detects default chat").option("--agent <id>","agent to bind the bot to (skips the prompt)").option("--account <name>","account label in channels.telegram.accounts (defaults to agent id)").option("--skip-chat-capture","don't listen for the first message after pairing").option("-c, --config <path>","path to agentx.json").action(async e=>{await pm({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});on.command("whatsapp").description("pair WhatsApp via QR (prints in terminal), then writes channels.whatsapp config").option("--agent <id>","default agent for inbound messages").option("--session-dir <path>","session directory (default: .agentx/whatsapp-sessions)").option("--skip-pair","skip QR pairing (use when session already exists)").option("-c, --config <path>","path to agentx.json").action(async e=>{await fm({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var $m=on.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");$m.command("invite").description("emit a single-use join link for another AgentX node").option("--url <url>","this node's URL as peers should reach it (Tailscale IP etc.)").option("-c, --config <path>","path to agentx.json").action(async e=>{await ym({url:e.url,configPath:e.config})});$m.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,o)=>{await wm(e,{configPath:o.config})});on.action(()=>{console.log(),console.log(en.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${en.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${en.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${en.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${en.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(en.dim(" GitLab connect is the next slice.")),console.log()});oe();import{Command as hw}from"commander";import ye from"chalk";var zn=new hw().name("usage").description("token usage analysis and reporting");zn.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=T(),[o,t]=e.node.bind.split(":"),s=await(await fetch(`http://${o||"127.0.0.1"}:${t}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(ye.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(ye.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${ye.bold(i(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${i(s.totalInput)}`),console.log(` Output: ${i(s.totalOutput)}`),console.log(` Cache read: ${i(s.totalCacheRead)}`),console.log(` Cache create: ${i(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${ye.red(String(s.totalErrors))}`),console.log(),console.log(ye.bold(" By Agent:"));let r=Object.entries(s.byAgent||{});r.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of r){let l=i(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${ye.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${ye.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(ye.red(" Daemon not running. Start with: agentx daemon start")):console.log(ye.red(` ${e.message}`))}});zn.command("report").description("run full session analysis (parses Claude Code JSONL files)").option("--days <n>","analyze last N days","7").action(async e=>{let{execSync:o}=await import("child_process"),{existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!t(s)){console.log(ye.red(` Script not found: ${s}`)),console.log(ye.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(ye.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(ye.red(" Analysis failed. Is Python 3 installed?"))}});zn.command("surfaces").description("which CLI commands and dashboard pages are actually used").option("--days <n>","window in days","30").option("--kind <kind>","cli | page (default: both)").option("--unused","list registered surfaces with ZERO recorded use instead").option("--json","raw JSON output").action(async e=>{let{listSurfaceUse:o}=await import("./surface-usage-O5L4KLGS.js"),t=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=o({kind:t,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:i}=await import("./program-KGILRYLG.js"),r=await i(),a=new Set(n.filter(d=>d.kind==="cli").map(d=>d.name)),c=[],l=(d,u)=>{for(let f of d.commands??[]){let p=u?`${u} ${f.name()}`:f.name();c.push(p),l(f,p)}};l(r,"");let g=c.filter(d=>!a.has(d)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(ye.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${ye.dim("\xB7")} ${d}`);console.log(),console.log(ye.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(ye.dim(" it must also fail the impact test. See docs/architecture/surface-reduction.md")),console.log();return}if(e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(),console.log(ye.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(ye.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(ye.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(ye.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=ye.dim(`${i.days}d`);console.log(` ${ye.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(ye.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as yw}from"commander";import xe from"chalk";import{readFileSync as ww}from"fs";import{resolve as $w}from"path";oe();var Qo=new yw().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");Qo.command("serve",{isDefault:!0}).description("start the dashboard server (live view always; boards if configured)").option("--port <n>","override dashboard.port").option("--bind <host>","override dashboard.bind (e.g. 0.0.0.0)").action(async e=>{try{try{Ma($w(process.cwd(),".env"))}catch{}let o=bw(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-YKQ7BCJY.js");t(o)}catch(o){console.log(xe.red(` ${o.message}`)),process.env.DEBUG&&o.stack&&console.log(xe.dim(o.stack)),process.exit(1)}});function bw(e,o){try{let t=T();return e&&(t.dashboard.port=parseInt(e,10)),o&&(t.dashboard.bind=o),t}catch{return console.log(xe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(xe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
451
+ `}function Hn(e,o,t=".env"){let n=dm(t),s=gm(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${Fr(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${Fr(o)}`})),Yy(n,Qy(s))}function Wr(e,o=".env"){return gm(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var mm="https://t.me/BotFather";async function Zy(e){try{let o=await fetch(`https://api.telegram.org/bot${e}/getMe`,{signal:AbortSignal.timeout(8e3)});if(!o.ok)return null;let t=await o.json();return t?.ok?t.result:null}catch{return null}}async function ew(e,o){let t=Date.now()+o,n=0;try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=-1&timeout=0`,{signal:AbortSignal.timeout(5e3)})).json();i?.result?.length&&(n=i.result[0].update_id+1)}catch{}for(;Date.now()<t;)try{let i=await(await fetch(`https://api.telegram.org/bot${e}/getUpdates?offset=${n}&timeout=10`,{signal:AbortSignal.timeout(15e3)})).json();for(let r of i?.result||[]){n=Math.max(n,r.update_id+1);let a=r.message||r.edited_message||r.channel_post;if(a?.chat?.id)return{chatId:a.chat.id,chatTitle:a.chat.title||a.chat.username||a.chat.first_name,from:a.from?.first_name||a.from?.username||"unknown"}}}catch{}return null}async function pm(e={}){console.log(),console.log(ae.bold(" Connect Telegram")),console.log(),console.log(ae.dim(` 1. Open ${mm}`)),console.log(ae.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ae.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:o}=await Gn({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});o&&rt(mm);let{token:t}=await Gn({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:b=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(b.trim())||"That doesn't look like a Telegram token"});t||(console.log(ae.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await Zy(t.trim());n||(console.log(ae.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ae.green(`\u2713 ${n.first_name} (@${n.username})`));let{readFileSync:s,existsSync:i}=await import("fs"),{resolve:r}=await import("path"),a=e.configPath||r(process.cwd(),"agentx.json");i(a)||(console.log(ae.red(` No agentx.json at ${a}. Run: agentx init`)),process.exit(1));let c=JSON.parse(s(a,"utf-8")),l=Object.keys(c.agents||{});l.length===0&&(console.log(ae.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await Gn({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map($=>({title:$,value:$})),initial:0})).agent),g||(console.log(ae.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},u=e.account||g;d[u]&&d[u].agentBinding!==g&&(u=(await Gn({type:"text",name:"account",message:`Account "${u}" is already in use. Pick a different label:`,initial:`${g}-2`,validate:$=>/^[a-z0-9-]+$/i.test($)||"lowercase letters, digits, hyphens only"})).account),u||(console.log(ae.red(" Aborted")),process.exit(1));let f=`TG_${u.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Hn(f,t.trim()),process.env[f]=t.trim();let p=await ie(b=>{Ie(b,"channels.telegram.enabled",!0),Ie(b,`channels.telegram.accounts.${u}`,{token:`\${${f}}`,agentBinding:g});let $=Ot(b,`agents.${g}.mentions`)||[],E=`@${n.username}`;$.includes(E)||($.push(E),Ie(b,`agents.${g}.mentions`,$))},{configPath:e.configPath});if(p.success||(console.log(ae.red(` \u2717 ${p.error}`)),process.exit(1)),console.log(),console.log(ae.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ae.dim(` Token stored in .env as ${f}`)),console.log(ae.dim(` Mentions updated to include @${n.username}`)),p.reloaded?console.log(ae.dim(" Daemon hot-reloaded.")):console.log(ae.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:y}=await Gn({type:"confirm",name:"capture",message:"Listen for a message so we can set this as your default --notify target?",initial:!0});if(!y)return;console.log(),console.log(ae.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ae.dim(" Waiting up to 90s..."));let w=await ew(t.trim(),9e4);if(!w){console.log(ae.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ae.dim(" agentx config set notifications.destination.channel telegram")),console.log(ae.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ae.dim(` agentx config set notifications.destination.accountId ${u}`));return}let k=await ie(b=>{Ie(b,"notifications.destination",{channel:"telegram",chatId:String(w.chatId),accountId:u})},{configPath:e.configPath});if(!k.success){console.log(ae.red(` \u2717 failed to save destination: ${k.error}`));return}console.log(ae.green(" \u2713 Default --notify target set")),console.log(ae.dim(` Chat: ${w.chatTitle||w.chatId} (from ${w.from})`)),console.log(ae.dim(" From now on, --notify me resolves to this chat.")),k.reloaded&&console.log(ae.dim(" Daemon hot-reloaded."))}import ve from"chalk";import Br from"prompts";import{existsSync as Hr,mkdirSync as ow,readdirSync as tw,readFileSync as um}from"fs";import{resolve as Jr}from"path";var nw=".agentx/whatsapp-sessions";function sw(){let e=Jr(process.cwd(),".agentx/daemon.pid");if(!Hr(e))return!1;try{let o=parseInt(um(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function iw(e){if(!Hr(e))return!1;try{return tw(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function rw(e,o){let t;try{t=await import("@whiskeysockets/baileys")}catch{return o(ve.red(" WhatsApp pairing needs @whiskeysockets/baileys.")),o(ve.red(" Install with: pnpm add @whiskeysockets/baileys (or npm install)")),!1}let{makeWASocket:n,useMultiFileAuthState:s}=t.default||t;ow(e,{recursive:!0});let{state:i,saveCreds:r}=await s(e),a;try{a=(await t.fetchLatestBaileysVersion()).version}catch{}let c={level:"silent",trace:()=>{},debug:()=>{},info:()=>{},warn:()=>{},fatal:()=>{},error:()=>{},child:()=>c},l=n({auth:{creds:i.creds,keys:t.makeCacheableSignalKeyStore?t.makeCacheableSignalKeyStore(i.keys,c):i.keys},...a?{version:a}:{},logger:c,printQRInTerminal:!1,browser:["agentx-connect","pairing","1.0"],syncFullHistory:!1,markOnlineOnConnect:!1});return l.ev.on("creds.update",r),await new Promise(g=>{let u=setTimeout(()=>{o(ve.yellow(" Timed out waiting for scan (2min)."));try{l.end(void 0)}catch{}g(!1)},12e4);l.ev.on("connection.update",async f=>{if(f.qr){o(ve.dim(" Scan this QR with WhatsApp \u2192 Linked devices \u2192 Link a device:")),o("");try{let{default:p}=await import("qrcode-terminal");p.generate(f.qr,{small:!0})}catch{o(` QR: ${f.qr}`)}o("")}if(f.connection==="open"){clearTimeout(u),o(ve.green(" \u2713 Paired"));try{l.end(void 0)}catch{}g(!0)}f.connection==="close"&&!f.qr&&f.lastDisconnect?.error?.output?.statusCode===401&&(clearTimeout(u),o(ve.red(" \u2717 Authorization failed \u2014 rescan required")),g(!1))})})}async function fm(e={}){if(console.log(),console.log(ve.bold(" Connect WhatsApp")),console.log(),sw()){console.log(ve.yellow(" \u26A0 The daemon is running. Stop it first so pairing can open a fresh Baileys session:")),console.log(ve.dim(" agentx daemon stop")),console.log();let{cont:l}=await Br({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(ve.red(" Aborted")),process.exit(1))}let o=e.configPath||Jr(process.cwd(),"agentx.json");Hr(o)||(console.log(ve.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(um(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||nw,s=Jr(process.cwd(),n),i=Object.keys(t.agents||{});i.length===0&&(console.log(ve.red(" No agents configured. Run: agentx agent add")),process.exit(1));let r=e.agent;r||(r=(await Br({type:"select",name:"agent",message:"Default agent for incoming messages:",choices:i.map(g=>({title:g,value:g})),initial:0})).agent),r||(console.log(ve.red(" Aborted")),process.exit(1));let a=!e.skipPair;if(iw(s)&&a){let{keep:l}=await Br({type:"confirm",name:"keep",message:`An existing session was found at ${n}. Keep it (recommended), or pair again?`,initial:!0});a=!l,l&&console.log(ve.dim(" Keeping existing session \u2014 skipping QR pair."))}a&&(await rw(s,g=>console.log(g))||(console.log(ve.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await ie(l=>{Ie(l,"channels.whatsapp.enabled",!0),Ie(l,"channels.whatsapp.sessionDir",n),Ie(l,"channels.whatsapp.defaultAgent",r)},{configPath:e.configPath});c.success||(console.log(ve.red(` \u2717 ${c.error}`)),process.exit(1)),console.log(),console.log(ve.green(` \u2713 WhatsApp bound to agent "${r}"`)),console.log(ve.dim(` Session: ${n}`)),console.log(ve.dim(" Start the daemon to begin receiving:")),console.log(ve.dim(" agentx daemon start")),console.log(ve.dim(" Add routes later with:")),console.log(ve.dim(` agentx config set channels.whatsapp.routes '[{"contact":"+1234567890","agent":"${r}"}]'`)),console.log()}import{randomBytes as aw}from"crypto";import je from"chalk";import hm from"prompts";var si="agentx-mesh:",ii="//join/";function cw(e){return Buffer.from(e,"utf-8").toString("base64url")}function lw(e){return Buffer.from(e,"base64url").toString("utf-8")}function dw(e){return`${si}${ii}${cw(JSON.stringify(e))}`}function gw(e){if(!e.startsWith(`${si}${ii}`))throw new Error(`Not a mesh invite link \u2014 expected ${si}${ii}\u2026`);let o=e.slice(si.length+ii.length),t=JSON.parse(lw(o));if(t.version!==1)throw new Error(`Unsupported invite version: ${t.version}`);if(typeof t.url!="string"||typeof t.token!="string"||typeof t.name!="string")throw new Error("Invite payload missing required fields (url, token, name)");return t}function mw(){return aw(32).toString("hex")}function pw(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function uw(e){return e?.node?.name||e?.node?.id||"node"}async function ym(e){let{readFileSync:o,existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=e.configPath||n(process.cwd(),"agentx.json");t(s)||(console.log(je.red(` No agentx.json at ${s}. Run: agentx init`)),process.exit(1));let i=JSON.parse(o(s,"utf-8")),r=Wr("MESH_TOKEN");r||(r=mw(),Hn("MESH_TOKEN",r),console.log(je.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||pw(i);if((a.includes("0.0.0.0")||a.includes("127.0.0.1")||a.includes("localhost"))&&!e.url){let{url:d}=await hm({type:"text",name:"url",message:"This node's URL as peers should reach it (e.g. http://100.x.x.x:18800):",initial:a,validate:u=>/^https?:\/\//.test(u)||"must start with http:// or https://"});d||(console.log(je.red(" Aborted")),process.exit(1)),a=d}let l=await ie(d=>{Ie(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(je.red(` \u2717 ${l.error}`)),process.exit(1));let g=dw({url:a,token:r,name:uw(i),version:1});console.log(),console.log(je.bold(" Mesh invite")),console.log(),console.log(` ${je.cyan(g)}`),console.log(),console.log(je.dim(" Run on the other node:")),console.log(je.dim(` agentx connect mesh join "${g}"`)),console.log(),console.log(je.yellow(" Share over a trusted channel only \u2014 whoever holds this link can join your mesh.")),console.log()}async function wm(e,o={}){let t;try{t=gw(e)}catch(i){console.log(je.red(` \u2717 ${i.message}`)),process.exit(1)}let n=Wr("MESH_TOKEN");if(n&&n!==t.token){let{overwrite:i}=await hm({type:"confirm",name:"overwrite",message:"A different MESH_TOKEN already exists in .env. Overwrite with the invite's token?",initial:!1});i||(console.log(je.red(" Aborted (keeping existing .env)")),process.exit(1))}Hn("MESH_TOKEN",t.token);let s=await ie(i=>{Ie(i,"mesh.enabled",!0);let r=Ot(i,"mesh.peers")||[],a=r.findIndex(l=>l.name===t.name),c={name:t.name,url:t.url,token:"${MESH_TOKEN}"};a>=0?r[a]=c:r.push(c),Ie(i,"mesh.peers",r)},{configPath:o.configPath});s.success||(console.log(je.red(` \u2717 ${s.error}`)),process.exit(1)),console.log(je.green(" \u2713 Joined mesh")),console.log(je.dim(` Peer: ${t.name} @ ${t.url}`)),console.log(je.dim(" Shared token stored in .env as MESH_TOKEN")),s.reloaded?console.log(je.dim(" Daemon hot-reloaded.")):console.log(je.dim(" Restart the daemon to start the mesh (agentx daemon start).")),console.log();try{let i=await fetch(`${t.url.replace(/\/$/,"")}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)});if(i.ok){let r=await i.json(),a=Array.isArray(r.agents)?r.agents.length:"?";console.log(je.dim(` Reachable \u2014 ${t.name} exposes ${a} agents`))}else console.log(je.yellow(` Peer returned HTTP ${i.status} \u2014 double-check the URL`))}catch(i){console.log(je.yellow(` Could not reach ${t.url} right now (${i?.cause?.code||i.message}) \u2014 verify VPN / Tailscale when the peer daemon is up`))}}var on=new fw().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");on.command("telegram").description("pair a Telegram bot \u2014 persists token in .env, binds to an agent, auto-detects default chat").option("--agent <id>","agent to bind the bot to (skips the prompt)").option("--account <name>","account label in channels.telegram.accounts (defaults to agent id)").option("--skip-chat-capture","don't listen for the first message after pairing").option("-c, --config <path>","path to agentx.json").action(async e=>{await pm({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});on.command("whatsapp").description("pair WhatsApp via QR (prints in terminal), then writes channels.whatsapp config").option("--agent <id>","default agent for inbound messages").option("--session-dir <path>","session directory (default: .agentx/whatsapp-sessions)").option("--skip-pair","skip QR pairing (use when session already exists)").option("-c, --config <path>","path to agentx.json").action(async e=>{await fm({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var $m=on.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");$m.command("invite").description("emit a single-use join link for another AgentX node").option("--url <url>","this node's URL as peers should reach it (Tailscale IP etc.)").option("-c, --config <path>","path to agentx.json").action(async e=>{await ym({url:e.url,configPath:e.config})});$m.command("join <link>").description("accept an invite link from another AgentX node").option("-c, --config <path>","path to agentx.json").action(async(e,o)=>{await wm(e,{configPath:o.config})});on.action(()=>{console.log(),console.log(en.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${en.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${en.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${en.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${en.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(en.dim(" GitLab connect is the next slice.")),console.log()});oe();import{Command as hw}from"commander";import ye from"chalk";var zn=new hw().name("usage").description("token usage analysis and reporting");zn.command("today",{isDefault:!0}).description("show today's token usage").action(async()=>{try{let e=T(),[o,t]=e.node.bind.split(":"),s=await(await fetch(`http://${o||"127.0.0.1"}:${t}/usage`,{signal:AbortSignal.timeout(3e3)})).json();if(console.log(),console.log(ye.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(ye.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${ye.bold(i(s.totalTokens))} tokens across ${s.totalTasks} tasks`),console.log(` Input: ${i(s.totalInput)}`),console.log(` Output: ${i(s.totalOutput)}`),console.log(` Cache read: ${i(s.totalCacheRead)}`),console.log(` Cache create: ${i(s.totalCacheCreate)}`),s.cacheHitRatio>0&&console.log(` Cache hit: ${(s.cacheHitRatio*100).toFixed(1)}%`),s.totalErrors>0&&console.log(` Errors: ${ye.red(String(s.totalErrors))}`),console.log(),console.log(ye.bold(" By Agent:"));let r=Object.entries(s.byAgent||{});r.sort((a,c)=>c[1].total-a[1].total);for(let[a,c]of r){let l=i(c.total||c.input+c.output+c.cacheRead+c.cacheCreate),g=c.avgDuration?`${(c.avgDuration/1e3).toFixed(1)}s avg`:"";console.log(` ${ye.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${ye.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(ye.red(" Daemon not running. Start with: agentx daemon start")):console.log(ye.red(` ${e.message}`))}});zn.command("report").description("run full session analysis (parses Claude Code JSONL files)").option("--days <n>","analyze last N days","7").action(async e=>{let{execSync:o}=await import("child_process"),{existsSync:t}=await import("fs"),{resolve:n}=await import("path"),s=n(process.cwd(),"scripts/token-report.py");if(!t(s)){console.log(ye.red(` Script not found: ${s}`)),console.log(ye.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(ye.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(ye.red(" Analysis failed. Is Python 3 installed?"))}});zn.command("surfaces").description("which CLI commands and dashboard pages are actually used").option("--days <n>","window in days","30").option("--kind <kind>","cli | page (default: both)").option("--unused","list registered surfaces with ZERO recorded use instead").option("--json","raw JSON output").action(async e=>{let{listSurfaceUse:o}=await import("./surface-usage-O5L4KLGS.js"),t=e.kind==="cli"||e.kind==="page"?e.kind:void 0,n=o({kind:t,sinceDays:Number(e.days)||30});if(e.unused){let{buildProgram:i}=await import("./program-QKXRASTV.js"),r=await i(),a=new Set(n.filter(d=>d.kind==="cli").map(d=>d.name)),c=[],l=(d,u)=>{for(let f of d.commands??[]){let p=u?`${u} ${f.name()}`:f.name();c.push(p),l(f,p)}};l(r,"");let g=c.filter(d=>!a.has(d)).sort();if(e.json){console.log(JSON.stringify({windowDays:Number(e.days)||30,unused:g},null,2));return}console.log(),console.log(ye.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${ye.dim("\xB7")} ${d}`);console.log(),console.log(ye.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(ye.dim(" it must also fail the impact test. See docs/architecture/surface-reduction.md")),console.log();return}if(e.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(),console.log(ye.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(ye.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(ye.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(ye.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=ye.dim(`${i.days}d`);console.log(` ${ye.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(ye.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as yw}from"commander";import xe from"chalk";import{readFileSync as ww}from"fs";import{resolve as $w}from"path";oe();var Qo=new yw().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");Qo.command("serve",{isDefault:!0}).description("start the dashboard server (live view always; boards if configured)").option("--port <n>","override dashboard.port").option("--bind <host>","override dashboard.bind (e.g. 0.0.0.0)").action(async e=>{try{try{Ma($w(process.cwd(),".env"))}catch{}let o=bw(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-GL6GQ32D.js");t(o)}catch(o){console.log(xe.red(` ${o.message}`)),process.env.DEBUG&&o.stack&&console.log(xe.dim(o.stack)),process.exit(1)}});function bw(e,o){try{let t=T();return e&&(t.dashboard.port=parseInt(e,10)),o&&(t.dashboard.bind=o),t}catch{return console.log(xe.yellow(" No agentx.json found \u2014 starting dashboard in setup-only mode.")),console.log(xe.dim(" Visit http://127.0.0.1:"+(e||"4202")+` to run the wizard.
452
452
  `)),{node:{id:"setup",name:"Setup",bind:"127.0.0.1:18800"},providers:{},agents:{},channels:{},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},boards:[],dashboard:{enabled:!0,port:e?parseInt(e,10):4202,bind:o||"127.0.0.1",daemonUrl:"http://localhost:18800",daemons:[]},business:void 0,session:{staleMinutes:120}}}}Qo.command("list").description("list configured boards").action(()=>{try{let e=T();if(!e.boards?.length){console.log(xe.dim(`
453
453
  No boards configured.
454
454
  `));return}console.log();for(let o of e.boards){console.log(` ${xe.cyan(o.id)} \u2014 ${o.name}`);let t=o.source;console.log(xe.dim(` source: ${t.type}${t.projects?" ("+t.projects.join(", ")+")":""}`)),o.primaryToolLabel&&console.log(xe.dim(` primary label: ${o.primaryToolLabel}`)),console.log(xe.dim(` window: ${o.timeRangeDays} days`))}console.log()}catch(e){console.log(xe.red(` ${e.message}`)),process.exit(1)}});Qo.command("add <id>").description("add a GitLab board to agentx.json").requiredOption("--name <name>","human-readable board name").requiredOption("--projects <paths>","comma-separated GitLab project paths (e.g. 'globex/system,globex/website')").option("--label <label>","primary tool label ANDed into every query (e.g. 'Tool::Claude')").option("--days <n>","open-window time range in days","30").option("--closed-days <n>","closed-window in days","30").action((e,o)=>{try{Yn(t=>{if(Array.isArray(t.boards)||(t.boards=[]),t.boards.find(i=>i.id===e))throw new Error(`board "${e}" already exists`);let n=String(o.projects).split(",").map(i=>i.trim()).filter(Boolean);if(n.length===0)throw new Error("--projects must include at least one path");let s={id:e,name:o.name,source:{type:"gitlab",projects:n},timeRangeDays:parseInt(o.days,10)||30,closedWindowDays:parseInt(o.closedDays,10)||30};return o.label&&(s.primaryToolLabel=o.label),t.boards.push(s),`added board "${e}" (${n.join(", ")})`})}catch(t){console.log(xe.red(` ${t.message}`)),process.exit(1)}});Qo.command("edit <id>").description("edit board fields without re-creating it").option("--name <name>","rename").option("--projects <paths>","comma-separated GitLab project paths (replaces the list)").option("--label <label>","primary tool label (set to '-' to clear)").option("--days <n>","open-window time range in days").option("--closed-days <n>","closed-window in days").action((e,o)=>{try{Yn(t=>{let s=(Array.isArray(t.boards)?t.boards:[]).find(r=>r.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=[];if(o.name&&(s.name=o.name,i.push(`name="${o.name}"`)),o.projects){let r=String(o.projects).split(",").map(a=>a.trim()).filter(Boolean);if(r.length===0)throw new Error("--projects must include at least one path");s.source={...s.source||{type:"gitlab"},type:"gitlab",projects:r},i.push(`projects=${r.length}`)}if(o.label!==void 0&&(o.label==="-"?(delete s.primaryToolLabel,i.push("label cleared")):(s.primaryToolLabel=o.label,i.push(`label="${o.label}"`))),o.days&&(s.timeRangeDays=parseInt(o.days,10)||s.timeRangeDays,i.push(`days=${s.timeRangeDays}`)),o.closedDays&&(s.closedWindowDays=parseInt(o.closedDays,10)||s.closedWindowDays,i.push(`closed-days=${s.closedWindowDays}`)),i.length===0)throw new Error("no changes \u2014 pass at least one option");return`board "${e}" updated (${i.join(", ")})`})}catch(t){console.log(xe.red(` ${t.message}`)),process.exit(1)}});var Gr=Qo.command("column").description("manage a board's columns (add / remove / edit / list)");Gr.command("list <boardId>").description("list columns on a board, in order").action(e=>{try{let t=(JSON.parse(ww("agentx.json","utf-8")).boards||[]).find(s=>s.id===e);if(!t)throw new Error(`board "${e}" not found`);let n=t.columns||[];if(n.length===0){console.log(xe.dim(" no columns (board falls back to GitLab default flow)"));return}for(let s of n){let i=s.kind==="scoped-label"?`scoped="${s.scopedLabel}"`:s.kind==="label"?`label="${s.mapsToLabel||""}"`:s.kind==="open-backlog"?`prefix="${s.scopedPrefix}"`:s.kind;console.log(` ${xe.cyan(s.id.padEnd(12))} ${s.title.padEnd(14)} ${xe.dim(i)}`)}}catch(o){console.log(xe.red(` ${o.message}`)),process.exit(1)}});Gr.command("add <boardId> <columnId>").description("add a column to a board").requiredOption("--title <title>","column title").option("--kind <kind>","open-backlog | scoped-label | closed | label","scoped-label").option("--scoped <label>","for kind=scoped-label, the full label (e.g. 'Status::Doing')").option("--label <label>","for kind=label, the label name to add/remove").option("--scoped-prefix <prefix>","for kind=open-backlog/scoped-label","Status").option("--accent <color>","hex/CSS color for the column accent bar").action((e,o,t)=>{try{Yn(n=>{let i=(Array.isArray(n.boards)?n.boards:[]).find(a=>a.id===e);if(!i)throw new Error(`board "${e}" not found`);if(i.columns=i.columns||[],i.columns.find(a=>a.id===o))throw new Error(`column "${o}" already exists on board "${e}"`);let r={id:o,title:t.title,kind:t.kind,scopedPrefix:t.scopedPrefix};if(t.kind==="scoped-label"){if(!t.scoped)throw new Error("--scoped required for kind=scoped-label");r.scopedLabel=t.scoped}if(t.kind==="label"){if(!t.label)throw new Error("--label required for kind=label");r.mapsToLabel=t.label}return t.accent&&(r.accent=t.accent),i.columns.push(r),`column "${o}" added to board "${e}"`})}catch(n){console.log(xe.red(` ${n.message}`)),process.exit(1)}});Gr.command("remove <boardId> <columnId>").alias("rm").description("remove a column from a board").action((e,o)=>{try{Yn(t=>{let s=(Array.isArray(t.boards)?t.boards:[]).find(r=>r.id===e);if(!s)throw new Error(`board "${e}" not found`);let i=(s.columns||[]).length;if(s.columns=(s.columns||[]).filter(r=>r.id!==o),s.columns.length===i)throw new Error(`column "${o}" not found`);return`column "${o}" removed from board "${e}"`})}catch(t){console.log(xe.red(` ${t.message}`)),process.exit(1)}});Qo.command("remove <id>").alias("rm").description("remove a board from agentx.json").action(e=>{try{Yn(o=>{if(!Array.isArray(o.boards)||o.boards.length===0)throw new Error("no boards configured");let t=o.boards.length;if(o.boards=o.boards.filter(n=>n.id!==e),o.boards.length===t)throw new Error(`board "${e}" not found`);return`removed board "${e}"`})}catch(o){console.log(xe.red(` ${o.message}`)),process.exit(1)}});function Yn(e){let{summary:o,backupPath:t}=to(n=>e(n));console.log(xe.green(`
@@ -675,7 +675,7 @@ Restart the daemon to activate.
675
675
  dist/
676
676
  *.log
677
677
  .env
678
- `}import{Command as gb}from"commander";import Pe from"chalk";import{writeFileSync as mb,mkdirSync as pb,existsSync as vi,readFileSync as fp,appendFileSync as hp}from"fs";import{resolve as fn,dirname as $p}from"path";import{homedir as ua}from"os";var bp=new gb().name("completion").description("generate a shell completion script for agentx").option("-s, --shell <shell>","shell to generate completion for: zsh|bash|fish","zsh").option("-i, --install","install the completion script to a default path for the shell").option("-o, --output <path>","write the script to this path (overrides default install path)").option("-y, --yes","skip confirmation prompts (non-interactive)").action(async e=>{let{buildProgram:o}=await import("./program-KGILRYLG.js"),t=await o(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=hb(t);break;case"bash":s=kb(t);break;case"fish":s=vb(t);break;default:console.error(Pe.red(`unsupported shell: ${n}`)),console.error(Pe.dim("supported: zsh, bash, fish")),process.exit(1)}if(!e.install&&!e.output){process.stdout.write(s);return}let i=e.output?fn(String(e.output)):ub(n);pb($p(i),{recursive:!0}),mb(i,s),console.log(Pe.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${i}`),console.log(),fb(n,i,!!e.yes)});function ub(e){let o=ua();switch(e){case"zsh":return fn(o,".zsh","completions","_agentx");case"bash":return fn(o,".bash_completion.d","agentx.bash");case"fish":return fn(o,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function fb(e,o,t){if(e==="zsh"){let n=fn(ua(),".zshrc"),s=$p(o),i=`fpath=(${s} $fpath)`,r="autoload -U compinit && compinit",a=vi(n)?fp(n,"utf-8"):"",c=!a.includes(s),l=!/autoload\s+-U\s+compinit/.test(a);if(!c&&!l){console.log(Pe.dim("~/.zshrc already has fpath + compinit wired up. Run `exec zsh` to pick up the new script."));return}if(t&&vi(n)){let g=["","# agentx completion"];c&&g.push(i),l&&g.push(r),hp(n,g.join(`
678
+ `}import{Command as gb}from"commander";import Pe from"chalk";import{writeFileSync as mb,mkdirSync as pb,existsSync as vi,readFileSync as fp,appendFileSync as hp}from"fs";import{resolve as fn,dirname as $p}from"path";import{homedir as ua}from"os";var bp=new gb().name("completion").description("generate a shell completion script for agentx").option("-s, --shell <shell>","shell to generate completion for: zsh|bash|fish","zsh").option("-i, --install","install the completion script to a default path for the shell").option("-o, --output <path>","write the script to this path (overrides default install path)").option("-y, --yes","skip confirmation prompts (non-interactive)").action(async e=>{let{buildProgram:o}=await import("./program-QKXRASTV.js"),t=await o(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=hb(t);break;case"bash":s=kb(t);break;case"fish":s=vb(t);break;default:console.error(Pe.red(`unsupported shell: ${n}`)),console.error(Pe.dim("supported: zsh, bash, fish")),process.exit(1)}if(!e.install&&!e.output){process.stdout.write(s);return}let i=e.output?fn(String(e.output)):ub(n);pb($p(i),{recursive:!0}),mb(i,s),console.log(Pe.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${i}`),console.log(),fb(n,i,!!e.yes)});function ub(e){let o=ua();switch(e){case"zsh":return fn(o,".zsh","completions","_agentx");case"bash":return fn(o,".bash_completion.d","agentx.bash");case"fish":return fn(o,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function fb(e,o,t){if(e==="zsh"){let n=fn(ua(),".zshrc"),s=$p(o),i=`fpath=(${s} $fpath)`,r="autoload -U compinit && compinit",a=vi(n)?fp(n,"utf-8"):"",c=!a.includes(s),l=!/autoload\s+-U\s+compinit/.test(a);if(!c&&!l){console.log(Pe.dim("~/.zshrc already has fpath + compinit wired up. Run `exec zsh` to pick up the new script."));return}if(t&&vi(n)){let g=["","# agentx completion"];c&&g.push(i),l&&g.push(r),hp(n,g.join(`
679
679
  `)+`
680
680
  `),console.log(Pe.green("\u2713 Patched ~/.zshrc")),console.log(Pe.dim("Reload your shell: exec zsh"));return}console.log(Pe.dim("Add this to ~/.zshrc if not already present:")),c&&console.log(Pe.cyan(` ${i}`)),l&&console.log(Pe.cyan(` ${r}`)),console.log(),console.log(Pe.dim("Then reload: exec zsh")),console.log(Pe.dim("Or rerun with --yes to auto-patch ~/.zshrc"));return}if(e==="bash"){let n=fn(ua(),".bashrc"),s=`[ -f "${o}" ] && source "${o}"`;if((vi(n)?fp(n,"utf-8"):"").includes(o)){console.log(Pe.dim("~/.bashrc already sources this file. Start a new shell to pick it up."));return}if(t&&vi(n)){hp(n,`
681
681
  # agentx completion
@@ -691,4 +691,4 @@ ${xb({...o,category:e.category})}`),g&&a.set(l.id,g)}let c=`https://github.com/$
691
691
  ${t.url}`)}catch(o){console.error(yn.red(` ${o.message}`)),process.exitCode=1}});is.command("draft <file>").description("turn a draft JSON file ({category, title, fields}) into a pre-filled issue form link; '-' reads stdin").requiredOption("--model <model>","the model that wrote the draft").option("--models <pathOrUrl>","model list to read",ha).action(async(e,o)=>{try{let t=await $a(o.models);if(!ya(o.model,t)){console.log(wa(o.model,t)),process.exitCode=1;return}let n=e==="-"?await Ab():await Eb(e,"utf8"),s=JSON.parse(n),{version:i}=await ms(),r=Sp({...s,fields:s.fields??{}},{model:o.model,version:i??"unknown"});console.log(r)}catch(t){console.error(yn.red(` ${t.message}`)),process.exitCode=1}});async function Ab(){let e=[];for await(let o of process.stdin)e.push(o);return Buffer.concat(e).toString("utf8")}async function GC(){let e=await ms(),o=new Tb().name("agentx").description("self-hosted multi-agent orchestrator \u2014 Telegram, WhatsApp, crons, A2A mesh, wiki knowledge").version(e.version||"1.0.0","-v, --version","display the version number");o.hook("preAction",(t,n)=>{let s=Jl(n);Hl(s)&&Bl("cli",s)});for(let t of[yd,hd,on,Dt,Lt,ro,Rl,at,Ps,Co,No,Qt,lm,Xo,Ds,zm,Yo,Ld,zd,Un,sg,cg,gg,ug,fg,Ng,Pg,Mg,Yt,zn,Qm,Nn,Bo,bp,is])o.addCommand(t);for(let t of Ap)o.addCommand(t,{hidden:!0});return o.addHelpText("after",()=>{let t=Ap.map(n=>n.name()).sort();return["",`Advanced (${t.length}, hidden \u2014 run \`agentx <command> --help\` for any of them):`,jb(t,74," "),""].join(`
692
692
  `)}),o}var Ap=[te,sn,ot,$o,Dn,Vt,Ke,_o,Qo,ft,ln,dn,Go,Ge,Wt,oi,Jm,Hm,Oo,no,Kl,lt,ns,mr,et,Ze,Ut,pr,fi,Ao,Do,cp,dp,Xm];function jb(e,o,t){let n=[],s="";for(let i of e)s&&s.length+i.length+2>o&&(n.push(t+s),s=""),s+=(s?", ":"")+i;return s&&n.push(t+s),n.join(`
693
693
  `)}export{GC as buildProgram};
694
- //# sourceMappingURL=program-KGILRYLG.js.map
694
+ //# sourceMappingURL=program-QKXRASTV.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentix-cli",
3
- "version": "0.87.0",
3
+ "version": "0.89.0",
4
4
  "description": "AI operations layer for small and medium businesses. Routes Telegram, WhatsApp, GitLab, GitHub, crons, webhooks, and mesh tasks to AI agents. Web wizard for operators, CLI for engineers. Self-hosted.",
5
5
  "license": "MIT",
6
6
  "author": {