agentix-cli 0.14.0 → 0.15.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 +64 -34
- package/dist/agent-LRSSVFDR.js +2 -0
- package/dist/board-dashboard-DAPHL6W2.js +4508 -0
- package/dist/board-dashboard-DAPHL6W2.js.map +1 -0
- package/dist/chunk-3XULOWYB.js +199 -0
- package/dist/chunk-3XULOWYB.js.map +1 -0
- package/dist/{chunk-ZRYBSI5G.js → chunk-7MBTMCKY.js} +2 -2
- package/dist/{chunk-XVYMZ4M7.js → chunk-AU37OREL.js} +5 -5
- package/dist/chunk-B4Q4X7D5.js +6 -0
- package/dist/chunk-B4Q4X7D5.js.map +1 -0
- package/dist/chunk-CXY2RYNI.js +11 -0
- package/dist/chunk-CXY2RYNI.js.map +1 -0
- package/dist/chunk-FIOB3MEX.js +2 -0
- package/dist/chunk-HLRVDCNH.js +5 -0
- package/dist/{chunk-NJR5WF5E.js.map → chunk-HLRVDCNH.js.map} +1 -1
- package/dist/chunk-IEVEMKAI.js +168 -0
- package/dist/chunk-IEVEMKAI.js.map +1 -0
- package/dist/{chunk-O72LPMBR.js → chunk-RB7265LO.js} +2 -2
- package/dist/chunk-RGUYBH77.js +7 -0
- package/dist/chunk-RGUYBH77.js.map +1 -0
- package/dist/chunk-WVNSWBCU.js +138 -0
- package/dist/chunk-WVNSWBCU.js.map +1 -0
- package/dist/cli.js +34 -24
- package/dist/cli.js.map +1 -1
- package/dist/{compaction-7I3E5QUO.js → compaction-JBZZ7I7Y.js} +4 -4
- package/dist/config-DCJYECL4.js +2 -0
- package/dist/config-mutator-6EJHSP3Y.js +2 -0
- package/dist/debug-3MEUO2P2.js +2 -0
- package/dist/{heal-OTGT5HHJ.js → heal-WKY5I4KB.js} +2 -2
- package/dist/index.d.ts +224 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/loader-PTCXLJEX.js +2 -0
- package/dist/memory-extract-AD7KMRPC.js +2 -0
- package/dist/{providers-G3WZ4RVJ.js → providers-VUIWO3ZK.js} +2 -2
- package/dist/registry-5ND7GLFJ.js +2 -0
- package/dist/scheduler-FCXOXCN5.js +2 -0
- package/dist/{subagent-WV7QKQ3L.js → subagent-2SJHSSJS.js} +2 -2
- package/dist/{usage-dashboard-M7AFIGMJ.js → usage-dashboard-QX3CF6KK.js} +8 -8
- package/dist/usage-dashboard-QX3CF6KK.js.map +1 -0
- package/dist/whatsapp-state-6D6FHHD2.js +2 -0
- package/dist/whatsapp-state-6D6FHHD2.js.map +1 -0
- package/dist/workspace-setup-ZWTT42XT.js +2 -0
- package/dist/workspace-setup-ZWTT42XT.js.map +1 -0
- package/package.json +2 -1
- package/dist/agent-DW3NYIIL.js +0 -2
- package/dist/board-dashboard-6TKE6NMV.js +0 -1435
- package/dist/board-dashboard-6TKE6NMV.js.map +0 -1
- package/dist/chunk-4YCH6IZV.js +0 -2
- package/dist/chunk-DYOBFJLX.js +0 -11
- package/dist/chunk-DYOBFJLX.js.map +0 -1
- package/dist/chunk-ITZEVXZ4.js +0 -2
- package/dist/chunk-ITZEVXZ4.js.map +0 -1
- package/dist/chunk-M33CB2H4.js +0 -6
- package/dist/chunk-M33CB2H4.js.map +0 -1
- package/dist/chunk-NJR5WF5E.js +0 -5
- package/dist/chunk-RB73FZXJ.js +0 -133
- package/dist/chunk-RB73FZXJ.js.map +0 -1
- package/dist/chunk-UPT2UMF6.js +0 -159
- package/dist/chunk-UPT2UMF6.js.map +0 -1
- package/dist/config-7QJ2QJIC.js +0 -2
- package/dist/config-mutator-GAEVGHDD.js +0 -2
- package/dist/debug-N3B5NVJU.js +0 -2
- package/dist/loader-YQE6XJBT.js +0 -2
- package/dist/memory-extract-RGPUPMKU.js +0 -2
- package/dist/registry-YVAG4EO5.js +0 -2
- package/dist/usage-dashboard-M7AFIGMJ.js.map +0 -1
- package/dist/workspace-setup-QQTCJY4B.js +0 -2
- /package/dist/{agent-DW3NYIIL.js.map → agent-LRSSVFDR.js.map} +0 -0
- /package/dist/{chunk-ZRYBSI5G.js.map → chunk-7MBTMCKY.js.map} +0 -0
- /package/dist/{chunk-XVYMZ4M7.js.map → chunk-AU37OREL.js.map} +0 -0
- /package/dist/{chunk-4YCH6IZV.js.map → chunk-FIOB3MEX.js.map} +0 -0
- /package/dist/{chunk-O72LPMBR.js.map → chunk-RB7265LO.js.map} +0 -0
- /package/dist/{compaction-7I3E5QUO.js.map → compaction-JBZZ7I7Y.js.map} +0 -0
- /package/dist/{config-7QJ2QJIC.js.map → config-DCJYECL4.js.map} +0 -0
- /package/dist/{config-mutator-GAEVGHDD.js.map → config-mutator-6EJHSP3Y.js.map} +0 -0
- /package/dist/{debug-N3B5NVJU.js.map → debug-3MEUO2P2.js.map} +0 -0
- /package/dist/{heal-OTGT5HHJ.js.map → heal-WKY5I4KB.js.map} +0 -0
- /package/dist/{loader-YQE6XJBT.js.map → loader-PTCXLJEX.js.map} +0 -0
- /package/dist/{memory-extract-RGPUPMKU.js.map → memory-extract-AD7KMRPC.js.map} +0 -0
- /package/dist/{providers-G3WZ4RVJ.js.map → providers-VUIWO3ZK.js.map} +0 -0
- /package/dist/{registry-YVAG4EO5.js.map → registry-5ND7GLFJ.js.map} +0 -0
- /package/dist/{workspace-setup-QQTCJY4B.js.map → scheduler-FCXOXCN5.js.map} +0 -0
- /package/dist/{subagent-WV7QKQ3L.js.map → subagent-2SJHSSJS.js.map} +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import{f as b,i as $}from"./chunk-B4Q4X7D5.js";import{existsSync as g,readFileSync as S,writeFileSync as T,appendFileSync as R,mkdirSync as W}from"fs";import{resolve as c}from"path";import{hostname as j}from"os";$();import{existsSync as v,readFileSync as x,writeFileSync as h,copyFileSync as B}from"fs";import{resolve as y}from"path";function w(e,t={}){let n=t.configPath||y(process.cwd(),"agentx.json");if(!v(n))throw new Error(`agentx.json not found at ${n}`);let a=JSON.parse(x(n,"utf-8")),r=e(a),i=typeof r=="string"?{summary:r}:r,s=JSON.stringify(a,null,2)+`
|
|
2
|
+
`,d=n+".tmp";h(d,s,"utf-8");try{JSON.parse(x(d,"utf-8"))}catch(u){throw new Error(`config did not round-trip cleanly: ${u.message}`)}let l;return t.skipBackup||(l=`${n}.bak.${Date.now()}`,B(n,l)),h(n,s,"utf-8"),t.skipReload||_().catch(()=>{}),{summary:i.summary,payload:i.payload,backupPath:l}}function k(e,t={}){let n=t.configPath||y(process.cwd(),"agentx.json");if(v(n)&&!t.overwrite)throw new Error(`agentx.json already exists at ${n}. Pass overwrite=true to replace it.`);return h(n,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,"utf-8"),{file:n}}async function _(){try{let t=b().dashboard.daemonUrl?.replace(/\/+$/,"")||"http://127.0.0.1:18800";await fetch(`${t}/reload`,{method:"POST"}).catch(()=>null)}catch{}}function C(e=process.cwd()){let t=c(e,"agentx.json");if(!g(t))return{configExists:!1,agentCount:0,channelCount:0};try{let n=JSON.parse(S(t,"utf-8")),a=n.agents?Object.keys(n.agents).length:0,r=n.channels?Object.values(n.channels).filter(i=>i&&i.enabled).length:0;return{configExists:!0,agentCount:a,channelCount:r,nodeName:n.node?.name}}catch{return{configExists:!1,agentCount:0,channelCount:0}}}function F(e,t=process.cwd()){if(!e.nodeName?.trim())throw new Error("Team name is required.");if(!e.agent?.id?.trim())throw new Error("Agent id is required.");if(!/^[a-z0-9][a-z0-9_-]*$/.test(e.agent.id))throw new Error("Agent id must be lowercase (letters, digits, -, _) and start with a letter or digit.");if(!e.agent.name?.trim())throw new Error("Agent name is required.");let n=D(e.agent.triggerWords);if(n.length===0)throw new Error("At least one trigger word is required.");if(e.agent.tier!=="claude-code"&&e.agent.tier!=="sdk")throw new Error("AI engine must be claude-code or sdk.");let a=c(t,"agentx.json"),r=c(t,".env"),i=c(t,"agents",e.agent.id),s=C(t);W(i,{recursive:!0});let d=c(i,"CLAUDE.md");if(!g(d)){let m=e.agent.personality?.trim()||`You are ${e.agent.name}, an assistant on the ${e.nodeName} team.`;T(d,`# ${e.agent.name}
|
|
4
|
+
|
|
5
|
+
${m}
|
|
6
|
+
`)}let l=e.telegram?`TG_${e.agent.id.toUpperCase()}_BOT_TOKEN`:void 0,u;if(s.configExists)u=w(o=>{if(o.node=o.node||{},o.node.name||(o.node.name=e.nodeName),o.node.id||(o.node.id=E(e.nodeName)||"team"),o.node.bind||(o.node.bind="127.0.0.1:18800"),o.node.defaultAgent=o.node.defaultAgent||e.agent.id,o.providers=o.providers||{},o.providers.claude||(o.providers.claude={apiKey:"${ANTHROPIC_API_KEY}"}),o.agents=o.agents||{},o.agents[e.agent.id])throw new Error(`Agent "${e.agent.id}" already exists.`);return o.agents[e.agent.id]=I(e,i,n),e.telegram&&(o.channels=o.channels||{},o.channels.telegram=o.channels.telegram||{enabled:!0,accounts:{},policy:{dm:"pair",group:"mention-required"}},o.channels.telegram.enabled=!0,o.channels.telegram.accounts=o.channels.telegram.accounts||{},o.channels.telegram.accounts[e.telegram.accountId]=z(e,l)),{summary:`added agent "${e.agent.id}"`+(e.telegram?" + telegram account":"")}},{configPath:a}).backupPath;else{let m=U(e,i,n,l);k(m,{configPath:a})}H(r,e,l);let p=[];return(e.anthropicApiKey||!g(c(t,".env")))&&p.push("Double-check the API keys in .env"),e.agent.tier==="claude-code"&&p.push("Run claude --version to confirm Claude Code is installed (needed for the claude-code engine)"),p.push("Start the daemon: agentx daemon start"),p.push("Open the dashboard: http://127.0.0.1:4202"),{summary:s.configExists?`Added agent "${e.agent.id}" to your team.`:`Initialized your team with first agent "${e.agent.id}".`,nextSteps:p,backupPath:u}}function D(e){return(e||"").split(/[,\s]+/).map(t=>t.trim()).filter(Boolean).filter((t,n,a)=>a.indexOf(t)===n)}function E(e){return(e||"").toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")}function U(e,t,n,a){let i={node:{id:E(e.nodeName)||"team",name:e.nodeName,bind:"127.0.0.1:18800",defaultAgent:e.agent.id},providers:{claude:{apiKey:"${ANTHROPIC_API_KEY}"}},agents:{[e.agent.id]:I(e,t,n)},channels:{},crons:{},mesh:{enabled:!1,peers:[],discovery:"static",healthCheck:{interval:60,timeout:10}},dashboard:{enabled:!0,port:4202,bind:"127.0.0.1",daemonUrl:"http://localhost:18800"},boards:[]};return e.telegram&&a?i.channels.telegram={enabled:!0,accounts:{[e.telegram.accountId]:z(e,a)},policy:{dm:"pair",group:"mention-required"}}:i.channels.telegram={enabled:!1,accounts:{},policy:{dm:"pair",group:"mention-required"}},i}function I(e,t,n){let a={name:e.agent.name,workspace:t,tier:e.agent.tier,mentions:n,maxConcurrent:2,permissionMode:"default"};return e.agent.model&&(a.model=e.agent.model),e.agent.personality?.trim()&&(a.systemPrompt=e.agent.personality.trim().slice(0,400)),a}function z(e,t){return{botToken:"${"+t+"}",botUsername:e.telegram?.botUsername||"",agentBinding:e.agent.id}}function H(e,t,n){let a=g(e)?S(e,"utf-8"):"",r=[];if(t.anthropicApiKey&&!a.includes("ANTHROPIC_API_KEY=")&&r.push(`ANTHROPIC_API_KEY=${t.anthropicApiKey}`),t.telegram&&n&&!a.includes(`${n}=`)&&r.push(`${n}=${t.telegram.botToken}`),!g(e)){T(e,[...["# AgentX environment variables","# (Never commit this file \u2014 it contains secrets.)",""],...r,""].join(`
|
|
7
|
+
`));return}if(r.length>0){let i=a.endsWith(`
|
|
8
|
+
`)?"":`
|
|
9
|
+
`;R(e,i+r.join(`
|
|
10
|
+
`)+`
|
|
11
|
+
`)}}function se(e,t){let n=C(),a=K(n);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(a)}async function de(e,t){let n="";await new Promise(r=>{e.on("data",i=>{n+=i}),e.on("end",()=>r())});let a;try{a=JSON.parse(n)}catch{t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Invalid JSON"}));return}try{let r=F(a);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(r))}catch(r){t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:r.message||"wizard failed"}))}}function K(e){let t=e.configExists?e.agentCount===0?"Add your first agent":"Add another agent":"Set up your team",n=e.nodeName||j().replace(/\.local$/,"");return`<!DOCTYPE html>
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="utf-8">
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
16
|
+
<title>AgentX \u2014 Setup</title>
|
|
17
|
+
<style>
|
|
18
|
+
:root{--bg:#0b0d14;--card:#151823;--border:#2a2d3a;--text:#e6e8ef;--muted:#8b8fa3;--accent:#6366f1;--green:#22c55e;--red:#ef4444}
|
|
19
|
+
*{box-sizing:border-box}
|
|
20
|
+
html,body{margin:0;min-height:100%;background:var(--bg);color:var(--text);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
|
|
21
|
+
header{padding:18px 24px;border-bottom:1px solid var(--border);background:#10131c;display:flex;align-items:center;gap:12px}
|
|
22
|
+
header .brand{font-weight:600;color:var(--accent);font-size:15px}
|
|
23
|
+
header .sub{color:var(--muted);font-weight:500}
|
|
24
|
+
.spacer{flex:1}
|
|
25
|
+
a.link{color:var(--muted);text-decoration:none;font-size:13px;padding:4px 10px;border:1px solid var(--border);border-radius:6px}
|
|
26
|
+
a.link:hover{color:var(--accent);border-color:var(--accent)}
|
|
27
|
+
main{max-width:620px;margin:0 auto;padding:32px 22px 60px}
|
|
28
|
+
h1{font-size:24px;margin:0 0 6px}
|
|
29
|
+
.lead{color:var(--muted);margin:0 0 26px}
|
|
30
|
+
section.step{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:20px 22px;margin:14px 0}
|
|
31
|
+
section.step h2{font-size:14px;font-weight:600;margin:0 0 14px;color:var(--text);display:flex;align-items:center;gap:10px}
|
|
32
|
+
section.step h2 .num{background:var(--accent);color:#fff;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}
|
|
33
|
+
label{display:block;margin:10px 0 4px;font-size:12px;color:var(--muted)}
|
|
34
|
+
label .hint{color:var(--muted);font-weight:400;font-size:11px;margin-left:6px}
|
|
35
|
+
input,textarea,select{width:100%;background:#0e1119;color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px 10px;font:13px/1.4 inherit}
|
|
36
|
+
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent)}
|
|
37
|
+
textarea{resize:vertical;min-height:70px;font-family:inherit}
|
|
38
|
+
.row{display:flex;gap:10px}
|
|
39
|
+
.row > *{flex:1}
|
|
40
|
+
.toggle{display:flex;align-items:center;gap:8px;margin:14px 0 4px;font-size:13px;color:var(--text);cursor:pointer}
|
|
41
|
+
.toggle input{width:auto}
|
|
42
|
+
.optional{border-left:2px solid var(--border);padding-left:14px;margin-top:10px;display:none}
|
|
43
|
+
.optional.show{display:block}
|
|
44
|
+
footer.actions{display:flex;gap:10px;padding:20px 0;align-items:center}
|
|
45
|
+
button.primary{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:10px 20px;font-size:14px;font-weight:600;cursor:pointer}
|
|
46
|
+
button.primary:hover{filter:brightness(1.1)}
|
|
47
|
+
button.primary:disabled{opacity:0.5;cursor:not-allowed}
|
|
48
|
+
button.ghost{background:transparent;color:var(--muted);border:1px solid var(--border);border-radius:6px;padding:9px 16px;cursor:pointer}
|
|
49
|
+
.hint-block{font-size:11px;color:var(--muted);margin-top:6px;line-height:1.55}
|
|
50
|
+
.hint-block code{background:#10131c;padding:1px 6px;border-radius:3px;color:var(--text);font-family:ui-monospace,monospace;font-size:11px}
|
|
51
|
+
#msg{margin:14px 0;padding:12px 16px;border-radius:6px;font-size:13px;display:none}
|
|
52
|
+
#msg.ok{display:block;background:rgba(34,197,94,0.12);color:var(--green);border:1px solid rgba(34,197,94,0.3)}
|
|
53
|
+
#msg.err{display:block;background:rgba(239,68,68,0.12);color:var(--red);border:1px solid rgba(239,68,68,0.3)}
|
|
54
|
+
#next-steps{margin-top:12px;padding-left:20px}
|
|
55
|
+
#next-steps li{margin:4px 0}
|
|
56
|
+
#next-steps code{background:#10131c;padding:1px 6px;border-radius:3px;color:var(--text);font-family:ui-monospace,monospace;font-size:12px}
|
|
57
|
+
.config-banner{background:rgba(99,102,241,0.12);border:1px solid rgba(99,102,241,0.3);border-radius:6px;padding:10px 14px;margin-bottom:16px;color:var(--muted);font-size:12px}
|
|
58
|
+
.config-banner b{color:var(--text)}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<header>
|
|
63
|
+
<div class="brand">AgentX <span class="sub">\xB7 Setup</span></div>
|
|
64
|
+
<div class="spacer"></div>
|
|
65
|
+
<a href="/glossary" class="link">? Glossary</a>
|
|
66
|
+
<a href="/live" class="link">Skip \u2014 open dashboard</a>
|
|
67
|
+
</header>
|
|
68
|
+
<main>
|
|
69
|
+
<h1>${A(t)}</h1>
|
|
70
|
+
<p class="lead">Fill in the basics below. We'll write <code>agentx.json</code>, set up a folder for your first agent, and point you at the next step.</p>
|
|
71
|
+
|
|
72
|
+
${e.configExists?`<div class="config-banner">Existing install: <b>${e.agentCount}</b> agent(s), <b>${e.channelCount}</b> channel(s) already configured. This wizard will add to it.</div>`:""}
|
|
73
|
+
|
|
74
|
+
<div id="msg"></div>
|
|
75
|
+
|
|
76
|
+
<form id="wizard" autocomplete="off">
|
|
77
|
+
<section class="step">
|
|
78
|
+
<h2><span class="num">1</span>Team basics</h2>
|
|
79
|
+
<label>Team name<span class="hint">(what you'd call this AgentX install)</span></label>
|
|
80
|
+
<input name="nodeName" value="${A(n)}" placeholder="My Team" required />
|
|
81
|
+
</section>
|
|
82
|
+
|
|
83
|
+
<section class="step">
|
|
84
|
+
<h2><span class="num">2</span>First agent</h2>
|
|
85
|
+
<div class="row">
|
|
86
|
+
<div>
|
|
87
|
+
<label>Agent name</label>
|
|
88
|
+
<input name="agentName" value="Assistant" placeholder="Support Bot" required />
|
|
89
|
+
</div>
|
|
90
|
+
<div>
|
|
91
|
+
<label>Agent id<span class="hint">(lowercase, no spaces)</span></label>
|
|
92
|
+
<input name="agentId" value="assistant" pattern="[a-z0-9][a-z0-9_-]*" required />
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<label>Trigger words<span class="hint">(words that activate this agent \u2014 comma or space separated, e.g. <code>@support, support</code>)</span></label>
|
|
96
|
+
<input name="triggerWords" value="@assistant, assistant" required />
|
|
97
|
+
<div class="row">
|
|
98
|
+
<div>
|
|
99
|
+
<label>AI engine</label>
|
|
100
|
+
<select name="tier">
|
|
101
|
+
<option value="claude-code">Claude Code (recommended)</option>
|
|
102
|
+
<option value="sdk">Anthropic API (BYO key)</option>
|
|
103
|
+
</select>
|
|
104
|
+
</div>
|
|
105
|
+
<div>
|
|
106
|
+
<label>Model<span class="hint">(optional)</span></label>
|
|
107
|
+
<input name="model" value="claude-sonnet-4-6" placeholder="claude-sonnet-4-6" />
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
<label>Personality / instructions<span class="hint">(optional \u2014 what this agent does, in plain English)</span></label>
|
|
111
|
+
<textarea name="personality" placeholder="You are a support agent for Acme Co. Answer customer questions about our product, be friendly, keep replies short."></textarea>
|
|
112
|
+
</section>
|
|
113
|
+
|
|
114
|
+
<section class="step">
|
|
115
|
+
<h2><span class="num">3</span>First channel</h2>
|
|
116
|
+
<label class="toggle"><input type="checkbox" id="enableTelegram" /> Connect Telegram now</label>
|
|
117
|
+
<div class="optional" id="telegramFields">
|
|
118
|
+
<label>Account id<span class="hint">(a label you choose \u2014 e.g. <code>support</code>)</span></label>
|
|
119
|
+
<input name="telegramAccountId" value="default" />
|
|
120
|
+
<label>Bot token<span class="hint">(from <a href="https://t.me/BotFather" target="_blank" style="color:var(--accent)">@BotFather</a>)</span></label>
|
|
121
|
+
<input name="telegramBotToken" placeholder="123456:ABCdef..." />
|
|
122
|
+
<label>Bot username<span class="hint">(optional \u2014 e.g. <code>my_support_bot</code>)</span></label>
|
|
123
|
+
<input name="telegramBotUsername" placeholder="my_support_bot" />
|
|
124
|
+
</div>
|
|
125
|
+
</section>
|
|
126
|
+
|
|
127
|
+
<section class="step">
|
|
128
|
+
<h2><span class="num">4</span>Anthropic API key</h2>
|
|
129
|
+
<label>API key<span class="hint">(optional if you'll paste it into <code>.env</code> manually, or if you're only using Claude Code)</span></label>
|
|
130
|
+
<input name="anthropicApiKey" type="password" placeholder="sk-ant-\u2026" autocomplete="off" />
|
|
131
|
+
<div class="hint-block">
|
|
132
|
+
The key is written to <code>.env</code> as <code>ANTHROPIC_API_KEY</code>. AgentX never transmits it \u2014 everything stays on this machine.
|
|
133
|
+
</div>
|
|
134
|
+
</section>
|
|
135
|
+
|
|
136
|
+
<footer class="actions">
|
|
137
|
+
<button type="submit" class="primary" id="submitBtn">Save and continue</button>
|
|
138
|
+
<button type="button" class="ghost" onclick="window.location.href='/live'">Skip, I'll do it later</button>
|
|
139
|
+
</footer>
|
|
140
|
+
</form>
|
|
141
|
+
</main>
|
|
142
|
+
<script>
|
|
143
|
+
document.getElementById('enableTelegram').addEventListener('change', (e) => {
|
|
144
|
+
document.getElementById('telegramFields').classList.toggle('show', e.target.checked);
|
|
145
|
+
});
|
|
146
|
+
document.getElementById('wizard').addEventListener('submit', async (e) => {
|
|
147
|
+
e.preventDefault();
|
|
148
|
+
const f = e.target;
|
|
149
|
+
const msg = document.getElementById('msg');
|
|
150
|
+
const btn = document.getElementById('submitBtn');
|
|
151
|
+
msg.className = ''; msg.style.display = 'none';
|
|
152
|
+
btn.disabled = true; btn.textContent = 'Saving\u2026';
|
|
153
|
+
const telegramEnabled = document.getElementById('enableTelegram').checked;
|
|
154
|
+
const payload = {
|
|
155
|
+
nodeName: f.nodeName.value.trim(),
|
|
156
|
+
agent: {
|
|
157
|
+
id: f.agentId.value.trim(),
|
|
158
|
+
name: f.agentName.value.trim(),
|
|
159
|
+
triggerWords: f.triggerWords.value.trim(),
|
|
160
|
+
tier: f.tier.value,
|
|
161
|
+
model: f.model.value.trim() || undefined,
|
|
162
|
+
personality: f.personality.value.trim() || undefined,
|
|
163
|
+
},
|
|
164
|
+
anthropicApiKey: f.anthropicApiKey.value.trim() || undefined,
|
|
165
|
+
};
|
|
166
|
+
if (telegramEnabled) {
|
|
167
|
+
payload.telegram = {
|
|
168
|
+
accountId: f.telegramAccountId.value.trim() || 'default',
|
|
169
|
+
botToken: f.telegramBotToken.value.trim(),
|
|
170
|
+
botUsername: f.telegramBotUsername.value.trim() || undefined,
|
|
171
|
+
};
|
|
172
|
+
if (!payload.telegram.botToken) {
|
|
173
|
+
msg.className = 'err'; msg.textContent = 'Bot token is required when Telegram is enabled.';
|
|
174
|
+
btn.disabled = false; btn.textContent = 'Save and continue'; return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const r = await fetch('/api/setup', {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'agentx-wizard' },
|
|
181
|
+
body: JSON.stringify(payload),
|
|
182
|
+
});
|
|
183
|
+
const data = await r.json();
|
|
184
|
+
if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));
|
|
185
|
+
const steps = data.nextSteps.map((s) => '<li>' + s.replace(/\`([^\`]+)\`/g, '<code>$1</code>') + '</li>').join('');
|
|
186
|
+
msg.className = 'ok';
|
|
187
|
+
msg.innerHTML = '<b>' + data.summary + '</b><ol id="next-steps">' + steps + '</ol>';
|
|
188
|
+
btn.textContent = 'Done';
|
|
189
|
+
btn.disabled = true;
|
|
190
|
+
} catch (err) {
|
|
191
|
+
msg.className = 'err'; msg.textContent = err.message;
|
|
192
|
+
btn.disabled = false; btn.textContent = 'Save and continue';
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
</script>
|
|
196
|
+
</body>
|
|
197
|
+
</html>`}function A(e){return String(e||"").replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}import{createHash as M,randomBytes as N}from"crypto";import{existsSync as q,mkdirSync as J,readFileSync as L,writeFileSync as Y}from"fs";import{resolve as X,dirname as G}from"path";var f="agx_live_",V=".agentx/tokens.json",P=class{file;constructor(t=process.cwd(),n=V){this.file=X(t,n)}load(){if(!q(this.file))return[];try{return JSON.parse(L(this.file,"utf-8"))}catch{return[]}}save(t){J(G(this.file),{recursive:!0}),Y(this.file,JSON.stringify(t,null,2)+`
|
|
198
|
+
`,"utf-8")}create(t){if(!t.name?.trim())throw new Error("Token name is required.");if(!Array.isArray(t.scopes)||t.scopes.length===0)throw new Error("At least one scope is required.");for(let s of t.scopes)if(!Q(s))throw new Error(`Invalid scope: ${s}`);let n=N(32).toString("hex"),a=f+n,r={id:"tok_"+N(4).toString("hex"),name:t.name.trim(),prefix:f+n.slice(0,4),hash:O(a),scopes:[...t.scopes],createdAt:new Date().toISOString(),expiresAt:t.expiresInDays?new Date(Date.now()+t.expiresInDays*86400*1e3).toISOString():void 0},i=this.load();return i.push(r),this.save(i),{token:a,record:r}}list(){return this.load()}revoke(t){let n=this.load(),a=n.find(r=>r.id===t);return a?(a.revokedAt=new Date().toISOString(),this.save(n),a):null}verify(t){if(!t||!t.startsWith(f))return null;let n=O(t),a=this.load(),r=a.find(d=>d.hash===n);if(!r||r.revokedAt||r.expiresAt&&Date.parse(r.expiresAt)<Date.now())return null;let i=Date.now(),s=r.lastUsedAt?Date.parse(r.lastUsedAt):0;if(i-s>6e4){r.lastUsedAt=new Date(i).toISOString();try{this.save(a)}catch{}}return r}};function ue(e,t){return!!(e.scopes.includes(t)||t.startsWith("agent:")&&e.scopes.includes("agent:*")||t==="dashboard:read"&&e.scopes.includes("dashboard:write"))}function Q(e){return e==="dashboard:read"||e==="dashboard:write"||e==="agent:*"||/^agent:[a-z0-9][a-z0-9_-]*$/.test(e)||e==="mesh:peer"}function O(e){return"sha256:"+M("sha256").update(e).digest("hex")}function me(e){let t=e.headers.authorization,n=Array.isArray(t)?t[0]:t;if(n&&n.toLowerCase().startsWith("bearer "))return n.slice(7).trim();if(e.url)try{let r=new URL(e.url,"http://localhost").searchParams.get("token");if(r)return r}catch{}return null}export{w as a,C as b,se as c,de as d,P as e,ue as f,me as g};
|
|
199
|
+
//# sourceMappingURL=chunk-3XULOWYB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon/setup-wizard.ts","../src/daemon/config-mutate.ts","../src/daemon/token-store.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { hostname } from \"os\"\nimport type { IncomingMessage, ServerResponse } from \"http\"\nimport { mutateAgentxConfig, writeAgentxConfig } from \"./config-mutate\"\n\n// --- /setup wizard: form-driven first-run experience for non-technical operators ---\n//\n// This is the web equivalent of `agentx init` + `agentx agent add` + `agentx\n// channel add`, collapsed into one page. It writes agentx.json and scaffolds\n// the first agent's workspace so a business operator can go from a blank\n// machine to a working AgentX install without editing JSON.\n//\n// The route lives on the board-dashboard server (port 4202) because that's the\n// surface operators actually open. It talks to the loopback daemon for the\n// post-install restart; the wizard itself never requires a running daemon.\n\nexport interface WizardPayload {\n nodeName: string\n agent: {\n id: string\n name: string\n triggerWords: string // comma/space separated; we normalise on the server\n tier: \"claude-code\" | \"sdk\"\n model?: string\n personality?: string // short free text → CLAUDE.md\n }\n telegram?: {\n accountId: string\n botToken: string\n botUsername?: string\n }\n anthropicApiKey?: string\n}\n\n/**\n * Return the current state of the working directory so the wizard can choose\n * between \"fresh install\" and \"add another\" flows.\n */\nexport function wizardState(baseDir: string = process.cwd()): {\n configExists: boolean\n agentCount: number\n channelCount: number\n nodeName?: string\n} {\n const file = resolve(baseDir, \"agentx.json\")\n if (!existsSync(file)) return { configExists: false, agentCount: 0, channelCount: 0 }\n try {\n const cfg = JSON.parse(readFileSync(file, \"utf-8\"))\n const agents = cfg.agents ? Object.keys(cfg.agents).length : 0\n const channels = cfg.channels\n ? Object.values(cfg.channels).filter((c: any) => c && c.enabled).length\n : 0\n return { configExists: true, agentCount: agents, channelCount: channels, nodeName: cfg.node?.name }\n } catch {\n return { configExists: false, agentCount: 0, channelCount: 0 }\n }\n}\n\n/**\n * Execute the wizard submission. Returns a short human-readable summary of\n * what was written. Throws on validation error — the caller surfaces the\n * message to the user.\n */\nexport function runWizard(payload: WizardPayload, baseDir: string = process.cwd()): {\n summary: string\n nextSteps: string[]\n backupPath?: string\n} {\n // --- validate ---\n if (!payload.nodeName?.trim()) throw new Error(\"Team name is required.\")\n if (!payload.agent?.id?.trim()) throw new Error(\"Agent id is required.\")\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(payload.agent.id)) {\n throw new Error(\"Agent id must be lowercase (letters, digits, -, _) and start with a letter or digit.\")\n }\n if (!payload.agent.name?.trim()) throw new Error(\"Agent name is required.\")\n const mentions = splitMentions(payload.agent.triggerWords)\n if (mentions.length === 0) throw new Error(\"At least one trigger word is required.\")\n if (payload.agent.tier !== \"claude-code\" && payload.agent.tier !== \"sdk\") {\n throw new Error(\"AI engine must be claude-code or sdk.\")\n }\n\n const configPath = resolve(baseDir, \"agentx.json\")\n const envPath = resolve(baseDir, \".env\")\n const workspaceDir = resolve(baseDir, \"agents\", payload.agent.id)\n const state = wizardState(baseDir)\n\n // --- scaffold workspace ---\n mkdirSync(workspaceDir, { recursive: true })\n const claudeMd = resolve(workspaceDir, \"CLAUDE.md\")\n if (!existsSync(claudeMd)) {\n const personality = payload.agent.personality?.trim() || `You are ${payload.agent.name}, an assistant on the ${payload.nodeName} team.`\n writeFileSync(claudeMd, `# ${payload.agent.name}\\n\\n${personality}\\n`)\n }\n\n // --- build / mutate agentx.json ---\n const telegramTokenRef = payload.telegram\n ? `TG_${payload.agent.id.toUpperCase()}_BOT_TOKEN`\n : undefined\n\n let backupPath: string | undefined\n if (!state.configExists) {\n const cfg = buildFreshConfig(payload, workspaceDir, mentions, telegramTokenRef)\n writeAgentxConfig(cfg, { configPath })\n } else {\n const result = mutateAgentxConfig((cfg) => {\n cfg.node = cfg.node || {}\n if (!cfg.node.name) cfg.node.name = payload.nodeName\n if (!cfg.node.id) cfg.node.id = slugify(payload.nodeName) || \"team\"\n if (!cfg.node.bind) cfg.node.bind = \"127.0.0.1:18800\"\n cfg.node.defaultAgent = cfg.node.defaultAgent || payload.agent.id\n\n cfg.providers = cfg.providers || {}\n if (!cfg.providers.claude) cfg.providers.claude = { apiKey: \"${ANTHROPIC_API_KEY}\" }\n\n cfg.agents = cfg.agents || {}\n if (cfg.agents[payload.agent.id]) throw new Error(`Agent \"${payload.agent.id}\" already exists.`)\n cfg.agents[payload.agent.id] = agentBlock(payload, workspaceDir, mentions)\n\n if (payload.telegram) {\n cfg.channels = cfg.channels || {}\n cfg.channels.telegram = cfg.channels.telegram || { enabled: true, accounts: {}, policy: { dm: \"pair\", group: \"mention-required\" } }\n cfg.channels.telegram.enabled = true\n cfg.channels.telegram.accounts = cfg.channels.telegram.accounts || {}\n cfg.channels.telegram.accounts[payload.telegram.accountId] = telegramAccountBlock(payload, telegramTokenRef!)\n }\n\n return { summary: `added agent \"${payload.agent.id}\"` + (payload.telegram ? \" + telegram account\" : \"\") }\n }, { configPath })\n backupPath = result.backupPath\n }\n\n // --- write / append .env ---\n ensureEnvEntries(envPath, payload, telegramTokenRef)\n\n const nextSteps: string[] = []\n if (payload.anthropicApiKey || !existsSync(resolve(baseDir, \".env\"))) {\n nextSteps.push(\"Double-check the API keys in .env\")\n }\n if (payload.agent.tier === \"claude-code\") {\n nextSteps.push(\"Run claude --version to confirm Claude Code is installed (needed for the claude-code engine)\")\n }\n nextSteps.push(\"Start the daemon: agentx daemon start\")\n nextSteps.push(\"Open the dashboard: http://127.0.0.1:4202\")\n\n return {\n summary: state.configExists\n ? `Added agent \"${payload.agent.id}\" to your team.`\n : `Initialized your team with first agent \"${payload.agent.id}\".`,\n nextSteps,\n backupPath,\n }\n}\n\nfunction splitMentions(s: string): string[] {\n return (s || \"\")\n .split(/[,\\s]+/)\n .map((m) => m.trim())\n .filter(Boolean)\n // Normalise: ensure @-prefix entries stay, plain ones are kept as-is.\n .filter((m, i, a) => a.indexOf(m) === i)\n}\n\nfunction slugify(s: string): string {\n return (s || \"\").toLowerCase().replace(/[^a-z0-9-]+/g, \"-\").replace(/^-+|-+$/g, \"\")\n}\n\nfunction buildFreshConfig(payload: WizardPayload, workspaceDir: string, mentions: string[], telegramTokenRef?: string) {\n const id = slugify(payload.nodeName) || \"team\"\n const cfg: any = {\n node: { id, name: payload.nodeName, bind: \"127.0.0.1:18800\", defaultAgent: payload.agent.id },\n providers: { claude: { apiKey: \"${ANTHROPIC_API_KEY}\" } },\n agents: { [payload.agent.id]: agentBlock(payload, workspaceDir, mentions) },\n channels: {},\n crons: {},\n mesh: { enabled: false, peers: [], discovery: \"static\", healthCheck: { interval: 60, timeout: 10 } },\n dashboard: { enabled: true, port: 4202, bind: \"127.0.0.1\", daemonUrl: \"http://localhost:18800\" },\n boards: [],\n }\n if (payload.telegram && telegramTokenRef) {\n cfg.channels.telegram = {\n enabled: true,\n accounts: { [payload.telegram.accountId]: telegramAccountBlock(payload, telegramTokenRef) },\n policy: { dm: \"pair\", group: \"mention-required\" },\n }\n } else {\n cfg.channels.telegram = { enabled: false, accounts: {}, policy: { dm: \"pair\", group: \"mention-required\" } }\n }\n return cfg\n}\n\nfunction agentBlock(payload: WizardPayload, workspaceDir: string, mentions: string[]) {\n const block: any = {\n name: payload.agent.name,\n workspace: workspaceDir,\n tier: payload.agent.tier,\n mentions,\n maxConcurrent: 2,\n permissionMode: \"default\",\n }\n if (payload.agent.model) block.model = payload.agent.model\n if (payload.agent.personality?.trim()) block.systemPrompt = payload.agent.personality.trim().slice(0, 400)\n return block\n}\n\nfunction telegramAccountBlock(payload: WizardPayload, tokenRef: string) {\n return {\n botToken: \"${\" + tokenRef + \"}\",\n botUsername: payload.telegram?.botUsername || \"\",\n agentBinding: payload.agent.id,\n }\n}\n\nfunction ensureEnvEntries(envPath: string, payload: WizardPayload, telegramTokenRef?: string): void {\n const existing = existsSync(envPath) ? readFileSync(envPath, \"utf-8\") : \"\"\n const lines: string[] = []\n\n if (payload.anthropicApiKey && !existing.includes(\"ANTHROPIC_API_KEY=\")) {\n lines.push(`ANTHROPIC_API_KEY=${payload.anthropicApiKey}`)\n }\n if (payload.telegram && telegramTokenRef && !existing.includes(`${telegramTokenRef}=`)) {\n lines.push(`${telegramTokenRef}=${payload.telegram.botToken}`)\n }\n\n if (!existsSync(envPath)) {\n const header = [\n \"# AgentX environment variables\",\n \"# (Never commit this file — it contains secrets.)\",\n \"\",\n ]\n writeFileSync(envPath, [...header, ...lines, \"\"].join(\"\\n\"))\n return\n }\n if (lines.length > 0) {\n const sep = existing.endsWith(\"\\n\") ? \"\" : \"\\n\"\n appendFileSync(envPath, sep + lines.join(\"\\n\") + \"\\n\")\n }\n}\n\n// --- HTTP handlers used by board-dashboard.ts ---\n\nexport function handleWizardGet(_req: IncomingMessage, res: ServerResponse): void {\n const state = wizardState()\n const html = renderWizardHtml(state)\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n res.end(html)\n}\n\nexport async function handleWizardPost(req: IncomingMessage, res: ServerResponse): Promise<void> {\n let raw = \"\"\n await new Promise<void>((ok) => { req.on(\"data\", (c) => { raw += c }); req.on(\"end\", () => ok()) })\n let payload: WizardPayload\n try { payload = JSON.parse(raw) }\n catch { res.writeHead(400, { \"Content-Type\": \"application/json\" }); res.end(JSON.stringify({ error: \"Invalid JSON\" })); return }\n try {\n const result = runWizard(payload)\n res.writeHead(200, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify(result))\n } catch (e: any) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify({ error: e.message || \"wizard failed\" }))\n }\n}\n\nfunction renderWizardHtml(state: ReturnType<typeof wizardState>): string {\n const heading = state.configExists\n ? (state.agentCount === 0 ? \"Add your first agent\" : \"Add another agent\")\n : \"Set up your team\"\n const defaultNode = state.nodeName || hostname().replace(/\\.local$/, \"\")\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>AgentX — Setup</title>\n<style>\n:root{--bg:#0b0d14;--card:#151823;--border:#2a2d3a;--text:#e6e8ef;--muted:#8b8fa3;--accent:#6366f1;--green:#22c55e;--red:#ef4444}\n*{box-sizing:border-box}\nhtml,body{margin:0;min-height:100%;background:var(--bg);color:var(--text);font:14px/1.5 -apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif}\nheader{padding:18px 24px;border-bottom:1px solid var(--border);background:#10131c;display:flex;align-items:center;gap:12px}\nheader .brand{font-weight:600;color:var(--accent);font-size:15px}\nheader .sub{color:var(--muted);font-weight:500}\n.spacer{flex:1}\na.link{color:var(--muted);text-decoration:none;font-size:13px;padding:4px 10px;border:1px solid var(--border);border-radius:6px}\na.link:hover{color:var(--accent);border-color:var(--accent)}\nmain{max-width:620px;margin:0 auto;padding:32px 22px 60px}\nh1{font-size:24px;margin:0 0 6px}\n.lead{color:var(--muted);margin:0 0 26px}\nsection.step{background:var(--card);border:1px solid var(--border);border-radius:10px;padding:20px 22px;margin:14px 0}\nsection.step h2{font-size:14px;font-weight:600;margin:0 0 14px;color:var(--text);display:flex;align-items:center;gap:10px}\nsection.step h2 .num{background:var(--accent);color:#fff;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}\nlabel{display:block;margin:10px 0 4px;font-size:12px;color:var(--muted)}\nlabel .hint{color:var(--muted);font-weight:400;font-size:11px;margin-left:6px}\ninput,textarea,select{width:100%;background:#0e1119;color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px 10px;font:13px/1.4 inherit}\ninput:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent)}\ntextarea{resize:vertical;min-height:70px;font-family:inherit}\n.row{display:flex;gap:10px}\n.row > *{flex:1}\n.toggle{display:flex;align-items:center;gap:8px;margin:14px 0 4px;font-size:13px;color:var(--text);cursor:pointer}\n.toggle input{width:auto}\n.optional{border-left:2px solid var(--border);padding-left:14px;margin-top:10px;display:none}\n.optional.show{display:block}\nfooter.actions{display:flex;gap:10px;padding:20px 0;align-items:center}\nbutton.primary{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:10px 20px;font-size:14px;font-weight:600;cursor:pointer}\nbutton.primary:hover{filter:brightness(1.1)}\nbutton.primary:disabled{opacity:0.5;cursor:not-allowed}\nbutton.ghost{background:transparent;color:var(--muted);border:1px solid var(--border);border-radius:6px;padding:9px 16px;cursor:pointer}\n.hint-block{font-size:11px;color:var(--muted);margin-top:6px;line-height:1.55}\n.hint-block code{background:#10131c;padding:1px 6px;border-radius:3px;color:var(--text);font-family:ui-monospace,monospace;font-size:11px}\n#msg{margin:14px 0;padding:12px 16px;border-radius:6px;font-size:13px;display:none}\n#msg.ok{display:block;background:rgba(34,197,94,0.12);color:var(--green);border:1px solid rgba(34,197,94,0.3)}\n#msg.err{display:block;background:rgba(239,68,68,0.12);color:var(--red);border:1px solid rgba(239,68,68,0.3)}\n#next-steps{margin-top:12px;padding-left:20px}\n#next-steps li{margin:4px 0}\n#next-steps code{background:#10131c;padding:1px 6px;border-radius:3px;color:var(--text);font-family:ui-monospace,monospace;font-size:12px}\n.config-banner{background:rgba(99,102,241,0.12);border:1px solid rgba(99,102,241,0.3);border-radius:6px;padding:10px 14px;margin-bottom:16px;color:var(--muted);font-size:12px}\n.config-banner b{color:var(--text)}\n</style>\n</head>\n<body>\n<header>\n <div class=\"brand\">AgentX <span class=\"sub\">· Setup</span></div>\n <div class=\"spacer\"></div>\n <a href=\"/glossary\" class=\"link\">? Glossary</a>\n <a href=\"/live\" class=\"link\">Skip — open dashboard</a>\n</header>\n<main>\n <h1>${escapeHtml(heading)}</h1>\n <p class=\"lead\">Fill in the basics below. We'll write <code>agentx.json</code>, set up a folder for your first agent, and point you at the next step.</p>\n\n ${state.configExists ? `<div class=\"config-banner\">Existing install: <b>${state.agentCount}</b> agent(s), <b>${state.channelCount}</b> channel(s) already configured. This wizard will add to it.</div>` : \"\"}\n\n <div id=\"msg\"></div>\n\n <form id=\"wizard\" autocomplete=\"off\">\n <section class=\"step\">\n <h2><span class=\"num\">1</span>Team basics</h2>\n <label>Team name<span class=\"hint\">(what you'd call this AgentX install)</span></label>\n <input name=\"nodeName\" value=\"${escapeHtml(defaultNode)}\" placeholder=\"My Team\" required />\n </section>\n\n <section class=\"step\">\n <h2><span class=\"num\">2</span>First agent</h2>\n <div class=\"row\">\n <div>\n <label>Agent name</label>\n <input name=\"agentName\" value=\"Assistant\" placeholder=\"Support Bot\" required />\n </div>\n <div>\n <label>Agent id<span class=\"hint\">(lowercase, no spaces)</span></label>\n <input name=\"agentId\" value=\"assistant\" pattern=\"[a-z0-9][a-z0-9_-]*\" required />\n </div>\n </div>\n <label>Trigger words<span class=\"hint\">(words that activate this agent — comma or space separated, e.g. <code>@support, support</code>)</span></label>\n <input name=\"triggerWords\" value=\"@assistant, assistant\" required />\n <div class=\"row\">\n <div>\n <label>AI engine</label>\n <select name=\"tier\">\n <option value=\"claude-code\">Claude Code (recommended)</option>\n <option value=\"sdk\">Anthropic API (BYO key)</option>\n </select>\n </div>\n <div>\n <label>Model<span class=\"hint\">(optional)</span></label>\n <input name=\"model\" value=\"claude-sonnet-4-6\" placeholder=\"claude-sonnet-4-6\" />\n </div>\n </div>\n <label>Personality / instructions<span class=\"hint\">(optional — what this agent does, in plain English)</span></label>\n <textarea name=\"personality\" placeholder=\"You are a support agent for Acme Co. Answer customer questions about our product, be friendly, keep replies short.\"></textarea>\n </section>\n\n <section class=\"step\">\n <h2><span class=\"num\">3</span>First channel</h2>\n <label class=\"toggle\"><input type=\"checkbox\" id=\"enableTelegram\" /> Connect Telegram now</label>\n <div class=\"optional\" id=\"telegramFields\">\n <label>Account id<span class=\"hint\">(a label you choose — e.g. <code>support</code>)</span></label>\n <input name=\"telegramAccountId\" value=\"default\" />\n <label>Bot token<span class=\"hint\">(from <a href=\"https://t.me/BotFather\" target=\"_blank\" style=\"color:var(--accent)\">@BotFather</a>)</span></label>\n <input name=\"telegramBotToken\" placeholder=\"123456:ABCdef...\" />\n <label>Bot username<span class=\"hint\">(optional — e.g. <code>my_support_bot</code>)</span></label>\n <input name=\"telegramBotUsername\" placeholder=\"my_support_bot\" />\n </div>\n </section>\n\n <section class=\"step\">\n <h2><span class=\"num\">4</span>Anthropic API key</h2>\n <label>API key<span class=\"hint\">(optional if you'll paste it into <code>.env</code> manually, or if you're only using Claude Code)</span></label>\n <input name=\"anthropicApiKey\" type=\"password\" placeholder=\"sk-ant-…\" autocomplete=\"off\" />\n <div class=\"hint-block\">\n The key is written to <code>.env</code> as <code>ANTHROPIC_API_KEY</code>. AgentX never transmits it — everything stays on this machine.\n </div>\n </section>\n\n <footer class=\"actions\">\n <button type=\"submit\" class=\"primary\" id=\"submitBtn\">Save and continue</button>\n <button type=\"button\" class=\"ghost\" onclick=\"window.location.href='/live'\">Skip, I'll do it later</button>\n </footer>\n </form>\n</main>\n<script>\ndocument.getElementById('enableTelegram').addEventListener('change', (e) => {\n document.getElementById('telegramFields').classList.toggle('show', e.target.checked);\n});\ndocument.getElementById('wizard').addEventListener('submit', async (e) => {\n e.preventDefault();\n const f = e.target;\n const msg = document.getElementById('msg');\n const btn = document.getElementById('submitBtn');\n msg.className = ''; msg.style.display = 'none';\n btn.disabled = true; btn.textContent = 'Saving…';\n const telegramEnabled = document.getElementById('enableTelegram').checked;\n const payload = {\n nodeName: f.nodeName.value.trim(),\n agent: {\n id: f.agentId.value.trim(),\n name: f.agentName.value.trim(),\n triggerWords: f.triggerWords.value.trim(),\n tier: f.tier.value,\n model: f.model.value.trim() || undefined,\n personality: f.personality.value.trim() || undefined,\n },\n anthropicApiKey: f.anthropicApiKey.value.trim() || undefined,\n };\n if (telegramEnabled) {\n payload.telegram = {\n accountId: f.telegramAccountId.value.trim() || 'default',\n botToken: f.telegramBotToken.value.trim(),\n botUsername: f.telegramBotUsername.value.trim() || undefined,\n };\n if (!payload.telegram.botToken) {\n msg.className = 'err'; msg.textContent = 'Bot token is required when Telegram is enabled.';\n btn.disabled = false; btn.textContent = 'Save and continue'; return;\n }\n }\n try {\n const r = await fetch('/api/setup', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'agentx-wizard' },\n body: JSON.stringify(payload),\n });\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n const steps = data.nextSteps.map((s) => '<li>' + s.replace(/\\`([^\\`]+)\\`/g, '<code>$1</code>') + '</li>').join('');\n msg.className = 'ok';\n msg.innerHTML = '<b>' + data.summary + '</b><ol id=\"next-steps\">' + steps + '</ol>';\n btn.textContent = 'Done';\n btn.disabled = true;\n } catch (err) {\n msg.className = 'err'; msg.textContent = err.message;\n btn.disabled = false; btn.textContent = 'Save and continue';\n }\n});\n</script>\n</body>\n</html>`\n}\n\nfunction escapeHtml(s: string): string {\n return String(s || \"\").replace(/[&<>\"']/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" }[c] as string))\n}\n","import { existsSync, readFileSync, writeFileSync, copyFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { loadDaemonConfig } from \"./config\"\n\n// --- Shared helpers for safe agentx.json mutation ---\n//\n// Multiple CLI commands and the dashboard admin UI all need to read → tweak →\n// write agentx.json without corrupting it on failure. This module owns the\n// atomic-write + backup + best-effort-reload pattern so every caller gets the\n// same guarantees.\n\nexport interface MutateOptions {\n /** Absolute path to the target agentx.json. Defaults to ./agentx.json. */\n configPath?: string\n /** When true, don't write a timestamped backup. Use for operations that are\n * intrinsically reversible (or when the caller already took a snapshot). */\n skipBackup?: boolean\n /** When true, don't POST /reload after writing. Handy in tests. */\n skipReload?: boolean\n}\n\nexport interface MutateResult<T = void> {\n summary: string\n payload?: T\n}\n\n/**\n * Read agentx.json, let the mutator tweak it in-place, then atomically write\n * the result back to disk. The mutator returns a short human-readable summary\n * of what changed and may optionally return a payload for the caller to relay.\n *\n * If the mutator throws, nothing is written. If writing succeeds but the file\n * doesn't round-trip as JSON, we restore from backup and rethrow.\n */\nexport function mutateAgentxConfig<T = void>(\n mutator: (cfg: any) => MutateResult<T> | string,\n opts: MutateOptions = {},\n): { summary: string; payload?: T; backupPath?: string } {\n const file = opts.configPath || resolve(process.cwd(), \"agentx.json\")\n if (!existsSync(file)) throw new Error(`agentx.json not found at ${file}`)\n\n const cfg = JSON.parse(readFileSync(file, \"utf-8\"))\n const raw = mutator(cfg)\n const result: MutateResult<T> = typeof raw === \"string\" ? { summary: raw } : raw\n\n const json = JSON.stringify(cfg, null, 2) + \"\\n\"\n const tmp = file + \".tmp\"\n writeFileSync(tmp, json, \"utf-8\")\n try {\n JSON.parse(readFileSync(tmp, \"utf-8\"))\n } catch (e: any) {\n throw new Error(`config did not round-trip cleanly: ${e.message}`)\n }\n\n let backupPath: string | undefined\n if (!opts.skipBackup) {\n backupPath = `${file}.bak.${Date.now()}`\n copyFileSync(file, backupPath)\n }\n writeFileSync(file, json, \"utf-8\")\n\n if (!opts.skipReload) triggerLocalReload().catch(() => { /* daemon may be off */ })\n\n return { summary: result.summary, payload: result.payload, backupPath }\n}\n\n/**\n * Write a fresh agentx.json from scratch. Used by the setup wizard on a truly\n * empty working directory. Fails if a file already exists (callers must pass\n * the overwrite flag explicitly — we don't want to silently clobber an\n * operator's hand-written config).\n */\nexport function writeAgentxConfig(\n cfg: unknown,\n opts: { configPath?: string; overwrite?: boolean } = {},\n): { file: string } {\n const file = opts.configPath || resolve(process.cwd(), \"agentx.json\")\n if (existsSync(file) && !opts.overwrite) {\n throw new Error(`agentx.json already exists at ${file}. Pass overwrite=true to replace it.`)\n }\n writeFileSync(file, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\")\n return { file }\n}\n\n/**\n * POST to the primary daemon's /reload endpoint so it picks up config changes\n * without a full restart. Silently no-ops if the daemon isn't running.\n */\nasync function triggerLocalReload(): Promise<void> {\n try {\n const cfg = loadDaemonConfig()\n const url = cfg.dashboard.daemonUrl?.replace(/\\/+$/, \"\") || \"http://127.0.0.1:18800\"\n await fetch(`${url}/reload`, { method: \"POST\" }).catch(() => null)\n } catch { /* config didn't load — leave it */ }\n}\n","import { createHash, randomBytes } from \"crypto\"\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\"\nimport { resolve, dirname } from \"path\"\n\n// --- Scoped API tokens ---\n//\n// Tokens let external services (other agentx instances, webhook senders, custom\n// apps) talk to this daemon with explicit scopes instead of sharing a single\n// all-powerful dashboard token.\n//\n// We only ever store the sha256 of each token + its printable prefix. The full\n// token is shown exactly once, at creation time, and the operator copies it.\n// Format: agx_live_<hex(32)> — prefix lets secret-scanners catch leaks.\n//\n// Scopes (string equality; \"agent:*\" grants any agent):\n// dashboard:read — /api/live, /api/agents, /api/task/history\n// dashboard:write — /api/admin/*, config mutation endpoints\n// agent:<id> — /api/public/agents/<id>/messages\n// agent:* — any agent\n// mesh:peer — cross-node mesh (forward-compatible — not enforced yet)\n\nexport const TOKEN_PREFIX = \"agx_live_\"\nconst DEFAULT_FILE = \".agentx/tokens.json\"\n\nexport interface TokenRecord {\n id: string // short public id (shown in lists)\n name: string\n prefix: string // full printable prefix (TOKEN_PREFIX + first-4 chars of body)\n hash: string // sha256 of the full token\n scopes: string[]\n createdAt: string\n expiresAt?: string\n revokedAt?: string\n lastUsedAt?: string\n}\n\nexport class TokenStore {\n private file: string\n\n constructor(baseDir: string = process.cwd(), fileRel: string = DEFAULT_FILE) {\n this.file = resolve(baseDir, fileRel)\n }\n\n private load(): TokenRecord[] {\n if (!existsSync(this.file)) return []\n try { return JSON.parse(readFileSync(this.file, \"utf-8\")) as TokenRecord[] } catch { return [] }\n }\n\n private save(records: TokenRecord[]): void {\n mkdirSync(dirname(this.file), { recursive: true })\n writeFileSync(this.file, JSON.stringify(records, null, 2) + \"\\n\", \"utf-8\")\n }\n\n /**\n * Mint a new token. Returns the full token string AND the record.\n * The full token is the only place the secret is ever exposed — the caller\n * must surface it to the operator immediately; after this call the store only\n * knows the hash.\n */\n create(input: {\n name: string\n scopes: string[]\n expiresInDays?: number\n }): { token: string; record: TokenRecord } {\n if (!input.name?.trim()) throw new Error(\"Token name is required.\")\n if (!Array.isArray(input.scopes) || input.scopes.length === 0) {\n throw new Error(\"At least one scope is required.\")\n }\n for (const s of input.scopes) {\n if (!isValidScope(s)) throw new Error(`Invalid scope: ${s}`)\n }\n const body = randomBytes(32).toString(\"hex\")\n const token = TOKEN_PREFIX + body\n const record: TokenRecord = {\n id: \"tok_\" + randomBytes(4).toString(\"hex\"),\n name: input.name.trim(),\n prefix: TOKEN_PREFIX + body.slice(0, 4),\n hash: hashToken(token),\n scopes: [...input.scopes],\n createdAt: new Date().toISOString(),\n expiresAt: input.expiresInDays\n ? new Date(Date.now() + input.expiresInDays * 86400 * 1000).toISOString()\n : undefined,\n }\n const records = this.load()\n records.push(record)\n this.save(records)\n return { token, record }\n }\n\n list(): TokenRecord[] {\n return this.load()\n }\n\n revoke(id: string): TokenRecord | null {\n const records = this.load()\n const rec = records.find((r) => r.id === id)\n if (!rec) return null\n rec.revokedAt = new Date().toISOString()\n this.save(records)\n return rec\n }\n\n /**\n * Look up a token string. Returns the record on success, null on unknown /\n * revoked / expired. Updates lastUsedAt opportunistically (write-on-success).\n */\n verify(token: string): TokenRecord | null {\n if (!token || !token.startsWith(TOKEN_PREFIX)) return null\n const hash = hashToken(token)\n const records = this.load()\n const rec = records.find((r) => r.hash === hash)\n if (!rec) return null\n if (rec.revokedAt) return null\n if (rec.expiresAt && Date.parse(rec.expiresAt) < Date.now()) return null\n // Throttle lastUsedAt updates to at most once per minute to avoid disk churn.\n const now = Date.now()\n const last = rec.lastUsedAt ? Date.parse(rec.lastUsedAt) : 0\n if (now - last > 60_000) {\n rec.lastUsedAt = new Date(now).toISOString()\n try { this.save(records) } catch { /* best-effort */ }\n }\n return rec\n }\n}\n\n/**\n * Check whether a record has a given required scope. \"agent:<id>\" required\n * matches either itself or \"agent:*\". \"dashboard:write\" implicitly grants\n * \"dashboard:read\" for convenience.\n */\nexport function recordHasScope(record: TokenRecord, required: string): boolean {\n if (record.scopes.includes(required)) return true\n if (required.startsWith(\"agent:\") && record.scopes.includes(\"agent:*\")) return true\n if (required === \"dashboard:read\" && record.scopes.includes(\"dashboard:write\")) return true\n return false\n}\n\nfunction isValidScope(s: string): boolean {\n return (\n s === \"dashboard:read\" ||\n s === \"dashboard:write\" ||\n s === \"agent:*\" ||\n /^agent:[a-z0-9][a-z0-9_-]*$/.test(s) ||\n s === \"mesh:peer\"\n )\n}\n\nexport function hashToken(token: string): string {\n return \"sha256:\" + createHash(\"sha256\").update(token).digest(\"hex\")\n}\n\n/**\n * Extract a bearer token from the request headers. Falls back to the\n * `?token=` query param so EventSource (which can't set headers in most\n * browsers) can still authenticate.\n */\nexport function extractToken(req: { headers: Record<string, string | string[] | undefined>; url?: string }): string | null {\n const auth = req.headers[\"authorization\"]\n const authHeader = Array.isArray(auth) ? auth[0] : auth\n if (authHeader && authHeader.toLowerCase().startsWith(\"bearer \")) {\n return authHeader.slice(7).trim()\n }\n if (req.url) {\n try {\n const u = new URL(req.url, \"http://localhost\")\n const tok = u.searchParams.get(\"token\")\n if (tok) return tok\n } catch { /* */ }\n }\n return null\n}\n"],"mappings":"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","names":["existsSync","readFileSync","writeFileSync","appendFileSync","mkdirSync","resolve","hostname","init_config","existsSync","readFileSync","writeFileSync","copyFileSync","resolve","mutateAgentxConfig","mutator","opts","file","cfg","raw","result","json","tmp","e","backupPath","triggerLocalReload","writeAgentxConfig","url","loadDaemonConfig","wizardState","baseDir","file","resolve","existsSync","cfg","readFileSync","agents","channels","c","runWizard","payload","mentions","splitMentions","configPath","envPath","workspaceDir","state","mkdirSync","claudeMd","personality","writeFileSync","telegramTokenRef","backupPath","mutateAgentxConfig","slugify","agentBlock","telegramAccountBlock","buildFreshConfig","writeAgentxConfig","ensureEnvEntries","nextSteps","s","m","i","block","tokenRef","existing","lines","sep","appendFileSync","handleWizardGet","_req","res","html","renderWizardHtml","handleWizardPost","req","raw","ok","result","e","heading","defaultNode","hostname","escapeHtml","createHash","randomBytes","existsSync","mkdirSync","readFileSync","writeFileSync","resolve","dirname","TOKEN_PREFIX","DEFAULT_FILE","TokenStore","baseDir","fileRel","records","input","isValidScope","body","token","record","hashToken","id","rec","hash","r","now","last","recordHasScope","required","s","extractToken","req","auth","authHeader","tok"]}
|
|
@@ -17,7 +17,7 @@ SKIP:
|
|
|
17
17
|
For each fact, output a JSON array:
|
|
18
18
|
[{"category":"fact|secret|preference|commitment|task-state","content":"concise fact, 1-2 sentences","keywords":["keyword1","keyword2"]}]
|
|
19
19
|
|
|
20
|
-
If nothing worth remembering, output: []`;async function h(t,s,a,n,r){if(s.length<20&&a.length<50)return;let{createProvider:i}=await import("./providers-
|
|
20
|
+
If nothing worth remembering, output: []`;async function h(t,s,a,n,r){if(s.length<20&&a.length<50)return;let{createProvider:i}=await import("./providers-VUIWO3ZK.js"),c=(await i("claude").generate([{role:"system",content:f},{role:"user",content:`${n.sender} (via ${n.channel}): ${s}
|
|
21
21
|
|
|
22
22
|
Agent: ${a}`}],{model:m,maxTokens:512})).content.trim().match(/\[[\s\S]*\]/);if(!c)return;let o=JSON.parse(c[0]);if(!Array.isArray(o)||o.length===0)return;let d=new Date().toISOString().slice(0,10);for(let e of o)r.hasSimilar(t,e.content)||r.addMemory(t,{agentId:t,category:e.category,content:e.content,keywords:e.keywords||[],source:{...n,date:d},expiresAt:e.category==="task-state"?new Date(Date.now()+7*24*60*60*1e3).toISOString():void 0});Math.random()<.02&&r.prune(t)}export{h as a};
|
|
23
|
-
//# sourceMappingURL=chunk-
|
|
23
|
+
//# sourceMappingURL=chunk-7MBTMCKY.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as Ce,b as Se,c as ge}from"./chunk-SFQUP3BP.js";import{d as X,h as p}from"./chunk-
|
|
1
|
+
import{a as Ce,b as Se,c as ge}from"./chunk-SFQUP3BP.js";import{d as X,h as p}from"./chunk-RB7265LO.js";import{a as de,c as ue,g as me}from"./chunk-KXZMYLHQ.js";import{a as F,b as ce,f as pe}from"./chunk-M7HKBG3V.js";import{a as Te,d as fe}from"./chunk-MCJUAE6V.js";import{e as v}from"./chunk-DSYKYZMT.js";import{b as he,c as ye}from"./chunk-QOYAX2FT.js";import{z as R}from"zod";var Re=R.object({provider:R.enum(["claude-code","claude","openai","ollama","custom"]).default("claude-code"),model:R.string().optional(),apiKey:R.string().optional(),skills:R.array(R.string()).default([]),output:R.object({dir:R.string().default("./generated")}).default({}),context7:R.object({enabled:R.boolean().default(!0),apiKey:R.string().optional()}).default({}),agentic:R.object({maxIterations:R.number().default(20),enabledTools:R.array(R.string()).default(["create_files","ask_user","read_file","search_files","list_directory","run_command","edit_file"]),disabledTools:R.array(R.string()).default([])}).default({})}),dt=["component","page","api","website","document","script","config","skill","media","report","test","workflow","schema","email","diagram","auto"],ut={component:"UI component (any framework)",page:"Full page or screen",api:"API endpoint, route handler, or service",website:"Multi-page website or app",document:"Markdown, documentation, or specification",script:"Standalone script or utility",config:"Configuration file or setup",skill:"Agent skill (SKILL.md format for skills.sh)",media:"Media generation prompt (image/audio/video description)",report:"Analysis report or audit",test:"Test suite, test fixtures, or test data",workflow:"CI/CD pipeline, GitHub Actions, or automation",schema:"Database schema, Zod validators, or GraphQL types",email:"Email template (React Email, MJML, HTML)",diagram:"Mermaid, D2, or PlantUML diagram",auto:"Auto-detect the best output type"};import{existsSync as Ye,promises as Je}from"fs";import B from"path";import Qe from"fast-glob";var Ae={"prisma/schema.prisma":{type:"prisma",category:"database"},"drizzle/schema.ts":{type:"drizzle",category:"database"},"schema.graphql":{type:"graphql",category:"api"},"schema.gql":{type:"graphql",category:"api"},"openapi.yaml":{type:"openapi",category:"api"},"openapi.json":{type:"openapi",category:"api"},"swagger.yaml":{type:"openapi",category:"api"},"swagger.json":{type:"openapi",category:"api"}};async function Me(o){let e={},t=await Qe.glob("**/*",{cwd:o,deep:4,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/.next/**","**/target/**","**/__pycache__/**","**/vendor/**","**/.git/**"],onlyFiles:!0});for(let[s,i]of Object.entries(Ae)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="database"){let a=await K(B.resolve(o,l));if(a){e.database={type:i.type,content:Z(a,3e3),tables:Ve(a,i.type)};break}}}for(let[s,i]of Object.entries(Ae)){let l=t.find(a=>a.endsWith(s)||a===s);if(l&&i.category==="api"){let a=await K(B.resolve(o,l));if(a){e.api={type:i.type,content:Z(a,3e3)};break}}}if(!e.api){let s=t.find(i=>i.includes("trpc")&&(i.endsWith("router.ts")||i.endsWith("router.js")));if(s){let i=await K(B.resolve(o,s));i&&(e.api={type:"trpc",content:Z(i,3e3)})}}let n=t.find(s=>s===".env.example"||s===".env.local.example"||s===".env.template");if(n){let s=await K(B.resolve(o,n));s&&(e.env=Xe(s))}let r=t.filter(s=>(s.includes("models")||s.includes("types")||s.includes("schemas"))&&(s.endsWith(".ts")||s.endsWith(".py")||s.endsWith(".rs")||s.endsWith(".go")));if(r.length){e.models=[];for(let s of r.slice(0,5)){let i=await K(B.resolve(o,s));i&&e.models.push({path:s,content:Z(i,2e3),type:B.extname(s).slice(1)})}}return e}function Ve(o,e){if(e==="prisma"){let t=o.match(/model\s+(\w+)\s*\{/g);return t?t.map(n=>n.replace(/model\s+/,"").replace(/\s*\{/,"")):[]}return[]}function Xe(o){return{variables:o.split(`
|
|
2
2
|
`).filter(n=>n.trim()&&!n.trim().startsWith("#")).map(n=>{let[r]=n.split("="),s=r.trim(),i=n.includes("=")&&n.split("=")[1]?.trim().length>0;return{key:s,required:!i}})}}async function K(o){try{return Ye(o)?await Je.readFile(o,"utf8"):null}catch{return null}}function Z(o,e){return o.length<=e?o:o.slice(0,e)+`
|
|
3
3
|
... (truncated)`}function Ie(o){let e=[];if(o.database&&e.push(`## Database Schema (${o.database.type})
|
|
4
4
|
`+(o.database.tables?.length?`Tables: ${o.database.tables.join(", ")}
|
|
@@ -38,7 +38,7 @@ ${s.join(`
|
|
|
38
38
|
... (output truncated)`:i;return s.exitCode!==0?{tool_use_id:e.id,content:`Command exited with code ${s.exitCode}:
|
|
39
39
|
${l}`,is_error:!0}:{tool_use_id:e.id,content:l||"(no output)"}}async editFile(e){let t=String(e.input.path||""),n=e.input.edits,r=re.resolve(this.cwd,t);if(!n||n.length===0)return{tool_use_id:e.id,content:"No edits provided.",is_error:!0};let s=await N.checkFileWrite(t);if(s==="deny")return{tool_use_id:e.id,content:`File write blocked by permissions: ${t}`,is_error:!0};if(s==="skip")return{tool_use_id:e.id,content:`File write skipped (plan mode): ${t}`};if(p.has("pre:file-write")){let a=await p.execute("pre:file-write",{event:"pre:file-write",file:r,cwd:this.cwd});if(a.blocked)return{tool_use_id:e.id,content:a.message||`File edit blocked by pre:file-write hook: ${t}`,is_error:!0}}let i=await J.readFile(r,"utf8"),l=[];for(let a of n)i.includes(a.old_text)?(i=i.replace(a.old_text,a.new_text),l.push(`Replaced: "${a.old_text.slice(0,40)}..."`)):l.push(`Not found: "${a.old_text.slice(0,40)}..."`);return this.options.dryRun||await J.writeFile(r,i,"utf8"),p.has("post:file-write")&&await p.execute("post:file-write",{event:"post:file-write",file:r,fileContent:i,cwd:this.cwd}),{tool_use_id:e.id,content:`Edited ${t}:
|
|
40
40
|
${l.join(`
|
|
41
|
-
`)}`}}async createFiles(e){let t=e.input,n=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${n.length} file(s) for creation.`,files:n}}async spawnAgent(e){let t=String(e.input.agent_id||""),n=String(e.input.prompt||""),r=Number(e.input.timeout_seconds)||300;if(!t||!n)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-
|
|
41
|
+
`)}`}}async createFiles(e){let t=e.input,n=t.files||[];return{tool_use_id:e.id,content:t.summary||`Queued ${n.length} file(s) for creation.`,files:n}}async spawnAgent(e){let t=String(e.input.agent_id||""),n=String(e.input.prompt||""),r=Number(e.input.timeout_seconds)||300;if(!t||!n)return{tool_use_id:e.id,content:"agent_id and prompt are required.",is_error:!0};try{let{SubAgentManager:s}=await import("./subagent-2SJHSSJS.js"),{getGlobalRegistry:i}=await import("./registry-5ND7GLFJ.js"),l=i();if(!l)return{tool_use_id:e.id,content:"Sub-agent spawning requires the daemon to be running.",is_error:!0};let h=await new s(l).spawn({targetAgentId:t,prompt:n,parentAgentId:"orchestrator",timeout:r*1e3});return h.success?{tool_use_id:e.id,content:`Sub-agent "${t}" completed (${Math.round(h.duration/1e3)}s):
|
|
42
42
|
|
|
43
43
|
${h.content}`}:{tool_use_id:e.id,content:`Sub-agent "${t}" failed: ${h.error}`,is_error:!0}}catch(s){return{tool_use_id:e.id,content:`Failed to spawn sub-agent: ${s.message}`,is_error:!0}}}async askUser(e){let t=String(e.input.question||""),n=e.input.options,r=t;return n?.length&&(r+=`
|
|
44
44
|
Options: ${n.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",followUp:r}}};async function ve(o){let{provider:e,systemPrompt:t,messages:n,providerOptions:r,cwd:s,maxIterations:i=20,enabledTools:l,interactive:a=!0,overwrite:h=!1,dryRun:c=!1,onProgress:f}=o;if(!e.generateRaw)return We(o);let x=new Q(s,{interactive:a,overwrite:h,dryRun:c}),b=de(l),$=n.filter(k=>k.role!=="system").map(k=>({role:k.role,content:k.content})),G=[],C=0,S="",O,M=0;for(;M<i;){M++,f?.({type:"iteration_start",iteration:M}),v.step(M,`Agentic loop iteration (${b.length} tools available)`);let k;try{k=await e.generateRaw($,t,b,r)}catch(y){if(y.message?.includes("not available"))return We(o);throw y}C+=k.usage.input_tokens+k.usage.output_tokens;for(let y of k.content)y.type==="text"&&(S+=y.text,f?.({type:"text_delta",text:y.text}));if(k.stop_reason==="end_turn"||k.stop_reason==="max_tokens")break;if(k.stop_reason==="tool_use"){let y=k.content.filter(_=>_.type==="tool_use");if(y.length===0)break;$.push({role:"assistant",content:k.content});let I=[];for(let _ of y){f?.({type:"tool_call",name:_.name,id:_.id,input:_.input}),v.step(M,`Tool call: ${_.name}`);let w=await x.execute({name:_.name,id:_.id,input:_.input});f?.({type:"tool_result",name:_.name,id:_.id,content:w.content.slice(0,200),is_error:w.is_error}),w.files?.length&&(G.push(...w.files),f?.({type:"files_created",files:w.files})),w.followUp&&(O=w.followUp),I.push({type:"tool_result",tool_use_id:w.tool_use_id,content:w.content,is_error:w.is_error})}if($.push({role:"user",content:I}),O)break;continue}break}return f?.({type:"complete",iterations:M,totalTokens:C}),{files:G,content:S,followUp:O,tokensUsed:C,iterations:M}}async function We(o){let{provider:e,systemPrompt:t,messages:n,providerOptions:r,maxIterations:s=5}=o,l=[{role:"system",content:t+`
|
|
@@ -47,7 +47,7 @@ Options: ${n.join(", ")}`),{tool_use_id:e.id,content:"Question sent to user.",fo
|
|
|
47
47
|
`);l.push({role:"assistant",content:b.content+(G?`
|
|
48
48
|
|
|
49
49
|
Files created:
|
|
50
|
-
${G}`:"")}),l.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}return{files:a,content:c,followUp:f,tokensUsed:h,iterations:x}}function _e(o){return typeof o.generateRaw=="function"}var se=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function ze(o,e,t){let n=Re.parse(t||{}),r=new Y(o);await r.load();let[s,i,l]=await Promise.all([Ce(o),Me(o),Te(o)]),a="";if(n.context7.enabled)try{a=await Oe(s,e,n.context7.apiKey)}catch{}let h=r.buildMemoryContext(e),c=ke(o);return v.context("memory",h?"loaded":"empty"),v.context("instructions",c?"loaded from project":"none"),{techStack:s,schemas:i,skills:l,docs:a,config:n,memoryContext:h,projectInstructions:c}}async function Uo(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:h=!0}=o,c=e;if(p.has("pre:prompt")){let u=await p.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:prompt hook");u.modified?.task&&(c=String(u.modified.task))}if(p.has("pre:generate")){let u=await p.execute("pre:generate",{event:"pre:generate",task:c,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:generate hook")}F.info("Analyzing project...");let f=await ze(t,c,{provider:s,context7:{enabled:a,apiKey:l}}),x=we(o.outputType,c);F.info(`Output type: ${x}`);let b=fe(f.skills,c,x);b.length&&F.info(`Loaded ${b.length} relevant skill(s): ${b.map(u=>u.skill.frontmatter.name).join(", ")}`);let $=He(f,x,b.map(u=>u.skill));if(!await pe(l))throw new Error("No credentials configured. Run `agentx model` to set up.");let C=me(s,l),S=i||ce()?.model,O=[...o.sessionMessages||[],{role:"user",content:c}];F.info("Generating...");let M=_e(C),k=o.maxSteps??(M?20:5),y=await ve({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...O],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:k,enabledTools:f.config.agentic.enabledTools.filter(u=>!f.config.agentic.disabledTools.includes(u)),interactive:h,overwrite:n,dryRun:r,onProgress:u=>{u.type==="iteration_start"&&u.iteration>1&&F.info(`Step ${u.iteration}/${k}...`),u.type==="tool_call"&&v.step(0,`Tool: ${u.name}`)}});if(y.tokensUsed){let u=S||"claude-sonnet-4-20250514",L=Math.round(y.tokensUsed*.3),ie=y.tokensUsed-L;X.recordStep(1,u,L,ie)}let{content:I}=y,{followUp:_,tokensUsed:w}=y;if(y.iterations>1&&F.info(`Completed in ${y.iterations} step(s)`),p.has("post:response")){let u=await p.execute("post:response",{event:"post:response",content:I,task:c,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by post:response hook");u.modified?.content&&(I=String(u.modified.content))}if(_&&h)return{files:{written:[],skipped:[],errors:[]},content:I,outputType:x,followUp:_,tokensUsed:w};let U=new Map;for(let u of y.files)U.set(u.path,u);let A=ne(x,f.techStack,o.outputDir),T=await oe(Array.from(U.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:A}),j;if(o.heal!==!1&&!r&&T.written.length>0){let{HealEngine:u}=await import("./heal-
|
|
50
|
+
${G}`:"")}),l.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}return{files:a,content:c,followUp:f,tokensUsed:h,iterations:x}}function _e(o){return typeof o.generateRaw=="function"}var se=class{queue=[];resolvers=[];closed=!1;push(e){if(this.closed)return;let t=this.resolvers.shift();if(t){t({value:e,done:!1});return}this.queue.push(e)}close(){if(!this.closed){this.closed=!0;for(let e of this.resolvers.splice(0))e({value:void 0,done:!0})}}async next(){return this.queue.length?{value:this.queue.shift(),done:!1}:this.closed?{value:void 0,done:!0}:new Promise(e=>{this.resolvers.push(e)})}async*[Symbol.asyncIterator](){for(;;){let{value:e,done:t}=await this.next();if(t)return;yield e}}};async function ze(o,e,t){let n=Re.parse(t||{}),r=new Y(o);await r.load();let[s,i,l]=await Promise.all([Ce(o),Me(o),Te(o)]),a="";if(n.context7.enabled)try{a=await Oe(s,e,n.context7.apiKey)}catch{}let h=r.buildMemoryContext(e),c=ke(o);return v.context("memory",h?"loaded":"empty"),v.context("instructions",c?"loaded from project":"none"),{techStack:s,schemas:i,skills:l,docs:a,config:n,memoryContext:h,projectInstructions:c}}async function Uo(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:h=!0}=o,c=e;if(p.has("pre:prompt")){let u=await p.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:prompt hook");u.modified?.task&&(c=String(u.modified.task))}if(p.has("pre:generate")){let u=await p.execute("pre:generate",{event:"pre:generate",task:c,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by pre:generate hook")}F.info("Analyzing project...");let f=await ze(t,c,{provider:s,context7:{enabled:a,apiKey:l}}),x=we(o.outputType,c);F.info(`Output type: ${x}`);let b=fe(f.skills,c,x);b.length&&F.info(`Loaded ${b.length} relevant skill(s): ${b.map(u=>u.skill.frontmatter.name).join(", ")}`);let $=He(f,x,b.map(u=>u.skill));if(!await pe(l))throw new Error("No credentials configured. Run `agentx model` to set up.");let C=me(s,l),S=i||ce()?.model,O=[...o.sessionMessages||[],{role:"user",content:c}];F.info("Generating...");let M=_e(C),k=o.maxSteps??(M?20:5),y=await ve({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...O],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:k,enabledTools:f.config.agentic.enabledTools.filter(u=>!f.config.agentic.disabledTools.includes(u)),interactive:h,overwrite:n,dryRun:r,onProgress:u=>{u.type==="iteration_start"&&u.iteration>1&&F.info(`Step ${u.iteration}/${k}...`),u.type==="tool_call"&&v.step(0,`Tool: ${u.name}`)}});if(y.tokensUsed){let u=S||"claude-sonnet-4-20250514",L=Math.round(y.tokensUsed*.3),ie=y.tokensUsed-L;X.recordStep(1,u,L,ie)}let{content:I}=y,{followUp:_,tokensUsed:w}=y;if(y.iterations>1&&F.info(`Completed in ${y.iterations} step(s)`),p.has("post:response")){let u=await p.execute("post:response",{event:"post:response",content:I,task:c,cwd:t});if(u.blocked)throw new Error(u.message||"Blocked by post:response hook");u.modified?.content&&(I=String(u.modified.content))}if(_&&h)return{files:{written:[],skipped:[],errors:[]},content:I,outputType:x,followUp:_,tokensUsed:w};let U=new Map;for(let u of y.files)U.set(u.path,u);let A=ne(x,f.techStack,o.outputDir),T=await oe(Array.from(U.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:A}),j;if(o.heal!==!1&&!r&&T.written.length>0){let{HealEngine:u}=await import("./heal-WKY5I4KB.js");j=await new u(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(T.written,c),!j.healed&&j.error&&await p.execute("on:error",{event:"on:error",error:new Error(j.error),task:c,cwd:t})}return p.has("post:generate")&&await p.execute("post:generate",{event:"post:generate",task:c,content:I,cwd:t}),{files:T,content:I,outputType:x,tokensUsed:w,healResult:j}}async function*Eo(o){let{task:e,cwd:t,overwrite:n=!1,dryRun:r=!1,provider:s="claude-code",model:i,apiKey:l,context7:a=!0,interactive:h=!0}=o,c=e;if(p.has("pre:prompt")){let d=await p.execute("pre:prompt",{event:"pre:prompt",task:e,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:prompt hook"};return}d.modified?.task&&(c=String(d.modified.task))}if(p.has("pre:generate")){let d=await p.execute("pre:generate",{event:"pre:generate",task:c,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by pre:generate hook"};return}}let f=await ze(t,c,{provider:s,context7:{enabled:a,apiKey:l}}),x=we(o.outputType,c);yield{type:"context_ready",outputType:x};let b=fe(f.skills,c,x),$=He(f,x,b.map(d=>d.skill));if(!await pe(l)){yield{type:"error",error:"No credentials configured. Run `agentx model` to set up."};return}let C=me(s,l),S=i||ce()?.model,O=_e(C),M=o.maxSteps??(O?20:5),k=[...o.sessionMessages||[],{role:"user",content:c}];if(O){let d=new se,P,g,q=(async()=>{try{P=await ve({provider:C,systemPrompt:$,messages:[{role:"system",content:$},...k],providerOptions:{model:S,maxTokens:8192},cwd:t,maxIterations:M,enabledTools:f.config.agentic.enabledTools.filter(m=>!f.config.agentic.disabledTools.includes(m)),interactive:h,overwrite:n,dryRun:r,onProgress:m=>{m.type==="text_delta"&&d.push({type:"text_delta",text:m.text}),m.type==="iteration_start"&&d.push({type:"iteration",iteration:m.iteration}),m.type==="tool_call"&&d.push({type:"tool_call",name:m.name,id:m.id}),m.type==="tool_result"&&d.push({type:"tool_result",name:m.name,id:m.id,is_error:m.is_error}),m.type==="files_created"&&d.push({type:"step_complete",step:0,filesCount:m.files.length})}})}catch(m){g=m}finally{d.close()}})();for await(let m of d)yield m;if(await q,g){yield{type:"error",error:g instanceof Error?g.message:String(g)};return}if(!P){yield{type:"error",error:"Agentic loop failed without a result"};return}yield{type:"done",result:{content:P.content,files:P.files,tokensUsed:P.tokensUsed,followUp:P.followUp}};let{content:E}=P;if(p.has("post:response")){let m=await p.execute("post:response",{event:"post:response",content:E,task:c,cwd:t});if(m.blocked){yield{type:"error",error:m.message||"Blocked by post:response hook"};return}m.modified?.content&&(E=String(m.modified.content))}if(P.followUp&&h){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:E,outputType:x,followUp:P.followUp,tokensUsed:P.tokensUsed}};return}let z=new Map;for(let m of P.files)z.set(m.path,m);let le=ne(x,f.techStack,o.outputDir),V=await oe(Array.from(z.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:le}),H;if(o.heal!==!1&&!r&&V.written.length>0){let{HealEngine:m}=await import("./heal-WKY5I4KB.js");H=await new m(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(V.written,c)}p.has("post:generate")&&await p.execute("post:generate",{event:"post:generate",task:c,content:E,cwd:t}),yield{type:"generate_result",result:{files:V,content:E,outputType:x,tokensUsed:P.tokensUsed,healResult:H}};return}let y=[{role:"system",content:$},...k],I=[],_=0,w="",U,A=0;A++,v.step(A,`Starting generation (model: ${S||"default"})`);let T;if(C.stream){let d="",P;for await(let g of C.stream(y,{model:S,maxTokens:8192}))yield g,g.type==="text_delta"&&(d+=g.text),g.type==="done"&&(P=g.result);T=P||{content:d,files:[],tokensUsed:0}}else{let d=await C.generate(y,{model:S,maxTokens:8192});d.content&&(yield{type:"text_delta",text:d.content}),yield{type:"done",result:d},T=d}_+=T.tokensUsed||0,w=T.content;let j=T.tokensUsed||0,u=S||"claude-sonnet-4-20250514",L=Math.round(j*.3),ie=j-L;if(X.recordStep(A,u,L,ie),v.api("generate",u,j),v.step(A,`Generated ${T.files.length} file(s), ${j} tokens`),T.files.length&&I.push(...T.files),T.followUp&&(U=T.followUp),yield{type:"step_complete",step:A,filesCount:T.files.length},!U&&(w.includes("[CONTINUE]")||w.includes("Next, I'll")||w.includes("Now let me")||w.includes("I'll also generate"))&&T.files.length>0){let P=T.files.map(g=>`Created: ${g.path}${g.description?` \u2014 ${g.description}`:""}`).join(`
|
|
51
51
|
`);for(y.push({role:"assistant",content:w+(P?`
|
|
52
52
|
|
|
53
53
|
Files created:
|
|
@@ -55,7 +55,7 @@ ${P}`:"")}),y.push({role:"user",content:"Continue generating the remaining files
|
|
|
55
55
|
`);y.push({role:"assistant",content:g.content+(H?`
|
|
56
56
|
|
|
57
57
|
Files created:
|
|
58
|
-
${H}`:"")}),y.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(p.has("post:response")){let d=await p.execute("post:response",{event:"post:response",content:w,task:c,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by post:response hook"};return}d.modified?.content&&(w=String(d.modified.content))}if(U&&h){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:w,outputType:x,followUp:U,tokensUsed:_}};return}let Pe=new Map;for(let d of I)Pe.set(d.path,d);let Ke=ne(x,f.techStack,o.outputDir),ae=await oe(Array.from(Pe.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:Ke}),W;if(o.heal!==!1&&!r&&ae.written.length>0){let{HealEngine:d}=await import("./heal-
|
|
58
|
+
${H}`:"")}),y.push({role:"user",content:"Continue generating the remaining files. Build on what you've already created. When finished, do not include [CONTINUE] in your response."})}}if(p.has("post:response")){let d=await p.execute("post:response",{event:"post:response",content:w,task:c,cwd:t});if(d.blocked){yield{type:"error",error:d.message||"Blocked by post:response hook"};return}d.modified?.content&&(w=String(d.modified.content))}if(U&&h){yield{type:"generate_result",result:{files:{written:[],skipped:[],errors:[]},content:w,outputType:x,followUp:U,tokensUsed:_}};return}let Pe=new Map;for(let d of I)Pe.set(d.path,d);let Ke=ne(x,f.techStack,o.outputDir),ae=await oe(Array.from(Pe.values()),{cwd:t,overwrite:n,dryRun:r,outputDir:Ke}),W;if(o.heal!==!1&&!r&&ae.written.length>0){let{HealEngine:d}=await import("./heal-WKY5I4KB.js");W=await new d(t,{enabled:!0,testCommand:o.healConfig?.testCommand,buildCommand:o.healConfig?.buildCommand,lintCommand:o.healConfig?.lintCommand,maxAttempts:o.healConfig?.maxAttempts??3,provider:s,model:S,apiKey:l}).detectAndHeal(ae.written,c),!W.healed&&W.error&&await p.execute("on:error",{event:"on:error",error:new Error(W.error),task:c,cwd:t})}p.has("post:generate")&&await p.execute("post:generate",{event:"post:generate",task:c,content:w,cwd:t}),yield{type:"generate_result",result:{files:ae,content:w,outputType:x,tokensUsed:_,healResult:W}}}function He(o,e,t){let n=[];n.push(`You are agentx, an agentic code generation tool. You generate high-quality, production-ready output for any tech stack.
|
|
59
59
|
|
|
60
60
|
Your primary tool is \`create_files\` \u2014 use it to output all generated code, documents, and configs as files.
|
|
61
61
|
If the request is ambiguous or you need critical information to proceed correctly, use \`ask_user\` to ask a clarifying question.
|
|
@@ -105,4 +105,4 @@ ${o.projectInstructions}`),o.memoryContext&&n.push(o.memoryContext),n.push(`# Ou
|
|
|
105
105
|
Generate output appropriate for: ${e}. Use the \`create_files\` tool to output all files.`),n.join(`
|
|
106
106
|
|
|
107
107
|
`)}export{Re as a,dt as b,ut as c,Me as d,Ie as e,Oe as f,Ue as g,we as h,Ee as i,De as j,be as k,ee as l,N as m,Y as n,qe as o,ke as p,xe as q,Q as r,ze as s,Uo as t,Eo as u};
|
|
108
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-AU37OREL.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{b as g,c as w}from"./chunk-FIOB3MEX.js";import{z as n}from"zod";var C,v,L,z,T,$,m,h=g(()=>{"use strict";C=n.enum(["mon","tue","wed","thu","fri","sat","sun"]),v=n.object({days:n.array(C).default(["mon","tue","wed","thu","fri"]),start:n.string().regex(/^\d{2}:\d{2}$/),end:n.string().regex(/^\d{2}:\d{2}$/),lunch:n.object({start:n.string().regex(/^\d{2}:\d{2}$/),end:n.string().regex(/^\d{2}:\d{2}$/)}).optional()}),L=n.object({title:n.string(),responsibilities:n.array(n.string()).default([]),sopPath:n.string().optional(),kpis:n.array(n.string()).default([])}),z=n.object({role:n.string(),reportsTo:n.string().optional(),schedule:v,utilizationTarget:n.number().min(0).max(1).default(.8)}),T=n.object({channel:n.string(),chatId:n.string(),accountId:n.string().optional()}),$=n.discriminatedUnion("type",[n.object({type:n.literal("backlog"),path:n.string().default(".agentx/backlog.md")}),n.object({type:n.literal("gitlab"),projects:n.array(n.string()).default([])}),n.object({type:n.literal("wiki"),path:n.string(),glob:n.string().default("**/*.md")})]),m=n.object({enabled:n.boolean().default(!1),timezone:n.string().default("UTC"),mainChannel:T,workSource:$,roles:n.record(n.string(),L).default({}),orgChart:n.record(n.string(),z).default({}),workTickMinutes:n.number().int().min(1).max(60).default(15),idleQueueThreshold:n.number().int().min(0).default(0)})});import{z as t}from"zod";function ee(o,r){let s=new Set(o.labels||[]);if(o.state==="closed"){let a=r.find(l=>l.kind==="closed");if(a)return a.id}for(let a of r)if(a.kind==="scoped-label"&&a.scopedLabel&&s.has(a.scopedLabel))return a.id;for(let a of r)if(a.kind==="label"&&a.mapsToLabel&&s.has(a.mapsToLabel))return a.id;let i=r.find(a=>a.kind==="open-backlog");if(i){let a=i.scopedPrefix+"::";return[...s].some(d=>d.startsWith(a))?null:i.id}return r[0]?.id??null}function te(o,r){let s=[],i=[],a=!1,l=!1;return r.kind==="scoped-label"&&r.scopedLabel?s.push(r.scopedLabel):r.kind==="label"&&r.mapsToLabel?s.push(r.mapsToLabel):r.kind==="closed"&&(a=!0),o&&(o.kind==="scoped-label"&&o.scopedLabel?i.push(o.scopedLabel):o.kind==="label"&&o.mapsToLabel?i.push(o.mapsToLabel):o.kind==="closed"&&r.kind!=="closed"&&(l=!0)),{addLabels:s.length?s:void 0,removeLabels:i.length?i:void 0,closeIssue:a||void 0,reopen:l||void 0}}var B,D,I,P,A,E,y,O,k,S=g(()=>{"use strict";B=t.object({name:t.string(),color:t.string().regex(/^#[0-9a-f]{6}$/i).default("#6366f1"),description:t.string().optional()}),D=t.object({id:t.string().regex(/^[a-z0-9_-]+$/,"column id must be lowercase slug"),title:t.string(),kind:t.enum(["open-backlog","scoped-label","closed","label"]).default("label"),mapsToLabel:t.string().optional(),scopedLabel:t.string().optional(),scopedPrefix:t.string().default("Status"),accent:t.string().optional()}),I=t.object({enabled:t.boolean().default(!0),staleDoingMinutes:t.number().int().min(1).default(45),respectLunchBreak:t.boolean().default(!0),respectSchedule:t.boolean().default(!0),action:t.enum(["badge","notify"]).default("badge")}),P=t.discriminatedUnion("type",[t.object({type:t.literal("gitlab"),projects:t.array(t.string()).min(1)})]),A=[{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"}],E=t.object({id:t.string().regex(/^[a-z0-9_-]+$/,"board id must be lowercase slug"),name:t.string(),source:P,primaryToolLabel:t.string().optional(),labels:t.array(B).default([]),columns:t.array(D).min(1).default(A),timeRangeDays:t.number().int().min(1).max(365).default(30),closedWindowDays:t.number().int().min(1).max(365).default(30),reconciliation:I.default({})}),y=t.array(E).default([]),O=t.object({name:t.string(),url:t.string(),dashboardUrl:t.string().optional(),token:t.string().optional(),dashboardToken:t.string().optional()}),k=t.object({enabled:t.boolean().default(!1),port:t.number().int().default(4202),bind:t.string().default("127.0.0.1"),token:t.string().optional(),daemonUrl:t.string().default("http://localhost:18800"),daemons:t.array(O).default([]),draftAgent:t.string().optional()}).default({})});var V={};w(V,{daemonConfigSchema:()=>j,expandEnvVars:()=>p,loadDaemonConfig:()=>H,validateWorkspaces:()=>Q});import{z as e}from"zod";import{readFileSync as x,existsSync as u}from"fs";import{resolve as f}from"path";function R(o){let r=f(o,".env");if(!u(r))return;let s=x(r,"utf-8");for(let i of s.split(`
|
|
2
|
+
`)){let a=i.trim();if(!a||a.startsWith("#"))continue;let l=a.indexOf("=");if(l===-1)continue;let d=a.slice(0,l).trim(),c=a.slice(l+1).trim();process.env[d]||(process.env[d]=c)}}function p(o){if(typeof o=="string")return o.replace(/\$\{(\w+)\}/g,(r,s)=>process.env[s]||"");if(Array.isArray(o))return o.map(p);if(o!==null&&typeof o=="object"){let r={};for(let[s,i]of Object.entries(o))r[s]=p(i);return r}return o}function H(o){let r=o?[o]:[f(process.cwd(),"agentx.json"),f(process.cwd(),".agentx/config.json")];R(process.cwd());let s,i;for(let c of r)if(u(c)){s=x(c,"utf-8"),i=c;break}if(!s||!i)throw new Error(`No config found. Create agentx.json or .agentx/config.json
|
|
3
|
+
Searched: ${r.join(", ")}`);let a;try{a=JSON.parse(s)}catch(c){throw new Error(`Invalid JSON in ${i}: ${c.message}`)}let l=p(a),d=j.safeParse(l);if(!d.success){let c=d.error.issues.map(b=>` ${b.path.join(".")}: ${b.message}`).join(`
|
|
4
|
+
`);throw new Error(`Config validation failed (${i}):
|
|
5
|
+
${c}`)}return d.data}function Q(o){let r=[];for(let[s,i]of Object.entries(o.agents)){if(!u(i.workspace)){r.push(`Agent "${s}": workspace not found at ${i.workspace}`);continue}if(i.tier==="claude-code"){let d=f(i.workspace,".claude");u(d)||r.push(`Agent "${s}": no .claude/ directory in workspace ${i.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let a=i.provider||"claude",l=o.providers[a];i.tier!=="claude-code"&&(!l||!l.apiKey)&&r.push(`Agent "${s}": provider "${a}" has no API key configured. Set providers.${a}.apiKey in config or use tier "claude-code" for subscription.`)}for(let[s,i]of Object.entries(o.crons))o.agents[i.agent]||r.push(`Cron "${s}": references unknown agent "${i.agent}"`);if(o.channels.telegram.enabled)for(let[s,i]of Object.entries(o.channels.telegram.accounts))o.agents[i.agentBinding]||r.push(`Telegram account "${s}": references unknown agent "${i.agentBinding}"`);return r}var M,U,J,N,W,_,q,F,K,j,G=g(()=>{h();S();M=e.object({apiKey:e.string().optional(),defaultModel:e.string().optional(),baseUrl:e.string().optional()}),U=e.object({name:e.string(),workspace:e.string(),tier:e.enum(["claude-code","sdk","orchestrator"]).default("claude-code"),provider:e.string().optional(),model:e.string().optional(),systemPrompt:e.string().optional(),mentions:e.array(e.string()).default([]),maxConcurrent:e.number().default(1),maxExecutionMinutes:e.number().int().min(1).max(240).default(20),permissionMode:e.string().default("default"),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")}),J=e.object({token:e.string(),agentBinding:e.string()}),N=e.object({telegram:e.object({enabled:e.boolean().default(!1),accounts:e.record(e.string(),J).default({}),policy:e.object({dm:e.enum(["pair","block"]).default("pair"),group:e.enum(["mention-required","all"]).default("mention-required")}).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([])}).default({}),discord:e.object({enabled:e.boolean().default(!1),token:e.string().optional(),agentBinding:e.string().optional()}).default({}),slack:e.object({enabled:e.boolean().default(!1),botToken:e.string().optional(),appToken:e.string().optional(),agentBinding:e.string().optional()}).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(),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({})}),W=e.object({enabled:e.boolean().default(!0),schedule:e.string(),timezone:e.string().default("UTC"),agent:e.string(),prompt:e.string(),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(o=>Array.isArray(o)?o:[o]),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),_=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()}),q=e.object({url:e.string(),name:e.string(),token:e.string().optional()}),F=e.object({enabled:e.boolean().default(!1),peers:e.array(q).default([]),discovery:e.enum(["static","mdns"]).default("static"),healthCheck:e.object({interval:e.number().default(60),timeout:e.number().default(10)}).default({})}),K=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({}),j=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(),M).default({}),agents:e.record(e.string(),U).default({}),channels:N.default({}),crons:e.record(e.string(),W).default({}),services:e.record(e.string(),_).default({}),notifications:K,mesh:F.default({}),business:m.optional(),boards:y,dashboard:k,webhooks:e.array(e.object({id:e.string().regex(/^[a-z0-9][a-z0-9_-]*$/,"webhook id must be lowercase slug"),source:e.enum(["gitlab","github","sentry","stripe","discord","slack","custom"]),agentId:e.string(),secretEnv:e.string().optional(),description:e.string().optional(),enabled:e.boolean().default(!0)})).default([]),session:e.object({staleMinutes:e.number().int().min(1).max(1440).default(120)}).default({})})});export{ee as a,te as b,S as c,j as d,p as e,H as f,Q as g,V as h,G as i};
|
|
6
|
+
//# sourceMappingURL=chunk-B4Q4X7D5.js.map
|