agentix-cli 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -118
- package/apps/mac-helper/Sources/AgentXHelper/AXTree.swift +159 -0
- package/apps/mac-helper/Sources/AgentXHelper/Brand.swift +63 -0
- package/apps/mac-helper/Sources/AgentXHelper/Focus.swift +97 -0
- package/apps/mac-helper/Sources/AgentXHelper/HUD.swift +179 -0
- package/apps/mac-helper/Sources/AgentXHelper/OCR.swift +117 -0
- package/apps/mac-helper/Sources/AgentXHelper/Pointer.swift +309 -0
- package/apps/mac-helper/Sources/AgentXHelper/Screens.swift +67 -0
- package/apps/mac-helper/Sources/AgentXHelper/Typer.swift +185 -0
- package/apps/mac-helper/Sources/AgentXHelper/Vision.swift +201 -0
- package/apps/mac-helper/Sources/AgentXHelper/main.swift +265 -0
- package/apps/mac-helper/build.sh +39 -0
- package/apps/mac-voice/Resources/Info.plist +18 -0
- package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +108 -0
- package/apps/mac-voice/Sources/AgentXVoice/Brand.swift +123 -0
- package/apps/mac-voice/Sources/AgentXVoice/Config.swift +68 -0
- package/apps/mac-voice/Sources/AgentXVoice/Hold.swift +74 -0
- package/apps/mac-voice/Sources/AgentXVoice/Hotkey.swift +76 -0
- package/apps/mac-voice/Sources/AgentXVoice/Markdown.swift +140 -0
- package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +275 -0
- package/apps/mac-voice/Sources/AgentXVoice/Progress.swift +147 -0
- package/apps/mac-voice/Sources/AgentXVoice/Recorder.swift +139 -0
- package/apps/mac-voice/Sources/AgentXVoice/ResultCard.swift +162 -0
- package/apps/mac-voice/Sources/AgentXVoice/SmartPaste.swift +72 -0
- package/apps/mac-voice/Sources/AgentXVoice/Speech.swift +192 -0
- package/apps/mac-voice/Sources/AgentXVoice/StepLabel.swift +159 -0
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +380 -0
- package/apps/mac-voice/build.sh +32 -0
- package/dist/{App-U52IPUK2.js → App-IEQXWJ7B.js} +2 -2
- package/dist/{ChatApp-XP4OMHPL.js → ChatApp-NWOSAP5U.js} +2 -2
- package/dist/{agent-V2CA4TXD.js → agent-LS4CZPJ6.js} +2 -2
- package/dist/{board-dashboard-TTMAYRLG.js → board-dashboard-6QQCKFB3.js} +8 -10
- package/dist/board-dashboard-6QQCKFB3.js.map +1 -0
- package/dist/{chunk-DCDQZR7I.js → chunk-3QVOWDHZ.js} +6 -6
- package/dist/chunk-3QVOWDHZ.js.map +1 -0
- package/dist/{chunk-FIEJDZVC.js → chunk-4KXBUORV.js} +2 -2
- package/dist/{chunk-UFAGYX73.js → chunk-6F2IKJ2F.js} +8 -8
- package/dist/chunk-6F2IKJ2F.js.map +1 -0
- package/dist/chunk-AE2LDMZU.js +2 -0
- package/dist/chunk-AE2LDMZU.js.map +1 -0
- package/dist/{chunk-VTE7L6LO.js → chunk-DI7FMCDK.js} +2 -2
- package/dist/{chunk-AX2PWSRT.js → chunk-F5AEXRPR.js} +2 -2
- package/dist/{chunk-CJQQIRPD.js → chunk-GMNKJXTR.js} +7 -7
- package/dist/chunk-GMNKJXTR.js.map +1 -0
- package/dist/{chunk-L2IZPR6P.js → chunk-JIOLJIBM.js} +2 -2
- package/dist/{chunk-IB3F7VBE.js → chunk-JKYMXLYL.js} +3 -3
- package/dist/chunk-JKYMXLYL.js.map +1 -0
- package/dist/{chunk-LNRB5MCU.js → chunk-LNWX4MPX.js} +151 -134
- package/dist/chunk-LNWX4MPX.js.map +1 -0
- package/dist/{chunk-WZ72HX5C.js → chunk-OTXDKKEU.js} +145 -138
- package/dist/chunk-OTXDKKEU.js.map +1 -0
- package/dist/{chunk-IBUSGCLQ.js → chunk-SBCZLZG3.js} +2 -2
- package/dist/{chunk-2T5W3ETS.js → chunk-SC5DIKBB.js} +2 -2
- package/dist/{chunk-BPIRO4YD.js → chunk-UYSNGBDT.js} +2 -2
- package/dist/chunk-XPXO5K4L.js +164 -0
- package/dist/chunk-XPXO5K4L.js.map +1 -0
- package/dist/{chunk-GDWJUGB5.js → chunk-Z2Y24ETP.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-5Z3URGPY.js +2 -0
- package/dist/config-ORSGLVRW.js +2 -0
- package/dist/config-mutator-JB3S2E7H.js +2 -0
- package/dist/doctor-FS2BX6H4.js +2 -0
- package/dist/index.d.ts +63 -42
- package/dist/index.js +12 -19
- package/dist/index.js.map +1 -1
- package/dist/program-I4J63BQ7.js +2 -0
- package/dist/query-R7EI3VGX.js +2 -0
- package/dist/registry-UJIJBLUR.js +2 -0
- package/dist/request-planner-BKT6RZKX.js +2 -0
- package/dist/request-planner-BKT6RZKX.js.map +1 -0
- package/dist/{review-candidates-AEUXRQQC.js → review-candidates-F3OFYTCZ.js} +2 -2
- package/dist/routing-S5WSFIAD.js +2 -0
- package/dist/scheduler-DSAOMV4O.js +2 -0
- package/dist/{seat-VZ7AVO27.js → seat-ZVHXNAEN.js} +2 -2
- package/dist/{select-F5I5PO2O.js → select-L7C52URW.js} +2 -2
- package/dist/wiki-5YQI4YKM.js +2 -0
- package/dist/wiki-5YQI4YKM.js.map +1 -0
- package/package.json +14 -3
- package/scripts/postinstall.mjs +80 -0
- package/dist/board-dashboard-TTMAYRLG.js.map +0 -1
- package/dist/chunk-CJQQIRPD.js.map +0 -1
- package/dist/chunk-DCDQZR7I.js.map +0 -1
- package/dist/chunk-IB3F7VBE.js.map +0 -1
- package/dist/chunk-LNRB5MCU.js.map +0 -1
- package/dist/chunk-OPHIXXGI.js +0 -157
- package/dist/chunk-OPHIXXGI.js.map +0 -1
- package/dist/chunk-UFAGYX73.js.map +0 -1
- package/dist/chunk-WZ72HX5C.js.map +0 -1
- package/dist/client-PX25MD47.js +0 -2
- package/dist/config-HL5F36V4.js +0 -2
- package/dist/config-mutator-HBX53OMJ.js +0 -2
- package/dist/doctor-PBAH6XL3.js +0 -2
- package/dist/program-YGXVCV2Y.js +0 -2
- package/dist/query-ZKTFJMNE.js +0 -2
- package/dist/registry-PSZDPFZK.js +0 -2
- package/dist/routing-4PV66BK6.js +0 -2
- package/dist/routing-4PV66BK6.js.map +0 -1
- package/dist/scheduler-GZZAN6ZG.js +0 -2
- package/dist/wiki-N5SMP3DT.js +0 -2
- /package/dist/{App-U52IPUK2.js.map → App-IEQXWJ7B.js.map} +0 -0
- /package/dist/{ChatApp-XP4OMHPL.js.map → ChatApp-NWOSAP5U.js.map} +0 -0
- /package/dist/{agent-V2CA4TXD.js.map → agent-LS4CZPJ6.js.map} +0 -0
- /package/dist/{chunk-FIEJDZVC.js.map → chunk-4KXBUORV.js.map} +0 -0
- /package/dist/{chunk-VTE7L6LO.js.map → chunk-DI7FMCDK.js.map} +0 -0
- /package/dist/{chunk-AX2PWSRT.js.map → chunk-F5AEXRPR.js.map} +0 -0
- /package/dist/{chunk-L2IZPR6P.js.map → chunk-JIOLJIBM.js.map} +0 -0
- /package/dist/{chunk-IBUSGCLQ.js.map → chunk-SBCZLZG3.js.map} +0 -0
- /package/dist/{chunk-2T5W3ETS.js.map → chunk-SC5DIKBB.js.map} +0 -0
- /package/dist/{chunk-BPIRO4YD.js.map → chunk-UYSNGBDT.js.map} +0 -0
- /package/dist/{chunk-GDWJUGB5.js.map → chunk-Z2Y24ETP.js.map} +0 -0
- /package/dist/{client-PX25MD47.js.map → client-5Z3URGPY.js.map} +0 -0
- /package/dist/{config-HL5F36V4.js.map → config-ORSGLVRW.js.map} +0 -0
- /package/dist/{config-mutator-HBX53OMJ.js.map → config-mutator-JB3S2E7H.js.map} +0 -0
- /package/dist/{doctor-PBAH6XL3.js.map → doctor-FS2BX6H4.js.map} +0 -0
- /package/dist/{program-YGXVCV2Y.js.map → program-I4J63BQ7.js.map} +0 -0
- /package/dist/{query-ZKTFJMNE.js.map → query-R7EI3VGX.js.map} +0 -0
- /package/dist/{registry-PSZDPFZK.js.map → registry-UJIJBLUR.js.map} +0 -0
- /package/dist/{review-candidates-AEUXRQQC.js.map → review-candidates-F3OFYTCZ.js.map} +0 -0
- /package/dist/{scheduler-GZZAN6ZG.js.map → routing-S5WSFIAD.js.map} +0 -0
- /package/dist/{seat-VZ7AVO27.js.map → scheduler-DSAOMV4O.js.map} +0 -0
- /package/dist/{wiki-N5SMP3DT.js.map → seat-ZVHXNAEN.js.map} +0 -0
- /package/dist/{select-F5I5PO2O.js.map → select-L7C52URW.js.map} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import{b as m,c as C}from"./chunk-FIOB3MEX.js";import{z as t}from"zod";var T,A,$,I,P,D,L,_,z,h,y=m(()=>{"use strict";T=t.enum(["mon","tue","wed","thu","fri","sat","sun"]),A=t.object({days:t.array(T).default(["mon","tue","wed","thu","fri"]),start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/),lunch:t.object({start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/)}).optional()}),$=t.object({title:t.string(),responsibilities:t.array(t.string()).default([]),sopPath:t.string().optional(),kpis:t.array(t.string()).default([])}),I=t.object({role:t.string(),reportsTo:t.string().optional(),schedule:A,utilizationTarget:t.number().min(0).max(1).default(.8)}),P=t.object({channel:t.string(),chatId:t.string(),accountId:t.string().optional()}),D=t.discriminatedUnion("type",[t.object({type:t.literal("backlog"),path:t.string().default(".agentx/backlog.md")}),t.object({type:t.literal("gitlab"),projects:t.array(t.string()).default([])}),t.object({type:t.literal("wiki"),path:t.string(),glob:t.string().default("**/*.md")})]),L=t.object({id:t.string(),pm:t.string().optional(),client:t.string().optional()}),_=t.object({channel:t.string().optional(),chatId:t.string().optional(),username:t.string().optional(),senderId:t.string().optional(),client:t.string(),project:t.string().optional(),displayName:t.string().optional()}),z=t.object({name:t.string().optional(),kind:t.enum(["client","internal","own"]).optional(),respondWithin:t.string().optional(),standing:t.array(t.string()).default([])}),h=t.object({enabled:t.boolean().default(!1),timezone:t.string().default("UTC"),mainChannel:P,workSource:D,roles:t.record(t.string(),$).default({}),orgChart:t.record(t.string(),I).default({}),projects:t.array(L).default([]),contactMap:t.array(_).default([]),clients:t.record(t.string(),z).default({}),workTickMinutes:t.number().int().min(1).max(60).default(15),idleQueueThreshold:t.number().int().min(0).default(0),standup:t.object({enabled:t.boolean().default(!0),plansDir:t.string().default(".agentx/plans"),maxAgentsPerDay:t.number().int().min(1).max(100).default(20),dryRun:t.boolean().default(!1)}).default({})})});import{z as n}from"zod";function be(a,i){let s=new Set(a.labels||[]);if(a.state==="closed"){let r=i.find(l=>l.kind==="closed");if(r)return r.id}for(let r of i)if(r.kind==="scoped-label"&&r.scopedLabel&&s.has(r.scopedLabel))return r.id;for(let r of i)if(r.kind==="label"&&r.mapsToLabel&&s.has(r.mapsToLabel))return r.id;let o=i.find(r=>r.kind==="open-backlog");if(o){let r=o.scopedPrefix+"::";return[...s].some(
|
|
2
|
-
`)){let r=o.trim();if(!r||r.startsWith("#"))continue;let l=r.indexOf("=");if(l===-1)continue;let
|
|
1
|
+
import{b as m,c as C}from"./chunk-FIOB3MEX.js";import{z as t}from"zod";var T,A,$,I,P,D,L,_,z,h,y=m(()=>{"use strict";T=t.enum(["mon","tue","wed","thu","fri","sat","sun"]),A=t.object({days:t.array(T).default(["mon","tue","wed","thu","fri"]),start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/),lunch:t.object({start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/)}).optional()}),$=t.object({title:t.string(),responsibilities:t.array(t.string()).default([]),sopPath:t.string().optional(),kpis:t.array(t.string()).default([])}),I=t.object({role:t.string(),reportsTo:t.string().optional(),schedule:A,utilizationTarget:t.number().min(0).max(1).default(.8)}),P=t.object({channel:t.string(),chatId:t.string(),accountId:t.string().optional()}),D=t.discriminatedUnion("type",[t.object({type:t.literal("backlog"),path:t.string().default(".agentx/backlog.md")}),t.object({type:t.literal("gitlab"),projects:t.array(t.string()).default([])}),t.object({type:t.literal("wiki"),path:t.string(),glob:t.string().default("**/*.md")})]),L=t.object({id:t.string(),pm:t.string().optional(),client:t.string().optional()}),_=t.object({channel:t.string().optional(),chatId:t.string().optional(),username:t.string().optional(),senderId:t.string().optional(),client:t.string(),project:t.string().optional(),displayName:t.string().optional()}),z=t.object({name:t.string().optional(),kind:t.enum(["client","internal","own"]).optional(),respondWithin:t.string().optional(),standing:t.array(t.string()).default([])}),h=t.object({enabled:t.boolean().default(!1),timezone:t.string().default("UTC"),mainChannel:P,workSource:D,roles:t.record(t.string(),$).default({}),orgChart:t.record(t.string(),I).default({}),projects:t.array(L).default([]),contactMap:t.array(_).default([]),clients:t.record(t.string(),z).default({}),workTickMinutes:t.number().int().min(1).max(60).default(15),idleQueueThreshold:t.number().int().min(0).default(0),standup:t.object({enabled:t.boolean().default(!0),plansDir:t.string().default(".agentx/plans"),maxAgentsPerDay:t.number().int().min(1).max(100).default(20),dryRun:t.boolean().default(!1)}).default({})})});import{z as n}from"zod";function be(a,i){let s=new Set(a.labels||[]);if(a.state==="closed"){let r=i.find(l=>l.kind==="closed");if(r)return r.id}for(let r of i)if(r.kind==="scoped-label"&&r.scopedLabel&&s.has(r.scopedLabel))return r.id;for(let r of i)if(r.kind==="label"&&r.mapsToLabel&&s.has(r.mapsToLabel))return r.id;let o=i.find(r=>r.kind==="open-backlog");if(o){let r=o.scopedPrefix+"::";return[...s].some(c=>c.startsWith(r))?null:o.id}return i[0]?.id??null}function he(a,i){let s=[],o=[],r=!1,l=!1;return i.kind==="scoped-label"&&i.scopedLabel?s.push(i.scopedLabel):i.kind==="label"&&i.mapsToLabel?s.push(i.mapsToLabel):i.kind==="closed"&&(r=!0),a&&(a.kind==="scoped-label"&&a.scopedLabel?o.push(a.scopedLabel):a.kind==="label"&&a.mapsToLabel?o.push(a.mapsToLabel):a.kind==="closed"&&i.kind!=="closed"&&(l=!0)),{addLabels:s.length?s:void 0,removeLabels:o.length?o:void 0,closeIssue:r||void 0,reopen:l||void 0}}var E,B,M,R,O,U,x,K,S,k=m(()=>{"use strict";E=n.object({name:n.string(),color:n.string().regex(/^#[0-9a-f]{6}$/i).default("#6366f1"),description:n.string().optional()}),B=n.object({id:n.string().regex(/^[a-z0-9_-]+$/,"column id must be lowercase slug"),title:n.string(),kind:n.enum(["open-backlog","scoped-label","closed","label"]).default("label"),mapsToLabel:n.string().optional(),scopedLabel:n.string().optional(),scopedPrefix:n.string().default("Status"),accent:n.string().optional()}),M=n.object({enabled:n.boolean().default(!0),staleDoingMinutes:n.number().int().min(1).default(45),respectLunchBreak:n.boolean().default(!0),respectSchedule:n.boolean().default(!0),action:n.enum(["badge","notify"]).default("badge")}),R=n.discriminatedUnion("type",[n.object({type:n.literal("gitlab"),projects:n.array(n.string()).min(1)})]),O=[{id:"open",title:"Open",kind:"open-backlog",scopedPrefix:"Status",accent:"#6b7280"},{id:"todo",title:"To Do",kind:"scoped-label",scopedLabel:"Status::To Do",scopedPrefix:"Status",accent:"#fb7a35"},{id:"doing",title:"Doing",kind:"scoped-label",scopedLabel:"Status::Doing",scopedPrefix:"Status",accent:"#22c55e"},{id:"onhold",title:"On Hold",kind:"scoped-label",scopedLabel:"Status::On Hold",scopedPrefix:"Status",accent:"#f59e0b"},{id:"review",title:"Review",kind:"scoped-label",scopedLabel:"Status::Review",scopedPrefix:"Status",accent:"#3b82f6"},{id:"closed",title:"Closed",kind:"closed",scopedPrefix:"Status",accent:"#6b7280"}],U=n.object({id:n.string().regex(/^[a-z0-9_-]+$/,"board id must be lowercase slug"),name:n.string(),source:R,primaryToolLabel:n.string().optional(),labels:n.array(E).default([]),columns:n.array(B).min(1).default(O),timeRangeDays:n.number().int().min(1).max(365).default(30),closedWindowDays:n.number().int().min(1).max(365).default(30),reconciliation:M.default({})}),x=n.array(U).default([]),K=n.object({name:n.string(),url:n.string(),dashboardUrl:n.string().optional(),token:n.string().optional(),dashboardToken:n.string().optional()}),S=n.object({enabled:n.boolean().default(!1),port:n.number().int().default(4202),bind:n.string().default("127.0.0.1"),token:n.string().optional(),daemonUrl:n.string().default("http://localhost:18800"),daemons:n.array(K).default([]),draftAgent:n.string().optional()}).default({})});var ue={};C(ue,{INTEGRATION_KINDS:()=>G,daemonConfigSchema:()=>w,expandEnvVars:()=>g,loadDaemonConfig:()=>de,validateWorkspaces:()=>ce});import{z as e}from"zod";import{readFileSync as j,existsSync as f}from"fs";import{resolve as p}from"path";function N(a){let i=p(a,".env");if(!f(i))return;let s=j(i,"utf-8");for(let o of s.split(`
|
|
2
|
+
`)){let r=o.trim();if(!r||r.startsWith("#"))continue;let l=r.indexOf("=");if(l===-1)continue;let c=r.slice(0,l).trim(),d=r.slice(l+1).trim();process.env[c]||(process.env[c]=d)}}function g(a){if(typeof a=="string")return a.replace(/\$\{(\w+)\}/g,(i,s)=>process.env[s]||"");if(Array.isArray(a))return a.map(g);if(a!==null&&typeof a=="object"){let i={};for(let[s,o]of Object.entries(a))i[s]=g(o);return i}return a}function le(a,i){let s=[],o=new Set;for(let r of a){let l=r.path.join("."),c=/^channels\.telegram\.accounts\.([^.]+)\.token$/.exec(l);if(c&&r.message.toLowerCase().includes("required")){let d=c[1],u=`tg:${d}`;if(o.has(u))continue;o.add(u),s.push(`Hint: Telegram account "${d}" is enabled but has no bot token.
|
|
3
3
|
Either:
|
|
4
4
|
A) Open ${i} and set channels.telegram.accounts.${d}.token to your bot token (or "\${TG_${d.toUpperCase()}_BOT_TOKEN}" + the matching .env entry).
|
|
5
5
|
B) If you don't need Telegram on this instance, remove the entire "telegram" block under "channels" (or set channels.telegram.enabled to false AND drop accounts.${d}).`)}}return s}function de(a){let i=a?[a]:[p(process.cwd(),"agentx.json"),p(process.cwd(),".agentx/config.json")];N(process.cwd());let s,o;for(let d of i)if(f(d)){s=j(d,"utf-8"),o=d;break}if(!s||!o)throw new Error(`No config found. Create agentx.json or .agentx/config.json
|
|
6
|
-
Searched: ${i.join(", ")}`);let r;try{r=JSON.parse(s)}catch(d){throw new Error(`Invalid JSON in ${o}: ${d.message}`)}let l=g(r),
|
|
7
|
-
`),
|
|
6
|
+
Searched: ${i.join(", ")}`);let r;try{r=JSON.parse(s)}catch(d){throw new Error(`Invalid JSON in ${o}: ${d.message}`)}let l=g(r),c=w.safeParse(l);if(!c.success){let d=c.error.issues.map(b=>` ${b.path.join(".")}: ${b.message}`).join(`
|
|
7
|
+
`),u=le(c.error.issues,o),v=u.length?`
|
|
8
8
|
|
|
9
|
-
${
|
|
9
|
+
${u.join(`
|
|
10
10
|
|
|
11
11
|
`)}`:"";throw new Error(`Config validation failed (${o}):
|
|
12
|
-
${d}${v}`)}return u.data}function ue(a){let i=[];for(let[s,o]of Object.entries(a.agents)){if(!f(o.workspace)){i.push(`Agent "${s}": workspace not found at ${o.workspace}`);continue}if(o.tier==="claude-code"){let u=p(o.workspace,".claude");f(u)||i.push(`Agent "${s}": no .claude/ directory in workspace ${o.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let r=o.provider||"claude",l=a.providers[r];!["claude-code","codex-cli","opencode"].includes(o.tier)&&(!l||!l.apiKey)&&i.push(`Agent "${s}": provider "${r}" has no API key configured. Set providers.${r}.apiKey in config or use a CLI-backed tier ("claude-code", "codex-cli", or "opencode").`)}for(let[s,o]of Object.entries(a.crons))a.agents[o.agent]||i.push(`Cron "${s}": references unknown agent "${o.agent}"`);if(a.channels.telegram.enabled)for(let[s,o]of Object.entries(a.channels.telegram.accounts))a.agents[o.agentBinding]||i.push(`Telegram account "${s}": references unknown agent "${o.agentBinding}"`);return i}var Z,F,W,q,H,J,G,Y,Q,V,X,ee,te,ne,ae,oe,re,ie,se,w,fe=m(()=>{y();k();Z=e.object({apiKey:e.string().optional(),defaultModel:e.string().optional(),baseUrl:e.string().optional(),thinking:e.boolean().optional()}),F=e.object({type:e.literal("stdio").optional(),command:e.string(),args:e.array(e.string()).default([]),env:e.record(e.string(),e.string()).optional()}),W=e.object({type:e.literal("http"),url:e.string().url(),headers:e.record(e.string(),e.string()).optional()}),q=e.union([W,F]),H=e.object({tokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),privateAppTokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),apiKeyEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),refreshTokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),clientIdEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),clientSecretEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),auth:e.literal("keyring").optional(),sessionDir:e.string().optional()}).strict(),J=e.object({kind:e.string().min(1),label:e.string().min(1),credentials:H.default({}),metadata:e.record(e.string(),e.union([e.string(),e.number(),e.boolean()])).default({}),enabled:e.boolean().default(!0)}),G=["telegram-bot","whatsapp","gitlab-user","github-user","gmail","hotmail","smtp","hubspot","salesforce","pipedrive","odoo","trello","linear","asana","jira","notion","stripe","sentry","vercel","twilio","custom"],Y=e.object({name:e.string(),workspace:e.string(),tier:e.enum(["claude-code","codex-cli","opencode","sdk","orchestrator"]).default("claude-code"),provider:e.string().optional(),model:e.string().optional(),systemPrompt:e.string().optional(),mentions:e.array(e.string()).default([]),intents:e.array(e.string()).default([]),maxDelegationDepth:e.number().int().min(0).max(50).default(5),mcp:e.record(e.string(),q).optional(),codegraph:e.boolean().default(!1),contextStrategy:e.enum(["layered","planner"]).optional(),contextReferences:e.boolean().default(!1),richMessages:e.boolean().default(!0),maxConcurrent:e.number().default(1),maxExecutionMinutes:e.number().int().min(1).max(240).default(20),permissionMode:e.string().default("default"),toolUseRequired:e.array(e.string()).default([]),gitlabAutoReply:e.boolean().optional(),persistentProcess:e.boolean().default(!1),queueMode:e.enum(["collect","followup","drop"]).default("collect"),heartbeat:e.object({enabled:e.boolean().default(!1),intervalMinutes:e.number().default(30),prompt:e.string().default("Check inbox, pending tasks, and system health. Report anything that needs attention."),channel:e.string().default("heartbeat")}).default({}),access:e.enum(["private","public"]).default("private"),integrations:e.array(J).default([])}),Q=e.object({token:e.string(),agentBinding:e.string(),allowFrom:e.array(e.string()).optional(),pollInbound:e.boolean().default(!0)}),V=e.object({telegram:e.object({enabled:e.boolean().default(!1),accounts:e.record(e.string(),Q).default({}),policy:e.object({dm:e.enum(["pair","block"]).default("pair"),group:e.enum(["mention-required","all"]).default("mention-required"),allowFrom:e.array(e.string()).optional()}).default({})}).default({}),whatsapp:e.object({enabled:e.boolean().default(!1),sessionDir:e.string().default(".agentx/whatsapp-sessions"),defaultAgent:e.string().optional(),allowFrom:e.array(e.string()).optional(),routes:e.array(e.object({contact:e.string().optional(),group:e.string().optional(),agent:e.string()})).default([]),ingest:e.object({enabled:e.boolean().default(!1),mode:e.enum(["metadata-only","messages"]).default("metadata-only"),allowContacts:e.array(e.string()).default([]),allowGroups:e.array(e.string()).default([]),denyContacts:e.array(e.string()).default([]),denyGroups:e.array(e.string()).default([]),messageCap:e.number().int().min(1).max(500).default(50),historyDays:e.number().int().min(1).max(365).default(30),contactRefreshDays:e.number().int().min(1).max(90).default(7),throttle:e.object({minMsBetweenCalls:e.number().int().min(100).default(1500),maxCallsPerMinute:e.number().int().min(1).default(20),maxChatsPerSweep:e.number().int().min(1).default(25)}).default({}),retentionDays:e.number().int().min(0).default(0)}).default({})}).default({}),gitlab:e.object({enabled:e.boolean().default(!1),webhookPort:e.number().default(18810),webhookSecret:e.string().optional(),host:e.string().default("https://gitlab.com"),token:e.string().optional(),autoReplyLegacy:e.boolean().default(!0),routes:e.array(e.object({project:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),gitlabUsernames:e.array(e.string()).default([]),keywords:e.array(e.string()).default([]),token:e.string().optional(),node:e.string().optional()})).default([])}).default({}),github:e.object({enabled:e.boolean().default(!1),autoReplyLegacy:e.boolean().default(!0),token:e.string().optional(),tokenFile:e.string().optional(),appId:e.number().optional(),clientId:e.string().optional(),privateKeyFile:e.string().optional(),webhookSecret:e.string().optional(),routes:e.array(e.object({repo:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),githubUsernames:e.array(e.string()).default([]),token:e.string().optional(),tokenFile:e.string().optional(),node:e.string().optional()})).default([])}).default({}),ntfy:e.object({enabled:e.boolean().default(!1),server:e.string().default("https://ntfy.sh"),topic:e.string().optional(),token:e.string().optional(),defaultPriority:e.number().int().min(1).max(5).default(3),defaultTitle:e.string().optional()}).default({}),webrtc:e.object({enabled:e.boolean().default(!1),stunServers:e.array(e.string()).default(["stun:stun.l.google.com:19302"]),turnServers:e.array(e.object({urls:e.string(),username:e.string().optional(),credential:e.string().optional()})).default([]),allowedCallers:e.array(e.string()).default([]),ringNotify:e.array(e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()})).default([]),callUrlBase:e.string().optional(),bot:e.object({enabled:e.boolean().default(!1),defaultAgentId:e.string().optional(),whisperBackend:e.enum(["auto","mlx","openai"]).default("auto"),whisperModel:e.string().optional(),whisperLanguage:e.string().default("auto"),mlxBinary:e.string().optional(),transcriptChannel:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),maxCallMinutes:e.number().int().min(1).max(240).default(30)}).default({})}).default({})}),X=e.object({enabled:e.boolean().default(!0),schedule:e.string(),timezone:e.string().default("UTC"),agent:e.string(),prompt:e.string().default(""),command:e.string().optional(),timeout:e.number().default(600),model:e.string().optional(),maxOutputTokens:e.number().int().min(50).max(8e3).optional(),onError:e.union([e.enum(["log","notify","disable"]),e.array(e.enum(["log","notify","disable"]))]).default("log").transform(a=>Array.isArray(a)?a:[a]),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}).refine(a=>!!(a.command?.trim()||a.prompt?.trim()),{message:"a cron needs either a prompt (dispatch an agent) or a command (run it directly)"}),ee=e.object({name:e.string(),triggers:e.array(e.object({pattern:e.string(),channel:e.string().optional()})),allowedContacts:e.array(e.string()).optional(),agent:e.string(),prompt:e.string(),schedule:e.string().optional(),timezone:e.string().default("UTC"),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),te=e.object({url:e.string(),name:e.string(),token:e.string().optional()}),ne=e.object({name:e.string(),agent:e.string(),enabled:e.boolean().default(!0)}),ae=e.object({enabled:e.boolean().default(!1),peers:e.array(te).default([]),inboxes:e.array(ne).default([]),discovery:e.enum(["static","mdns"]).default("static"),healthCheck:e.object({interval:e.number().default(60),timeout:e.number().default(10)}).default({})}),oe=e.object({enabled:e.boolean().default(!1),baseDir:e.string().default(".agentx/graph"),draftAgent:e.string().optional(),reviewAgent:e.string().optional(),autoApproveStructure:e.enum(["strict","extend-leaves","any"]).default("extend-leaves"),autoApproveConfidence:e.number().min(0).max(1).default(1),classifierModel:e.string().default("claude-haiku-4-5-20251001"),retrievalWeights:e.object({graph:e.number().min(0).default(.6),bm25:e.number().min(0).default(.4)}).default({})}).default({}),re=e.object({mode:e.enum(["off","shadow","active"]).default("off"),backend:e.string().optional(),model:e.string().optional(),timeoutMs:e.number().int().min(100).default(1e4),temperature:e.number().min(.01).default(1),explore:e.number().min(0).max(1).default(.15)}).default({}),ie=e.object({enabled:e.boolean().default(!1),dbPath:e.string().default(".agentx/decisions/decisions.sqlite"),redactState:e.boolean().default(!1),keepStateRows:e.number().int().min(0).default(2e3),defaultBackend:e.string().default("local"),backends:e.object({local:e.object({provider:e.string().default("claude-code"),model:e.string().default("claude-haiku-4-5-20251001"),structureMode:e.enum(["auto","tool","text"]).default("auto"),normalizeProbabilities:e.boolean().default(!0),nRetryMalformedStructure:e.number().int().min(0).max(3).default(1),maxStateChars:e.number().int().min(500).default(24e3)}).default({}),simpleJev:e.object({baseUrl:e.string().default("http://127.0.0.1:8000/v1"),model:e.string().optional(),apiKeyEnv:e.string().optional(),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(6e3),maxChoiceOptions:e.number().int().min(2).max(255).default(50)}).default({}),jev:e.object({baseUrl:e.string().default("https://openrouter.ai/api/alpha"),path:e.string().default("/decisions"),model:e.string().default("jev-latest"),apiKeyEnv:e.string().default("OPENROUTER_API_KEY"),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(9e4),maxChoiceOptions:e.number().int().min(2).max(255).default(255)}).default({}),typesafe:e.object({baseUrl:e.string().default("https://api.typesafe.ai/v1"),path:e.string().default("/systemone"),model:e.string().default("jev-latest"),apiKeyEnv:e.string().default("TYPESAFE_API_KEY"),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(9e4),maxChoiceOptions:e.number().int().min(2).max(255).default(255)}).default({})}).default({}),seats:e.record(e.string(),re).default({}),routing:e.object({cheapModel:e.string().optional()}).default({})}).default({}),se=e.object({longTaskThreshold:e.number().default(30),destination:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),on:e.object({taskComplete:e.boolean().default(!0),taskError:e.boolean().default(!0),taskQueued:e.boolean().default(!1)}).default({})}).default({}),w=e.object({node:e.object({id:e.string(),name:e.string(),bind:e.string().default("127.0.0.1:18800"),defaultAgent:e.string().optional()}),providers:e.record(e.string(),Z).default({}),agents:e.record(e.string(),Y).default({}),channels:V.default({}),crons:e.record(e.string(),X).default({}),services:e.record(e.string(),ee).default({}),notifications:se,mesh:ae.default({}),business:h.optional(),boards:x,dashboard:S,graph:oe,decisions:ie,workflows:e.object({enabled:e.boolean().default(!1),dir:e.string().default(".agentx/workflows"),n8n:e.object({baseUrl:e.string().default(""),apiKey:e.string().default("")}).default({baseUrl:"",apiKey:""}),matching:e.object({enabled:e.boolean().default(!1),mode:e.enum(["suggest","auto"]).default("suggest"),autoRunThreshold:e.number().min(0).max(1).default(.85),suggestThreshold:e.number().min(0).max(1).default(.65)}).default({}),editor:e.enum(["disabled","readonly","edit"]).default("edit")}).default({}),procedures:e.object({enabled:e.boolean().default(!0),dir:e.string().default(".agentx/procedures"),extraction:e.object({enabled:e.boolean().default(!1),onTaskCompletion:e.boolean().default(!1),minOccurrences:e.number().int().min(2).default(3),sinceDays:e.number().int().min(1).default(7),maxClusters:e.number().int().min(1).default(5),via:e.string().optional()}).default({}),injection:e.object({enabled:e.boolean().default(!0),maxProcedures:e.number().int().min(1).default(2),minScore:e.number().min(0).max(1).default(.5)}).default({})}).default({}),webhooks:e.array(e.object({id:e.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"webhook id must be lowercase slug"),source:e.string().min(1),agentId:e.string(),secretEnv:e.string().optional(),description:e.string().optional(),enabled:e.boolean().default(!0),node:e.string().optional(),triggers:e.record(e.string(),e.string()).optional(),defaultWorkflow:e.string().optional()})).default([]),session:e.object({staleMinutes:e.number().int().min(1).max(1440).default(720),maxTurnsPerSession:e.number().int().min(2).max(200).default(40),tierTwoThresholdTokens:e.number().int().min(5e4).max(2e5).default(18e4),contextStrategy:e.enum(["layered","planner"]).default("layered"),maxClaudeCodeDispatchesPerHour:e.number().int().min(1).max(1e4).default(80),maxClaudeCodeDispatchesPer5h:e.number().int().min(1).max(5e4).default(180),continuityStateTurns:e.number().int().min(0).max(5).default(0)}).default({}),plugins:e.array(e.string()).default([]),processPool:e.object({maxIdleSeconds:e.number().int().min(5).max(86400).default(30),maxAgeSeconds:e.number().int().min(60).max(86400).default(2700),sweepIntervalSeconds:e.number().int().min(1).max(300).default(5)}).default({})})});export{be as a,he as b,k as c,G as d,w as e,g as f,de as g,ue as h,ce as i,fe as j};
|
|
13
|
-
//# sourceMappingURL=chunk-
|
|
12
|
+
${d}${v}`)}return c.data}function ce(a){let i=[];for(let[s,o]of Object.entries(a.agents)){if(!f(o.workspace)){i.push(`Agent "${s}": workspace not found at ${o.workspace}`);continue}if(o.tier==="claude-code"){let c=p(o.workspace,".claude");f(c)||i.push(`Agent "${s}": no .claude/ directory in workspace ${o.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let r=o.provider||"claude",l=a.providers[r];!["claude-code","codex-cli","opencode"].includes(o.tier)&&(!l||!l.apiKey)&&i.push(`Agent "${s}": provider "${r}" has no API key configured. Set providers.${r}.apiKey in config or use a CLI-backed tier ("claude-code", "codex-cli", or "opencode").`)}for(let[s,o]of Object.entries(a.crons))a.agents[o.agent]||i.push(`Cron "${s}": references unknown agent "${o.agent}"`);if(a.channels.telegram.enabled)for(let[s,o]of Object.entries(a.channels.telegram.accounts))a.agents[o.agentBinding]||i.push(`Telegram account "${s}": references unknown agent "${o.agentBinding}"`);return i}var Z,F,W,q,H,J,G,Y,Q,V,X,ee,te,ne,ae,oe,re,ie,se,w,fe=m(()=>{y();k();Z=e.object({apiKey:e.string().optional(),defaultModel:e.string().optional(),baseUrl:e.string().optional(),thinking:e.boolean().optional()}),F=e.object({type:e.literal("stdio").optional(),command:e.string(),args:e.array(e.string()).default([]),env:e.record(e.string(),e.string()).optional()}),W=e.object({type:e.literal("http"),url:e.string().url(),headers:e.record(e.string(),e.string()).optional()}),q=e.union([W,F]),H=e.object({tokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),privateAppTokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),apiKeyEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),refreshTokenEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),clientIdEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),clientSecretEnv:e.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),auth:e.literal("keyring").optional(),sessionDir:e.string().optional()}).strict(),J=e.object({kind:e.string().min(1),label:e.string().min(1),credentials:H.default({}),metadata:e.record(e.string(),e.union([e.string(),e.number(),e.boolean()])).default({}),enabled:e.boolean().default(!0)}),G=["telegram-bot","whatsapp","gitlab-user","github-user","gmail","hotmail","smtp","hubspot","salesforce","pipedrive","odoo","trello","linear","asana","jira","notion","stripe","sentry","vercel","twilio","custom"],Y=e.object({name:e.string(),workspace:e.string(),tier:e.enum(["claude-code","codex-cli","opencode","sdk","orchestrator"]).default("claude-code"),provider:e.string().optional(),model:e.string().optional(),systemPrompt:e.string().optional(),mentions:e.array(e.string()).default([]),intents:e.array(e.string()).default([]),maxDelegationDepth:e.number().int().min(0).max(50).default(5),mcp:e.record(e.string(),q).optional(),codegraph:e.boolean().default(!1),contextStrategy:e.enum(["layered","planner"]).optional(),contextReferences:e.boolean().default(!1),richMessages:e.boolean().default(!0),maxConcurrent:e.number().default(1),maxExecutionMinutes:e.number().int().min(1).max(240).default(20),permissionMode:e.string().default("default"),toolUseRequired:e.array(e.string()).default([]),gitlabAutoReply:e.boolean().optional(),persistentProcess:e.boolean().default(!1),queueMode:e.enum(["collect","followup","drop"]).default("collect"),heartbeat:e.object({enabled:e.boolean().default(!1),intervalMinutes:e.number().default(30),prompt:e.string().default("Check inbox, pending tasks, and system health. Report anything that needs attention."),channel:e.string().default("heartbeat")}).default({}),access:e.enum(["private","public"]).default("private"),integrations:e.array(J).default([])}),Q=e.object({token:e.string(),agentBinding:e.string(),allowFrom:e.array(e.string()).optional(),pollInbound:e.boolean().default(!0)}),V=e.object({telegram:e.object({enabled:e.boolean().default(!1),accounts:e.record(e.string(),Q).default({}),policy:e.object({dm:e.enum(["pair","block"]).default("pair"),group:e.enum(["mention-required","all"]).default("mention-required"),allowFrom:e.array(e.string()).optional()}).default({})}).default({}),whatsapp:e.object({enabled:e.boolean().default(!1),sessionDir:e.string().default(".agentx/whatsapp-sessions"),defaultAgent:e.string().optional(),allowFrom:e.array(e.string()).optional(),routes:e.array(e.object({contact:e.string().optional(),group:e.string().optional(),agent:e.string()})).default([]),ingest:e.object({enabled:e.boolean().default(!1),mode:e.enum(["metadata-only","messages"]).default("metadata-only"),allowContacts:e.array(e.string()).default([]),allowGroups:e.array(e.string()).default([]),denyContacts:e.array(e.string()).default([]),denyGroups:e.array(e.string()).default([]),messageCap:e.number().int().min(1).max(500).default(50),historyDays:e.number().int().min(1).max(365).default(30),contactRefreshDays:e.number().int().min(1).max(90).default(7),throttle:e.object({minMsBetweenCalls:e.number().int().min(100).default(1500),maxCallsPerMinute:e.number().int().min(1).default(20),maxChatsPerSweep:e.number().int().min(1).default(25)}).default({}),retentionDays:e.number().int().min(0).default(0)}).default({})}).default({}),gitlab:e.object({enabled:e.boolean().default(!1),webhookPort:e.number().default(18810),webhookSecret:e.string().optional(),host:e.string().default("https://gitlab.com"),token:e.string().optional(),autoReplyLegacy:e.boolean().default(!0),routes:e.array(e.object({project:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),gitlabUsernames:e.array(e.string()).default([]),keywords:e.array(e.string()).default([]),token:e.string().optional(),node:e.string().optional()})).default([])}).default({}),github:e.object({enabled:e.boolean().default(!1),autoReplyLegacy:e.boolean().default(!0),token:e.string().optional(),tokenFile:e.string().optional(),appId:e.number().optional(),clientId:e.string().optional(),privateKeyFile:e.string().optional(),webhookSecret:e.string().optional(),routes:e.array(e.object({repo:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),githubUsernames:e.array(e.string()).default([]),token:e.string().optional(),tokenFile:e.string().optional(),node:e.string().optional()})).default([])}).default({}),ntfy:e.object({enabled:e.boolean().default(!1),server:e.string().default("https://ntfy.sh"),topic:e.string().optional(),token:e.string().optional(),defaultPriority:e.number().int().min(1).max(5).default(3),defaultTitle:e.string().optional()}).default({}),webrtc:e.object({enabled:e.boolean().default(!1),stunServers:e.array(e.string()).default(["stun:stun.l.google.com:19302"]),turnServers:e.array(e.object({urls:e.string(),username:e.string().optional(),credential:e.string().optional()})).default([]),allowedCallers:e.array(e.string()).default([]),ringNotify:e.array(e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()})).default([]),callUrlBase:e.string().optional(),bot:e.object({enabled:e.boolean().default(!1),defaultAgentId:e.string().optional(),whisperBackend:e.enum(["auto","mlx","openai"]).default("auto"),whisperModel:e.string().optional(),whisperLanguage:e.string().default("auto"),mlxBinary:e.string().optional(),transcriptChannel:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),maxCallMinutes:e.number().int().min(1).max(240).default(30)}).default({})}).default({})}),X=e.object({enabled:e.boolean().default(!0),schedule:e.string(),timezone:e.string().default("UTC"),agent:e.string(),prompt:e.string().default(""),command:e.string().optional(),timeout:e.number().default(600),model:e.string().optional(),maxOutputTokens:e.number().int().min(50).max(8e3).optional(),onError:e.union([e.enum(["log","notify","disable"]),e.array(e.enum(["log","notify","disable"]))]).default("log").transform(a=>Array.isArray(a)?a:[a]),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}).refine(a=>!!(a.command?.trim()||a.prompt?.trim()),{message:"a cron needs either a prompt (dispatch an agent) or a command (run it directly)"}),ee=e.object({name:e.string(),triggers:e.array(e.object({pattern:e.string(),channel:e.string().optional()})),allowedContacts:e.array(e.string()).optional(),agent:e.string(),prompt:e.string(),schedule:e.string().optional(),timezone:e.string().default("UTC"),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),te=e.object({url:e.string(),name:e.string(),token:e.string().optional()}),ne=e.object({name:e.string(),agent:e.string(),enabled:e.boolean().default(!0)}),ae=e.object({enabled:e.boolean().default(!1),peers:e.array(te).default([]),inboxes:e.array(ne).default([]),discovery:e.enum(["static","mdns"]).default("static"),healthCheck:e.object({interval:e.number().default(60),timeout:e.number().default(10)}).default({})}),oe=e.object({enabled:e.boolean().default(!1),baseDir:e.string().default(".agentx/graph"),draftAgent:e.string().optional(),reviewAgent:e.string().optional(),autoApproveStructure:e.enum(["strict","extend-leaves","any"]).default("extend-leaves"),autoApproveConfidence:e.number().min(0).max(1).default(1),classifierModel:e.string().default("claude-haiku-4-5-20251001"),retrievalWeights:e.object({graph:e.number().min(0).default(.6),bm25:e.number().min(0).default(.4)}).default({})}).default({}),re=e.object({mode:e.enum(["off","shadow","active"]).default("off"),backend:e.string().optional(),model:e.string().optional(),timeoutMs:e.number().int().min(100).default(1e4),temperature:e.number().min(.01).default(1),explore:e.number().min(0).max(1).default(.15)}).default({}),ie=e.object({enabled:e.boolean().default(!1),dbPath:e.string().default(".agentx/decisions/decisions.sqlite"),redactState:e.boolean().default(!1),keepStateRows:e.number().int().min(0).default(2e3),defaultBackend:e.string().default("local"),backends:e.object({local:e.object({provider:e.string().default("claude-code"),model:e.string().default("claude-haiku-4-5-20251001"),structureMode:e.enum(["auto","tool","text"]).default("auto"),normalizeProbabilities:e.boolean().default(!0),nRetryMalformedStructure:e.number().int().min(0).max(3).default(1),maxStateChars:e.number().int().min(500).default(24e3)}).default({}),simpleJev:e.object({baseUrl:e.string().default("http://127.0.0.1:8000/v1"),model:e.string().optional(),apiKeyEnv:e.string().optional(),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(6e3),maxChoiceOptions:e.number().int().min(2).max(255).default(50)}).default({}),jev:e.object({baseUrl:e.string().default("https://openrouter.ai/api/alpha"),path:e.string().default("/decisions"),model:e.string().default("jev-latest"),apiKeyEnv:e.string().default("OPENROUTER_API_KEY"),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(9e4),maxChoiceOptions:e.number().int().min(2).max(255).default(255)}).default({}),typesafe:e.object({baseUrl:e.string().default("https://api.typesafe.ai/v1"),path:e.string().default("/systemone"),model:e.string().default("jev-latest"),apiKeyEnv:e.string().default("TYPESAFE_API_KEY"),timeoutMs:e.number().int().min(100).default(3e4),maxStateChars:e.number().int().min(500).default(9e4),maxChoiceOptions:e.number().int().min(2).max(255).default(255)}).default({})}).default({}),seats:e.record(e.string(),re).default({}),routing:e.object({cheapModel:e.string().optional(),cheapModels:e.object({"claude-code":e.string().optional(),"codex-cli":e.string().optional()}).optional()}).default({})}).default({}),se=e.object({longTaskThreshold:e.number().default(30),destination:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),on:e.object({taskComplete:e.boolean().default(!0),taskError:e.boolean().default(!0),taskQueued:e.boolean().default(!1)}).default({})}).default({}),w=e.object({node:e.object({id:e.string(),name:e.string(),bind:e.string().default("127.0.0.1:18800"),defaultAgent:e.string().optional()}),providers:e.record(e.string(),Z).default({}),agents:e.record(e.string(),Y).default({}),channels:V.default({}),crons:e.record(e.string(),X).default({}),services:e.record(e.string(),ee).default({}),notifications:se,mesh:ae.default({}),business:h.optional(),boards:x,dashboard:S,graph:oe,decisions:ie,workflows:e.object({enabled:e.boolean().default(!1),dir:e.string().default(".agentx/workflows"),n8n:e.object({baseUrl:e.string().default(""),apiKey:e.string().default("")}).default({baseUrl:"",apiKey:""}),matching:e.object({enabled:e.boolean().default(!1),mode:e.enum(["suggest","auto"]).default("suggest"),autoRunThreshold:e.number().min(0).max(1).default(.85),suggestThreshold:e.number().min(0).max(1).default(.65)}).default({}),editor:e.enum(["disabled","readonly","edit"]).default("edit")}).default({}),procedures:e.object({enabled:e.boolean().default(!0),dir:e.string().default(".agentx/procedures"),extraction:e.object({enabled:e.boolean().default(!1),onTaskCompletion:e.boolean().default(!1),minOccurrences:e.number().int().min(2).default(3),sinceDays:e.number().int().min(1).default(7),maxClusters:e.number().int().min(1).default(5),via:e.string().optional()}).default({}),injection:e.object({enabled:e.boolean().default(!0),maxProcedures:e.number().int().min(1).default(2),minScore:e.number().min(0).max(1).default(.5)}).default({})}).default({}),webhooks:e.array(e.object({id:e.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"webhook id must be lowercase slug"),source:e.string().min(1),agentId:e.string(),secretEnv:e.string().optional(),description:e.string().optional(),enabled:e.boolean().default(!0),node:e.string().optional(),triggers:e.record(e.string(),e.string()).optional(),defaultWorkflow:e.string().optional()})).default([]),session:e.object({staleMinutes:e.number().int().min(1).max(1440).default(720),maxTurnsPerSession:e.number().int().min(2).max(200).default(40),tierTwoThresholdTokens:e.number().int().min(5e4).max(2e5).default(18e4),contextStrategy:e.enum(["layered","planner"]).default("layered"),maxClaudeCodeDispatchesPerHour:e.number().int().min(1).max(1e4).default(80),maxClaudeCodeDispatchesPer5h:e.number().int().min(1).max(5e4).default(180),continuityStateTurns:e.number().int().min(0).max(5).default(0)}).default({}),plugins:e.array(e.string()).default([]),processPool:e.object({maxIdleSeconds:e.number().int().min(5).max(86400).default(30),maxAgeSeconds:e.number().int().min(60).max(86400).default(2700),sweepIntervalSeconds:e.number().int().min(1).max(300).default(5)}).default({})})});export{be as a,he as b,k as c,G as d,w as e,g as f,de as g,ce as h,ue as i,fe as j};
|
|
13
|
+
//# sourceMappingURL=chunk-GMNKJXTR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/business/config.ts","../src/boards/config.ts","../src/daemon/config.ts"],"sourcesContent":["import { z } from \"zod\"\n\n// --- Business layer configuration schema (EXPERIMENTAL) ---\n// Optional top-level `business` key in agentx.json.\n// When enabled, AgentX simulates a team with roles, schedules, and a work pool.\n// Experimental: off by default, undocumented while the model settles —\n// config shape may change between minor versions without migration.\n\nconst dayEnum = z.enum([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"])\n\nconst scheduleSchema = z.object({\n days: z.array(dayEnum).default([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"]),\n start: z.string().regex(/^\\d{2}:\\d{2}$/), // \"09:00\"\n end: z.string().regex(/^\\d{2}:\\d{2}$/), // \"17:00\"\n lunch: z.object({\n start: z.string().regex(/^\\d{2}:\\d{2}$/),\n end: z.string().regex(/^\\d{2}:\\d{2}$/),\n }).optional(),\n})\n\nconst roleSchema = z.object({\n title: z.string(),\n responsibilities: z.array(z.string()).default([]),\n sopPath: z.string().optional(),\n kpis: z.array(z.string()).default([]),\n})\n\nconst orgEntrySchema = z.object({\n role: z.string(),\n reportsTo: z.string().optional(),\n schedule: scheduleSchema,\n utilizationTarget: z.number().min(0).max(1).default(0.8),\n})\n\nconst channelRefSchema = z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n})\n\nconst workSourceSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"backlog\"),\n path: z.string().default(\".agentx/backlog.md\"),\n }),\n z.object({\n type: z.literal(\"gitlab\"),\n projects: z.array(z.string()).default([]), // empty = all configured gitlab projects\n }),\n z.object({\n type: z.literal(\"wiki\"),\n path: z.string(),\n glob: z.string().default(\"**/*.md\"),\n }),\n])\n\n/** Per-project metadata. Phase 3 of the architectural rescue —\n * `pm` is the agentId responsible for gating dispatches on this\n * project. Optional; when null, dispatches don't go through a PM\n * gate. The wiring lives in `decideAndCommit` (gated by a flag,\n * separate commit). */\nconst projectSchema = z.object({\n /** Project identifier. For GitLab/GitHub: \"owner/repo\". For\n * acme-internal projects: a stable string. */\n id: z.string(),\n /** AgentId of the PM for this project. Looked up by\n * `Organization.pmFor(project)` at dispatch time. */\n pm: z.string().optional(),\n /** Optional client this project belongs to. Used by the activity\n * graph to attribute non-projected events (Telegram chats, free-\n * text WhatsApp, cron jobs) to the right client. Falls back to\n * the leading segment of `id` (split on \"/\") when unset. */\n client: z.string().optional(),\n})\n\n/** Maps a chat or sender to a client/project so free-text channels\n * (telegram/whatsapp/slack/discord/email) get attributed correctly\n * in the activity graph. Without this, every chat lands in the\n * fallback \"internal\" bucket — the operator can't tell which client\n * the agent was helping.\n *\n * Match priority: chatId > username > channel-default. First match\n * wins. All fields except `client` are optional; `project` falls\n * back to `${client}/_chat` when unset. */\nconst contactMapSchema = z.object({\n /** Channel kind, e.g. \"telegram\", \"whatsapp\", \"slack\", \"discord\". */\n channel: z.string().optional(),\n /** Native chat id (\"-100...\" for tg groups, JID for WhatsApp). */\n chatId: z.string().optional(),\n /** Sender username/handle as exposed by the channel adapter. */\n username: z.string().optional(),\n /** Numeric sender id when username is unstable. */\n senderId: z.string().optional(),\n /** Client this contact belongs to. Required. */\n client: z.string(),\n /** Project this contact's traffic should attribute to. Defaults to\n * `${client}/_chat`. */\n project: z.string().optional(),\n /** Display name override for the initiator pill. */\n displayName: z.string().optional(),\n})\n\n/** Per-client policy. Clients are DERIVED from `projects` and `contactMap`\n * — one exists the moment either mentions it — so nothing needs declaring\n * up front. This record only carries overrides for the two things a\n * heuristic cannot know: how fast a delay costs you, and what an agent may\n * do for this client without asking first. */\nconst clientPolicySchema = z.object({\n /** Display name. Defaults to the client id. */\n name: z.string().optional(),\n /** \"client\" is someone who is waiting on you and can be let down; \"own\"\n * is your own product; \"internal\" is machinery with no external clock. */\n kind: z.enum([\"client\", \"internal\", \"own\"]).optional(),\n /** How long a wait may last before it starts costing: \"4h\", \"90m\", \"2d\".\n * Unset means no external clock, so delay is flat. */\n respondWithin: z.string().optional(),\n /** Capabilities an agent may exercise unattended. \"*\" means all. Ignored\n * for kind \"client\" — see mayProceedUnattended(). */\n standing: z.array(z.string()).default([]),\n})\n\nexport const businessConfigSchema = z.object({\n enabled: z.boolean().default(false),\n timezone: z.string().default(\"UTC\"),\n mainChannel: channelRefSchema,\n workSource: workSourceSchema,\n roles: z.record(z.string(), roleSchema).default({}),\n orgChart: z.record(z.string(), orgEntrySchema).default({}),\n /** Per-project metadata. Phase 3 — defaults to empty array, so\n * existing agentx.json files validate without modification. */\n projects: z.array(projectSchema).default([]),\n /** Maps free-text chat senders to a client/project so the activity\n * graph can attribute Telegram/WhatsApp/etc. to the right client\n * instead of the catch-all \"internal\" bucket. */\n contactMap: z.array(contactMapSchema).default([]),\n /** Overrides for derived clients. Keyed by client id; absent entries get\n * defaults, so this stays empty until you need a clock or an\n * authorization. */\n clients: z.record(z.string(), clientPolicySchema).default({}),\n /** Work-tick cadence in minutes during business hours. Default 15. */\n workTickMinutes: z.number().int().min(1).max(60).default(15),\n /** Max queue depth for an idle agent before skipping the work tick (avoids piling up). */\n idleQueueThreshold: z.number().int().min(0).default(0),\n /** Standup-tick gating + plan-driven priorities. The day-cycle's morning\n * STANDUP used to fire unconditionally per agent — operators reported it\n * as \"mechanical\" because it dispatched a Claude turn even when no human\n * had set a plan for the day. Now: the cycle reads\n * .agentx/plans/<date>.md (day → week → month fallback) and either\n * injects the plan as standup priorities, or posts a \"no plan today\"\n * notification to mainChannel and dispatches no agent. */\n standup: z.object({\n /** Master switch. When false, fireStandup is a no-op (silent). */\n enabled: z.boolean().default(true),\n /** Plans directory, relative to the daemon CWD. */\n plansDir: z.string().default(\".agentx/plans\"),\n /** Hard ceiling on how many agents the standup tick can dispatch in a\n * single morning — guards against an org-chart misconfiguration\n * fanning out to dozens of Claude calls before anyone notices. */\n maxAgentsPerDay: z.number().int().min(1).max(100).default(20),\n /** When true, even with a plan present the cycle won't dispatch — only\n * posts the resolved plan to mainChannel for human review. Useful as\n * a kill-switch while iterating on plan formats. */\n dryRun: z.boolean().default(false),\n }).default({}),\n})\n\nexport type BusinessConfig = z.infer<typeof businessConfigSchema>\nexport type BusinessRole = z.infer<typeof roleSchema>\nexport type BusinessOrgEntry = z.infer<typeof orgEntrySchema>\nexport type BusinessSchedule = z.infer<typeof scheduleSchema>\nexport type BusinessWorkSource = z.infer<typeof workSourceSchema>\nexport type BusinessChannelRef = z.infer<typeof channelRefSchema>\nexport type BusinessProject = z.infer<typeof projectSchema>\n","import { z } from \"zod\"\n\n// --- Kanban board configuration ---\n//\n// Top-level optional keys in agentx.json, independent of the business layer:\n//\n// boards: array of kanban boards, each backed by a WorkSource\n// dashboard: HTTP server controlling whether the board UI serves\n//\n// Both default to empty / disabled so existing installs see no change.\n\nexport const boardLabelSchema = z.object({\n /** Label name — used verbatim as the GitLab label string. */\n name: z.string(),\n color: z.string().regex(/^#[0-9a-f]{6}$/i).default(\"#6366f1\"),\n description: z.string().optional(),\n})\n\n/**\n * A board column. `kind` controls what issues land here and how drag-to-this-column\n * mutates the issue:\n *\n * - \"open-backlog\": opened issues that have NO scoped label matching `scopedPrefix`\n * (default \"Status\"). Dragging INTO this column removes any existing scoped label.\n * - \"scoped-label\": opened issues carrying `scopedLabel` (e.g. \"Status::Doing\").\n * Scoped labels are mutually exclusive by prefix, so adding the new one lets\n * GitLab auto-remove the old one (Premium), but we still explicitly strip the\n * previous column's label for compatibility.\n * - \"closed\": all closed issues. Dragging here closes the issue; dragging away\n * reopens it.\n * - \"label\" (default, legacy): opened issues with `mapsToLabel`; flat add/remove.\n */\nexport const boardColumnSchema = z.object({\n id: z.string().regex(/^[a-z0-9_-]+$/, \"column id must be lowercase slug\"),\n title: z.string(),\n kind: z.enum([\"open-backlog\", \"scoped-label\", \"closed\", \"label\"]).default(\"label\"),\n /** For kind=\"label\": label written on entry, removed on exit. */\n mapsToLabel: z.string().optional(),\n /** For kind=\"scoped-label\": the full scoped label (e.g. \"Status::Doing\"). */\n scopedLabel: z.string().optional(),\n /** For kind=\"open-backlog\": scoped prefix that marks \"claimed\" cards to exclude. */\n scopedPrefix: z.string().default(\"Status\"),\n /** CSS color or hex — shown as the column's top accent bar. */\n accent: z.string().optional(),\n})\nexport type BoardColumnId = string\n\nexport const boardReconcileSchema = z.object({\n enabled: z.boolean().default(true),\n staleDoingMinutes: z.number().int().min(1).default(45),\n respectLunchBreak: z.boolean().default(true),\n respectSchedule: z.boolean().default(true),\n /** Badge only for P1/P3; auto-notify + auto-demote deferred. */\n action: z.enum([\"badge\", \"notify\"]).default(\"badge\"),\n})\n\nexport const boardSourceSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"gitlab\"),\n /** GitLab project paths (e.g. \"globex/globex-system-v2\"). At least one required. */\n projects: z.array(z.string()).min(1),\n }),\n // future: backlog, wiki\n])\n\n/**\n * GitLab-style default board — six columns:\n * Open (backlog) → To Do → Doing → On Hold → Review → Closed\n *\n * Drives the `Status::*` scoped label taxonomy. Moving a card adds/removes the\n * column's scoped label; moving INTO Closed closes the issue; moving OUT of\n * Closed reopens it; moving INTO Open strips any Status::* label.\n */\nexport const DEFAULT_COLUMNS: Array<z.infer<typeof boardColumnSchema>> = [\n { id: \"open\", title: \"Open\", kind: \"open-backlog\", scopedPrefix: \"Status\", accent: \"#6b7280\" },\n { id: \"todo\", title: \"To Do\", kind: \"scoped-label\", scopedLabel: \"Status::To Do\", scopedPrefix: \"Status\", accent: \"#fb7a35\" },\n { id: \"doing\", title: \"Doing\", kind: \"scoped-label\", scopedLabel: \"Status::Doing\", scopedPrefix: \"Status\", accent: \"#22c55e\" },\n { id: \"onhold\", title: \"On Hold\", kind: \"scoped-label\", scopedLabel: \"Status::On Hold\", scopedPrefix: \"Status\", accent: \"#f59e0b\" },\n { id: \"review\", title: \"Review\", kind: \"scoped-label\", scopedLabel: \"Status::Review\", scopedPrefix: \"Status\", accent: \"#3b82f6\" },\n { id: \"closed\", title: \"Closed\", kind: \"closed\", scopedPrefix: \"Status\", accent: \"#6b7280\" },\n]\n\nexport const boardSchema = z.object({\n id: z.string().regex(/^[a-z0-9_-]+$/, \"board id must be lowercase slug\"),\n name: z.string(),\n source: boardSourceSchema,\n /** If set, ANDed into every listAll query and shown as a baseline chip in the UI. */\n primaryToolLabel: z.string().optional(),\n labels: z.array(boardLabelSchema).default([]),\n columns: z.array(boardColumnSchema).min(1).default(DEFAULT_COLUMNS),\n timeRangeDays: z.number().int().min(1).max(365).default(30),\n /** Maximum closed-issue window (days) shown in the Closed column. */\n closedWindowDays: z.number().int().min(1).max(365).default(30),\n reconciliation: boardReconcileSchema.default({}),\n})\n\nexport const boardsConfigSchema = z.array(boardSchema).default([])\n\nexport const dashboardDaemonSchema = z.object({\n name: z.string(),\n /** Daemon HTTP URL (the one serving /agents, /health, /task). */\n url: z.string(),\n /** Optional board-dashboard URL if we want to proxy admin writes to this\n * peer. Defaults to `url` with port :18800/:19900 rewritten to :4202,\n * matching our convention that the dashboard runs alongside the daemon. */\n dashboardUrl: z.string().optional(),\n /** Bearer for the daemon's HTTP API (live snapshot, task stream). */\n token: z.string().optional(),\n /** Bearer for the peer's dashboard when proxying admin calls. Defaults to\n * `token` when unset. */\n dashboardToken: z.string().optional(),\n})\n\nexport const dashboardConfigSchema = z.object({\n enabled: z.boolean().default(false),\n port: z.number().int().default(4202),\n bind: z.string().default(\"127.0.0.1\"),\n /** Opt-in bearer token for writes. If unset, writes are unauthenticated. */\n token: z.string().optional(),\n /** Primary daemon the dashboard talks to for live view + A2A. */\n daemonUrl: z.string().default(\"http://localhost:18800\"),\n /** Additional daemons to poll (beyond peers discovered via primary's /mesh). */\n daemons: z.array(dashboardDaemonSchema).default([]),\n /** Default agent used for AI-assisted drafting in the create-issue flow. */\n draftAgent: z.string().optional(),\n}).default({})\n\nexport type BoardConfig = z.infer<typeof boardSchema>\nexport type BoardLabel = z.infer<typeof boardLabelSchema>\nexport type BoardColumn = z.infer<typeof boardColumnSchema>\nexport type BoardSource = z.infer<typeof boardSourceSchema>\nexport type BoardReconcile = z.infer<typeof boardReconcileSchema>\nexport type DashboardConfig = z.infer<typeof dashboardConfigSchema>\n\n/**\n * Decide which column an item lives in. Walks columns in order; the first\n * matching column wins. Items with `state: \"closed\"` always land in the\n * first `kind: \"closed\"` column; otherwise the first `scoped-label` whose\n * `scopedLabel` is present wins; otherwise the first `label` column whose\n * `mapsToLabel` is present; otherwise the first `open-backlog` column.\n *\n * Returns `null` when the item carries a scoped label matching an\n * `open-backlog` column's `scopedPrefix` but no `scoped-label` column claims\n * it — those are off-board workflow states (e.g. `Status::Done` when no\n * Done column exists) and must not leak into the backlog.\n */\nexport function deriveStage(\n item: { state?: \"opened\" | \"closed\"; labels?: string[] },\n columns: BoardColumn[],\n): BoardColumnId | null {\n const set = new Set(item.labels || [])\n if (item.state === \"closed\") {\n const closed = columns.find((c) => c.kind === \"closed\")\n if (closed) return closed.id\n }\n for (const c of columns) {\n if (c.kind === \"scoped-label\" && c.scopedLabel && set.has(c.scopedLabel)) return c.id\n }\n for (const c of columns) {\n if (c.kind === \"label\" && c.mapsToLabel && set.has(c.mapsToLabel)) return c.id\n }\n const backlog = columns.find((c) => c.kind === \"open-backlog\")\n if (backlog) {\n // If the item has any scoped-prefix label, it's not an open-backlog candidate.\n const prefix = backlog.scopedPrefix + \"::\"\n const hasScoped = [...set].some((l) => l.startsWith(prefix))\n return hasScoped ? null : backlog.id\n }\n return columns[0]?.id ?? null\n}\n\n/**\n * Describes how to mutate an issue to move it between two columns.\n * `closeIssue` / `reopen` take precedence over label mutations on the same action.\n */\nexport interface ColumnTransition {\n addLabels?: string[]\n removeLabels?: string[]\n closeIssue?: boolean\n reopen?: boolean\n}\n\nexport function transitionDiff(\n fromColumn: BoardColumn | undefined,\n toColumn: BoardColumn,\n): ColumnTransition {\n const add: string[] = []\n const remove: string[] = []\n let closeIssue = false\n let reopen = false\n\n // Handle target column.\n if (toColumn.kind === \"scoped-label\" && toColumn.scopedLabel) {\n add.push(toColumn.scopedLabel)\n } else if (toColumn.kind === \"label\" && toColumn.mapsToLabel) {\n add.push(toColumn.mapsToLabel)\n } else if (toColumn.kind === \"closed\") {\n closeIssue = true\n }\n\n // Handle source column — strip its label; if it was \"closed\", reopen.\n if (fromColumn) {\n if (fromColumn.kind === \"scoped-label\" && fromColumn.scopedLabel) {\n remove.push(fromColumn.scopedLabel)\n } else if (fromColumn.kind === \"label\" && fromColumn.mapsToLabel) {\n remove.push(fromColumn.mapsToLabel)\n } else if (fromColumn.kind === \"closed\" && toColumn.kind !== \"closed\") {\n reopen = true\n }\n }\n\n return {\n addLabels: add.length ? add : undefined,\n removeLabels: remove.length ? remove : undefined,\n closeIssue: closeIssue || undefined,\n reopen: reopen || undefined,\n }\n}\n","import { z } from \"zod\"\nimport { readFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { businessConfigSchema } from \"@/business/config\"\nimport { boardsConfigSchema, dashboardConfigSchema } from \"@/boards/config\"\n\n/**\n * Load .env file into process.env (simple, no dependency).\n */\nfunction loadDotEnv(dir: string): void {\n const envPath = resolve(dir, \".env\")\n if (!existsSync(envPath)) return\n\n const content = readFileSync(envPath, \"utf-8\")\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) continue\n const eqIdx = trimmed.indexOf(\"=\")\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const value = trimmed.slice(eqIdx + 1).trim()\n if (!process.env[key]) {\n process.env[key] = value\n }\n }\n}\n\n// --- Daemon configuration schema & loader ---\n\nconst providerConfigSchema = z.object({\n apiKey: z.string().optional(),\n defaultModel: z.string().optional(),\n baseUrl: z.string().optional(),\n /** Toggle thinking-mode output on backends that support it (DeepSeek\n * V4 `reasoning_content`). When `true` (the DeepSeek default), the\n * agent streams its reasoning live in the dashboard task modal and\n * the agentic round-trip echoes it back on the next iteration. Set\n * to `false` to disable for cost/latency-sensitive agents. Ignored\n * on backends that don't speak the thinking-mode protocol. */\n thinking: z.boolean().optional(),\n})\n\nconst mcpStdioServerSchema = z.object({\n type: z.literal(\"stdio\").optional(),\n command: z.string(),\n args: z.array(z.string()).default([]),\n env: z.record(z.string(), z.string()).optional(),\n})\n\nconst mcpHttpServerSchema = z.object({\n type: z.literal(\"http\"),\n url: z.string().url(),\n headers: z.record(z.string(), z.string()).optional(),\n})\n\n// HTTP variant first so a record with `type: \"http\"` matches the HTTP\n// shape; stdio is the default fallback when `type` is absent (keeps the\n// original `{ command, args, env }` configs valid without a migration).\nconst mcpServerSchema = z.union([mcpHttpServerSchema, mcpStdioServerSchema])\n\n/**\n * Per-agent integration registration. Declares which third-party services\n * an agent has credentials for — e.g. \"@cx-bot has a Telegram bot token,\n * a HubSpot private app token, and a Gmail account\". The actual secret is\n * NEVER stored in agentx.json: only an env-var reference (`tokenEnv`) or a\n * keyring directive. Skills, channel adapters, and the action layer read\n * from this registry to discover what an agent can use.\n *\n * The `kind` field is open-string (well-known values listed below in\n * INTEGRATION_KINDS) so new services can be declared without a schema\n * bump. Doctor warns on unknown kinds.\n */\nconst integrationCredentialsSchema = z.object({\n /** Env var holding the secret. Uppercase identifier; daemon resolves at use-time. */\n tokenEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n /** Alternate env-var keys for credential schemes that need >1 secret\n * (e.g. HubSpot private app + portal id, OAuth refresh tokens). */\n privateAppTokenEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n apiKeyEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n refreshTokenEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n clientIdEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n clientSecretEnv: z.string().regex(/^[A-Z][A-Z0-9_]*$/).optional(),\n /** OS keyring directive — credential lives in macOS Keychain / Linux\n * Secret Service / Windows Credential Manager. The skill that reads\n * this integration is responsible for resolving the keyring entry\n * (typically keyed by agentId+kind). */\n auth: z.literal(\"keyring\").optional(),\n /** File-based session directory (WhatsApp, Telegram MTProto, etc.). */\n sessionDir: z.string().optional(),\n}).strict()\n\nconst integrationSchema = z.object({\n /** Service identifier — open string, well-known values in INTEGRATION_KINDS. */\n kind: z.string().min(1),\n /** Human-readable label (e.g. \"@cx_bot\", \"Acme CRM\", \"alex@example.com\"). Unique per (agent, kind). */\n label: z.string().min(1),\n credentials: integrationCredentialsSchema.default({}),\n /** Non-secret metadata — username, email, host URL, portal id, JID, etc.\n * Visible in the dashboard and to skills. */\n metadata: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).default({}),\n /** Operator-set toggle without removing the entry. */\n enabled: z.boolean().default(true),\n})\n\nexport type Integration = z.infer<typeof integrationSchema>\n\n/**\n * Canonical kind list — for autocomplete + doctor validation. Open string\n * schema so new services drop in without a bump; doctor warns when a kind\n * is outside this list.\n */\nexport const INTEGRATION_KINDS = [\n // Inbound channels\n \"telegram-bot\",\n \"whatsapp\",\n // Code platforms (user-scoped tokens, not channel routing)\n \"gitlab-user\",\n \"github-user\",\n // Email\n \"gmail\",\n \"hotmail\",\n \"smtp\",\n // CRM / ERP\n \"hubspot\",\n \"salesforce\",\n \"pipedrive\",\n \"odoo\",\n // Project management\n \"trello\",\n \"linear\",\n \"asana\",\n \"jira\",\n \"notion\",\n // Payments\n \"stripe\",\n // Observability / hosting\n \"sentry\",\n \"vercel\",\n // Voice / SMS\n \"twilio\",\n // Catch-all\n \"custom\",\n] as const\n\nconst agentConfigSchema = z.object({\n name: z.string(),\n workspace: z.string(),\n tier: z.enum([\"claude-code\", \"codex-cli\", \"opencode\", \"sdk\", \"orchestrator\"]).default(\"claude-code\"),\n provider: z.string().optional(),\n model: z.string().optional(),\n systemPrompt: z.string().optional(),\n mentions: z.array(z.string()).default([]),\n /** Phase 5 — typed capabilities (drop-condition fallback). Free-form\n * list of intent strings this agent is allowed to handle. When set,\n * the org-chart `canHandle(agentId, project, intent)` check rejects\n * dispatches with intents not in this list. When empty/unset\n * (the default), the agent is permissive — handles any intent.\n * Intent matching is exact-string for now; a glob/prefix layer can\n * come later if it produces real rejections.\n * Example: [\"issue.opened\", \"issue.commented\", \"merge_request.opened\"]\n * Example: [\"cron.fired\", \"message.received\"] */\n intents: z.array(z.string()).default([]),\n /** Phase 8 — capability-bounded security. Max distinct upstream\n * agents in the delegation chain on the same (project, subject)\n * before a dispatch to THIS agent is refused. The ledger itself\n * provides the chain — `decideAndCommit` walks recent decisions on\n * the subject and counts distinct agents. Default 5; set to 0 to\n * disable for an agent that's always called as the bottom of a\n * chain. The check prevents cascade loops where A → B → A → B → ...\n * blows past sane chain depth. */\n maxDelegationDepth: z.number().int().min(0).max(50).default(5),\n /** MCP servers this agent's Claude Code session should load. Synced\n * to <workspace>/.mcp.json at daemon boot via agent-mcp.ts. Operator\n * edits to .mcp.json are respected (see SyncResult.skipped-operator-owned). */\n mcp: z.record(z.string(), mcpServerSchema).optional(),\n /** Enable CodeGraph (https://github.com/colbymchenry/codegraph) for this\n * agent's claude-code or codex-cli workspace. When true, agentx (a) adds\n * a codegraph MCP server to <workspace>/.mcp.json, (b) extends\n * .claude/settings.json permissions.allow with the codegraph_* tools,\n * (c) appends a CodeGraph instruction section to the managed CLAUDE.md,\n * and (d) background-indexes the workspace at daemon boot if .codegraph/\n * is missing. Off by default — flip on for coding agents (globex-v2-coder,\n * initech-v2-coder, umbrella-coding, etc.) where token-volume on exploration\n * loops is the bottleneck. */\n codegraph: z.boolean().default(false),\n /** Per-agent override for the global `session.contextStrategy`. Lets\n * one agent run `planner` (smaller upfront context, more tool-driven\n * exploration) while siblings stay on `layered`. Used for agents that\n * consistently bloat their cache via large workspace reads. */\n contextStrategy: z.enum([\"layered\", \"planner\"]).optional(),\n /** When true, the registry resolves references-recipes for this agent's\n * workspace and renders a deterministic [Verified References] block at\n * priority 4.7. Off by default — flip on per agent (pm-initech, devops-agent,\n * etc.) once a `references/` registry exists in the agent's workspace\n * or repo root. See src/agents/references/. */\n contextReferences: z.boolean().default(false),\n /** Whether this agent may emit in-band `agentx:ui` rich-message directives\n * (buttons/polls/media) on chat channels. Default true — set false to make\n * the render layer strip any directive and send plain text only. */\n richMessages: z.boolean().default(true),\n maxConcurrent: z.number().default(1),\n /** Hard wall-clock cap on a single Claude Code invocation. Exceeding the\n * cap sends SIGTERM (exit 143). Default 20 min — bump for devops/coder\n * agents that do long investigations or multi-file refactors. */\n maxExecutionMinutes: z.number().int().min(1).max(240).default(20),\n permissionMode: z.string().default(\"default\"),\n /** Improvement plan #3 — tool-use-required preset. When set,\n * AgentX inspects the stream-json events from each task and\n * fails the response with `tool_required_not_called: <name>`\n * when none of the listed tool names was invoked. Catches the\n * silent-degrade pattern observed when a model below the\n * capability bar (e.g. Haiku on a Write-required prompt)\n * produces a plausible-looking text response without ever\n * calling the required tool. Caller can retry with a stronger\n * model or sharpen the prompt.\n *\n * Tool names match the canonical Claude Code names (\"Write\",\n * \"Edit\", \"Bash\", \"Read\", …). Free-form so future tools work\n * without a schema bump. Empty/unset means no enforcement\n * (default — backward compatible). */\n toolUseRequired: z.array(z.string()).default([]),\n /** Per-agent override for the channel-level `autoReplyLegacy` on\n * gitlab/github. When set, it wins over `channels.<name>.autoReplyLegacy`\n * for this agent's replies: `true` makes the daemon auto-post the agent's\n * final text as a comment (right for coder agents that end their turn with\n * a summary and don't call `agentx_channel_reply`); `false` suppresses it\n * (right for chatty agents whose reasoning shouldn't land as a comment).\n * Unset → fall back to the channel default. */\n gitlabAutoReply: z.boolean().optional(),\n /** Opt into process reuse for claude-code (stream-json) or codex-cli\n * (app-server), or opencode (dedicated v2 server). Conversations have isolated processes. Unsupported Codex\n * versions fall back to exec before submitting any turn. Other tiers\n * ignore this flag. Codex loads the operator's Codex config, unlike exec's\n * --ignore-user-config path: review additional MCP servers before enabling.\n * Codex and OpenCode each use an 8-process cap and 5-minute idle eviction; processPool\n * settings apply to Claude only. Default false for gradual rollout.\n * See docs/architecture/persistent-codex-process.md and\n * docs/architecture/persistent-claude-process.md and\n * docs/architecture/persistent-opencode-process.md for details. */\n persistentProcess: z.boolean().default(false),\n queueMode: z.enum([\"collect\", \"followup\", \"drop\"]).default(\"collect\"),\n heartbeat: z.object({\n enabled: z.boolean().default(false),\n intervalMinutes: z.number().default(30),\n prompt: z.string().default(\"Check inbox, pending tasks, and system health. Report anything that needs attention.\"),\n channel: z.string().default(\"heartbeat\"),\n }).default({}),\n /** Reachability via the external public API.\n * - \"private\" (default): this agent is daemon-internal + channel-bound only.\n * - \"public\": external apps can POST /api/public/agents/<id>/messages\n * with a scoped token (agent:<id> or agent:*). */\n access: z.enum([\"private\", \"public\"]).default(\"private\"),\n /** Per-agent third-party integrations registry. Declares which services\n * this agent has credentials for (telegram-bot, hubspot, gitlab-user,\n * gmail, etc.). Secrets stay in env vars / keyring; this block holds\n * declarations + non-secret metadata only. Skills and channel adapters\n * read from here to know what the agent can use. See INTEGRATION_KINDS. */\n integrations: z.array(integrationSchema).default([]),\n})\n\nconst telegramAccountSchema = z.object({\n token: z.string(),\n agentBinding: z.string(),\n /** Per-account sender allowlist. When set, OVERRIDES the global\n * `policy.allowFrom`. Entries accept:\n * - numeric user id (\"1816212449\") — matches sender (from.id)\n * - numeric chat id (\"-1003861455814\") — matches chat (chat.id)\n * - \"@username\" — matches sender username\n * A message is dispatched iff at least one entry matches. */\n allowFrom: z.array(z.string()).optional(),\n /** When false, the daemon keeps the bot token registered so outbound\n * `send()` / ring notifications work, but does NOT long-poll for inbound\n * updates. Use this on nodes where the bound agent lives on a different\n * daemon — otherwise two daemons race on the same `getUpdates` cursor and\n * Telegram responds 409 Conflict on every poll.\n * Defaults to true (poll) so existing single-node setups are unchanged. */\n pollInbound: z.boolean().default(true),\n})\n\nconst channelsConfigSchema = z.object({\n telegram: z.object({\n enabled: z.boolean().default(false),\n accounts: z.record(z.string(), telegramAccountSchema).default({}),\n policy: z.object({\n dm: z.enum([\"pair\", \"block\"]).default(\"pair\"),\n group: z.enum([\"mention-required\", \"all\"]).default(\"mention-required\"),\n /** Global sender allowlist applied to every account that doesn't set\n * its own `allowFrom`. When neither is configured, every incoming\n * message is dropped — closed by default. Same entry forms as the\n * per-account list (user id, chat id, @username). */\n allowFrom: z.array(z.string()).optional(),\n }).default({}),\n }).default({}),\n whatsapp: z.object({\n enabled: z.boolean().default(false),\n sessionDir: z.string().default(\".agentx/whatsapp-sessions\"),\n defaultAgent: z.string().optional(),\n allowFrom: z.array(z.string()).optional(),\n routes: z.array(z.object({\n contact: z.string().optional(),\n group: z.string().optional(),\n agent: z.string(),\n })).default([]),\n /** Data-source ingestion — turns WhatsApp from a messaging-only channel\n * into a source that seeds the wiki with contact/group metadata (and\n * optionally bounded message windows) per an explicit allowlist.\n * Default-deny: `enabled: false` and empty allowlists mean nothing is\n * ingested. See docs/reference/whatsapp-ingest.md for the full story. */\n ingest: z.object({\n enabled: z.boolean().default(false),\n /** `metadata-only` pulls contact/group info; `messages` additionally\n * pulls the last `messageCap` messages per allowlisted chat. */\n mode: z.enum([\"metadata-only\", \"messages\"]).default(\"metadata-only\"),\n /** Phone numbers or JIDs. Substring match, same semantics as allowFrom. */\n allowContacts: z.array(z.string()).default([]),\n allowGroups: z.array(z.string()).default([]),\n denyContacts: z.array(z.string()).default([]),\n denyGroups: z.array(z.string()).default([]),\n /** Per-chat cap when mode = \"messages\". Keeps the raw-entry size bounded. */\n messageCap: z.number().int().min(1).max(500).default(50),\n /** Max age (days) of messages to consider for the bounded window. */\n historyDays: z.number().int().min(1).max(365).default(30),\n /** Skip re-writing a contact entry unless this many days have passed\n * OR the profile hash differs. Prevents churn on unchanged profiles. */\n contactRefreshDays: z.number().int().min(1).max(90).default(7),\n /** Safety rails on live Baileys reads — personal-account accounts\n * can get throttled/banned under burst reads. */\n throttle: z.object({\n minMsBetweenCalls: z.number().int().min(100).default(1500),\n maxCallsPerMinute: z.number().int().min(1).default(20),\n maxChatsPerSweep: z.number().int().min(1).default(25),\n }).default({}),\n /** Purge absorbed raw entries older than this many days. `0` = never. */\n retentionDays: z.number().int().min(0).default(0),\n }).default({}),\n }).default({}),\n gitlab: z.object({\n enabled: z.boolean().default(false),\n webhookPort: z.number().default(18810),\n webhookSecret: z.string().optional(),\n host: z.string().default(\"https://gitlab.com\"),\n token: z.string().optional(),\n /** Legacy auto-reply: when true (default), the router posts the agent's\n * `response.content` as a comment automatically. When false, the agent\n * must call the `channel.reply` action explicitly to reply — agent\n * reasoning text is logged but not posted. Flip to false once the\n * project's agents have migrated their gitlab skill to use channel.reply.\n * Default true preserves today's behaviour for unmigrated projects. */\n autoReplyLegacy: z.boolean().default(true),\n routes: z.array(z.object({\n project: z.string(),\n agent: z.string(),\n })).default([]),\n agentMappings: z.array(z.object({\n agentId: z.string(),\n gitlabUsernames: z.array(z.string()).default([]),\n keywords: z.array(z.string()).default([]),\n token: z.string().optional(),\n /** If set, the agent lives on a remote mesh peer (node id). Forces the\n * username→agent map to resolve to this mapping even when a local\n * agent's token resolves to the same GitLab user — prevents collisions\n * like two agents both claiming @devops-acme. */\n node: z.string().optional(),\n })).default([]),\n }).default({}),\n github: z.object({\n enabled: z.boolean().default(false),\n /** Legacy auto-reply — same semantics as gitlab.autoReplyLegacy.\n * Defaults true; set false once agent skills use channel.reply. */\n autoReplyLegacy: z.boolean().default(true),\n /** GitHub PAT or env var (${GITHUB_TOKEN}) for posting comments back. */\n token: z.string().optional(),\n /** Path to file containing the token (first line read at startup). */\n tokenFile: z.string().optional(),\n /** GitHub App ID (legacy issuer). */\n appId: z.number().optional(),\n /** GitHub App Client ID (preferred JWT issuer per GitHub's updated docs). */\n clientId: z.string().optional(),\n /** Path to the GitHub App private key PEM file. */\n privateKeyFile: z.string().optional(),\n /** Webhook secret for validating X-Hub-Signature-256. */\n webhookSecret: z.string().optional(),\n /** Repo → agent routing. Use \"owner/repo\" or \"*\" for default. */\n routes: z.array(z.object({\n repo: z.string(),\n agent: z.string(),\n })).default([]),\n /** Per-agent identity mappings (GitHub usernames, tokens, mesh nodes). */\n agentMappings: z.array(z.object({\n agentId: z.string(),\n githubUsernames: z.array(z.string()).default([]),\n token: z.string().optional(),\n tokenFile: z.string().optional(),\n node: z.string().optional(),\n })).default([]),\n }).default({}),\n /** ntfy push notifications — outbound only. The operator-facing tap on\n * the shoulder: cron failures, task errors, and anything an agent decides\n * is worth interrupting a human for. `chatId` on an outgoing message is\n * the topic; empty falls back to `topic` here. */\n ntfy: z.object({\n enabled: z.boolean().default(false),\n /** Self-hosted ntfy base URL. Defaults to the public server. */\n server: z.string().default(\"https://ntfy.sh\"),\n /** Default topic. Treat it as a secret — on ntfy.sh, knowing the topic\n * is the only thing needed to read or publish to it. */\n topic: z.string().optional(),\n /** Access token for protected topics. */\n token: z.string().optional(),\n /** 1 (min) .. 5 (max). ntfy's own default is 3. */\n defaultPriority: z.number().int().min(1).max(5).default(3),\n defaultTitle: z.string().optional(),\n }).default({}),\n webrtc: z.object({\n enabled: z.boolean().default(false),\n /** ICE STUN servers for NAT discovery. Default is Google's public STUN. */\n stunServers: z.array(z.string()).default([\"stun:stun.l.google.com:19302\"]),\n /** Optional TURN relays (required when both peers are behind symmetric NAT). */\n turnServers: z.array(z.object({\n urls: z.string(),\n username: z.string().optional(),\n credential: z.string().optional(),\n })).default([]),\n /** Peer names permitted to *initiate* a call into this daemon. Empty = allow all mesh peers. */\n allowedCallers: z.array(z.string()).default([]),\n /** Where to send \"someone is calling\" notifications when an inbound ring\n * arrives. Each entry is delivered via the matching channel adapter —\n * same plumbing as any other outbound message. Empty disables notifications. */\n ringNotify: z.array(z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n })).default([]),\n /** Base URL used when building the tap-to-join link in ring notifications.\n * Defaults to `http://<node.bind>` — override when the daemon's public\n * hostname differs (e.g. HTTPS-terminated tunnel, Tailscale MagicDNS). */\n callUrlBase: z.string().optional(),\n /** AI participant (\"bot\") joins calls when a browser opens with `?bot=<id>`.\n * v1 is transcribe-only — bot consumes remote audio, transcribes via\n * Whisper, posts chunks to the configured channel. No TTS-back. */\n bot: z.object({\n enabled: z.boolean().default(false),\n /** Default agent id used to attribute the transcript when the URL\n * doesn't override via `?bot=<other-agent>`. */\n defaultAgentId: z.string().optional(),\n /** \"auto\" tries mlx-whisper, falls back to OpenAI; explicit forces. */\n whisperBackend: z.enum([\"auto\", \"mlx\", \"openai\"]).default(\"auto\"),\n whisperModel: z.string().optional(),\n whisperLanguage: z.string().default(\"auto\"),\n /** Absolute path to mlx_whisper if not on the daemon's PATH (common\n * on macOS launchd, where ~/.pyenv/shims is missing from the env). */\n mlxBinary: z.string().optional(),\n /** Where to send each transcribed chunk. Same shape as ringNotify[]. */\n transcriptChannel: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n /** Hard cap so a forgotten bot doesn't run forever. */\n maxCallMinutes: z.number().int().min(1).max(240).default(30),\n }).default({}),\n }).default({}),\n})\n\nconst cronJobSchema = z.object({\n enabled: z.boolean().default(true),\n schedule: z.string(),\n timezone: z.string().default(\"UTC\"),\n agent: z.string(),\n prompt: z.string().default(\"\"),\n /**\n * A shell command to run INSTEAD of dispatching the agent.\n *\n * Seven of this fleet's twenty-six crons were a single command wrapped\n * in an agent, and every one of them carried a paragraph like \"Run this\n * EXACT command. Do NOT substitute, rewrite, shorten, or fall back to\n * alternative commands.\" That paragraph is a scar: it exists because\n * models kept substituting, and no amount of prompt severity makes a\n * language model a deterministic executor.\n *\n * Measured before this existed: ~$0.31 and ~24s per run to execute one\n * `node script.js` and repeat ten lines of its output — a 114k-token\n * context for a job with no judgement in it at all.\n *\n * When set, the scheduler runs the command directly. No model, no\n * tokens, no improvisation. `agent` is still required and is who gets\n * told when it fails.\n */\n command: z.string().optional(),\n timeout: z.number().default(600),\n model: z.string().optional(),\n /** Soft cap on output length. Claude Code CLI has no hard flag for this,\n * but appending an instruction to the prompt is reliably honored. Use\n * 1500 for briefs, 500 for status pings, 300 for pure classifiers. */\n maxOutputTokens: z.number().int().min(50).max(8000).optional(),\n onError: z.union([\n z.enum([\"log\", \"notify\", \"disable\"]),\n z.array(z.enum([\"log\", \"notify\", \"disable\"])),\n ]).default(\"log\").transform(v => Array.isArray(v) ? v : [v]),\n notify: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n}).refine((j) => Boolean(j.command?.trim() || j.prompt?.trim()), {\n message: \"a cron needs either a prompt (dispatch an agent) or a command (run it directly)\",\n})\n\nconst serviceSchema = z.object({\n name: z.string(),\n triggers: z.array(z.object({\n pattern: z.string(),\n channel: z.string().optional(),\n })),\n allowedContacts: z.array(z.string()).optional(),\n agent: z.string(),\n prompt: z.string(),\n schedule: z.string().optional(),\n timezone: z.string().default(\"UTC\"),\n notify: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n})\n\nconst meshPeerSchema = z.object({\n url: z.string(),\n name: z.string(),\n token: z.string().optional(),\n})\n\n/** A named, operator-declared destination that remote mesh nodes may send\n * to. Deliberately minimal: the published surface is the name and whether\n * it accepts, so there is nothing here that could leak local state if it\n * were echoed back. Which agent handles it stays private to this node. */\nconst meshInboxSchema = z.object({\n name: z.string(),\n agent: z.string(),\n enabled: z.boolean().default(true),\n})\n\nconst meshConfigSchema = z.object({\n enabled: z.boolean().default(false),\n peers: z.array(meshPeerSchema).default([]),\n /** Empty by default — a node publishes no inboxes until an operator\n * declares one, so this feature is opt-in per node. */\n inboxes: z.array(meshInboxSchema).default([]),\n discovery: z.enum([\"static\", \"mdns\"]).default(\"static\"),\n healthCheck: z.object({\n interval: z.number().default(60),\n timeout: z.number().default(10),\n }).default({}),\n})\n\n/** Intent Knowledge Graph — fixed-axis, LLM-proposed taxonomy used by the\n * Intent layer in context.ts and (eventually) wiki retrieval. Off by default\n * so existing installs see no change. */\nconst graphConfigSchema = z.object({\n enabled: z.boolean().default(false),\n /** Where the schema/nodes/classifications live. Relative to cwd. */\n baseDir: z.string().default(\".agentx/graph\"),\n /** Which agent makes LLM classification proposals. Falls back to\n * `dashboard.draftAgent` at call sites if unset. */\n draftAgent: z.string().optional(),\n /** Agent used by `agentx graph review` to triage pending classifications.\n * Should be an agent with the wiki skill so it can call `wiki query` for\n * context before deciding approve/reject. Falls back to draftAgent. */\n reviewAgent: z.string().optional(),\n /** Structural auto-approval policy. Evaluated against each classification\n * independently of `autoApproveConfidence`; either triggers approval.\n * - \"strict\" : never approve via structure — every classification\n * waits for human review\n * - \"extend-leaves\" : auto-approve when the proposed path (a) reuses only\n * existing nodes, or (b) adds exactly one NEW node at\n * the deepest level. Structural changes (new mid-path\n * node, new root) still queue for review. Default.\n * - \"any\" : auto-approve every classification regardless of\n * structural change\n */\n autoApproveStructure: z.enum([\"strict\", \"extend-leaves\", \"any\"]).default(\"extend-leaves\"),\n /** Minimum classifier confidence (0..1) to auto-approve. OR'd with the\n * structural policy — either hitting the threshold lets the classification\n * bypass the pending queue. 1.0 (default) disables this knob, so approval\n * is driven by `autoApproveStructure` alone. Lower it to e.g. 0.7 if you\n * also want high-confidence structural changes auto-approved. */\n autoApproveConfidence: z.number().min(0).max(1).default(1.0),\n /** Anthropic model id used for the direct classifier call (Phase 2 of\n * classifier-retire). Default haiku — classification is metadata, not\n * work, so we use the cheapest fast model. Override only if Haiku is\n * rate-limited or you want to A/B test. */\n classifierModel: z.string().default(\"claude-haiku-4-5-20251001\"),\n /** Weights for the wiki hybrid retrieval score. Path-ancestry match vs\n * BM25 over article text. Sum need not be 1. */\n retrievalWeights: z.object({\n graph: z.number().min(0).default(0.6),\n bm25: z.number().min(0).default(0.4),\n }).default({}),\n}).default({})\n\n// --- Typed-decision seats (src/decisions) ---\n//\n// Everything here defaults off. A seat in \"shadow\" runs alongside the\n// incumbent and only records; \"active\" lets its answer steer behaviour, and\n// no seat should reach it before its calibration report says what threshold\n// to use and what that threshold costs.\nconst decisionSeatSchema = z.object({\n /** off: the seat is unreachable. shadow: runs and records, incumbent stays\n * authoritative. active: the answer is used. */\n mode: z.enum([\"off\", \"shadow\", \"active\"]).default(\"off\"),\n /** Backend name from the decisions registry. Per-seat, so one seat can be\n * graded against a different backend than another at the same time. */\n backend: z.string().optional(),\n model: z.string().optional(),\n timeoutMs: z.number().int().min(100).default(10_000),\n /** Post-hoc temperature fitted on this seat's own labeled rows. 1 means\n * \"not calibrated yet\", which is where every seat starts — see\n * `agentx decisions calibrate`. */\n temperature: z.number().min(0.01).default(1),\n /** Fraction of would-be-skips to run anyway. Not a tuning knob: a skipped\n * decision can never be graded, so without exploration an active seat's\n * metrics are computed on the biased sample it selected for itself.\n * Setting this to 0 in active mode means the calibration report stops\n * being trustworthy the day you promote the seat. */\n explore: z.number().min(0).max(1).default(0.15),\n}).default({})\n\nconst decisionsConfigSchema = z.object({\n enabled: z.boolean().default(false),\n dbPath: z.string().default(\".agentx/decisions/decisions.sqlite\"),\n /** State can contain message text. With this on, only the hash is kept,\n * which costs the ability to replay a decision offline. */\n redactState: z.boolean().default(false),\n /** Keep the serialized state for this many rows per seat, then prune to\n * hashes. Enough to replay and to grade an alternative backend on\n * identical inputs, without growing without bound. */\n keepStateRows: z.number().int().min(0).default(2000),\n defaultBackend: z.string().default(\"local\"),\n backends: z.object({\n local: z.object({\n provider: z.string().default(\"claude-code\"),\n model: z.string().default(\"claude-haiku-4-5-20251001\"),\n /** auto resolves to a forced tool where the provider guarantees one,\n * and JSON-in-text otherwise (claude-code on OAuth cannot force a\n * tool). Never resolves to logprobs: that costs one call per\n * question, so it has to be asked for. */\n structureMode: z.enum([\"auto\", \"tool\", \"text\"]).default(\"auto\"),\n normalizeProbabilities: z.boolean().default(true),\n nRetryMalformedStructure: z.number().int().min(0).max(3).default(1),\n maxStateChars: z.number().int().min(500).default(24_000),\n }).default({}),\n /** A simple-jev server (featherless-ai/simple-jev). Reads the model's\n * next-token logits rather than asking it to write a probability, so\n * the distribution is the model's posterior instead of a number it\n * chose. Still not calibrated to correctness — that comes from\n * `agentx decisions recalibrate`. */\n simpleJev: z.object({\n baseUrl: z.string().default(\"http://127.0.0.1:8000/v1\"),\n model: z.string().optional(),\n apiKeyEnv: z.string().optional(),\n timeoutMs: z.number().int().min(100).default(30_000),\n maxStateChars: z.number().int().min(500).default(6_000),\n /** Their Choice takes 2-50 candidates, well under Jev's 255. */\n maxChoiceOptions: z.number().int().min(2).max(255).default(50),\n }).default({}),\n /** TypeSafe Jev through OpenRouter's alpha decisions endpoint.\n * Verified live 2026-09-19 — resolves to typesafe/jev-1.13-20260917,\n * provider \"TypeSafe\", ~0.5s round trip. The id is \"jev-latest\";\n * the namespaced \"typesafe/jev-latest\" 400s, and neither appears in\n * OpenRouter's public model list. Needs OPENROUTER_API_KEY. */\n jev: z.object({\n baseUrl: z.string().default(\"https://openrouter.ai/api/alpha\"),\n path: z.string().default(\"/decisions\"),\n model: z.string().default(\"jev-latest\"),\n apiKeyEnv: z.string().default(\"OPENROUTER_API_KEY\"),\n timeoutMs: z.number().int().min(100).default(30_000),\n maxStateChars: z.number().int().min(500).default(90_000),\n maxChoiceOptions: z.number().int().min(2).max(255).default(255),\n }).default({}),\n /** Jev direct from TypeSafe rather than through OpenRouter. Same\n * contract, different billing and rate limits. Needs TYPESAFE_API_KEY. */\n typesafe: z.object({\n baseUrl: z.string().default(\"https://api.typesafe.ai/v1\"),\n path: z.string().default(\"/systemone\"),\n model: z.string().default(\"jev-latest\"),\n apiKeyEnv: z.string().default(\"TYPESAFE_API_KEY\"),\n timeoutMs: z.number().int().min(100).default(30_000),\n maxStateChars: z.number().int().min(500).default(90_000),\n maxChoiceOptions: z.number().int().min(2).max(255).default(255),\n }).default({}),\n }).default({}),\n seats: z.record(z.string(), decisionSeatSchema).default({}),\n /** Model routing driven by the task-tier seat. Models are scoped to their\n * CLI engine; the legacy cheapModel applies only to Claude Code. */\n routing: z.object({\n cheapModel: z.string().optional(),\n cheapModels: z.object({\n \"claude-code\": z.string().optional(),\n \"codex-cli\": z.string().optional(),\n }).optional(),\n }).default({}),\n}).default({})\n\nconst notificationsSchema = z.object({\n /** Send notification when task takes longer than this (seconds). 0 = disabled. */\n longTaskThreshold: z.number().default(30),\n /** Where to send notifications */\n destination: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n /** Notify on these events */\n on: z.object({\n taskComplete: z.boolean().default(true),\n taskError: z.boolean().default(true),\n taskQueued: z.boolean().default(false),\n }).default({}),\n}).default({})\n\nexport const daemonConfigSchema = z.object({\n node: z.object({\n id: z.string(),\n name: z.string(),\n bind: z.string().default(\"127.0.0.1:18800\"),\n /** Default agent for voice/API calls that don't specify one (e.g. Siri) */\n defaultAgent: z.string().optional(),\n }),\n providers: z.record(z.string(), providerConfigSchema).default({}),\n agents: z.record(z.string(), agentConfigSchema).default({}),\n channels: channelsConfigSchema.default({}),\n crons: z.record(z.string(), cronJobSchema).default({}),\n services: z.record(z.string(), serviceSchema).default({}),\n notifications: notificationsSchema,\n mesh: meshConfigSchema.default({}),\n business: businessConfigSchema.optional(),\n boards: boardsConfigSchema,\n dashboard: dashboardConfigSchema,\n graph: graphConfigSchema,\n decisions: decisionsConfigSchema,\n /** Workflow engine — declarative state machines that bind channel events\n * to agents. Off by default; existing installs see no change until\n * flipped. Definitions live under `dir` (default .agentx/workflows/). */\n workflows: z.object({\n enabled: z.boolean().default(false),\n dir: z.string().default(\".agentx/workflows\"),\n /** n8n keeps its several hundred connectors; we keep the agents. Point\n * this at your n8n and the workflow builder lists YOUR n8n workflows as\n * steps, so nobody has to copy a webhook URL by hand. */\n n8n: z.object({\n baseUrl: z.string().default(\"\"),\n apiKey: z.string().default(\"\"),\n }).default({ baseUrl: \"\", apiKey: \"\" }),\n matching: z.object({\n enabled: z.boolean().default(false),\n mode: z.enum([\"suggest\", \"auto\"]).default(\"suggest\"),\n autoRunThreshold: z.number().min(0).max(1).default(0.85),\n suggestThreshold: z.number().min(0).max(1).default(0.65),\n }).default({}),\n /** Controls whether the dashboard exposes the visual editor. \"readonly\"\n * serves the list + run timelines but strips write controls from the\n * page. \"disabled\" hides the tab entirely. */\n editor: z.enum([\"disabled\", \"readonly\", \"edit\"]).default(\"edit\"),\n }).default({}),\n /** Procedures — user-perspective SOPs mined from recurring activity.\n * The extraction cadence itself lives in `crons.procedure-extract`\n * (written by `agentx procedure watch`); this block holds the miner's\n * thresholds and the injection gates the daemon reads. */\n procedures: z.object({\n enabled: z.boolean().default(true),\n dir: z.string().default(\".agentx/procedures\"),\n extraction: z.object({\n enabled: z.boolean().default(false),\n /** Count patterns live after each completed task (no LLM cost). */\n onTaskCompletion: z.boolean().default(false),\n minOccurrences: z.number().int().min(2).default(3),\n sinceDays: z.number().int().min(1).default(7),\n maxClusters: z.number().int().min(1).default(5),\n /** Agent whose session distills drafts (LLM path). */\n via: z.string().optional(),\n }).default({}),\n /** Inject matching procedures into fresh agent sessions as guidance. */\n injection: z.object({\n enabled: z.boolean().default(true),\n maxProcedures: z.number().int().min(1).default(2),\n minScore: z.number().min(0).max(1).default(0.5),\n }).default({}),\n }).default({}),\n /** Registered inbound webhooks — an inventory the dashboard manages. Each\n * entry binds an (agent, source) pair to an optional signing secret. The\n * actual inbound URL is always POST /webhook/<agentId>/<source>. */\n webhooks: z.array(z.object({\n id: z.string().regex(/^[a-z0-9][a-z0-9_-]*$/, \"webhook id must be lowercase slug\"),\n // Open-string source — runtime + admin-panel + CLI all share a\n // canonical list (kept in sync via WEBHOOK_SOURCES). Loosened from a\n // strict enum so adding a new first-class service (the 5-step recipe)\n // doesn't require a schema bump in three places. Doctor + admin\n // validator still gate writes on the canonical list.\n source: z.string().min(1),\n agentId: z.string(),\n secretEnv: z.string().optional(),\n description: z.string().optional(),\n enabled: z.boolean().default(true),\n /** Route to a mesh peer instead of local execution. */\n node: z.string().optional(),\n /** Per-event-type workflow routing. Keys are platform event-type\n * strings — the format the platform's HTTP header uses, optionally\n * joined with the action. Examples:\n * GitHub: \"issues.opened\", \"pull_request.synchronize\",\n * \"push\" (action-less events use the bare type)\n * GitLab: \"Note Hook\", \"Merge Request Hook\"\n * Values are workflow ids registered via `agentx workflow create`.\n * When the inbound event-type matches a key, the named workflow is\n * dispatched; if no key matches, the webhook falls through to\n * `defaultWorkflow` (or the agent itself). Closes the recurring\n * GitHub problem of multiple event types collapsing to a single\n * workflow. */\n triggers: z.record(z.string(), z.string()).optional(),\n /** Workflow id used when no `triggers` entry matches the event-type.\n * Backward-compatible: pre-existing webhooks without `triggers`\n * always hit this path. */\n defaultWorkflow: z.string().optional(),\n })).default([]),\n /** Session cache-reuse policy. Controls when we drop a Claude `--resume`\n * session and rebuild the prompt from scratch. Every rotation captures a\n * continuity memo that's injected into the chat's next fresh session.\n * - `staleMinutes`: idle timeout before rotation. 12 h default — chat\n * conversations must survive a workday's pauses; overnight silence\n * starts fresh.\n * - `maxTurnsPerSession`: backstop cap on turns per Claude session.\n * Size-based rotation measures real context now, so this rarely fires\n * first.\n * - `tierTwoThresholdTokens`: rotate when the prior turn's END-OF-TURN\n * per-request context (last API call's input + cacheRead + cacheCreate)\n * reaches this. Claude bills the 1.5× long-context rate above 200K\n * per REQUEST — 180K leaves headroom. NOT the cumulative turn total:\n * that sums cache reads across every call and reads 10-20× too high. */\n session: z.object({\n staleMinutes: z.number().int().min(1).max(1440).default(720),\n maxTurnsPerSession: z.number().int().min(2).max(200).default(40),\n tierTwoThresholdTokens: z.number().int().min(50_000).max(200_000).default(180_000),\n /** Context assembly strategy:\n * - \"layered\" (default): the classic stacked layers — session history,\n * memory, cross-chat, wiki hint all appended every turn.\n * - \"planner\": a Haiku pre-call decides what to retrieve before the\n * main agent runs. Always-on core is kept (channel/scope/landscape/\n * identity/intent + last 3 turns verbatim); history blob, wiki hint,\n * and cross-chat are replaced by planner-selected bundles. Per-task\n * overrides via AgentTask.contextStrategy for A/B benchmarking. */\n contextStrategy: z.enum([\"layered\", \"planner\"]).default(\"layered\"),\n /** Soft dispatch budget for claude-code-tier agents (shared OAuth pools\n * one counter across the fleet). Warms at 80% of the cap; short-circuits\n * cold dispatches (no warm Claude session) when exceeded. Warm sessions\n * are always allowed through. Defaults sized for Max 5×:\n * - maxClaudeCodeDispatchesPerHour: 80 (headroom under typical hourly cap)\n * - maxClaudeCodeDispatchesPer5h: 180 (headroom under ~225/5h tier)\n * Raise for Max 20×, lower if your workload stays under the cap naturally. */\n maxClaudeCodeDispatchesPerHour: z.number().int().min(1).max(10_000).default(80),\n maxClaudeCodeDispatchesPer5h: z.number().int().min(1).max(50_000).default(180),\n /** How many requests BEFORE the immediate predecessor to show the\n * session-continuity seat. 0 keeps today's two-message state exactly.\n *\n * Off by default on purpose. A probe over 27 hand-written turns found\n * that at 3, the seat's safety question (`needsHistory`) becomes\n * cleanly separable where two messages leave it straddling zero — but\n * that rests on 7 positive examples from synthetic scenarios, and this\n * seat's failure mode is the agent silently losing conversation\n * context. The promotion gate for that wants labelled production rows,\n * not a good afternoon on a fixture. Raise it to collect them. */\n continuityStateTurns: z.number().int().min(0).max(5).default(0),\n }).default({}),\n /** Move B — JS/TS plugins. Each entry is an installed npm package name\n * (e.g. `agentx-plugin-mattermost` or `@acme/plugin-mattermost`); the\n * loader does a dynamic `import(name)` at boot, validates the manifest,\n * and calls plugin.setup(ctx). Plugins can register channel adapters\n * via ctx.addChannel() and subscribe to bus events via ctx.on(). Empty\n * default — installs that don't list plugins are unaffected. Plugin\n * authoring guide: docs/architecture/plugins.md. */\n plugins: z.array(z.string()).default([]),\n /** Persistent-process pool eviction knobs (handoff #8). The pool keeps\n * one warm Claude subprocess per (agent, channel, chatId) so latency\n * stays low; without bounds, an idle process can serve traffic days\n * later with stale context. These knobs cap that risk. All values are\n * in seconds for operator-friendliness; the registry uses ms internally.\n *\n * - `maxIdleSeconds`: a handle becomes eligible for cap-pressured\n * eviction this many seconds after its last turn. Default 30s\n * (matches the registry's pre-config behavior).\n * - `maxAgeSeconds`: a handle is killed unconditionally on the next\n * sweep once its total wall-clock idleness exceeds this. Default\n * 2700s (45min) — matches the registry's pre-config staleTimeoutMs.\n * - `sweepIntervalSeconds`: how often the sweeper checks. Default 5s.\n *\n * See `agents.<id>.persistentProcess` to opt an agent into the pool. */\n processPool: z.object({\n maxIdleSeconds: z.number().int().min(5).max(86_400).default(30),\n maxAgeSeconds: z.number().int().min(60).max(86_400).default(2700),\n sweepIntervalSeconds: z.number().int().min(1).max(300).default(5),\n }).default({}),\n})\n\nexport type DaemonConfig = z.infer<typeof daemonConfigSchema>\nexport type AgentDef = z.infer<typeof agentConfigSchema>\nexport type CronJobDef = z.infer<typeof cronJobSchema>\nexport type MeshPeer = z.infer<typeof meshPeerSchema>\n\n/**\n * Expand environment variables in strings: ${VAR_NAME} -> process.env.VAR_NAME\n */\nexport function expandEnvVars(obj: unknown): unknown {\n if (typeof obj === \"string\") {\n return obj.replace(/\\$\\{(\\w+)\\}/g, (_match, name) => process.env[name] || \"\")\n }\n if (Array.isArray(obj)) {\n return obj.map(expandEnvVars)\n }\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = expandEnvVars(value)\n }\n return result\n }\n return obj\n}\n\n/**\n * Translate raw Zod issues into actionable, copy-pasteable fixes for the\n * patterns we see in real first-run failures (missing tokens, missing\n * required env vars, etc.). Falls through silently for unknown patterns —\n * the raw `issues` block is always shown above this hint block.\n */\nfunction friendlyConfigHints(issues: ReadonlyArray<z.ZodIssue>, configPath: string): string[] {\n const hints: string[] = []\n const seen = new Set<string>()\n for (const issue of issues) {\n const path = issue.path.join(\".\")\n // Telegram account block exists but token is empty/missing — by far the\n // most common first-run trip. Tell the operator exactly which two\n // recoveries are valid, with the literal config path to edit.\n const tgTokenMatch = /^channels\\.telegram\\.accounts\\.([^.]+)\\.token$/.exec(path)\n if (tgTokenMatch && issue.message.toLowerCase().includes(\"required\")) {\n const account = tgTokenMatch[1]\n const key = `tg:${account}`\n if (seen.has(key)) continue\n seen.add(key)\n hints.push(\n `Hint: Telegram account \"${account}\" is enabled but has no bot token.\\n` +\n ` Either:\\n` +\n ` A) Open ${configPath} and set channels.telegram.accounts.${account}.token to your bot token (or \"\\${TG_${account.toUpperCase()}_BOT_TOKEN}\" + the matching .env entry).\\n` +\n ` B) If you don't need Telegram on this instance, remove the entire \"telegram\" block under \"channels\" (or set channels.telegram.enabled to false AND drop accounts.${account}).`\n )\n }\n }\n return hints\n}\n\n/**\n * Load daemon config from agentx.json, with env var expansion and validation.\n */\nexport function loadDaemonConfig(configPath?: string): DaemonConfig {\n const paths = configPath\n ? [configPath]\n : [\n resolve(process.cwd(), \"agentx.json\"),\n resolve(process.cwd(), \".agentx/config.json\"),\n ]\n\n // Load .env from same directory as config search\n loadDotEnv(process.cwd())\n\n let raw: string | undefined\n let foundPath: string | undefined\n\n for (const p of paths) {\n if (existsSync(p)) {\n raw = readFileSync(p, \"utf-8\")\n foundPath = p\n break\n }\n }\n\n if (!raw || !foundPath) {\n throw new Error(\n `No config found. Create agentx.json or .agentx/config.json\\n` +\n `Searched: ${paths.join(\", \")}`\n )\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (e: any) {\n throw new Error(`Invalid JSON in ${foundPath}: ${e.message}`)\n }\n\n // Expand environment variables\n const expanded = expandEnvVars(parsed)\n\n // Validate\n const result = daemonConfigSchema.safeParse(expanded)\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\")\n const hints = friendlyConfigHints(result.error.issues, foundPath)\n const hintBlock = hints.length ? `\\n\\n${hints.join(\"\\n\\n\")}` : \"\"\n throw new Error(`Config validation failed (${foundPath}):\\n${issues}${hintBlock}`)\n }\n\n return result.data\n}\n\n/**\n * Validate agent workspace directories exist and have .claude/ setup.\n */\nexport function validateWorkspaces(config: DaemonConfig): string[] {\n const warnings: string[] = []\n\n for (const [id, agent] of Object.entries(config.agents)) {\n if (!existsSync(agent.workspace)) {\n warnings.push(`Agent \"${id}\": workspace not found at ${agent.workspace}`)\n continue\n }\n\n if (agent.tier === \"claude-code\") {\n const claudeDir = resolve(agent.workspace, \".claude\")\n if (!existsSync(claudeDir)) {\n warnings.push(\n `Agent \"${id}\": no .claude/ directory in workspace ${agent.workspace}. ` +\n `Claude Code native features (hooks, MCP, skills) won't be available.`\n )\n }\n }\n\n // Check provider availability\n const providerName = agent.provider || \"claude\"\n const providerConfig = config.providers[providerName]\n if (![\"claude-code\", \"codex-cli\", \"opencode\"].includes(agent.tier) && (!providerConfig || !providerConfig.apiKey)) {\n warnings.push(\n `Agent \"${id}\": provider \"${providerName}\" has no API key configured. ` +\n `Set providers.${providerName}.apiKey in config or use a CLI-backed tier (\"claude-code\", \"codex-cli\", or \"opencode\").`\n )\n }\n }\n\n // Validate cron agent bindings\n for (const [id, cron] of Object.entries(config.crons)) {\n if (!config.agents[cron.agent]) {\n warnings.push(`Cron \"${id}\": references unknown agent \"${cron.agent}\"`)\n }\n }\n\n // Validate channel agent bindings\n if (config.channels.telegram.enabled) {\n for (const [name, account] of Object.entries(config.channels.telegram.accounts)) {\n if (!config.agents[account.agentBinding]) {\n warnings.push(\n `Telegram account \"${name}\": references unknown agent \"${account.agentBinding}\"`\n )\n }\n }\n }\n\n return warnings\n}\n"],"mappings":"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","names":["z","dayEnum","scheduleSchema","roleSchema","orgEntrySchema","channelRefSchema","workSourceSchema","projectSchema","contactMapSchema","clientPolicySchema","businessConfigSchema","init_config","__esmMin","z","deriveStage","item","columns","set","closed","c","backlog","prefix","l","transitionDiff","fromColumn","toColumn","add","remove","closeIssue","reopen","boardLabelSchema","boardColumnSchema","boardReconcileSchema","boardSourceSchema","DEFAULT_COLUMNS","boardSchema","boardsConfigSchema","dashboardDaemonSchema","dashboardConfigSchema","init_config","__esmMin","config_exports","__export","INTEGRATION_KINDS","daemonConfigSchema","expandEnvVars","loadDaemonConfig","validateWorkspaces","z","readFileSync","existsSync","resolve","loadDotEnv","dir","envPath","content","line","trimmed","eqIdx","key","value","obj","_match","name","result","friendlyConfigHints","issues","configPath","hints","seen","issue","path","tgTokenMatch","account","paths","raw","foundPath","p","parsed","e","expanded","i","hintBlock","config","warnings","id","agent","claudeDir","providerName","providerConfig","cron","providerConfigSchema","mcpStdioServerSchema","mcpHttpServerSchema","mcpServerSchema","integrationCredentialsSchema","integrationSchema","agentConfigSchema","telegramAccountSchema","channelsConfigSchema","cronJobSchema","serviceSchema","meshPeerSchema","meshInboxSchema","meshConfigSchema","graphConfigSchema","decisionSeatSchema","decisionsConfigSchema","notificationsSchema","init_config","__esmMin","v","j","businessConfigSchema","boardsConfigSchema","dashboardConfigSchema"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as R,b as j,c as O,d as W,e as D}from"./chunk-AJ5RMU7X.js";import{b as C}from"./chunk-EVWEG3VD.js";import{v,w as Q}from"./chunk-
|
|
1
|
+
import{a as R,b as j,c as O,d as W,e as D}from"./chunk-AJ5RMU7X.js";import{b as C}from"./chunk-EVWEG3VD.js";import{v,w as Q}from"./chunk-F5AEXRPR.js";import{b as $,c as M}from"./chunk-QOYAX2FT.js";import{readFileSync as T,existsSync as _}from"fs";Q();import{resolve as b}from"path";import{execSync as Y}from"child_process";async function V(n,i,s,e={}){let d=e.selectorModel??"haiku",a=e.synthModel??"sonnet",c=e.maxCandidates??3,l=e.maxHops??2,r=e.maxArticles??8,p=e.timeoutMs??6e4,u=e.log??console.error.bind(console,"[wiki-query]"),h=b(i.baseDir,"_index.md");if(!_(h))return w("no-catalog",n,"No _index.md found \u2014 run `agentx wiki status` to rebuild.");let k=T(h,"utf-8"),t=Date.now(),g=[],m="";try{let o=await B(n,i,s,c);o?(g=o,m=`[wiki-rerank seat] ${o.map(y=>y.title).join(" | ")}`):(m=await N(I(n,k,c),d,p),g=F(m))}catch(o){return u("selector failed:",o?.message),{...w("error",n,`Selector: ${o?.message||"unknown"}`),trace:{selectorMs:Date.now()-t,synthesisMs:0,selectorOutput:m}}}let A=Date.now()-t;if(g.length===0)return{...w("no-candidates",n,"Selector returned no candidates."),trace:{selectorMs:A,synthesisMs:0,selectorOutput:m}};let f=E(g,i,s,l,r);if(f.length===0)return{...w("no-candidates",n,"Candidates did not resolve to readable articles."),candidates:g,trace:{selectorMs:A,synthesisMs:0,selectorOutput:m}};let S=Date.now(),x="";try{x=await N(L(n,f),a,p*2)}catch(o){return u("synthesis failed:",o?.message),{...w("error",n,`Synthesis: ${o?.message||"unknown"}`),candidates:g,walked:f.map(y=>({title:y.meta.title,path:y.path,type:y.meta.type,hop:y.hop??0})),trace:{selectorMs:A,synthesisMs:Date.now()-S,selectorOutput:m}}}let P=Date.now()-S;return{answer:x.trim(),citations:f.map(o=>({title:o.meta.title,path:o.path,type:o.meta.type})),candidates:g,walked:f.map(o=>({title:o.meta.title,path:o.path,type:o.meta.type,hop:o.hop??0})),status:"ok",trace:{selectorMs:A,synthesisMs:P,selectorOutput:m}}}function w(n,i,s){return{answer:"",citations:[],candidates:[],walked:[],status:n,error:s}}function E(n,i,s,e,d){let a=new Map;for(let r of i.listArticles(s||""))a.set(r.meta.title.toLowerCase(),r.path);let c=new Map,l=[];for(let r of n)c.has(r.path)||l.push({path:r.path,hop:0});for(;l.length&&c.size<d;){let r=l.shift();if(c.has(r.path)||r.hop>e)continue;let p=s?i.readArticleAs(r.path,s):i.readArticle(r.path);if(p&&(c.set(r.path,{...p,hop:r.hop}),!(r.hop>=e)))for(let u of p.meta.related||[]){let h=a.get(u.toLowerCase());h&&!c.has(h)&&l.push({path:h,hop:r.hop+1})}}return Array.from(c.values())}async function B(n,i,s,e){try{let a=(i.rebuildIndex().articles??[]).filter(t=>t.path&&!t.path.includes("/_versions/"));if(a.length<2)return null;let c=a.map(t=>[t.title,(t.tags??[]).join(" "),(t.related??[]).join(" ")].join(" ")),l=M(n,$(c)).map(t=>t.docIndex);for(let t=0;t<a.length;t++)l.includes(t)||l.push(t);let p=l.slice(0,j).map(t=>({id:`k${t}`,title:a[t].title||a[t].path,tags:a[t].tags,excerpt:[a[t].type?`type: ${a[t].type}`:"",(a[t].related??[]).length?`related: ${(a[t].related??[]).join(", ")}`:""].filter(Boolean).join(" \xB7 ")})),u=await v(R,O({query:n,candidates:p,excerptChars:300}),W(p),{features:{agent:s??"unknown",stage:"catalog-selector"}});if(!u||u.mode!=="active")return null;let k=D(u.answers,p).ranked.slice(0,e).map(t=>a[Number(t.slice(1))]).filter(Boolean).map(t=>({title:t.title,path:t.path}));return k.length>0?k:null}catch{return null}}function I(n,i,s){return`You are picking candidate articles from a wiki catalog to answer a question. You do NOT answer the question. You pick which articles the answer is likely to come from.
|
|
2
2
|
|
|
3
3
|
## Question
|
|
4
4
|
|
|
@@ -42,4 +42,4 @@ ${s}
|
|
|
42
42
|
Answer the question in 2\u20136 sentences. Cite articles by their title in square brackets like [Article Title]. If the articles do not answer the question, say so plainly (do not invent). Prefer concrete facts over hedging.
|
|
43
43
|
|
|
44
44
|
Output ONLY the answer \u2014 no preamble, no "here is my answer:", no markdown fencing.`}function F(n){let i=n.match(/\[[\s\S]*?\]/);if(!i)return[];try{let s=JSON.parse(i[0]);return Array.isArray(s)?s.filter(e=>e&&typeof e.title=="string"&&typeof e.path=="string").map(e=>({title:e.title,path:e.path})):[]}catch{return[]}}async function N(n,i,s){let{writeFileSync:e,mkdirSync:d,rmSync:a}=await import("fs"),{tmpdir:c}=await import("os"),l=b(c(),`agentx-wiki-query-${process.pid}`);d(l,{recursive:!0});let r=b(l,`prompt-${Date.now()}.txt`);e(r,n);try{let p=`cat '${r}' | claude -p - --output-format json --max-turns 1 --model ${i} --disallowedTools "Bash Read Write Edit Glob Grep Agent WebSearch WebFetch NotebookEdit"`,u=Y(p,{env:C({...process.env}),encoding:"utf-8",timeout:s,maxBuffer:4*1024*1024});try{let h=JSON.parse(u);return String(h.result||h.content||"")}catch{return u}}finally{try{a(r,{force:!0})}catch{}}}export{V as a};
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
45
|
+
//# sourceMappingURL=chunk-JIOLJIBM.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{g as C,j as S}from"./chunk-
|
|
2
|
-
`):H(i),process.exit(e.errors>0?1:0)});async function P(n){let i=Number(process.versions.node.split(".")[0]);n.push({severity:i
|
|
1
|
+
import{g as C,j as S}from"./chunk-GMNKJXTR.js";S();import{Command as R}from"commander";import f from"chalk";import{execFileSync as h}from"child_process";import{existsSync as y,readFileSync as k,readdirSync as j,statSync as N}from"fs";import{resolve as m}from"path";import{createRequire as W}from"module";async function E(n={}){let i=[];await P(i);let e=T(i);return e&&L(i,e),e&&_(i,e),e&&D(i,e),e&&q(i,e),e&&B(i,e),n.running!==!1&&e&&await z(i,e),{checks:i,summary:A(i)}}var K=new R().name("doctor").description("pre-flight health check: Node, config, credentials, daemon").option("--no-running","skip the live daemon probe").option("--json","emit machine-readable JSON (stable shape for CI)").action(async n=>{let{checks:i,summary:e}=await E({running:n.running!==!1});n.json?process.stdout.write(JSON.stringify({checks:i,summary:e},null,2)+`
|
|
2
|
+
`):H(i),process.exit(e.errors>0?1:0)});async function P(n){let i=Number(process.versions.node.split(".")[0]);n.push({severity:i==22?"ok":"fail",group:"Environment",title:`Node.js ${process.versions.node}`,detail:i==22?void 0:"AgentX requires Node 22.x.",fix:i==22?void 0:"Install Node 22 (nvm install 22 && nvm use 22)"});let e=a=>{try{return h(process.platform==="win32"?"where":"which",[a],{encoding:"utf-8"}).trim().split(`
|
|
3
3
|
`)[0]}catch{return null}},o=e("npm");n.push({severity:o?"ok":"fail",group:"Environment",title:o?"npm on PATH":"npm not found",detail:o||void 0});let s=e("claude");if(s){let a;try{a=h("claude",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}n.push({severity:"ok",group:"Environment",title:`claude CLI ${a||"installed"}`,detail:s})}else n.push({severity:"warn",group:"Environment",title:"claude CLI not on PATH",detail:"Only required for agents on the claude-code tier.",fix:"See https://docs.anthropic.com/en/docs/claude-code"});let r=e("codex");if(r){let a;try{a=h("codex",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}n.push({severity:"ok",group:"Environment",title:`codex CLI ${a||"installed"}`,detail:r})}else n.push({severity:"warn",group:"Environment",title:"codex CLI not on PATH",detail:"Only required for agents on the codex-cli tier.",fix:"Install with `npm i -g @openai/codex`."});let l=e("opencode");if(l){let a;try{a=h("opencode",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}n.push({severity:"ok",group:"Environment",title:`opencode CLI ${a||"installed"}`,detail:l})}else n.push({severity:"warn",group:"Environment",title:"opencode CLI not on PATH",detail:"Only required for agents on the opencode tier.",fix:"Install from https://opencode.ai/docs/."});try{W(import.meta.url)("better-sqlite3"),n.push({severity:"ok",group:"Environment",title:`better-sqlite3 loads for Node ${process.version}`,detail:`NODE_MODULE_VERSION ${process.versions.modules}`})}catch(a){n.push({severity:"fail",group:"Environment",title:"better-sqlite3 native binding does not load",detail:a?.message??String(a),fix:`Run "pnpm rebuild better-sqlite3" with the same Node used by the daemon (${process.version}, modules ${process.versions.modules}).`})}}function T(n){let i=m(process.cwd(),"agentx.json");if(!y(i))return n.push({severity:"fail",group:"Config",title:"agentx.json not found",detail:`Looked in ${i}`,fix:"Run `agentx setup` to create one via the web wizard."}),null;let e;try{e=JSON.parse(k(i,"utf-8"))}catch(l){return n.push({severity:"fail",group:"Config",title:"agentx.json is not valid JSON",detail:l.message}),null}try{C(i),n.push({severity:"ok",group:"Config",title:`agentx.json valid (${Object.keys(e.agents||{}).length} agents, ${Object.keys(e.crons||{}).length} schedules)`})}catch(l){n.push({severity:"fail",group:"Config",title:"agentx.json failed schema validation",detail:l.message,fix:"Open /admin \u2192 Advanced tab to edit and re-save."})}let o=Object.entries(e.agents||{}).filter(([,l])=>l.tier==="claude-code");o.length>0&&((()=>{try{return h(process.platform==="win32"?"where":"which",["claude"],{stdio:"ignore"}),!0}catch{return!1}})()||n.push({severity:"fail",group:"Config",title:`${o.length} agent(s) use claude-code tier but claude CLI is missing`,detail:o.map(([a])=>a).join(", "),fix:"Install Claude Code (https://docs.anthropic.com/en/docs/claude-code) or switch these agents to tier=sdk."}));let s=Object.entries(e.agents||{}).filter(([,l])=>l.tier==="codex-cli");s.length>0&&((()=>{try{return h(process.platform==="win32"?"where":"which",["codex"],{stdio:"ignore"}),!0}catch{return!1}})()||n.push({severity:"fail",group:"Config",title:`${s.length} agent(s) use codex-cli tier but codex CLI is missing`,detail:s.map(([a])=>a).join(", "),fix:"Install Codex CLI with `npm i -g @openai/codex` or switch these agents to tier=claude-code."}));let r=Object.entries(e.agents||{}).filter(([,l])=>l.tier==="opencode");return r.length>0&&((()=>{try{return h(process.platform==="win32"?"where":"which",["opencode"],{stdio:"ignore"}),!0}catch{return!1}})()||n.push({severity:"fail",group:"Config",title:`${r.length} agent(s) use opencode tier but OpenCode CLI is missing`,detail:r.map(([a])=>a).join(", "),fix:"Install OpenCode from https://opencode.ai/docs/ or switch these agents to another tier."})),e}function L(n,i){let e=new Set;if($(i,e),e.size===0){n.push({severity:"ok",group:"Secrets",title:"No ${VAR} references in agentx.json"});return}let o=m(process.cwd(),".env"),s={};if(y(o))for(let a of k(o,"utf-8").split(/\r?\n/)){let g=a.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/i);g&&(s[g[1]]=g[2])}let r=[],l=[];for(let a of e){let g=process.env[a]??s[a];g===void 0?r.push(a):(!g.trim()||/^["']?\s*["']?$/.test(g))&&l.push(a)}r.length===0&&l.length===0?n.push({severity:"ok",group:"Secrets",title:`${e.size} env reference(s) resolved`}):(r.length>0&&n.push({severity:"fail",group:"Secrets",title:`${r.length} env var(s) referenced in agentx.json but missing`,detail:r.join(", "),fix:`Add to .env \u2014 e.g. ${r[0]}=<value>`}),l.length>0&&n.push({severity:"warn",group:"Secrets",title:`${l.length} env var(s) set but empty`,detail:l.join(", ")}))}function $(n,i){if(typeof n=="string")for(let e of n.matchAll(/\$\{([A-Z_][A-Z0-9_]*)\}/g))i.add(e[1]);else if(Array.isArray(n))for(let e of n)$(e,i);else if(n&&typeof n=="object")for(let e of Object.values(n))$(e,i)}function _(n,i){let e=[];for(let[o,s]of Object.entries(i.agents||{})){if(!s.workspace)continue;let r=s.workspace.startsWith("/")?s.workspace:m(process.cwd(),s.workspace);try{N(r).isDirectory()||e.push(`${o}: ${r} (exists but not a directory)`)}catch{e.push(`${o}: ${r}`)}}e.length===0?n.push({severity:"ok",group:"Workspaces",title:"All agent workspace folders exist"}):n.push({severity:"warn",group:"Workspaces",title:`${e.length} agent workspace(s) missing`,detail:e.join(`
|
|
4
4
|
`),fix:"The daemon will create missing folders on first task, but you won't see CLAUDE.md / skills until you populate them."})}function D(n,i){let e=/\$\{[A-Za-z_][A-Za-z0-9_]*\}/g,o=[];for(let[s,r]of Object.entries(i.agents||{})){if(!r.workspace)continue;let l=r.workspace.startsWith("/")?r.workspace:m(process.cwd(),r.workspace);for(let a of["settings.json","settings.local.json"]){let g=m(l,".claude",a);if(!y(g))continue;let w;try{w=JSON.parse(k(g,"utf-8"))}catch(d){o.push({severity:"fail",agent:s,msg:`${a}: JSON parse error \u2014 ${d.message}`});continue}let b=w.env||{};for(let[d,p]of Object.entries(b)){if(typeof p!="string")continue;let u=p.match(e);u&&o.push({severity:"fail",agent:s,msg:`${a} env.${d} contains unexpanded ${[...new Set(u)].join(",")} \u2014 Claude Code does NOT expand \${VAR} in settings.json (use a fully-literal value)`})}let t=b.PATH;if(typeof t=="string"){let d=t.split(":").filter(Boolean);d.includes("/usr/bin")||o.push({severity:"fail",agent:s,msg:`${a} env.PATH missing /usr/bin \u2014 cat/head/sh/which will fail`}),d.includes("/bin")||o.push({severity:"fail",agent:s,msg:`${a} env.PATH missing /bin \u2014 ls/cp/mv will fail`})}let c=w.permissions;if(c&&typeof c=="object"&&"allow"in c){let d=c.allow,p=c.deny;Array.isArray(d)&&d.length===0&&Array.isArray(p)&&p.length>0&&o.push({severity:"warn",agent:s,msg:`${a} permissions.allow is explicitly [] with ${p.length} deny rules \u2014 agent may be locked out (omit the key to use defaults instead)`})}}}if(o.length===0){n.push({severity:"ok",group:"Workspace settings",title:`All ${Object.keys(i.agents||{}).length} agent .claude/settings.json files clean`});return}for(let s of o)n.push({severity:s.severity,group:"Workspace settings",title:`${s.agent}: ${s.msg}`,fix:s.severity==="fail"?"Edit .claude/settings.json \u2014 replace ${VAR} with the literal value or omit the key to inherit.":"Either remove the empty allow list or populate it."})}function q(n,i){let e=i.webhooks??[],o=[],s=m(process.cwd(),i.workflows?.dir||".agentx/workflows"),r=new Set;try{if(y(s))for(let t of j(s))t.endsWith(".json")&&!t.startsWith("_")&&!t.endsWith(".disabled.json")&&r.add(t.replace(/\.json$/,""))}catch{}let l=new Set(["github","gitlab"]);for(let t of e){if(!t.enabled||!l.has(t.source))continue;!(t.triggers&&Object.keys(t.triggers).length>0)&&!t.defaultWorkflow&&o.push({severity:"warn",title:`webhook "${t.id}" (${t.source} -> ${t.agentId}) has no triggers map; every event-type collapses to the bound agent`,fix:'Add a triggers map: { "issues.opened": "wf-id", "pull_request.synchronize": "wf-id" } \u2014 or set defaultWorkflow.'})}for(let t of e)if(!(!t.enabled||!t.triggers)){for(let[c,d]of Object.entries(t.triggers))r.size>0&&!r.has(d)&&o.push({severity:"fail",title:`webhook "${t.id}".triggers["${c}"] -> "${d}" \u2014 no such workflow under ${i.workflows?.dir||".agentx/workflows"}`,fix:"Create the workflow file or fix the id in agentx.json"});t.defaultWorkflow&&r.size>0&&!r.has(t.defaultWorkflow)&&o.push({severity:"fail",title:`webhook "${t.id}".defaultWorkflow -> "${t.defaultWorkflow}" \u2014 no such workflow`,fix:"Create the workflow file or fix the id in agentx.json"})}try{if(y(s)){for(let t of j(s))if(!(!t.endsWith(".json")||t.startsWith("_")||t.endsWith(".disabled.json")))try{let c=JSON.parse(k(m(s,t),"utf-8"));c?.status==="active"&&c?.state==="quarantined"&&o.push({severity:"warn",title:`workflow "${c.id??t}" is status=active but state=quarantined \u2014 it looks live but will never dispatch`,fix:'Resolve the conflict the detector flagged, then set state back to "active" (or set status to "review" while parked).'})}catch{}}}catch{}let a=new Set((i.mesh?.peers??[]).map(t=>t.name));for(let t of e)!t.enabled||!t.node||a.has(t.node)||o.push({severity:"fail",title:`webhook "${t.id}" routes to mesh peer "${t.node}" which is not in mesh.peers`,fix:"Add the peer to mesh.peers or remove the node field on the webhook."});let g=new Map;for(let t of e){if(!t.enabled)continue;let c=`${t.source}:${t.agentId}`,d=g.get(c);d?o.push({severity:"warn",title:`webhook entries "${d}" and "${t.id}" both enabled for ${t.source} -> ${t.agentId}; only the first is dispatched`,fix:"Disable one entry, or merge their triggers maps into a single entry."}):g.set(c,t.id)}let w=new Set(Object.keys(i.agents??{}));for(let t of i.channels?.gitlab?.agentMappings??[])if(t?.agentId){if(t.node){a.has(t.node)||o.push({severity:"fail",title:`gitlab.agentMappings entry agentId="${t.agentId}" routes to mesh peer "${t.node}" which is not in mesh.peers`,fix:"Add the peer to mesh.peers or drop the node field on the mapping."});continue}w.has(t.agentId)||o.push({severity:"warn",title:`gitlab.agentMappings entry agentId="${t.agentId}" \u2014 no such agent in agents.* (and no node field, so it's not a cross-mesh route)`,fix:'Add the agent to agents.*, set node:"<peer>" if the agent lives remotely, or remove the mapping.'})}for(let[t,c]of Object.entries(i.channels?.telegram?.accounts??{}))c.agentBinding?w.has(c.agentBinding)||o.push({severity:"fail",title:`telegram account "${t}".agentBinding -> "${c.agentBinding}" \u2014 no such agent in agents.*`,fix:"Fix the agentBinding or define the agent in agents.*."}):o.push({severity:"fail",title:`telegram account "${t}" has no agentBinding; every DM to this bot will drop`,fix:"Set agentBinding to a valid agent id."});let b=new Set(["telegram-bot","whatsapp","slack-bot","discord-bot","gitlab-user","github-user","gmail","hotmail","smtp","hubspot","salesforce","pipedrive","odoo","trello","linear","asana","jira","notion","stripe","sentry","vercel","twilio","custom"]);for(let[t,c]of Object.entries(i.agents??{})){let d=c.integrations??[];if(!d.length)continue;let p=new Set;for(let u of d){let x=`${u.kind}::${u.label}`;p.has(x)&&o.push({severity:"warn",title:`agents.${t}.integrations: duplicate (${u.kind}, ${u.label})`,fix:"Remove the duplicate or rename one. (kind, label) must be unique per agent."}),p.add(x),b.has(u.kind)||o.push({severity:"warn",title:`agents.${t}.integrations: unknown kind "${u.kind}" on integration "${u.label}"`,fix:'Use a canonical kind from INTEGRATION_KINDS, or "custom" for ad-hoc services.'});let I=u.credentials||{};for(let[O,v]of Object.entries(I))typeof v=="string"&&/^[A-Z][A-Z0-9_]*$/.test(v)&&!process.env[v]&&o.push({severity:"warn",title:`agents.${t}.integrations[${u.kind}/${u.label}].${O} -> $${v} but env var is unset (in this shell)`,fix:`Set ${v} on the daemon environment. The daemon's process.env is what matters; this warning fires from your local shell.`})}}if(o.length===0){n.push({severity:"ok",group:"Routing",title:`${e.length} webhook(s), ${Object.keys(i.channels?.telegram?.accounts??{}).length} telegram account(s) \u2014 all routing references resolve`});return}for(let t of o)n.push({severity:t.severity,group:"Routing",title:t.title,fix:t.fix})}async function z(n,i){let e=i.dashboard?.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800",o={};i.dashboard?.token&&(o.Authorization=`Bearer ${i.dashboard.token}`);try{let s=new AbortController,r=setTimeout(()=>s.abort(),2e3),l=await fetch(e+"/health",{headers:o,signal:s.signal});if(clearTimeout(r),!l.ok){n.push({severity:"warn",group:"Runtime",title:`Daemon responded ${l.status}`,detail:e});return}let a=await l.json();n.push({severity:"ok",group:"Runtime",title:`Daemon healthy \u2014 ${a.agents?.length??0} agents live, uptime ${Math.round((a.uptime??0)/60)}m`,detail:e})}catch{n.push({severity:"warn",group:"Runtime",title:"Daemon not reachable (not running?)",detail:e,fix:"Run `agentx daemon start`. Skip this check with `agentx doctor --no-running`."})}}function B(n,i){let e=Object.entries(i.agents||{}).filter(([,s])=>s?.codegraph===!0&&(s.tier==="claude-code"||s.tier==="codex-cli"));if(e.length===0)return;let o=null;try{o=h(process.platform==="win32"?"where":"which",["codegraph"],{encoding:"utf-8"}).trim().split(`
|
|
5
5
|
`)[0]||null}catch{o=null}if(o){let s;try{s=h("codegraph",["--version"],{encoding:"utf-8",timeout:3e3}).trim()}catch{}n.push({severity:"ok",group:"CodeGraph",title:`codegraph CLI ${s||"installed"}`,detail:o})}else n.push({severity:"fail",group:"CodeGraph",title:"codegraph CLI not on PATH",detail:`${e.length} agent(s) have codegraph:true but the binary isn't available.`,fix:"Install with `npm i -g @colbymchenry/codegraph`."});for(let[s,r]of e){if(!r.workspace||!y(r.workspace)){n.push({severity:"warn",group:"CodeGraph",title:`${s}: workspace missing`,detail:`Workspace path ${r.workspace} does not exist \u2014 codegraph will skip this agent.`});continue}let l=m(r.workspace,".codegraph","codegraph.db");y(l)?n.push({severity:"ok",group:"CodeGraph",title:`${s}: index present`,detail:l}):n.push({severity:"warn",group:"CodeGraph",title:`${s}: index not built yet`,detail:".codegraph/ missing \u2014 daemon will background-index this workspace on next boot.",fix:`Run \`codegraph init --index ${r.workspace}\` to build it now.`})}}function A(n){return{errors:n.filter(i=>i.severity==="fail").length,warnings:n.filter(i=>i.severity==="warn").length,ok:n.filter(i=>i.severity==="ok").length}}function H(n){console.log(),console.log(f.bold(" agentx doctor")),console.log();let i=new Map;for(let o of n)i.has(o.group)||i.set(o.group,[]),i.get(o.group).push(o);for(let[o,s]of i){console.log(f.bold(" "+o));for(let r of s){let l=r.severity==="ok"?f.green("\u2713"):r.severity==="warn"?f.yellow("!"):f.red("\u2717");console.log(` ${l} ${r.title}`),r.detail&&console.log(f.dim(" "+r.detail.replace(/\n/g,`
|
|
6
6
|
`))),r.fix&&console.log(f.dim(" \u2192 "+r.fix))}console.log()}let e=A(n);e.errors>0?console.log(f.red.bold(` ${e.errors} error${e.errors===1?"":"s"}`)+(e.warnings?f.yellow(`, ${e.warnings} warning${e.warnings===1?"":"s"}`):"")+`. Fix the error${e.errors===1?"":"s"} and rerun.`):e.warnings>0?console.log(f.yellow.bold(` ${e.warnings} warning${e.warnings===1?"":"s"}.`)+f.dim(" Review but not blocking.")):console.log(f.green.bold(` All checks passed (${e.ok}).`)),console.log()}export{E as a,K as b};
|
|
7
|
-
//# sourceMappingURL=chunk-
|
|
7
|
+
//# sourceMappingURL=chunk-JKYMXLYL.js.map
|