clustr-ai 0.1.16 → 0.1.17
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/dist/server/index.js +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -170,7 +170,7 @@ Now execute the following task:
|
|
|
170
170
|
agent_id TEXT,
|
|
171
171
|
created_at TEXT DEFAULT (datetime('now'))
|
|
172
172
|
)
|
|
173
|
-
`).run();try{sr.prepare("ALTER TABLE file_changes ADD COLUMN agent_id TEXT").run()}catch{}var Sq=sr.prepare("INSERT INTO file_changes (file_path, change_type, diff_text, agent_id) VALUES (?, ?, ?, ?)"),kq=sr.prepare("SELECT id FROM agents WHERE agent_cwd IS NOT NULL AND status = 'running' ORDER BY length(agent_cwd) DESC"),Tq=sr.prepare("SELECT * FROM file_changes ORDER BY created_at DESC LIMIT ?"),Cq=sr.prepare("DELETE FROM file_changes");async function Aq(t){for(let e of["master","main"])try{return await ME("git",["rev-parse","--verify",e],{cwd:t}),e}catch{}return"master"}async function Oq(t,e,r){try{let{stdout:n}=await ME("git",["show",`${r}:${e}`],{cwd:t,maxBuffer:5242880});return n}catch{return""}}function zE(t){UE=t}function HE(t){Rq(),Tc=null,Aq(t).then(e=>{Tc=e}).catch(()=>{Tc="master"}),Hr=bc.watch(t,{ignored:e=>{let r=cf.relative(t,e),n=r.split(cf.sep);return n.includes(".git")||n.includes("node_modules")||n.includes("dist")||n.includes(".next")||n.includes("__pycache__")||n.includes("logs")||n.includes("log")||n.includes(".cache")||n.includes(".tmp")||n.includes("target")||n.includes("build")||n.includes("coverage")||r.endsWith(".pyc")||r.endsWith(".log")||r==="package-lock.json"||r==="yarn.lock"||r==="pnpm-lock.yaml"},persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:300,pollInterval:100}}),Hr.on("add",e=>of(e,"add",t)),Hr.on("change",e=>of(e,"change",t)),Hr.on("unlink",e=>of(e,"unlink",t))}function Rq(){Hr&&(Hr.close(),Hr=null)}async function of(t,e,r){let n=cf.relative(r,t),i=Tc||"master",s=null;try{let p=await Oq(r,n,i);if(e==="unlink")p&&(s=kc(n,p,"",i,"deleted"));else{let u=wq.readFileSync(t,"utf-8");p!==u&&(s=kc(n,p,u,i,"working"))}}catch{return}if(!s)return;let a=null,o=kq.all();for(let p of o){let u=sr.prepare("SELECT agent_cwd FROM agents WHERE id = ?").get(p.id);if(u?.agent_cwd&&t.startsWith(u.agent_cwd)){a=p.id;break}}let l={id:Sq.run(n,e,s,a).lastInsertRowid,file_path:n,change_type:e,diff_text:s,agent_id:a,created_at:new Date().toISOString()};UE?.emit("file:changed",l)}function WE(t=50){return Tq.all(t)}function $E(){Cq.run()}import{execFile as Pq}from"child_process";import{promisify as Iq}from"util";var Nq=Iq(Pq);async function Cc(t,e){return Nq("gh",t,{cwd:e,maxBuffer:10*1024*1024})}async function GE(t){try{return await Cc(["auth","status"],t),!0}catch{return!1}}async function VE(t){try{let{stdout:e}=await Cc(["repo","view","--json","nameWithOwner,url"],t);return JSON.parse(e)}catch{return null}}var YE="number,title,state,author,headRefName,baseRefName,createdAt,url,body,isDraft,reviewDecision,statusCheckRollup";async function lf(t,e="all"){try{let r=["pr","list","--state",e,"--json",YE,"--limit","50"],{stdout:n}=await Cc(r,t);return JSON.parse(n)}catch{return[]}}var Lq=YE+",reviews,comments";async function KE(t,e){try{let{stdout:r}=await Cc(["pr","view",String(e),"--json",Lq],t);return JSON.parse(r)}catch{return null}}import{execFile as aF}from"child_process";import{promisify as oF}from"util";import x8 from"os";import Bq from"crypto";import Ps from"fs";import XE from"path";import qq from"os";var uf=XE.join(qq.homedir(),".clustr"),pf=XE.join(uf,"config.json"),Ac=null;function JE(){if(Ac)return Ac;Ps.existsSync(uf)||Ps.mkdirSync(uf,{recursive:!0});let t;if(Ps.existsSync(pf))try{t=JSON.parse(Ps.readFileSync(pf,"utf8"))}catch{t={authToken:""}}else t={authToken:""};return t.authToken||(t.authToken=Bq.randomBytes(32).toString("hex"),Ps.writeFileSync(pf,JSON.stringify(t,null,2),{mode:384})),Ac=t,Ac}var o8=Ys(a8(),1);import Zj from"os";function Qj(){let t=Zj.networkInterfaces();for(let e of Object.keys(t))for(let r of t[e]||[])if(r.family==="IPv4"&&!r.internal)return r.address;return"127.0.0.1"}async function c8(t,e,r){let i=`http://${Qj()}:${t}`,s=JSON.stringify({url:r||i,localUrl:i,token:e}),a=await o8.default.toString(s,{type:"svg",color:{dark:"#ffffff",light:"#00000000"},margin:1});return{localUrl:i,remoteUrl:r,token:e,qrSvg:a}}import{spawn as eF}from"child_process";import{execFile as tF}from"child_process";import{promisify as rF}from"util";var nF=rF(tF),mr=null,Ws=null,At=null;function l8(){return Ws}async function iF(){try{return await nF("which",["cloudflared"]),!0}catch{return!1}}async function p8(t){return await iF()?new Promise(e=>{At=e,mr=eF("cloudflared",["tunnel","--url",`http://localhost:${t}`],{stdio:["ignore","pipe","pipe"]});let r=n=>{let s=n.toString().match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);s&&At&&(Ws=s[0],At(Ws),At=null)};mr.stdout?.on("data",r),mr.stderr?.on("data",r),mr.on("exit",()=>{Ws=null,mr=null,At&&(At(null),At=null)}),setTimeout(()=>{At&&(At(null),At=null)},15e3)}):null}function rh(){mr&&(mr.kill(),mr=null,Ws=null)}var nh=oF(aF),Gs=parseInt(process.env.CLUSTR_PORT||"3100",10),$c=JE();process.env.CLUSTR_TUNNEL==="1"&&p8(Gs).then(t=>{console.log(t?`Clustr tunnel active: ${t}`:"Clustr tunnel: cloudflared not found or timed out")});process.on("SIGINT",()=>{rh(),process.exit(0)});process.on("SIGTERM",()=>{rh(),process.exit(0)});var P=(0,Wc.default)();P.use((0,v8.default)());P.use(Wc.default.json({limit:"20mb"}));var u8=process.env.CLUSTR_SERVE_CLIENT,Hc=u8==="true"?zt.resolve(zt.dirname(sh(import.meta.url)),"..","client"):u8||"";Hc&&P.use(Wc.default.static(Hc));var d8=zt.resolve(zt.dirname(sh(import.meta.url)),"connect.html"),f8=zt.resolve(zt.dirname(sh(import.meta.url)),"..","server","connect.html"),h8=$s.existsSync(d8)?d8:$s.existsSync(f8)?f8:null;P.get("/connect",(t,e)=>{h8?e.sendFile(h8):e.status(404).send("Connect page not found")});P.get("/api/pair",async(t,e)=>{if(!(t.socket.localAddress==="127.0.0.1"||t.socket.localAddress==="::1"||t.socket.localAddress==="::ffff:127.0.0.1")){e.status(403).json({error:"Pairing info only accessible from localhost"});return}let n=await c8(Gs,$c.authToken,l8());e.json(n)});P.use("/api",(t,e,r)=>{if(t.path==="/pair"||t.socket.localAddress==="127.0.0.1"||t.socket.localAddress==="::1"||t.socket.localAddress==="::ffff:127.0.0.1")return r();if((t.query.token||t.headers.authorization?.replace("Bearer ",""))!==$c.authToken){e.status(401).json({error:"Unauthorized"});return}r()});var y8=sF(P),xe=new T_(y8,{cors:{origin:"*"}});xe.use((t,e)=>{let r=t.handshake.address;if(r==="127.0.0.1"||r==="::1"||r==="::ffff:127.0.0.1")return e();if((t.handshake.auth?.token||t.handshake.query?.token)!==$c.authToken)return e(new Error("Unauthorized"));e()});I_();PE(xe);LE(xe);fE(xe);zE(xe);kE(xe,()=>{xe.emit("agents:updated",St())});P.post("/api/agents",(t,e)=>{try{let{id:r,name:n,service:i="claude",task:s}=t.body;if(r)He(r,{status:"running"}),xe.emit("agents:updated",St()),e.json({id:r,status:"registered"});else{let a=F_(n,i,s,null);xe.emit("agents:updated",St()),e.json({id:a,status:"registered"})}}catch(r){e.status(400).json({error:r.message})}});P.get("/api/agents",(t,e)=>{e.json(St())});P.post("/api/agents/:id/ping",(t,e)=>{M_(t.params.id),e.json({status:"ok"})});P.delete("/api/agents/:id",(t,e)=>{U_(t.params.id),ef(t.params.id),xe.emit("agents:updated",St()),e.json({status:"deregistered"})});P.delete("/api/agents/:id/remove",(t,e)=>{ef(t.params.id),R_(t.params.id),xe.emit("agents:updated",St()),e.json({status:"removed"})});P.post("/api/messages",(t,e)=>{try{let{from:r,to:n,content:i}=t.body;if(n==="all"||n==="*"){let s=NE(r,i);e.json(s)}else{let s=n;if(!Mt(n)){let c=P_(n);c&&(s=c.id)}let o=tf(r,s,i);e.json(o)}}catch(r){e.status(400).json({error:r.message})}});P.get("/api/messages/:agentId",(t,e)=>{e.json(IE(t.params.agentId))});P.get("/api/messages",(t,e)=>{e.json(pc())});P.delete("/api/messages",(t,e)=>{B_(),xe.emit("messages:all",[]),e.json({status:"cleared"})});P.get("/api/context/:key?",(t,e)=>{let r=t.params.key;e.json(BE(r))});P.put("/api/context",(t,e)=>{try{let{key:r,value:n,updatedBy:i}=t.body;qE(r,n,i),e.json({status:"ok"})}catch(r){e.status(400).json({error:r.message})}});P.delete("/api/context/:key",(t,e)=>{try{DE(t.params.key),e.json({status:"removed"})}catch(r){e.status(400).json({error:r.message})}});P.get("/api/crewmd",(t,e)=>{e.json({content:As()})});P.put("/api/crewmd",(t,e)=>{try{let{content:r}=t.body;gE(r),e.json({status:"ok"})}catch(r){e.status(400).json({error:r.message})}});P.get("/api/agents/:id/cost",(t,e)=>{let r=Mt(t.params.id);if(!r){e.status(404).json({error:"Agent not found"});return}e.json({total_tokens:r.total_tokens||0,total_cost:r.total_cost||0})});P.get("/api/agents/:id/diff",async(t,e)=>{let r=Mt(t.params.id);if(!r||!r.checkpoint_hash||!r.agent_cwd){e.json({diff:""});return}let n=await H_(r.agent_cwd,r.checkpoint_hash);e.json({diff:n})});P.post("/api/agents/:id/rollback",async(t,e)=>{let r=Mt(t.params.id);if(!r||!r.checkpoint_hash||!r.agent_cwd){e.status(400).json({error:"No checkpoint available for this agent"});return}let n=await $_(r.agent_cwd,r.checkpoint_hash);n.success?e.json({status:"rolled_back",message:n.message}):e.status(400).json({error:n.message})});P.get("/api/file-changes",(t,e)=>{let r=parseInt(t.query.limit)||50;e.json(WE(r))});P.delete("/api/file-changes",(t,e)=>{$E(),xe.emit("file:changes:cleared"),e.json({status:"cleared"})});function Vs(){return St().find(r=>r.agent_cwd)?.agent_cwd||process.cwd()}P.get("/api/github/status",async(t,e)=>{let r=Vs(),n=await GE(r),i=n?await VE(r):null;e.json({available:n,repo:i})});P.get("/api/github/prs",async(t,e)=>{let r=Vs(),n=t.query.state||"all",i=await lf(r,n);e.json(i)});P.get("/api/github/prs/:number",async(t,e)=>{let r=Vs(),n=parseInt(t.params.number,10);if(isNaN(n)){e.status(400).json({error:"Invalid PR number"});return}let i=await KE(r,n);i?e.json(i):e.status(404).json({error:"PR not found"})});P.get("/api/git/branches",async(t,e)=>{let r=Vs(),n=await jd(r);e.json(n)});P.post("/api/pick-folder",async(t,e)=>{try{let r=x8.platform(),n="";if(r==="darwin"){let{stdout:i}=await nh("osascript",["-e",'set chosenFolder to choose folder with prompt "Select project directory"',"-e","return POSIX path of chosenFolder"]);n=i.trim().replace(/\/$/,"")}else if(r==="win32"){let{stdout:i}=await nh("powershell",["-NoProfile","-Command","Add-Type -AssemblyName System.Windows.Forms; $d = New-Object System.Windows.Forms.FolderBrowserDialog; $d.Description = 'Select project directory'; if ($d.ShowDialog() -eq 'OK') { $d.SelectedPath } else { '' }"]);n=i.trim()}else{let{stdout:i}=await nh("zenity",["--file-selection","--directory","--title=Select project directory"]);n=i.trim()}n?e.json({path:n}):e.json({path:null,cancelled:!0})}catch{e.json({path:null,cancelled:!0})}});var ih=zt.join(x8.homedir(),".clustr","uploads");P.post("/api/upload-image",(t,e)=>{try{let{data:r,mimeType:n}=t.body;if(!r||!n){e.status(400).json({error:"Missing data or mimeType"});return}$s.existsSync(ih)||$s.mkdirSync(ih,{recursive:!0});let i=(n.split("/")[1]||"png").replace(/[^a-zA-Z0-9]/g,"")||"png",s=`paste-${Date.now()}.${i}`,a=zt.join(ih,s),o=Buffer.from(r,"base64");$s.writeFileSync(a,o),e.json({path:a,filename:s})}catch(r){e.status(500).json({error:r.message})}});P.post("/api/spawn",(t,e)=>{try{let{name:r,task:n,cwd:i,service:s}=t.body,a=i||process.cwd();HE(a);let o=TE(r,n,{cwd:i,service:s});xe.emit("agents:updated",St()),e.json({id:o,status:"spawning"})}catch(r){e.status(400).json({error:r.message})}});P.post("/api/agents/:id/message",(t,e)=>{let{content:r}=t.body;Qd(t.params.id,r+"\r")?e.json({status:"sent"}):e.status(404).json({error:"Agent not running"})});P.get("/api/agents/:id/scrollback",(t,e)=>{e.json({scrollback:OE(t.params.id)})});xe.on("connection",t=>{t.emit("agents:updated",St()),t.emit("messages:all",pc()),t.emit("crewmd:updated",As()),t.on("agent:input",(e,r)=>{Qd(e,r)}),t.on("agent:resize",(e,r,n)=>{AE(e,r,n)})});Hc&&P.get("*",(t,e)=>{e.sendFile(zt.join(Hc,"index.html"))});var m8="",g8="";setInterval(async()=>{if(xe.engine.clientsCount===0)return;let t=Vs();try{let e=await lf(t,"all"),r=JSON.stringify(e.map(n=>`${n.number}:${n.state}:${n.reviewDecision}`));r!==m8&&(m8=r,xe.emit("github:prs:updated",e))}catch{}try{let e=await jd(t),r=JSON.stringify(e.branches.map(n=>n.name));r!==g8&&(g8=r,xe.emit("git:branches:updated",e))}catch{}},3e4);y8.listen(Gs,"0.0.0.0",()=>{console.log(`Clustr server running on http://localhost:${Gs}`),console.log(`Connect from phone: http://localhost:${Gs}/connect`),console.log(`Auth token: ${$c.authToken}`)});
|
|
173
|
+
`).run();try{sr.prepare("ALTER TABLE file_changes ADD COLUMN agent_id TEXT").run()}catch{}var Sq=sr.prepare("INSERT INTO file_changes (file_path, change_type, diff_text, agent_id) VALUES (?, ?, ?, ?)"),kq=sr.prepare("SELECT id FROM agents WHERE agent_cwd IS NOT NULL AND status = 'running' ORDER BY length(agent_cwd) DESC"),Tq=sr.prepare("SELECT * FROM file_changes ORDER BY created_at DESC LIMIT ?"),Cq=sr.prepare("DELETE FROM file_changes");async function Aq(t){for(let e of["master","main"])try{return await ME("git",["rev-parse","--verify",e],{cwd:t}),e}catch{}return"master"}async function Oq(t,e,r){try{let{stdout:n}=await ME("git",["show",`${r}:${e}`],{cwd:t,maxBuffer:5242880});return n}catch{return""}}function zE(t){UE=t}function HE(t){Rq(),Tc=null,Aq(t).then(e=>{Tc=e}).catch(()=>{Tc="master"}),Hr=bc.watch(t,{ignored:e=>{let r=cf.relative(t,e),n=r.split(cf.sep);return n.includes(".git")||n.includes("node_modules")||n.includes("dist")||n.includes(".next")||n.includes("__pycache__")||n.includes("logs")||n.includes("log")||n.includes(".cache")||n.includes(".tmp")||n.includes("target")||n.includes("build")||n.includes("coverage")||r.endsWith(".pyc")||r.endsWith(".log")||r==="package-lock.json"||r==="yarn.lock"||r==="pnpm-lock.yaml"},persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:300,pollInterval:100}}),Hr.on("add",e=>of(e,"add",t)),Hr.on("change",e=>of(e,"change",t)),Hr.on("unlink",e=>of(e,"unlink",t))}function Rq(){Hr&&(Hr.close(),Hr=null)}async function of(t,e,r){let n=cf.relative(r,t),i=Tc||"master",s=null;try{let p=await Oq(r,n,i);if(e==="unlink")p&&(s=kc(n,p,"",i,"deleted"));else{let u=wq.readFileSync(t,"utf-8");p!==u&&(s=kc(n,p,u,i,"working"))}}catch{return}if(!s)return;let a=null,o=kq.all();for(let p of o){let u=sr.prepare("SELECT agent_cwd FROM agents WHERE id = ?").get(p.id);if(u?.agent_cwd&&t.startsWith(u.agent_cwd)){a=p.id;break}}let l={id:Sq.run(n,e,s,a).lastInsertRowid,file_path:n,change_type:e,diff_text:s,agent_id:a,created_at:new Date().toISOString()};UE?.emit("file:changed",l)}function WE(t=50){return Tq.all(t)}function $E(){Cq.run()}import{execFile as Pq}from"child_process";import{promisify as Iq}from"util";var Nq=Iq(Pq);async function Cc(t,e){return Nq("gh",t,{cwd:e,maxBuffer:10*1024*1024})}async function GE(t){try{return await Cc(["auth","status"],t),!0}catch{return!1}}async function VE(t){try{let{stdout:e}=await Cc(["repo","view","--json","nameWithOwner,url"],t);return JSON.parse(e)}catch{return null}}var YE="number,title,state,author,headRefName,baseRefName,createdAt,url,body,isDraft,reviewDecision,statusCheckRollup";async function lf(t,e="all"){try{let r=["pr","list","--state",e,"--json",YE,"--limit","50"],{stdout:n}=await Cc(r,t);return JSON.parse(n)}catch{return[]}}var Lq=YE+",reviews,comments";async function KE(t,e){try{let{stdout:r}=await Cc(["pr","view",String(e),"--json",Lq],t);return JSON.parse(r)}catch{return null}}import{execFile as aF}from"child_process";import{promisify as oF}from"util";import x8 from"os";import Bq from"crypto";import Ps from"fs";import XE from"path";import qq from"os";var uf=XE.join(qq.homedir(),".clustr"),pf=XE.join(uf,"config.json"),Ac=null;function JE(){if(Ac)return Ac;Ps.existsSync(uf)||Ps.mkdirSync(uf,{recursive:!0});let t;if(Ps.existsSync(pf))try{t=JSON.parse(Ps.readFileSync(pf,"utf8"))}catch{t={authToken:""}}else t={authToken:""};return t.authToken||(t.authToken=Bq.randomBytes(32).toString("hex"),Ps.writeFileSync(pf,JSON.stringify(t,null,2),{mode:384})),Ac=t,Ac}var o8=Ys(a8(),1);import Zj from"os";function Qj(){let t=Zj.networkInterfaces();for(let e of Object.keys(t))for(let r of t[e]||[])if(r.family==="IPv4"&&!r.internal)return r.address;return"127.0.0.1"}async function c8(t,e,r){let i=`http://${Qj()}:${t}`,a=`${r||i}?token=${e}`,o=await o8.default.toString(a,{type:"svg",color:{dark:"#ffffff",light:"#00000000"},margin:1});return{localUrl:i,remoteUrl:r,token:e,qrSvg:o}}import{spawn as eF}from"child_process";import{execFile as tF}from"child_process";import{promisify as rF}from"util";var nF=rF(tF),mr=null,Ws=null,At=null;function l8(){return Ws}async function iF(){try{return await nF("which",["cloudflared"]),!0}catch{return!1}}async function p8(t){return await iF()?new Promise(e=>{At=e,mr=eF("cloudflared",["tunnel","--url",`http://localhost:${t}`],{stdio:["ignore","pipe","pipe"]});let r=n=>{let s=n.toString().match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);s&&At&&(Ws=s[0],At(Ws),At=null)};mr.stdout?.on("data",r),mr.stderr?.on("data",r),mr.on("exit",()=>{Ws=null,mr=null,At&&(At(null),At=null)}),setTimeout(()=>{At&&(At(null),At=null)},15e3)}):null}function rh(){mr&&(mr.kill(),mr=null,Ws=null)}var nh=oF(aF),Gs=parseInt(process.env.CLUSTR_PORT||"3100",10),$c=JE();process.env.CLUSTR_TUNNEL==="1"&&p8(Gs).then(t=>{console.log(t?`Clustr tunnel active: ${t}`:"Clustr tunnel: cloudflared not found or timed out")});process.on("SIGINT",()=>{rh(),process.exit(0)});process.on("SIGTERM",()=>{rh(),process.exit(0)});var P=(0,Wc.default)();P.use((0,v8.default)());P.use(Wc.default.json({limit:"20mb"}));var u8=process.env.CLUSTR_SERVE_CLIENT,Hc=u8==="true"?zt.resolve(zt.dirname(sh(import.meta.url)),"..","client"):u8||"";Hc&&P.use(Wc.default.static(Hc));var d8=zt.resolve(zt.dirname(sh(import.meta.url)),"connect.html"),f8=zt.resolve(zt.dirname(sh(import.meta.url)),"..","server","connect.html"),h8=$s.existsSync(d8)?d8:$s.existsSync(f8)?f8:null;P.get("/connect",(t,e)=>{h8?e.sendFile(h8):e.status(404).send("Connect page not found")});P.get("/api/pair",async(t,e)=>{if(!(t.socket.localAddress==="127.0.0.1"||t.socket.localAddress==="::1"||t.socket.localAddress==="::ffff:127.0.0.1")){e.status(403).json({error:"Pairing info only accessible from localhost"});return}let n=await c8(Gs,$c.authToken,l8());e.json(n)});P.use("/api",(t,e,r)=>{if(t.path==="/pair"||t.socket.localAddress==="127.0.0.1"||t.socket.localAddress==="::1"||t.socket.localAddress==="::ffff:127.0.0.1")return r();if((t.query.token||t.headers.authorization?.replace("Bearer ",""))!==$c.authToken){e.status(401).json({error:"Unauthorized"});return}r()});var y8=sF(P),xe=new T_(y8,{cors:{origin:"*"}});xe.use((t,e)=>{let r=t.handshake.address;if(r==="127.0.0.1"||r==="::1"||r==="::ffff:127.0.0.1")return e();if((t.handshake.auth?.token||t.handshake.query?.token)!==$c.authToken)return e(new Error("Unauthorized"));e()});I_();PE(xe);LE(xe);fE(xe);zE(xe);kE(xe,()=>{xe.emit("agents:updated",St())});P.post("/api/agents",(t,e)=>{try{let{id:r,name:n,service:i="claude",task:s}=t.body;if(r)He(r,{status:"running"}),xe.emit("agents:updated",St()),e.json({id:r,status:"registered"});else{let a=F_(n,i,s,null);xe.emit("agents:updated",St()),e.json({id:a,status:"registered"})}}catch(r){e.status(400).json({error:r.message})}});P.get("/api/agents",(t,e)=>{e.json(St())});P.post("/api/agents/:id/ping",(t,e)=>{M_(t.params.id),e.json({status:"ok"})});P.delete("/api/agents/:id",(t,e)=>{U_(t.params.id),ef(t.params.id),xe.emit("agents:updated",St()),e.json({status:"deregistered"})});P.delete("/api/agents/:id/remove",(t,e)=>{ef(t.params.id),R_(t.params.id),xe.emit("agents:updated",St()),e.json({status:"removed"})});P.post("/api/messages",(t,e)=>{try{let{from:r,to:n,content:i}=t.body;if(n==="all"||n==="*"){let s=NE(r,i);e.json(s)}else{let s=n;if(!Mt(n)){let c=P_(n);c&&(s=c.id)}let o=tf(r,s,i);e.json(o)}}catch(r){e.status(400).json({error:r.message})}});P.get("/api/messages/:agentId",(t,e)=>{e.json(IE(t.params.agentId))});P.get("/api/messages",(t,e)=>{e.json(pc())});P.delete("/api/messages",(t,e)=>{B_(),xe.emit("messages:all",[]),e.json({status:"cleared"})});P.get("/api/context/:key?",(t,e)=>{let r=t.params.key;e.json(BE(r))});P.put("/api/context",(t,e)=>{try{let{key:r,value:n,updatedBy:i}=t.body;qE(r,n,i),e.json({status:"ok"})}catch(r){e.status(400).json({error:r.message})}});P.delete("/api/context/:key",(t,e)=>{try{DE(t.params.key),e.json({status:"removed"})}catch(r){e.status(400).json({error:r.message})}});P.get("/api/crewmd",(t,e)=>{e.json({content:As()})});P.put("/api/crewmd",(t,e)=>{try{let{content:r}=t.body;gE(r),e.json({status:"ok"})}catch(r){e.status(400).json({error:r.message})}});P.get("/api/agents/:id/cost",(t,e)=>{let r=Mt(t.params.id);if(!r){e.status(404).json({error:"Agent not found"});return}e.json({total_tokens:r.total_tokens||0,total_cost:r.total_cost||0})});P.get("/api/agents/:id/diff",async(t,e)=>{let r=Mt(t.params.id);if(!r||!r.checkpoint_hash||!r.agent_cwd){e.json({diff:""});return}let n=await H_(r.agent_cwd,r.checkpoint_hash);e.json({diff:n})});P.post("/api/agents/:id/rollback",async(t,e)=>{let r=Mt(t.params.id);if(!r||!r.checkpoint_hash||!r.agent_cwd){e.status(400).json({error:"No checkpoint available for this agent"});return}let n=await $_(r.agent_cwd,r.checkpoint_hash);n.success?e.json({status:"rolled_back",message:n.message}):e.status(400).json({error:n.message})});P.get("/api/file-changes",(t,e)=>{let r=parseInt(t.query.limit)||50;e.json(WE(r))});P.delete("/api/file-changes",(t,e)=>{$E(),xe.emit("file:changes:cleared"),e.json({status:"cleared"})});function Vs(){return St().find(r=>r.agent_cwd)?.agent_cwd||process.cwd()}P.get("/api/github/status",async(t,e)=>{let r=Vs(),n=await GE(r),i=n?await VE(r):null;e.json({available:n,repo:i})});P.get("/api/github/prs",async(t,e)=>{let r=Vs(),n=t.query.state||"all",i=await lf(r,n);e.json(i)});P.get("/api/github/prs/:number",async(t,e)=>{let r=Vs(),n=parseInt(t.params.number,10);if(isNaN(n)){e.status(400).json({error:"Invalid PR number"});return}let i=await KE(r,n);i?e.json(i):e.status(404).json({error:"PR not found"})});P.get("/api/git/branches",async(t,e)=>{let r=Vs(),n=await jd(r);e.json(n)});P.post("/api/pick-folder",async(t,e)=>{try{let r=x8.platform(),n="";if(r==="darwin"){let{stdout:i}=await nh("osascript",["-e",'set chosenFolder to choose folder with prompt "Select project directory"',"-e","return POSIX path of chosenFolder"]);n=i.trim().replace(/\/$/,"")}else if(r==="win32"){let{stdout:i}=await nh("powershell",["-NoProfile","-Command","Add-Type -AssemblyName System.Windows.Forms; $d = New-Object System.Windows.Forms.FolderBrowserDialog; $d.Description = 'Select project directory'; if ($d.ShowDialog() -eq 'OK') { $d.SelectedPath } else { '' }"]);n=i.trim()}else{let{stdout:i}=await nh("zenity",["--file-selection","--directory","--title=Select project directory"]);n=i.trim()}n?e.json({path:n}):e.json({path:null,cancelled:!0})}catch{e.json({path:null,cancelled:!0})}});var ih=zt.join(x8.homedir(),".clustr","uploads");P.post("/api/upload-image",(t,e)=>{try{let{data:r,mimeType:n}=t.body;if(!r||!n){e.status(400).json({error:"Missing data or mimeType"});return}$s.existsSync(ih)||$s.mkdirSync(ih,{recursive:!0});let i=(n.split("/")[1]||"png").replace(/[^a-zA-Z0-9]/g,"")||"png",s=`paste-${Date.now()}.${i}`,a=zt.join(ih,s),o=Buffer.from(r,"base64");$s.writeFileSync(a,o),e.json({path:a,filename:s})}catch(r){e.status(500).json({error:r.message})}});P.post("/api/spawn",(t,e)=>{try{let{name:r,task:n,cwd:i,service:s}=t.body,a=i||process.cwd();HE(a);let o=TE(r,n,{cwd:i,service:s});xe.emit("agents:updated",St()),e.json({id:o,status:"spawning"})}catch(r){e.status(400).json({error:r.message})}});P.post("/api/agents/:id/message",(t,e)=>{let{content:r}=t.body;Qd(t.params.id,r+"\r")?e.json({status:"sent"}):e.status(404).json({error:"Agent not running"})});P.get("/api/agents/:id/scrollback",(t,e)=>{e.json({scrollback:OE(t.params.id)})});xe.on("connection",t=>{t.emit("agents:updated",St()),t.emit("messages:all",pc()),t.emit("crewmd:updated",As()),t.on("agent:input",(e,r)=>{Qd(e,r)}),t.on("agent:resize",(e,r,n)=>{AE(e,r,n)})});Hc&&P.get("*",(t,e)=>{e.sendFile(zt.join(Hc,"index.html"))});var m8="",g8="";setInterval(async()=>{if(xe.engine.clientsCount===0)return;let t=Vs();try{let e=await lf(t,"all"),r=JSON.stringify(e.map(n=>`${n.number}:${n.state}:${n.reviewDecision}`));r!==m8&&(m8=r,xe.emit("github:prs:updated",e))}catch{}try{let e=await jd(t),r=JSON.stringify(e.branches.map(n=>n.name));r!==g8&&(g8=r,xe.emit("git:branches:updated",e))}catch{}},3e4);y8.listen(Gs,"0.0.0.0",()=>{console.log(`Clustr server running on http://localhost:${Gs}`),console.log(`Connect from phone: http://localhost:${Gs}/connect`),console.log(`Auth token: ${$c.authToken}`)});
|
|
174
174
|
/*! Bundled license information:
|
|
175
175
|
|
|
176
176
|
depd/index.js:
|