agentix-cli 0.111.0 → 0.111.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ import{e as x,g as A}from"./chunk-JIT5GPTX.js";import{a as w,e as D}from"./chunk-2QNT5JDS.js";D();var h="guest:",b="guests",P=7,y=365,T=400;function I(e){let t=e.scopes.find(n=>n.startsWith(h));return t?t.slice(h.length):null}function _(e){return`g-${e.toString(36)}-${Math.random().toString(36).slice(2,6)}`}var l=e=>(Array.isArray(e)?e:typeof e=="string"?e.split(","):[]).map(t=>String(t).trim()).filter(Boolean).slice(0,50);function M(e,t){let n=(e.now??Date.now)(),o=String(t.name??"").trim().slice(0,120),s=String(t.guest??"").trim().slice(0,80);if(!o)return{ok:!1,error:'name is required: what you call this grant, e.g. "Support session for company X"'};if(!s)return{ok:!1,error:"guest is required: the other organisation's name"};if(!t.agentId||!e.hasAgent(t.agentId))return{ok:!1,error:`agent must be an agent on this node, got "${t.agentId??""}"`};let a=w.safeParse(t.level??"propose");if(!a.success)return{ok:!1,error:"level must be report, propose or act"};let r=t.days===void 0?P:Number(t.days);if(!Number.isFinite(r)||r<1||r>y)return{ok:!1,error:`days must be between 1 and ${y}`};let d=_(n),{token:u,record:g}=e.tokens.create({name:`guest ${s} (${o})`,scopes:[`${h}${d}`],expiresInDays:Math.ceil(r)}),{code:i,expiresAt:p}=e.codes.create({token:u,tokenId:g.id,name:d}),c={id:d,name:o,guest:s,agentId:t.agentId,folders:l(t.folders),skills:l(t.skills),commands:l(t.commands),level:a.data,state:"pending",tokenId:g.id,createdAt:new Date(n).toISOString(),expiresAt:new Date(n+r*864e5).toISOString(),usage:{turns:0,tokens:0}};return e.guests.add(c),e.guests.log({grant:d,event:"invited",detail:`${s}: ${o}`}),{ok:!0,code:i,codeExpiresAt:p,grant:c}}var j="That code didn't work. Ask the host for a new one.";async function Y(e,t,n){let o=Date.now(),s=n.now??Date.now,a=n.log??(f=>console.log(f)),r=n.limiter.retryAfter(t);if(r>0)return a(`[guests] join refused from ${t}: locked out for ${r}s more`),{status:429,body:{error:"too many attempts",retryAfter:r},retryAfter:r};let d=n.codes.redeem(e.code),u=d?n.tokens.verify(d.token):null,g=u?I(u):null,i=g?n.guests.get(g):null;if(await L(o,n.minMs??T),!d||!u||!i||i.tokenId!==u.id||i.state==="ended")return n.limiter.fail(t),a(`[guests] join failed from ${t}`),{status:401,body:{error:j}};n.limiter.succeed(t);let p=e.node&&typeof e.node=="object"?e.node:{},c=(f,S)=>typeof f=="string"&&f.trim()?f.replace(/\s+/g," ").trim().slice(0,S):void 0,m={id:c(p.id,80),name:c(p.name,80),address:t},$=i.expiresAt.slice(0,10),k=A(n.root,{title:`Guest mesh: ${i.guest} wants to join`,ask:`Let "${m.name??m.id??"a node"}" at ${t} use ${i.agentId} inside "${i.name}" (${i.level}, until ${$})?`,recommend:`Yes if ${i.guest} told you they are joining now. No if you did not expect it.`,if_silent:"discard",raised_by:b},{now:s()});return k.ok?(n.guests.update(i.id,{guestNode:m,cardId:k.card.id}),n.guests.log({grant:i.id,event:"joined",address:t,detail:m.name??m.id}),a(`[guests] ${i.id}: ${i.guest} joined from ${t}; waiting for the owner (card ${k.card.id})`),{status:200,body:{grant:i.id,name:i.name,agentId:i.agentId,level:i.level,expiresAt:i.expiresAt,state:"pending"},token:d.token}):(a(`[guests] ${i.id}: join from ${t} could not raise a card: ${k.error}`),{status:403,body:{error:"The host cannot take a join right now. Try again later."}})}var G="no grant opens this",R="waiting for the host to approve the join",O="the host paused this grant";function N(e,t){let n=e.now??Date.now,o=e.log??(r=>console.log(r));if(t.state==="ended")return t;if(Date.parse(t.expiresAt)<=n())return o(`[guests] ${t.id}: expired`),v({tokens:e.tokens,guests:e.guests,now:n},t.id,"expired")??t;if(t.state!=="pending")return t;let s=t.cardId?x(e.root,t.cardId):null,a=s?s.status==="decided"?s.verdict:s.status==="expired"?"no":null:null;if(a==="yes"){let r=e.guests.update(t.id,{state:"active",approvedAt:new Date(n()).toISOString()})??t;return e.guests.log({grant:t.id,event:"approved",detail:s?.decided_by}),o(`[guests] ${t.id}: join approved`),r}if(a==="no"){let r=s?.status==="expired"?"the host did not answer in time":"the host said no",d=v({tokens:e.tokens,guests:e.guests,now:n},t.id,r)??t;return e.guests.log({grant:t.id,event:"refused",detail:r}),o(`[guests] ${t.id}: join refused: ${r}`),d}return t}function J(e,t){let n=e?t.tokens.verify(e):null,o=n?I(n):null,s=o?t.guests.get(o):null;if(!n||!s||s.tokenId!==n.id)return{ok:!1,status:401,error:G};let a=N(t,s);return a.state==="ended"?{ok:!1,status:401,error:G}:a.state==="pending"?{ok:!1,status:403,error:R,waiting:!0}:a.state==="paused"?{ok:!1,status:403,error:O,paused:!0}:{ok:!0,grant:a}}function C(e){let t=(o,s)=>o.length?o.join(", "):`none named: do not touch ${s} unless the owner's own instructions already allow it for this work`,n=e.level==="report"?"report: read and answer only; change nothing":e.level==="propose"?"propose: you may prepare changes and open a merge request or draft; never merge, deploy or delete":"act: you may act inside the grant without asking";return[`[Guest mesh] You are working for a guest organisation, "${e.guest}", under the grant "${e.name}" that the owner of this node opened.`,`Stay inside it. Folders: ${t(e.folders,"files")}. Skills: ${t(e.skills,"skills")}. Commands: ${t(e.commands,"commands")}. Freedom: ${n}. The grant ends on ${e.expiresAt.slice(0,10)}.`,"Anything outside the grant: say it is not covered and stop. The guest sees only your answers: never reveal other chats, agents, people or files of this node."].join(`
2
+ `)}function q(e,t){return{agentId:e.agentId,message:t,context:{channel:"guest",chatId:`guest:${e.id}`,sender:`guest:${e.guest}`},systemPromptAppend:C(e),...e.level==="act"?{}:{autonomy:e.level}}}function B(e,t){let n=e.guests.get(t);if(!n||n.state!=="active")return null;let o=e.guests.update(t,{state:"paused",pausedAt:new Date((e.now??Date.now)()).toISOString()});return e.guests.log({grant:t,event:"paused"}),o}function U(e,t){let n=e.guests.get(t);if(!n||n.state!=="paused")return null;let o=e.guests.update(t,{state:"active",pausedAt:void 0});return e.guests.log({grant:t,event:"resumed"}),o}function v(e,t,n="ended by the host"){let o=e.guests.get(t);if(!o||o.state==="ended")return null;e.tokens.revoke(o.tokenId);let s=e.guests.update(t,{state:"ended",endedAt:new Date((e.now??Date.now)()).toISOString(),endedReason:n});return e.guests.log({grant:t,event:n==="expired"?"expired":"ended",detail:n}),s}function X(e,t,n){let o=e.guests.get(t);if(!o||o.state==="ended")return{ok:!1,error:`no open grant "${t}"`};let s={};if(n.folders!==void 0&&(s.folders=l(n.folders)),n.skills!==void 0&&(s.skills=l(n.skills)),n.commands!==void 0&&(s.commands=l(n.commands)),n.level!==void 0){let u=w.safeParse(n.level);if(!u.success)return{ok:!1,error:"level must be report, propose or act"};s.level=u.data}if(n.days!==void 0){let u=Number(n.days);if(!Number.isFinite(u)||u<1||u>y)return{ok:!1,error:`days must be between 1 and ${y}`};s.expiresAt=new Date((e.now??Date.now)()+u*864e5).toISOString()}let a=e.guests.update(t,s),r=["report","propose","act"],d=s.level&&r.indexOf(s.level)>r.indexOf(o.level)||s.folders&&s.folders.length>o.folders.length||s.skills&&s.skills.length>o.skills.length||s.commands&&s.commands.length>o.commands.length||s.expiresAt&&s.expiresAt>o.expiresAt;return e.guests.log({grant:t,event:d?"widened":"narrowed",detail:Object.keys(s).join(", ")}),{ok:!0,grant:a}}function W(e){return{grant:e.id,name:e.name,agentId:e.agentId,level:e.level,folders:e.folders,skills:e.skills,commands:e.commands,state:e.state,expiresAt:e.expiresAt,usage:e.usage}}async function L(e,t){let n=e+t-Date.now();n>0&&await new Promise(o=>setTimeout(o,n))}export{h as a,b,P as c,y as d,I as e,_ as f,M as g,j as h,Y as i,G as j,R as k,O as l,N as m,J as n,C as o,q as p,B as q,U as r,v as s,X as t,W as u};
3
+ //# sourceMappingURL=chunk-QLWGLRT5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/guests/grants.ts"],"sourcesContent":["import { TokenStore, type TokenRecord } from \"@/daemon/token-store\"\nimport { PairCodeStore } from \"@/daemon/pair-codes\"\nimport type { PairAttemptLimiter } from \"@/daemon/app-pair-code\"\nimport { createCard, readCard } from \"@/approvals/cards\"\nimport { autonomyLevelSchema, type AutonomyLevel } from \"@/guard/autonomy\"\nimport { GuestStore, type GuestGrant } from \"./store\"\n\n// --- Opening part of a mesh to a guest, and keeping it in hand (#380) ---\n//\n// Two roles. The host opens a grant: one of its agents, named folders,\n// skills and commands, a freedom level and an end date. The guest is the\n// other organisation's mesh. Access goes one way per grant.\n//\n// The guest asks, the host's agent acts. The guest never gets a shell or\n// a session on the host's machine: its messages run as turns of the host\n// agent, under the host's rules and in the host's log, with the routine\n// autonomy levels of #80 enforced on the run (report: read-only;\n// propose: no merge, deploy or delete; act: inside the grant, no question\n// asked). What the grant names is put in front of the agent on every turn.\n//\n// Joining is a one-time code, like phone pairing; the join arrives as a\n// decision card in the host's Approvals inbox. No yes, no join. The host\n// can pause, widen, narrow or end the grant while it is in use.\n\nexport const GUEST_SCOPE_PREFIX = \"guest:\"\n/** Who the join card is raised by: not an agent, so no agent is told the\n * verdict; the guest routes read it instead. */\nexport const JOIN_CARD_BY = \"guests\"\nexport const DEFAULT_GRANT_DAYS = 7\nexport const MAX_GRANT_DAYS = 365\nconst MIN_MS = 400\n\nexport interface GrantInput {\n name: string\n guest: string\n agentId: string\n folders?: string[]\n skills?: string[]\n commands?: string[]\n level?: string\n days?: number\n}\n\nexport interface GuestDeps {\n tokens: TokenStore\n codes: PairCodeStore\n guests: GuestStore\n hasAgent: (agentId: string) => boolean\n /** The install folder: where decision cards live. */\n root: string\n limiter: PairAttemptLimiter\n now?: () => number\n minMs?: number\n log?: (line: string) => void\n}\n\nexport function grantIdOf(rec: TokenRecord): string | null {\n const scope = rec.scopes.find((s) => s.startsWith(GUEST_SCOPE_PREFIX))\n return scope ? scope.slice(GUEST_SCOPE_PREFIX.length) : null\n}\n\nexport function newGrantId(now: number): string {\n return `g-${now.toString(36)}-${Math.random().toString(36).slice(2, 6)}`\n}\n\nconst list = (v: unknown): string[] =>\n (Array.isArray(v) ? v : typeof v === \"string\" ? v.split(\",\") : []).map((s) => String(s).trim()).filter(Boolean).slice(0, 50)\n\nexport type InviteResult =\n | { ok: true; code: string; codeExpiresAt: string; grant: GuestGrant }\n | { ok: false; error: string }\n\n/** Open a grant and mint the one-time code the guest joins with. */\nexport function inviteGuest(deps: Pick<GuestDeps, \"tokens\" | \"codes\" | \"guests\" | \"hasAgent\" | \"now\">, input: GrantInput): InviteResult {\n const now = (deps.now ?? Date.now)()\n const name = String(input.name ?? \"\").trim().slice(0, 120)\n const guest = String(input.guest ?? \"\").trim().slice(0, 80)\n if (!name) return { ok: false, error: \"name is required: what you call this grant, e.g. \\\"Support session for company X\\\"\" }\n if (!guest) return { ok: false, error: \"guest is required: the other organisation's name\" }\n if (!input.agentId || !deps.hasAgent(input.agentId)) return { ok: false, error: `agent must be an agent on this node, got \"${input.agentId ?? \"\"}\"` }\n const level = autonomyLevelSchema.safeParse(input.level ?? \"propose\")\n if (!level.success) return { ok: false, error: \"level must be report, propose or act\" }\n const days = input.days === undefined ? DEFAULT_GRANT_DAYS : Number(input.days)\n if (!Number.isFinite(days) || days < 1 || days > MAX_GRANT_DAYS) return { ok: false, error: `days must be between 1 and ${MAX_GRANT_DAYS}` }\n const id = newGrantId(now)\n const { token, record } = deps.tokens.create({ name: `guest ${guest} (${name})`, scopes: [`${GUEST_SCOPE_PREFIX}${id}`], expiresInDays: Math.ceil(days) })\n const { code, expiresAt: codeExpiresAt } = deps.codes.create({ token, tokenId: record.id, name: id })\n const grant: GuestGrant = {\n id, name, guest, agentId: input.agentId,\n folders: list(input.folders), skills: list(input.skills), commands: list(input.commands),\n level: level.data, state: \"pending\", tokenId: record.id,\n createdAt: new Date(now).toISOString(), expiresAt: new Date(now + days * 86_400_000).toISOString(),\n usage: { turns: 0, tokens: 0 },\n }\n deps.guests.add(grant)\n deps.guests.log({ grant: id, event: \"invited\", detail: `${guest}: ${name}` })\n return { ok: true, code, codeExpiresAt, grant }\n}\n\nexport type JoinResult =\n | { status: 200; body: { grant: string; name: string; agentId: string; level: AutonomyLevel; expiresAt: string; state: \"pending\" }; token: string }\n | { status: 401 | 403; body: { error: string } }\n | { status: 429; body: { error: string; retryAfter: number }; retryAfter: number }\n\n/** The guest runs `agentx mesh join` on their own node; \"run agentx app\n * pair\" (the phone app's PAIR_CODE_FAILED) is the host's command, not\n * theirs. Same reason as MEMBER_CODE_FAILED for teammates (#453, #643). */\nexport const JOIN_FAILED = \"That code didn't work. Ask the host for a new one.\"\n\n/** POST /mesh/guest/join: the guest trades the code for its key and asks\n * the host to approve the join. */\nexport async function joinGuest(\n body: Record<string, unknown>,\n client: string,\n deps: GuestDeps,\n): Promise<JoinResult> {\n const started = Date.now()\n const now = deps.now ?? Date.now\n const log = deps.log ?? ((line: string) => console.log(line))\n const wait = deps.limiter.retryAfter(client)\n if (wait > 0) {\n log(`[guests] join refused from ${client}: locked out for ${wait}s more`)\n return { status: 429, body: { error: \"too many attempts\", retryAfter: wait }, retryAfter: wait }\n }\n const redeemed = deps.codes.redeem(body.code)\n const rec = redeemed ? deps.tokens.verify(redeemed.token) : null\n const grantId = rec ? grantIdOf(rec) : null\n const grant = grantId ? deps.guests.get(grantId) : null\n await padTo(started, deps.minMs ?? MIN_MS)\n if (!redeemed || !rec || !grant || grant.tokenId !== rec.id || grant.state === \"ended\") {\n deps.limiter.fail(client)\n log(`[guests] join failed from ${client}`)\n return { status: 401, body: { error: JOIN_FAILED } }\n }\n deps.limiter.succeed(client)\n const node = (body.node && typeof body.node === \"object\" ? body.node : {}) as Record<string, unknown>\n const str = (v: unknown, n: number) => (typeof v === \"string\" && v.trim() ? v.replace(/\\s+/g, \" \").trim().slice(0, n) : undefined)\n const guestNode = { id: str(node.id, 80), name: str(node.name, 80), address: client }\n const until = grant.expiresAt.slice(0, 10)\n const card = createCard(deps.root, {\n title: `Guest mesh: ${grant.guest} wants to join`,\n ask: `Let \"${guestNode.name ?? guestNode.id ?? \"a node\"}\" at ${client} use ${grant.agentId} inside \"${grant.name}\" (${grant.level}, until ${until})?`,\n recommend: `Yes if ${grant.guest} told you they are joining now. No if you did not expect it.`,\n if_silent: \"discard\",\n raised_by: JOIN_CARD_BY,\n }, { now: now() })\n if (!card.ok) {\n log(`[guests] ${grant.id}: join from ${client} could not raise a card: ${card.error}`)\n return { status: 403, body: { error: \"The host cannot take a join right now. Try again later.\" } }\n }\n deps.guests.update(grant.id, { guestNode, cardId: card.card.id })\n deps.guests.log({ grant: grant.id, event: \"joined\", address: client, detail: guestNode.name ?? guestNode.id })\n log(`[guests] ${grant.id}: ${grant.guest} joined from ${client}; waiting for the owner (card ${card.card.id})`)\n return {\n status: 200,\n body: { grant: grant.id, name: grant.name, agentId: grant.agentId, level: grant.level, expiresAt: grant.expiresAt, state: \"pending\" },\n token: redeemed.token,\n }\n}\n\nexport type AccessResult =\n | { ok: true; grant: GuestGrant }\n | { ok: false; status: 401; error: string }\n | { ok: false; status: 403; error: string; waiting?: true; paused?: true }\n\nexport const NO_GRANT = \"no grant opens this\"\nexport const WAITING_HOST = \"waiting for the host to approve the join\"\nexport const PAUSED = \"the host paused this grant\"\n\ntype SettleDeps = Pick<GuestDeps, \"tokens\" | \"guests\" | \"root\" | \"now\" | \"log\">\n\n/** Applies what time and the host's card say: an expired grant ends, a\n * decided join card activates or ends the grant. Returns the grant as it\n * stands now. Both sides call this: the guest on every request, the host\n * before listing or acting, so a yes on the card counts at once. */\nexport function settleGrant(deps: SettleDeps, grant: GuestGrant): GuestGrant {\n const now = deps.now ?? Date.now\n const log = deps.log ?? ((line: string) => console.log(line))\n if (grant.state === \"ended\") return grant\n if (Date.parse(grant.expiresAt) <= now()) {\n log(`[guests] ${grant.id}: expired`)\n return endGrant({ tokens: deps.tokens, guests: deps.guests, now }, grant.id, \"expired\") ?? grant\n }\n if (grant.state !== \"pending\") return grant\n const card = grant.cardId ? readCard(deps.root, grant.cardId) : null\n const answer = !card ? null : card.status === \"decided\" ? card.verdict : card.status === \"expired\" ? \"no\" : null\n if (answer === \"yes\") {\n const out = deps.guests.update(grant.id, { state: \"active\", approvedAt: new Date(now()).toISOString() }) ?? grant\n deps.guests.log({ grant: grant.id, event: \"approved\", detail: card?.decided_by })\n log(`[guests] ${grant.id}: join approved`)\n return out\n }\n if (answer === \"no\") {\n const reason = card?.status === \"expired\" ? \"the host did not answer in time\" : \"the host said no\"\n const out = endGrant({ tokens: deps.tokens, guests: deps.guests, now }, grant.id, reason) ?? grant\n deps.guests.log({ grant: grant.id, event: \"refused\", detail: reason })\n log(`[guests] ${grant.id}: join refused: ${reason}`)\n return out\n }\n return grant\n}\n\n/** Whether `token` opens a grant right now. */\nexport function guestAccess(token: string | null, deps: SettleDeps): AccessResult {\n const rec = token ? deps.tokens.verify(token) : null\n const grantId = rec ? grantIdOf(rec) : null\n const found = grantId ? deps.guests.get(grantId) : null\n if (!rec || !found || found.tokenId !== rec.id) return { ok: false, status: 401, error: NO_GRANT }\n const grant = settleGrant(deps, found)\n if (grant.state === \"ended\") return { ok: false, status: 401, error: NO_GRANT }\n if (grant.state === \"pending\") return { ok: false, status: 403, error: WAITING_HOST, waiting: true }\n if (grant.state === \"paused\") return { ok: false, status: 403, error: PAUSED, paused: true }\n return { ok: true, grant }\n}\n\n/** What the host agent is told on every guest turn. */\nexport function grantBrief(grant: GuestGrant): string {\n const none = (xs: string[], word: string) => xs.length ? xs.join(\", \") : `none named: do not touch ${word} unless the owner's own instructions already allow it for this work`\n const level =\n grant.level === \"report\" ? \"report: read and answer only; change nothing\" :\n grant.level === \"propose\" ? \"propose: you may prepare changes and open a merge request or draft; never merge, deploy or delete\" :\n \"act: you may act inside the grant without asking\"\n return [\n `[Guest mesh] You are working for a guest organisation, \"${grant.guest}\", under the grant \"${grant.name}\" that the owner of this node opened.`,\n `Stay inside it. Folders: ${none(grant.folders, \"files\")}. Skills: ${none(grant.skills, \"skills\")}. Commands: ${none(grant.commands, \"commands\")}. Freedom: ${level}. The grant ends on ${grant.expiresAt.slice(0, 10)}.`,\n `Anything outside the grant: say it is not covered and stop. The guest sees only your answers: never reveal other chats, agents, people or files of this node.`,\n ].join(\"\\n\")\n}\n\n/** A guest's message as a turn of the host agent. */\nexport function guestTask(grant: GuestGrant, message: string): {\n agentId: string\n message: string\n context: { channel: \"guest\"; chatId: string; sender: string }\n systemPromptAppend: string\n autonomy?: AutonomyLevel\n} {\n return {\n agentId: grant.agentId,\n message,\n context: { channel: \"guest\", chatId: `guest:${grant.id}`, sender: `guest:${grant.guest}` },\n systemPromptAppend: grantBrief(grant),\n ...(grant.level === \"act\" ? {} : { autonomy: grant.level }),\n }\n}\n\ntype ControlDeps = Pick<GuestDeps, \"tokens\" | \"guests\" | \"now\">\n\nexport function pauseGrant(deps: ControlDeps, id: string): GuestGrant | null {\n const grant = deps.guests.get(id)\n if (!grant || grant.state !== \"active\") return null\n const out = deps.guests.update(id, { state: \"paused\", pausedAt: new Date((deps.now ?? Date.now)()).toISOString() })\n deps.guests.log({ grant: id, event: \"paused\" })\n return out\n}\n\nexport function resumeGrant(deps: ControlDeps, id: string): GuestGrant | null {\n const grant = deps.guests.get(id)\n if (!grant || grant.state !== \"paused\") return null\n const out = deps.guests.update(id, { state: \"active\", pausedAt: undefined })\n deps.guests.log({ grant: id, event: \"resumed\" })\n return out\n}\n\n/** Ends the grant: its key stops at once. */\nexport function endGrant(deps: ControlDeps, id: string, reason = \"ended by the host\"): GuestGrant | null {\n const grant = deps.guests.get(id)\n if (!grant || grant.state === \"ended\") return null\n deps.tokens.revoke(grant.tokenId)\n const out = deps.guests.update(id, { state: \"ended\", endedAt: new Date((deps.now ?? Date.now)()).toISOString(), endedReason: reason })\n deps.guests.log({ grant: id, event: reason === \"expired\" ? \"expired\" : \"ended\", detail: reason })\n return out\n}\n\nexport interface GrantPatch { folders?: unknown; skills?: unknown; commands?: unknown; level?: unknown; days?: unknown }\n\n/** Widen or narrow a grant while it is in use. */\nexport function updateGrant(deps: ControlDeps, id: string, patch: GrantPatch): { ok: true; grant: GuestGrant } | { ok: false; error: string } {\n const grant = deps.guests.get(id)\n if (!grant || grant.state === \"ended\") return { ok: false, error: `no open grant \"${id}\"` }\n const next: Partial<GuestGrant> = {}\n if (patch.folders !== undefined) next.folders = list(patch.folders)\n if (patch.skills !== undefined) next.skills = list(patch.skills)\n if (patch.commands !== undefined) next.commands = list(patch.commands)\n if (patch.level !== undefined) {\n const level = autonomyLevelSchema.safeParse(patch.level)\n if (!level.success) return { ok: false, error: \"level must be report, propose or act\" }\n next.level = level.data\n }\n if (patch.days !== undefined) {\n const days = Number(patch.days)\n if (!Number.isFinite(days) || days < 1 || days > MAX_GRANT_DAYS) return { ok: false, error: `days must be between 1 and ${MAX_GRANT_DAYS}` }\n next.expiresAt = new Date((deps.now ?? Date.now)() + days * 86_400_000).toISOString()\n }\n const out = deps.guests.update(id, next)!\n const order: AutonomyLevel[] = [\"report\", \"propose\", \"act\"]\n const wider = (next.level && order.indexOf(next.level) > order.indexOf(grant.level))\n || (next.folders && next.folders.length > grant.folders.length)\n || (next.skills && next.skills.length > grant.skills.length)\n || (next.commands && next.commands.length > grant.commands.length)\n || (next.expiresAt && next.expiresAt > grant.expiresAt)\n deps.guests.log({ grant: id, event: wider ? \"widened\" : \"narrowed\", detail: Object.keys(next).join(\", \") })\n return { ok: true, grant: out }\n}\n\n/** What the guest may know about its grant. */\nexport function grantForGuest(grant: GuestGrant): Record<string, unknown> {\n return {\n grant: grant.id, name: grant.name, agentId: grant.agentId, level: grant.level,\n folders: grant.folders, skills: grant.skills, commands: grant.commands,\n state: grant.state, expiresAt: grant.expiresAt, usage: grant.usage,\n }\n}\n\nasync function padTo(started: number, minMs: number): Promise<void> {\n const left = started + minMs - Date.now()\n if (left > 0) await new Promise((r) => setTimeout(r, left))\n}\n"],"mappings":"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","names":["init_autonomy","GUEST_SCOPE_PREFIX","JOIN_CARD_BY","DEFAULT_GRANT_DAYS","MAX_GRANT_DAYS","MIN_MS","grantIdOf","rec","scope","s","newGrantId","now","list","v","inviteGuest","deps","input","name","guest","level","autonomyLevelSchema","days","id","token","record","code","codeExpiresAt","grant","JOIN_FAILED","joinGuest","body","client","started","log","line","wait","redeemed","grantId","padTo","node","str","n","guestNode","until","card","createCard","NO_GRANT","WAITING_HOST","PAUSED","settleGrant","endGrant","readCard","answer","out","reason","guestAccess","found","grantBrief","none","xs","word","guestTask","message","pauseGrant","resumeGrant","updateGrant","patch","next","order","wider","grantForGuest","minMs","left","r"]}
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-EZLJIVQX.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-YK3YR2CQ.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
@@ -1,2 +1,2 @@
1
- import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u}from"./chunk-XF26QNAW.js";import"./chunk-RXLU6HJ6.js";import"./chunk-Y4CYQV7G.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{c as DEFAULT_GRANT_DAYS,a as GUEST_SCOPE_PREFIX,b as JOIN_CARD_BY,h as JOIN_FAILED,d as MAX_GRANT_DAYS,j as NO_GRANT,l as PAUSED,k as WAITING_HOST,s as endGrant,o as grantBrief,u as grantForGuest,e as grantIdOf,n as guestAccess,p as guestTask,g as inviteGuest,i as joinGuest,f as newGrantId,q as pauseGrant,r as resumeGrant,m as settleGrant,t as updateGrant};
2
- //# sourceMappingURL=grants-M4K6WXOO.js.map
1
+ import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u}from"./chunk-QLWGLRT5.js";import"./chunk-JIT5GPTX.js";import"./chunk-Y4CYQV7G.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";export{c as DEFAULT_GRANT_DAYS,a as GUEST_SCOPE_PREFIX,b as JOIN_CARD_BY,h as JOIN_FAILED,d as MAX_GRANT_DAYS,j as NO_GRANT,l as PAUSED,k as WAITING_HOST,s as endGrant,o as grantBrief,u as grantForGuest,e as grantIdOf,n as guestAccess,p as guestTask,g as inviteGuest,i as joinGuest,f as newGrantId,q as pauseGrant,r as resumeGrant,m as settleGrant,t as updateGrant};
2
+ //# sourceMappingURL=grants-BRAVOGBP.js.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{a as St,b as kt,c as vt,d as xt,e as $t,f as Ct,g as Pt,h as bt,ia as Tt,ja as Mt}from"./chunk-KDD6FPQ6.js";import"./chunk-WYSNRZV4.js";import"./chunk-U52IS3AF.js";import"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import"./chunk-DG5I6PPM.js";import"./chunk-ZVP6GB4G.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import"./chunk-EKJG63EJ.js";import"./chunk-LWYKS5JU.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-ACFQBLPX.js";import"./chunk-LQE73AZR.js";import"./chunk-2D3RYIDU.js";import"./chunk-XF26QNAW.js";import"./chunk-RXLU6HJ6.js";import{ca as yt,m as lt,n as ct,o as dt,p as mt,q as pt}from"./chunk-DTQQ4DAY.js";import"./chunk-53OS4TDU.js";import"./chunk-GLQLCBJS.js";import"./chunk-6W74CHNW.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-HCTWKWS3.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-LLNPKE7H.js";import"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import"./chunk-WXQQO2PD.js";import"./chunk-GV7S5BAX.js";import"./chunk-SZDACK6O.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{s as ut}from"./chunk-M2L6S3Z5.js";import"./chunk-QJP37VVA.js";import"./chunk-VWTBHLMX.js";import"./chunk-DXWDVKMX.js";import{a as ht}from"./chunk-Z7L74GGT.js";import"./chunk-36AXN6ZB.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-GSX4NK2N.js";import"./chunk-7UNS34CN.js";import"./chunk-MYVHVJWZ.js";import"./chunk-AV7T3SYT.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-FBODSJU6.js";import{f as gt,g as ft}from"./chunk-RS2T53EC.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-GQMUFSKB.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{ga as tt,ia as st,ja as ot,la as nt}from"./chunk-SIOWVLZG.js";import"./chunk-UIBUZ2N3.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,d as xt,e as $t,f as Ct,g as Pt,h as bt,ia as Tt,ja as Mt}from"./chunk-K24MYJFP.js";import"./chunk-3RTOS727.js";import"./chunk-U52IS3AF.js";import"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import"./chunk-DG5I6PPM.js";import"./chunk-ZVP6GB4G.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import"./chunk-EKJG63EJ.js";import"./chunk-LWYKS5JU.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import"./chunk-ACFQBLPX.js";import"./chunk-LQE73AZR.js";import"./chunk-2D3RYIDU.js";import"./chunk-QLWGLRT5.js";import"./chunk-JIT5GPTX.js";import{ca as yt,m as lt,n as ct,o as dt,p as mt,q as pt}from"./chunk-DTQQ4DAY.js";import"./chunk-53OS4TDU.js";import"./chunk-GLQLCBJS.js";import"./chunk-6W74CHNW.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-HCTWKWS3.js";import{a as B,b as M,c as F}from"./chunk-SFQUP3BP.js";import"./chunk-LLNPKE7H.js";import"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import"./chunk-WXQQO2PD.js";import"./chunk-GV7S5BAX.js";import"./chunk-SZDACK6O.js";import"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{s as ut}from"./chunk-M2L6S3Z5.js";import"./chunk-QJP37VVA.js";import"./chunk-VWTBHLMX.js";import"./chunk-DXWDVKMX.js";import{a as ht}from"./chunk-Z7L74GGT.js";import"./chunk-36AXN6ZB.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-GSX4NK2N.js";import"./chunk-7UNS34CN.js";import"./chunk-MYVHVJWZ.js";import"./chunk-AV7T3SYT.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-FBODSJU6.js";import{f as gt,g as ft}from"./chunk-RS2T53EC.js";import"./chunk-WPNRDEHW.js";import"./chunk-2GIDVZ4H.js";import{j as it,k as rt,l as at}from"./chunk-GQMUFSKB.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{ga as tt,ia as st,ja as ot,la as nt}from"./chunk-SIOWVLZG.js";import"./chunk-UIBUZ2N3.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).
@@ -1,4 +1,4 @@
1
- import{a as fd,b as Ps,g as hd}from"./chunk-XEOT2F4C.js";import{a as Kl,c as Ql}from"./chunk-4NFDDTGA.js";import{A as ar,B as pd,D as ud,a as so,b as Xl,f as Ut,g as Zl,h as ed,i as od,j as td,l as nd,m as sd,n as id,o as ir,p as rd,u as ad,v as cd,w as rr,x as ld}from"./chunk-DUBCOGQB.js";import{a as dd,c as gd,d as md}from"./chunk-4FU4BFCH.js";import"./chunk-N7HKIMMR.js";import{a as Ji,b as xc}from"./chunk-RKPAVWXF.js";import{$ as _n,A as kl,B as vl,C as xl,D as Sl,E as El,F as Al,G as Tl,H as _l,I as Cs,J as Co,K as Bo,L as Mt,M as Is,N as Ns,O as Zi,P as Dl,Q as Pl,R as Ml,S as Ll,T as ql,U as Fl,V as Lt,W as qt,X as Ul,Y as Wl,Z as Le,_ as Rs,a as Ic,aa as er,b as Nc,ba as Bl,ca as Gl,da as nr,ea as Yl,fa as _s,ga as Ft,h as $s,ha as Ds,i as Pc,ia as sr,j as In,ja as Vl,k as bs,l as qc,m as Fc,n as Qc,o as Zc,p as As,q as Gi,r as il,s as ml,t as pl,u as hl,v as yl,w as wl,x as $l,y as bl,z as Yi}from"./chunk-KDD6FPQ6.js";import{$a as zl,A as Ts,C as gl,Ia as Jl,Ja as or,Ka as Hl,La as tr,R as Nn,U as Vi,V as js,W as jl,Za as vo,ba as Wo,ca as Ol,da as Xi,fa as Ki,ha as Cl,ia as Il,ja as Rn,na as Os,qa as Nl,ra as Rl,sa as Qi,w as zi,x as ll,z as dl}from"./chunk-WYSNRZV4.js";import{a as Rc,d as _c,e as Dc}from"./chunk-U52IS3AF.js";import{a as ks,b as vs,c as Uc,d as Wc,e as Bc,g as Jc,h as Hc,j as Gc,k as zc,l as Yc,m as Vc,p as xs,s as Xc,t as Kc}from"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import"./chunk-DG5I6PPM.js";import"./chunk-ZVP6GB4G.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import{a as ul,b as fl}from"./chunk-EKJG63EJ.js";import{a as Mc,p as Lc}from"./chunk-LWYKS5JU.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as no}from"./chunk-ACFQBLPX.js";import{c as el,e as Ss,g as Es}from"./chunk-LQE73AZR.js";import{a as ol,b as tl,c as nl,d as sl}from"./chunk-2D3RYIDU.js";import"./chunk-XF26QNAW.js";import{a as rl,e as al,g as cl}from"./chunk-RXLU6HJ6.js";import{L as Uo,R as wc,ca as bc,g as tc,r as nc,y as Ui,z as ac}from"./chunk-DTQQ4DAY.js";import{b as It,g as Rt,h as ys,i as ws,j as _t,k as cc,l as at,m as On,u as $c}from"./chunk-53OS4TDU.js";import{e as uc,f as Bi,k as fc}from"./chunk-GLQLCBJS.js";import{b as Nt}from"./chunk-6W74CHNW.js";import"./chunk-HCTWKWS3.js";import"./chunk-SFQUP3BP.js";import{b as Cn}from"./chunk-LLNPKE7H.js";import{a as kc,b as vc}from"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import{a as Hi,e as Sc,f as Ec,h as Ac,i as Tc,k as jc,l as Oc,m as Cc}from"./chunk-WXQQO2PD.js";import{a as Dt}from"./chunk-GV7S5BAX.js";import{c as dc}from"./chunk-SZDACK6O.js";import{f as gc,g as mc,h as Wi}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as ic,k as pc}from"./chunk-M2L6S3Z5.js";import{a as hc,b as re,c as Ie,d as Pt,e as yc}from"./chunk-QJP37VVA.js";import"./chunk-VWTBHLMX.js";import{a as qi}from"./chunk-DXWDVKMX.js";import"./chunk-Z7L74GGT.js";import"./chunk-36AXN6ZB.js";import"./chunk-KA2UIZXG.js";import{a as Fi,b as sc}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as rc}from"./chunk-X5C5W3E4.js";import{e as lc}from"./chunk-GSX4NK2N.js";import"./chunk-7UNS34CN.js";import"./chunk-MYVHVJWZ.js";import{n as oc}from"./chunk-AV7T3SYT.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-FBODSJU6.js";import{g as Fo,i as hs}from"./chunk-RS2T53EC.js";import"./chunk-WPNRDEHW.js";import{b as Ct,d as ec}from"./chunk-2GIDVZ4H.js";import{a as Pi,b as _a,c as tu,d as ps,e as Da,f as Ya,g as au,h as Va,i as cu,m as Ot,n as Ka,q as Qa,u as Za,y as ko,z as jn}from"./chunk-GQMUFSKB.js";import{a as Oo,b as jt,e as Ha,f as Tn}from"./chunk-72SZI2UW.js";import{a as Xa,b as lu}from"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-5MUJZODV.js";import{a as jo,b as ou}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{A as su,N as Wa,O as Mi,Q as Li,X as iu,ga as Ba,h as Pa,ha as Ja,i as Ma,ia as T,j as La,ja as fs,k as qa,l as Fa,la as te,m as nu,z as Ua}from"./chunk-SIOWVLZG.js";import{f as qo,n as us}from"./chunk-UIBUZ2N3.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import{g as Ga,k as za,l as ru}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as du}from"commander";var yd=new du().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 Nc({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()});te();import{Command as gu}from"commander";import{execFileSync as ao}from"node:child_process";import{cpSync as wd,existsSync as dr,mkdirSync as cr,mkdtempSync as mu,readdirSync as pu,rmSync as $d,writeFileSync as bd}from"node:fs";import{dirname as kd,join as qe}from"node:path";import{homedir as Ms,release as uu,tmpdir as fu}from"node:os";import{setTimeout as hu}from"node:timers/promises";function Ls(){let e=Uc(process.platform,process.arch,uu());if(e)throw new Error(e)}function qs(){let e=qe(Ms(),"Library/LaunchAgents"),o=[];try{o=pu(e).filter(Jc)}catch{}let t=o.flatMap(n=>{let s=qe(e,n);try{return[{file:s,plist:ao("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return Hc(e,t)}function Dn(e){return`gui/${process.getuid()}/${e.label}`}async function lr(e){try{ao("launchctl",["bootout",Dn(e)],{stdio:"pipe"})}catch{}for(let o=0;o<30;o++){try{ao("launchctl",["print",Dn(e)],{stdio:"pipe"})}catch{return}await hu(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function vd(e){if(!dr(e.file))throw new Error("Run agentx desktop install first.");let o=!0;try{ao("launchctl",["print",Dn(e)],{stdio:"pipe"})}catch{o=!1}o||ao("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),ao("launchctl",["kickstart",Dn(e)],{stdio:"pipe"})}function yu(){let e=Vc();if(e&&dr(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 Wt=new gu("desktop").description("install and control the macOS desktop assistant");Wt.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=>{Ls();let o=T(),t=Wc(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=yu(),r=qe(Ms(),"Applications"),{keep:a,remove:c}=qs();if(console.log(`Desktop assistant \u2192 ${qe(r,ks)}
1
+ import{a as fd,b as Ps,g as hd}from"./chunk-XEOT2F4C.js";import{a as Kl,c as Ql}from"./chunk-4NFDDTGA.js";import{A as ar,B as pd,D as ud,a as so,b as Xl,f as Ut,g as Zl,h as ed,i as od,j as td,l as nd,m as sd,n as id,o as ir,p as rd,u as ad,v as cd,w as rr,x as ld}from"./chunk-3RHFEKFX.js";import{a as dd,c as gd,d as md}from"./chunk-4FU4BFCH.js";import"./chunk-N7HKIMMR.js";import{a as Ji,b as xc}from"./chunk-RKPAVWXF.js";import{$ as _n,A as kl,B as vl,C as xl,D as Sl,E as El,F as Al,G as Tl,H as _l,I as Cs,J as Co,K as Bo,L as Mt,M as Is,N as Ns,O as Zi,P as Dl,Q as Pl,R as Ml,S as Ll,T as ql,U as Fl,V as Lt,W as qt,X as Ul,Y as Wl,Z as Le,_ as Rs,a as Ic,aa as er,b as Nc,ba as Bl,ca as Gl,da as nr,ea as Yl,fa as _s,ga as Ft,h as $s,ha as Ds,i as Pc,ia as sr,j as In,ja as Vl,k as bs,l as qc,m as Fc,n as Qc,o as Zc,p as As,q as Gi,r as il,s as ml,t as pl,u as hl,v as yl,w as wl,x as $l,y as bl,z as Yi}from"./chunk-K24MYJFP.js";import{A as Ts,G as gl,Ma as Jl,Na as or,Oa as Hl,Pa as tr,V as Nn,Y as Vi,Z as js,_ as jl,bb as vo,db as zl,fa as Wo,ga as Ol,ha as Xi,ja as Ki,la as Cl,ma as Il,na as Rn,ra as Os,ua as Nl,va as Rl,w as zi,wa as Qi,x as ll,z as dl}from"./chunk-3RTOS727.js";import{a as Rc,d as _c,e as Dc}from"./chunk-U52IS3AF.js";import{a as ks,b as vs,c as Uc,d as Wc,e as Bc,g as Jc,h as Hc,j as Gc,k as zc,l as Yc,m as Vc,p as xs,s as Xc,t as Kc}from"./chunk-S2GAEH2F.js";import"./chunk-GTJIKXDB.js";import"./chunk-DG5I6PPM.js";import"./chunk-ZVP6GB4G.js";import"./chunk-PPUN7YHA.js";import"./chunk-VZLIBDLH.js";import{a as ul,b as fl}from"./chunk-EKJG63EJ.js";import{a as Mc,p as Lc}from"./chunk-LWYKS5JU.js";import"./chunk-2AXFYDWF.js";import"./chunk-AQASR6KR.js";import{b as no}from"./chunk-ACFQBLPX.js";import{c as el,e as Ss,g as Es}from"./chunk-LQE73AZR.js";import{a as ol,b as tl,c as nl,d as sl}from"./chunk-2D3RYIDU.js";import"./chunk-QLWGLRT5.js";import{a as rl,e as al,g as cl}from"./chunk-JIT5GPTX.js";import{L as Uo,R as wc,ca as bc,g as tc,r as nc,y as Ui,z as ac}from"./chunk-DTQQ4DAY.js";import{b as It,g as Rt,h as ys,i as ws,j as _t,k as cc,l as at,m as On,u as $c}from"./chunk-53OS4TDU.js";import{e as uc,f as Bi,k as fc}from"./chunk-GLQLCBJS.js";import{b as Nt}from"./chunk-6W74CHNW.js";import"./chunk-HCTWKWS3.js";import"./chunk-SFQUP3BP.js";import{b as Cn}from"./chunk-LLNPKE7H.js";import{a as kc,b as vc}from"./chunk-SHEUCITK.js";import"./chunk-Y4CYQV7G.js";import{a as Hi,e as Sc,f as Ec,h as Ac,i as Tc,k as jc,l as Oc,m as Cc}from"./chunk-WXQQO2PD.js";import{a as Dt}from"./chunk-GV7S5BAX.js";import{c as dc}from"./chunk-SZDACK6O.js";import{f as gc,g as mc,h as Wi}from"./chunk-76Z4VHDX.js";import"./chunk-W4YR2RO2.js";import"./chunk-AFRHKA7B.js";import{a as ic,k as pc}from"./chunk-M2L6S3Z5.js";import{a as hc,b as re,c as Ie,d as Pt,e as yc}from"./chunk-QJP37VVA.js";import"./chunk-VWTBHLMX.js";import{a as qi}from"./chunk-DXWDVKMX.js";import"./chunk-Z7L74GGT.js";import"./chunk-36AXN6ZB.js";import"./chunk-KA2UIZXG.js";import{a as Fi,b as sc}from"./chunk-GQ76J72O.js";import"./chunk-ILEC3IAV.js";import"./chunk-J3SOEFRE.js";import"./chunk-SIU6STB2.js";import{j as rc}from"./chunk-X5C5W3E4.js";import{e as lc}from"./chunk-GSX4NK2N.js";import"./chunk-7UNS34CN.js";import"./chunk-MYVHVJWZ.js";import{n as oc}from"./chunk-AV7T3SYT.js";import"./chunk-23A5K5UW.js";import"./chunk-QD6IICK7.js";import"./chunk-CECHWYJ2.js";import"./chunk-FBODSJU6.js";import{g as Fo,i as hs}from"./chunk-RS2T53EC.js";import"./chunk-WPNRDEHW.js";import{b as Ct,d as ec}from"./chunk-2GIDVZ4H.js";import{a as Pi,b as _a,c as tu,d as ps,e as Da,f as Ya,g as au,h as Va,i as cu,m as Ot,n as Ka,q as Qa,u as Za,y as ko,z as jn}from"./chunk-GQMUFSKB.js";import{a as Oo,b as jt,e as Ha,f as Tn}from"./chunk-72SZI2UW.js";import{a as Xa,b as lu}from"./chunk-FX3D7YON.js";import"./chunk-FCPTN6NF.js";import"./chunk-QOYAX2FT.js";import"./chunk-JXF54PT7.js";import"./chunk-5MUJZODV.js";import{a as jo,b as ou}from"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import{A as su,N as Wa,O as Mi,Q as Li,X as iu,ga as Ba,h as Pa,ha as Ja,i as Ma,ia as T,j as La,ja as fs,k as qa,l as Fa,la as te,m as nu,z as Ua}from"./chunk-SIOWVLZG.js";import{f as qo,n as us}from"./chunk-UIBUZ2N3.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import{g as Ga,k as za,l as ru}from"./chunk-RGDKHYY2.js";import"./chunk-QIJLFPWE.js";import{Command as du}from"commander";var yd=new du().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 Nc({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()});te();import{Command as gu}from"commander";import{execFileSync as ao}from"node:child_process";import{cpSync as wd,existsSync as dr,mkdirSync as cr,mkdtempSync as mu,readdirSync as pu,rmSync as $d,writeFileSync as bd}from"node:fs";import{dirname as kd,join as qe}from"node:path";import{homedir as Ms,release as uu,tmpdir as fu}from"node:os";import{setTimeout as hu}from"node:timers/promises";function Ls(){let e=Uc(process.platform,process.arch,uu());if(e)throw new Error(e)}function qs(){let e=qe(Ms(),"Library/LaunchAgents"),o=[];try{o=pu(e).filter(Jc)}catch{}let t=o.flatMap(n=>{let s=qe(e,n);try{return[{file:s,plist:ao("plutil",["-convert","xml1","-o","-",s],{encoding:"utf8",stdio:["ignore","pipe","ignore"]})}]}catch{return[]}});return Hc(e,t)}function Dn(e){return`gui/${process.getuid()}/${e.label}`}async function lr(e){try{ao("launchctl",["bootout",Dn(e)],{stdio:"pipe"})}catch{}for(let o=0;o<30;o++){try{ao("launchctl",["print",Dn(e)],{stdio:"pipe"})}catch{return}await hu(200)}throw new Error("The desktop login service did not stop. Retry agentx desktop stop before installing.")}function vd(e){if(!dr(e.file))throw new Error("Run agentx desktop install first.");let o=!0;try{ao("launchctl",["print",Dn(e)],{stdio:"pipe"})}catch{o=!1}o||ao("launchctl",["bootstrap",`gui/${process.getuid()}`,e.file],{stdio:"pipe"}),ao("launchctl",["kickstart",Dn(e)],{stdio:"pipe"})}function yu(){let e=Vc();if(e&&dr(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 Wt=new gu("desktop").description("install and control the macOS desktop assistant");Wt.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=>{Ls();let o=T(),t=Wc(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=yu(),r=qe(Ms(),"Applications"),{keep:a,remove:c}=qs();if(console.log(`Desktop assistant \u2192 ${qe(r,ks)}
2
2
  Computer-use helper \u2192 ${qe(r,vs)}
3
3
  Agent \u2192 ${n?`${t} (pinned)`:"picked from the menu-bar icon"}
4
4
  Daemon \u2192 ${s}
@@ -27,7 +27,7 @@ The AgentX daemon and a speech transcription backend must also be available. Run
27
27
  `))});function tf(e){let o=Math.round(el/6e4),t=[` Pairing code: ${Te.bold.cyan(Ss(e.code))}`,Te.dim(` Open the app from the phone's home screen and type this code. It works once, for ${o} minutes.`)," Or scan the QR code with the phone's camera and open the link.",` Device ${Te.cyan(e.deviceId)} (${e.deviceName}) paired to ${e.origin}.`,Te.yellow(" \u26A0 Anyone who scans the QR code or types the code can use the app. Clear the terminal when done.")];return e.origin.startsWith("https://")||t.push(Te.yellow(` \u26A0 ${e.origin} is not HTTPS: the phone can't install the app or keep the session from there.`)),t}function hr(){let e;try{e=JSON.parse(Jd("tailscale",["status","--json"],{encoding:"utf-8",timeout:5e3}))}catch{throw new Error("Could not read this machine's Tailscale name. Is Tailscale running? Or pass --url https://<address>.")}let o=String(e?.Self?.DNSName||"").replace(/\.$/,"");if(!o)throw new Error("Tailscale has no MagicDNS name for this machine. Pass --url https://<address>.");return`https://${o}`}var nf=new Set(["/app","/api/app","/member","/api/member"]);function yr(e,o){let t=[e,...Object.values(e?.Foreground??{})],n=[];for(let s of t)for(let[i,r]of Object.entries(s?.Web??{}))for(let[a,c]of Object.entries(r?.Handlers??{})){let l=String(c?.Proxy??"").match(/^(?:https?:\/\/)?(?:127\.0\.0\.1|localhost|\[::1\]):(\d+)/),g=a.replace(/\/+$/,"")||"/";l&&Number(l[1])===o&&!nf.has(g)&&n.push(`${i}${a}`)}return n}function wr(){try{return JSON.parse(Jd("tailscale",["serve","status","--json"],{encoding:"utf-8",timeout:5e3})||"{}")}catch{return null}}function Un(){try{return T().dashboard.port||4202}catch{return 4202}}te();import{Command as So}from"commander";import h from"chalk";import Me from"prompts";import{readFileSync as Ho,writeFileSync as Gt,existsSync as we,mkdirSync as xo,cpSync as $r,readdirSync as kr}from"fs";import{resolve as z,join as Jo,dirname as sf}from"path";import{fileURLToPath as rf}from"url";function me(){let e=z(process.cwd(),"agentx.json");if(!we(e))throw new Error("No agentx.json found. Run: agentx init");return JSON.parse(Ho(e,"utf-8"))}function Je(e){return re(o=>{for(let t of Object.keys(o))delete o[t];Object.assign(o,e)}).then(o=>{if(!o.success){console.error(h.red(` Config save failed: ${o.error}`));return}o.reloaded?console.error(h.dim(" (daemon hot-reloaded)")):o.reloadSkipped&&!/ECONNREFUSED|unreachable|fetch failed/i.test(o.reloadSkipped)&&console.error(h.dim(` (daemon reload skipped: ${o.reloadSkipped})`))})}var gt=new So().name("agent").description("manage agents \u2014 add, list, remove");gt.command("list").alias("ls").description("list configured agents").action(()=>{let e=me();console.log();for(let[o,t]of Object.entries(e.agents||{})){let n=t.mentions?.join(", ")||"";console.log(` ${h.cyan(o)} \u2014 ${t.name} (${t.tier})`),console.log(h.dim(` workspace: ${t.workspace}`)),n&&console.log(h.dim(` mentions: ${n}`))}console.log()});gt.command("add").description("add a new agent interactively").action(async()=>{let e=me(),o=await Me([{type:"text",name:"id",message:"Agent ID (kebab-case)",validate:l=>/^[a-z0-9-]+$/.test(l)||"Use lowercase, numbers, hyphens"},{type:"text",name:"name",message:"Display name"},{type:"text",name:"workspace",message:"Workspace path",initial:z(process.cwd(),"agents/")},{type:"select",name:"tier",message:"Execution tier",choices:[{title:"claude-code (subscription, full features)",value:"claude-code"},{title:"codex-cli (OpenAI Codex CLI)",value:"codex-cli"},{title:"opencode (configured OpenCode providers)",value:"opencode"},{title:"sdk (API key, programmatic)",value:"sdk"},{title:"orchestrator (any provider)",value:"orchestrator"}]},{type:"text",name:"model",message:"Model",initial:"claude-sonnet-4-6"},{type:"list",name:"mentions",message:"Mention patterns (comma-separated)",separator:","},{type:"number",name:"maxConcurrent",message:"Max concurrent tasks",initial:2},{type:"text",name:"systemPrompt",message:"System prompt"}]);if(!o.id)return;let t=o.workspace.endsWith(o.id)?o.workspace:Jo(o.workspace,o.id);xo(z(t,".claude/skills"),{recursive:!0});let n={name:o.name,workspace:t,tier:o.tier,model:o.model,mentions:o.mentions?.map(l=>l.trim()).filter(Boolean)||[],maxConcurrent:o.maxConcurrent,systemPrompt:o.systemPrompt,permissionMode:"default"},{setupWorkspace:s}=await import("./workspace-setup-HAV4CQV7.js"),i=s(o.id,n,"19900",(...l)=>{console.log(h.dim(` ${l.join(" ")}`))}),r=z(process.cwd(),"src/wiki/SKILL.md"),a=z(sf(rf(import.meta.url)),"../wiki/SKILL.md"),c=we(r)?r:a;we(c)&&(xo(z(t,".claude/skills/wiki"),{recursive:!0}),$r(c,z(t,".claude/skills/wiki/SKILL.md"))),e.agents=e.agents||{},e.agents[o.id]=n,await Je(e),console.log(h.green(`
28
28
  Agent "${o.id}" added`)),console.log(h.dim(` Workspace: ${t}`)),console.log(h.dim(` Created: ${i.created.length} files (CLAUDE.md, AGENTS.md, settings, rules)`)),console.log()});gt.command("remove <id>").alias("rm").description("remove an agent from config (keeps workspace)").action(async e=>{let o=me();if(!o.agents?.[e]){console.log(h.red(` Agent "${e}" not found`));return}delete o.agents[e],await Je(o),console.log(h.green(` Agent "${e}" removed from config (workspace preserved)`))});gt.command("capability <id>").alias("caps").description("set agent capability flags (intents, maxDelegationDepth, contextReferences, contextStrategy)").option("--intents <csv>","comma-separated intent allow-list (set to '-' to clear)").option("--max-delegation-depth <n>","max distinct upstream agents on the same subject before refusal (0 disables)").option("--context-references <bool>","render the deterministic [Verified References] block (true|false)").option("--context-strategy <name>","per-agent override: layered | planner").option("--max-execution-minutes <n>","wall-clock cap on a single Claude Code call (1\u2013240)").option("--show","just print the current capability fields").action(async(e,o)=>{let t=me(),n=t.agents?.[e];if(n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1)),o.show){console.log(),console.log(h.bold(` ${e}`)),console.log(` intents ${n.intents&&n.intents.length?n.intents.join(", "):h.dim("(any)")}`),console.log(` maxDelegationDepth ${n.maxDelegationDepth??5}`),console.log(` contextReferences ${n.contextReferences?"on":h.dim("off")}`),console.log(` contextStrategy ${n.contextStrategy||h.dim("(global default)")}`),console.log(` maxExecutionMinutes ${n.maxExecutionMinutes??20}`),console.log();return}let s=[];if(o.intents!==void 0&&(o.intents==="-"||o.intents===""?(n.intents=[],s.push("intents cleared (permissive)")):(n.intents=String(o.intents).split(",").map(i=>i.trim()).filter(Boolean),s.push(`intents=[${n.intents.join(", ")}]`))),o.maxDelegationDepth!==void 0){let i=parseInt(o.maxDelegationDepth,10);(!Number.isFinite(i)||i<0||i>50)&&(console.log(h.red(" --max-delegation-depth must be 0..50")),process.exit(1)),n.maxDelegationDepth=i,s.push(`maxDelegationDepth=${i}`)}if(o.contextReferences!==void 0){let i=String(o.contextReferences).toLowerCase();["true","false","on","off","1","0"].includes(i)||(console.log(h.red(" --context-references must be true|false")),process.exit(1)),n.contextReferences=i==="true"||i==="on"||i==="1",s.push(`contextReferences=${n.contextReferences}`)}if(o.contextStrategy!==void 0&&(o.contextStrategy==="-"||o.contextStrategy===""?(delete n.contextStrategy,s.push("contextStrategy cleared (uses global default)")):["layered","planner"].includes(o.contextStrategy)?(n.contextStrategy=o.contextStrategy,s.push(`contextStrategy=${o.contextStrategy}`)):(console.log(h.red(" --context-strategy must be layered|planner (or '-' to clear)")),process.exit(1))),o.maxExecutionMinutes!==void 0){let i=parseInt(o.maxExecutionMinutes,10);(!Number.isFinite(i)||i<1||i>240)&&(console.log(h.red(" --max-execution-minutes must be 1..240")),process.exit(1)),n.maxExecutionMinutes=i,s.push(`maxExecutionMinutes=${i}`)}s.length===0&&(console.log(h.yellow(" no changes \u2014 pass at least one flag, or use --show")),process.exit(1)),await Je(t),console.log(h.green(` \u2713 ${e}: ${s.join(", ")}`)),console.log(h.dim(" Restart the daemon (or POST /reload) for the change to take effect."))});var Wn=new So().name("integrations").alias("integ").description("manage per-agent third-party credentials (telegram-bot, hubspot, gitlab-user, gmail, etc.)");Wn.command("list <agentId>").alias("ls").description("list integrations declared on an agent").option("--json","emit JSON").action(async(e,o)=>{let n=me().agents?.[e];n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let s=n.integrations??[];if(o.json){console.log(JSON.stringify(s,null,2));return}if(!s.length){console.log(h.dim(`
29
29
  ${e}: no integrations declared. Add one with: agentx agent integrations add ${e}
30
- `));return}console.log(),console.log(h.bold(` ${e}`));for(let i of s){let r=i.enabled!==!1,a=[],c=i.credentials??{};for(let[g,d]of Object.entries(c))typeof d=="string"&&/^[A-Z][A-Z0-9_]*$/.test(d)?a.push(process.env[d]?h.green(`${g}:${d}=set`):h.yellow(`${g}:${d}=UNSET`)):g==="auth"&&d==="keyring"?a.push(h.dim("auth:keyring")):g==="sessionDir"&&typeof d=="string"&&a.push(h.dim(`sessionDir:${d}`));let l=Object.entries(i.metadata??{}).map(([g,d])=>`${g}=${d}`).join(" ");console.log(` ${r?h.cyan(i.kind.padEnd(14)):h.dim(i.kind.padEnd(14))} ${h.bold(i.label)}`),a.length&&console.log(` ${a.join(" ")}`),l&&console.log(` ${h.dim(l)}`),r||console.log(` ${h.dim("(disabled)")}`)}console.log()});Wn.command("add <agentId>").description("declare a new integration on an agent").option("--kind <name>","service kind (e.g. telegram-bot, hubspot, gitlab-user, gmail)").option("--label <text>","human-readable label (must be unique within (agent, kind))").option("--token-env <name>","env-var holding the secret (uppercase identifier)").option("--auth <mode>","alternative to --token-env: 'keyring' for OS keyring").option("--session-dir <path>","for whatsapp / mtproto: file-based session directory").option("--metadata <kvList>","comma-separated key=value pairs (e.g. 'username=alex,email=alex@example.com')").option("--no-prompt","fail instead of prompting for missing values").action(async(e,o)=>{let t=me();t.agents?.[e]||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let n=o.prompt!==!1,{INTEGRATION_KINDS:s}=await import("./config-ZHQYXFOJ.js"),i=String(o.kind||"").trim();!i&&n&&(i=((await Me({type:"autocomplete",name:"kind",message:"Service kind",choices:s.map(f=>({title:f,value:f}))})).kind||"").trim()),i||(console.log(h.red(" --kind is required")),process.exit(1));let r=String(o.label||"").trim();!r&&n&&(r=((await Me({type:"text",name:"label",message:'Label (e.g. "@cx_bot", "Acme CRM", "alex@example.com")'})).label||"").trim()),r||(console.log(h.red(" --label is required")),process.exit(1));let a=String(o.tokenEnv||"").trim(),c=String(o.auth||"").trim(),l=String(o.sessionDir||"").trim();if(!a&&!c&&!l&&n){let u=await Me({type:"select",name:"scheme",message:"Credential scheme",choices:[{title:"Env var (e.g. HUBSPOT_TOKEN_CX)",value:"tokenEnv"},{title:"OS keyring",value:"keyring"},{title:"File-based session (whatsapp / mtproto)",value:"sessionDir"}]});u.scheme==="tokenEnv"?a=((await Me({type:"text",name:"tokenEnv",message:"Env var name (uppercase)",initial:`${i.replace(/-/g,"_").toUpperCase()}_${e.replace(/-/g,"_").toUpperCase()}`})).tokenEnv||"").trim():u.scheme==="keyring"?c="keyring":u.scheme==="sessionDir"&&(l=((await Me({type:"text",name:"sessionDir",message:"Session directory path",initial:`.agentx/${i}-sessions/${e}`})).sessionDir||"").trim())}let g={};if(o.metadata)for(let u of String(o.metadata).split(",")){let[f,...p]=u.split("=");f&&(g[f.trim()]=p.join("=").trim())}else if(n){let u=await Me({type:"text",name:"metadata",message:"Metadata (k=v,k=v) \u2014 non-secret only, optional"});if(u.metadata)for(let f of String(u.metadata).split(",")){let[p,...y]=f.split("=");p&&(g[p.trim()]=y.join("=").trim())}}let d={};a&&(/^[A-Z][A-Z0-9_]*$/.test(a)||(console.log(h.red(` --token-env must be uppercase identifier (got "${a}")`)),process.exit(1)),d.tokenEnv=a),c==="keyring"&&(d.auth="keyring"),l&&(d.sessionDir=l),Object.keys(d).length||(console.log(h.red(" one of --token-env / --auth / --session-dir is required")),process.exit(1)),t.agents[e].integrations=t.agents[e].integrations??[],t.agents[e].integrations.find(u=>u.kind===i&&u.label===r)&&(console.log(h.red(` Integration (${i}, ${r}) already exists on ${e}`)),process.exit(1)),t.agents[e].integrations.push({kind:i,label:r,credentials:d,metadata:g,enabled:!0}),await Je(t),console.log(h.green(` \u2713 ${e}: added ${i} integration "${r}"`)),a&&!process.env[a]&&console.log(h.yellow(` \u26A0 env var ${a} is not set \u2014 set it on the daemon environment before use`))});Wn.command("remove <agentId> <kindOrLabel>").alias("rm").description("remove an integration (matched by kind, label, or 'kind:label')").action(async(e,o)=>{let t=me(),n=t.agents?.[e];n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let s=n.integrations??[],[i,r]=o.includes(":")?o.split(":",2):[o,""],a=s.findIndex(l=>l.kind===i&&(!r||l.label===r)||l.label===o);a===-1&&(console.log(h.red(` No integration matched "${o}"`)),process.exit(1));let c=s.splice(a,1)[0];await Je(t),console.log(h.green(` \u2713 removed ${c.kind} integration "${c.label}" from ${e}`))});Wn.command("test <agentId> [kindOrLabel]").description("validate env vars are set for one or all integrations on an agent").action(async(e,o)=>{let n=me().agents?.[e];n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let s=n.integrations??[],i=o?s.filter(a=>a.kind===o||a.label===o||`${a.kind}:${a.label}`===o):s;if(!i.length){console.log(h.yellow(" no integrations to test"));return}let r=0;console.log();for(let a of i){let c=a.credentials??{},l=[];for(let[g,d]of Object.entries(c))typeof d=="string"&&/^[A-Z][A-Z0-9_]*$/.test(d)&&!process.env[d]&&l.push(`${g}: env var ${d} is unset`);if(l.length){r+=1,console.log(` ${h.red("\u2717")} ${a.kind} "${a.label}"`);for(let g of l)console.log(` ${h.dim(g)}`)}else console.log(` ${h.green("\u2713")} ${a.kind} "${a.label}"`)}console.log(),r>0&&process.exit(1)});gt.addCommand(Wn);var Hs=new So().name("channel").description("manage channels \u2014 add telegram/whatsapp/gitlab, list");Hs.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=me();console.log();let o=e.channels?.telegram;if(o?.enabled){console.log(h.bold(" Telegram:"));for(let[s,i]of Object.entries(o.accounts||{}))console.log(` ${h.cyan(s)} -> agent: ${i.agentBinding}`)}else console.log(h.dim(" Telegram: disabled"));let t=e.channels?.whatsapp;if(t?.enabled){console.log(h.bold(" WhatsApp:")),console.log(` default agent: ${t.defaultAgent||"(none)"}`),console.log(` session: ${t.sessionDir||".agentx/whatsapp-sessions"}`);for(let s of t.routes||[]){let i=s.contact?`contact ${s.contact}`:`group "${s.group}"`;console.log(` ${i} -> agent: ${s.agent}`)}}else console.log(h.dim(" WhatsApp: disabled"));let n=e.channels?.gitlab;if(n?.enabled){console.log(h.bold(" GitLab:")),console.log(` host: ${n.host}`),console.log(` webhook: :${n.webhookPort}`);for(let s of n.routes||[])console.log(` ${s.project} -> agent: ${s.agent}`)}else console.log(h.dim(" GitLab: disabled"));console.log()});Hs.command("add").description("add a channel (telegram, whatsapp, or gitlab)").action(async()=>{let e=me(),o=Object.keys(e.agents||{});if(!o.length){console.log(h.red(" No agents configured. Run: agentx agent add"));return}let t=o.map(s=>({title:`${s} (${e.agents[s].name})`,value:s})),{channelType:n}=await Me({type:"select",name:"channelType",message:"Channel type",choices:[{title:"Telegram \u2014 bot via BotFather token",value:"telegram"},{title:"WhatsApp \u2014 link via QR code (self-chat or contacts)",value:"whatsapp"},{title:"GitLab \u2014 webhook for issues, MRs, comments, pipelines",value:"gitlab"}]});if(n){if(e.channels=e.channels||{},n==="telegram"){let s=await Me([{type:"text",name:"accountName",message:"Account name (e.g. 'default', 'devops')"},{type:"text",name:"token",message:"Bot token (from @BotFather)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:t}]);if(!s.accountName||!s.token)return;try{let r=await(await fetch(`https://api.telegram.org/bot${s.token}/getMe`)).json();if(!r.ok)throw new Error(r.description);console.log(h.green(` Bot verified: @${r.result.username}`));let a=`@${r.result.username}`,c=e.agents[s.agentBinding].mentions||[];c.includes(a)||(c.push(a,r.result.username),e.agents[s.agentBinding].mentions=c)}catch(i){console.log(h.red(` Invalid token: ${i.message}`));return}e.channels.telegram=e.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},e.channels.telegram.enabled=!0,e.channels.telegram.accounts[s.accountName]={token:s.token,agentBinding:s.agentBinding},await Je(e),console.log(h.green(` Telegram "${s.accountName}" added -> ${s.agentBinding}`))}if(n==="whatsapp"){let s=await Me([{type:"select",name:"defaultAgent",message:"Default agent for WhatsApp messages",choices:t},{type:"text",name:"sessionDir",message:"Session directory",initial:".agentx/whatsapp-sessions"},{type:"confirm",name:"addRoute",message:"Add a contact/group route?",initial:!0}]);if(!s.defaultAgent)return;let i=[],r=s.addRoute;for(;r;){let a=await Me([{type:"select",name:"type",message:"Route type",choices:[{title:"Contact (phone number)",value:"contact"},{title:"Group (name match)",value:"group"}]},{type:"text",name:"value",message:c=>c==="contact"?"Phone number (e.g. +10000000000)":"Group name (partial match)"},{type:"select",name:"agent",message:"Route to agent",choices:t},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);a.value&&a.agent&&i.push({[a.type]:a.value,agent:a.agent}),r=a.more}e.channels.whatsapp={enabled:!0,sessionDir:s.sessionDir,defaultAgent:s.defaultAgent,routes:i},await Je(e),xo(z(process.cwd(),s.sessionDir),{recursive:!0}),console.log(h.green(` WhatsApp enabled (${i.length} routes, default: ${s.defaultAgent})`)),console.log(h.dim(" Start daemon to scan QR code: agentx daemon start"))}if(n==="gitlab"){let s=await Me([{type:"text",name:"host",message:"GitLab instance URL",initial:"https://gitlab.example.com"},{type:"text",name:"token",message:"GitLab API token (PRIVATE-TOKEN)"},{type:"number",name:"webhookPort",message:"Webhook listen port",initial:18810},{type:"text",name:"webhookSecret",message:"Webhook secret (X-Gitlab-Token, optional)"},{type:"confirm",name:"addRoute",message:"Add a project route?",initial:!0}]);if(!s.token)return;let i=[],r=s.addRoute;for(;r;){let a=await Me([{type:"text",name:"project",message:"GitLab project path (e.g. group/project, or * for default)"},{type:"select",name:"agent",message:"Route to agent",choices:t},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);a.project&&a.agent&&i.push({project:a.project,agent:a.agent}),r=a.more}e.channels.gitlab={enabled:!0,host:s.host,token:s.token,webhookPort:s.webhookPort,webhookSecret:s.webhookSecret||void 0,routes:i},await Je(e),console.log(h.green(` GitLab enabled (${i.length} routes, webhook :${s.webhookPort})`)),console.log(h.dim(` Add webhook in GitLab: ${s.host}/<project>/-/hooks`)),console.log(h.dim(` URL: http://your-server:${s.webhookPort}/`)),s.webhookSecret&&console.log(h.dim(` Secret token: ${s.webhookSecret}`)),console.log(h.dim(" Events: Comments, Issues, Merge requests, Pipeline"))}console.log(h.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var zt=new So().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");zt.command("list").alias("ls").description("list cron jobs").action(()=>{let e=me();console.log();for(let[o,t]of Object.entries(e.crons||{})){let n=t.enabled?h.green("\u25CF"):h.dim("\u25CB");console.log(` ${n} ${h.cyan(o)} \u2014 ${t.schedule} (${t.timezone})`),console.log(h.dim(` agent: ${t.agent} | timeout: ${t.timeout}s`))}Object.keys(e.crons||{}).length||console.log(h.dim(" No cron jobs configured")),console.log()});zt.command("add").description("add a cron job").action(async()=>{let e=me(),o=Object.keys(e.agents||{}),t=await Me([{type:"text",name:"id",message:"Job ID (kebab-case)"},{type:"text",name:"schedule",message:"Cron expression (e.g. '0 9 * * *')"},{type:"text",name:"timezone",message:"Timezone",initial:"UTC"},{type:"select",name:"agent",message:"Agent",choices:o.map(n=>({title:n,value:n}))},{type:"text",name:"prompt",message:"Task prompt"},{type:"number",name:"timeout",message:"Timeout (seconds)",initial:600},{type:"confirm",name:"enabled",message:"Enable now?",initial:!1}]);!t.id||!t.schedule||(e.crons=e.crons||{},e.crons[t.id]={enabled:t.enabled,schedule:t.schedule,timezone:t.timezone,agent:t.agent,prompt:t.prompt,timeout:t.timeout,onError:["log"]},await Je(e),console.log(h.green(` Cron "${t.id}" added (${t.enabled?"enabled":"disabled"})`)),console.log())});zt.command("enable <id>").description("enable a cron job").action(async e=>{let o=me();if(!o.crons?.[e]){console.log(h.red(` Cron "${e}" not found`));return}if(o.crons[e].approval?.action==="create"){console.log(h.yellow(` Cron "${e}" is awaiting approval \u2014 run: agentx schedule approve ${e}`));return}o.crons[e].enabled=!0,await Je(o),console.log(h.green(` Cron "${e}" enabled`))});zt.command("disable <id>").description("disable a cron job").action(async e=>{let o=me();if(!o.crons?.[e]){console.log(h.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!1,await Je(o),console.log(h.green(` Cron "${e}" disabled`))});var io=new So().name("mesh").description("manage mesh peers \u2014 add, list, remove");io.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=me();if(console.log(),!e.mesh?.enabled)console.log(h.dim(" Mesh: disabled"));else{console.log(h.bold(" Mesh peers:"));for(let o of e.mesh.peers||[]){let t=h.red("unreachable");try{let s=await(await fetch(`${o.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();t=h.green(`healthy \u2014 ${s.agents?.length||0} agents`)}catch{}console.log(` ${h.cyan(o.name)} ${h.dim(o.url)} ${t}`)}}console.log()});io.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=me(),o=await Me([{type:"text",name:"name",message:"Peer name (e.g. 'server-2')"},{type:"text",name:"url",message:"Peer URL (e.g. 'http://100.64.0.11:18800')"},{type:"text",name:"token",message:"Auth token (optional, press enter to skip)"}]);if(!(!o.name||!o.url)){try{let n=await(await fetch(`${o.url}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)})).json();console.log(h.green(` Connected: ${n.name} (${n.skills?.length||0} agents)`))}catch{console.log(h.yellow(" Could not reach peer (adding anyway)"))}e.mesh=e.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},e.mesh.enabled=!0,e.mesh.peers=e.mesh.peers||[],e.mesh.peers.push({url:o.url,name:o.name,...o.token?{token:o.token}:{}}),await Je(e),console.log(h.green(` Peer "${o.name}" added`)),console.log()}});io.command("remove <name>").alias("rm").description("remove a mesh peer").action(async e=>{let o=me();o.mesh?.peers&&(o.mesh.peers=o.mesh.peers.filter(t=>t.name!==e),o.mesh.peers.length===0&&(o.mesh.enabled=!1),await Je(o),console.log(h.green(` Peer "${e}" removed`)))});io.command("health").description("tune mesh peer health checks (interval + timeout, in seconds)").option("--interval <s>","seconds between health probes (default 60)").option("--timeout <s>","per-probe timeout in seconds (default 10)").option("--show","just print the current values").action(async e=>{let o=me();if(o.mesh=o.mesh||{},o.mesh.healthCheck=o.mesh.healthCheck||{},e.show){console.log(` interval ${o.mesh.healthCheck.interval??60}s`),console.log(` timeout ${o.mesh.healthCheck.timeout??10}s`);return}let t=[];if(e.interval!==void 0){let n=parseInt(e.interval,10);(!Number.isFinite(n)||n<5||n>3600)&&(console.log(h.red(" --interval must be 5..3600 seconds")),process.exit(1)),o.mesh.healthCheck.interval=n,t.push(`interval=${n}s`)}if(e.timeout!==void 0){let n=parseInt(e.timeout,10);(!Number.isFinite(n)||n<1||n>60)&&(console.log(h.red(" --timeout must be 1..60 seconds")),process.exit(1)),o.mesh.healthCheck.timeout=n,t.push(`timeout=${n}s`)}t.length===0&&(console.log(h.yellow(" no changes \u2014 pass --interval and/or --timeout, or --show")),process.exit(1)),await Je(o),console.log(h.green(` \u2713 mesh.healthCheck: ${t.join(", ")}`)),console.log(h.dim(" Restart the daemon for the new cadence to take effect."))});io.command("announce <text...>").description("send a short note to every machine in the mesh (shown in event feeds)").option("--by <name>","who the note is from (an agent id or a person's name)").option("--node <url>","daemon to publish on (default: dashboard.daemonUrl, else this machine on port 18800)").option("--token <token>","mesh token, needed only when --node is another machine (default: MESH_TOKEN)").action(async(e,o)=>{let t=o.node||"";if(!t)try{t=T().dashboard?.daemonUrl||""}catch{}t=(t||"http://localhost:18800").replace(/\/+$/,"");let n=o.token||process.env.MESH_TOKEN||"",s={"Content-Type":"application/json"};n&&(s.Authorization=`Bearer ${n}`);try{let i=await fetch(`${t}/mesh/announce`,{method:"POST",headers:s,body:JSON.stringify({text:e.join(" "),...o.by?{by:o.by}:{}}),signal:AbortSignal.timeout(1e4)}),r=await i.json().catch(()=>({}));i.ok||(console.log(h.red(` Announcement refused (${i.status}): ${r.error||"unknown error"}`)),process.exit(1)),console.log(h.green(` \u2713 Announced from ${r.event?.node??"this machine"}`)+h.dim(` (event ${r.event?.id??"?"})`))}catch(i){console.log(h.red(` Could not reach the daemon at ${t}: ${i?.message||i}`)),process.exit(1)}});var Hd=e=>{let o=e||"";if(!o)try{o=T().dashboard?.daemonUrl||""}catch{}return(o||"http://localhost:18800").replace(/\/+$/,"")};async function Gs(e,o,t={}){let n=Hd(),s={"Content-Type":"application/json"};process.env.MESH_TOKEN&&(s.Authorization=`Bearer ${process.env.MESH_TOKEN}`);try{let i=await fetch(`${n}/mesh/guests/${encodeURIComponent(e)}/${o}`,{method:"POST",headers:s,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)}),r=await i.json().catch(()=>({}));i.ok||(console.log(h.red(` ${r.error||`HTTP ${i.status}`}`)),process.exit(1));let a=r.grant;console.log(h.green(` \u2713 ${a?.name??e}: ${a?.state}${r.stopped?`, ${r.stopped} running turn(s) stopped`:""}`))}catch(i){console.log(h.red(` Could not reach the daemon at ${n}: ${i?.message||i}. The daemon must be running: it stops the guest's running turns.`)),process.exit(1)}}var mt=io.command("guests").description("other organisations let into part of this mesh: open, watch, pause, widen, narrow, end");mt.command("invite").description("open a grant to a guest mesh and print the one-time code it joins with").requiredOption("--name <name>",'what you call it, e.g. "Support session for company X"').requiredOption("--guest <name>","the other organisation's name").requiredOption("--agent <id>","the agent of this node that works for them").option("--folders <list>","folders that agent may touch for them, comma-separated").option("--skills <list>","skills it may use for them, comma-separated").option("--commands <list>","commands it may run for them, comma-separated").option("--level <level>","report (read only) | propose (no merge, deploy or delete) | act","propose").option("--days <n>","how long the grant lasts (1 to 365)","7").option("--url <origin>","the address the guest reaches this node on (default: dashboard.daemonUrl)").action(async e=>{let{TokenStore:o}=await import("./token-store-YBSU2DTV.js"),{PairCodeStore:t,formatCode:n}=await import("./pair-codes-EYGELBPD.js"),{GuestStore:s}=await import("./store-7W2AP5H4.js"),{inviteGuest:i}=await import("./grants-M4K6WXOO.js"),r=T(),a=i({tokens:new o,codes:new t,guests:new s,hasAgent:l=>!!r.agents[l]},{name:e.name,guest:e.guest,agentId:e.agent,folders:e.folders?.split(","),skills:e.skills?.split(","),commands:e.commands?.split(","),level:e.level,days:Number(e.days)});a.ok||(console.log(h.red(` ${a.error}`)),process.exit(1));let c=(e.url||Hd()).replace(/\/+$/,"");console.log(),console.log(` Grant ${h.bold(a.grant.name)} for ${h.bold(a.grant.guest)}: ${a.grant.agentId}, ${a.grant.level}, until ${a.grant.expiresAt.slice(0,10)}`),console.log(h.dim(` id ${a.grant.id} \xB7 folders: ${a.grant.folders.join(", ")||"none"} \xB7 skills: ${a.grant.skills.join(", ")||"none"} \xB7 commands: ${a.grant.commands.join(", ")||"none"}`)),console.log(),console.log(" Send the guest this address and code. The code works once, for 10 minutes:"),console.log(),console.log(` ${h.cyan(c)}`),console.log(` ${h.bold(n(a.code))}`),console.log(),console.log(` They run: ${h.cyan(`agentx mesh join ${c} --code ${n(a.code)} --name <what-they-call-you>`)}`),console.log(` When they join, a card "Guest mesh: ${a.grant.guest} wants to join" asks you to approve it.`),console.log()});mt.command("list",{isDefault:!0}).alias("ls").description("every grant: state, guest, agent, level, end date, usage").option("--json","machine-readable output").action(async e=>{let{GuestStore:o}=await import("./store-7W2AP5H4.js"),t=new o().grants().sort((n,s)=>s.createdAt.localeCompare(n.createdAt));if(e.json){console.log(JSON.stringify(t,null,2));return}if(!t.length){console.log(h.dim(`
30
+ `));return}console.log(),console.log(h.bold(` ${e}`));for(let i of s){let r=i.enabled!==!1,a=[],c=i.credentials??{};for(let[g,d]of Object.entries(c))typeof d=="string"&&/^[A-Z][A-Z0-9_]*$/.test(d)?a.push(process.env[d]?h.green(`${g}:${d}=set`):h.yellow(`${g}:${d}=UNSET`)):g==="auth"&&d==="keyring"?a.push(h.dim("auth:keyring")):g==="sessionDir"&&typeof d=="string"&&a.push(h.dim(`sessionDir:${d}`));let l=Object.entries(i.metadata??{}).map(([g,d])=>`${g}=${d}`).join(" ");console.log(` ${r?h.cyan(i.kind.padEnd(14)):h.dim(i.kind.padEnd(14))} ${h.bold(i.label)}`),a.length&&console.log(` ${a.join(" ")}`),l&&console.log(` ${h.dim(l)}`),r||console.log(` ${h.dim("(disabled)")}`)}console.log()});Wn.command("add <agentId>").description("declare a new integration on an agent").option("--kind <name>","service kind (e.g. telegram-bot, hubspot, gitlab-user, gmail)").option("--label <text>","human-readable label (must be unique within (agent, kind))").option("--token-env <name>","env-var holding the secret (uppercase identifier)").option("--auth <mode>","alternative to --token-env: 'keyring' for OS keyring").option("--session-dir <path>","for whatsapp / mtproto: file-based session directory").option("--metadata <kvList>","comma-separated key=value pairs (e.g. 'username=alex,email=alex@example.com')").option("--no-prompt","fail instead of prompting for missing values").action(async(e,o)=>{let t=me();t.agents?.[e]||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let n=o.prompt!==!1,{INTEGRATION_KINDS:s}=await import("./config-ZHQYXFOJ.js"),i=String(o.kind||"").trim();!i&&n&&(i=((await Me({type:"autocomplete",name:"kind",message:"Service kind",choices:s.map(f=>({title:f,value:f}))})).kind||"").trim()),i||(console.log(h.red(" --kind is required")),process.exit(1));let r=String(o.label||"").trim();!r&&n&&(r=((await Me({type:"text",name:"label",message:'Label (e.g. "@cx_bot", "Acme CRM", "alex@example.com")'})).label||"").trim()),r||(console.log(h.red(" --label is required")),process.exit(1));let a=String(o.tokenEnv||"").trim(),c=String(o.auth||"").trim(),l=String(o.sessionDir||"").trim();if(!a&&!c&&!l&&n){let u=await Me({type:"select",name:"scheme",message:"Credential scheme",choices:[{title:"Env var (e.g. HUBSPOT_TOKEN_CX)",value:"tokenEnv"},{title:"OS keyring",value:"keyring"},{title:"File-based session (whatsapp / mtproto)",value:"sessionDir"}]});u.scheme==="tokenEnv"?a=((await Me({type:"text",name:"tokenEnv",message:"Env var name (uppercase)",initial:`${i.replace(/-/g,"_").toUpperCase()}_${e.replace(/-/g,"_").toUpperCase()}`})).tokenEnv||"").trim():u.scheme==="keyring"?c="keyring":u.scheme==="sessionDir"&&(l=((await Me({type:"text",name:"sessionDir",message:"Session directory path",initial:`.agentx/${i}-sessions/${e}`})).sessionDir||"").trim())}let g={};if(o.metadata)for(let u of String(o.metadata).split(",")){let[f,...p]=u.split("=");f&&(g[f.trim()]=p.join("=").trim())}else if(n){let u=await Me({type:"text",name:"metadata",message:"Metadata (k=v,k=v) \u2014 non-secret only, optional"});if(u.metadata)for(let f of String(u.metadata).split(",")){let[p,...y]=f.split("=");p&&(g[p.trim()]=y.join("=").trim())}}let d={};a&&(/^[A-Z][A-Z0-9_]*$/.test(a)||(console.log(h.red(` --token-env must be uppercase identifier (got "${a}")`)),process.exit(1)),d.tokenEnv=a),c==="keyring"&&(d.auth="keyring"),l&&(d.sessionDir=l),Object.keys(d).length||(console.log(h.red(" one of --token-env / --auth / --session-dir is required")),process.exit(1)),t.agents[e].integrations=t.agents[e].integrations??[],t.agents[e].integrations.find(u=>u.kind===i&&u.label===r)&&(console.log(h.red(` Integration (${i}, ${r}) already exists on ${e}`)),process.exit(1)),t.agents[e].integrations.push({kind:i,label:r,credentials:d,metadata:g,enabled:!0}),await Je(t),console.log(h.green(` \u2713 ${e}: added ${i} integration "${r}"`)),a&&!process.env[a]&&console.log(h.yellow(` \u26A0 env var ${a} is not set \u2014 set it on the daemon environment before use`))});Wn.command("remove <agentId> <kindOrLabel>").alias("rm").description("remove an integration (matched by kind, label, or 'kind:label')").action(async(e,o)=>{let t=me(),n=t.agents?.[e];n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let s=n.integrations??[],[i,r]=o.includes(":")?o.split(":",2):[o,""],a=s.findIndex(l=>l.kind===i&&(!r||l.label===r)||l.label===o);a===-1&&(console.log(h.red(` No integration matched "${o}"`)),process.exit(1));let c=s.splice(a,1)[0];await Je(t),console.log(h.green(` \u2713 removed ${c.kind} integration "${c.label}" from ${e}`))});Wn.command("test <agentId> [kindOrLabel]").description("validate env vars are set for one or all integrations on an agent").action(async(e,o)=>{let n=me().agents?.[e];n||(console.log(h.red(` Agent "${e}" not found`)),process.exit(1));let s=n.integrations??[],i=o?s.filter(a=>a.kind===o||a.label===o||`${a.kind}:${a.label}`===o):s;if(!i.length){console.log(h.yellow(" no integrations to test"));return}let r=0;console.log();for(let a of i){let c=a.credentials??{},l=[];for(let[g,d]of Object.entries(c))typeof d=="string"&&/^[A-Z][A-Z0-9_]*$/.test(d)&&!process.env[d]&&l.push(`${g}: env var ${d} is unset`);if(l.length){r+=1,console.log(` ${h.red("\u2717")} ${a.kind} "${a.label}"`);for(let g of l)console.log(` ${h.dim(g)}`)}else console.log(` ${h.green("\u2713")} ${a.kind} "${a.label}"`)}console.log(),r>0&&process.exit(1)});gt.addCommand(Wn);var Hs=new So().name("channel").description("manage channels \u2014 add telegram/whatsapp/gitlab, list");Hs.command("list").alias("ls").description("list configured channels and bindings").action(()=>{let e=me();console.log();let o=e.channels?.telegram;if(o?.enabled){console.log(h.bold(" Telegram:"));for(let[s,i]of Object.entries(o.accounts||{}))console.log(` ${h.cyan(s)} -> agent: ${i.agentBinding}`)}else console.log(h.dim(" Telegram: disabled"));let t=e.channels?.whatsapp;if(t?.enabled){console.log(h.bold(" WhatsApp:")),console.log(` default agent: ${t.defaultAgent||"(none)"}`),console.log(` session: ${t.sessionDir||".agentx/whatsapp-sessions"}`);for(let s of t.routes||[]){let i=s.contact?`contact ${s.contact}`:`group "${s.group}"`;console.log(` ${i} -> agent: ${s.agent}`)}}else console.log(h.dim(" WhatsApp: disabled"));let n=e.channels?.gitlab;if(n?.enabled){console.log(h.bold(" GitLab:")),console.log(` host: ${n.host}`),console.log(` webhook: :${n.webhookPort}`);for(let s of n.routes||[])console.log(` ${s.project} -> agent: ${s.agent}`)}else console.log(h.dim(" GitLab: disabled"));console.log()});Hs.command("add").description("add a channel (telegram, whatsapp, or gitlab)").action(async()=>{let e=me(),o=Object.keys(e.agents||{});if(!o.length){console.log(h.red(" No agents configured. Run: agentx agent add"));return}let t=o.map(s=>({title:`${s} (${e.agents[s].name})`,value:s})),{channelType:n}=await Me({type:"select",name:"channelType",message:"Channel type",choices:[{title:"Telegram \u2014 bot via BotFather token",value:"telegram"},{title:"WhatsApp \u2014 link via QR code (self-chat or contacts)",value:"whatsapp"},{title:"GitLab \u2014 webhook for issues, MRs, comments, pipelines",value:"gitlab"}]});if(n){if(e.channels=e.channels||{},n==="telegram"){let s=await Me([{type:"text",name:"accountName",message:"Account name (e.g. 'default', 'devops')"},{type:"text",name:"token",message:"Bot token (from @BotFather)"},{type:"select",name:"agentBinding",message:"Bind to agent",choices:t}]);if(!s.accountName||!s.token)return;try{let r=await(await fetch(`https://api.telegram.org/bot${s.token}/getMe`)).json();if(!r.ok)throw new Error(r.description);console.log(h.green(` Bot verified: @${r.result.username}`));let a=`@${r.result.username}`,c=e.agents[s.agentBinding].mentions||[];c.includes(a)||(c.push(a,r.result.username),e.agents[s.agentBinding].mentions=c)}catch(i){console.log(h.red(` Invalid token: ${i.message}`));return}e.channels.telegram=e.channels.telegram||{enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},e.channels.telegram.enabled=!0,e.channels.telegram.accounts[s.accountName]={token:s.token,agentBinding:s.agentBinding},await Je(e),console.log(h.green(` Telegram "${s.accountName}" added -> ${s.agentBinding}`))}if(n==="whatsapp"){let s=await Me([{type:"select",name:"defaultAgent",message:"Default agent for WhatsApp messages",choices:t},{type:"text",name:"sessionDir",message:"Session directory",initial:".agentx/whatsapp-sessions"},{type:"confirm",name:"addRoute",message:"Add a contact/group route?",initial:!0}]);if(!s.defaultAgent)return;let i=[],r=s.addRoute;for(;r;){let a=await Me([{type:"select",name:"type",message:"Route type",choices:[{title:"Contact (phone number)",value:"contact"},{title:"Group (name match)",value:"group"}]},{type:"text",name:"value",message:c=>c==="contact"?"Phone number (e.g. +10000000000)":"Group name (partial match)"},{type:"select",name:"agent",message:"Route to agent",choices:t},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);a.value&&a.agent&&i.push({[a.type]:a.value,agent:a.agent}),r=a.more}e.channels.whatsapp={enabled:!0,sessionDir:s.sessionDir,defaultAgent:s.defaultAgent,routes:i},await Je(e),xo(z(process.cwd(),s.sessionDir),{recursive:!0}),console.log(h.green(` WhatsApp enabled (${i.length} routes, default: ${s.defaultAgent})`)),console.log(h.dim(" Start daemon to scan QR code: agentx daemon start"))}if(n==="gitlab"){let s=await Me([{type:"text",name:"host",message:"GitLab instance URL",initial:"https://gitlab.example.com"},{type:"text",name:"token",message:"GitLab API token (PRIVATE-TOKEN)"},{type:"number",name:"webhookPort",message:"Webhook listen port",initial:18810},{type:"text",name:"webhookSecret",message:"Webhook secret (X-Gitlab-Token, optional)"},{type:"confirm",name:"addRoute",message:"Add a project route?",initial:!0}]);if(!s.token)return;let i=[],r=s.addRoute;for(;r;){let a=await Me([{type:"text",name:"project",message:"GitLab project path (e.g. group/project, or * for default)"},{type:"select",name:"agent",message:"Route to agent",choices:t},{type:"confirm",name:"more",message:"Add another route?",initial:!1}]);a.project&&a.agent&&i.push({project:a.project,agent:a.agent}),r=a.more}e.channels.gitlab={enabled:!0,host:s.host,token:s.token,webhookPort:s.webhookPort,webhookSecret:s.webhookSecret||void 0,routes:i},await Je(e),console.log(h.green(` GitLab enabled (${i.length} routes, webhook :${s.webhookPort})`)),console.log(h.dim(` Add webhook in GitLab: ${s.host}/<project>/-/hooks`)),console.log(h.dim(` URL: http://your-server:${s.webhookPort}/`)),s.webhookSecret&&console.log(h.dim(` Secret token: ${s.webhookSecret}`)),console.log(h.dim(" Events: Comments, Issues, Merge requests, Pipeline"))}console.log(h.dim(" Restart daemon to apply: agentx daemon stop && agentx daemon start")),console.log()}});var zt=new So().name("cron").description("manage cron jobs \u2014 add, list, enable, disable");zt.command("list").alias("ls").description("list cron jobs").action(()=>{let e=me();console.log();for(let[o,t]of Object.entries(e.crons||{})){let n=t.enabled?h.green("\u25CF"):h.dim("\u25CB");console.log(` ${n} ${h.cyan(o)} \u2014 ${t.schedule} (${t.timezone})`),console.log(h.dim(` agent: ${t.agent} | timeout: ${t.timeout}s`))}Object.keys(e.crons||{}).length||console.log(h.dim(" No cron jobs configured")),console.log()});zt.command("add").description("add a cron job").action(async()=>{let e=me(),o=Object.keys(e.agents||{}),t=await Me([{type:"text",name:"id",message:"Job ID (kebab-case)"},{type:"text",name:"schedule",message:"Cron expression (e.g. '0 9 * * *')"},{type:"text",name:"timezone",message:"Timezone",initial:"UTC"},{type:"select",name:"agent",message:"Agent",choices:o.map(n=>({title:n,value:n}))},{type:"text",name:"prompt",message:"Task prompt"},{type:"number",name:"timeout",message:"Timeout (seconds)",initial:600},{type:"confirm",name:"enabled",message:"Enable now?",initial:!1}]);!t.id||!t.schedule||(e.crons=e.crons||{},e.crons[t.id]={enabled:t.enabled,schedule:t.schedule,timezone:t.timezone,agent:t.agent,prompt:t.prompt,timeout:t.timeout,onError:["log"]},await Je(e),console.log(h.green(` Cron "${t.id}" added (${t.enabled?"enabled":"disabled"})`)),console.log())});zt.command("enable <id>").description("enable a cron job").action(async e=>{let o=me();if(!o.crons?.[e]){console.log(h.red(` Cron "${e}" not found`));return}if(o.crons[e].approval?.action==="create"){console.log(h.yellow(` Cron "${e}" is awaiting approval \u2014 run: agentx schedule approve ${e}`));return}o.crons[e].enabled=!0,await Je(o),console.log(h.green(` Cron "${e}" enabled`))});zt.command("disable <id>").description("disable a cron job").action(async e=>{let o=me();if(!o.crons?.[e]){console.log(h.red(` Cron "${e}" not found`));return}o.crons[e].enabled=!1,await Je(o),console.log(h.green(` Cron "${e}" disabled`))});var io=new So().name("mesh").description("manage mesh peers \u2014 add, list, remove");io.command("list").alias("ls").description("list mesh peers").action(async()=>{let e=me();if(console.log(),!e.mesh?.enabled)console.log(h.dim(" Mesh: disabled"));else{console.log(h.bold(" Mesh peers:"));for(let o of e.mesh.peers||[]){let t=h.red("unreachable");try{let s=await(await fetch(`${o.url}/health`,{signal:AbortSignal.timeout(3e3)})).json();t=h.green(`healthy \u2014 ${s.agents?.length||0} agents`)}catch{}console.log(` ${h.cyan(o.name)} ${h.dim(o.url)} ${t}`)}}console.log()});io.command("add").description("add a mesh peer (another agentx server)").action(async()=>{let e=me(),o=await Me([{type:"text",name:"name",message:"Peer name (e.g. 'server-2')"},{type:"text",name:"url",message:"Peer URL (e.g. 'http://100.64.0.11:18800')"},{type:"text",name:"token",message:"Auth token (optional, press enter to skip)"}]);if(!(!o.name||!o.url)){try{let n=await(await fetch(`${o.url}/.well-known/agent-card.json`,{signal:AbortSignal.timeout(5e3)})).json();console.log(h.green(` Connected: ${n.name} (${n.skills?.length||0} agents)`))}catch{console.log(h.yellow(" Could not reach peer (adding anyway)"))}e.mesh=e.mesh||{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},e.mesh.enabled=!0,e.mesh.peers=e.mesh.peers||[],e.mesh.peers.push({url:o.url,name:o.name,...o.token?{token:o.token}:{}}),await Je(e),console.log(h.green(` Peer "${o.name}" added`)),console.log()}});io.command("remove <name>").alias("rm").description("remove a mesh peer").action(async e=>{let o=me();o.mesh?.peers&&(o.mesh.peers=o.mesh.peers.filter(t=>t.name!==e),o.mesh.peers.length===0&&(o.mesh.enabled=!1),await Je(o),console.log(h.green(` Peer "${e}" removed`)))});io.command("health").description("tune mesh peer health checks (interval + timeout, in seconds)").option("--interval <s>","seconds between health probes (default 60)").option("--timeout <s>","per-probe timeout in seconds (default 10)").option("--show","just print the current values").action(async e=>{let o=me();if(o.mesh=o.mesh||{},o.mesh.healthCheck=o.mesh.healthCheck||{},e.show){console.log(` interval ${o.mesh.healthCheck.interval??60}s`),console.log(` timeout ${o.mesh.healthCheck.timeout??10}s`);return}let t=[];if(e.interval!==void 0){let n=parseInt(e.interval,10);(!Number.isFinite(n)||n<5||n>3600)&&(console.log(h.red(" --interval must be 5..3600 seconds")),process.exit(1)),o.mesh.healthCheck.interval=n,t.push(`interval=${n}s`)}if(e.timeout!==void 0){let n=parseInt(e.timeout,10);(!Number.isFinite(n)||n<1||n>60)&&(console.log(h.red(" --timeout must be 1..60 seconds")),process.exit(1)),o.mesh.healthCheck.timeout=n,t.push(`timeout=${n}s`)}t.length===0&&(console.log(h.yellow(" no changes \u2014 pass --interval and/or --timeout, or --show")),process.exit(1)),await Je(o),console.log(h.green(` \u2713 mesh.healthCheck: ${t.join(", ")}`)),console.log(h.dim(" Restart the daemon for the new cadence to take effect."))});io.command("announce <text...>").description("send a short note to every machine in the mesh (shown in event feeds)").option("--by <name>","who the note is from (an agent id or a person's name)").option("--node <url>","daemon to publish on (default: dashboard.daemonUrl, else this machine on port 18800)").option("--token <token>","mesh token, needed only when --node is another machine (default: MESH_TOKEN)").action(async(e,o)=>{let t=o.node||"";if(!t)try{t=T().dashboard?.daemonUrl||""}catch{}t=(t||"http://localhost:18800").replace(/\/+$/,"");let n=o.token||process.env.MESH_TOKEN||"",s={"Content-Type":"application/json"};n&&(s.Authorization=`Bearer ${n}`);try{let i=await fetch(`${t}/mesh/announce`,{method:"POST",headers:s,body:JSON.stringify({text:e.join(" "),...o.by?{by:o.by}:{}}),signal:AbortSignal.timeout(1e4)}),r=await i.json().catch(()=>({}));i.ok||(console.log(h.red(` Announcement refused (${i.status}): ${r.error||"unknown error"}`)),process.exit(1)),console.log(h.green(` \u2713 Announced from ${r.event?.node??"this machine"}`)+h.dim(` (event ${r.event?.id??"?"})`))}catch(i){console.log(h.red(` Could not reach the daemon at ${t}: ${i?.message||i}`)),process.exit(1)}});var Hd=e=>{let o=e||"";if(!o)try{o=T().dashboard?.daemonUrl||""}catch{}return(o||"http://localhost:18800").replace(/\/+$/,"")};async function Gs(e,o,t={}){let n=Hd(),s={"Content-Type":"application/json"};process.env.MESH_TOKEN&&(s.Authorization=`Bearer ${process.env.MESH_TOKEN}`);try{let i=await fetch(`${n}/mesh/guests/${encodeURIComponent(e)}/${o}`,{method:"POST",headers:s,body:JSON.stringify(t),signal:AbortSignal.timeout(15e3)}),r=await i.json().catch(()=>({}));i.ok||(console.log(h.red(` ${r.error||`HTTP ${i.status}`}`)),process.exit(1));let a=r.grant;console.log(h.green(` \u2713 ${a?.name??e}: ${a?.state}${r.stopped?`, ${r.stopped} running turn(s) stopped`:""}`))}catch(i){console.log(h.red(` Could not reach the daemon at ${n}: ${i?.message||i}. The daemon must be running: it stops the guest's running turns.`)),process.exit(1)}}var mt=io.command("guests").description("other organisations let into part of this mesh: open, watch, pause, widen, narrow, end");mt.command("invite").description("open a grant to a guest mesh and print the one-time code it joins with").requiredOption("--name <name>",'what you call it, e.g. "Support session for company X"').requiredOption("--guest <name>","the other organisation's name").requiredOption("--agent <id>","the agent of this node that works for them").option("--folders <list>","folders that agent may touch for them, comma-separated").option("--skills <list>","skills it may use for them, comma-separated").option("--commands <list>","commands it may run for them, comma-separated").option("--level <level>","report (read only) | propose (no merge, deploy or delete) | act","propose").option("--days <n>","how long the grant lasts (1 to 365)","7").option("--url <origin>","the address the guest reaches this node on (default: dashboard.daemonUrl)").action(async e=>{let{TokenStore:o}=await import("./token-store-YBSU2DTV.js"),{PairCodeStore:t,formatCode:n}=await import("./pair-codes-EYGELBPD.js"),{GuestStore:s}=await import("./store-7W2AP5H4.js"),{inviteGuest:i}=await import("./grants-BRAVOGBP.js"),r=T(),a=i({tokens:new o,codes:new t,guests:new s,hasAgent:l=>!!r.agents[l]},{name:e.name,guest:e.guest,agentId:e.agent,folders:e.folders?.split(","),skills:e.skills?.split(","),commands:e.commands?.split(","),level:e.level,days:Number(e.days)});a.ok||(console.log(h.red(` ${a.error}`)),process.exit(1));let c=(e.url||Hd()).replace(/\/+$/,"");console.log(),console.log(` Grant ${h.bold(a.grant.name)} for ${h.bold(a.grant.guest)}: ${a.grant.agentId}, ${a.grant.level}, until ${a.grant.expiresAt.slice(0,10)}`),console.log(h.dim(` id ${a.grant.id} \xB7 folders: ${a.grant.folders.join(", ")||"none"} \xB7 skills: ${a.grant.skills.join(", ")||"none"} \xB7 commands: ${a.grant.commands.join(", ")||"none"}`)),console.log(),console.log(" Send the guest this address and code. The code works once, for 10 minutes:"),console.log(),console.log(` ${h.cyan(c)}`),console.log(` ${h.bold(n(a.code))}`),console.log(),console.log(` They run: ${h.cyan(`agentx mesh join ${c} --code ${n(a.code)} --name <what-they-call-you>`)}`),console.log(` When they join, a card "Guest mesh: ${a.grant.guest} wants to join" asks you to approve it.`),console.log()});mt.command("list",{isDefault:!0}).alias("ls").description("every grant: state, guest, agent, level, end date, usage").option("--json","machine-readable output").action(async e=>{let{GuestStore:o}=await import("./store-7W2AP5H4.js"),t=new o().grants().sort((n,s)=>s.createdAt.localeCompare(n.createdAt));if(e.json){console.log(JSON.stringify(t,null,2));return}if(!t.length){console.log(h.dim(`
31
31
  No guest grants. Open one: agentx mesh guests invite --name \u2026 --guest \u2026 --agent \u2026
32
32
  `));return}console.log();for(let n of t){let s=n.state==="active"?h.green("active"):n.state==="pending"?h.yellow(n.guestNode?"waiting for your approval":"not joined yet"):n.state==="paused"?h.yellow("paused"):h.red(`ended${n.endedReason?`: ${n.endedReason}`:""}`);console.log(` ${h.cyan(n.id)} ${h.bold(n.name)} ${n.guest} \u2192 ${n.agentId} ${n.level} ${s}`),console.log(h.dim(` until ${n.expiresAt.slice(0,10)} \xB7 ${n.usage.turns} turn(s), ${n.usage.tokens} tokens${n.usage.lastAt?` \xB7 last ${n.usage.lastAt.slice(0,16).replace("T"," ")} UTC`:""}${n.guestNode?.name?` \xB7 node ${n.guestNode.name}`:""}`))}console.log()});mt.command("show <id>").description("one grant, what it opens and what the guest did").action(async e=>{let{GuestStore:o}=await import("./store-7W2AP5H4.js"),t=new o,n=t.get(e);n||(console.log(h.red(` No grant "${e}". See \`agentx mesh guests\`.`)),process.exit(1)),console.log(),console.log(` ${h.bold(n.name)} (${n.id}) \xB7 ${n.state}`),console.log(` guest: ${n.guest}${n.guestNode?` \xB7 node ${n.guestNode.name??n.guestNode.id??"?"} at ${n.guestNode.address??"?"}`:""}`),console.log(` agent: ${n.agentId} \xB7 level: ${n.level} \xB7 until ${n.expiresAt.slice(0,10)}`),console.log(` folders: ${n.folders.join(", ")||"none"}
33
33
  skills: ${n.skills.join(", ")||"none"}
@@ -453,7 +453,7 @@ return aid ?? null`}function py(e,o){if(e.kind==="path"){let s=e.pts,i=s[Math.fl
453
453
  Latest runs (${s.length})`),s.length===0&&console.log(B.dim(" nothing recorded yet"));for(let r of s){let a=r.status==="ok"?B.green("ok"):r.status==="in-flight"?B.yellow("running"):B.red(r.status);console.log(` ${B.dim(Om(r.startedAt))} ${(r.channel??"?").padEnd(9)} ${r.agentId} ${a} ${Cm(r.messagePreview)}`)}console.log()});us();su();import{Command as Cw}from"commander";import{existsSync as Iw}from"fs";import ye from"chalk";var an=new Cw("requests").description("what you asked agents for that is not finished, oldest first"),Dm={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 Zr(){if(!Iw(hc()))return console.error(ye.red(" no agentx.json here: run this from the install folder, the one that holds agentx.json")),process.exitCode=1,null;let e=qo();return e?new Ua(e):(process.exitCode=1,null)}var mi=e=>new Date(e).toISOString().slice(0,16).replace("T"," ")+" UTC";function Pm(e){let o=e.state==="needs_attention"?ye.red:e.state==="waiting_owner"?ye.yellow:ye.dim;console.log(` ${ye.cyan(e.id)} ${o(`[${Dm[e.state]??e.state}]`)} ${ye.dim(`${mi(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(ye.yellow(` Question: ${e.question}`)),e.state==="needs_attention"&&e.attentionReason&&console.log(ye.red(` ${e.attentionReason}`)),e.evidence&&console.log(ye.green(` Evidence: ${e.evidence}`)),e.closeReason&&console.log(ye.dim(` Reason: ${e.closeReason}`))}an.command("list",{isDefault:!0}).alias("ls").description("open requests, oldest first").option("--json","machine-readable output").action(e=>{let o=Zr();if(!o)return;let t=o.listOpen();if(e.json){console.log(JSON.stringify(t,null,2));return}if(zi().enabled||console.log(ye.dim(" requests are off: turn them on with `agentx requests settings --enabled on`")),t.length===0){console.log(ye.dim(" no open requests"));return}for(let n of t)Pm(n);console.log(ye.dim(`
454
454
  ${t.length} open. Close one: agentx requests done <id> --evidence <link> \xB7 agentx requests drop <id>`))});an.command("show <id>").description("one request and the runs, delegations and cards linked to it").action(e=>{let o=Zr();if(!o)return;let t=o.get(e);if(!t||t.state==="candidate"){console.error(ye.red(` no request "${e}"`)),process.exitCode=1;return}Pm(t),console.log(ye.dim(` Last activity ${mi(t.updatedAt)}${t.closedAt?` \xB7 closed ${mi(t.closedAt)}`:""}`));for(let n of o.links(e))console.log(ye.dim(` ${n.kind} ${n.ref} (${mi(n.at)})`))});function Mm(e,o,t,n){an.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=Zr();if(!r)return;let a=e==="done"?i.evidence:i.reason??"dropped by the owner";if(!a){console.error(ye.red(` ${n}`)),process.exitCode=1;return}let c=r.get(s);if(!c||c.state==="candidate"){console.error(ye.red(` no request "${s}"`)),process.exitCode=1;return}if(!r.close(s,e==="done"?"done":"dropped",a,Date.now())){console.error(ye.red(` ${s} is already closed (${Dm[c.state]??c.state})`)),process.exitCode=1;return}console.log(ye.green(` \u2713 ${s} ${e==="done"?"closed as done":"dropped"}`))})}Mm("done","close a request as finished, with a link to the evidence","--evidence <link>","a finished request needs --evidence <link>");Mm("drop","drop a request you no longer want","--reason <text>","");an.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(ye.red(` ${n.message}`)),process.exitCode=1;return}if(Object.values(o).some(n=>n!==void 0)){let n=await ll(o);if(!n.success){console.error(ye.red(` ${n.error}`)),process.exitCode=1;return}console.log(ye.green(" \u2713 saved")+(n.reloaded?ye.dim(" (daemon reloaded)"):""))}let t=zi();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 Nw}from"commander";import cn from"chalk";te();var Lm=new Nw("request-status").description("show each person the state of their request in the thread where they asked (GitLab, GitHub)").argument("[channel]",rr.join(" or ")).argument("[state]","on or off").action(async(e,o)=>{if(e!==void 0){o!=="on"&&o!=="off"&&(console.error(cn.red("\u2717 say on or off, for example: agentx request-status gitlab on")),process.exit(1));let n="",s=await re(i=>{n=ld(i,e,o==="on")});s.success||(console.error(cn.red(`\u2717 ${s.error}`)),process.exit(1)),console.log(cn.green(`\u2713 ${n}`)),s.reloaded&&console.log(cn.dim(" daemon hot-reloaded"))}let t=T().requestStatus.channels.map(n=>n.toLowerCase());for(let n of rr)console.log(` ${n.padEnd(8)} ${t.includes(n)?cn.green("on"):cn.dim("off")}`)});import{Command as o$}from"commander";import ln from"chalk";import ce from"chalk";import es from"prompts";import{readFileSync as Rw,writeFileSync as _w,existsSync as Dw}from"fs";import{resolve as qm}from"path";var Pw=/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;function Mw(e){let o=e.trim();return o.startsWith('"')&&o.endsWith('"')||o.startsWith("'")&&o.endsWith("'")?o.slice(1,-1):o}function ea(e){return/[\s#"'\\]/.test(e)||e===""?JSON.stringify(e):e}function Fm(e=".env"){let o=qm(e);if(!Dw(o))return[];let t=Rw(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(Pw);i?n.push({kind:"kv",key:i[1],value:Mw(i[2]),raw:s}):n.push({kind:"comment",raw:s})}return n.length&&n[n.length-1].kind==="blank"&&n.pop(),n}function Lw(e){return e.map(o=>o.kind==="kv"?`${o.key}=${ea(o.value)}`:o.raw).join(`
455
455
  `)+`
456
- `}function Zn(e,o,t=".env"){let n=qm(t),s=Fm(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${ea(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${ea(o)}`})),_w(n,Lw(s))}function oa(e,o=".env"){return Fm(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var Um="https://t.me/BotFather";async function qw(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 Fw(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 Wm(e={}){console.log(),console.log(ce.bold(" Connect Telegram")),console.log(),console.log(ce.dim(` 1. Open ${Um}`)),console.log(ce.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ce.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:o}=await es({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});o&&dt(Um);let{token:t}=await es({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:k=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(k.trim())||"That doesn't look like a Telegram token"});t||(console.log(ce.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await qw(t.trim());n||(console.log(ce.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ce.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(ce.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(ce.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await es({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map($=>({title:$,value:$})),initial:0})).agent),g||(console.log(ce.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},u=e.account||g;d[u]&&d[u].agentBinding!==g&&(u=(await es({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(ce.red(" Aborted")),process.exit(1));let f=`TG_${u.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Zn(f,t.trim()),process.env[f]=t.trim();let p=await re(k=>{Ie(k,"channels.telegram.enabled",!0),Ie(k,`channels.telegram.accounts.${u}`,{token:`\${${f}}`,agentBinding:g});let $=Pt(k,`agents.${g}.mentions`)||[],E=`@${n.username}`;$.includes(E)||($.push(E),Ie(k,`agents.${g}.mentions`,$))},{configPath:e.configPath});if(p.success||(console.log(ce.red(` \u2717 ${p.error}`)),process.exit(1)),console.log(),console.log(ce.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ce.dim(` Token stored in .env as ${f}`)),console.log(ce.dim(` Mentions updated to include @${n.username}`)),p.reloaded?console.log(ce.dim(" Daemon hot-reloaded.")):console.log(ce.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:y}=await es({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(ce.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ce.dim(" Waiting up to 90s..."));let w=await Fw(t.trim(),9e4);if(!w){console.log(ce.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ce.dim(" agentx config set notifications.destination.channel telegram")),console.log(ce.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ce.dim(` agentx config set notifications.destination.accountId ${u}`));return}let b=await re(k=>{Ie(k,"notifications.destination",{channel:"telegram",chatId:String(w.chatId),accountId:u})},{configPath:e.configPath});if(!b.success){console.log(ce.red(` \u2717 failed to save destination: ${b.error}`));return}console.log(ce.green(" \u2713 Default --notify target set")),console.log(ce.dim(` Chat: ${w.chatTitle||w.chatId} (from ${w.from})`)),console.log(ce.dim(" From now on, --notify me resolves to this chat.")),b.reloaded&&console.log(ce.dim(" Daemon hot-reloaded."))}import ve from"chalk";import ta from"prompts";import{existsSync as sa,mkdirSync as Uw,readdirSync as Ww,readFileSync as Bm}from"fs";import{resolve as na}from"path";var Bw=".agentx/whatsapp-sessions";function Jw(){let e=na(process.cwd(),".agentx/daemon.pid");if(!sa(e))return!1;try{let o=parseInt(Bm(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function Hw(e){if(!sa(e))return!1;try{return Ww(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function Gw(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;Uw(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 Jm(e={}){if(console.log(),console.log(ve.bold(" Connect WhatsApp")),console.log(),Jw()){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 ta({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(ve.red(" Aborted")),process.exit(1))}let o=e.configPath||na(process.cwd(),"agentx.json");sa(o)||(console.log(ve.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(Bm(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||Bw,s=na(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 ta({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(Hw(s)&&a){let{keep:l}=await ta({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 Gw(s,g=>console.log(g))||(console.log(ve.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await re(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 zw}from"crypto";import je from"chalk";import Hm from"prompts";var pi="agentx-mesh:",ui="//join/";function Yw(e){return Buffer.from(e,"utf-8").toString("base64url")}function Vw(e){return Buffer.from(e,"base64url").toString("utf-8")}function Xw(e){return`${pi}${ui}${Yw(JSON.stringify(e))}`}function Kw(e){if(!e.startsWith(`${pi}${ui}`))throw new Error(`Not a mesh invite link \u2014 expected ${pi}${ui}\u2026`);let o=e.slice(pi.length+ui.length),t=JSON.parse(Vw(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 Qw(){return zw(32).toString("hex")}function Zw(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function e$(e){return e?.node?.name||e?.node?.id||"node"}async function Gm(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=oa("MESH_TOKEN");r||(r=Qw(),Zn("MESH_TOKEN",r),console.log(je.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||Zw(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 re(d=>{Ie(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(je.red(` \u2717 ${l.error}`)),process.exit(1));let g=Xw({url:a,token:r,name:e$(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 zm(e,o={}){let t;try{t=Kw(e)}catch(i){console.log(je.red(` \u2717 ${i.message}`)),process.exit(1)}let n=oa("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))}Zn("MESH_TOKEN",t.token);let s=await re(i=>{Ie(i,"mesh.enabled",!0);let r=Pt(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 dn=new o$().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");dn.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 Wm({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});dn.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 Jm({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var Ym=dn.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");Ym.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 Gm({url:e.url,configPath:e.config})});Ym.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 zm(e,{configPath:o.config})});dn.action(()=>{console.log(),console.log(ln.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${ln.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${ln.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${ln.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${ln.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(ln.dim(" GitLab connect is the next slice.")),console.log()});te();import{Command as t$}from"commander";import X from"chalk";var vt=new t$().name("usage").description("token usage analysis and reporting");vt.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(X.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(X.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${X.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: ${X.red(String(s.totalErrors))}`),console.log(),console.log(X.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(` ${X.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${X.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(X.red(" Daemon not running. Start with: agentx daemon start")):console.log(X.red(` ${e.message}`))}});vt.command("plan").description("show the Claude plan windows as Claude Code last reported them, and any hold on fresh sessions").option("--lift","lift the hold on fresh sessions now, without waiting for the reset time").option("--json","raw JSON output").action(async e=>{try{let o=T(),[t,n]=o.node.bind.split(":"),s=`http://${t||"127.0.0.1"}:${n}`,i=e.lift?await fetch(`${s}/usage/plan/lift`,{method:"POST",signal:AbortSignal.timeout(3e3)}):await fetch(`${s}/usage/plan`,{signal:AbortSignal.timeout(3e3)});if(!i.ok)throw new Error(`Daemon answered ${i.status}. It may be older than this command; restart it.`);let r=await i.json();if(e.json){console.log(JSON.stringify(r,null,2));return}let a=d=>d.replace(/_/g," ");if(console.log(),e.lift){let d=r.lifted.map(u=>a(u.window));console.log(d.length?` Lifted the hold on: ${d.join(", ")}. The next fresh session asks Claude again.`:X.dim(" No hold to lift.")),console.log();return}let c=r.now,l=new Set(r.holds.map(d=>d.window));console.log(X.bold(" Claude plan (as Claude Code last reported it)")),console.log(),r.provider.length===0&&console.log(X.dim(" No report yet. Claude Code reports on each turn; the list is empty after a daemon restart."));for(let d of r.provider){let u=d.usingOverage?"extra usage":d.status==="allowed_warning"?"nearly full":d.status,f=typeof d.utilization=="number"?`${Math.round(d.utilization*100)}% used`:"",p=Math.max(1,Math.round((d.resetsAt-c)/6e4)),y=d.resetsAt>c?p<60?`resets in ${p} min`:p<48*60?`resets in ${Math.round(p/60)} h`:`resets in ${Math.round(p/1440)} days`:"",w=l.has(d.window)?X.red("holding fresh sessions"):"";console.log(` ${a(d.window).padEnd(18)} ${u.padEnd(12)} ${[f,y,w].filter(Boolean).join(", ")}`)}console.log();let g=d=>d?` of ${d}`:"";console.log(` Fresh sessions started: ${r.lastHour}${g(r.maxPerHour)} in the last hour, ${r.last5h}${g(r.maxPer5h)} in the last 5 hours`),l.size&&console.log(X.dim(" To try again now: agentx usage plan --lift")),console.log()}catch(o){o.cause?.code==="ECONNREFUSED"?console.log(X.red(" Daemon not running. Start with: agentx daemon start")):console.log(X.red(` ${o.message}`))}});vt.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(X.red(` Script not found: ${s}`)),console.log(X.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(X.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(X.red(" Analysis failed. Is Python 3 installed?"))}});vt.command("channels").description("cost per channel over a fixed range of days, next to a saved baseline").requiredOption("--from <date>","first day, YYYY-MM-DD").requiredOption("--to <date>","last day, YYYY-MM-DD").option("--save <file>","write this range's figures to a JSON file").option("--baseline <file>","a file written by --save, shown beside this range").option("--json","raw JSON output").action(async e=>{let{readFileSync:o,writeFileSync:t}=await import("fs"),{TokenTracker:n}=await import("./token-tracker-W7DFDEFN.js"),{channelCosts:s,costPerTask:i}=await import("./usage-channels-KBLEC4NE.js"),r=p=>/^\d{4}-\d{2}-\d{2}$/.test(p)&&!Number.isNaN(Date.parse(p));if(!r(e.from)||!r(e.to)||e.from>e.to){console.log(X.red(" --from and --to must be YYYY-MM-DD, with --from not after --to")),process.exitCode=1;return}let a=s(new n,e.from,e.to);e.save&&t(e.save,JSON.stringify(a,null,2));let c=null;if(e.baseline)try{c=JSON.parse(o(e.baseline,"utf-8"))}catch(p){console.log(X.red(` Cannot read baseline ${e.baseline}: ${p.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify(c?{baseline:c,current:a}:a,null,2));return}let l=p=>p===null?"-":`$${p.toFixed(p<10?3:2)}`,g=p=>`${(p/1e6).toFixed(1)}M`;console.log(),console.log(X.bold(` Cost per channel, ${a.from} to ${a.to} (${a.days} day(s) with data)`)),c&&console.log(X.dim(` Baseline: ${c.from} to ${c.to} (${c.days} day(s) with data)`)),console.log();let d=` ${"channel".padEnd(14)} ${"tasks".padStart(6)} ${"cache read".padStart(11)} ${"cache write".padStart(11)} ${"output".padStart(8)} ${"cost".padStart(10)} ${"per task".padStart(9)}`;console.log(X.dim(c?`${d} ${"baseline".padStart(9)} ${"change".padStart(7)}`:d));let f=[...new Set([...Object.keys(a.channels),...Object.keys(c?.channels||{})])].map(p=>[p,a.channels[p],c?.channels[p]]).sort((p,y)=>(y[1]?.cost||0)-(p[1]?.cost||0));f.push(["TOTAL",a.total,c?.total]);for(let[p,y,w]of f){let b=i(y),k=` ${p.padEnd(14)} ${String(y?.tasks||0).padStart(6)} ${g(y?.cacheRead||0).padStart(11)} ${g(y?.cacheCreate||0).padStart(11)} ${g(y?.output||0).padStart(8)} ${l(y?.cost||0).padStart(10)} ${l(b).padStart(9)}`;if(c){let $=i(w),E=b!==null&&$?`${((b-$)/$*100).toFixed(0)}%`:"-";k+=` ${l($).padStart(9)} ${E.padStart(7)}`}console.log(k)}console.log(),c&&console.log(X.dim(" change = cost per task against the baseline; the two ranges do not have the same tasks.")),e.save&&console.log(X.dim(` Saved ${e.save}`)),console.log()});vt.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-HCJTUS6Z.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-EZLJIVQX.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(X.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${X.dim("\xB7")} ${d}`);console.log(),console.log(X.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(X.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(X.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(X.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(X.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(X.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=X.dim(`${i.days}d`);console.log(` ${X.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(X.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as n$}from"commander";import xe from"chalk";import{readFileSync as s$}from"fs";import{resolve as i$}from"path";te();var ot=new n$().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");ot.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{ec(i$(process.cwd(),".env"))}catch{}let o=r$(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-3TVUCOSI.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 r$(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.
456
+ `}function Zn(e,o,t=".env"){let n=qm(t),s=Fm(n),i=s.findIndex(r=>r.kind==="kv"&&r.key===e);i>=0?s[i]={kind:"kv",key:e,value:o,raw:`${e}=${ea(o)}`}:(s.length&&s[s.length-1].kind!=="blank"&&s.push({kind:"blank",raw:""}),s.push({kind:"kv",key:e,value:o,raw:`${e}=${ea(o)}`})),_w(n,Lw(s))}function oa(e,o=".env"){return Fm(o).find(s=>s.kind==="kv"&&s.key===e)?.value}var Um="https://t.me/BotFather";async function qw(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 Fw(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 Wm(e={}){console.log(),console.log(ce.bold(" Connect Telegram")),console.log(),console.log(ce.dim(` 1. Open ${Um}`)),console.log(ce.dim(" /newbot (or /mybots \u2192 pick existing \u2192 API Token)")),console.log(ce.dim(" 2. Copy the HTTP API token \u2014 looks like 123456789:ABCdef...")),console.log();let{wantsBrowser:o}=await es({type:"confirm",name:"wantsBrowser",message:"Open BotFather in your browser?",initial:!0});o&&dt(Um);let{token:t}=await es({type:"password",name:"token",message:"Paste the bot token from BotFather:",validate:k=>/^\d+:[A-Za-z0-9_-]{20,}$/.test(k.trim())||"That doesn't look like a Telegram token"});t||(console.log(ce.red(" Aborted")),process.exit(1)),process.stdout.write(" Verifying token... ");let n=await qw(t.trim());n||(console.log(ce.red("\u2717 invalid or revoked")),process.exit(1)),console.log(ce.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(ce.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(ce.red(" No agents configured. Run: agentx agent add")),process.exit(1));let g=e.agent;g||(g=(await es({type:"select",name:"agent",message:"Bind this bot to which agent?",choices:l.map($=>({title:$,value:$})),initial:0})).agent),g||(console.log(ce.red(" Aborted")),process.exit(1));let d=c.channels?.telegram?.accounts||{},u=e.account||g;d[u]&&d[u].agentBinding!==g&&(u=(await es({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(ce.red(" Aborted")),process.exit(1));let f=`TG_${u.toUpperCase().replace(/-/g,"_")}_BOT_TOKEN`;Zn(f,t.trim()),process.env[f]=t.trim();let p=await re(k=>{Ie(k,"channels.telegram.enabled",!0),Ie(k,`channels.telegram.accounts.${u}`,{token:`\${${f}}`,agentBinding:g});let $=Pt(k,`agents.${g}.mentions`)||[],E=`@${n.username}`;$.includes(E)||($.push(E),Ie(k,`agents.${g}.mentions`,$))},{configPath:e.configPath});if(p.success||(console.log(ce.red(` \u2717 ${p.error}`)),process.exit(1)),console.log(),console.log(ce.green(` \u2713 Bot @${n.username} bound to agent "${g}"`)),console.log(ce.dim(` Token stored in .env as ${f}`)),console.log(ce.dim(` Mentions updated to include @${n.username}`)),p.reloaded?console.log(ce.dim(" Daemon hot-reloaded.")):console.log(ce.dim(" Start the daemon to begin polling (agentx daemon start)")),e.skipChatCapture)return;console.log();let{capture:y}=await es({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(ce.dim(` Send any message to @${n.username} from the chat you want to use.`)),console.log(ce.dim(" Waiting up to 90s..."));let w=await Fw(t.trim(),9e4);if(!w){console.log(ce.yellow(" No message received \u2014 skipping. You can set it later with:")),console.log(ce.dim(" agentx config set notifications.destination.channel telegram")),console.log(ce.dim(" agentx config set notifications.destination.chatId <chatId>")),console.log(ce.dim(` agentx config set notifications.destination.accountId ${u}`));return}let b=await re(k=>{Ie(k,"notifications.destination",{channel:"telegram",chatId:String(w.chatId),accountId:u})},{configPath:e.configPath});if(!b.success){console.log(ce.red(` \u2717 failed to save destination: ${b.error}`));return}console.log(ce.green(" \u2713 Default --notify target set")),console.log(ce.dim(` Chat: ${w.chatTitle||w.chatId} (from ${w.from})`)),console.log(ce.dim(" From now on, --notify me resolves to this chat.")),b.reloaded&&console.log(ce.dim(" Daemon hot-reloaded."))}import ve from"chalk";import ta from"prompts";import{existsSync as sa,mkdirSync as Uw,readdirSync as Ww,readFileSync as Bm}from"fs";import{resolve as na}from"path";var Bw=".agentx/whatsapp-sessions";function Jw(){let e=na(process.cwd(),".agentx/daemon.pid");if(!sa(e))return!1;try{let o=parseInt(Bm(e,"utf-8").trim(),10);return o?(process.kill(o,0),!0):!1}catch{return!1}}function Hw(e){if(!sa(e))return!1;try{return Ww(e).some(o=>o.includes("creds")||o.endsWith(".json"))}catch{return!1}}async function Gw(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;Uw(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 Jm(e={}){if(console.log(),console.log(ve.bold(" Connect WhatsApp")),console.log(),Jw()){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 ta({type:"confirm",name:"cont",message:"Continue anyway? (expect errors)",initial:!1});l||(console.log(ve.red(" Aborted")),process.exit(1))}let o=e.configPath||na(process.cwd(),"agentx.json");sa(o)||(console.log(ve.red(` No agentx.json at ${o}. Run: agentx init`)),process.exit(1));let t=JSON.parse(Bm(o,"utf-8")),n=e.sessionDir||t.channels?.whatsapp?.sessionDir||Bw,s=na(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 ta({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(Hw(s)&&a){let{keep:l}=await ta({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 Gw(s,g=>console.log(g))||(console.log(ve.red(" Pairing failed. You can retry with `agentx connect whatsapp`.")),process.exit(1)));let c=await re(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 zw}from"crypto";import je from"chalk";import Hm from"prompts";var pi="agentx-mesh:",ui="//join/";function Yw(e){return Buffer.from(e,"utf-8").toString("base64url")}function Vw(e){return Buffer.from(e,"base64url").toString("utf-8")}function Xw(e){return`${pi}${ui}${Yw(JSON.stringify(e))}`}function Kw(e){if(!e.startsWith(`${pi}${ui}`))throw new Error(`Not a mesh invite link \u2014 expected ${pi}${ui}\u2026`);let o=e.slice(pi.length+ui.length),t=JSON.parse(Vw(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 Qw(){return zw(32).toString("hex")}function Zw(e){let o=e?.node?.bind||"127.0.0.1:18800",[t,n]=o.split(":");return`http://${t}:${n}`}function e$(e){return e?.node?.name||e?.node?.id||"node"}async function Gm(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=oa("MESH_TOKEN");r||(r=Qw(),Zn("MESH_TOKEN",r),console.log(je.dim(" Generated new MESH_TOKEN (32 bytes) and saved to .env")));let a=e.url||Zw(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 re(d=>{Ie(d,"mesh.enabled",!0)},{configPath:e.configPath});l.success||(console.log(je.red(` \u2717 ${l.error}`)),process.exit(1));let g=Xw({url:a,token:r,name:e$(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 zm(e,o={}){let t;try{t=Kw(e)}catch(i){console.log(je.red(` \u2717 ${i.message}`)),process.exit(1)}let n=oa("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))}Zn("MESH_TOKEN",t.token);let s=await re(i=>{Ie(i,"mesh.enabled",!0);let r=Pt(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 dn=new o$().name("connect").description("connect a channel or mesh peer \u2014 no manual file editing required");dn.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 Wm({agent:e.agent,account:e.account,configPath:e.config,skipChatCapture:!!e.skipChatCapture})});dn.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 Jm({agent:e.agent,sessionDir:e.sessionDir,skipPair:!!e.skipPair,configPath:e.config})});var Ym=dn.command("mesh").description("mesh invite + join \u2014 replaces manual MESH_TOKEN copy-paste");Ym.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 Gm({url:e.url,configPath:e.config})});Ym.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 zm(e,{configPath:o.config})});dn.action(()=>{console.log(),console.log(ln.bold(" agentx connect \u2014 which channel?")),console.log(),console.log(` ${ln.cyan("agentx connect telegram")} \u2014 pair a Telegram bot`),console.log(` ${ln.cyan("agentx connect whatsapp")} \u2014 pair WhatsApp via QR`),console.log(` ${ln.cyan("agentx connect mesh invite")} \u2014 emit a mesh join link for another node`),console.log(` ${ln.cyan("agentx connect mesh join <link>")} \u2014 accept a mesh invite`),console.log(),console.log(ln.dim(" GitLab connect is the next slice.")),console.log()});te();import{Command as t$}from"commander";import X from"chalk";var vt=new t$().name("usage").description("token usage analysis and reporting");vt.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(X.bold(" Token Usage (last 7 days)")),console.log(),s.totalTasks===0){console.log(X.dim(" No tasks recorded yet")),console.log();return}let i=a=>a.toLocaleString();console.log(` Total: ${X.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: ${X.red(String(s.totalErrors))}`),console.log(),console.log(X.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(` ${X.cyan(a)}: ${l} tokens (${c.tasks} tasks) ${X.dim(g)}`)}console.log()}catch(e){e.cause?.code==="ECONNREFUSED"?console.log(X.red(" Daemon not running. Start with: agentx daemon start")):console.log(X.red(` ${e.message}`))}});vt.command("plan").description("show the Claude plan windows as Claude Code last reported them, and any hold on fresh sessions").option("--lift","lift the hold on fresh sessions now, without waiting for the reset time").option("--json","raw JSON output").action(async e=>{try{let o=T(),[t,n]=o.node.bind.split(":"),s=`http://${t||"127.0.0.1"}:${n}`,i=e.lift?await fetch(`${s}/usage/plan/lift`,{method:"POST",signal:AbortSignal.timeout(3e3)}):await fetch(`${s}/usage/plan`,{signal:AbortSignal.timeout(3e3)});if(!i.ok)throw new Error(`Daemon answered ${i.status}. It may be older than this command; restart it.`);let r=await i.json();if(e.json){console.log(JSON.stringify(r,null,2));return}let a=d=>d.replace(/_/g," ");if(console.log(),e.lift){let d=r.lifted.map(u=>a(u.window));console.log(d.length?` Lifted the hold on: ${d.join(", ")}. The next fresh session asks Claude again.`:X.dim(" No hold to lift.")),console.log();return}let c=r.now,l=new Set(r.holds.map(d=>d.window));console.log(X.bold(" Claude plan (as Claude Code last reported it)")),console.log(),r.provider.length===0&&console.log(X.dim(" No report yet. Claude Code reports on each turn; the list is empty after a daemon restart."));for(let d of r.provider){let u=d.usingOverage?"extra usage":d.status==="allowed_warning"?"nearly full":d.status,f=typeof d.utilization=="number"?`${Math.round(d.utilization*100)}% used`:"",p=Math.max(1,Math.round((d.resetsAt-c)/6e4)),y=d.resetsAt>c?p<60?`resets in ${p} min`:p<48*60?`resets in ${Math.round(p/60)} h`:`resets in ${Math.round(p/1440)} days`:"",w=l.has(d.window)?X.red("holding fresh sessions"):"";console.log(` ${a(d.window).padEnd(18)} ${u.padEnd(12)} ${[f,y,w].filter(Boolean).join(", ")}`)}console.log();let g=d=>d?` of ${d}`:"";console.log(` Fresh sessions started: ${r.lastHour}${g(r.maxPerHour)} in the last hour, ${r.last5h}${g(r.maxPer5h)} in the last 5 hours`),l.size&&console.log(X.dim(" To try again now: agentx usage plan --lift")),console.log()}catch(o){o.cause?.code==="ECONNREFUSED"?console.log(X.red(" Daemon not running. Start with: agentx daemon start")):console.log(X.red(` ${o.message}`))}});vt.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(X.red(` Script not found: ${s}`)),console.log(X.dim(" The token analyzer script should be at scripts/token-report.py"));return}console.log(X.dim(" Analyzing Claude Code sessions..."));try{o(`SINCE_DAYS=${e.days} python3 "${s}"`,{stdio:"inherit"})}catch{console.log(X.red(" Analysis failed. Is Python 3 installed?"))}});vt.command("channels").description("cost per channel over a fixed range of days, next to a saved baseline").requiredOption("--from <date>","first day, YYYY-MM-DD").requiredOption("--to <date>","last day, YYYY-MM-DD").option("--save <file>","write this range's figures to a JSON file").option("--baseline <file>","a file written by --save, shown beside this range").option("--json","raw JSON output").action(async e=>{let{readFileSync:o,writeFileSync:t}=await import("fs"),{TokenTracker:n}=await import("./token-tracker-W7DFDEFN.js"),{channelCosts:s,costPerTask:i}=await import("./usage-channels-KBLEC4NE.js"),r=p=>/^\d{4}-\d{2}-\d{2}$/.test(p)&&!Number.isNaN(Date.parse(p));if(!r(e.from)||!r(e.to)||e.from>e.to){console.log(X.red(" --from and --to must be YYYY-MM-DD, with --from not after --to")),process.exitCode=1;return}let a=s(new n,e.from,e.to);e.save&&t(e.save,JSON.stringify(a,null,2));let c=null;if(e.baseline)try{c=JSON.parse(o(e.baseline,"utf-8"))}catch(p){console.log(X.red(` Cannot read baseline ${e.baseline}: ${p.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify(c?{baseline:c,current:a}:a,null,2));return}let l=p=>p===null?"-":`$${p.toFixed(p<10?3:2)}`,g=p=>`${(p/1e6).toFixed(1)}M`;console.log(),console.log(X.bold(` Cost per channel, ${a.from} to ${a.to} (${a.days} day(s) with data)`)),c&&console.log(X.dim(` Baseline: ${c.from} to ${c.to} (${c.days} day(s) with data)`)),console.log();let d=` ${"channel".padEnd(14)} ${"tasks".padStart(6)} ${"cache read".padStart(11)} ${"cache write".padStart(11)} ${"output".padStart(8)} ${"cost".padStart(10)} ${"per task".padStart(9)}`;console.log(X.dim(c?`${d} ${"baseline".padStart(9)} ${"change".padStart(7)}`:d));let f=[...new Set([...Object.keys(a.channels),...Object.keys(c?.channels||{})])].map(p=>[p,a.channels[p],c?.channels[p]]).sort((p,y)=>(y[1]?.cost||0)-(p[1]?.cost||0));f.push(["TOTAL",a.total,c?.total]);for(let[p,y,w]of f){let b=i(y),k=` ${p.padEnd(14)} ${String(y?.tasks||0).padStart(6)} ${g(y?.cacheRead||0).padStart(11)} ${g(y?.cacheCreate||0).padStart(11)} ${g(y?.output||0).padStart(8)} ${l(y?.cost||0).padStart(10)} ${l(b).padStart(9)}`;if(c){let $=i(w),E=b!==null&&$?`${((b-$)/$*100).toFixed(0)}%`:"-";k+=` ${l($).padStart(9)} ${E.padStart(7)}`}console.log(k)}console.log(),c&&console.log(X.dim(" change = cost per task against the baseline; the two ranges do not have the same tasks.")),e.save&&console.log(X.dim(` Saved ${e.save}`)),console.log()});vt.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-HCJTUS6Z.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-YK3YR2CQ.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(X.bold(` Never used in the last ${e.days} days (${g.length}/${c.length})`)),console.log();for(let d of g)console.log(` ${X.dim("\xB7")} ${d}`);console.log(),console.log(X.dim(" Zero use is necessary but not sufficient to remove a surface \u2014")),console.log(X.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(X.dim(` No surface usage recorded in the last ${e.days} days.`)),console.log(X.dim(" Counting starts once this build has been running for a while.")),console.log();return}console.log(),console.log(X.bold(` Surface usage \u2014 last ${e.days} days`)),console.log();let s="";for(let i of n){i.kind!==s&&(console.log(X.dim(` ${i.kind==="cli"?"CLI commands":"Dashboard pages"}`)),s=i.kind);let r=String(i.count).padStart(6),a=X.dim(`${i.days}d`);console.log(` ${X.cyan(r)} ${i.name.padEnd(28)} ${a}`)}console.log(),console.log(X.dim(` ${n.length} surface(s) with recorded use. See --unused for the rest.`)),console.log()});import{Command as n$}from"commander";import xe from"chalk";import{readFileSync as s$}from"fs";import{resolve as i$}from"path";te();var ot=new n$().name("board").description("kanban board dashboard \u2014 visual work view over configured sources");ot.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{ec(i$(process.cwd(),".env"))}catch{}let o=r$(e.port,e.bind),{startBoardDashboard:t}=await import("./board-dashboard-MZVUQ2YO.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 r$(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.
457
457
  `)),{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}}}}ot.command("list").description("list configured boards").action(()=>{try{let e=T();if(!e.boards?.length){console.log(xe.dim(`
458
458
  No boards configured.
459
459
  `));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)}});ot.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{os(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)}});ot.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{os(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 ia=ot.command("column").description("manage a board's columns (add / remove / edit / list)");ia.command("list <boardId>").description("list columns on a board, in order").action(e=>{try{let t=(JSON.parse(s$("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)}});ia.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{os(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)}});ia.command("remove <boardId> <columnId>").alias("rm").description("remove a column from a board").action((e,o)=>{try{os(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)}});ot.command("remove <id>").alias("rm").description("remove a board from agentx.json").action(e=>{try{os(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 os(e){let{summary:o,backupPath:t}=so(n=>e(n));console.log(xe.green(`
@@ -680,7 +680,7 @@ Restart the daemon to activate.
680
680
  dist/
681
681
  *.log
682
682
  .env
683
- `}import{Command as Kb}from"commander";import Pe from"chalk";import{writeFileSync as Qb,mkdirSync as Zb,existsSync as Ii,readFileSync as Bp,appendFileSync as Jp}from"fs";import{resolve as xn,dirname as zp}from"path";import{homedir as ja}from"os";var Yp=new Kb().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-EZLJIVQX.js"),t=await o(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=tk(t);break;case"bash":s=ak(t);break;case"fish":s=ck(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?xn(String(e.output)):ek(n);Zb(zp(i),{recursive:!0}),Qb(i,s),console.log(Pe.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${i}`),console.log(),ok(n,i,!!e.yes)});function ek(e){let o=ja();switch(e){case"zsh":return xn(o,".zsh","completions","_agentx");case"bash":return xn(o,".bash_completion.d","agentx.bash");case"fish":return xn(o,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function ok(e,o,t){if(e==="zsh"){let n=xn(ja(),".zshrc"),s=zp(o),i=`fpath=(${s} $fpath)`,r="autoload -U compinit && compinit",a=Ii(n)?Bp(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&&Ii(n)){let g=["","# agentx completion"];c&&g.push(i),l&&g.push(r),Jp(n,g.join(`
683
+ `}import{Command as Kb}from"commander";import Pe from"chalk";import{writeFileSync as Qb,mkdirSync as Zb,existsSync as Ii,readFileSync as Bp,appendFileSync as Jp}from"fs";import{resolve as xn,dirname as zp}from"path";import{homedir as ja}from"os";var Yp=new Kb().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-YK3YR2CQ.js"),t=await o(),n=String(e.shell||"zsh").toLowerCase(),s;switch(n){case"zsh":s=tk(t);break;case"bash":s=ak(t);break;case"fish":s=ck(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?xn(String(e.output)):ek(n);Zb(zp(i),{recursive:!0}),Qb(i,s),console.log(Pe.green(`\u2713 Wrote ${n} completion to:`)),console.log(` ${i}`),console.log(),ok(n,i,!!e.yes)});function ek(e){let o=ja();switch(e){case"zsh":return xn(o,".zsh","completions","_agentx");case"bash":return xn(o,".bash_completion.d","agentx.bash");case"fish":return xn(o,".config","fish","completions","agentx.fish");default:throw new Error(`unsupported shell: ${e}`)}}function ok(e,o,t){if(e==="zsh"){let n=xn(ja(),".zshrc"),s=zp(o),i=`fpath=(${s} $fpath)`,r="autoload -U compinit && compinit",a=Ii(n)?Bp(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&&Ii(n)){let g=["","# agentx completion"];c&&g.push(i),l&&g.push(r),Jp(n,g.join(`
684
684
  `)+`
685
685
  `),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=xn(ja(),".bashrc"),s=`[ -f "${o}" ] && source "${o}"`;if((Ii(n)?Bp(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&&Ii(n)){Jp(n,`
686
686
  # agentx completion
@@ -696,4 +696,4 @@ ${lk({...o,category:e.category})}`),g&&a.set(l.id,g)}let c=`https://github.com/$
696
696
  ${t.url}`)}catch(o){console.error(En.red(` ${o.message}`)),process.exitCode=1}});ms.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",Ca).action(async(e,o)=>{try{let t=await Ra(o.models);if(!Ia(o.model,t)){console.log(Na(o.model,t)),process.exitCode=1;return}let n=e==="-"?await mk():await gk(e,"utf8"),s=JSON.parse(n),{version:i}=await $s(),r=Qp({...s,fields:s.fields??{}},{model:o.model,version:i??"unknown"});console.log(r)}catch(t){console.error(En.red(` ${t.message}`)),process.exitCode=1}});async function mk(){let e=[];for await(let o of process.stdin)e.push(o);return Buffer.concat(e).toString("utf8")}async function zI(){let e=await $s(),o=new pk().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=gd(n);md(s)&&dd("cli",s)});for(let t of[Wd,Ud,dn,Wt,Ht,co,Ql,gt,Hs,No,_o,an,Lm,et,Js,vp,Ko,mg,pg,vg,Vn,Rg,Mg,dg,Fg,Ug,sm,cm,lm,$o,vt,Tp,Fn,Go,Yp,ms])o.addCommand(t);for(let t of eu)o.addCommand(t,{hidden:!0});return o.addHelpText("after",()=>{let t=eu.map(n=>n.name()).sort();return["",`Advanced (${t.length}, hidden \u2014 run \`agentx <command> --help\` for any of them):`,uk(t,74," "),""].join(`
697
697
  `)}),o}var eu=[ne,pn,st,bo,Bn,nn,Qe,Po,ot,kt,yn,wn,Vo,ze,Vt,di,$p,bp,Io,io,yd,pt,ds,vr,nt,oo,zt,xr,Si,To,Mo,Mp,Lp,Ap];function uk(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(`
698
698
  `)}export{zI as buildProgram};
699
- //# sourceMappingURL=program-EZLJIVQX.js.map
699
+ //# sourceMappingURL=program-YK3YR2CQ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentix-cli",
3
- "version": "0.111.0",
3
+ "version": "0.111.1",
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": {