@agensis/agensis-agent 0.1.28 → 0.1.29
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/bin/agensis.mjs +33 -32
- package/package.json +1 -1
package/bin/agensis.mjs
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`}function
|
|
4
|
-
`}function
|
|
5
|
-
`
|
|
6
|
-
`))
|
|
2
|
+
var hn=Object.defineProperty;var gn=(e,t)=>()=>(e&&(t=e(e=0)),t);var yn=(e,t)=>{for(var n in t)hn(e,n,{get:t[n],enumerable:!0})};var nt={};yn(nt,{createE2bProvider:()=>Nn});function Ae(e){return`'${String(e).replace(/'/g,"'\\''")}'`}function Nn({apiKey:e,anthropicApiKey:t,gitToken:n="",repoUrl:r="",template:s=""}={}){if(!e)throw new Error("E2B_API_KEY is not set on the daemon host.");if(!r)throw new Error("Sandbox needs a repo URL (set sandbox_config.repoUrl or the agent's repo).");return{async ensureEnv(){let o={apiKey:e,envs:t?{ANTHROPIC_API_KEY:t}:{}},i;try{({Sandbox:i}=await import("e2b"))}catch(u){if(u&&(u.code==="ERR_MODULE_NOT_FOUND"||u.code==="MODULE_NOT_FOUND"||/Cannot find package 'e2b'/.test(String(u&&u.message)))){let a=Number(String(process.versions.node).split(".")[0])||0,l=a<20||a===21?` Sandbox mode needs Node >=20.18.1 (<21 or >=22); you have ${process.versions.node}. Upgrade Node, then run \`npm i e2b\` in the daemon.`:" Run `npm i e2b` in the daemon to enable Sandbox mode.";throw new Error(`Sandbox execution requires the optional 'e2b' package, which is not installed.${l}`)}throw u}let c=s?await i.create(s,o):await i.create(o);return await c.commands.run("bash -lc 'command -v claude >/dev/null || npm i -g @anthropic-ai/claude-code'"),{sbx:c,dir:On}},async putRepo(o){let i=n?r.replace(/^https:\/\//,`https://x-access-token:${n}@`):r;try{let c=await o.sbx.commands.run(`git clone ${Ae(i)} ${Ae(o.dir)}`);if(c&&typeof c.exitCode=="number"&&c.exitCode!==0)throw new Error(`git clone failed: ${c.stderr||`exit ${c.exitCode}`}`)}catch(c){if(c&&String(c.message||"").startsWith("git clone failed:"))throw c;let u=c&&(c.stderr||c.exitCode!=null)?c.stderr||`exit ${c.exitCode}`:String(c?.message||c);throw new Error(`git clone failed: ${u}`)}},async exec(o,{cmd:i,args:c=[],env:u={},onData:a}){let l=`${i} ${c.map(Ae).join(" ")}`,m={cwd:o.dir,envs:{...u,IS_SANDBOX:"1",AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS:"1"},onStdout:g=>{try{a?.(g)}catch{}}};try{let g=await o.sbx.commands.run(l,m);return{status:g.exitCode,stdout:g.stdout||"",stderr:g.stderr||"",error:null}}catch(g){return g&&typeof g.exitCode=="number"?{status:g.exitCode,stdout:g.stdout||"",stderr:g.stderr||"",error:null}:{status:null,stdout:"",stderr:String(g?.message||g),error:g}}},async getResult(o){try{return{patch:(await o.sbx.commands.run("git add -A && git diff --cached",{cwd:o.dir})).stdout||""}}catch(i){return{patch:i&&i.stdout||""}}},async destroy(o){await o.sbx.kill()}}}var On,rt=gn(()=>{On="/home/user/repo"});import Y from"node:process";import le from"node:fs";import de from"node:path";import me from"node:os";import Ar from"node:crypto";import k from"node:process";import ue from"ws";import{spawn as Sn}from"node:child_process";function qe(e){let t=Math.max(0,Math.round(e/1e3)),n=Math.floor(t/60),r=t%60;return n>0?`${n}m ${r}s`:`${r}s`}var wn=50*1024*1024;function ie(e){let{cmd:t,args:n=[],env:r={},cwd:s,timeoutMs:o=0,label:i="working",heartbeatMs:c=15e3,input:u="",now:a=Date.now,log:l=console,signal:m,onData:g}=e||{};return new Promise(S=>{if(m?.aborted){S({status:null,stdout:"",stderr:"",aborted:!0,error:new Error("cancelled")});return}let f;try{let p=n.some(C=>C==="--dangerously-skip-permissions"),v=typeof process.getuid=="function"&&process.getuid()===0,D={...process.env,...r};delete D.AGENSIS_TOKEN,delete D.ANTHROPIC_API_KEY,delete D.ANTHROPIC_AUTH_TOKEN,p&&v&&(D.IS_SANDBOX="1"),f=Sn(t,n,{cwd:s,detached:!0,env:D})}catch(p){S({status:null,stdout:"",stderr:"",error:p});return}u?f.stdin?.end(String(u)):f.stdin?.end();let x="",_="";f.stdout?.setEncoding("utf8"),f.stderr?.setEncoding("utf8");let y=(p,v)=>p.length>=wn?p:p+v;f.stdout?.on("data",p=>{if(x=y(x,p),g)try{g(p)}catch{}}),f.stderr?.on("data",p=>_=y(_,p));let I=a(),A=c>0?setInterval(()=>{l.log(` \u2026 still ${i} (${qe(a()-I)}) \u2014 Ctrl+C to cancel`)},c):null;A?.unref&&A.unref();let E=p=>{if(f.pid!=null)try{process.kill(-f.pid,p)}catch{try{f.kill(p)}catch{}}},P=!1,B=o>0?setTimeout(()=>{P=!0,E("SIGKILL")},o):null;B?.unref&&B.unref();let h=!1,w=null,M=()=>{h=!0,E("SIGTERM"),w=setTimeout(()=>E("SIGKILL"),3e3),w?.unref&&w.unref()};m&&m.addEventListener("abort",M,{once:!0});let d=(p,v)=>{A&&clearInterval(A),B&&clearTimeout(B),w&&clearTimeout(w),m&&m.removeEventListener("abort",M),S({status:p,stdout:x,stderr:_,aborted:h,error:v||(h?new Error("cancelled"):P?new Error(`timed out after ${qe(o)}`):null)})};f.on("error",p=>d(null,p)),f.on("close",p=>d(p,null))})}import{spawn as bn}from"node:child_process";var Xe=10*60*1e3;function Ve(e={}){let t={...process.env,...e};return delete t.AGENSIS_TOKEN,delete t.ANTHROPIC_API_KEY,delete t.ANTHROPIC_AUTH_TOKEN,t}var ke=class{#e=[];#t=[];#n=!1;push(t){if(this.#n)return;let n=this.#t.shift();n?n({value:t,done:!1}):this.#e.push(t)}close(){this.#n=!0;for(let t of this.#t.splice(0))t({value:void 0,done:!0})}[Symbol.asyncIterator](){return{next:()=>this.#e.length?Promise.resolve({value:this.#e.shift(),done:!1}):this.#n?Promise.resolve({value:void 0,done:!0}):new Promise(t=>this.#t.push(t))}}};function Qe(){let e=new Map;return(t,n)=>{let r=(e.get(t)||Promise.resolve()).then(n,n);return e.set(t,r.catch(()=>{})),r}}var _n=["mcp__agensis"];function vn(e){return e==="yolo"?{permissionMode:"bypassPermissions",allowDangerouslySkipPermissions:!0}:e==="accept_edits"?{permissionMode:"acceptEdits"}:{permissionMode:"default"}}function En(e){if(!e||e.type!=="content_block_delta")return"";let t=e.delta;return t&&t.type==="text_delta"&&typeof t.text=="string"?t.text:""}function kn(e){return`${JSON.stringify({type:"stream_event",event:{type:"content_block_delta",delta:{type:"text_delta",text:e}}})}
|
|
3
|
+
`}function In(e){return`${JSON.stringify({type:"result",result:e})}
|
|
4
|
+
`}function An(e){return`${JSON.stringify({type:"agensis_step",step:e})}
|
|
5
|
+
`}var Cn=["file_path","path","pattern","command","description","prompt"],Ye=120;function Ie(e){if(!e||typeof e!="object")return"";for(let t of Cn){let n=e[t];if(typeof n!="string")continue;let r=n.replace(/\s+/g," ").trim();if(r)return r.length>Ye?`${r.slice(0,Ye)}\u2026`:r}return""}function Ze(e){return JSON.stringify({cwd:e.cwd||"",model:e.model||"",permissionMode:e.permissionMode||"default",hostFolders:[...e.hostFolders||[]].sort(),leanCli:!!e.leanCli,mcpUrl:e.mcp?.url||"",mcpToken:e.mcp?.env?.AGENSIS_MCP_TOKEN||""})}function et({queryFn:e,idleCloseMs:t=Xe}={}){let n=new Map,r=Qe(),s=(u,a,l)=>{let m=n.get(u);if(!(!m||a&&m!==a))if(n.delete(u),clearTimeout(m.idleTimer),m.closed=!0,m.queue.close(),l&&m.activeTurn&&m.activeTurn.finish(l),typeof m.query.close=="function")try{m.query.close()}catch{}else Promise.resolve(m.query.return?.()).catch(()=>{})},o=u=>{let a=n.get(u);a&&(clearTimeout(a.idleTimer),a.idleTimer=setTimeout(()=>s(u),t),a.idleTimer.unref?.())},i=async(u,a)=>{let l=n.get(u),m=Ze(a);if(l&&l.fingerprint===m&&!l.closed)return l;l&&s(u,l),e||(e=(await import("@anthropic-ai/claude-agent-sdk")).query);let g=new ke,S=vn(a.permissionMode),f=a.leanCli&&a.mcp?{agensis:{type:"http",url:a.mcp.url,headers:{Authorization:"Bearer ${AGENSIS_MCP_TOKEN}"}}}:void 0,x=e({prompt:g,options:{cwd:a.cwd,model:a.model,...S,allowedTools:_n,additionalDirectories:a.hostFolders&&a.hostFolders.length?a.hostFolders:void 0,mcpServers:f,strictMcpConfig:a.leanCli?!0:void 0,settingSources:a.leanCli?[]:void 0,persistSession:a.leanCli?!1:void 0,includePartialMessages:!0,env:Ve(a.mcp?.env)}});return l={query:x,queue:g,sessionId:"",idleTimer:null,activeTurn:null,closed:!1,terminalError:null,fingerprint:m},n.set(u,l),l.pump=(async()=>{let _=null;try{for await(let y of x){y.session_id&&(l.sessionId=y.session_id);let I=l.activeTurn;if(I){if(y.type==="stream_event"){let A=En(y.event);A&&(I.streamed+=A,I.onData?.(kn(A)))}else if(y.type==="result")if(y.subtype==="success"){let A=y.result==null?I.streamed:String(y.result);I.onData?.(In(A)),I.finish({status:0,stdout:A,stderr:"",error:null})}else{let A=Array.isArray(y.errors)?y.errors.filter(Boolean).join(`
|
|
6
|
+
`):y.result,E=new Error(A||`claude-agent-sdk result error: ${y.subtype}`);I.finish({status:1,stdout:I.streamed,stderr:E.message,error:E})}else if(y.type==="assistant"){let A=y.message?.content;if(Array.isArray(A))for(let E of A)!E||E.type!=="tool_use"||!E.name||I.onData?.(An({kind:"tool",name:String(E.name),detail:Ie(E.input)}))}}}_=new Error("claude-agent-sdk connection closed")}catch(y){_=y}finally{l.closed=!0,l.terminalError=_,clearTimeout(l.idleTimer),l.queue.close(),n.get(u)===l&&n.delete(u),l.activeTurn&&l.activeTurn.finish({status:null,stdout:l.activeTurn.streamed,stderr:String(_?.message||_||""),error:_})}})(),l};return{run:u=>r(u.sessionKey||"default",async()=>{let{sessionKey:a="default",prompt:l,signal:m,onData:g,timeoutMs:S=0}=u;if(m?.aborted)return{status:null,stdout:"",stderr:"",aborted:!0,error:new Error("cancelled")};let f;try{f=await i(a,u)}catch(_){return{status:null,stdout:"",stderr:"",error:_}}if(f.closed){let _=f.terminalError||new Error("claude-agent-sdk connection closed");return{status:null,stdout:"",stderr:String(_.message||_),error:_}}clearTimeout(f.idleTimer);let x=await new Promise(_=>{let y=!1,I=null,A={streamed:"",onData:g,finish(P){y||(y=!0,f.activeTurn===A&&(f.activeTurn=null),m&&m.removeEventListener("abort",E),I&&clearTimeout(I),_(P))}},E=()=>{let P={status:null,stdout:A.streamed,stderr:"",aborted:!0,error:new Error("cancelled")};Promise.resolve(f.query.interrupt?.()).catch(()=>{}),s(a,f,P)};f.activeTurn=A,m&&m.addEventListener("abort",E,{once:!0}),S>0&&(I=setTimeout(()=>{let P=new Error(`timed out after ${S}ms`);Promise.resolve(f.query.interrupt?.()).catch(()=>{}),s(a,f,{status:null,stdout:A.streamed,stderr:P.message,error:P})},S),I.unref?.()),f.queue.push({type:"user",message:{role:"user",content:l},parent_tool_use_id:null,session_id:f.sessionId})});return n.get(a)===f&&o(a),x}),shutdown:()=>{for(let u of[...n.keys()])s(u)}}}function xn(e){let t=1,n="",r=new Map,s=new Set;e.stdout.setEncoding("utf8"),e.stdout.on("data",i=>{n+=i;let c;for(;(c=n.indexOf(`
|
|
7
|
+
`))>=0;){let u=n.slice(0,c);if(n=n.slice(c+1),!u.trim())continue;let a;try{a=JSON.parse(u)}catch{continue}if(a.id!==void 0&&r.has(a.id)){let{resolve:l,reject:m}=r.get(a.id);r.delete(a.id),a.error?m(new Error(a.error.message||"codex app-server error")):l(a.result)}else if(a.method)for(let l of s)l(a.method,a.params,a.id)}});let o=i=>{for(let{reject:c}of r.values())c(i);r.clear()};return e.on("exit",()=>o(new Error("codex app-server exited"))),e.on("error",i=>o(i)),{request(i,c){let u=t++;return new Promise((a,l)=>{r.set(u,{resolve:a,reject:l}),e.stdin.write(`${JSON.stringify({id:u,method:i,params:c})}
|
|
7
8
|
`)})},notify(i,c){e.stdin.write(`${JSON.stringify({method:i,params:c})}
|
|
8
9
|
`)},respond(i,c){e.stdin.write(`${JSON.stringify({id:i,result:c})}
|
|
9
10
|
`)},respondError(i,c){e.stdin.write(`${JSON.stringify({id:i,error:{code:-32601,message:c}})}
|
|
10
|
-
`)},onMessage(i){return
|
|
11
|
+
`)},onMessage(i){return s.add(i),()=>s.delete(i)}}}function Mn(e){return e==="yolo"?{approvalPolicy:"never",sandbox:"danger-full-access"}:{}}function tt({spawnFn:e=bn,idleCloseMs:t=Xe}={}){let n=new Map,r=Qe(),s=u=>{let a=n.get(u);if(a){n.delete(u),clearTimeout(a.idleTimer);try{a.child.kill("SIGTERM")}catch{}}},o=u=>{let a=n.get(u);a&&(clearTimeout(a.idleTimer),a.idleTimer=setTimeout(()=>s(u),t),a.idleTimer.unref?.())},i=async(u,a)=>{let l=n.get(u),m=Ze(a);if(l&&l.fingerprint===m)return l;l&&s(u);let g=e("codex",["app-server"],{cwd:a.cwd,env:Ve(a.mcp?.env),stdio:["pipe","pipe","pipe"]}),S=xn(g);await S.request("initialize",{clientInfo:{name:"agensis-agent",version:a.clientVersion||"unknown"}}),S.notify("initialized");let f=a.leanCli&&a.mcp?{mcp_servers:{agensis:{url:a.mcp.url,bearer_token_env_var:"AGENSIS_MCP_TOKEN"}}}:void 0,x=await S.request("thread/start",{cwd:a.cwd,ephemeral:a.leanCli||void 0,model:a.model,config:f,...Mn(a.permissionMode)}),_={child:g,rpc:S,threadId:x.thread.id,fingerprint:m,idleTimer:null};return n.set(u,_),_};return{run:u=>r(u.sessionKey||"default",async()=>{let{sessionKey:a="default",prompt:l,signal:m,onData:g,timeoutMs:S=0}=u;if(m?.aborted)return{status:null,stdout:"",stderr:"",aborted:!0,error:new Error("cancelled")};let f;try{f=await i(a,u)}catch(E){return{status:null,stdout:"",stderr:"",error:E}}let x="",_="",y=null,I=!1,A=await new Promise(E=>{let P=!1,B=p=>{P||(P=!0,d(),E(p))},h=f.rpc.onMessage((p,v,D)=>{if(D!==void 0){if(p==="item/commandExecution/requestApproval"){let C=u.permissionMode==="yolo"?"acceptForSession":"decline";f.rpc.respond(D,{decision:C})}else if(p==="item/fileChange/requestApproval"){let C=u.permissionMode==="yolo"||u.permissionMode==="accept_edits"?"acceptForSession":"decline";f.rpc.respond(D,{decision:C})}else f.rpc.respondError(D,`Agensis daemon cannot handle Codex request ${p}`);return}if(!(!v||v.threadId!==f.threadId)){if(p==="turn/started"){y=v.turn?.id??y;return}if(!(y&&v.turnId&&v.turnId!==y)){if(p==="item/agentMessage/delta")x+=v.delta||"",g?.(v.delta||"");else if(p==="item/completed"&&v.item?.type==="agentMessage")_=v.item.text||_;else if(p==="turn/completed"){let C=v.turn?.status==="failed"||v.turn?.error;B({status:C?1:0,stdout:_||x,stderr:C?String(v.turn?.error?.message||v.turn?.error||""):"",error:C?new Error(String(v.turn?.error?.message||v.turn?.error||"codex turn failed")):null})}}}}),w=()=>{I=!0,f.rpc.request("turn/interrupt",{threadId:f.threadId}).catch(()=>{});let p={status:null,stdout:x,stderr:"",aborted:!0,error:new Error("cancelled")};B(p),s(a)};m&&m.addEventListener("abort",w,{once:!0});let M=S>0?setTimeout(()=>{let p=new Error(`timed out after ${S}ms`);f.rpc.request("turn/interrupt",{threadId:f.threadId}).catch(()=>{}),B({status:null,stdout:x,stderr:p.message,error:p}),s(a)},S):null;M?.unref?.();function d(){h(),m&&m.removeEventListener("abort",w),M&&clearTimeout(M)}f.rpc.request("turn/start",{threadId:f.threadId,input:[{type:"text",text:l}]}).then(p=>{y=p?.turn?.id||y}).catch(p=>B({status:null,stdout:"",stderr:"",error:p}))});return I||o(a),A}),shutdown:()=>{for(let u of[...n.keys()])s(u)}}}function st({run:e=ie}={}){return{run:t=>e(t)}}var Tn=null,$n=null,ot=new Set;function Bn(e){let t=String(e&&e.message||e||"");return/Cannot find module|ERR_MODULE_NOT_FOUND|ENOENT|command not found/i.test(t)}function Dn(e,{local:t,pooled:n,log:r=console}={}){let s=t||st(),o=n||(e==="claude"?Tn||=et():e==="codex"?$n||=tt():null);return o?{async run(i){if(ot.has(e))return s.run(i);let c=await o.run(i);return c.error&&Bn(c.error)?(ot.add(e),r.log?.(`[executor] ${e} fast connection unavailable (${c.error.message}); falling back to subprocess mode for this and future jobs.`),s.run(i)):c}}:s}function Pn(e){return{async run({cmd:t,args:n=[],env:r={},onData:s,signal:o,job:i}){let c=null;try{c=await e.ensureEnv({job:i,signal:o}),await e.putRepo(c,{job:i,signal:o});let u=await e.exec(c,{cmd:t,args:n,env:r,onData:s,signal:o}),a=await e.getResult(c,{job:i}).catch(()=>({})),l=a&&a.patch?String(a.patch).trim():"",m=l?`${u.stdout||""}
|
|
11
12
|
|
|
12
13
|
\`\`\`diff
|
|
13
14
|
${l}
|
|
14
|
-
\`\`\``:u.stdout||"";return{status:u.status,stdout:m,stderr:u.stderr||"",error:u.error||null}}catch(u){return{status:null,stdout:"",stderr:"",error:u}}finally{if(c)try{await e.destroy(c)}catch{}}}}}function
|
|
15
|
+
\`\`\``:u.stdout||"";return{status:u.status,stdout:m,stderr:u.stderr||"",error:u.error||null}}catch(u){return{status:null,stdout:"",stderr:"",error:u}}finally{if(c)try{await e.destroy(c)}catch{}}}}}function it(e,{makeProvider:t,family:n}={}){return(e&&e.agent&&e.agent.run_mode)==="sandbox"?Pn((t||Rn)(e)):n==="claude"||n==="codex"?Dn(n):st()}function Rn(e){let t=e.agent&&e.agent.sandbox_provider||"e2b",n=e.agent&&e.agent.sandbox_config||{};if(t!=="e2b")throw new Error(`Sandbox provider "${t}" is not available yet (only e2b is wired).`);return Un({apiKey:process.env.E2B_API_KEY,anthropicApiKey:process.env.ANTHROPIC_API_KEY,gitToken:process.env.GIT_TOKEN||"",repoUrl:e.repoUrl||e.agent&&e.agent.repo_url||n.repoUrl||"",template:n.template||""})}function Ln(e=process.versions.node){let[t,n,r]=String(e).split(".").map(s=>Number(s)||0);return t===21?!1:t>=22?!0:t!==20?!1:n>18?!0:n<18?!1:r>=1}function Un(e){let t=null,n=async()=>{if(!t){if(!Ln())throw new Error(`Sandbox execution requires Node >=20.18.1 (you have ${process.versions.node}). Upgrade Node to use Sandbox agents; Built-in and Remote daemon modes still work on Node 18.`);t=(await Promise.resolve().then(()=>(rt(),nt))).createE2bProvider(e)}return t};return{ensureEnv:async r=>(await n()).ensureEnv(r),putRepo:async(r,s)=>(await n()).putRepo(r,s),exec:async(r,s)=>(await n()).exec(r,s),getResult:async(r,s)=>(await n()).getResult(r,s),destroy:async r=>(await n()).destroy(r)}}function at(e={}){let{runJob:t}=e,n=Math.max(1,Number(e.concurrency)||1),r=new Map,s=0,o=[];function i(_){let y=r.get(_);return y||(y={queued:[],active:null},r.set(_,y)),y}function c(_){if(_==null)return!1;for(let y of r.values())if(y.active&&!y.active.cancelled&&y.active.job.key===_||y.queued.some(I=>I.key===_))return!0;return!1}function u(){for(let[_,y]of r){if(s>=n)break;if(y.active||y.queued.length===0)continue;let I=y.queued.shift(),A=new AbortController;y.active={job:I,controller:A,cancelled:!1},s+=1,Promise.resolve().then(()=>A.signal.aborted?void 0:t(I,{signal:A.signal})).catch(()=>{}).finally(()=>{y.active=null,s-=1,y.queued.length===0&&!y.active&&r.delete(_),u(),a()})}}function a(){if(s>0)return;for(let y of r.values())if(y.queued.length)return;let _=o;o=[];for(let y of _)y()}function l(_){if(_&&_.key!=null&&c(_.key))return{accepted:!1,deduped:!0,position:0,startedImmediately:!1};let y=_&&_.lane!=null?String(_.lane):"",I=i(y),A=!I.active&&I.queued.length===0&&s<n;I.queued.push(_);let E=I.queued.length+(I.active?1:0);return u(),{accepted:!0,deduped:!1,position:E,startedImmediately:A}}function m(_,y){let I=!1;for(let[A,E]of r)y!=null&&A!==String(y)||E.active&&(E.active.cancelled=!0,E.active.controller.abort(_||"cancelled"),I=!0);return I}function g(_,y){if(_==null)return!1;let I=!1;for(let[A,E]of[...r]){E.active?.job?.key===_&&(E.active.cancelled=!0,E.active.controller.abort(y||"cancelled"),I=!0);let P=E.queued.length;E.queued=E.queued.filter(B=>B.key!==_),E.queued.length!==P&&(I=!0),!E.active&&E.queued.length===0&&r.delete(A)}return a(),I}function S(){let _=0;for(let y of r.values())_+=y.queued.length;return _}function f(){return s}function x(){return s===0&&S()===0?Promise.resolve():new Promise(_=>o.push(_))}return{enqueue:l,cancel:g,cancelActive:m,has:c,size:S,active:f,idle:x}}import ft from"node:crypto";import Fn from"node:http";import pt from"node:os";import X from"node:process";var ct=8787,Ce="claude-haiku-4-5",jn=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/,Gn=100,Hn=new Set(["say","wave","hush","open","choose"]),ye="x-agensis-bridge-secret";function Jn(){return`cbs_${ft.randomBytes(24).toString("base64url")}`}function Kn(e){let t=e?.headers||{},n=String(t[ye]||t[ye.toLowerCase()]||"").trim();if(n)return n;let s=String(t.authorization||t.Authorization||"").trim().match(/^Bearer\s+(.+)$/i);return s?s[1].trim():""}function zn(e,t){let n=String(t||""),r=Kn(e);if(!n||!r)return!1;let s=Buffer.from(r),o=Buffer.from(n);return s.length!==o.length?!1:ft.timingSafeEqual(s,o)}function Wn(e={},t={}){let n=String(t.authSecret||"").trim();if(n)return n;let r=String(e.cursorBuddyBridgeSecret||"").trim();if(r)return r;let s=String(X.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim();return s||Jn()}function qn(e,t){return e==="OPTIONS"||e==="GET"&&t==="/cursorbuddy/health"}function j(e,t,n){e.writeHead(t,{"content-type":"application/json","access-control-allow-origin":"*","access-control-allow-methods":"GET, POST, OPTIONS","access-control-allow-headers":"content-type, authorization, x-agensis-bridge-secret"}),e.end(JSON.stringify(n))}function ut(e){e.writeHead(200,{"content-type":"text/event-stream; charset=utf-8","cache-control":"no-store, no-transform",connection:"keep-alive","access-control-allow-origin":"*","access-control-allow-methods":"GET, POST, OPTIONS","access-control-allow-headers":"content-type, authorization, x-agensis-bridge-secret","x-accel-buffering":"no"})}function H(e,t){e.write(`data: ${typeof t=="string"?t:JSON.stringify(t)}
|
|
15
16
|
|
|
16
|
-
`)}function ae(e){return new Promise((t,n)=>{let r="";e.on("data",
|
|
17
|
-
${
|
|
17
|
+
`)}function ae(e){return new Promise((t,n)=>{let r="";e.on("data",s=>{r+=s,r.length>256*1024&&(n(new Error("request body is too large")),e.destroy())}),e.on("error",n),e.on("end",()=>t(r))})}function Yn(e){let t=[],n="",r="",s=!1;for(let o of String(e||"")){if(s){n+=o,s=!1;continue}if(o==="\\"){s=!0;continue}if(r){o===r?r="":n+=o;continue}if(o==='"'||o==="'"){r=o;continue}if(/\s/.test(o)){n&&(t.push(n),n="");continue}n+=o}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function Xn(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function he(e,t){return e.some(n=>n===t||String(n).startsWith(`${t}=`))}function lt(e,t){let n=[];t&&n.push("CursorBuddy local runtime context:",JSON.stringify(t,null,2),"");for(let r of Array.isArray(e)?e:[]){let s=String(r?.role||"user"),o=String(r?.content||"");o.trim()&&n.push(`${s.toUpperCase()}:
|
|
18
|
+
${o}`)}return n.join(`
|
|
18
19
|
|
|
19
|
-
`).trim()||"Say that the local Agensis runtime is connected."}function
|
|
20
|
-
`))>=0;)u(t.slice(0,l)),t=t.slice(l+1)},end(){t&&(u(t),t="")},get live(){return r?n:o},get result(){return s??(r?n:o)}}}function te(e,t,n,r=null){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:t,choices:[{index:0,delta:n?{content:n}:{},finish_reason:r}]}}function ge(e){return`http://127.0.0.1:${e}`}function Qn(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function Zn(e){return String(e||"").slice(0,18)}function U(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function er(e={},t={},n={}){let r=U(e.metadata)||{},o=U(e.page)||U(r.page)||{},s=U(e.client)||U(r.client)||{},i=U(r.runtime)||{},c=U(e.manifest)||U(r.manifest)||null;return{url:String(e.url||o.url||r.websiteSource||e.websiteSource||"").slice(0,2048),title:String(e.title||o.title||"").slice(0,300),surface:String(e.surface||i.surface||t.surface||"").slice(0,80),instanceId:String(e.instanceId||i.instanceId||"").slice(0,140),workspaceId:String(t.workspaceId||e.workspaceId||n.workspace||"").slice(0,120),agentId:String(t.agentId||e.agentId||n.agent||"").slice(0,120),runtime:{...i,local:!0,connected:!0,connection:t},page:o,client:s,project:U(e.project)||U(r.project)||null,manifest:c,selection:U(e.selection)||null,updatedAt:new Date().toISOString()}}function tr(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function nr(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!Rn.test(r))throw new Error("Connection key format is invalid. Create a fresh CursorBuddy key first.");if(typeof n!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let o=Qn(e,t),s=await n(`${o}/backend/cursorbuddy/connection-keys/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:r,baseUrl:o,host:mt.hostname(),cwd:t.cwd||e.cwd||X.cwd(),name:t.name||e.name||e.handle||"CursorBuddy runtime",surface:t.surface||"browser_extension",scope:t.scope||"machine",runtimeKind:t.runtimeKind||"agensis-cli-local-bridge",version:t.version||e.version||X.env.npm_package_version||"",permissionMode:t.permissionMode||e.permissionMode,model:t.model||e.model,metadata:U(t.metadata)||null,websiteSource:t.websiteSource||t.metadata?.websiteSource||"",page:U(t.page)||U(t.metadata?.page)||null,client:U(t.client)||U(t.metadata?.client)||null,manifest:U(t.manifest)||U(t.metadata?.manifest)||null})}),i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(tr(s,i));return{key:r,baseUrl:o,data:i?.data||i}}async function ht(e,t={}){let n=Number(t.port??e.cursorBuddyPort??X.env.AGENSIS_CURSORBUDDY_PORT??it),r=Hn(e,t),o=new Date().toISOString(),s=[],i=[],c=new Set,u=t.fetchImpl||globalThis.fetch,a=1,l=null,m=n,_=null,b=(p,g={})=>{let A={ts:new Date().toISOString(),event:p,detail:g};return s.push(A),s.length>200&&s.shift(),t.log?.(`CursorBuddy local bridge: ${p}${Object.keys(g).length?` ${JSON.stringify(g)}`:""}`),A},h=()=>({connected:!!e.cursorBuddyRuntime,mode:e.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:e.agent,workspaceId:e.workspace,agensisUrl:e.url,handle:e.handle,name:e.name,cwd:e.cwd,updatedAt:new Date().toISOString()}),M=()=>{if(typeof t.connectionProvider!="function")return null;try{let p=t.connectionProvider();return!p||typeof p!="object"||Array.isArray(p)?null:{...h(),...p,connected:p.connected===!0}}catch{return null}},w=()=>{let p=M();return p?.connected===!1?p:_?{...h(),...p||{},..._,connected:!0,updatedAt:p?.updatedAt||_.updatedAt}:p||h()};function S(p={}){if(!p||typeof p!="object"||Array.isArray(p))return null;let g=String(p.action||p.type||"").trim().toLowerCase();if(!Un.has(g))return null;let A={id:a++,ts:new Date().toISOString(),action:g,text:String(p.text||p.say||p.message||"").slice(0,1200),label:String(p.label||"").slice(0,80),value:String(p.value||p.prompt||"").slice(0,1200),holdMs:Number.isFinite(p.holdMs)?Math.max(0,Math.min(6e4,p.holdMs)):void 0,source:String(p.source||"agensis-daemon").slice(0,80)};return p.options&&Array.isArray(p.options)&&(A.options=p.options.map(d=>({label:String(d?.label||"").slice(0,80),value:String(d?.value||d?.task||"").slice(0,1200)})).filter(d=>d.label).slice(0,6)),A}function E(p){for(i.push(p);i.length>Ln;)i.shift();b("control",{id:p.id,action:p.action,chars:p.text.length});for(let g of[...c])try{H(g,{type:"command",command:p})}catch{c.delete(g)}return p}function I(p){let g=Yn(p);if(g){let A=S(g.command);return A&&(E(A),b("chat_control",{id:A.id,action:A.action})),{content:g.content,model:"cursorbuddy-local-control",fast:!0}}return null}async function x(p){let g=I(p);if(g)return g;let A=ct(p?.messages,l),d=lt(e,A,p?.model),f=await ie({cmd:d.cmd,args:d.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:d.stdin});if(f.error||f.status!==0)throw new Error(f.error?.message||String(f.stderr||"").trim()||`Command exited with status ${f.status}`);return{content:ut(f.stdout||f.stderr),model:d.model}}async function $(p,g){let A=`agensis-cursorbuddy-${Date.now()}`,d=I(p);if(d){let T=d.model||"cursorbuddy-local-control";return H(g,te(A,T,d.content)),H(g,te(A,T,"","stop")),H(g,"[DONE]"),b("chat_fast",{chars:d.content.length,model:T}),{content:d.content,model:T,fast:!0}}let f=ct(p?.messages,l),v=lt(e,f,p?.model,{stream:!0}),D="",C=T=>{T&&(D+=T,H(g,te(A,v.model||e.model,T)))},O=v.streamJson?Vn(C):null,y=await ie({cmd:v.cmd,args:v.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:v.stdin,onData:T=>{if(O)O.feed(T);else{let F=String(T||"");D+=F,H(g,te(A,v.model||e.model,F))}}});if(O){O.end();let T=O.result||"";!D&&T?C(T):D=T||D}if(y.error||y.status!==0){let T=y.error?.message||String(y.stderr||"").trim()||`Command exited with status ${y.status}`;throw new Error(T)}let N=O?D:ut(D||y.stdout||y.stderr);return!O&&N&&N!==D&&(H(g,te(A,v.model||e.model,N)),D=N),H(g,te(A,v.model||e.model,"","stop")),H(g,"[DONE]"),{content:D||N,model:v.model}}let P=Pn.createServer(async(p,g)=>{if(g.setHeader("access-control-allow-origin","*"),g.setHeader("access-control-allow-methods","GET, POST, OPTIONS"),g.setHeader("access-control-allow-headers","content-type, authorization, x-agensis-bridge-secret"),p.method==="OPTIONS"){g.writeHead(204),g.end();return}let A=new URL(p.url||"/",ge(m||it));if(!Jn(p.method,A.pathname)&&!Gn(p,r)){j(g,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(p.method==="GET"&&A.pathname==="/cursorbuddy/health"){let d=ge(m);j(g,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:Ae(e),daemonModel:e.model,port:m,host:mt.hostname(),pid:X.pid,bootedAt:o,authRequired:!0,authHeader:ye,stream:!0,streaming:!0,supportsStreaming:!0,chatStream:!0,capabilities:{chatStream:!0,controlStream:!0,fastAvatarReplies:!1,nativeCursorBuddyControl:!0},latestControlId:i.at(-1)?.id||0,connection:w(),context:l,endpoints:{chat:`${d}/v1/chat/completions`,chatStream:`${d}/v1/chat/completions`,edit:`${d}/cursorbuddy/edit`,context:`${d}/cursorbuddy/context`,control:`${d}/cursorbuddy/control`,controlStream:`${d}/cursorbuddy/control/stream`,logs:`${d}/cursorbuddy/logs`}});return}if(p.method==="GET"&&A.pathname==="/cursorbuddy/logs"){j(g,200,{ok:!0,events:s.slice(-100)});return}if(p.method==="GET"&&A.pathname==="/cursorbuddy/context"){j(g,200,{ok:!0,context:l});return}if(p.method==="GET"&&A.pathname==="/cursorbuddy/control"){let d=Number(A.searchParams.get("after")||0),f=i.filter(v=>v.id>d);j(g,200,{ok:!0,commands:f,latestId:i.at(-1)?.id||0});return}if(p.method==="GET"&&A.pathname==="/cursorbuddy/control/stream"){let d=Number(A.searchParams.get("after")||0);at(g),c.add(g),H(g,{type:"ready",latestId:i.at(-1)?.id||0});for(let v of i.filter(D=>D.id>d))H(g,{type:"command",command:v});let f=setInterval(()=>{try{H(g,{type:"ping",ts:new Date().toISOString()})}catch{c.delete(g),clearInterval(f)}},15e3);f.unref&&f.unref(),p.on("close",()=>{c.delete(g),clearInterval(f)});return}if(p.method==="POST"&&A.pathname==="/cursorbuddy/control"){try{let d=JSON.parse(await ae(p)||"{}"),f=S(d);if(!f){j(g,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let v=E(f);j(g,200,{ok:!0,command:v})}catch(d){b("control_error",{error:String(d?.message||d)}),j(g,400,{ok:!1,error:String(d?.message||d)})}return}if(p.method==="POST"&&A.pathname==="/cursorbuddy/context"){try{let d=JSON.parse(await ae(p)||"{}");l={url:String(d.url||"").slice(0,2048),title:String(d.title||"").slice(0,300),surface:String(d.surface||"").slice(0,80),instanceId:String(d.instanceId||"").slice(0,140),workspaceId:String(d.workspaceId||e.workspace||"").slice(0,120),agentId:String(d.agentId||e.agent||"").slice(0,120),runtime:d.runtime&&typeof d.runtime=="object"?d.runtime:null,page:d.page&&typeof d.page=="object"?d.page:null,client:d.client&&typeof d.client=="object"?d.client:null,project:d.project&&typeof d.project=="object"?d.project:null,manifest:d.manifest&&typeof d.manifest=="object"?d.manifest:null,selection:d.selection&&typeof d.selection=="object"?d.selection:null,updatedAt:new Date().toISOString()},b("context",{url:l.url,surface:l.surface,instanceId:l.instanceId}),j(g,200,{ok:!0,context:l})}catch(d){b("context_error",{error:String(d?.message||d)}),j(g,400,{ok:!1,error:String(d?.message||d)})}return}if(p.method==="POST"&&A.pathname==="/cursorbuddy/connect"){try{let d=JSON.parse(await ae(p)||"{}"),f=await nr(e,d,u),v=f.data||{};_={connected:!0,mode:"agensis-claimed",keyId:Zn(f.key),agentId:String(v.agentId||v.agent?.id||e.agent||""),workspaceId:String(v.workspaceId||v.workspace_id||v.agent?.workspace_id||e.workspace||""),agensisUrl:f.baseUrl,handle:String(v.handle||v.agent?.handle||e.handle||""),name:String(v.agent?.name||d.name||e.name||"CursorBuddy runtime"),cwd:String(d.cwd||e.cwd||X.cwd()),surface:String(d.surface||"browser_extension"),command:String(v.command||v.localCommand||""),updatedAt:new Date().toISOString()},l=er(d,_,e),b("connect",{mode:_.mode,keyId:_.keyId,agentId:_.agentId,workspaceId:_.workspaceId,url:l.url}),j(g,200,{ok:!0,connection:_,claim:v})}catch(d){b("connect_error",{error:String(d?.message||d)}),j(g,400,{ok:!1,error:String(d?.message||d)})}return}if(p.method==="POST"&&A.pathname==="/cursorbuddy/edit"){try{let d=JSON.parse(await ae(p)||"{}"),f=[{role:"system",content:"You are the local CursorBuddy edit agent. The user selected a DOM element in their own site. Use the payload to inspect and change the local checkout, then report what changed."},{role:"user",content:JSON.stringify(d,null,2)}];b("edit_request",{selector:d?.target?.selector||""});let v=await x({messages:f,model:d?.model});b("edit_done",{chars:v.content.length}),j(g,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:v.content})}catch(d){b("edit_error",{error:String(d?.message||d)}),j(g,500,{ok:!1,error:String(d?.message||d)})}return}if(p.method==="POST"&&A.pathname.endsWith("/chat/completions")){try{let d=JSON.parse(await ae(p)||"{}");if(b("chat_request",{messages:Array.isArray(d.messages)?d.messages.length:0,model:ft(d.model,Ae(e))}),d.stream===!0){at(g);let v=await $(d,g);b("chat_done",{chars:v.content.length,stream:!0,fast:v.fast===!0}),g.end();return}let f=await x(d);b("chat_done",{chars:f.content.length,fast:f.fast===!0}),j(g,200,{id:`agensis-cursorbuddy-${Date.now()}`,object:"chat.completion",model:f.model||d.model||e.model,choices:[{index:0,message:{role:"assistant",content:f.content},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}catch(d){b("chat_error",{error:String(d?.message||d)}),j(g,500,{error:{message:String(d?.message||d)}})}return}g.writeHead(404),g.end("CursorBuddy local bridge")});return await new Promise((p,g)=>{P.once("error",g),P.listen(n,"127.0.0.1",()=>{m=P.address().port,P.off("error",g),p()})}),b("listening",{url:`${ge(m)}/cursorbuddy/health`}),{port:m,url:ge(m),secret:r,authHeader:ye,close(){return new Promise(p=>P.close(()=>p()))},getContext(){return l}}}import ne from"node:fs/promises";import rr from"node:os";import J from"node:path";var gt=200,yt=256*1024,or=2,sr=new Set([".md",".markdown",".txt"]);function ir(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function xe({cwd:e,memoryDir:t,homedir:n=rr.homedir()}={}){let r=String(t||"").trim();if(r)return r.startsWith("~")?J.join(n,r.slice(1)):J.resolve(r);let o=String(e||"").trim();return o?J.join(n,".claude","projects",ir(o),"memory"):null}async function Me(e){if(!e)return null;try{let t=await ne.realpath(e);return(await ne.stat(t)).isDirectory()?t:null}catch{return null}}async function ar(e,t){if(!e)throw new Error("memory root unavailable");let n=J.isAbsolute(String(t))?String(t):J.join(e,String(t)),r=await ne.realpath(n),o=e.endsWith(J.sep)?e:e+J.sep;if(r!==e&&!r.startsWith(o))throw new Error(`path escapes memory root: ${t}`);return r}function cr(e){let t=J.basename(e).toLowerCase();return t==="memory.md"?"index":t==="claude.md"?"instructions":"memory"}async function Ne(e,t,n,r){if(n>or||r.length>=gt)return;let o;try{o=await ne.readdir(t,{withFileTypes:!0})}catch{return}for(let s of o){if(r.length>=gt)break;if(s.name.startsWith("."))continue;let i=J.join(t,s.name);if(s.isDirectory())await Ne(e,i,n+1,r);else if(s.isFile()&&sr.has(J.extname(s.name).toLowerCase())){let c=J.relative(e,i);r.push({path:c,kind:cr(c)})}}}async function ur(e){let t=await Me(e);if(!t)return[];let n=[];return await Ne(t,t,0,n),n.sort((r,o)=>r.kind==="index"?-1:o.kind==="index"?1:r.path.localeCompare(o.path)),n}async function lr(e,t){let n=await Me(e),r=await ar(n,t),o=await ne.readFile(r),s=o.length>yt;return{content:o.subarray(0,yt).toString("utf8"),byteSize:o.length,truncated:s}}async function St(e){let t=await Me(e);if(!t)return"";let n=[];await Ne(t,t,0,n),n.sort((o,s)=>o.path.localeCompare(s.path));let r=[];for(let o of n)try{let s=await ne.stat(J.join(t,o.path));r.push(`${o.path}:${s.size}:${Math.floor(s.mtimeMs)}`)}catch{}return r.join("|")}async function wt(e){let t=await ur(e),n=[];for(let r of t)try{let{content:o,byteSize:s}=await lr(e,r.path);n.push({path:r.path,kind:r.kind,content:o,byteSize:s})}catch{}return n}import bt from"node:fs";import re from"node:path";import _t from"node:os";function dr(e){try{return bt.statSync(e).isDirectory()}catch{return!1}}function Oe(e){try{return bt.readdirSync(e,{withFileTypes:!0})}catch{return[]}}function vt({home:e=_t.homedir(),cwd:t=process.cwd()}={}){let n=[e&&re.join(e,".claude","commands"),t&&re.join(t,".claude","commands")].filter(Boolean),r=new Set,o=[],s=(i,c)=>{if(!i)return;let u=c?`${c}:${i}`:i;r.has(u)||(r.add(u),o.push({name:i,parent:c||null}))};for(let i of n)for(let c of Oe(i)){if(c.name.startsWith("."))continue;if(c.name.endsWith(".md")){s(c.name.slice(0,-3),null);continue}let u=re.join(i,c.name);if(c.isDirectory()||c.isSymbolicLink()&&dr(u))for(let a of Oe(u))a.name.startsWith(".")||a.name.endsWith(".md")&&s(a.name.slice(0,-3),c.name)}return o}function Et({home:e=_t.homedir(),cwd:t=process.cwd()}={}){let n=[e&&re.join(e,".claude","skills"),e&&re.join(e,".codex","skills"),t&&re.join(t,".claude","skills")].filter(Boolean),r=new Set;for(let o of n)for(let s of Oe(o))s.name.startsWith(".")||(s.name.endsWith(".md")?r.add(s.name.slice(0,-3)):(s.isDirectory()||s.isSymbolicLink())&&r.add(s.name));return[...r].sort()}import{readFile as mr}from"node:fs/promises";var fr=new Set(["127.0.0.1","localhost","::1","[::1]"]);function kt(e,t,n){let r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(n,Math.trunc(r))):t}function pr(e,t){if(!e||typeof e!="object"||e.shared===!1)return null;let n=String(e.id||e.upstreamModel||`model-${t+1}`).trim();if(!n)return null;if(!/^[a-zA-Z0-9._:@/-]+$/.test(n))throw new Error(`Shared model id '${n}' may only contain letters, numbers, dot, underscore, colon, at, slash, or dash.`);let r=new URL(String(e.baseUrl||"http://127.0.0.1:11434/v1"));if(!fr.has(r.hostname))throw new Error(`Shared model '${n}' must use a loopback endpoint.`);if(!["http:","https:"].includes(r.protocol))throw new Error(`Shared model '${n}' must use an HTTP endpoint.`);return{id:n.slice(0,160),name:String(e.name||n).trim().slice(0,160)||n,provider:String(e.provider||"local").trim().slice(0,80)||"local",protocol:"openai-chat",baseUrl:r.toString().replace(/\/$/,""),upstreamModel:String(e.upstreamModel||n).trim().slice(0,200)||n,apiKeyEnv:String(e.apiKeyEnv||"").trim().slice(0,120),capabilities:[...new Set((Array.isArray(e.capabilities)?e.capabilities:["text","streaming"]).map(o=>String(o||"").trim().toLowerCase()).filter(Boolean))].slice(0,16),...e.contextWindow?{contextWindow:kt(e.contextWindow,void 0,1e7)}:{},maxConcurrency:kt(e.maxConcurrency,1,64),shared:!0}}async function Ct(e){if(!e)return[];let t=JSON.parse(await mr(e,"utf8")),n=Array.isArray(t)?t:t?.models;if(!Array.isArray(n))throw new Error("Shared model config must contain a models array.");return n.slice(0,32).map(pr).filter(Boolean)}function It(e){return(Array.isArray(e)?e:[]).filter(t=>t?.shared).map(t=>({id:t.id,name:t.name,provider:t.provider,protocol:t.protocol,upstreamModel:t.upstreamModel,capabilities:[...t.capabilities],...t.contextWindow?{contextWindow:t.contextWindow}:{},maxConcurrency:t.maxConcurrency,shared:!0}))}async function At({models:e,request:t,send:n,signal:r,fetchImpl:o=fetch,env:s=process.env}){let i=String(t?.requestId||"").trim();if(!i)throw new Error("Inference requestId is required.");let c=(Array.isArray(e)?e:[]).find(S=>S.id===t?.model);if(!c)throw new Error(`Shared model '${t?.model||""}' is not available.`);let u={"content-type":"application/json"},a=c.apiKeyEnv?s[c.apiKeyEnv]:"";a&&(u.authorization=`Bearer ${a}`),n({action:"agent_inference_started",requestId:i,model:c.id});let{requestId:l,model:m,type:_,action:b,...h}=t,M=await o(`${c.baseUrl}/chat/completions`,{method:"POST",headers:u,body:JSON.stringify({...h,model:c.upstreamModel,stream:t.stream===!0}),signal:r});if(!M.ok){let S=await M.text().catch(()=>"");throw new Error(S||`Local model returned HTTP ${M.status}.`)}if(t.stream===!0){if(!M.body)throw new Error("Local model returned an empty stream.");let S=M.body.getReader(),E=new TextDecoder,I="",x,$=g=>{let A=g.trim();if(!A.startsWith("data:"))return!1;let d=A.slice(5).trim();if(!d)return!1;if(d==="[DONE]")return!0;try{let f=JSON.parse(d);f?.usage&&(x=f.usage),n({action:"agent_inference_delta",requestId:i,model:c.id,chunk:f})}catch{}return!1},P=!1;for(;!P;){let{done:g,value:A}=await S.read();I+=E.decode(A||new Uint8Array,{stream:!g});let d=I.split(/\r?\n/);I=g?"":d.pop()||"";for(let f of d)if($(f)){P=!0;break}if(g)break}I&&$(I);let p={action:"agent_inference_result",requestId:i,model:c.id,...x?{usage:x}:{}};return n(p),p}let w=await M.json();return n({action:"agent_inference_result",requestId:i,model:c.id,response:w}),w}import xt from"node:fs";import W from"node:fs/promises";import hr from"node:os";import K from"node:path";var Ot="status.json",Tt="heartbeat.json",Te="heartbeat.md",gr="agent.json",yr="soul.md",Sr=16*1024,wr=`# Heartbeat
|
|
20
|
+
`).trim()||"Say that the local Agensis runtime is connected."}function dt(e){let t=String(e||"").trim();if(!t)return"";try{let n=JSON.parse(t);if(typeof n?.result=="string")return n.result;if(typeof n?.message=="string")return n.message;if(typeof n?.content=="string")return n.content}catch{}return t}function Vn(e){let t=Array.isArray(e?.messages)?e.messages:[];for(let n=t.length-1;n>=0;n-=1){let r=t[n];if(String(r?.role||"user")!=="user")continue;let s=String(r?.content||"").trim();if(s)return s}return""}function Qn(e,t=280){let n=Vn(e).replace(/\s+/g," ").trim();if(!n)return"";if(n.length<=t)return n;let r=[/\b(tell me (?:a )?joke)\b/i,/\b(make (?:him|the buddy|cursorbuddy|avatar) wave|wave(?: hello)?|say hi|say hello)\b/i,/\b(what site|which site|what page|where am i|where are you|current url)\b/i,/\b(are you connected|connected|working|online|there)\b/i,/\b(show|guide|tour|walk|around|sections?|features?|important|highlight|what can i do|what should i do|help me)\b/i,/\b(open|show|bring up|get back|display)\b.{0,80}\b(prompt|bubble|dialog|panel|options|menu)\b/i,/\b(hide|hush|close|dismiss|clear|stop|cancel|be quiet)\b.{0,80}\b(bubble|prompt|dialog|panel|options|menu)?\b/i,/^(hi|hello|hey|yo|sup)\b/i];for(let s of r){let o=n.match(s);if(o?.[0])return o[0].trim()}return n.slice(-t).trim()}function Zn(e){let t=Qn(e);if(!t)return null;if(/\b(?:him|the buddy|cursorbuddy|cursor buddy|avatar|buddy|pet|character)\b/i.test(t)&&/\bwave(?: hello)?\b/i.test(t))return{content:"Waving now.",command:{action:"wave",text:"Hi. How can I help?",source:"chat"}};let r=t.match(/^(?:say|speak)\s+(.{1,180})$/i)||t.match(/\b(?:make|tell)\s+(?:him|the buddy|cursorbuddy|avatar)\s+(?:say|speak)\s+(.{1,180})$/i);return r?.[1]?{content:"Saying it now.",command:{action:"say",text:r[1].trim(),source:"chat"}}:/^(stop|cancel|dismiss|close|hide|hush|be quiet)\b/i.test(t)?{content:"Closed.",command:{action:"hush",source:"chat"}}:/\b(open|show)\b.*\b(options|chat|bubble|prompt)\b/i.test(t)?{content:"Opening options.",command:{action:"open",text:"What should I help with?",source:"chat"}}:null}function er(e){let t=String(e||"").trim();return t?/\s/.test(t)||t.startsWith("-")?!0:/^(claude|codex|node|npm|bun|python|python3|sh|bash|zsh)(?:$|\.)/.test(t):!1}function ht(e,t){let n=String(e||"").trim();return!n||er(n)?t:n}function gt(e){let t=String(e||"").trim();return!t||t==="haiku-4.5"||t==="claude-haiku-4.5"?Ce:t}function xe(e={}){return gt(e.cursorBuddyModel||X.env.AGENSIS_CURSORBUDDY_MODEL||Ce)}function mt(e,t,n,r={}){let{cmd:s,args:o}=Yn(e.codingCmd||"claude -p"),i=[...o],c=gt(ht(n,xe(e))),u="",a=!1;return Xn(s)?(c&&!he(i,"--model")&&i.push("--model",c),r.stream===!0&&!he(i,"--output-format")?(i.push("--output-format","stream-json","--include-partial-messages"),he(i,"--verbose")||i.push("--verbose"),a=!0):(he(i,"--output-format")||i.push("--output-format","json"),a=i.some(m=>String(m).includes("stream-json"))),u=t):i.push(t),{cmd:s,args:i,model:c,stdin:u,streamJson:a}}function tr(e=()=>{}){let t="",n="",r=!1,s="",o=null,i=a=>{a&&e(a)},c=a=>{if(!a||typeof a!="object")return;let l=a.event&&a.event.delta||a.delta;if(l&&l.type==="text_delta"&&typeof l.text=="string"){r=!0,n+=l.text,i(l.text);return}if(a.type==="result"&&typeof a.result=="string"){o=a.result;return}if(a.type==="assistant"&&a.message&&Array.isArray(a.message.content)){let m=a.message.content.filter(g=>g&&g.type==="text"&&typeof g.text=="string").map(g=>g.text).join("");m&&(s+=m)}},u=a=>{let l=String(a).trim();if(l)try{c(JSON.parse(l))}catch{}};return{feed(a){t+=String(a||"");let l;for(;(l=t.indexOf(`
|
|
21
|
+
`))>=0;)u(t.slice(0,l)),t=t.slice(l+1)},end(){t&&(u(t),t="")},get live(){return r?n:s},get result(){return o??(r?n:s)}}}function te(e,t,n,r=null){return{id:e,object:"chat.completion.chunk",created:Math.floor(Date.now()/1e3),model:t,choices:[{index:0,delta:n?{content:n}:{},finish_reason:r}]}}function ge(e){return`http://127.0.0.1:${e}`}function nr(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function rr(e){return String(e||"").slice(0,18)}function U(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function or(e={},t={},n={}){let r=U(e.metadata)||{},s=U(e.page)||U(r.page)||{},o=U(e.client)||U(r.client)||{},i=U(r.runtime)||{},c=U(e.manifest)||U(r.manifest)||null;return{url:String(e.url||s.url||r.websiteSource||e.websiteSource||"").slice(0,2048),title:String(e.title||s.title||"").slice(0,300),surface:String(e.surface||i.surface||t.surface||"").slice(0,80),instanceId:String(e.instanceId||i.instanceId||"").slice(0,140),workspaceId:String(t.workspaceId||e.workspaceId||n.workspace||"").slice(0,120),agentId:String(t.agentId||e.agentId||n.agent||"").slice(0,120),runtime:{...i,local:!0,connected:!0,connection:t},page:s,client:o,project:U(e.project)||U(r.project)||null,manifest:c,selection:U(e.selection)||null,updatedAt:new Date().toISOString()}}function sr(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function ir(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!jn.test(r))throw new Error("Connection key format is invalid. Create a fresh CursorBuddy key first.");if(typeof n!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let s=nr(e,t),o=await n(`${s}/backend/cursorbuddy/connection-keys/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:r,baseUrl:s,host:pt.hostname(),cwd:t.cwd||e.cwd||X.cwd(),name:t.name||e.name||e.handle||"CursorBuddy runtime",surface:t.surface||"browser_extension",scope:t.scope||"machine",runtimeKind:t.runtimeKind||"agensis-cli-local-bridge",version:t.version||e.version||X.env.npm_package_version||"",permissionMode:t.permissionMode||e.permissionMode,model:t.model||e.model,metadata:U(t.metadata)||null,websiteSource:t.websiteSource||t.metadata?.websiteSource||"",page:U(t.page)||U(t.metadata?.page)||null,client:U(t.client)||U(t.metadata?.client)||null,manifest:U(t.manifest)||U(t.metadata?.manifest)||null})}),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(sr(o,i));return{key:r,baseUrl:s,data:i?.data||i}}async function yt(e,t={}){let n=Number(t.port??e.cursorBuddyPort??X.env.AGENSIS_CURSORBUDDY_PORT??ct),r=Wn(e,t),s=new Date().toISOString(),o=[],i=[],c=new Set,u=t.fetchImpl||globalThis.fetch,a=1,l=null,m=n,g=null,S=(h,w={})=>{let M={ts:new Date().toISOString(),event:h,detail:w};return o.push(M),o.length>200&&o.shift(),t.log?.(`CursorBuddy local bridge: ${h}${Object.keys(w).length?` ${JSON.stringify(w)}`:""}`),M},f=()=>({connected:!!e.cursorBuddyRuntime,mode:e.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:e.agent,workspaceId:e.workspace,agensisUrl:e.url,handle:e.handle,name:e.name,cwd:e.cwd,updatedAt:new Date().toISOString()}),x=()=>{if(typeof t.connectionProvider!="function")return null;try{let h=t.connectionProvider();return!h||typeof h!="object"||Array.isArray(h)?null:{...f(),...h,connected:h.connected===!0}}catch{return null}},_=()=>{let h=x();return h?.connected===!1?h:g?{...f(),...h||{},...g,connected:!0,updatedAt:h?.updatedAt||g.updatedAt}:h||f()};function y(h={}){if(!h||typeof h!="object"||Array.isArray(h))return null;let w=String(h.action||h.type||"").trim().toLowerCase();if(!Hn.has(w))return null;let M={id:a++,ts:new Date().toISOString(),action:w,text:String(h.text||h.say||h.message||"").slice(0,1200),label:String(h.label||"").slice(0,80),value:String(h.value||h.prompt||"").slice(0,1200),holdMs:Number.isFinite(h.holdMs)?Math.max(0,Math.min(6e4,h.holdMs)):void 0,source:String(h.source||"agensis-daemon").slice(0,80)};return h.options&&Array.isArray(h.options)&&(M.options=h.options.map(d=>({label:String(d?.label||"").slice(0,80),value:String(d?.value||d?.task||"").slice(0,1200)})).filter(d=>d.label).slice(0,6)),M}function I(h){for(i.push(h);i.length>Gn;)i.shift();S("control",{id:h.id,action:h.action,chars:h.text.length});for(let w of[...c])try{H(w,{type:"command",command:h})}catch{c.delete(w)}return h}function A(h){let w=Zn(h);if(w){let M=y(w.command);return M&&(I(M),S("chat_control",{id:M.id,action:M.action})),{content:w.content,model:"cursorbuddy-local-control",fast:!0}}return null}async function E(h){let w=A(h);if(w)return w;let M=lt(h?.messages,l),d=mt(e,M,h?.model),p=await ie({cmd:d.cmd,args:d.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:d.stdin});if(p.error||p.status!==0)throw new Error(p.error?.message||String(p.stderr||"").trim()||`Command exited with status ${p.status}`);return{content:dt(p.stdout||p.stderr),model:d.model}}async function P(h,w){let M=`agensis-cursorbuddy-${Date.now()}`,d=A(h);if(d){let T=d.model||"cursorbuddy-local-control";return H(w,te(M,T,d.content)),H(w,te(M,T,"","stop")),H(w,"[DONE]"),S("chat_fast",{chars:d.content.length,model:T}),{content:d.content,model:T,fast:!0}}let p=lt(h?.messages,l),v=mt(e,p,h?.model,{stream:!0}),D="",C=T=>{T&&(D+=T,H(w,te(M,v.model||e.model,T)))},N=v.streamJson?tr(C):null,b=await ie({cmd:v.cmd,args:v.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:v.stdin,onData:T=>{if(N)N.feed(T);else{let F=String(T||"");D+=F,H(w,te(M,v.model||e.model,F))}}});if(N){N.end();let T=N.result||"";!D&&T?C(T):D=T||D}if(b.error||b.status!==0){let T=b.error?.message||String(b.stderr||"").trim()||`Command exited with status ${b.status}`;throw new Error(T)}let O=N?D:dt(D||b.stdout||b.stderr);return!N&&O&&O!==D&&(H(w,te(M,v.model||e.model,O)),D=O),H(w,te(M,v.model||e.model,"","stop")),H(w,"[DONE]"),{content:D||O,model:v.model}}let B=Fn.createServer(async(h,w)=>{if(w.setHeader("access-control-allow-origin","*"),w.setHeader("access-control-allow-methods","GET, POST, OPTIONS"),w.setHeader("access-control-allow-headers","content-type, authorization, x-agensis-bridge-secret"),h.method==="OPTIONS"){w.writeHead(204),w.end();return}let M=new URL(h.url||"/",ge(m||ct));if(!qn(h.method,M.pathname)&&!zn(h,r)){j(w,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(h.method==="GET"&&M.pathname==="/cursorbuddy/health"){let d=ge(m);j(w,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:xe(e),daemonModel:e.model,port:m,host:pt.hostname(),pid:X.pid,bootedAt:s,authRequired:!0,authHeader:ye,stream:!0,streaming:!0,supportsStreaming:!0,chatStream:!0,capabilities:{chatStream:!0,controlStream:!0,fastAvatarReplies:!1,nativeCursorBuddyControl:!0},latestControlId:i.at(-1)?.id||0,connection:_(),context:l,endpoints:{chat:`${d}/v1/chat/completions`,chatStream:`${d}/v1/chat/completions`,edit:`${d}/cursorbuddy/edit`,context:`${d}/cursorbuddy/context`,control:`${d}/cursorbuddy/control`,controlStream:`${d}/cursorbuddy/control/stream`,logs:`${d}/cursorbuddy/logs`}});return}if(h.method==="GET"&&M.pathname==="/cursorbuddy/logs"){j(w,200,{ok:!0,events:o.slice(-100)});return}if(h.method==="GET"&&M.pathname==="/cursorbuddy/context"){j(w,200,{ok:!0,context:l});return}if(h.method==="GET"&&M.pathname==="/cursorbuddy/control"){let d=Number(M.searchParams.get("after")||0),p=i.filter(v=>v.id>d);j(w,200,{ok:!0,commands:p,latestId:i.at(-1)?.id||0});return}if(h.method==="GET"&&M.pathname==="/cursorbuddy/control/stream"){let d=Number(M.searchParams.get("after")||0);ut(w),c.add(w),H(w,{type:"ready",latestId:i.at(-1)?.id||0});for(let v of i.filter(D=>D.id>d))H(w,{type:"command",command:v});let p=setInterval(()=>{try{H(w,{type:"ping",ts:new Date().toISOString()})}catch{c.delete(w),clearInterval(p)}},15e3);p.unref&&p.unref(),h.on("close",()=>{c.delete(w),clearInterval(p)});return}if(h.method==="POST"&&M.pathname==="/cursorbuddy/control"){try{let d=JSON.parse(await ae(h)||"{}"),p=y(d);if(!p){j(w,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let v=I(p);j(w,200,{ok:!0,command:v})}catch(d){S("control_error",{error:String(d?.message||d)}),j(w,400,{ok:!1,error:String(d?.message||d)})}return}if(h.method==="POST"&&M.pathname==="/cursorbuddy/context"){try{let d=JSON.parse(await ae(h)||"{}");l={url:String(d.url||"").slice(0,2048),title:String(d.title||"").slice(0,300),surface:String(d.surface||"").slice(0,80),instanceId:String(d.instanceId||"").slice(0,140),workspaceId:String(d.workspaceId||e.workspace||"").slice(0,120),agentId:String(d.agentId||e.agent||"").slice(0,120),runtime:d.runtime&&typeof d.runtime=="object"?d.runtime:null,page:d.page&&typeof d.page=="object"?d.page:null,client:d.client&&typeof d.client=="object"?d.client:null,project:d.project&&typeof d.project=="object"?d.project:null,manifest:d.manifest&&typeof d.manifest=="object"?d.manifest:null,selection:d.selection&&typeof d.selection=="object"?d.selection:null,updatedAt:new Date().toISOString()},S("context",{url:l.url,surface:l.surface,instanceId:l.instanceId}),j(w,200,{ok:!0,context:l})}catch(d){S("context_error",{error:String(d?.message||d)}),j(w,400,{ok:!1,error:String(d?.message||d)})}return}if(h.method==="POST"&&M.pathname==="/cursorbuddy/connect"){try{let d=JSON.parse(await ae(h)||"{}"),p=await ir(e,d,u),v=p.data||{};g={connected:!0,mode:"agensis-claimed",keyId:rr(p.key),agentId:String(v.agentId||v.agent?.id||e.agent||""),workspaceId:String(v.workspaceId||v.workspace_id||v.agent?.workspace_id||e.workspace||""),agensisUrl:p.baseUrl,handle:String(v.handle||v.agent?.handle||e.handle||""),name:String(v.agent?.name||d.name||e.name||"CursorBuddy runtime"),cwd:String(d.cwd||e.cwd||X.cwd()),surface:String(d.surface||"browser_extension"),command:String(v.command||v.localCommand||""),updatedAt:new Date().toISOString()},l=or(d,g,e),S("connect",{mode:g.mode,keyId:g.keyId,agentId:g.agentId,workspaceId:g.workspaceId,url:l.url}),j(w,200,{ok:!0,connection:g,claim:v})}catch(d){S("connect_error",{error:String(d?.message||d)}),j(w,400,{ok:!1,error:String(d?.message||d)})}return}if(h.method==="POST"&&M.pathname==="/cursorbuddy/edit"){try{let d=JSON.parse(await ae(h)||"{}"),p=[{role:"system",content:"You are the local CursorBuddy edit agent. The user selected a DOM element in their own site. Use the payload to inspect and change the local checkout, then report what changed."},{role:"user",content:JSON.stringify(d,null,2)}];S("edit_request",{selector:d?.target?.selector||""});let v=await E({messages:p,model:d?.model});S("edit_done",{chars:v.content.length}),j(w,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:v.content})}catch(d){S("edit_error",{error:String(d?.message||d)}),j(w,500,{ok:!1,error:String(d?.message||d)})}return}if(h.method==="POST"&&M.pathname.endsWith("/chat/completions")){try{let d=JSON.parse(await ae(h)||"{}");if(S("chat_request",{messages:Array.isArray(d.messages)?d.messages.length:0,model:ht(d.model,xe(e))}),d.stream===!0){ut(w);let v=await P(d,w);S("chat_done",{chars:v.content.length,stream:!0,fast:v.fast===!0}),w.end();return}let p=await E(d);S("chat_done",{chars:p.content.length,fast:p.fast===!0}),j(w,200,{id:`agensis-cursorbuddy-${Date.now()}`,object:"chat.completion",model:p.model||d.model||e.model,choices:[{index:0,message:{role:"assistant",content:p.content},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}catch(d){S("chat_error",{error:String(d?.message||d)}),j(w,500,{error:{message:String(d?.message||d)}})}return}w.writeHead(404),w.end("CursorBuddy local bridge")});return await new Promise((h,w)=>{B.once("error",w),B.listen(n,"127.0.0.1",()=>{m=B.address().port,B.off("error",w),h()})}),S("listening",{url:`${ge(m)}/cursorbuddy/health`}),{port:m,url:ge(m),secret:r,authHeader:ye,close(){return new Promise(h=>B.close(()=>h()))},getContext(){return l}}}import ne from"node:fs/promises";import ar from"node:os";import J from"node:path";var St=200,wt=256*1024,cr=2,ur=new Set([".md",".markdown",".txt"]);function lr(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function Me({cwd:e,memoryDir:t,homedir:n=ar.homedir()}={}){let r=String(t||"").trim();if(r)return r.startsWith("~")?J.join(n,r.slice(1)):J.resolve(r);let s=String(e||"").trim();return s?J.join(n,".claude","projects",lr(s),"memory"):null}async function Oe(e){if(!e)return null;try{let t=await ne.realpath(e);return(await ne.stat(t)).isDirectory()?t:null}catch{return null}}async function dr(e,t){if(!e)throw new Error("memory root unavailable");let n=J.isAbsolute(String(t))?String(t):J.join(e,String(t)),r=await ne.realpath(n),s=e.endsWith(J.sep)?e:e+J.sep;if(r!==e&&!r.startsWith(s))throw new Error(`path escapes memory root: ${t}`);return r}function mr(e){let t=J.basename(e).toLowerCase();return t==="memory.md"?"index":t==="claude.md"?"instructions":"memory"}async function Ne(e,t,n,r){if(n>cr||r.length>=St)return;let s;try{s=await ne.readdir(t,{withFileTypes:!0})}catch{return}for(let o of s){if(r.length>=St)break;if(o.name.startsWith("."))continue;let i=J.join(t,o.name);if(o.isDirectory())await Ne(e,i,n+1,r);else if(o.isFile()&&ur.has(J.extname(o.name).toLowerCase())){let c=J.relative(e,i);r.push({path:c,kind:mr(c)})}}}async function fr(e){let t=await Oe(e);if(!t)return[];let n=[];return await Ne(t,t,0,n),n.sort((r,s)=>r.kind==="index"?-1:s.kind==="index"?1:r.path.localeCompare(s.path)),n}async function pr(e,t){let n=await Oe(e),r=await dr(n,t),s=await ne.readFile(r),o=s.length>wt;return{content:s.subarray(0,wt).toString("utf8"),byteSize:s.length,truncated:o}}async function bt(e){let t=await Oe(e);if(!t)return"";let n=[];await Ne(t,t,0,n),n.sort((s,o)=>s.path.localeCompare(o.path));let r=[];for(let s of n)try{let o=await ne.stat(J.join(t,s.path));r.push(`${s.path}:${o.size}:${Math.floor(o.mtimeMs)}`)}catch{}return r.join("|")}async function _t(e){let t=await fr(e),n=[];for(let r of t)try{let{content:s,byteSize:o}=await pr(e,r.path);n.push({path:r.path,kind:r.kind,content:s,byteSize:o})}catch{}return n}import vt from"node:fs";import re from"node:path";import Et from"node:os";function hr(e){try{return vt.statSync(e).isDirectory()}catch{return!1}}function Te(e){try{return vt.readdirSync(e,{withFileTypes:!0})}catch{return[]}}function kt({home:e=Et.homedir(),cwd:t=process.cwd()}={}){let n=[e&&re.join(e,".claude","commands"),t&&re.join(t,".claude","commands")].filter(Boolean),r=new Set,s=[],o=(i,c)=>{if(!i)return;let u=c?`${c}:${i}`:i;r.has(u)||(r.add(u),s.push({name:i,parent:c||null}))};for(let i of n)for(let c of Te(i)){if(c.name.startsWith("."))continue;if(c.name.endsWith(".md")){o(c.name.slice(0,-3),null);continue}let u=re.join(i,c.name);if(c.isDirectory()||c.isSymbolicLink()&&hr(u))for(let a of Te(u))a.name.startsWith(".")||a.name.endsWith(".md")&&o(a.name.slice(0,-3),c.name)}return s}function It({home:e=Et.homedir(),cwd:t=process.cwd()}={}){let n=[e&&re.join(e,".claude","skills"),e&&re.join(e,".codex","skills"),t&&re.join(t,".claude","skills")].filter(Boolean),r=new Set;for(let s of n)for(let o of Te(s))o.name.startsWith(".")||(o.name.endsWith(".md")?r.add(o.name.slice(0,-3)):(o.isDirectory()||o.isSymbolicLink())&&r.add(o.name));return[...r].sort()}import{readFile as gr}from"node:fs/promises";var yr=new Set(["127.0.0.1","localhost","::1","[::1]"]);function At(e,t,n){let r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(n,Math.trunc(r))):t}function Sr(e,t){if(!e||typeof e!="object"||e.shared===!1)return null;let n=String(e.id||e.upstreamModel||`model-${t+1}`).trim();if(!n)return null;if(!/^[a-zA-Z0-9._:@/-]+$/.test(n))throw new Error(`Shared model id '${n}' may only contain letters, numbers, dot, underscore, colon, at, slash, or dash.`);let r=new URL(String(e.baseUrl||"http://127.0.0.1:11434/v1"));if(!yr.has(r.hostname))throw new Error(`Shared model '${n}' must use a loopback endpoint.`);if(!["http:","https:"].includes(r.protocol))throw new Error(`Shared model '${n}' must use an HTTP endpoint.`);return{id:n.slice(0,160),name:String(e.name||n).trim().slice(0,160)||n,provider:String(e.provider||"local").trim().slice(0,80)||"local",protocol:"openai-chat",baseUrl:r.toString().replace(/\/$/,""),upstreamModel:String(e.upstreamModel||n).trim().slice(0,200)||n,apiKeyEnv:String(e.apiKeyEnv||"").trim().slice(0,120),capabilities:[...new Set((Array.isArray(e.capabilities)?e.capabilities:["text","streaming"]).map(s=>String(s||"").trim().toLowerCase()).filter(Boolean))].slice(0,16),...e.contextWindow?{contextWindow:At(e.contextWindow,void 0,1e7)}:{},maxConcurrency:At(e.maxConcurrency,1,64),shared:!0}}async function Ct(e){if(!e)return[];let t=JSON.parse(await gr(e,"utf8")),n=Array.isArray(t)?t:t?.models;if(!Array.isArray(n))throw new Error("Shared model config must contain a models array.");return n.slice(0,32).map(Sr).filter(Boolean)}function xt(e){return(Array.isArray(e)?e:[]).filter(t=>t?.shared).map(t=>({id:t.id,name:t.name,provider:t.provider,protocol:t.protocol,upstreamModel:t.upstreamModel,capabilities:[...t.capabilities],...t.contextWindow?{contextWindow:t.contextWindow}:{},maxConcurrency:t.maxConcurrency,shared:!0}))}async function Mt({models:e,request:t,send:n,signal:r,fetchImpl:s=fetch,env:o=process.env}){let i=String(t?.requestId||"").trim();if(!i)throw new Error("Inference requestId is required.");let c=(Array.isArray(e)?e:[]).find(y=>y.id===t?.model);if(!c)throw new Error(`Shared model '${t?.model||""}' is not available.`);let u={"content-type":"application/json"},a=c.apiKeyEnv?o[c.apiKeyEnv]:"";a&&(u.authorization=`Bearer ${a}`),n({action:"agent_inference_started",requestId:i,model:c.id});let{requestId:l,model:m,type:g,action:S,...f}=t,x=await s(`${c.baseUrl}/chat/completions`,{method:"POST",headers:u,body:JSON.stringify({...f,model:c.upstreamModel,stream:t.stream===!0}),signal:r});if(!x.ok){let y=await x.text().catch(()=>"");throw new Error(y||`Local model returned HTTP ${x.status}.`)}if(t.stream===!0){if(!x.body)throw new Error("Local model returned an empty stream.");let y=x.body.getReader(),I=new TextDecoder,A="",E,P=w=>{let M=w.trim();if(!M.startsWith("data:"))return!1;let d=M.slice(5).trim();if(!d)return!1;if(d==="[DONE]")return!0;try{let p=JSON.parse(d);p?.usage&&(E=p.usage),n({action:"agent_inference_delta",requestId:i,model:c.id,chunk:p})}catch{}return!1},B=!1;for(;!B;){let{done:w,value:M}=await y.read();A+=I.decode(M||new Uint8Array,{stream:!w});let d=A.split(/\r?\n/);A=w?"":d.pop()||"";for(let p of d)if(P(p)){B=!0;break}if(w)break}A&&P(A);let h={action:"agent_inference_result",requestId:i,model:c.id,...E?{usage:E}:{}};return n(h),h}let _=await x.json();return n({action:"agent_inference_result",requestId:i,model:c.id,response:_}),_}import Ot from"node:fs";import z from"node:fs/promises";import wr from"node:os";import K from"node:path";var $t="status.json",Bt="heartbeat.json",$e="heartbeat.md",br="agent.json",_r="soul.md",vr=16*1024,Er=`# Heartbeat
|
|
21
22
|
|
|
22
23
|
This file tells you what to do on each heartbeat \u2014 the recurring "still here, still
|
|
23
24
|
working" moment. Edit it freely; the daemon reads it but never overwrites your edits.
|
|
@@ -30,30 +31,30 @@ On each heartbeat:
|
|
|
30
31
|
- If you've finished and there's nothing to do, a short idle note is fine.
|
|
31
32
|
|
|
32
33
|
Add your own recurring checks below.
|
|
33
|
-
`,
|
|
34
|
-
`),
|
|
35
|
-
`}async function De(e){let t=K.join(oe(e),Ot),n;try{let c=await W.stat(t);if(!c.isFile()||c.size>br)return null;n=await W.readFile(t,"utf8")}catch{return null}let r;try{r=JSON.parse(n)}catch{return null}if(!r||typeof r!="object"||Array.isArray(r))return null;let o=Nt(r.status),s=Nt(r.note??r.message);if(!o&&!s)return null;let i={};return o&&(i.status=o),s&&(i.note=s),r.ts!=null&&Number.isFinite(Number(r.ts))&&(i.ts=Number(r.ts)),i}function Nt(e){return e==null?"":String(e).trim().replace(/\s+/g," ").slice(0,_r)}async function Lt(e){let t=await Be(e);if(!t)return!1;let n=K.join(t,Te);try{return await W.access(n),!0}catch{}return Se(n,wr)}async function Ut(e){let t=K.join(oe(e),Te);try{let n=await W.stat(t);return!n.isFile()||n.size>Sr?null:(await W.readFile(t,"utf8")).trim()||null}catch{return null}}var Er=30*60*1e3,kr=15*1e3,Ft=2,Cr=10*1024,Ir="claude-opus-4-8",Z="0.1.28";async function we(e={}){let t=Ar(e);t.sharedModels=t.share?await Ct(t.sharedModelsFile):[];let n=!1,r=null,o=null,s=null,i=null,c=0,u=null,a=null,l="",m=null,_=!1,b=null,h=new Map,M=null,w={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},S=new Map,E=new Map,I=[],x=()=>w,$=()=>({connected:_&&!!t.cursorBuddyRuntime,mode:t.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:b?.agentId||b?.agent_id||t.agent,workspaceId:b?.workspaceId||b?.workspace_id||t.workspace,agensisUrl:t.url,handle:b?.handle||t.handle,name:b?.name||t.name,cwd:t.cwd,updatedAt:new Date().toISOString()}),P=()=>{M||!t.lanListener||(M=new ue.Server({port:0}),M.on("listening",()=>{let{port:C}=M.address();w={transport:"ws",listening:!0,addrs:Vr(C),auth:"hub-pairwise"},B(`Agent-mesh LAN listener on port ${C}`),ce(r,t,x())}),M.on("connection",C=>{let O=!1,y=setTimeout(()=>{if(!O)try{C.close(1008,"peer auth required")}catch{}},5e3);C.once("message",N=>{clearTimeout(y);let T=Re(N),F=T?.type==="peer_auth"?S.get(T.ticket):null;if(!F||F.fromAgentId!==T.fromAgentId||Date.now()>F.exp){try{C.close(1008,"invalid ticket")}catch{}return}S.delete(T.ticket),O=!0,C.on("message",G=>{let R=Re(G);R?.type==="agent_job"&&R.job?.id&&a.enqueue({...R.job,key:R.job.id,lane:jt(R.job),ws:r}).accepted&&B(`Queued peer-handoff job ${R.job.id} from ${T.fromAgentId}`)})})}),M.on("error",C=>B(`LAN listener error: ${C?.message||C}`)))},p=()=>{if(M){try{M.close()}catch{}M=null}w={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},g=C=>new Promise((O,y)=>{if(!L(r,{action:"peer_ticket_request",targetAgentId:C})){y(new Error("hub socket not open"));return}let N=E.get(C)||[];N.push({resolve:O,reject:y}),E.set(C,N),setTimeout(()=>{let T=E.get(C)||[],F=T.findIndex(G=>G.resolve===O);F>=0&&(T.splice(F,1),y(new Error("peer ticket request timed out")))},1e4)}),A=()=>new Promise((C,O)=>{if(!L(r,{action:"peer_list_request"})){O(new Error("hub socket not open"));return}I.push(C),setTimeout(()=>{let y=I.indexOf(C);y>=0&&(I.splice(y,1),C([]))},1e4)}),d=async(C,O)=>{let y=null;try{let T=(await A()).find(R=>R.agentId===C&&R.reach?.listening&&R.reach.addrs?.length);if(!T)return!1;let F=await g(C),G=F.peer?.addrs?.[0]||T.reach.addrs[0];return!G?.host||!G?.port?!1:(y=new ue(`ws://${G.host}:${G.port}`),await new Promise((R,Ee)=>{y.once("open",R),y.once("error",Ee),setTimeout(()=>Ee(new Error("peer connect timed out")),5e3)}),L(y,{type:"peer_auth",ticket:F.ticket,fromAgentId:t.agent}),L(y,{type:"agent_job",job:O}),!0)}catch(N){return B(`Peer handoff to ${C} failed, falling back to hub relay: ${N?.message||N}`),!1}finally{try{y?.close()}catch{}}},f=()=>{n=!0,Kt(h),o&&clearTimeout(o),s&&clearInterval(s),i&&clearInterval(i),m&&(m.close().catch(()=>{}),m=null),p(),Pt(t,{status:"stopped",connected:!1});try{r?.close()}catch{}u&&u()};if(a=st({concurrency:t.once?1:t.maxConcurrency,runJob:async(C,O)=>{await Gr(t,C,O),t.once&&f()}}),t.cursorBuddyBridge)try{m=await ht(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:B,connectionProvider:$}),m?.secret&&(t.cursorBuddyBridgeSecret=m.secret)}catch(C){if(to(C)){let O=await no(t.cursorBuddyPort);if(O?.ok){let y=O.pid?` pid ${O.pid}`:"";B(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${y}`)}else B(`CursorBuddy local bridge port ${t.cursorBuddyPort} is in use but did not answer health`)}else B(`CursorBuddy local bridge unavailable: ${C?.message||C}`);m=null}k.once("SIGINT",f),k.once("SIGTERM",f);let v=()=>{if(n)return;let C=Mr(t.url,t.token,t);l="",B(`Connecting to ${C.replace(t.token,"redacted")}`),r=new ue(C),r.on("open",()=>{_=!1,b=null,B(`Connected. Registering @${t.handle||"agent"} from ${t.cwd}`),L(r,{type:"auth",token:t.token}),L(r,{action:"agent_register",workspaceId:t.workspace,agentId:t.agent,handle:t.handle,name:t.name,host:me.hostname(),cwd:t.cwd,metadata:{codingCmd:t.codingCmd,model:t.model,permissionMode:t.permissionMode,permissionFlags:je(t.permissionMode),once:t.once,runtime:"agensis",version:Z}}),s=setInterval(()=>{Promise.all([Vt(t,x()).catch(()=>null),De(t).catch(()=>null)]).then(([O,y])=>{L(r,{action:"agent_heartbeat",...O?{capabilitiesHash:O.capabilitiesHash,memoryHash:O.memoryHash}:{},metadata:Pe(t,a,y,Wt(t)?m?.getContext?.():null,h)})})},t.heartbeatMs),s.unref&&s.unref()}),r.on("message",O=>{let y=Re(O);if(y){if(y.type==="agent_registered"){_=!0,b=y.connection||y.agent||null,Gt(t,y.agent),B(`Registered as ${y.connection?.name||t.name} on ${y.connection?.host||me.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,y)).catch(N=>{B(`Profile save failed: ${N?.message||N}`)}),$e(t,y.agent).catch(()=>{}),Lt(t).catch(()=>{}),Jt(r,t),P(),ce(r,t,x());return}if(y.type==="agent_config"){Gt(t,y.agent),B(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),$e(t,y.agent).catch(()=>{});return}if(y.type==="agent_memory_refresh"){Jt(r,t),ce(r,t,x());return}if(y.type==="agent_capabilities_refresh"){ce(r,t,x());return}if(y.type==="agent_inference_cancel"){h.get(String(y.requestId||""))?.abort();return}if(y.type==="agent_job_cancel"){let N=String(y.jobId||"");N&&a.cancel(N,y.reason||"Cancelled by Agensis")&&B(`Cancelled job ${N}`);return}if(y.type==="agent_inference_request"&&y.requestId){let N=String(y.requestId),T=t.sharedModels.find(R=>R.id===y.model),F=[...h.values()].filter(R=>R.model===y.model).length;if(!T){L(r,{action:"agent_inference_error",requestId:N,error:`Shared model '${y.model||""}' is not available.`});return}if(F>=T.maxConcurrency){L(r,{action:"agent_inference_error",requestId:N,error:"Shared model is at capacity.",code:"capacity_exhausted"});return}let G=new AbortController;h.set(N,{abort:()=>G.abort(),model:T.id}),L(r,{action:"agent_heartbeat",metadata:Pe(t,a,null,null,h)}),At({models:t.sharedModels,request:y,signal:G.signal,send:R=>L(r,R)}).catch(R=>{L(r,{action:"agent_inference_error",requestId:N,error:G.signal.aborted?"Inference cancelled.":R?.message||String(R),code:G.signal.aborted?"cancelled":"inference_failed"})}).finally(()=>{h.delete(N),L(r,{action:"agent_heartbeat",metadata:Pe(t,a,null,null,h)})});return}if(y.type==="peer_ticket"){let N=y.peer?.agentId,T=E.get(N)||[],F=T.shift();T.length?E.set(N,T):E.delete(N),F&&F.resolve(y);return}if(y.type==="peer_ticket_grant"){S.set(y.ticket,{fromAgentId:y.fromAgentId,exp:y.exp});return}if(y.type==="peer_list"){let N=I.shift();N&&N(Array.isArray(y.peers)?y.peers:[]);return}if(y.type==="agent_reach_disable"){p(),ce(r,t,x());return}if(y.type==="error"){B(`Server rejected request: ${y.message||"unknown error"}`);return}if(y.type==="agent_disabled"){_=!1,b=null,B(`Agent disabled by Agensis: ${y.reason||"deactivated"}`),f();return}if(y.type==="agent_job"&&y.job?.id){let N=a.enqueue({...y.job,key:y.job.id,lane:jt(y.job),ws:r});N.accepted&&(c+=1,B(`Queued job ${y.job.id} at position ${N.position}`),t.once&&a.idle().then(()=>f()))}}}),r.on("close",(O,y)=>{Kt(h),_=!1,b=null;let N=String(y||"");if(B(`Socket closed (${O||"no-code"}${N?`: ${N}`:""})`),s&&(clearInterval(s),s=null),O===1008&&/agent deactivated|authentication failed/i.test(N)){B("Stopping daemon because Agensis rejected this agent connection."),f();return}if(l==="ECONNREFUSED"&&Or(t.url)){B("Local agent backend is not running on 127.0.0.1:3142."),B("Start it in another terminal with: npm run backend"),B("Then rerun this connect command."),f();return}t.once&&c>0&&a.active()===0&&a.size()===0&&f(),!(n||t.once)&&(o=setTimeout(v,2e3),o.unref&&o.unref())}),r.on("error",O=>{l=O?.code||"",B(`Socket error: ${O?.message||O}`)})},D=async()=>{let C=await De(t).catch(()=>null);await Dt(t,{busy:a.active()>0,active:a.active(),queueSize:a.size(),connected:r?.readyState===ue.OPEN,agentStatus:C?.status,agentNote:C?.note}).catch(()=>{})};D(),i=setInterval(()=>{D()},t.heartbeatMs),i.unref&&i.unref(),v(),await new Promise(C=>{let O=setInterval(async()=>{t.once&&c>0&&a.active()===0&&a.size()===0&&f(),n&&f()},500);u=()=>{clearInterval(O),C()}}),u=null,k.off("SIGINT",f),k.off("SIGTERM",f)}function Ar(e){let t=xr(e.cursorBuddyBridge),n=e.noCoding===!0||k.env.AGENSIS_NO_CODING==="1",o=!se(e.fullCliContext,se(k.env.AGENSIS_FULL_CLI_CONTEXT,!1))&&se(e.leanCli,!0),s={url:String(e.url||e.baseUrl||k.env.AGENSIS_URL||"").trim(),token:String(e.token||k.env.AGENSIS_TOKEN||"").trim(),workspace:String(e.workspace||e.workspaceId||k.env.AGENSIS_WORKSPACE||k.env.AGENSIS_WORKSPACE_ID||"").trim(),agent:String(e.agent||e.agentId||k.env.AGENSIS_AGENT||k.env.AGENSIS_AGENT_ID||"").trim(),handle:en(e.handle||k.env.AGENSIS_HANDLE||e.name||k.env.AGENSIS_NAME||"agent"),name:String(e.name||k.env.AGENSIS_NAME||e.handle||k.env.AGENSIS_HANDLE||"agensis Agent").trim(),cwd:String(e.cwd||k.env.AGENSIS_CWD||k.cwd()).trim(),codingCmd:n?"":String(e.codingCmd||k.env.AGENSIS_CODING_CMD||k.env.CODING_CMD||"claude -p").trim(),model:Fe(e.model||k.env.AGENSIS_MODEL||k.env.CLAUDE_MODEL||""),permissionMode:be(e.permissionMode||e.permission_mode||e.permission||k.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||k.env.AGENSIS_TIMEOUT_MS||Er),heartbeatMs:Number(e.heartbeatMs||k.env.AGENSIS_HEARTBEAT_MS||kr),maxConcurrency:Math.max(1,Number(e.maxConcurrency||k.env.AGENSIS_MAX_CONCURRENCY||Ft)||Ft),once:!!(e.once||k.env.AGENSIS_ONCE==="1"),exitOnOnce:!!e.exitOnOnce,onRegistered:typeof e.onRegistered=="function"?e.onRegistered:null,primaryDaemon:!!(e.primaryDaemon||k.env.AGENSIS_PRIMARY_DAEMON==="1"),cursorBuddyRuntime:!!(e.cursorBuddyRuntime||k.env.AGENSIS_CURSORBUDDY_RUNTIME==="1"),cursorBuddyBridge:t,cursorBuddyPort:Number(e.cursorBuddyPort||k.env.AGENSIS_CURSORBUDDY_PORT||8787),cursorBuddyBridgeSecret:String(e.cursorBuddyBridgeSecret||k.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),cursorBuddyModel:String(e.cursorBuddyModel||k.env.AGENSIS_CURSORBUDDY_MODEL||"haiku-4.5").trim(),lanListener:!!(e.lanListener||e.lan||k.env.AGENSIS_LAN==="1"),share:!!(e.share||k.env.AGENSIS_SHARE==="1"),sharedModelsFile:String(e.sharedModelsFile||k.env.AGENSIS_SHARED_MODELS_FILE||"").trim(),noCoding:n,leanCli:o,fastConnection:se(e.fastConnection,se(k.env.AGENSIS_FAST_CONNECTION,!0)),syncMemory:se(e.syncMemory,k.env.AGENSIS_SYNC_MEMORY==="1"),hostFolders:Yt(e.hostFolders??e.host_folders??k.env.AGENSIS_HOST_FOLDERS)};s.sharedModelsFile&&!de.isAbsolute(s.sharedModelsFile)&&(s.sharedModelsFile=de.resolve(s.cwd,s.sharedModelsFile));let i=[];if(s.url||i.push("--url"),s.token||i.push("--token"),s.workspace||i.push("--workspace"),s.agent||i.push("--agent"),s.share&&!s.sharedModelsFile&&i.push("--shared-models-file"),i.length)throw new Error(`Missing required option(s): ${i.join(", ")}`);return s}function se(e,t){return e==null||e===""?t:typeof e=="boolean"?e:!/^(0|false|off|no)$/i.test(String(e).trim())}function xr(e){let t=k.env.AGENSIS_CURSORBUDDY_BRIDGE;return t!==void 0&&t!==""?!/^(0|false|off|no)$/i.test(String(t).trim()):e==null||e===""?!1:typeof e=="boolean"?e:!/^(0|false|off|no)$/i.test(String(e).trim())}function Mr(e,t,n={}){let r=Ue(e);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.pathname="/backend/ws",r.search="",n.workspace&&r.searchParams.set("workspaceId",n.workspace),n.agent&&r.searchParams.set("agentId",n.agent),r.toString()}function Ue(e){let t=new URL(e);return Nr(t)&&(t.protocol="http:",t.hostname="127.0.0.1",t.port="3142"),t}function Nr(e){if(!(e.hostname==="localhost"||e.hostname==="127.0.0.1"||e.hostname==="0.0.0.0")||e.port==="3142")return!1;if(e.port==="5173"||e.port==="8888")return!0;let t=Number(e.port||0);return t>=49152&&t<=65535}function Or(e){try{let t=Ue(e);return(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="0.0.0.0")&&t.port==="3142"}catch{return!1}}function jt(e){let t=String(e?.sessionId||""),n=String(e?.threadParentId||"");return`${t}::${n}`}var Tr=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,Br=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function $r(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function Dr(e){for(let t of Br){let n=String(e||"").match(t),r=$r(n?.[1]||"");if(r)return r}return""}function Pr(e){let t=String(e||"").replace(/\s+/g," ").trim();if(!t)return"";let n=/latest user message\s*:\s*/gi,r=null,o=null;for(;r=n.exec(t);)o=r;if(!o)return"";let s=t.slice(o.index+o[0].length).trim(),i=s.search(/\b(Return a useful response|Conversation context follows|Previous user|Previous assistant|Diagnostic notes|System prompt|Developer message)\b/i);return(i>=0?s.slice(0,i):s).trim().replace(/^["'“”‘’]+|["'“”‘’]+$/g,"").trim()}function Rr(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=Pr(t)||t;if(!r)return"";if(r.length<=500)return r;let o=[/\b(?:can you\s+)?(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:wave|waves|waving|say|speak)\b.{0,160}/i,/\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b.{0,120}\b(?:wave|waves|waving|say|speak|open|show|hide|hush|close|dismiss|clear)\b.{0,160}/i,/\b(?:wave|open|show|hide|hush|close|dismiss|clear)\b.{0,120}\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy|bubble|prompt|dialog|panel|options|menu)\b/i,/\b(?:say|speak)\s+[`"'“”‘’]?.{1,180}/i];for(let s of o){let i=r.match(s);if(i?.[0])return i[0].trim()}return""}function Lr(e){let t=Rr(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=Tr.test(t);if(!n&&!r)return null;let o="agensis-native-control";if(/\b(hide|hush|close|dismiss|clear)\b.*\b(bubble|prompt|dialog|panel|options|menu)\b/i.test(t)||/^hush\b/i.test(t))return{action:"hush",source:o};if(/\b(open|show|bring up|get back|display)\b.*\b(prompt|bubble|dialog|panel|options|menu)\b/i.test(t)||/^open\b/i.test(t))return{action:"open",source:o};let s=Dr(t);return s&&r?{action:"say",text:s,source:o}:r&&/\b(wave|waves|waving)\b/i.test(t)?{action:"wave",text:s,source:o}:null}async function Ur(e,t){let r=`http://127.0.0.1:${Number(e.cursorBuddyPort||8787)}/cursorbuddy/control`,o=String(e.cursorBuddyBridgeSecret||k.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),s={"content-type":"application/json"};o&&(s.authorization=`Bearer ${o}`,s["x-agensis-bridge-secret"]=o);let i=await fetch(r,{method:"POST",headers:s,body:JSON.stringify(t)}),c=null;try{c=await i.json()}catch{c=null}if(!i.ok||c?.ok===!1)throw new Error(c?.error||`CursorBuddy control failed with HTTP ${i.status}`);return c}function Fr(e){return e.action==="wave"?"Sent CursorBuddy a wave command.":e.action==="say"?`Sent CursorBuddy speech: ${e.text||""}`.trim():e.action==="open"?"Opened CursorBuddy's prompt.":e.action==="hush"?"Dismissed CursorBuddy's bubble.":e.action==="choose"?"Sent CursorBuddy options.":"Sent CursorBuddy control command."}function Wt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function jr(e,t,n,r){let o="cursorbuddy-control",s="native",i=[],c=(l="")=>{L(t.ws,{action:"agent_job_delta",jobId:t.id,content:l,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i})};c("");let u="",a="";try{await Ur(e,n),u=Fr(n),c(u)}catch(l){a=String(l?.message||l),u=`CursorBuddy control failed: ${a}`,c(u)}L(t.ws,{action:"agent_job_result",jobId:t.id,response:u,error:a,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i}),B(`Finished native CursorBuddy ${n.action} job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`)}async function Gr(e,t,{signal:n}){let r=Date.now();B(`Starting job ${t.id}`);let o=Lr(t.prompt);if(o&&Wt(e)){await jr(e,t,o,r),e.once&&(B("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>k.exit(0),150));return}let s=Kr(e,t),i=await Hr(e,t),c="",u="",a=0,l=($="")=>{L(t.ws,{action:"agent_job_delta",jobId:t.id,content:$,elapsedMs:Date.now()-r,model:s.model,permissionMode:s.permissionMode,permissionFlags:s.permissionFlags})};l("");let m=s.streamJson?Wr():null,_=setInterval(()=>l(c),1e3);_.unref&&_.unref();let b=!/[\\/]/.test(s.cmd),h=e.fastConnection&&b?Qt(s.cmd)?"claude":Zt(s.cmd)?"codex":null:null,w=await ot(t,{family:h}).run({cmd:s.cmd,args:[...s.args,i],env:s.env,cwd:t.cwd||e.cwd,timeoutMs:e.timeoutMs,heartbeatMs:e.heartbeatMs,label:"agent job",signal:n,job:t,prompt:i,model:s.model,permissionMode:s.permissionMode,hostFolders:Xt(e,t),leanCli:e.leanCli,mcp:e.leanCli?Le(e):null,sessionKey:`${t.workspaceId||e.workspace||""}:${e.agent||e.handle||""}`,clientVersion:Z,onData:$=>{m?(m.feed($),c=m.live):(c+=String($||""),u=eo(`${u}
|
|
36
|
-
${
|
|
37
|
-
${c}`:"",l=["You are running as a local agensis workspace agent daemon.",`Workspace: ${t.workspaceId||e.workspace}`,`Channel session: ${t.sessionId||""}`,`Agent: ${n.name||e.name} (@${n.handle||e.handle})`,`Requested model: ${
|
|
34
|
+
`,kr=8*1024,Ir=400;function Nt(e,t){return String(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/\.{2,}/g,".").replace(/^[.-]+/,"").slice(0,96)||t}function oe({workspace:e,agent:t,homedir:n=wr.homedir()}={}){return K.join(n,".agensis",Nt(e,"workspace"),Nt(t,"agent"))}function Dt(e){return K.join(oe(e),$t)}function Pt(e){return K.join(oe(e),$e)}async function Be(e){let t=oe(e);try{return await z.mkdir(t,{recursive:!0}),t}catch{return null}}async function Se(e,t){let n=`${e}.tmp-${process.pid}`;try{return await z.writeFile(n,t),await z.rename(n,e),!0}catch{try{await z.rm(n,{force:!0})}catch{}return!1}}async function De(e,t){if(!t||typeof t!="object")return!1;let n=await Be(e);if(!n)return!1;let r={id:t.id??e.agent??"",workspace:t.workspace_id??e.workspace??"",name:t.name??e.name??"",handle:t.handle??e.handle??"",model:t.model??e.model??"",permissionMode:t.permissionMode??t.permission_mode??e.permissionMode??"",description:t.description??"",instructions:t.instructions??"",systemPrompt:t.system_prompt??t.systemPrompt??"",tools:Array.isArray(t.tools)?t.tools:[],skills:Array.isArray(t.skills)?t.skills:[],memoryDir:t.memory_dir??t.memoryDir??"",version:Number(t.version||0),updatedAt:new Date().toISOString()},s=await Se(K.join(n,br),`${JSON.stringify(r,null,2)}
|
|
35
|
+
`),o=String(t.soul??""),i=await Se(K.join(n,_r),o);return s&&i}async function Rt(e,t={}){let n=await Be(e);return n?Se(K.join(n,Bt),Ut(e,t)):!1}function Lt(e,t={}){let n=oe(e);try{return Ot.mkdirSync(n,{recursive:!0}),Ot.writeFileSync(K.join(n,Bt),Ut(e,t)),!0}catch{return!1}}function Ut(e,t){let n=Date.now(),r={ts:n,iso:new Date(n).toISOString(),status:t.status||(t.busy?"busy":"online"),busy:!!t.busy,active:Number(t.active||0),queueSize:Number(t.queueSize||0),connected:!!t.connected,model:e.model||"",permissionMode:e.permissionMode||"",handle:e.handle||"",agent:e.agent||"",workspace:e.workspace||"",pid:process.pid,heartbeatMs:e.heartbeatMs,...t.agentStatus?{agentStatus:t.agentStatus}:{},...t.agentNote?{agentNote:t.agentNote}:{}};return`${JSON.stringify(r,null,2)}
|
|
36
|
+
`}async function Pe(e){let t=K.join(oe(e),$t),n;try{let c=await z.stat(t);if(!c.isFile()||c.size>kr)return null;n=await z.readFile(t,"utf8")}catch{return null}let r;try{r=JSON.parse(n)}catch{return null}if(!r||typeof r!="object"||Array.isArray(r))return null;let s=Tt(r.status),o=Tt(r.note??r.message);if(!s&&!o)return null;let i={};return s&&(i.status=s),o&&(i.note=o),r.ts!=null&&Number.isFinite(Number(r.ts))&&(i.ts=Number(r.ts)),i}function Tt(e){return e==null?"":String(e).trim().replace(/\s+/g," ").slice(0,Ir)}async function Ft(e){let t=await Be(e);if(!t)return!1;let n=K.join(t,$e);try{return await z.access(n),!0}catch{}return Se(n,Er)}async function jt(e){let t=K.join(oe(e),$e);try{let n=await z.stat(t);return!n.isFile()||n.size>vr?null:(await z.readFile(t,"utf8")).trim()||null}catch{return null}}var Cr=30*60*1e3,xr=15*1e3,Gt=2,Mr=10*1024,Or="claude-opus-4-8",Z="0.1.29";async function we(e={}){let t=Nr(e);t.sharedModels=t.share?await Ct(t.sharedModelsFile):[];let n=!1,r=null,s=null,o=null,i=null,c=0,u=null,a=null,l="",m=null,g=!1,S=null,f=new Map,x=null,_={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},y=new Map,I=new Map,A=[],E=()=>_,P=()=>({connected:g&&!!t.cursorBuddyRuntime,mode:t.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:S?.agentId||S?.agent_id||t.agent,workspaceId:S?.workspaceId||S?.workspace_id||t.workspace,agensisUrl:t.url,handle:S?.handle||t.handle,name:S?.name||t.name,cwd:t.cwd,updatedAt:new Date().toISOString()}),B=()=>{x||!t.lanListener||(x=new ue.Server({port:0}),x.on("listening",()=>{let{port:C}=x.address();_={transport:"ws",listening:!0,addrs:to(C),auth:"hub-pairwise"},$(`Agent-mesh LAN listener on port ${C}`),ce(r,t,E())}),x.on("connection",C=>{let N=!1,b=setTimeout(()=>{if(!N)try{C.close(1008,"peer auth required")}catch{}},5e3);C.once("message",O=>{clearTimeout(b);let T=Le(O),F=T?.type==="peer_auth"?y.get(T.ticket):null;if(!F||F.fromAgentId!==T.fromAgentId||Date.now()>F.exp){try{C.close(1008,"invalid ticket")}catch{}return}y.delete(T.ticket),N=!0,C.on("message",G=>{let R=Le(G);R?.type==="agent_job"&&R.job?.id&&a.enqueue({...R.job,key:R.job.id,lane:Ht(R.job),ws:r}).accepted&&$(`Queued peer-handoff job ${R.job.id} from ${T.fromAgentId}`)})})}),x.on("error",C=>$(`LAN listener error: ${C?.message||C}`)))},h=()=>{if(x){try{x.close()}catch{}x=null}_={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},w=C=>new Promise((N,b)=>{if(!L(r,{action:"peer_ticket_request",targetAgentId:C})){b(new Error("hub socket not open"));return}let O=I.get(C)||[];O.push({resolve:N,reject:b}),I.set(C,O),setTimeout(()=>{let T=I.get(C)||[],F=T.findIndex(G=>G.resolve===N);F>=0&&(T.splice(F,1),b(new Error("peer ticket request timed out")))},1e4)}),M=()=>new Promise((C,N)=>{if(!L(r,{action:"peer_list_request"})){N(new Error("hub socket not open"));return}A.push(C),setTimeout(()=>{let b=A.indexOf(C);b>=0&&(A.splice(b,1),C([]))},1e4)}),d=async(C,N)=>{let b=null;try{let T=(await M()).find(R=>R.agentId===C&&R.reach?.listening&&R.reach.addrs?.length);if(!T)return!1;let F=await w(C),G=F.peer?.addrs?.[0]||T.reach.addrs[0];return!G?.host||!G?.port?!1:(b=new ue(`ws://${G.host}:${G.port}`),await new Promise((R,Ee)=>{b.once("open",R),b.once("error",Ee),setTimeout(()=>Ee(new Error("peer connect timed out")),5e3)}),L(b,{type:"peer_auth",ticket:F.ticket,fromAgentId:t.agent}),L(b,{type:"agent_job",job:N}),!0)}catch(O){return $(`Peer handoff to ${C} failed, falling back to hub relay: ${O?.message||O}`),!1}finally{try{b?.close()}catch{}}},p=()=>{n=!0,Wt(f),s&&clearTimeout(s),o&&clearInterval(o),i&&clearInterval(i),m&&(m.close().catch(()=>{}),m=null),h(),Lt(t,{status:"stopped",connected:!1});try{r?.close()}catch{}u&&u()};if(a=at({concurrency:t.once?1:t.maxConcurrency,runJob:async(C,N)=>{await zr(t,C,N),t.once&&p()}}),t.cursorBuddyBridge)try{m=await yt(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:$,connectionProvider:P}),m?.secret&&(t.cursorBuddyBridgeSecret=m.secret)}catch(C){if(so(C)){let N=await io(t.cursorBuddyPort);if(N?.ok){let b=N.pid?` pid ${N.pid}`:"";$(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${b}`)}else $(`CursorBuddy local bridge port ${t.cursorBuddyPort} is in use but did not answer health`)}else $(`CursorBuddy local bridge unavailable: ${C?.message||C}`);m=null}k.once("SIGINT",p),k.once("SIGTERM",p);let v=()=>{if(n)return;let C=$r(t.url,t.token,t);l="",$(`Connecting to ${C.replace(t.token,"redacted")}`),r=new ue(C),r.on("open",()=>{g=!1,S=null,$(`Connected. Registering @${t.handle||"agent"} from ${t.cwd}`),L(r,{type:"auth",token:t.token}),L(r,{action:"agent_register",workspaceId:t.workspace,agentId:t.agent,handle:t.handle,name:t.name,host:me.hostname(),cwd:t.cwd,metadata:{codingCmd:t.codingCmd,model:t.model,permissionMode:t.permissionMode,permissionFlags:Ge(t.permissionMode),once:t.once,runtime:"agensis",version:Z}}),o=setInterval(()=>{Promise.all([Zt(t,E()).catch(()=>null),Pe(t).catch(()=>null)]).then(([N,b])=>{L(r,{action:"agent_heartbeat",...N?{capabilitiesHash:N.capabilitiesHash,memoryHash:N.memoryHash}:{},metadata:Re(t,a,b,qt(t)?m?.getContext?.():null,f)})})},t.heartbeatMs),o.unref&&o.unref()}),r.on("message",N=>{let b=Le(N);if(b){if(b.type==="agent_registered"){g=!0,S=b.connection||b.agent||null,Jt(t,b.agent),$(`Registered as ${b.connection?.name||t.name} on ${b.connection?.host||me.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,b)).catch(O=>{$(`Profile save failed: ${O?.message||O}`)}),De(t,b.agent).catch(()=>{}),Ft(t).catch(()=>{}),zt(r,t),B(),ce(r,t,E());return}if(b.type==="agent_config"){Jt(t,b.agent),$(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),De(t,b.agent).catch(()=>{});return}if(b.type==="agent_memory_refresh"){zt(r,t),ce(r,t,E());return}if(b.type==="agent_capabilities_refresh"){ce(r,t,E());return}if(b.type==="agent_inference_cancel"){f.get(String(b.requestId||""))?.abort();return}if(b.type==="agent_job_cancel"){let O=String(b.jobId||"");O&&a.cancel(O,b.reason||"Cancelled by Agensis")&&$(`Cancelled job ${O}`);return}if(b.type==="agent_inference_request"&&b.requestId){let O=String(b.requestId),T=t.sharedModels.find(R=>R.id===b.model),F=[...f.values()].filter(R=>R.model===b.model).length;if(!T){L(r,{action:"agent_inference_error",requestId:O,error:`Shared model '${b.model||""}' is not available.`});return}if(F>=T.maxConcurrency){L(r,{action:"agent_inference_error",requestId:O,error:"Shared model is at capacity.",code:"capacity_exhausted"});return}let G=new AbortController;f.set(O,{abort:()=>G.abort(),model:T.id}),L(r,{action:"agent_heartbeat",metadata:Re(t,a,null,null,f)}),Mt({models:t.sharedModels,request:b,signal:G.signal,send:R=>L(r,R)}).catch(R=>{L(r,{action:"agent_inference_error",requestId:O,error:G.signal.aborted?"Inference cancelled.":R?.message||String(R),code:G.signal.aborted?"cancelled":"inference_failed"})}).finally(()=>{f.delete(O),L(r,{action:"agent_heartbeat",metadata:Re(t,a,null,null,f)})});return}if(b.type==="peer_ticket"){let O=b.peer?.agentId,T=I.get(O)||[],F=T.shift();T.length?I.set(O,T):I.delete(O),F&&F.resolve(b);return}if(b.type==="peer_ticket_grant"){y.set(b.ticket,{fromAgentId:b.fromAgentId,exp:b.exp});return}if(b.type==="peer_list"){let O=A.shift();O&&O(Array.isArray(b.peers)?b.peers:[]);return}if(b.type==="agent_reach_disable"){h(),ce(r,t,E());return}if(b.type==="error"){$(`Server rejected request: ${b.message||"unknown error"}`);return}if(b.type==="agent_disabled"){g=!1,S=null,$(`Agent disabled by Agensis: ${b.reason||"deactivated"}`),p();return}if(b.type==="agent_job"&&b.job?.id){let O=a.enqueue({...b.job,key:b.job.id,lane:Ht(b.job),ws:r});O.accepted&&(c+=1,$(`Queued job ${b.job.id} at position ${O.position}`),t.once&&a.idle().then(()=>p()))}}}),r.on("close",(N,b)=>{Wt(f),g=!1,S=null;let O=String(b||"");if($(`Socket closed (${N||"no-code"}${O?`: ${O}`:""})`),o&&(clearInterval(o),o=null),N===1008&&/agent deactivated|authentication failed/i.test(O)){$("Stopping daemon because Agensis rejected this agent connection."),p();return}if(l==="ECONNREFUSED"&&Dr(t.url)){$("Local agent backend is not running on 127.0.0.1:3142."),$("Start it in another terminal with: npm run backend"),$("Then rerun this connect command."),p();return}t.once&&c>0&&a.active()===0&&a.size()===0&&p(),!(n||t.once)&&(s=setTimeout(v,2e3),s.unref&&s.unref())}),r.on("error",N=>{l=N?.code||"",$(`Socket error: ${N?.message||N}`)})},D=async()=>{let C=await Pe(t).catch(()=>null);await Rt(t,{busy:a.active()>0,active:a.active(),queueSize:a.size(),connected:r?.readyState===ue.OPEN,agentStatus:C?.status,agentNote:C?.note}).catch(()=>{})};D(),i=setInterval(()=>{D()},t.heartbeatMs),i.unref&&i.unref(),v(),await new Promise(C=>{let N=setInterval(async()=>{t.once&&c>0&&a.active()===0&&a.size()===0&&p(),n&&p()},500);u=()=>{clearInterval(N),C()}}),u=null,k.off("SIGINT",p),k.off("SIGTERM",p)}function Nr(e){let t=Tr(e.cursorBuddyBridge),n=e.noCoding===!0||k.env.AGENSIS_NO_CODING==="1",s=!se(e.fullCliContext,se(k.env.AGENSIS_FULL_CLI_CONTEXT,!1))&&se(e.leanCli,!0),o={url:String(e.url||e.baseUrl||k.env.AGENSIS_URL||"").trim(),token:String(e.token||k.env.AGENSIS_TOKEN||"").trim(),workspace:String(e.workspace||e.workspaceId||k.env.AGENSIS_WORKSPACE||k.env.AGENSIS_WORKSPACE_ID||"").trim(),agent:String(e.agent||e.agentId||k.env.AGENSIS_AGENT||k.env.AGENSIS_AGENT_ID||"").trim(),handle:nn(e.handle||k.env.AGENSIS_HANDLE||e.name||k.env.AGENSIS_NAME||"agent"),name:String(e.name||k.env.AGENSIS_NAME||e.handle||k.env.AGENSIS_HANDLE||"agensis Agent").trim(),cwd:String(e.cwd||k.env.AGENSIS_CWD||k.cwd()).trim(),codingCmd:n?"":String(e.codingCmd||k.env.AGENSIS_CODING_CMD||k.env.CODING_CMD||"claude -p").trim(),model:je(e.model||k.env.AGENSIS_MODEL||k.env.CLAUDE_MODEL||""),permissionMode:be(e.permissionMode||e.permission_mode||e.permission||k.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||k.env.AGENSIS_TIMEOUT_MS||Cr),heartbeatMs:Number(e.heartbeatMs||k.env.AGENSIS_HEARTBEAT_MS||xr),maxConcurrency:Math.max(1,Number(e.maxConcurrency||k.env.AGENSIS_MAX_CONCURRENCY||Gt)||Gt),once:!!(e.once||k.env.AGENSIS_ONCE==="1"),exitOnOnce:!!e.exitOnOnce,onRegistered:typeof e.onRegistered=="function"?e.onRegistered:null,primaryDaemon:!!(e.primaryDaemon||k.env.AGENSIS_PRIMARY_DAEMON==="1"),cursorBuddyRuntime:!!(e.cursorBuddyRuntime||k.env.AGENSIS_CURSORBUDDY_RUNTIME==="1"),cursorBuddyBridge:t,cursorBuddyPort:Number(e.cursorBuddyPort||k.env.AGENSIS_CURSORBUDDY_PORT||8787),cursorBuddyBridgeSecret:String(e.cursorBuddyBridgeSecret||k.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),cursorBuddyModel:String(e.cursorBuddyModel||k.env.AGENSIS_CURSORBUDDY_MODEL||"haiku-4.5").trim(),lanListener:!!(e.lanListener||e.lan||k.env.AGENSIS_LAN==="1"),share:!!(e.share||k.env.AGENSIS_SHARE==="1"),sharedModelsFile:String(e.sharedModelsFile||k.env.AGENSIS_SHARED_MODELS_FILE||"").trim(),noCoding:n,leanCli:s,fastConnection:se(e.fastConnection,se(k.env.AGENSIS_FAST_CONNECTION,!0)),syncMemory:se(e.syncMemory,k.env.AGENSIS_SYNC_MEMORY==="1"),hostFolders:Vt(e.hostFolders??e.host_folders??k.env.AGENSIS_HOST_FOLDERS)};o.sharedModelsFile&&!de.isAbsolute(o.sharedModelsFile)&&(o.sharedModelsFile=de.resolve(o.cwd,o.sharedModelsFile));let i=[];if(o.url||i.push("--url"),o.token||i.push("--token"),o.workspace||i.push("--workspace"),o.agent||i.push("--agent"),o.share&&!o.sharedModelsFile&&i.push("--shared-models-file"),i.length)throw new Error(`Missing required option(s): ${i.join(", ")}`);return o}function se(e,t){return e==null||e===""?t:typeof e=="boolean"?e:!/^(0|false|off|no)$/i.test(String(e).trim())}function Tr(e){let t=k.env.AGENSIS_CURSORBUDDY_BRIDGE;return t!==void 0&&t!==""?!/^(0|false|off|no)$/i.test(String(t).trim()):e==null||e===""?!1:typeof e=="boolean"?e:!/^(0|false|off|no)$/i.test(String(e).trim())}function $r(e,t,n={}){let r=Fe(e);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.pathname="/backend/ws",r.search="",n.workspace&&r.searchParams.set("workspaceId",n.workspace),n.agent&&r.searchParams.set("agentId",n.agent),r.toString()}function Fe(e){let t=new URL(e);return Br(t)&&(t.protocol="http:",t.hostname="127.0.0.1",t.port="3142"),t}function Br(e){if(!(e.hostname==="localhost"||e.hostname==="127.0.0.1"||e.hostname==="0.0.0.0")||e.port==="3142")return!1;if(e.port==="5173"||e.port==="8888")return!0;let t=Number(e.port||0);return t>=49152&&t<=65535}function Dr(e){try{let t=Fe(e);return(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="0.0.0.0")&&t.port==="3142"}catch{return!1}}function Ht(e){let t=String(e?.sessionId||""),n=String(e?.threadParentId||"");return`${t}::${n}`}var Pr=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,Rr=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function Lr(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function Ur(e){for(let t of Rr){let n=String(e||"").match(t),r=Lr(n?.[1]||"");if(r)return r}return""}function Fr(e){let t=String(e||"").replace(/\s+/g," ").trim();if(!t)return"";let n=/latest user message\s*:\s*/gi,r=null,s=null;for(;r=n.exec(t);)s=r;if(!s)return"";let o=t.slice(s.index+s[0].length).trim(),i=o.search(/\b(Return a useful response|Conversation context follows|Previous user|Previous assistant|Diagnostic notes|System prompt|Developer message)\b/i);return(i>=0?o.slice(0,i):o).trim().replace(/^["'“”‘’]+|["'“”‘’]+$/g,"").trim()}function jr(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=Fr(t)||t;if(!r)return"";if(r.length<=500)return r;let s=[/\b(?:can you\s+)?(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:wave|waves|waving|say|speak)\b.{0,160}/i,/\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b.{0,120}\b(?:wave|waves|waving|say|speak|open|show|hide|hush|close|dismiss|clear)\b.{0,160}/i,/\b(?:wave|open|show|hide|hush|close|dismiss|clear)\b.{0,120}\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy|bubble|prompt|dialog|panel|options|menu)\b/i,/\b(?:say|speak)\s+[`"'“”‘’]?.{1,180}/i];for(let o of s){let i=r.match(o);if(i?.[0])return i[0].trim()}return""}function Gr(e){let t=jr(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=Pr.test(t);if(!n&&!r)return null;let s="agensis-native-control";if(/\b(hide|hush|close|dismiss|clear)\b.*\b(bubble|prompt|dialog|panel|options|menu)\b/i.test(t)||/^hush\b/i.test(t))return{action:"hush",source:s};if(/\b(open|show|bring up|get back|display)\b.*\b(prompt|bubble|dialog|panel|options|menu)\b/i.test(t)||/^open\b/i.test(t))return{action:"open",source:s};let o=Ur(t);return o&&r?{action:"say",text:o,source:s}:r&&/\b(wave|waves|waving)\b/i.test(t)?{action:"wave",text:o,source:s}:null}async function Hr(e,t){let r=`http://127.0.0.1:${Number(e.cursorBuddyPort||8787)}/cursorbuddy/control`,s=String(e.cursorBuddyBridgeSecret||k.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),o={"content-type":"application/json"};s&&(o.authorization=`Bearer ${s}`,o["x-agensis-bridge-secret"]=s);let i=await fetch(r,{method:"POST",headers:o,body:JSON.stringify(t)}),c=null;try{c=await i.json()}catch{c=null}if(!i.ok||c?.ok===!1)throw new Error(c?.error||`CursorBuddy control failed with HTTP ${i.status}`);return c}function Jr(e){return e.action==="wave"?"Sent CursorBuddy a wave command.":e.action==="say"?`Sent CursorBuddy speech: ${e.text||""}`.trim():e.action==="open"?"Opened CursorBuddy's prompt.":e.action==="hush"?"Dismissed CursorBuddy's bubble.":e.action==="choose"?"Sent CursorBuddy options.":"Sent CursorBuddy control command."}function qt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function Kr(e,t,n,r){let s="cursorbuddy-control",o="native",i=[],c=(l="")=>{L(t.ws,{action:"agent_job_delta",jobId:t.id,content:l,elapsedMs:Date.now()-r,model:s,permissionMode:o,permissionFlags:i})};c("");let u="",a="";try{await Hr(e,n),u=Jr(n),c(u)}catch(l){a=String(l?.message||l),u=`CursorBuddy control failed: ${a}`,c(u)}L(t.ws,{action:"agent_job_result",jobId:t.id,response:u,error:a,elapsedMs:Date.now()-r,model:s,permissionMode:o,permissionFlags:i}),$(`Finished native CursorBuddy ${n.action} job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`)}async function zr(e,t,{signal:n}){let r=Date.now();$(`Starting job ${t.id}`);let s=Gr(t.prompt);if(s&&qt(e)){await Kr(e,t,s,r),e.once&&($("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>k.exit(0),150));return}let o=Yr(e,t),i=await Wr(e,t),c="",u="",a=0,l=(B="")=>{L(t.ws,{action:"agent_job_delta",jobId:t.id,content:B,elapsedMs:Date.now()-r,model:o.model,permissionMode:o.permissionMode,permissionFlags:o.permissionFlags})},m=B=>{L(t.ws,{action:"agent_job_step",jobId:t.id,kind:B.kind,name:B.name,detail:B.detail,elapsedMs:Date.now()-r})};l("");let g=o.streamJson?Xr({onStep:m}):null,S=setInterval(()=>l(c),1e3);S.unref&&S.unref();let f=!/[\\/]/.test(o.cmd),x=e.fastConnection&&f?en(o.cmd)?"claude":tn(o.cmd)?"codex":null:null,y=await it(t,{family:x}).run({cmd:o.cmd,args:[...o.args,i],env:o.env,cwd:t.cwd||e.cwd,timeoutMs:e.timeoutMs,heartbeatMs:e.heartbeatMs,label:"agent job",signal:n,job:t,prompt:i,model:o.model,permissionMode:o.permissionMode,hostFolders:Qt(e,t),leanCli:e.leanCli,mcp:e.leanCli?Ue(e):null,sessionKey:`${t.workspaceId||e.workspace||""}:${e.agent||e.handle||""}`,clientVersion:Z,onData:B=>{g?(g.feed(B),c=g.live):(c+=String(B||""),u=oo(`${u}
|
|
37
|
+
${B}`));let h=Date.now();h-a>150&&(a=h,l(c))}});clearInterval(S),g&&(g.end(),c=g.live,l(c));let I=String(y.stdout||"").trim(),A=String(y.stderr||"").trim(),E=y.error?y.error.message:y.status===0?"":A||`Command exited with status ${y.status}`,P=g?g.result||(E?"":A):I||(E?"":A)||u||"";L(t.ws,{action:"agent_job_result",jobId:t.id,response:P,error:E,elapsedMs:Date.now()-r,model:o.model,permissionMode:o.permissionMode,permissionFlags:o.permissionFlags}),$(`Finished job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`),e.once&&($("One-shot job complete; exiting."),setTimeout(()=>k.exit(0),150))}async function Wr(e,t){let n=t.agent||{},r=Array.isArray(n.skills)?n.skills.join(", "):String(n.skills||""),s=Array.isArray(n.tools)?n.tools.join(", "):String(n.tools||""),o=Yt(e,t),i=Xt(e,t),c=await jt(e).catch(()=>null),u=c?`Heartbeat (recurring instructions \u2014 edit at ${Pt(e)}):
|
|
38
|
+
${c}`:"",l=["You are running as a local agensis workspace agent daemon.",`Workspace: ${t.workspaceId||e.workspace}`,`Channel session: ${t.sessionId||""}`,`Agent: ${n.name||e.name} (@${n.handle||e.handle})`,`Requested model: ${o}`,`Permission mode: ${i}`,n.description?`Description:
|
|
38
39
|
${n.description}`:"",n.soul?`Soul:
|
|
39
40
|
${n.soul}`:"",n.system_prompt?`System instructions:
|
|
40
41
|
${n.system_prompt}`:"",n.instructions?`Additional instructions:
|
|
41
|
-
${n.instructions}`:"",
|
|
42
|
-
${
|
|
43
|
-
${r}`:"",'Thread widgets: this chat has a right-side widget rail the human watches. When you work a multi-step task here, surface it: call create_thread_item (kind "todo", "plan", or "blocker") with the Channel session id above to post your plan steps and to-dos, mark them done with update_thread_item as you finish, and raise a "blocker" when you need the human to answer something (read their reply from the item response via list_thread_items). Keep it to a few real items, not every micro-step; skip it for quick one-off replies.',`Status file: you can report your own working status by overwriting the JSON file at ${
|
|
42
|
+
${n.instructions}`:"",s?`Enabled tools:
|
|
43
|
+
${s}`:"",r?`Enabled skills:
|
|
44
|
+
${r}`:"",'Thread widgets: this chat has a right-side widget rail the human watches. When you work a multi-step task here, surface it: call create_thread_item (kind "todo", "plan", or "blocker") with the Channel session id above to post your plan steps and to-dos, mark them done with update_thread_item as you finish, and raise a "blocker" when you need the human to answer something (read their reply from the item response via list_thread_items). Keep it to a few real items, not every micro-step; skip it for quick one-off replies.',`Status file: you can report your own working status by overwriting the JSON file at ${Dt(e)} with e.g. {"status":"working","note":"short summary of what you're doing"}. Your daemon reads it on its next heartbeat (~${Math.round((e.heartbeatMs||15e3)/1e3)}s) and surfaces it on your agent card. Optional and best-effort \u2014 overwrite the whole file, keep note under ~200 chars, and there's no need to clear it.`,u,"User message:",String(t.prompt||""),"Identity boundary: answer as the workspace agent named above. Do not adopt the identity of any browser, desktop, avatar, pet, widget, or UI surface.","Respond with a clear channel-ready result. Use markdown for structure \u2014 bullets, headers, and code blocks where appropriate. If you changed files, summarize the files and verification. If you cannot complete it, say exactly why."].filter(Boolean).join(`
|
|
44
45
|
|
|
45
|
-
`);return e.leanCli?
|
|
46
|
+
`);return e.leanCli?qr(l,Mr):l}function qr(e,t){let n=String(e||"");if(Buffer.byteLength(n,"utf8")<=t)return n;let r=`[... older or optional Agensis context omitted ...]
|
|
46
47
|
|
|
47
|
-
`,
|
|
48
|
-
`))>=0;)
|
|
49
|
-
`)}function
|
|
50
|
-
`,{mode:384}),await fe.rename(i,
|
|
51
|
-
`)}import
|
|
52
|
-
`,{mode:384}),await pe.rename(
|
|
53
|
-
`),
|
|
48
|
+
`,s=Math.max(0,t-Buffer.byteLength(r,"utf8")),o=[...n],i=0,c=o.length;for(;i<c;){let u=Math.ceil((i+c)/2),a=o.slice(o.length-u).join("");Buffer.byteLength(a,"utf8")<=s?i=u:c=u-1}return r+o.slice(o.length-i).join("")}function Yr(e,t){let{cmd:n,args:r}=ro(e.codingCmd),s=Yt(e,t),o=Xt(e,t),i=no(r),c=Ge(o),u=Qt(e,t);if(en(n)){let a=[...i];s&&a.push("--model",s);let l;if(e.leanCli){let f=Ue(e);a.push("--no-session-persistence","--safe-mode","--mcp-config",JSON.stringify({mcpServers:{agensis:{type:"http",url:f.url,headers:{Authorization:"Bearer ${AGENSIS_MCP_TOKEN}"}}}}),"--strict-mcp-config"),l=f.env}if(o==="accept_edits"&&a.push("--permission-mode","acceptEdits"),o==="yolo"){let f=t&&t.agent&&t.agent.run_mode==="sandbox",x=typeof k.getuid=="function"&&k.getuid()===0,_=f||Vr(),y=k.env.AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS==="1";_||!x||y?a.push("--dangerously-skip-permissions"):(c=[],$("running as root with no sandbox detected: dropping --dangerously-skip-permissions (Claude rejects it as root). Set AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS=1 if this host really is sandboxed."))}let m=i.some(f=>f==="--output-format"||String(f).startsWith("--output-format=")),g=i.includes("-p")||i.includes("--print"),S=!1;!m&&g?(a.push("--output-format","stream-json","--include-partial-messages"),i.includes("--verbose")||a.push("--verbose"),S=!0):m&&(S=i.some(f=>/stream-json/.test(String(f))));for(let f of u)a.push("--add-dir",f);return{cmd:n,args:a,model:s,permissionMode:o,permissionFlags:c,streamJson:S,env:l}}if(tn(n)){let a=[...i];s&&a.push("--model",s);let l;if(e.leanCli&&i.includes("exec")){let m=Ue(e);a.push("--ephemeral","--ignore-user-config","--ignore-rules","--disable","plugins","--disable","memories","--disable","hooks","--disable","skill_search","-c","project_doc_max_bytes=0","-c",`mcp_servers.agensis.url=${JSON.stringify(m.url)}`,"-c",'mcp_servers.agensis.bearer_token_env_var="AGENSIS_MCP_TOKEN"'),l=m.env}return o==="yolo"&&a.push("--sandbox","danger-full-access","--ask-for-approval","never"),{cmd:n,args:a,model:s,permissionMode:o,permissionFlags:c,env:l}}return{cmd:n,args:r,model:s,permissionMode:o,permissionFlags:c}}function Ue(e){let t=Fe(e.url);return t.pathname="/backend/mcp",t.search="",t.hash="",{url:t.toString(),env:{AGENSIS_MCP_TOKEN:e.token}}}function Xr({onStep:e}={}){let t="",n="",r=!1,s="",o=null,i=!1,c=new Set,u=m=>{if(!(typeof e!="function"||!m.name))try{e(m)}catch{}},a=m=>{if(!m||typeof m!="object")return;if(m.type==="agensis_step"){let S=m.step;S&&typeof S=="object"&&(i=!0,u({kind:S.kind||"tool",name:String(S.name||""),detail:String(S.detail||"")}));return}let g=m.event&&m.event.delta||m.delta;if(g&&g.type==="text_delta"&&typeof g.text=="string"){r=!0,n+=g.text;return}if(m.type==="result"&&typeof m.result=="string"){o=m.result;return}if(m.type==="assistant"&&m.message&&Array.isArray(m.message.content)){let S=m.message.content.filter(f=>f&&f.type==="text"&&typeof f.text=="string").map(f=>f.text).join("");if(S&&(s+=S),!i)for(let f of m.message.content){if(!f||f.type!=="tool_use")continue;let x=typeof f.id=="string"?f.id:"";if(x){if(c.has(x))continue;c.add(x)}u({kind:"tool",name:String(f.name||""),detail:Ie(f.input)})}}},l=m=>{let g=String(m).trim();if(g)try{a(JSON.parse(g))}catch{}};return{feed(m){t+=String(m||"");let g;for(;(g=t.indexOf(`
|
|
49
|
+
`))>=0;)l(t.slice(0,g)),t=t.slice(g+1)},end(){t&&(l(t),t="")},get live(){return r?n:s},get result(){return o??(r?n:s)}}}function Yt(e,t){return je(t?.agent?.model||t?.model||e.model)}function je(e){let t=String(e||"").trim();return!t||t==="auto"||t==="claude-fable-5"?Or:t}function Xt(e,t){return be(t?.agent?.permissionMode||t?.agent?.permission_mode||t?.permissionMode||t?.permission_mode||e.permissionMode)}function be(e){let t=String(e||"").trim().toLowerCase().replace(/[-\s]+/g,"_");return["yolo","no_sandbox","danger","danger_full_access","dangerously_skip_permissions"].includes(t)?"yolo":["accept_edits","acceptedits","auto_approve","auto_approve_edits"].includes(t)?"accept_edits":"default"}function Ge(e){return be(e)==="yolo"?["--no-sandbox","--yolo"]:[]}function Vt(e){let t=Array.isArray(e)?e:String(e||"").split(/[,\n]/),n=new Set,r=[];for(let s of t){let o=String(s||"").trim();!o||n.has(o)||(n.add(o),r.push(o))}return r}function Qt(e,t){let n=t?.agent?.metadata?.host_folders??t?.agent?.hostFolders??t?.hostFolders??t?.host_folders,r=Vt(n);return r.length>0?r:e.hostFolders||[]}var Q;function Vr(){if(Q!==void 0)return Q;let e=k.env;if(e.AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS==="1"||e.AGENSIS_SANDBOX_HOST==="1"||e.IS_SANDBOX==="1")return Q=!0;if(e.AGENSIS_NO_SANDBOX_AUTODETECT==="1")return Q=!1;try{if(le.existsSync("/.dockerenv")||le.existsSync("/run/.containerenv"))return Q=!0}catch{}try{let t=le.readFileSync("/proc/1/cgroup","utf8");if(/docker|kubepods|containerd|lxc|podman/i.test(t))return Q=!0}catch{}return Q=!1}function Re(e,t,n,r=null,s=null){let o={busy:t.active()>0,queueSize:t.size(),cwd:e.cwd,model:e.model,permissionMode:e.permissionMode,permissionFlags:Ge(e.permissionMode),daemon:{runtime:"agensis-cli",version:Z,pid:k.pid,node:k.version,platform:k.platform,arch:k.arch,host:me.hostname(),cwd:e.cwd}};if(s instanceof Map){let i={};for(let c of s.values()){let u=String(c?.model||"");u&&(i[u]=(i[u]||0)+1)}o.activeInferenceByModel=i}return r&&typeof r=="object"&&(o.cursorBuddy=Qr(r)),n?.status&&(o.agentStatus=n.status),n?.note&&(o.agentNote=n.note),(n?.status||n?.note)&&(o.agentStatusAt=new Date().toISOString()),o}function Qr(e={}){let t=e.client&&typeof e.client=="object"?e.client:{},n=e.page&&typeof e.page=="object"?e.page:{},r=e.runtime&&typeof e.runtime=="object"?e.runtime:{},s=e.manifest&&typeof e.manifest=="object"?e.manifest:{},o=e.project&&typeof e.project=="object"?e.project:{};return{surface:String(e.surface||"").slice(0,80),instanceId:String(e.instanceId||"").slice(0,140),url:String(e.url||"").slice(0,2048),title:String(e.title||"").slice(0,300),origin:String(n.origin||"").slice(0,300),hostname:String(n.hostname||"").slice(0,200),pathname:String(n.pathname||"").slice(0,500),visibilityState:String(n.visibilityState||"").slice(0,40),focused:n.focused===!0,userAgent:String(t.userAgent||"").slice(0,500),platform:String(t.platform||"").slice(0,120),language:String(t.language||"").slice(0,80),viewport:t.viewport&&typeof t.viewport=="object"?{width:Number(t.viewport.width)||0,height:Number(t.viewport.height)||0,devicePixelRatio:Number(t.viewport.devicePixelRatio)||0}:null,runtimeMarker:String(r.marker||"").slice(0,120),extensionMarker:String(r.extensionMarker||"").slice(0,120),manifest:{name:String(s.name||"").slice(0,120),version:String(s.version||"").slice(0,80),source:String(s.source||"").slice(0,500)},project:{name:String(o.name||"").slice(0,120),root:String(o.root||"").slice(0,500),agent:String(o.agent||"").slice(0,80)},updatedAt:String(e.updatedAt||"").slice(0,80)}}function Jt(e,t){if(!t||typeof t!="object")return;t.name&&(e.name=String(t.name).trim()||e.name),(t.handle||t.name)&&(e.handle=nn(t.handle||t.name||e.handle)),t.model&&(e.model=je(t.model));let n=t.permissionMode||t.permission_mode;n&&(e.permissionMode=be(n)),(t.memory_dir!==void 0||t.memoryDir!==void 0)&&(e.memoryDir=String(t.memory_dir??t.memoryDir??"").trim())}function Zr(){let e=["claude","codex","gh","node","npm","python3","git","fly","vercel"],t=(k.env.PATH||"").split(de.delimiter).filter(Boolean);return e.filter(n=>t.some(r=>{try{return le.existsSync(de.join(r,n))}catch{return!1}}))}function eo(){try{let e=le.readFileSync(de.join(me.homedir(),".claude.json"),"utf8"),n=JSON.parse(e)?.mcpServers;if(n&&typeof n=="object")return Object.keys(n).sort()}catch{}return[]}function Kt(e){return Ar.createHash("sha1").update(String(e)).digest("hex").slice(0,16)}async function Zt(e,t=null){let n=It({cwd:e.cwd}),r=kt({cwd:e.cwd}),s=Zr(),o=eo(),i=e.syncMemory&&Me({cwd:e.cwd,memoryDir:e.memoryDir})||null,c=xt(e.sharedModels),u=Kt(JSON.stringify({skills:n,commands:r,clis:s,mcpServers:o,memoryRoot:i,sharedModels:c,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null})),a=Kt(await bt(i));return{skills:n,commands:r,clis:s,mcpServers:o,memoryRoot:i,sharedModels:c,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null,capabilitiesHash:u,memoryHash:a}}async function ce(e,t,n=null){try{let r=await Zt(t,n);L(e,{action:"agent_capabilities_sync",workspaceId:t.workspace,agentId:t.agent,skills:r.skills,commands:r.commands,clis:r.clis,mcpServers:r.mcpServers,sharedModels:r.sharedModels,codingRoute:r.codingRoute,shared:r.shared,memoryRoot:r.memoryRoot,reach:r.reach||void 0,hash:r.capabilitiesHash,memoryHash:r.memoryHash}),$(`Capabilities synced \u2014 skills:${r.skills.length} commands:${r.commands.length} clis:${r.clis.length} mcp:${r.mcpServers.length}`)}catch(r){$(`Capabilities sync skipped: ${r?.message||r}`)}}function to(e){let t=me.networkInterfaces(),n=[];for(let r of Object.values(t))for(let s of r||[])s.family==="IPv4"&&!s.internal&&n.push({host:s.address,port:e,scope:"lan"});return n.slice(0,4)}async function zt(e,t){try{if(!t.syncMemory)return;let n=Me({cwd:t.cwd,memoryDir:t.memoryDir});if(!n)return;let r=await _t(n);L(e,{action:"agent_memory_sync",workspaceId:t.workspace,agentId:t.agent,root:n,files:r}),$(`Synced ${r.length} memory file${r.length===1?"":"s"} from ${n}`)}catch(n){$(`Memory sync skipped: ${n?.message||n}`)}}function no(e){let t=new Set(["--model","-m","--permission-mode","--sandbox","--ask-for-approval","--approval-policy"]),n=new Set(["--dangerously-skip-permissions","--no-sandbox","--yolo","--accept-edits"]),r=[];for(let s=0;s<e.length;s+=1){let o=e[s],[i]=String(o).split("=",1);if(!n.has(o)){if(t.has(i)){String(o).includes("=")||(s+=1);continue}r.push(o)}}return r}function en(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function tn(e){return/(^|\/)codex(?:$|\.)/.test(String(e||""))}function ro(e){let t=[],n="",r="",s=!1;for(let o of e){if(s){n+=o,s=!1;continue}if(o==="\\"){s=!0;continue}if(r){o===r?r="":n+=o;continue}if(o==='"'||o==="'"){r=o;continue}if(/\s/.test(o)){n&&(t.push(n),n="");continue}n+=o}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function Le(e){try{return JSON.parse(String(e))}catch{return null}}function L(e,t){return!e||e.readyState!==ue.OPEN?!1:(e.send(JSON.stringify(t)),!0)}function oo(e){return String(e||"").split(/\r?\n/).map(t=>t.trim()).filter(Boolean).slice(-1)[0]||""}function nn(e){return String(e||"").trim().toLowerCase().replace(/^@+/,"").replace(/[^a-z0-9_.-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)}function so(e){return e?.code==="EADDRINUSE"||/\bEADDRINUSE\b/.test(String(e?.message||e))}async function io(e){let t=new AbortController,n=setTimeout(()=>t.abort(),700);try{let r=await fetch(`http://127.0.0.1:${Number(e||8787)}/cursorbuddy/health`,{cache:"no-store",signal:t.signal}),s=await r.json().catch(()=>({}));return!r.ok||!s?.ok?null:s}catch{return null}finally{clearTimeout(n)}}function $(e){k.stderr.write(`[agensis] ${e}
|
|
50
|
+
`)}function Wt(e){if(e instanceof Map)for(let t of e.values())try{t?.abort?.()}catch{}}import ao from"node:crypto";import fe from"node:fs/promises";import co from"node:os";import rn from"node:path";var ee="default",on=2,uo=/^[a-zA-Z0-9_.-]{1,64}$/,lo=["url","token","workspace","agent","handle","name","cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","leanCli","fullCliContext","syncMemory","lanListener","primaryDaemon","cursorBuddyBridge","cursorBuddyPort","hostFolders"];function W(e=ee){let t=String(e||ee).trim();if(!uo.test(t))throw new Error("Daemon profile names may only contain letters, numbers, dot, dash, and underscore.");return t}function sn(e=ee,t={}){let n=t.homedir||co.homedir();return rn.join(n,".agensis","daemon-profiles",`${W(e)}.json`)}function He(e={}){let t={};for(let n of lo){let r=e[n];r!=null&&r!==""&&(t[n]=r)}return t}function V(e,t,n=[]){for(let r of t)if(String(e?.[r]||"").trim())return!0;for(let r of n)if(String(process.env[r]||"").trim())return!0;return!1}function an(e={}){return!!(V(e,["url","baseUrl"],["AGENSIS_URL"])||V(e,["token"],["AGENSIS_TOKEN"])||V(e,["workspace","workspaceId"],["AGENSIS_WORKSPACE","AGENSIS_WORKSPACE_ID"])||V(e,["agent","agentId"],["AGENSIS_AGENT","AGENSIS_AGENT_ID"]))}function Je(e={}){return!!(V(e,["url","baseUrl"],["AGENSIS_URL"])&&V(e,["token"],["AGENSIS_TOKEN"])&&V(e,["workspace","workspaceId"],["AGENSIS_WORKSPACE","AGENSIS_WORKSPACE_ID"])&&V(e,["agent","agentId"],["AGENSIS_AGENT","AGENSIS_AGENT_ID"]))}async function cn(e=ee,t={}){let n=sn(e,t),r;try{r=await fe.readFile(n,"utf8")}catch(c){if(c?.code==="ENOENT")return null;throw c}let s;try{s=JSON.parse(r)}catch(c){throw new Error(`Daemon profile "${W(e)}" is unreadable: ${c?.message||c}`)}let o=s?.config;if(!o?.url||!o?.token||!o?.workspace||!o?.agent)return null;let i=He(o);return Number(s.version||1)<on&&Number(i.maxConcurrency)===8&&(i.maxConcurrency=2),i}async function _e(e=ee,t={},n={}){let r=He(t);if(!r.url||!r.token||!r.workspace||!r.agent)return null;let s=sn(e,n),o=rn.dirname(s);await fe.mkdir(o,{recursive:!0,mode:448});let i=`${s}.${process.pid}.${Date.now()}.tmp`,c={version:on,savedAt:new Date().toISOString(),profile:W(e),tokenHash:ao.createHash("sha256").update(r.token).digest("hex"),config:r};return await fe.writeFile(i,`${JSON.stringify(c,null,2)}
|
|
51
|
+
`,{mode:384}),await fe.rename(i,s),await fe.chmod(s,384).catch(()=>{}),s}function un(e,t={}){let n={...e,...He(t),command:"connect"};return t.fullCliContext===!0&&(n.leanCli=!1),t.codingCmd!==void 0&&t.noCoding===void 0&&(n.noCoding=!1),t.cursorBuddyBridge===void 0&&!n.primaryDaemon&&(n.cursorBuddyBridge=!1),t.once!==void 0&&(n.once=t.once),t.exitOnOnce!==void 0&&(n.exitOnOnce=t.exitOnOnce),n}function ln(e=ee){let t=W(e);return[`No saved Agensis daemon profile found for "${t}".`,"","To connect the main agent once:","1. Run: agensis setup","2. Sign in or create an account in the browser.","3. Approve this machine as your primary local agent.","","Manual fallback: open Agensis > AI Agents, copy a connection command,","and run that full agensis connect command from the repo folder.","","After the daemon registers successfully, this CLI saves the profile locally.",`Then restart it with: agensis connect${t===ee?"":` --profile ${t}`}`].join(`
|
|
52
|
+
`)}import mo from"node:crypto";import pe from"node:fs/promises";import dn from"node:os";import Ke from"node:path";import ze from"node:process";var fo=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/;function po(e={}){return String(e.url||e.baseUrl||ze.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function mn(e,t={}){let n=t.homedir||dn.homedir(),r=mo.createHash("sha256").update(String(e)).digest("hex");return Ke.join(n,".agensis","cursorbuddy","connection-keys",`${r}.json`)}function ho(){return new Error("Missing or invalid --key. Create a CursorBuddy connection key in Agensis first.")}function We(e){let t=String(e||"").trim();if(!fo.test(t))throw ho();return t}function go(e,t,n,r){let s=t?.token,o=t?.workspaceId||t?.workspace_id||t?.agent?.workspace_id,i=t?.agentId||t?.agent?.id;if(!s||!o||!i)throw new Error("CursorBuddy key claim did not return a complete daemon connection payload");let{key:c,subcommand:u,...a}=e;return{...a,command:"connect",url:t.baseUrl||n,token:s,workspace:o,agent:i,handle:t.handle||e.handle,name:t.agent?.name||e.name||"CursorBuddy runtime",model:t.model||e.model,permissionMode:t.permissionMode||t.permission_mode||e.permissionMode,cwd:e.cwd||r,cursorBuddyRuntime:!0}}async function yo(e,t={}){We(e);let n=mn(e,t),r;try{r=await pe.readFile(n,"utf8")}catch(i){if(i?.code==="ENOENT")return null;throw i}let s;try{s=JSON.parse(r)}catch(i){throw new Error(`Cached CursorBuddy daemon config is unreadable: ${i?.message||i}`)}let o=s?.daemonArgs;return!o?.token||!o?.workspace||!o?.agent||!o?.url?null:o}async function So(e,t,n={}){if(We(e),!t?.token||!t?.workspace||!t?.agent||!t?.url)return;let r=mn(e,n),s=Ke.dirname(r);await pe.mkdir(s,{recursive:!0,mode:448});let o=`${r}.${ze.pid}.${Date.now()}.tmp`,i={version:1,savedAt:new Date().toISOString(),keyHash:Ke.basename(r,".json"),daemonArgs:t};await pe.writeFile(o,`${JSON.stringify(i,null,2)}
|
|
53
|
+
`,{mode:384}),await pe.rename(o,r),await pe.chmod(r,384).catch(()=>{})}function wo(e,t,n){let r={...e,command:"connect"};for(let s of["cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","leanCli","lanListener","once"])t[s]!==void 0&&(r[s]=t[s]);return t.codingCmd!==void 0&&t.noCoding===void 0&&(r.noCoding=!1),r.cwd||(r.cwd=n),r.cursorBuddyRuntime=!0,r}function bo(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function _o(e){return e.json().catch(()=>({}))}async function fn(e,t={}){let n=We(e?.key),r=po(e),s=t.fetchImpl||globalThis.fetch;if(typeof s!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let o=t.cwd||ze.cwd(),i=t.hostname||dn.hostname(),c=t.version||Z,u={homedir:t.homedir},a=await s(`${r}/backend/cursorbuddy/connection-keys/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:n,baseUrl:r,host:i,cwd:e.cwd||o,name:e.name,surface:e.surface||"local_cli",scope:e.scope||"machine",runtimeKind:"agensis-cli",version:c,permissionMode:e.permissionMode,model:e.model})}),l=await _o(a);if(!a.ok){let g=bo(a,l);if(a.status===409||/already been claimed/i.test(g)){let S=await yo(n,u);if(S)return wo(S,e,o);throw new Error(`${g}. No cached daemon config was found on this machine; create a new CursorBuddy key in Agensis or run the full copied agensis connect command.`)}throw new Error(g)}let m=go(e,l?.data||l,r,o);return await So(n,m,u),m}import vo from"node:crypto";import Eo from"node:http";import ko from"node:os";import q from"node:process";import{spawn as Io}from"node:child_process";var Ao="https://agensis.io",Co=10*60*1e3;function ve(e,t,n){e.writeHead(t,{"content-type":"application/json","access-control-allow-origin":"*","access-control-allow-methods":"POST, OPTIONS","access-control-allow-headers":"content-type"}),e.end(JSON.stringify(n))}function xo(e){return new Promise((t,n)=>{let r="";e.on("data",s=>{r+=s,r.length>128*1024&&(n(new Error("setup callback body is too large")),e.destroy())}),e.on("error",n),e.on("end",()=>t(r))})}function Mo(e){let t=String(e||q.env.AGENSIS_URL||Ao).trim(),n=new URL(t);if(n.protocol!=="http:"&&n.protocol!=="https:")throw new Error("Agensis setup URL must be http or https.");return n.search="",n.hash="",n.toString().replace(/\/+$/,"")}function Oo(e){let t=q.platform==="darwin"?"open":q.platform==="win32"?"cmd":"xdg-open",n=q.platform==="win32"?["/c","start","",e]:[e],r=Io(t,n,{detached:!0,stdio:"ignore"});r.on("error",()=>{}),r.unref()}function No(e){let t=e?.daemonArgs||e?.data?.daemonArgs||e?.data||{},r=["url","token","workspace","agent"].filter(s=>!String(t[s]||"").trim());if(r.length)throw new Error(`Setup callback did not include ${r.join(", ")}`);return{...t,command:"connect"}}function To(e,t,n){let r=new URL(Mo(e.url||e.baseUrl));return r.searchParams.set("source","agensis-cli"),r.searchParams.set("referrer","agensis-cli"),r.searchParams.set("intent","setup"),r.searchParams.set("callback",t),r.searchParams.set("state",n),r.searchParams.set("profile",W(e.profile||"default")),r.searchParams.set("host",ko.hostname()),r.searchParams.set("cwd",String(e.cwd||q.cwd())),e.handle&&r.searchParams.set("handle",String(e.handle)),e.name&&r.searchParams.set("name",String(e.name)),r.toString()}async function pn(e={}){let t=W(e.profile||"default"),n=vo.randomBytes(24).toString("base64url"),r=Number(e.setupTimeoutMs||q.env.AGENSIS_SETUP_TIMEOUT_MS||Co),s,o=new Promise((a,l)=>{let m=setTimeout(()=>l(new Error("Agensis setup timed out waiting for browser login.")),r);m.unref&&m.unref(),s=Eo.createServer(async(g,S)=>{if(S.setHeader("access-control-allow-origin","*"),S.setHeader("access-control-allow-methods","POST, OPTIONS"),S.setHeader("access-control-allow-headers","content-type"),g.method==="OPTIONS"){S.writeHead(204),S.end();return}if(g.method!=="POST"||g.url!=="/agensis/setup-callback"){ve(S,404,{ok:!1,error:"Unknown Agensis setup callback route"});return}try{let f=JSON.parse(await xo(g)||"{}");if(f?.state!==n){ve(S,403,{ok:!1,error:"Setup state did not match"});return}let x={...No(f),primaryDaemon:!0,cursorBuddyBridge:e.cursorBuddyBridge!==!1};await _e(t,x),clearTimeout(m),ve(S,200,{ok:!0,profile:t}),a(x)}catch(f){ve(S,400,{ok:!1,error:String(f?.message||f)})}}),s.once("error",l)});await new Promise((a,l)=>{s.listen(0,"127.0.0.1",m=>m?l(m):a())});let{port:i}=s.address(),c=`http://127.0.0.1:${i}/agensis/setup-callback`,u=To(e,c,n);q.stdout.write(`[agensis] Opening Agensis to sign in and connect this machine.
|
|
54
|
+
`),q.stdout.write(`[agensis] If the browser did not open, visit:
|
|
54
55
|
${u}
|
|
55
|
-
`),
|
|
56
|
-
`),a}finally{await new Promise(a=>
|
|
56
|
+
`),Oo(u);try{let a=await o;return q.stdout.write(`[agensis] Saved daemon profile "${t}". Starting primary agent daemon.
|
|
57
|
+
`),a}finally{await new Promise(a=>s.close(()=>a())).catch(()=>{})}}function $o(e){let t={command:"connect"},n=[...e],r=n[0];if(r&&!r.startsWith("-")&&(t.command=n.shift(),t.command==="buddy")){let s=n[0];s&&!s.startsWith("-")?t.subcommand=n.shift():t.subcommand="connect"}for(let s=0;s<n.length;s+=1){let o=n[s];if(!o.startsWith("--"))throw new Error(`Unexpected argument: ${o}`);let[i,c]=o.slice(2).split(/=(.*)/s,2),u=i.replace(/-([a-z])/g,(l,m)=>m.toUpperCase());if(u==="help"){t.help=!0;continue}if(u==="version"){t.version=!0;continue}if(u==="once"){t.once=!0;continue}if(u==="lan"){t.lanListener=!0;continue}if(u==="share"){t.share=!0;continue}if(u==="noCoding"){t.noCoding=!0;continue}if(u==="fullCliContext"){t.fullCliContext=!0;continue}if(u==="syncMemory"){t.syncMemory=!0;continue}if(u==="cursorbuddyBridge"){t.cursorBuddyBridge=!0;continue}if(u==="noCursorbuddyBridge"){t.cursorBuddyBridge=!1;continue}if(u==="yolo"||u==="noSandbox"){t.permissionMode="yolo";continue}if(u==="acceptEdits"){t.permissionMode="accept_edits";continue}if(u==="hostFolder"||u==="hostFolders"||u==="addDir"){let l=c!==void 0?c:n[++s];if(l==null||l.startsWith("--"))throw new Error(`Missing value for --${i}`);t.hostFolders=[...t.hostFolders||[],l];continue}let a=c!==void 0?c:n[++s];if(a==null||a.startsWith("--"))throw new Error(`Missing value for --${i}`);t[u]=a}return t}function Bo(){return`agensis agent daemon
|
|
57
58
|
|
|
58
59
|
Usage:
|
|
59
60
|
agensis --url <workspace-url> --token <token> --workspace <id> --agent <id> [options]
|
|
@@ -99,7 +100,7 @@ Options:
|
|
|
99
100
|
--profile <name> Save/reuse a local daemon profile, default: default
|
|
100
101
|
--version Print the CLI version
|
|
101
102
|
--help Show this help
|
|
102
|
-
`}async function
|
|
103
|
-
`)}}:e}async function
|
|
104
|
-
`);return}if(e.command==="buddy"){if(e.subcommand!=="connect")throw new Error(`Unknown buddy command "${e.subcommand||""}". Use "agensis buddy connect --key <cbk_...>".`);let n=await
|
|
103
|
+
`}async function Do(e){let t=e.profile!==void 0,n=e.handle||e.name,r=W(e.profile||(Je(e)&&n?n:"default"));if(!an(e)){let s=await cn(r);if(!s)throw new Error(ln(r));return un(s,e)}return Je(e)?{...e,cursorBuddyBridge:e.cursorBuddyBridge===!0,onRegistered:async s=>{await _e(r,s);let o=t||r!=="default"?`agensis connect --profile ${r}`:"agensis connect";Y.stdout.write(`[agensis] Saved daemon profile "${r}". Restart with: ${o}
|
|
104
|
+
`)}}:e}async function Po(){let e=$o(Y.argv.slice(2));if(e.help){Y.stdout.write(Bo());return}if(e.version){Y.stdout.write(`${Z}
|
|
105
|
+
`);return}if(e.command==="buddy"){if(e.subcommand!=="connect")throw new Error(`Unknown buddy command "${e.subcommand||""}". Use "agensis buddy connect --key <cbk_...>".`);let n=await fn(e);n.cursorBuddyBridge=e.cursorBuddyBridge!==!1,n.cursorBuddyRuntime=!0,n.exitOnOnce=!0,await we(n),n.once&&Y.exit(0);return}if(e.command==="setup"){let n=await pn(e);n.exitOnOnce=!0,await we({...e,...n}),n.once&&Y.exit(0);return}if(e.command!=="connect")throw new Error(`Unknown command "${e.command}". Use "agensis setup", "agensis connect --url ...", or "agensis buddy connect --key ...".`);let t=await Do(e);t.exitOnOnce=!0,await we(t),t.once&&Y.exit(0)}Po().catch(e=>{Y.stderr.write(`${e?.message||e}
|
|
105
106
|
`),Y.exitCode=1});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agensis/agensis-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"description": "Run a local agensis workspace agent daemon. Connects to a workspace, receives @mention jobs, runs a configured coding CLI in the local folder, and posts results back to agensis. Ships as a single minified bundle.",
|
|
5
5
|
"homepage": "https://agensis.io",
|
|
6
6
|
"repository": {
|