@agensis/agensis-agent 0.1.22 → 0.1.24
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 +25 -21
- package/package.json +4 -1
package/bin/agensis.mjs
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import Y from"node:process";import
|
|
2
|
+
var Xt=Object.defineProperty;var Vt=(e,t)=>()=>(e&&(t=e(e=0)),t);var Qt=(e,t)=>{for(var n in t)Xt(e,n,{get:t[n],enumerable:!0})};var Je={};Qt(Je,{createE2bProvider:()=>nn});function ve(e){return`'${String(e).replace(/'/g,"'\\''")}'`}function nn({apiKey:e,anthropicApiKey:t,gitToken:n="",repoUrl:r="",template:o=""}={}){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 s={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 d=Number(String(process.versions.node).split(".")[0])||0,f=d<20||d===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.${f}`)}throw u}let a=o?await i.create(o,s):await i.create(s);return await a.commands.run("bash -lc 'command -v claude >/dev/null || npm i -g @anthropic-ai/claude-code'"),{sbx:a,dir:tn}},async putRepo(s){let i=n?r.replace(/^https:\/\//,`https://x-access-token:${n}@`):r;try{let a=await s.sbx.commands.run(`git clone ${ve(i)} ${ve(s.dir)}`);if(a&&typeof a.exitCode=="number"&&a.exitCode!==0)throw new Error(`git clone failed: ${a.stderr||`exit ${a.exitCode}`}`)}catch(a){if(a&&String(a.message||"").startsWith("git clone failed:"))throw a;let u=a&&(a.stderr||a.exitCode!=null)?a.stderr||`exit ${a.exitCode}`:String(a?.message||a);throw new Error(`git clone failed: ${u}`)}},async exec(s,{cmd:i,args:a=[],onData:u}){let d=`${i} ${a.map(ve).join(" ")}`,f={cwd:s.dir,envs:{IS_SANDBOX:"1",AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS:"1"},onStdout:h=>{try{u?.(h)}catch{}}};try{let h=await s.sbx.commands.run(d,f);return{status:h.exitCode,stdout:h.stdout||"",stderr:h.stderr||"",error:null}}catch(h){return h&&typeof h.exitCode=="number"?{status:h.exitCode,stdout:h.stdout||"",stderr:h.stderr||"",error:null}:{status:null,stdout:"",stderr:String(h?.message||h),error:h}}},async getResult(s){try{return{patch:(await s.sbx.commands.run("git add -A && git diff --cached",{cwd:s.dir})).stdout||""}}catch(i){return{patch:i&&i.stdout||""}}},async destroy(s){await s.sbx.kill()}}}var tn,We=Vt(()=>{tn="/home/user/repo"});import Y from"node:process";import ue from"node:fs";import de from"node:path";import le from"node:os";import Yn from"node:crypto";import b from"node:process";import ce from"ws";import{spawn as Zt}from"node:child_process";function He(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 en=50*1024*1024;function se(e){let{cmd:t,args:n=[],cwd:r,timeoutMs:o=0,label:s="working",heartbeatMs:i=15e3,input:a="",now:u=Date.now,log:d=console,signal:f,onData:h}=e||{};return new Promise(S=>{if(f?.aborted){S({status:null,stdout:"",stderr:"",aborted:!0,error:new Error("cancelled")});return}let g;try{let c=n.some(P=>P==="--dangerously-skip-permissions"),y=typeof process.getuid=="function"&&process.getuid()===0,v={...process.env};delete v.ANTHROPIC_API_KEY,delete v.ANTHROPIC_AUTH_TOKEN,c&&y&&(v.IS_SANDBOX="1"),g=Zt(t,n,{cwd:r,detached:!0,env:v})}catch(c){S({status:null,stdout:"",stderr:"",error:c});return}a?g.stdin?.end(String(a)):g.stdin?.end();let x="",$="";g.stdout?.setEncoding("utf8"),g.stderr?.setEncoding("utf8");let _=(c,y)=>c.length>=en?c:c+y;g.stdout?.on("data",c=>{if(x=_(x,c),h)try{h(c)}catch{}}),g.stderr?.on("data",c=>$=_($,c));let w=u(),M=i>0?setInterval(()=>{d.log(` \u2026 still ${s} (${He(u()-w)}) \u2014 Ctrl+C to cancel`)},i):null;M?.unref&&M.unref();let N=c=>{if(g.pid!=null)try{process.kill(-g.pid,c)}catch{try{g.kill(c)}catch{}}},O=!1,F=o>0?setTimeout(()=>{O=!0,N("SIGKILL")},o):null;F?.unref&&F.unref();let U=!1,l=null,p=()=>{U=!0,N("SIGTERM"),l=setTimeout(()=>N("SIGKILL"),3e3),l?.unref&&l.unref()};f&&f.addEventListener("abort",p,{once:!0});let k=(c,y)=>{M&&clearInterval(M),F&&clearTimeout(F),l&&clearTimeout(l),f&&f.removeEventListener("abort",p),S({status:c,stdout:x,stderr:$,aborted:U,error:y||(U?new Error("cancelled"):O?new Error(`timed out after ${He(o)}`):null)})};g.on("error",c=>k(null,c)),g.on("close",c=>k(c,null))})}function rn({run:e=se}={}){return{run:t=>e(t)}}function on(e){return{async run({cmd:t,args:n=[],onData:r,signal:o,job:s}){let i=null;try{i=await e.ensureEnv({job:s,signal:o}),await e.putRepo(i,{job:s,signal:o});let a=await e.exec(i,{cmd:t,args:n,onData:r,signal:o}),u=await e.getResult(i,{job:s}).catch(()=>({})),d=u&&u.patch?String(u.patch).trim():"",f=d?`${a.stdout||""}
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
\`\`\`diff
|
|
5
|
+
${d}
|
|
6
|
+
\`\`\``:a.stdout||"";return{status:a.status,stdout:f,stderr:a.stderr||"",error:a.error||null}}catch(a){return{status:null,stdout:"",stderr:"",error:a}}finally{if(i)try{await e.destroy(i)}catch{}}}}}function Ke(e,{makeProvider:t}={}){return(e&&e.agent&&e.agent.run_mode)==="sandbox"?on((t||sn)(e)):rn()}function sn(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 cn({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 an(e=process.versions.node){let[t,n,r]=String(e).split(".").map(o=>Number(o)||0);return t===21?!1:t>=22?!0:t!==20?!1:n>18?!0:n<18?!1:r>=1}function cn(e){let t=null,n=async()=>{if(!t){if(!an())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(()=>(We(),Je))).createE2bProvider(e)}return t};return{ensureEnv:async r=>(await n()).ensureEnv(r),putRepo:async(r,o)=>(await n()).putRepo(r,o),exec:async(r,o)=>(await n()).exec(r,o),getResult:async(r,o)=>(await n()).getResult(r,o),destroy:async r=>(await n()).destroy(r)}}function ze(e={}){let{runJob:t}=e,n=Math.max(1,Number(e.concurrency)||1),r=new Map,o=0,s=[];function i(_){let w=r.get(_);return w||(w={queued:[],active:null},r.set(_,w)),w}function a(_){if(_==null)return!1;for(let w of r.values())if(w.active&&!w.active.cancelled&&w.active.job.key===_||w.queued.some(M=>M.key===_))return!0;return!1}function u(){for(let[_,w]of r){if(o>=n)break;if(w.active||w.queued.length===0)continue;let M=w.queued.shift(),N=new AbortController;w.active={job:M,controller:N,cancelled:!1},o+=1,Promise.resolve().then(()=>N.signal.aborted?void 0:t(M,{signal:N.signal})).catch(()=>{}).finally(()=>{w.active=null,o-=1,w.queued.length===0&&!w.active&&r.delete(_),u(),d()})}}function d(){if(o>0)return;for(let w of r.values())if(w.queued.length)return;let _=s;s=[];for(let w of _)w()}function f(_){if(_&&_.key!=null&&a(_.key))return{accepted:!1,deduped:!0,position:0,startedImmediately:!1};let w=_&&_.lane!=null?String(_.lane):"",M=i(w),N=!M.active&&M.queued.length===0&&o<n;M.queued.push(_);let O=M.queued.length+(M.active?1:0);return u(),{accepted:!0,deduped:!1,position:O,startedImmediately:N}}function h(_,w){let M=!1;for(let[N,O]of r)w!=null&&N!==String(w)||O.active&&(O.active.cancelled=!0,O.active.controller.abort(_||"cancelled"),M=!0);return M}function S(_,w){if(_==null)return!1;let M=!1;for(let[N,O]of[...r]){O.active?.job?.key===_&&(O.active.cancelled=!0,O.active.controller.abort(w||"cancelled"),M=!0);let F=O.queued.length;O.queued=O.queued.filter(U=>U.key!==_),O.queued.length!==F&&(M=!0),!O.active&&O.queued.length===0&&r.delete(N)}return d(),M}function g(){let _=0;for(let w of r.values())_+=w.queued.length;return _}function x(){return o}function $(){return o===0&&g()===0?Promise.resolve():new Promise(_=>s.push(_))}return{enqueue:f,cancel:S,cancelActive:h,has:a,size:g,active:x,idle:$}}import Ze from"node:crypto";import un from"node:http";import et from"node:os";import X from"node:process";var qe=8787,Ee="claude-haiku-4-5",dn=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/,ln=100,mn=new Set(["say","wave","hush","open","choose"]),ge="x-agensis-bridge-secret";function fn(){return`cbs_${Ze.randomBytes(24).toString("base64url")}`}function pn(e){let t=e?.headers||{},n=String(t[ge]||t[ge.toLowerCase()]||"").trim();if(n)return n;let o=String(t.authorization||t.Authorization||"").trim().match(/^Bearer\s+(.+)$/i);return o?o[1].trim():""}function hn(e,t){let n=String(t||""),r=pn(e);if(!n||!r)return!1;let o=Buffer.from(r),s=Buffer.from(n);return o.length!==s.length?!1:Ze.timingSafeEqual(o,s)}function gn(e={},t={}){let n=String(t.authSecret||"").trim();if(n)return n;let r=String(e.cursorBuddyBridgeSecret||"").trim();if(r)return r;let o=String(X.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim();return o||fn()}function yn(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 Ye(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)}
|
|
7
|
+
|
|
8
|
+
`)}function ie(e){return new Promise((t,n)=>{let r="";e.on("data",o=>{r+=o,r.length>256*1024&&(n(new Error("request body is too large")),e.destroy())}),e.on("error",n),e.on("end",()=>t(r))})}function Sn(e){let t=[],n="",r="",o=!1;for(let s of String(e||"")){if(o){n+=s,o=!1;continue}if(s==="\\"){o=!0;continue}if(r){s===r?r="":n+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){n&&(t.push(n),n="");continue}n+=s}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function wn(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function pe(e,t){return e.some(n=>n===t||String(n).startsWith(`${t}=`))}function Xe(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 o=String(r?.role||"user"),s=String(r?.content||"");s.trim()&&n.push(`${o.toUpperCase()}:
|
|
5
9
|
${s}`)}return n.join(`
|
|
6
10
|
|
|
7
|
-
`).trim()||"Say that the local Agensis runtime is connected."}function
|
|
8
|
-
`))>=0;)u(t.slice(0,p)),t=t.slice(p+1)},end(){t&&(u(t),t="")},get live(){return r?n:o},get result(){return s??(r?n:o)}}}function Z(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 fe(e){return`http://127.0.0.1:${e}`}function ln(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function dn(e){return String(e||"").slice(0,18)}function R(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function mn(e={},t={},n={}){let r=R(e.metadata)||{},o=R(e.page)||R(r.page)||{},s=R(e.client)||R(r.client)||{},i=R(r.runtime)||{},c=R(e.manifest)||R(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:R(e.project)||R(r.project)||null,manifest:c,selection:R(e.selection)||null,updatedAt:new Date().toISOString()}}function fn(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function pn(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!qt.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=ln(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:qe.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:R(t.metadata)||null,websiteSource:t.websiteSource||t.metadata?.websiteSource||"",page:R(t.page)||R(t.metadata?.page)||null,client:R(t.client)||R(t.metadata?.client)||null,manifest:R(t.manifest)||R(t.metadata?.manifest)||null})}),i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(fn(s,i));return{key:r,baseUrl:o,data:i?.data||i}}async function Ve(e,t={}){let n=Number(t.port??e.cursorBuddyPort??X.env.AGENSIS_CURSORBUDDY_PORT??Ge),r=en(e,t),o=new Date().toISOString(),s=[],i=[],c=new Set,u=t.fetchImpl||globalThis.fetch,l=1,p=null,y=n,S=null,h=(d,f={})=>{let v={ts:new Date().toISOString(),event:d,detail:f};return s.push(v),s.length>200&&s.shift(),t.log?.(`CursorBuddy local bridge: ${d}${Object.keys(f).length?` ${JSON.stringify(f)}`:""}`),v},$=()=>({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()}),O=()=>{if(typeof t.connectionProvider!="function")return null;try{let d=t.connectionProvider();return!d||typeof d!="object"||Array.isArray(d)?null:{...$(),...d,connected:d.connected===!0}}catch{return null}},b=()=>{let d=O();return d?.connected===!1?d:S?{...$(),...d||{},...S,connected:!0,updatedAt:d?.updatedAt||S.updatedAt}:d||$()};function w(d={}){if(!d||typeof d!="object"||Array.isArray(d))return null;let f=String(d.action||d.type||"").trim().toLowerCase();if(!Xt.has(f))return null;let v={id:l++,ts:new Date().toISOString(),action:f,text:String(d.text||d.say||d.message||"").slice(0,1200),label:String(d.label||"").slice(0,80),value:String(d.value||d.prompt||"").slice(0,1200),holdMs:Number.isFinite(d.holdMs)?Math.max(0,Math.min(6e4,d.holdMs)):void 0,source:String(d.source||"agensis-daemon").slice(0,80)};return d.options&&Array.isArray(d.options)&&(v.options=d.options.map(a=>({label:String(a?.label||"").slice(0,80),value:String(a?.value||a?.task||"").slice(0,1200)})).filter(a=>a.label).slice(0,6)),v}function A(d){for(i.push(d);i.length>Yt;)i.shift();h("control",{id:d.id,action:d.action,chars:d.text.length});for(let f of[...c])try{H(f,{type:"command",command:d})}catch{c.delete(f)}return d}function N(d){let f=an(d);if(f){let v=w(f.command);return v&&(A(v),h("chat_control",{id:v.id,action:v.action})),{content:f.content,model:"cursorbuddy-local-control",fast:!0}}return null}async function B(d){let f=N(d);if(f)return f;let v=Je(d?.messages,p),a=ze(e,v,d?.model),g=await oe({cmd:a.cmd,args:a.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:a.stdin});if(g.error||g.status!==0)throw new Error(g.error?.message||String(g.stderr||"").trim()||`Command exited with status ${g.status}`);return{content:We(g.stdout||g.stderr),model:a.model}}async function F(d,f){let v=`agensis-cursorbuddy-${Date.now()}`,a=N(d);if(a){let C=a.model||"cursorbuddy-local-control";return H(f,Z(v,C,a.content)),H(f,Z(v,C,"","stop")),H(f,"[DONE]"),h("chat_fast",{chars:a.content.length,model:C}),{content:a.content,model:C,fast:!0}}let g=Je(d?.messages,p),M=ze(e,g,d?.model,{stream:!0}),j="",E=C=>{C&&(j+=C,H(f,Z(v,M.model||e.model,C)))},I=M.streamJson?un(E):null,m=await oe({cmd:M.cmd,args:M.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:M.stdin,onData:C=>{if(I)I.feed(C);else{let P=String(C||"");j+=P,H(f,Z(v,M.model||e.model,P))}}});if(I){I.end();let C=I.result||"";!j&&C?E(C):j=C||j}if(m.error||m.status!==0){let C=m.error?.message||String(m.stderr||"").trim()||`Command exited with status ${m.status}`;throw new Error(C)}let _=I?j:We(j||m.stdout||m.stderr);return!I&&_&&_!==j&&(H(f,Z(v,M.model||e.model,_)),j=_),H(f,Z(v,M.model||e.model,"","stop")),H(f,"[DONE]"),{content:j||_,model:M.model}}let L=Kt.createServer(async(d,f)=>{if(f.setHeader("access-control-allow-origin","*"),f.setHeader("access-control-allow-methods","GET, POST, OPTIONS"),f.setHeader("access-control-allow-headers","content-type, authorization, x-agensis-bridge-secret"),d.method==="OPTIONS"){f.writeHead(204),f.end();return}let v=new URL(d.url||"/",fe(y||Ge));if(!tn(d.method,v.pathname)&&!Zt(d,r)){U(f,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/health"){let a=fe(y);U(f,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:ve(e),daemonModel:e.model,port:y,host:qe.hostname(),pid:X.pid,bootedAt:o,authRequired:!0,authHeader:pe,stream:!0,streaming:!0,supportsStreaming:!0,chatStream:!0,capabilities:{chatStream:!0,controlStream:!0,fastAvatarReplies:!1,nativeCursorBuddyControl:!0},latestControlId:i.at(-1)?.id||0,connection:b(),context:p,endpoints:{chat:`${a}/v1/chat/completions`,chatStream:`${a}/v1/chat/completions`,edit:`${a}/cursorbuddy/edit`,context:`${a}/cursorbuddy/context`,control:`${a}/cursorbuddy/control`,controlStream:`${a}/cursorbuddy/control/stream`,logs:`${a}/cursorbuddy/logs`}});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/logs"){U(f,200,{ok:!0,events:s.slice(-100)});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/context"){U(f,200,{ok:!0,context:p});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/control"){let a=Number(v.searchParams.get("after")||0),g=i.filter(M=>M.id>a);U(f,200,{ok:!0,commands:g,latestId:i.at(-1)?.id||0});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/control/stream"){let a=Number(v.searchParams.get("after")||0);He(f),c.add(f),H(f,{type:"ready",latestId:i.at(-1)?.id||0});for(let M of i.filter(j=>j.id>a))H(f,{type:"command",command:M});let g=setInterval(()=>{try{H(f,{type:"ping",ts:new Date().toISOString()})}catch{c.delete(f),clearInterval(g)}},15e3);g.unref&&g.unref(),d.on("close",()=>{c.delete(f),clearInterval(g)});return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/control"){try{let a=JSON.parse(await se(d)||"{}"),g=w(a);if(!g){U(f,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let M=A(g);U(f,200,{ok:!0,command:M})}catch(a){h("control_error",{error:String(a?.message||a)}),U(f,400,{ok:!1,error:String(a?.message||a)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/context"){try{let a=JSON.parse(await se(d)||"{}");p={url:String(a.url||"").slice(0,2048),title:String(a.title||"").slice(0,300),surface:String(a.surface||"").slice(0,80),instanceId:String(a.instanceId||"").slice(0,140),workspaceId:String(a.workspaceId||e.workspace||"").slice(0,120),agentId:String(a.agentId||e.agent||"").slice(0,120),runtime:a.runtime&&typeof a.runtime=="object"?a.runtime:null,page:a.page&&typeof a.page=="object"?a.page:null,client:a.client&&typeof a.client=="object"?a.client:null,project:a.project&&typeof a.project=="object"?a.project:null,manifest:a.manifest&&typeof a.manifest=="object"?a.manifest:null,selection:a.selection&&typeof a.selection=="object"?a.selection:null,updatedAt:new Date().toISOString()},h("context",{url:p.url,surface:p.surface,instanceId:p.instanceId}),U(f,200,{ok:!0,context:p})}catch(a){h("context_error",{error:String(a?.message||a)}),U(f,400,{ok:!1,error:String(a?.message||a)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/connect"){try{let a=JSON.parse(await se(d)||"{}"),g=await pn(e,a,u),M=g.data||{};S={connected:!0,mode:"agensis-claimed",keyId:dn(g.key),agentId:String(M.agentId||M.agent?.id||e.agent||""),workspaceId:String(M.workspaceId||M.workspace_id||M.agent?.workspace_id||e.workspace||""),agensisUrl:g.baseUrl,handle:String(M.handle||M.agent?.handle||e.handle||""),name:String(M.agent?.name||a.name||e.name||"CursorBuddy runtime"),cwd:String(a.cwd||e.cwd||X.cwd()),surface:String(a.surface||"browser_extension"),command:String(M.command||M.localCommand||""),updatedAt:new Date().toISOString()},p=mn(a,S,e),h("connect",{mode:S.mode,keyId:S.keyId,agentId:S.agentId,workspaceId:S.workspaceId,url:p.url}),U(f,200,{ok:!0,connection:S,claim:M})}catch(a){h("connect_error",{error:String(a?.message||a)}),U(f,400,{ok:!1,error:String(a?.message||a)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/edit"){try{let a=JSON.parse(await se(d)||"{}"),g=[{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(a,null,2)}];h("edit_request",{selector:a?.target?.selector||""});let M=await B({messages:g,model:a?.model});h("edit_done",{chars:M.content.length}),U(f,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:M.content})}catch(a){h("edit_error",{error:String(a?.message||a)}),U(f,500,{ok:!1,error:String(a?.message||a)})}return}if(d.method==="POST"&&v.pathname.endsWith("/chat/completions")){try{let a=JSON.parse(await se(d)||"{}");if(h("chat_request",{messages:Array.isArray(a.messages)?a.messages.length:0,model:Ye(a.model,ve(e))}),a.stream===!0){He(f);let M=await F(a,f);h("chat_done",{chars:M.content.length,stream:!0,fast:M.fast===!0}),f.end();return}let g=await B(a);h("chat_done",{chars:g.content.length,fast:g.fast===!0}),U(f,200,{id:`agensis-cursorbuddy-${Date.now()}`,object:"chat.completion",model:g.model||a.model||e.model,choices:[{index:0,message:{role:"assistant",content:g.content},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}catch(a){h("chat_error",{error:String(a?.message||a)}),U(f,500,{error:{message:String(a?.message||a)}})}return}f.writeHead(404),f.end("CursorBuddy local bridge")});return await new Promise((d,f)=>{L.once("error",f),L.listen(n,"127.0.0.1",()=>{y=L.address().port,L.off("error",f),d()})}),h("listening",{url:`${fe(y)}/cursorbuddy/health`}),{port:y,url:fe(y),secret:r,authHeader:pe,close(){return new Promise(d=>L.close(()=>d()))},getContext(){return p}}}import ee from"node:fs/promises";import hn from"node:os";import J from"node:path";var Qe=200,Ze=256*1024,gn=2,yn=new Set([".md",".markdown",".txt"]);function Sn(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function _e({cwd:e,memoryDir:t,homedir:n=hn.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",Sn(o),"memory"):null}async function Ae(e){if(!e)return null;try{let t=await ee.realpath(e);return(await ee.stat(t)).isDirectory()?t:null}catch{return null}}async function wn(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 ee.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 bn(e){let t=J.basename(e).toLowerCase();return t==="memory.md"?"index":t==="claude.md"?"instructions":"memory"}async function Ee(e,t,n,r){if(n>gn||r.length>=Qe)return;let o;try{o=await ee.readdir(t,{withFileTypes:!0})}catch{return}for(let s of o){if(r.length>=Qe)break;if(s.name.startsWith("."))continue;let i=J.join(t,s.name);if(s.isDirectory())await Ee(e,i,n+1,r);else if(s.isFile()&&yn.has(J.extname(s.name).toLowerCase())){let c=J.relative(e,i);r.push({path:c,kind:bn(c)})}}}async function kn(e){let t=await Ae(e);if(!t)return[];let n=[];return await Ee(t,t,0,n),n.sort((r,o)=>r.kind==="index"?-1:o.kind==="index"?1:r.path.localeCompare(o.path)),n}async function vn(e,t){let n=await Ae(e),r=await wn(n,t),o=await ee.readFile(r),s=o.length>Ze;return{content:o.subarray(0,Ze).toString("utf8"),byteSize:o.length,truncated:s}}async function et(e){let t=await Ae(e);if(!t)return"";let n=[];await Ee(t,t,0,n),n.sort((o,s)=>o.path.localeCompare(s.path));let r=[];for(let o of n)try{let s=await ee.stat(J.join(t,o.path));r.push(`${o.path}:${s.size}:${Math.floor(s.mtimeMs)}`)}catch{}return r.join("|")}async function tt(e){let t=await kn(e),n=[];for(let r of t)try{let{content:o,byteSize:s}=await vn(e,r.path);n.push({path:r.path,kind:r.kind,content:o,byteSize:s})}catch{}return n}import nt from"node:fs";import te from"node:path";import rt from"node:os";function _n(e){try{return nt.statSync(e).isDirectory()}catch{return!1}}function Ie(e){try{return nt.readdirSync(e,{withFileTypes:!0})}catch{return[]}}function ot({home:e=rt.homedir(),cwd:t=process.cwd()}={}){let n=[e&&te.join(e,".claude","commands"),t&&te.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 Ie(i)){if(c.name.startsWith("."))continue;if(c.name.endsWith(".md")){s(c.name.slice(0,-3),null);continue}let u=te.join(i,c.name);if(c.isDirectory()||c.isSymbolicLink()&&_n(u))for(let l of Ie(u))l.name.startsWith(".")||l.name.endsWith(".md")&&s(l.name.slice(0,-3),c.name)}return o}function st({home:e=rt.homedir(),cwd:t=process.cwd()}={}){let n=[e&&te.join(e,".claude","skills"),e&&te.join(e,".codex","skills"),t&&te.join(t,".claude","skills")].filter(Boolean),r=new Set;for(let o of n)for(let s of Ie(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 An}from"node:fs/promises";var En=new Set(["127.0.0.1","localhost","::1","[::1]"]);function it(e,t,n){let r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(n,Math.trunc(r))):t}function In(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(!En.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:it(e.contextWindow,void 0,1e7)}:{},maxConcurrency:it(e.maxConcurrency,1,64),shared:!0}}async function at(e){if(!e)return[];let t=JSON.parse(await An(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(In).filter(Boolean)}function ct(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 ut({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(w=>w.id===t?.model);if(!c)throw new Error(`Shared model '${t?.model||""}' is not available.`);let u={"content-type":"application/json"},l=c.apiKeyEnv?s[c.apiKeyEnv]:"";l&&(u.authorization=`Bearer ${l}`),n({action:"agent_inference_started",requestId:i,model:c.id});let{requestId:p,model:y,type:S,action:h,...$}=t,O=await o(`${c.baseUrl}/chat/completions`,{method:"POST",headers:u,body:JSON.stringify({...$,model:c.upstreamModel,stream:t.stream===!0}),signal:r});if(!O.ok){let w=await O.text().catch(()=>"");throw new Error(w||`Local model returned HTTP ${O.status}.`)}if(t.stream===!0){if(!O.body)throw new Error("Local model returned an empty stream.");let w=O.body.getReader(),A=new TextDecoder,N="",B,F=f=>{let v=f.trim();if(!v.startsWith("data:"))return!1;let a=v.slice(5).trim();if(!a)return!1;if(a==="[DONE]")return!0;try{let g=JSON.parse(a);g?.usage&&(B=g.usage),n({action:"agent_inference_delta",requestId:i,model:c.id,chunk:g})}catch{}return!1},L=!1;for(;!L;){let{done:f,value:v}=await w.read();N+=A.decode(v||new Uint8Array,{stream:!f});let a=N.split(/\r?\n/);N=f?"":a.pop()||"";for(let g of a)if(F(g)){L=!0;break}if(f)break}N&&F(N);let d={action:"agent_inference_result",requestId:i,model:c.id,...B?{usage:B}:{}};return n(d),d}let b=await O.json();return n({action:"agent_inference_result",requestId:i,model:c.id,response:b}),b}import lt from"node:fs";import z from"node:fs/promises";import Cn from"node:os";import W from"node:path";var ft="status.json",pt="heartbeat.json",Ce="heartbeat.md",Mn="agent.json",Bn="soul.md",xn=16*1024,On=`# Heartbeat
|
|
11
|
+
`).trim()||"Say that the local Agensis runtime is connected."}function Ve(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 bn(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 o=String(r?.content||"").trim();if(o)return o}return""}function _n(e,t=280){let n=bn(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 o of r){let s=n.match(o);if(s?.[0])return s[0].trim()}return n.slice(-t).trim()}function kn(e){let t=_n(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 vn(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 tt(e,t){let n=String(e||"").trim();return!n||vn(n)?t:n}function nt(e){let t=String(e||"").trim();return!t||t==="haiku-4.5"||t==="claude-haiku-4.5"?Ee:t}function Ie(e={}){return nt(e.cursorBuddyModel||X.env.AGENSIS_CURSORBUDDY_MODEL||Ee)}function Qe(e,t,n,r={}){let{cmd:o,args:s}=Sn(e.codingCmd||"claude -p"),i=[...s],a=nt(tt(n,Ie(e))),u="",d=!1;return wn(o)?(a&&!pe(i,"--model")&&i.push("--model",a),r.stream===!0&&!pe(i,"--output-format")?(i.push("--output-format","stream-json","--include-partial-messages"),pe(i,"--verbose")||i.push("--verbose"),d=!0):(pe(i,"--output-format")||i.push("--output-format","json"),d=i.some(h=>String(h).includes("stream-json"))),u=t):i.push(t),{cmd:o,args:i,model:a,stdin:u,streamJson:d}}function En(e=()=>{}){let t="",n="",r=!1,o="",s=null,i=d=>{d&&e(d)},a=d=>{if(!d||typeof d!="object")return;let f=d.event&&d.event.delta||d.delta;if(f&&f.type==="text_delta"&&typeof f.text=="string"){r=!0,n+=f.text,i(f.text);return}if(d.type==="result"&&typeof d.result=="string"){s=d.result;return}if(d.type==="assistant"&&d.message&&Array.isArray(d.message.content)){let h=d.message.content.filter(S=>S&&S.type==="text"&&typeof S.text=="string").map(S=>S.text).join("");h&&(o+=h)}},u=d=>{let f=String(d).trim();if(f)try{a(JSON.parse(f))}catch{}};return{feed(d){t+=String(d||"");let f;for(;(f=t.indexOf(`
|
|
12
|
+
`))>=0;)u(t.slice(0,f)),t=t.slice(f+1)},end(){t&&(u(t),t="")},get live(){return r?n:o},get result(){return s??(r?n:o)}}}function ee(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 he(e){return`http://127.0.0.1:${e}`}function In(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function An(e){return String(e||"").slice(0,18)}function R(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function Cn(e={},t={},n={}){let r=R(e.metadata)||{},o=R(e.page)||R(r.page)||{},s=R(e.client)||R(r.client)||{},i=R(r.runtime)||{},a=R(e.manifest)||R(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:R(e.project)||R(r.project)||null,manifest:a,selection:R(e.selection)||null,updatedAt:new Date().toISOString()}}function xn(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function Mn(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!dn.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=In(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:et.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:R(t.metadata)||null,websiteSource:t.websiteSource||t.metadata?.websiteSource||"",page:R(t.page)||R(t.metadata?.page)||null,client:R(t.client)||R(t.metadata?.client)||null,manifest:R(t.manifest)||R(t.metadata?.manifest)||null})}),i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(xn(s,i));return{key:r,baseUrl:o,data:i?.data||i}}async function rt(e,t={}){let n=Number(t.port??e.cursorBuddyPort??X.env.AGENSIS_CURSORBUDDY_PORT??qe),r=gn(e,t),o=new Date().toISOString(),s=[],i=[],a=new Set,u=t.fetchImpl||globalThis.fetch,d=1,f=null,h=n,S=null,g=(l,p={})=>{let k={ts:new Date().toISOString(),event:l,detail:p};return s.push(k),s.length>200&&s.shift(),t.log?.(`CursorBuddy local bridge: ${l}${Object.keys(p).length?` ${JSON.stringify(p)}`:""}`),k},x=()=>({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()}),$=()=>{if(typeof t.connectionProvider!="function")return null;try{let l=t.connectionProvider();return!l||typeof l!="object"||Array.isArray(l)?null:{...x(),...l,connected:l.connected===!0}}catch{return null}},_=()=>{let l=$();return l?.connected===!1?l:S?{...x(),...l||{},...S,connected:!0,updatedAt:l?.updatedAt||S.updatedAt}:l||x()};function w(l={}){if(!l||typeof l!="object"||Array.isArray(l))return null;let p=String(l.action||l.type||"").trim().toLowerCase();if(!mn.has(p))return null;let k={id:d++,ts:new Date().toISOString(),action:p,text:String(l.text||l.say||l.message||"").slice(0,1200),label:String(l.label||"").slice(0,80),value:String(l.value||l.prompt||"").slice(0,1200),holdMs:Number.isFinite(l.holdMs)?Math.max(0,Math.min(6e4,l.holdMs)):void 0,source:String(l.source||"agensis-daemon").slice(0,80)};return l.options&&Array.isArray(l.options)&&(k.options=l.options.map(c=>({label:String(c?.label||"").slice(0,80),value:String(c?.value||c?.task||"").slice(0,1200)})).filter(c=>c.label).slice(0,6)),k}function M(l){for(i.push(l);i.length>ln;)i.shift();g("control",{id:l.id,action:l.action,chars:l.text.length});for(let p of[...a])try{H(p,{type:"command",command:l})}catch{a.delete(p)}return l}function N(l){let p=kn(l);if(p){let k=w(p.command);return k&&(M(k),g("chat_control",{id:k.id,action:k.action})),{content:p.content,model:"cursorbuddy-local-control",fast:!0}}return null}async function O(l){let p=N(l);if(p)return p;let k=Xe(l?.messages,f),c=Qe(e,k,l?.model),y=await se({cmd:c.cmd,args:c.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:c.stdin});if(y.error||y.status!==0)throw new Error(y.error?.message||String(y.stderr||"").trim()||`Command exited with status ${y.status}`);return{content:Ve(y.stdout||y.stderr),model:c.model}}async function F(l,p){let k=`agensis-cursorbuddy-${Date.now()}`,c=N(l);if(c){let C=c.model||"cursorbuddy-local-control";return H(p,ee(k,C,c.content)),H(p,ee(k,C,"","stop")),H(p,"[DONE]"),g("chat_fast",{chars:c.content.length,model:C}),{content:c.content,model:C,fast:!0}}let y=Xe(l?.messages,f),v=Qe(e,y,l?.model,{stream:!0}),P="",I=C=>{C&&(P+=C,H(p,ee(k,v.model||e.model,C)))},A=v.streamJson?En(I):null,m=await se({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:C=>{if(A)A.feed(C);else{let L=String(C||"");P+=L,H(p,ee(k,v.model||e.model,L))}}});if(A){A.end();let C=A.result||"";!P&&C?I(C):P=C||P}if(m.error||m.status!==0){let C=m.error?.message||String(m.stderr||"").trim()||`Command exited with status ${m.status}`;throw new Error(C)}let E=A?P:Ve(P||m.stdout||m.stderr);return!A&&E&&E!==P&&(H(p,ee(k,v.model||e.model,E)),P=E),H(p,ee(k,v.model||e.model,"","stop")),H(p,"[DONE]"),{content:P||E,model:v.model}}let U=un.createServer(async(l,p)=>{if(p.setHeader("access-control-allow-origin","*"),p.setHeader("access-control-allow-methods","GET, POST, OPTIONS"),p.setHeader("access-control-allow-headers","content-type, authorization, x-agensis-bridge-secret"),l.method==="OPTIONS"){p.writeHead(204),p.end();return}let k=new URL(l.url||"/",he(h||qe));if(!yn(l.method,k.pathname)&&!hn(l,r)){j(p,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/health"){let c=he(h);j(p,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:Ie(e),daemonModel:e.model,port:h,host:et.hostname(),pid:X.pid,bootedAt:o,authRequired:!0,authHeader:ge,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:f,endpoints:{chat:`${c}/v1/chat/completions`,chatStream:`${c}/v1/chat/completions`,edit:`${c}/cursorbuddy/edit`,context:`${c}/cursorbuddy/context`,control:`${c}/cursorbuddy/control`,controlStream:`${c}/cursorbuddy/control/stream`,logs:`${c}/cursorbuddy/logs`}});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/logs"){j(p,200,{ok:!0,events:s.slice(-100)});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/context"){j(p,200,{ok:!0,context:f});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/control"){let c=Number(k.searchParams.get("after")||0),y=i.filter(v=>v.id>c);j(p,200,{ok:!0,commands:y,latestId:i.at(-1)?.id||0});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/control/stream"){let c=Number(k.searchParams.get("after")||0);Ye(p),a.add(p),H(p,{type:"ready",latestId:i.at(-1)?.id||0});for(let v of i.filter(P=>P.id>c))H(p,{type:"command",command:v});let y=setInterval(()=>{try{H(p,{type:"ping",ts:new Date().toISOString()})}catch{a.delete(p),clearInterval(y)}},15e3);y.unref&&y.unref(),l.on("close",()=>{a.delete(p),clearInterval(y)});return}if(l.method==="POST"&&k.pathname==="/cursorbuddy/control"){try{let c=JSON.parse(await ie(l)||"{}"),y=w(c);if(!y){j(p,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let v=M(y);j(p,200,{ok:!0,command:v})}catch(c){g("control_error",{error:String(c?.message||c)}),j(p,400,{ok:!1,error:String(c?.message||c)})}return}if(l.method==="POST"&&k.pathname==="/cursorbuddy/context"){try{let c=JSON.parse(await ie(l)||"{}");f={url:String(c.url||"").slice(0,2048),title:String(c.title||"").slice(0,300),surface:String(c.surface||"").slice(0,80),instanceId:String(c.instanceId||"").slice(0,140),workspaceId:String(c.workspaceId||e.workspace||"").slice(0,120),agentId:String(c.agentId||e.agent||"").slice(0,120),runtime:c.runtime&&typeof c.runtime=="object"?c.runtime:null,page:c.page&&typeof c.page=="object"?c.page:null,client:c.client&&typeof c.client=="object"?c.client:null,project:c.project&&typeof c.project=="object"?c.project:null,manifest:c.manifest&&typeof c.manifest=="object"?c.manifest:null,selection:c.selection&&typeof c.selection=="object"?c.selection:null,updatedAt:new Date().toISOString()},g("context",{url:f.url,surface:f.surface,instanceId:f.instanceId}),j(p,200,{ok:!0,context:f})}catch(c){g("context_error",{error:String(c?.message||c)}),j(p,400,{ok:!1,error:String(c?.message||c)})}return}if(l.method==="POST"&&k.pathname==="/cursorbuddy/connect"){try{let c=JSON.parse(await ie(l)||"{}"),y=await Mn(e,c,u),v=y.data||{};S={connected:!0,mode:"agensis-claimed",keyId:An(y.key),agentId:String(v.agentId||v.agent?.id||e.agent||""),workspaceId:String(v.workspaceId||v.workspace_id||v.agent?.workspace_id||e.workspace||""),agensisUrl:y.baseUrl,handle:String(v.handle||v.agent?.handle||e.handle||""),name:String(v.agent?.name||c.name||e.name||"CursorBuddy runtime"),cwd:String(c.cwd||e.cwd||X.cwd()),surface:String(c.surface||"browser_extension"),command:String(v.command||v.localCommand||""),updatedAt:new Date().toISOString()},f=Cn(c,S,e),g("connect",{mode:S.mode,keyId:S.keyId,agentId:S.agentId,workspaceId:S.workspaceId,url:f.url}),j(p,200,{ok:!0,connection:S,claim:v})}catch(c){g("connect_error",{error:String(c?.message||c)}),j(p,400,{ok:!1,error:String(c?.message||c)})}return}if(l.method==="POST"&&k.pathname==="/cursorbuddy/edit"){try{let c=JSON.parse(await ie(l)||"{}"),y=[{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(c,null,2)}];g("edit_request",{selector:c?.target?.selector||""});let v=await O({messages:y,model:c?.model});g("edit_done",{chars:v.content.length}),j(p,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:v.content})}catch(c){g("edit_error",{error:String(c?.message||c)}),j(p,500,{ok:!1,error:String(c?.message||c)})}return}if(l.method==="POST"&&k.pathname.endsWith("/chat/completions")){try{let c=JSON.parse(await ie(l)||"{}");if(g("chat_request",{messages:Array.isArray(c.messages)?c.messages.length:0,model:tt(c.model,Ie(e))}),c.stream===!0){Ye(p);let v=await F(c,p);g("chat_done",{chars:v.content.length,stream:!0,fast:v.fast===!0}),p.end();return}let y=await O(c);g("chat_done",{chars:y.content.length,fast:y.fast===!0}),j(p,200,{id:`agensis-cursorbuddy-${Date.now()}`,object:"chat.completion",model:y.model||c.model||e.model,choices:[{index:0,message:{role:"assistant",content:y.content},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}catch(c){g("chat_error",{error:String(c?.message||c)}),j(p,500,{error:{message:String(c?.message||c)}})}return}p.writeHead(404),p.end("CursorBuddy local bridge")});return await new Promise((l,p)=>{U.once("error",p),U.listen(n,"127.0.0.1",()=>{h=U.address().port,U.off("error",p),l()})}),g("listening",{url:`${he(h)}/cursorbuddy/health`}),{port:h,url:he(h),secret:r,authHeader:ge,close(){return new Promise(l=>U.close(()=>l()))},getContext(){return f}}}import te from"node:fs/promises";import On from"node:os";import J from"node:path";var ot=200,st=256*1024,Nn=2,Bn=new Set([".md",".markdown",".txt"]);function $n(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function Ae({cwd:e,memoryDir:t,homedir:n=On.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",$n(o),"memory"):null}async function Ce(e){if(!e)return null;try{let t=await te.realpath(e);return(await te.stat(t)).isDirectory()?t:null}catch{return null}}async function Tn(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 te.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 Dn(e){let t=J.basename(e).toLowerCase();return t==="memory.md"?"index":t==="claude.md"?"instructions":"memory"}async function xe(e,t,n,r){if(n>Nn||r.length>=ot)return;let o;try{o=await te.readdir(t,{withFileTypes:!0})}catch{return}for(let s of o){if(r.length>=ot)break;if(s.name.startsWith("."))continue;let i=J.join(t,s.name);if(s.isDirectory())await xe(e,i,n+1,r);else if(s.isFile()&&Bn.has(J.extname(s.name).toLowerCase())){let a=J.relative(e,i);r.push({path:a,kind:Dn(a)})}}}async function Rn(e){let t=await Ce(e);if(!t)return[];let n=[];return await xe(t,t,0,n),n.sort((r,o)=>r.kind==="index"?-1:o.kind==="index"?1:r.path.localeCompare(o.path)),n}async function Pn(e,t){let n=await Ce(e),r=await Tn(n,t),o=await te.readFile(r),s=o.length>st;return{content:o.subarray(0,st).toString("utf8"),byteSize:o.length,truncated:s}}async function it(e){let t=await Ce(e);if(!t)return"";let n=[];await xe(t,t,0,n),n.sort((o,s)=>o.path.localeCompare(s.path));let r=[];for(let o of n)try{let s=await te.stat(J.join(t,o.path));r.push(`${o.path}:${s.size}:${Math.floor(s.mtimeMs)}`)}catch{}return r.join("|")}async function at(e){let t=await Rn(e),n=[];for(let r of t)try{let{content:o,byteSize:s}=await Pn(e,r.path);n.push({path:r.path,kind:r.kind,content:o,byteSize:s})}catch{}return n}import ct from"node:fs";import ne from"node:path";import ut from"node:os";function Ln(e){try{return ct.statSync(e).isDirectory()}catch{return!1}}function Me(e){try{return ct.readdirSync(e,{withFileTypes:!0})}catch{return[]}}function dt({home:e=ut.homedir(),cwd:t=process.cwd()}={}){let n=[e&&ne.join(e,".claude","commands"),t&&ne.join(t,".claude","commands")].filter(Boolean),r=new Set,o=[],s=(i,a)=>{if(!i)return;let u=a?`${a}:${i}`:i;r.has(u)||(r.add(u),o.push({name:i,parent:a||null}))};for(let i of n)for(let a of Me(i)){if(a.name.startsWith("."))continue;if(a.name.endsWith(".md")){s(a.name.slice(0,-3),null);continue}let u=ne.join(i,a.name);if(a.isDirectory()||a.isSymbolicLink()&&Ln(u))for(let d of Me(u))d.name.startsWith(".")||d.name.endsWith(".md")&&s(d.name.slice(0,-3),a.name)}return o}function lt({home:e=ut.homedir(),cwd:t=process.cwd()}={}){let n=[e&&ne.join(e,".claude","skills"),e&&ne.join(e,".codex","skills"),t&&ne.join(t,".claude","skills")].filter(Boolean),r=new Set;for(let o of n)for(let s of Me(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 Un}from"node:fs/promises";var jn=new Set(["127.0.0.1","localhost","::1","[::1]"]);function mt(e,t,n){let r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(n,Math.trunc(r))):t}function Fn(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(!jn.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:mt(e.contextWindow,void 0,1e7)}:{},maxConcurrency:mt(e.maxConcurrency,1,64),shared:!0}}async function ft(e){if(!e)return[];let t=JSON.parse(await Un(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(Fn).filter(Boolean)}function pt(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 ht({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 a=(Array.isArray(e)?e:[]).find(w=>w.id===t?.model);if(!a)throw new Error(`Shared model '${t?.model||""}' is not available.`);let u={"content-type":"application/json"},d=a.apiKeyEnv?s[a.apiKeyEnv]:"";d&&(u.authorization=`Bearer ${d}`),n({action:"agent_inference_started",requestId:i,model:a.id});let{requestId:f,model:h,type:S,action:g,...x}=t,$=await o(`${a.baseUrl}/chat/completions`,{method:"POST",headers:u,body:JSON.stringify({...x,model:a.upstreamModel,stream:t.stream===!0}),signal:r});if(!$.ok){let w=await $.text().catch(()=>"");throw new Error(w||`Local model returned HTTP ${$.status}.`)}if(t.stream===!0){if(!$.body)throw new Error("Local model returned an empty stream.");let w=$.body.getReader(),M=new TextDecoder,N="",O,F=p=>{let k=p.trim();if(!k.startsWith("data:"))return!1;let c=k.slice(5).trim();if(!c)return!1;if(c==="[DONE]")return!0;try{let y=JSON.parse(c);y?.usage&&(O=y.usage),n({action:"agent_inference_delta",requestId:i,model:a.id,chunk:y})}catch{}return!1},U=!1;for(;!U;){let{done:p,value:k}=await w.read();N+=M.decode(k||new Uint8Array,{stream:!p});let c=N.split(/\r?\n/);N=p?"":c.pop()||"";for(let y of c)if(F(y)){U=!0;break}if(p)break}N&&F(N);let l={action:"agent_inference_result",requestId:i,model:a.id,...O?{usage:O}:{}};return n(l),l}let _=await $.json();return n({action:"agent_inference_result",requestId:i,model:a.id,response:_}),_}import gt from"node:fs";import K from"node:fs/promises";import Gn from"node:os";import W from"node:path";var wt="status.json",bt="heartbeat.json",Oe="heartbeat.md",Hn="agent.json",Jn="soul.md",Wn=16*1024,Kn=`# Heartbeat
|
|
9
13
|
|
|
10
14
|
This file tells you what to do on each heartbeat \u2014 the recurring "still here, still
|
|
11
15
|
working" moment. Edit it freely; the daemon reads it but never overwrites your edits.
|
|
@@ -18,28 +22,28 @@ On each heartbeat:
|
|
|
18
22
|
- If you've finished and there's nothing to do, a short idle note is fine.
|
|
19
23
|
|
|
20
24
|
Add your own recurring checks below.
|
|
21
|
-
`,
|
|
22
|
-
`),s=String(t.soul??""),i=await
|
|
23
|
-
`}async function xe(e){let t=W.join(ne(e),ft),n;try{let c=await z.stat(t);if(!c.isFile()||c.size>Nn)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 o=mt(r.status),s=mt(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 mt(e){return e==null?"":String(e).trim().replace(/\s+/g," ").slice(0,$n)}async function bt(e){let t=await Me(e);if(!t)return!1;let n=W.join(t,Ce);try{return await z.access(n),!0}catch{}return he(n,On)}async function kt(e){let t=W.join(ne(e),Ce);try{let n=await z.stat(t);return!n.isFile()||n.size>xn?null:(await z.readFile(t,"utf8")).trim()||null}catch{return null}}var Tn=30*60*1e3,Rn=15*1e3,vt=8,Pn="claude-opus-4-8",re="0.1.22";async function ge(e={}){let t=Ln(e);t.sharedModels=t.share?await at(t.sharedModelsFile):[];let n=!1,r=null,o=null,s=null,i=null,c=0,u=null,l=null,p="",y=null,S=!1,h=null,$=new Map,O=null,b={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},w=new Map,A=new Map,N=[],B=()=>b,F=()=>({connected:S&&!!t.cursorBuddyRuntime,mode:t.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:h?.agentId||h?.agent_id||t.agent,workspaceId:h?.workspaceId||h?.workspace_id||t.workspace,agensisUrl:t.url,handle:h?.handle||t.handle,name:h?.name||t.name,cwd:t.cwd,updatedAt:new Date().toISOString()}),L=()=>{O||!t.lanListener||(O=new ae.Server({port:0}),O.on("listening",()=>{let{port:E}=O.address();b={transport:"ws",listening:!0,addrs:ir(E),auth:"hub-pairwise"},x(`Agent-mesh LAN listener on port ${E}`),ie(r,t,B())}),O.on("connection",E=>{let I=!1,m=setTimeout(()=>{if(!I)try{E.close(1008,"peer auth required")}catch{}},5e3);E.once("message",_=>{clearTimeout(m);let C=Ne(_),P=C?.type==="peer_auth"?w.get(C.ticket):null;if(!P||P.fromAgentId!==C.fromAgentId||Date.now()>P.exp){try{E.close(1008,"invalid ticket")}catch{}return}w.delete(C.ticket),I=!0,E.on("message",G=>{let D=Ne(G);D?.type==="agent_job"&&D.job?.id&&l.enqueue({...D.job,key:D.job.id,lane:_t(D.job),ws:r}).accepted&&x(`Queued peer-handoff job ${D.job.id} from ${C.fromAgentId}`)})})}),O.on("error",E=>x(`LAN listener error: ${E?.message||E}`)))},d=()=>{if(O){try{O.close()}catch{}O=null}b={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},f=E=>new Promise((I,m)=>{if(!T(r,{action:"peer_ticket_request",targetAgentId:E})){m(new Error("hub socket not open"));return}let _=A.get(E)||[];_.push({resolve:I,reject:m}),A.set(E,_),setTimeout(()=>{let C=A.get(E)||[],P=C.findIndex(G=>G.resolve===I);P>=0&&(C.splice(P,1),m(new Error("peer ticket request timed out")))},1e4)}),v=()=>new Promise((E,I)=>{if(!T(r,{action:"peer_list_request"})){I(new Error("hub socket not open"));return}N.push(E),setTimeout(()=>{let m=N.indexOf(E);m>=0&&(N.splice(m,1),E([]))},1e4)}),a=async(E,I)=>{let m=null;try{let C=(await v()).find(D=>D.agentId===E&&D.reach?.listening&&D.reach.addrs?.length);if(!C)return!1;let P=await f(E),G=P.peer?.addrs?.[0]||C.reach.addrs[0];return!G?.host||!G?.port?!1:(m=new ae(`ws://${G.host}:${G.port}`),await new Promise((D,be)=>{m.once("open",D),m.once("error",be),setTimeout(()=>be(new Error("peer connect timed out")),5e3)}),T(m,{type:"peer_auth",ticket:P.ticket,fromAgentId:t.agent}),T(m,{type:"agent_job",job:I}),!0)}catch(_){return x(`Peer handoff to ${E} failed, falling back to hub relay: ${_?.message||_}`),!1}finally{try{m?.close()}catch{}}},g=()=>{n=!0,Ct($),o&&clearTimeout(o),s&&clearInterval(s),i&&clearInterval(i),y&&(y.close().catch(()=>{}),y=null),d(),St(t,{status:"stopped",connected:!1});try{r?.close()}catch{}u&&u()};if(l=Fe({concurrency:t.once?1:t.maxConcurrency,runJob:async(E,I)=>{await Zn(t,E,I),t.once&&g()}}),t.cursorBuddyBridge)try{y=await Ve(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:x,connectionProvider:F}),y?.secret&&(t.cursorBuddyBridgeSecret=y.secret)}catch(E){if(mr(E)){let I=await fr(t.cursorBuddyPort);if(I?.ok){let m=I.pid?` pid ${I.pid}`:"";x(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${m}`)}else x(`CursorBuddy local bridge port ${t.cursorBuddyPort} is in use but did not answer health`)}else x(`CursorBuddy local bridge unavailable: ${E?.message||E}`);y=null}k.once("SIGINT",g),k.once("SIGTERM",g);let M=()=>{if(n)return;let E=jn(t.url,t.token,t);p="",x(`Connecting to ${E.replace(t.token,"redacted")}`),r=new ae(E),r.on("open",()=>{S=!1,h=null,x(`Connected. Registering @${t.handle||"agent"} from ${t.cwd}`),T(r,{type:"auth",token:t.token}),T(r,{action:"agent_register",workspaceId:t.workspace,agentId:t.agent,handle:t.handle,name:t.name,host:ue.hostname(),cwd:t.cwd,metadata:{codingCmd:t.codingCmd,model:t.model,permissionMode:t.permissionMode,permissionFlags:De(t.permissionMode),once:t.once,runtime:"agensis",version:re}}),s=setInterval(()=>{Promise.all([$t(t,B()).catch(()=>null),xe(t).catch(()=>null)]).then(([I,m])=>{T(r,{action:"agent_heartbeat",...I?{capabilitiesHash:I.capabilitiesHash,memoryHash:I.memoryHash}:{},metadata:Oe(t,l,m,xt(t)?y?.getContext?.():null,$)})})},t.heartbeatMs),s.unref&&s.unref()}),r.on("message",I=>{let m=Ne(I);if(m){if(m.type==="agent_registered"){S=!0,h=m.connection||m.agent||null,At(t,m.agent),x(`Registered as ${m.connection?.name||t.name} on ${m.connection?.host||ue.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,m)).catch(_=>{x(`Profile save failed: ${_?.message||_}`)}),Be(t,m.agent).catch(()=>{}),bt(t).catch(()=>{}),It(r,t),L(),ie(r,t,B());return}if(m.type==="agent_config"){At(t,m.agent),x(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),Be(t,m.agent).catch(()=>{});return}if(m.type==="agent_memory_refresh"){It(r,t),ie(r,t,B());return}if(m.type==="agent_capabilities_refresh"){ie(r,t,B());return}if(m.type==="agent_inference_cancel"){$.get(String(m.requestId||""))?.abort();return}if(m.type==="agent_job_cancel"){let _=String(m.jobId||"");_&&l.cancel(_,m.reason||"Cancelled by Agensis")&&x(`Cancelled job ${_}`);return}if(m.type==="agent_inference_request"&&m.requestId){let _=String(m.requestId),C=t.sharedModels.find(D=>D.id===m.model),P=[...$.values()].filter(D=>D.model===m.model).length;if(!C){T(r,{action:"agent_inference_error",requestId:_,error:`Shared model '${m.model||""}' is not available.`});return}if(P>=C.maxConcurrency){T(r,{action:"agent_inference_error",requestId:_,error:"Shared model is at capacity.",code:"capacity_exhausted"});return}let G=new AbortController;$.set(_,{abort:()=>G.abort(),model:C.id}),T(r,{action:"agent_heartbeat",metadata:Oe(t,l,null,null,$)}),ut({models:t.sharedModels,request:m,signal:G.signal,send:D=>T(r,D)}).catch(D=>{T(r,{action:"agent_inference_error",requestId:_,error:G.signal.aborted?"Inference cancelled.":D?.message||String(D),code:G.signal.aborted?"cancelled":"inference_failed"})}).finally(()=>{$.delete(_),T(r,{action:"agent_heartbeat",metadata:Oe(t,l,null,null,$)})});return}if(m.type==="peer_ticket"){let _=m.peer?.agentId,C=A.get(_)||[],P=C.shift();C.length?A.set(_,C):A.delete(_),P&&P.resolve(m);return}if(m.type==="peer_ticket_grant"){w.set(m.ticket,{fromAgentId:m.fromAgentId,exp:m.exp});return}if(m.type==="peer_list"){let _=N.shift();_&&_(Array.isArray(m.peers)?m.peers:[]);return}if(m.type==="agent_reach_disable"){d(),ie(r,t,B());return}if(m.type==="error"){x(`Server rejected request: ${m.message||"unknown error"}`);return}if(m.type==="agent_disabled"){S=!1,h=null,x(`Agent disabled by Agensis: ${m.reason||"deactivated"}`),g();return}if(m.type==="agent_job"&&m.job?.id){let _=l.enqueue({...m.job,key:m.job.id,lane:_t(m.job),ws:r});_.accepted&&(c+=1,x(`Queued job ${m.job.id} at position ${_.position}`),t.once&&l.idle().then(()=>g()))}}}),r.on("close",(I,m)=>{Ct($),S=!1,h=null;let _=String(m||"");if(x(`Socket closed (${I||"no-code"}${_?`: ${_}`:""})`),s&&(clearInterval(s),s=null),I===1008&&/agent deactivated|authentication failed/i.test(_)){x("Stopping daemon because Agensis rejected this agent connection."),g();return}if(p==="ECONNREFUSED"&&Gn(t.url)){x("Local agent backend is not running on 127.0.0.1:3142."),x("Start it in another terminal with: npm run backend"),x("Then rerun this connect command."),g();return}t.once&&c>0&&l.active()===0&&l.size()===0&&g(),!(n||t.once)&&(o=setTimeout(M,2e3),o.unref&&o.unref())}),r.on("error",I=>{p=I?.code||"",x(`Socket error: ${I?.message||I}`)})},j=async()=>{let E=await xe(t).catch(()=>null);await yt(t,{busy:l.active()>0,active:l.active(),queueSize:l.size(),connected:r?.readyState===ae.OPEN,agentStatus:E?.status,agentNote:E?.note}).catch(()=>{})};j(),i=setInterval(()=>{j()},t.heartbeatMs),i.unref&&i.unref(),M(),await new Promise(E=>{let I=setInterval(async()=>{t.once&&c>0&&l.active()===0&&l.size()===0&&g(),n&&g()},500);u=()=>{clearInterval(I),E()}}),u=null,k.off("SIGINT",g),k.off("SIGTERM",g)}function Ln(e){let t=Un(e.cursorBuddyBridge),n=e.noCoding===!0||k.env.AGENSIS_NO_CODING==="1",r={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:Dt(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:$e(e.model||k.env.AGENSIS_MODEL||k.env.CLAUDE_MODEL||""),permissionMode:ye(e.permissionMode||e.permission_mode||e.permission||k.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||k.env.AGENSIS_TIMEOUT_MS||Tn),heartbeatMs:Number(e.heartbeatMs||k.env.AGENSIS_HEARTBEAT_MS||Rn),maxConcurrency:Math.max(1,Number(e.maxConcurrency||k.env.AGENSIS_MAX_CONCURRENCY||vt)||vt),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};r.sharedModelsFile&&!ce.isAbsolute(r.sharedModelsFile)&&(r.sharedModelsFile=ce.resolve(r.cwd,r.sharedModelsFile));let o=[];if(r.url||o.push("--url"),r.token||o.push("--token"),r.workspace||o.push("--workspace"),r.agent||o.push("--agent"),r.share&&!r.sharedModelsFile&&o.push("--shared-models-file"),o.length)throw new Error(`Missing required option(s): ${o.join(", ")}`);return r}function Un(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 jn(e,t,n={}){let r=Bt(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 Bt(e){let t=new URL(e);return Fn(t)&&(t.protocol="http:",t.hostname="127.0.0.1",t.port="3142"),t}function Fn(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 Gn(e){try{let t=Bt(e);return(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="0.0.0.0")&&t.port==="3142"}catch{return!1}}function _t(e){let t=String(e?.sessionId||""),n=String(e?.threadParentId||"");return`${t}::${n}`}var Hn=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,Jn=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function Wn(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function zn(e){for(let t of Jn){let n=String(e||"").match(t),r=Wn(n?.[1]||"");if(r)return r}return""}function Kn(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 qn(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=Kn(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 Yn(e){let t=qn(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=Hn.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=zn(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 Xn(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 Vn(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 xt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function Qn(e,t,n,r){let o="cursorbuddy-control",s="native",i=[],c=(p="")=>{T(t.ws,{action:"agent_job_delta",jobId:t.id,content:p,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i})};c("");let u="",l="";try{await Xn(e,n),u=Vn(n),c(u)}catch(p){l=String(p?.message||p),u=`CursorBuddy control failed: ${l}`,c(u)}T(t.ws,{action:"agent_job_result",jobId:t.id,response:u,error:l,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i}),x(`Finished native CursorBuddy ${n.action} job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`)}async function Zn(e,t,{signal:n}){let r=Date.now();x(`Starting job ${t.id}`);let o=Yn(t.prompt);if(o&&xt(e)){await Qn(e,t,o,r),e.once&&(x("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>k.exit(0),150));return}let s=tr(e,t),i=await er(e,t),c="",u="",l=0,p=(A="")=>{T(t.ws,{action:"agent_job_delta",jobId:t.id,content:A,elapsedMs:Date.now()-r,model:s.model,permissionMode:s.permissionMode,permissionFlags:s.permissionFlags})};p("");let y=s.streamJson?nr():null,S=setInterval(()=>p(c),1e3);S.unref&&S.unref();let h=await oe({cmd:s.cmd,args:[...s.args,i],cwd:t.cwd||e.cwd,timeoutMs:e.timeoutMs,heartbeatMs:e.heartbeatMs,label:"agent job",signal:n,onData:A=>{y?(y.feed(A),c=y.live):(c+=String(A||""),u=dr(`${u}
|
|
24
|
-
${
|
|
25
|
-
${
|
|
25
|
+
`,zn=8*1024,qn=400;function yt(e,t){return String(e||"").trim().replace(/[^a-zA-Z0-9._-]+/g,"-").replace(/\.{2,}/g,".").replace(/^[.-]+/,"").slice(0,96)||t}function re({workspace:e,agent:t,homedir:n=Gn.homedir()}={}){return W.join(n,".agensis",yt(e,"workspace"),yt(t,"agent"))}function _t(e){return W.join(re(e),wt)}function kt(e){return W.join(re(e),Oe)}async function Ne(e){let t=re(e);try{return await K.mkdir(t,{recursive:!0}),t}catch{return null}}async function ye(e,t){let n=`${e}.tmp-${process.pid}`;try{return await K.writeFile(n,t),await K.rename(n,e),!0}catch{try{await K.rm(n,{force:!0})}catch{}return!1}}async function Be(e,t){if(!t||typeof t!="object")return!1;let n=await Ne(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()},o=await ye(W.join(n,Hn),`${JSON.stringify(r,null,2)}
|
|
26
|
+
`),s=String(t.soul??""),i=await ye(W.join(n,Jn),s);return o&&i}async function vt(e,t={}){let n=await Ne(e);return n?ye(W.join(n,bt),It(e,t)):!1}function Et(e,t={}){let n=re(e);try{return gt.mkdirSync(n,{recursive:!0}),gt.writeFileSync(W.join(n,bt),It(e,t)),!0}catch{return!1}}function It(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)}
|
|
27
|
+
`}async function $e(e){let t=W.join(re(e),wt),n;try{let a=await K.stat(t);if(!a.isFile()||a.size>zn)return null;n=await K.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=St(r.status),s=St(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 St(e){return e==null?"":String(e).trim().replace(/\s+/g," ").slice(0,qn)}async function At(e){let t=await Ne(e);if(!t)return!1;let n=W.join(t,Oe);try{return await K.access(n),!0}catch{}return ye(n,Kn)}async function Ct(e){let t=W.join(re(e),Oe);try{let n=await K.stat(t);return!n.isFile()||n.size>Wn?null:(await K.readFile(t,"utf8")).trim()||null}catch{return null}}var Xn=30*60*1e3,Vn=15*1e3,xt=8,Qn="claude-opus-4-8",oe="0.1.24";async function Se(e={}){let t=Zn(e);t.sharedModels=t.share?await ft(t.sharedModelsFile):[];let n=!1,r=null,o=null,s=null,i=null,a=0,u=null,d=null,f="",h=null,S=!1,g=null,x=new Map,$=null,_={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},w=new Map,M=new Map,N=[],O=()=>_,F=()=>({connected:S&&!!t.cursorBuddyRuntime,mode:t.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:g?.agentId||g?.agent_id||t.agent,workspaceId:g?.workspaceId||g?.workspace_id||t.workspace,agensisUrl:t.url,handle:g?.handle||t.handle,name:g?.name||t.name,cwd:t.cwd,updatedAt:new Date().toISOString()}),U=()=>{$||!t.lanListener||($=new ce.Server({port:0}),$.on("listening",()=>{let{port:I}=$.address();_={transport:"ws",listening:!0,addrs:kr(I),auth:"hub-pairwise"},B(`Agent-mesh LAN listener on port ${I}`),ae(r,t,O())}),$.on("connection",I=>{let A=!1,m=setTimeout(()=>{if(!A)try{I.close(1008,"peer auth required")}catch{}},5e3);I.once("message",E=>{clearTimeout(m);let C=De(E),L=C?.type==="peer_auth"?w.get(C.ticket):null;if(!L||L.fromAgentId!==C.fromAgentId||Date.now()>L.exp){try{I.close(1008,"invalid ticket")}catch{}return}w.delete(C.ticket),A=!0,I.on("message",G=>{let T=De(G);T?.type==="agent_job"&&T.job?.id&&d.enqueue({...T.job,key:T.job.id,lane:Mt(T.job),ws:r}).accepted&&B(`Queued peer-handoff job ${T.job.id} from ${C.fromAgentId}`)})})}),$.on("error",I=>B(`LAN listener error: ${I?.message||I}`)))},l=()=>{if($){try{$.close()}catch{}$=null}_={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},p=I=>new Promise((A,m)=>{if(!D(r,{action:"peer_ticket_request",targetAgentId:I})){m(new Error("hub socket not open"));return}let E=M.get(I)||[];E.push({resolve:A,reject:m}),M.set(I,E),setTimeout(()=>{let C=M.get(I)||[],L=C.findIndex(G=>G.resolve===A);L>=0&&(C.splice(L,1),m(new Error("peer ticket request timed out")))},1e4)}),k=()=>new Promise((I,A)=>{if(!D(r,{action:"peer_list_request"})){A(new Error("hub socket not open"));return}N.push(I),setTimeout(()=>{let m=N.indexOf(I);m>=0&&(N.splice(m,1),I([]))},1e4)}),c=async(I,A)=>{let m=null;try{let C=(await k()).find(T=>T.agentId===I&&T.reach?.listening&&T.reach.addrs?.length);if(!C)return!1;let L=await p(I),G=L.peer?.addrs?.[0]||C.reach.addrs[0];return!G?.host||!G?.port?!1:(m=new ce(`ws://${G.host}:${G.port}`),await new Promise((T,ke)=>{m.once("open",T),m.once("error",ke),setTimeout(()=>ke(new Error("peer connect timed out")),5e3)}),D(m,{type:"peer_auth",ticket:L.ticket,fromAgentId:t.agent}),D(m,{type:"agent_job",job:A}),!0)}catch(E){return B(`Peer handoff to ${I} failed, falling back to hub relay: ${E?.message||E}`),!1}finally{try{m?.close()}catch{}}},y=()=>{n=!0,$t(x),o&&clearTimeout(o),s&&clearInterval(s),i&&clearInterval(i),h&&(h.close().catch(()=>{}),h=null),l(),Et(t,{status:"stopped",connected:!1});try{r?.close()}catch{}u&&u()};if(d=ze({concurrency:t.once?1:t.maxConcurrency,runJob:async(I,A)=>{await pr(t,I,A),t.once&&y()}}),t.cursorBuddyBridge)try{h=await rt(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:B,connectionProvider:F}),h?.secret&&(t.cursorBuddyBridgeSecret=h.secret)}catch(I){if(xr(I)){let A=await Mr(t.cursorBuddyPort);if(A?.ok){let m=A.pid?` pid ${A.pid}`:"";B(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${m}`)}else B(`CursorBuddy local bridge port ${t.cursorBuddyPort} is in use but did not answer health`)}else B(`CursorBuddy local bridge unavailable: ${I?.message||I}`);h=null}b.once("SIGINT",y),b.once("SIGTERM",y);let v=()=>{if(n)return;let I=tr(t.url,t.token,t);f="",B(`Connecting to ${I.replace(t.token,"redacted")}`),r=new ce(I),r.on("open",()=>{S=!1,g=null,B(`Connected. Registering @${t.handle||"agent"} from ${t.cwd}`),D(r,{type:"auth",token:t.token}),D(r,{action:"agent_register",workspaceId:t.workspace,agentId:t.agent,handle:t.handle,name:t.name,host:le.hostname(),cwd:t.cwd,metadata:{codingCmd:t.codingCmd,model:t.model,permissionMode:t.permissionMode,permissionFlags:Pe(t.permissionMode),once:t.once,runtime:"agensis",version:oe}}),s=setInterval(()=>{Promise.all([Lt(t,O()).catch(()=>null),$e(t).catch(()=>null)]).then(([A,m])=>{D(r,{action:"agent_heartbeat",...A?{capabilitiesHash:A.capabilitiesHash,memoryHash:A.memoryHash}:{},metadata:Te(t,d,m,Dt(t)?h?.getContext?.():null,x)})})},t.heartbeatMs),s.unref&&s.unref()}),r.on("message",A=>{let m=De(A);if(m){if(m.type==="agent_registered"){S=!0,g=m.connection||m.agent||null,Ot(t,m.agent),B(`Registered as ${m.connection?.name||t.name} on ${m.connection?.host||le.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,m)).catch(E=>{B(`Profile save failed: ${E?.message||E}`)}),Be(t,m.agent).catch(()=>{}),At(t).catch(()=>{}),Bt(r,t),U(),ae(r,t,O());return}if(m.type==="agent_config"){Ot(t,m.agent),B(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),Be(t,m.agent).catch(()=>{});return}if(m.type==="agent_memory_refresh"){Bt(r,t),ae(r,t,O());return}if(m.type==="agent_capabilities_refresh"){ae(r,t,O());return}if(m.type==="agent_inference_cancel"){x.get(String(m.requestId||""))?.abort();return}if(m.type==="agent_job_cancel"){let E=String(m.jobId||"");E&&d.cancel(E,m.reason||"Cancelled by Agensis")&&B(`Cancelled job ${E}`);return}if(m.type==="agent_inference_request"&&m.requestId){let E=String(m.requestId),C=t.sharedModels.find(T=>T.id===m.model),L=[...x.values()].filter(T=>T.model===m.model).length;if(!C){D(r,{action:"agent_inference_error",requestId:E,error:`Shared model '${m.model||""}' is not available.`});return}if(L>=C.maxConcurrency){D(r,{action:"agent_inference_error",requestId:E,error:"Shared model is at capacity.",code:"capacity_exhausted"});return}let G=new AbortController;x.set(E,{abort:()=>G.abort(),model:C.id}),D(r,{action:"agent_heartbeat",metadata:Te(t,d,null,null,x)}),ht({models:t.sharedModels,request:m,signal:G.signal,send:T=>D(r,T)}).catch(T=>{D(r,{action:"agent_inference_error",requestId:E,error:G.signal.aborted?"Inference cancelled.":T?.message||String(T),code:G.signal.aborted?"cancelled":"inference_failed"})}).finally(()=>{x.delete(E),D(r,{action:"agent_heartbeat",metadata:Te(t,d,null,null,x)})});return}if(m.type==="peer_ticket"){let E=m.peer?.agentId,C=M.get(E)||[],L=C.shift();C.length?M.set(E,C):M.delete(E),L&&L.resolve(m);return}if(m.type==="peer_ticket_grant"){w.set(m.ticket,{fromAgentId:m.fromAgentId,exp:m.exp});return}if(m.type==="peer_list"){let E=N.shift();E&&E(Array.isArray(m.peers)?m.peers:[]);return}if(m.type==="agent_reach_disable"){l(),ae(r,t,O());return}if(m.type==="error"){B(`Server rejected request: ${m.message||"unknown error"}`);return}if(m.type==="agent_disabled"){S=!1,g=null,B(`Agent disabled by Agensis: ${m.reason||"deactivated"}`),y();return}if(m.type==="agent_job"&&m.job?.id){let E=d.enqueue({...m.job,key:m.job.id,lane:Mt(m.job),ws:r});E.accepted&&(a+=1,B(`Queued job ${m.job.id} at position ${E.position}`),t.once&&d.idle().then(()=>y()))}}}),r.on("close",(A,m)=>{$t(x),S=!1,g=null;let E=String(m||"");if(B(`Socket closed (${A||"no-code"}${E?`: ${E}`:""})`),s&&(clearInterval(s),s=null),A===1008&&/agent deactivated|authentication failed/i.test(E)){B("Stopping daemon because Agensis rejected this agent connection."),y();return}if(f==="ECONNREFUSED"&&rr(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."),y();return}t.once&&a>0&&d.active()===0&&d.size()===0&&y(),!(n||t.once)&&(o=setTimeout(v,2e3),o.unref&&o.unref())}),r.on("error",A=>{f=A?.code||"",B(`Socket error: ${A?.message||A}`)})},P=async()=>{let I=await $e(t).catch(()=>null);await vt(t,{busy:d.active()>0,active:d.active(),queueSize:d.size(),connected:r?.readyState===ce.OPEN,agentStatus:I?.status,agentNote:I?.note}).catch(()=>{})};P(),i=setInterval(()=>{P()},t.heartbeatMs),i.unref&&i.unref(),v(),await new Promise(I=>{let A=setInterval(async()=>{t.once&&a>0&&d.active()===0&&d.size()===0&&y(),n&&y()},500);u=()=>{clearInterval(A),I()}}),u=null,b.off("SIGINT",y),b.off("SIGTERM",y)}function Zn(e){let t=er(e.cursorBuddyBridge),n=e.noCoding===!0||b.env.AGENSIS_NO_CODING==="1",r={url:String(e.url||e.baseUrl||b.env.AGENSIS_URL||"").trim(),token:String(e.token||b.env.AGENSIS_TOKEN||"").trim(),workspace:String(e.workspace||e.workspaceId||b.env.AGENSIS_WORKSPACE||b.env.AGENSIS_WORKSPACE_ID||"").trim(),agent:String(e.agent||e.agentId||b.env.AGENSIS_AGENT||b.env.AGENSIS_AGENT_ID||"").trim(),handle:Ut(e.handle||b.env.AGENSIS_HANDLE||e.name||b.env.AGENSIS_NAME||"agent"),name:String(e.name||b.env.AGENSIS_NAME||e.handle||b.env.AGENSIS_HANDLE||"agensis Agent").trim(),cwd:String(e.cwd||b.env.AGENSIS_CWD||b.cwd()).trim(),codingCmd:n?"":String(e.codingCmd||b.env.AGENSIS_CODING_CMD||b.env.CODING_CMD||"claude -p").trim(),model:Re(e.model||b.env.AGENSIS_MODEL||b.env.CLAUDE_MODEL||""),permissionMode:we(e.permissionMode||e.permission_mode||e.permission||b.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||b.env.AGENSIS_TIMEOUT_MS||Xn),heartbeatMs:Number(e.heartbeatMs||b.env.AGENSIS_HEARTBEAT_MS||Vn),maxConcurrency:Math.max(1,Number(e.maxConcurrency||b.env.AGENSIS_MAX_CONCURRENCY||xt)||xt),once:!!(e.once||b.env.AGENSIS_ONCE==="1"),exitOnOnce:!!e.exitOnOnce,onRegistered:typeof e.onRegistered=="function"?e.onRegistered:null,primaryDaemon:!!(e.primaryDaemon||b.env.AGENSIS_PRIMARY_DAEMON==="1"),cursorBuddyRuntime:!!(e.cursorBuddyRuntime||b.env.AGENSIS_CURSORBUDDY_RUNTIME==="1"),cursorBuddyBridge:t,cursorBuddyPort:Number(e.cursorBuddyPort||b.env.AGENSIS_CURSORBUDDY_PORT||8787),cursorBuddyBridgeSecret:String(e.cursorBuddyBridgeSecret||b.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),cursorBuddyModel:String(e.cursorBuddyModel||b.env.AGENSIS_CURSORBUDDY_MODEL||"haiku-4.5").trim(),lanListener:!!(e.lanListener||e.lan||b.env.AGENSIS_LAN==="1"),share:!!(e.share||b.env.AGENSIS_SHARE==="1"),sharedModelsFile:String(e.sharedModelsFile||b.env.AGENSIS_SHARED_MODELS_FILE||"").trim(),noCoding:n};r.sharedModelsFile&&!de.isAbsolute(r.sharedModelsFile)&&(r.sharedModelsFile=de.resolve(r.cwd,r.sharedModelsFile));let o=[];if(r.url||o.push("--url"),r.token||o.push("--token"),r.workspace||o.push("--workspace"),r.agent||o.push("--agent"),r.share&&!r.sharedModelsFile&&o.push("--shared-models-file"),o.length)throw new Error(`Missing required option(s): ${o.join(", ")}`);return r}function er(e){let t=b.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 tr(e,t,n={}){let r=Tt(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 Tt(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 rr(e){try{let t=Tt(e);return(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="0.0.0.0")&&t.port==="3142"}catch{return!1}}function Mt(e){let t=String(e?.sessionId||""),n=String(e?.threadParentId||"");return`${t}::${n}`}var or=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,sr=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function ir(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function ar(e){for(let t of sr){let n=String(e||"").match(t),r=ir(n?.[1]||"");if(r)return r}return""}function cr(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 ur(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=cr(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 dr(e){let t=ur(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=or.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=ar(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 lr(e,t){let r=`http://127.0.0.1:${Number(e.cursorBuddyPort||8787)}/cursorbuddy/control`,o=String(e.cursorBuddyBridgeSecret||b.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)}),a=null;try{a=await i.json()}catch{a=null}if(!i.ok||a?.ok===!1)throw new Error(a?.error||`CursorBuddy control failed with HTTP ${i.status}`);return a}function mr(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 Dt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function fr(e,t,n,r){let o="cursorbuddy-control",s="native",i=[],a=(f="")=>{D(t.ws,{action:"agent_job_delta",jobId:t.id,content:f,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i})};a("");let u="",d="";try{await lr(e,n),u=mr(n),a(u)}catch(f){d=String(f?.message||f),u=`CursorBuddy control failed: ${d}`,a(u)}D(t.ws,{action:"agent_job_result",jobId:t.id,response:u,error:d,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 pr(e,t,{signal:n}){let r=Date.now();B(`Starting job ${t.id}`);let o=dr(t.prompt);if(o&&Dt(e)){await fr(e,t,o,r),e.once&&(B("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>b.exit(0),150));return}let s=gr(e,t),i=await hr(e,t),a="",u="",d=0,f=(N="")=>{D(t.ws,{action:"agent_job_delta",jobId:t.id,content:N,elapsedMs:Date.now()-r,model:s.model,permissionMode:s.permissionMode,permissionFlags:s.permissionFlags})};f("");let h=s.streamJson?yr():null,S=setInterval(()=>f(a),1e3);S.unref&&S.unref();let x=await Ke(t).run({cmd:s.cmd,args:[...s.args,i],cwd:t.cwd||e.cwd,timeoutMs:e.timeoutMs,heartbeatMs:e.heartbeatMs,label:"agent job",signal:n,job:t,onData:N=>{h?(h.feed(N),a=h.live):(a+=String(N||""),u=Cr(`${u}
|
|
28
|
+
${N}`));let O=Date.now();O-d>150&&(d=O,f(a))}});clearInterval(S),h&&(h.end(),a=h.live,f(a));let $=String(x.stdout||"").trim(),_=String(x.stderr||"").trim(),w=x.error?x.error.message:x.status===0?"":_||`Command exited with status ${x.status}`,M=h?h.result||(w?"":_):$||(w?"":_)||u||"";D(t.ws,{action:"agent_job_result",jobId:t.id,response:M,error:w,elapsedMs:Date.now()-r,model:s.model,permissionMode:s.permissionMode,permissionFlags:s.permissionFlags}),B(`Finished job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`),e.once&&(B("One-shot job complete; exiting."),setTimeout(()=>b.exit(0),150))}async function hr(e,t){let n=t.agent||{},r=Array.isArray(n.skills)?n.skills.join(", "):String(n.skills||""),o=Array.isArray(n.tools)?n.tools.join(", "):String(n.tools||""),s=Rt(e,t),i=Pt(e,t),a=await Ct(e).catch(()=>null),u=a?`Heartbeat (recurring instructions \u2014 edit at ${kt(e)}):
|
|
29
|
+
${a}`:"";return["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: ${s}`,`Permission mode: ${i}`,n.description?`Description:
|
|
26
30
|
${n.description}`:"",n.soul?`Soul:
|
|
27
31
|
${n.soul}`:"",n.system_prompt?`System instructions:
|
|
28
32
|
${n.system_prompt}`:"",n.instructions?`Additional instructions:
|
|
29
33
|
${n.instructions}`:"",o?`Enabled tools:
|
|
30
34
|
${o}`:"",r?`Enabled skills:
|
|
31
|
-
${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 ${
|
|
35
|
+
${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 ${_t(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,"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.","User message:",String(t.prompt||"")].filter(Boolean).join(`
|
|
32
36
|
|
|
33
|
-
`)}function
|
|
34
|
-
`))>=0;)i(e.slice(0,u)),e=e.slice(u+1)},end(){e&&(i(e),e="")},get live(){return n?t:r},get result(){return o??(n?t:r)}}}function
|
|
35
|
-
`)}function
|
|
36
|
-
`,{mode:384}),await
|
|
37
|
-
`)}import
|
|
38
|
-
`,{mode:384}),await
|
|
37
|
+
`)}function gr(e,t){let{cmd:n,args:r}=Ar(e.codingCmd),o=Rt(e,t),s=Pt(e,t),i=vr(r),a=Pe(s);if(Er(n)){let u=[...i];if(o&&u.push("--model",o),s==="accept_edits"&&u.push("--permission-mode","acceptEdits"),s==="yolo"){let S=t&&t.agent&&t.agent.run_mode==="sandbox",g=typeof b.getuid=="function"&&b.getuid()===0,x=S||Sr(),$=b.env.AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS==="1";x||!g||$?u.push("--dangerously-skip-permissions"):(a=[],B("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 d=i.some(S=>S==="--output-format"||String(S).startsWith("--output-format=")),f=i.includes("-p")||i.includes("--print"),h=!1;return!d&&f?(u.push("--output-format","stream-json","--include-partial-messages"),i.includes("--verbose")||u.push("--verbose"),h=!0):d&&(h=i.some(S=>/stream-json/.test(String(S)))),{cmd:n,args:u,model:o,permissionMode:s,permissionFlags:a,streamJson:h}}if(Ir(n)){let u=[...i];return o&&u.push("--model",o),s==="yolo"&&u.push("--sandbox","danger-full-access","--ask-for-approval","never"),{cmd:n,args:u,model:o,permissionMode:s,permissionFlags:a}}return{cmd:n,args:r,model:o,permissionMode:s,permissionFlags:a}}function yr(){let e="",t="",n=!1,r="",o=null,s=a=>{if(!a||typeof a!="object")return;let u=a.event&&a.event.delta||a.delta;if(u&&u.type==="text_delta"&&typeof u.text=="string"){n=!0,t+=u.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 d=a.message.content.filter(f=>f&&f.type==="text"&&typeof f.text=="string").map(f=>f.text).join("");d&&(r+=d)}},i=a=>{let u=String(a).trim();if(u)try{s(JSON.parse(u))}catch{}};return{feed(a){e+=String(a||"");let u;for(;(u=e.indexOf(`
|
|
38
|
+
`))>=0;)i(e.slice(0,u)),e=e.slice(u+1)},end(){e&&(i(e),e="")},get live(){return n?t:r},get result(){return o??(n?t:r)}}}function Rt(e,t){return Re(t?.agent?.model||t?.model||e.model)}function Re(e){let t=String(e||"").trim();return!t||t==="auto"||t==="claude-fable-5"?Qn:t}function Pt(e,t){return we(t?.agent?.permissionMode||t?.agent?.permission_mode||t?.permissionMode||t?.permission_mode||e.permissionMode)}function we(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 Pe(e){return we(e)==="yolo"?["--no-sandbox","--yolo"]:[]}var Q;function Sr(){if(Q!==void 0)return Q;let e=b.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(ue.existsSync("/.dockerenv")||ue.existsSync("/run/.containerenv"))return Q=!0}catch{}try{let t=ue.readFileSync("/proc/1/cgroup","utf8");if(/docker|kubepods|containerd|lxc|podman/i.test(t))return Q=!0}catch{}return Q=!1}function Te(e,t,n,r=null,o=null){let s={busy:t.active()>0,queueSize:t.size(),cwd:e.cwd,model:e.model,permissionMode:e.permissionMode,permissionFlags:Pe(e.permissionMode),daemon:{runtime:"agensis-cli",version:oe,pid:b.pid,node:b.version,platform:b.platform,arch:b.arch,host:le.hostname(),cwd:e.cwd}};if(o instanceof Map){let i={};for(let a of o.values()){let u=String(a?.model||"");u&&(i[u]=(i[u]||0)+1)}s.activeInferenceByModel=i}return r&&typeof r=="object"&&(s.cursorBuddy=wr(r)),n?.status&&(s.agentStatus=n.status),n?.note&&(s.agentNote=n.note),(n?.status||n?.note)&&(s.agentStatusAt=new Date().toISOString()),s}function wr(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:{},o=e.manifest&&typeof e.manifest=="object"?e.manifest:{},s=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(o.name||"").slice(0,120),version:String(o.version||"").slice(0,80),source:String(o.source||"").slice(0,500)},project:{name:String(s.name||"").slice(0,120),root:String(s.root||"").slice(0,500),agent:String(s.agent||"").slice(0,80)},updatedAt:String(e.updatedAt||"").slice(0,80)}}function Ot(e,t){if(!t||typeof t!="object")return;t.name&&(e.name=String(t.name).trim()||e.name),(t.handle||t.name)&&(e.handle=Ut(t.handle||t.name||e.handle)),t.model&&(e.model=Re(t.model));let n=t.permissionMode||t.permission_mode;n&&(e.permissionMode=we(n)),(t.memory_dir!==void 0||t.memoryDir!==void 0)&&(e.memoryDir=String(t.memory_dir??t.memoryDir??"").trim())}function br(){let e=["claude","codex","gh","node","npm","python3","git","fly","vercel"],t=(b.env.PATH||"").split(de.delimiter).filter(Boolean);return e.filter(n=>t.some(r=>{try{return ue.existsSync(de.join(r,n))}catch{return!1}}))}function _r(){try{let e=ue.readFileSync(de.join(le.homedir(),".claude.json"),"utf8"),n=JSON.parse(e)?.mcpServers;if(n&&typeof n=="object")return Object.keys(n).sort()}catch{}return[]}function Nt(e){return Yn.createHash("sha1").update(String(e)).digest("hex").slice(0,16)}async function Lt(e,t=null){let n=lt({cwd:e.cwd}),r=dt({cwd:e.cwd}),o=br(),s=_r(),i=Ae({cwd:e.cwd,memoryDir:e.memoryDir})||null,a=pt(e.sharedModels),u=Nt(JSON.stringify({skills:n,commands:r,clis:o,mcpServers:s,memoryRoot:i,sharedModels:a,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null})),d=Nt(await it(i));return{skills:n,commands:r,clis:o,mcpServers:s,memoryRoot:i,sharedModels:a,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null,capabilitiesHash:u,memoryHash:d}}async function ae(e,t,n=null){try{let r=await Lt(t,n);D(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}),B(`Capabilities synced \u2014 skills:${r.skills.length} commands:${r.commands.length} clis:${r.clis.length} mcp:${r.mcpServers.length}`)}catch(r){B(`Capabilities sync skipped: ${r?.message||r}`)}}function kr(e){let t=le.networkInterfaces(),n=[];for(let r of Object.values(t))for(let o of r||[])o.family==="IPv4"&&!o.internal&&n.push({host:o.address,port:e,scope:"lan"});return n.slice(0,4)}async function Bt(e,t){try{let n=Ae({cwd:t.cwd,memoryDir:t.memoryDir});if(!n)return;let r=await at(n);D(e,{action:"agent_memory_sync",workspaceId:t.workspace,agentId:t.agent,root:n,files:r}),B(`Synced ${r.length} memory file${r.length===1?"":"s"} from ${n}`)}catch(n){B(`Memory sync skipped: ${n?.message||n}`)}}function vr(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 o=0;o<e.length;o+=1){let s=e[o],[i]=String(s).split("=",1);if(!n.has(s)){if(t.has(i)){String(s).includes("=")||(o+=1);continue}r.push(s)}}return r}function Er(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function Ir(e){return/(^|\/)codex(?:$|\.)/.test(String(e||""))}function Ar(e){let t=[],n="",r="",o=!1;for(let s of e){if(o){n+=s,o=!1;continue}if(s==="\\"){o=!0;continue}if(r){s===r?r="":n+=s;continue}if(s==='"'||s==="'"){r=s;continue}if(/\s/.test(s)){n&&(t.push(n),n="");continue}n+=s}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function De(e){try{return JSON.parse(String(e))}catch{return null}}function D(e,t){return!e||e.readyState!==ce.OPEN?!1:(e.send(JSON.stringify(t)),!0)}function Cr(e){return String(e||"").split(/\r?\n/).map(t=>t.trim()).filter(Boolean).slice(-1)[0]||""}function Ut(e){return String(e||"").trim().toLowerCase().replace(/^@+/,"").replace(/[^a-z0-9_.-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)}function xr(e){return e?.code==="EADDRINUSE"||/\bEADDRINUSE\b/.test(String(e?.message||e))}async function Mr(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}),o=await r.json().catch(()=>({}));return!r.ok||!o?.ok?null:o}catch{return null}finally{clearTimeout(n)}}function B(e){b.stderr.write(`[agensis] ${e}
|
|
39
|
+
`)}function $t(e){if(e instanceof Map)for(let t of e.values())try{t?.abort?.()}catch{}}import Or from"node:crypto";import me from"node:fs/promises";import Nr from"node:os";import jt from"node:path";var Z="default",Br=/^[a-zA-Z0-9_.-]{1,64}$/,$r=["url","token","workspace","agent","handle","name","cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","lanListener","primaryDaemon","cursorBuddyBridge","cursorBuddyPort"];function z(e=Z){let t=String(e||Z).trim();if(!Br.test(t))throw new Error("Daemon profile names may only contain letters, numbers, dot, dash, and underscore.");return t}function Ft(e=Z,t={}){let n=t.homedir||Nr.homedir();return jt.join(n,".agensis","daemon-profiles",`${z(e)}.json`)}function Le(e={}){let t={};for(let n of $r){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 Gt(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 Ue(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 Ht(e=Z,t={}){let n=Ft(e,t),r;try{r=await me.readFile(n,"utf8")}catch(i){if(i?.code==="ENOENT")return null;throw i}let o;try{o=JSON.parse(r)}catch(i){throw new Error(`Daemon profile "${z(e)}" is unreadable: ${i?.message||i}`)}let s=o?.config;return!s?.url||!s?.token||!s?.workspace||!s?.agent?null:Le(s)}async function be(e=Z,t={},n={}){let r=Le(t);if(!r.url||!r.token||!r.workspace||!r.agent)return null;let o=Ft(e,n),s=jt.dirname(o);await me.mkdir(s,{recursive:!0,mode:448});let i=`${o}.${process.pid}.${Date.now()}.tmp`,a={version:1,savedAt:new Date().toISOString(),profile:z(e),tokenHash:Or.createHash("sha256").update(r.token).digest("hex"),config:r};return await me.writeFile(i,`${JSON.stringify(a,null,2)}
|
|
40
|
+
`,{mode:384}),await me.rename(i,o),await me.chmod(o,384).catch(()=>{}),o}function Jt(e,t={}){let n={...e,...Le(t),command:"connect"};return 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 Wt(e=Z){let t=z(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===Z?"":` --profile ${t}`}`].join(`
|
|
41
|
+
`)}import Tr from"node:crypto";import fe from"node:fs/promises";import Kt from"node:os";import je from"node:path";import Fe from"node:process";var Dr=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/;function Rr(e={}){return String(e.url||e.baseUrl||Fe.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function zt(e,t={}){let n=t.homedir||Kt.homedir(),r=Tr.createHash("sha256").update(String(e)).digest("hex");return je.join(n,".agensis","cursorbuddy","connection-keys",`${r}.json`)}function Pr(){return new Error("Missing or invalid --key. Create a CursorBuddy connection key in Agensis first.")}function Ge(e){let t=String(e||"").trim();if(!Dr.test(t))throw Pr();return t}function Lr(e,t,n,r){let o=t?.token,s=t?.workspaceId||t?.workspace_id||t?.agent?.workspace_id,i=t?.agentId||t?.agent?.id;if(!o||!s||!i)throw new Error("CursorBuddy key claim did not return a complete daemon connection payload");let{key:a,subcommand:u,...d}=e;return{...d,command:"connect",url:t.baseUrl||n,token:o,workspace:s,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 Ur(e,t={}){Ge(e);let n=zt(e,t),r;try{r=await fe.readFile(n,"utf8")}catch(i){if(i?.code==="ENOENT")return null;throw i}let o;try{o=JSON.parse(r)}catch(i){throw new Error(`Cached CursorBuddy daemon config is unreadable: ${i?.message||i}`)}let s=o?.daemonArgs;return!s?.token||!s?.workspace||!s?.agent||!s?.url?null:s}async function jr(e,t,n={}){if(Ge(e),!t?.token||!t?.workspace||!t?.agent||!t?.url)return;let r=zt(e,n),o=je.dirname(r);await fe.mkdir(o,{recursive:!0,mode:448});let s=`${r}.${Fe.pid}.${Date.now()}.tmp`,i={version:1,savedAt:new Date().toISOString(),keyHash:je.basename(r,".json"),daemonArgs:t};await fe.writeFile(s,`${JSON.stringify(i,null,2)}
|
|
42
|
+
`,{mode:384}),await fe.rename(s,r),await fe.chmod(r,384).catch(()=>{})}function Fr(e,t,n){let r={...e,command:"connect"};for(let o of["cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","lanListener","once"])t[o]!==void 0&&(r[o]=t[o]);return t.codingCmd!==void 0&&t.noCoding===void 0&&(r.noCoding=!1),r.cwd||(r.cwd=n),r.cursorBuddyRuntime=!0,r}function Gr(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function Hr(e){return e.json().catch(()=>({}))}async function qt(e,t={}){let n=Ge(e?.key),r=Rr(e),o=t.fetchImpl||globalThis.fetch;if(typeof o!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let s=t.cwd||Fe.cwd(),i=t.hostname||Kt.hostname(),a=t.version||oe,u={homedir:t.homedir},d=await o(`${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||s,name:e.name,surface:e.surface||"local_cli",scope:e.scope||"machine",runtimeKind:"agensis-cli",version:a,permissionMode:e.permissionMode,model:e.model})}),f=await Hr(d);if(!d.ok){let S=Gr(d,f);if(d.status===409||/already been claimed/i.test(S)){let g=await Ur(n,u);if(g)return Fr(g,e,s);throw new Error(`${S}. 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(S)}let h=Lr(e,f?.data||f,r,s);return await jr(n,h,u),h}import Jr from"node:crypto";import Wr from"node:http";import Kr from"node:os";import q from"node:process";import{spawn as zr}from"node:child_process";var qr="https://agensis.io",Yr=10*60*1e3;function _e(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 Xr(e){return new Promise((t,n)=>{let r="";e.on("data",o=>{r+=o,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 Vr(e){let t=String(e||q.env.AGENSIS_URL||qr).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 Qr(e){let t=q.platform==="darwin"?"open":q.platform==="win32"?"cmd":"xdg-open",n=q.platform==="win32"?["/c","start","",e]:[e],r=zr(t,n,{detached:!0,stdio:"ignore"});r.on("error",()=>{}),r.unref()}function Zr(e){let t=e?.daemonArgs||e?.data?.daemonArgs||e?.data||{},r=["url","token","workspace","agent"].filter(o=>!String(t[o]||"").trim());if(r.length)throw new Error(`Setup callback did not include ${r.join(", ")}`);return{...t,command:"connect"}}function eo(e,t,n){let r=new URL(Vr(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",z(e.profile||"default")),r.searchParams.set("host",Kr.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 Yt(e={}){let t=z(e.profile||"default"),n=Jr.randomBytes(24).toString("base64url"),r=Number(e.setupTimeoutMs||q.env.AGENSIS_SETUP_TIMEOUT_MS||Yr),o,s=new Promise((d,f)=>{let h=setTimeout(()=>f(new Error("Agensis setup timed out waiting for browser login.")),r);h.unref&&h.unref(),o=Wr.createServer(async(S,g)=>{if(g.setHeader("access-control-allow-origin","*"),g.setHeader("access-control-allow-methods","POST, OPTIONS"),g.setHeader("access-control-allow-headers","content-type"),S.method==="OPTIONS"){g.writeHead(204),g.end();return}if(S.method!=="POST"||S.url!=="/agensis/setup-callback"){_e(g,404,{ok:!1,error:"Unknown Agensis setup callback route"});return}try{let x=JSON.parse(await Xr(S)||"{}");if(x?.state!==n){_e(g,403,{ok:!1,error:"Setup state did not match"});return}let $={...Zr(x),primaryDaemon:!0,cursorBuddyBridge:e.cursorBuddyBridge!==!1};await be(t,$),clearTimeout(h),_e(g,200,{ok:!0,profile:t}),d($)}catch(x){_e(g,400,{ok:!1,error:String(x?.message||x)})}}),o.once("error",f)});await new Promise((d,f)=>{o.listen(0,"127.0.0.1",h=>h?f(h):d())});let{port:i}=o.address(),a=`http://127.0.0.1:${i}/agensis/setup-callback`,u=eo(e,a,n);q.stdout.write(`[agensis] Opening Agensis to sign in and connect this machine.
|
|
39
43
|
`),q.stdout.write(`[agensis] If the browser did not open, visit:
|
|
40
44
|
${u}
|
|
41
|
-
`),
|
|
42
|
-
`),
|
|
45
|
+
`),Qr(u);try{let d=await s;return q.stdout.write(`[agensis] Saved daemon profile "${t}". Starting primary agent daemon.
|
|
46
|
+
`),d}finally{await new Promise(d=>o.close(()=>d())).catch(()=>{})}}function to(e){let t={command:"connect"},n=[...e],r=n[0];if(r&&!r.startsWith("-")&&(t.command=n.shift(),t.command==="buddy")){let o=n[0];o&&!o.startsWith("-")?t.subcommand=n.shift():t.subcommand="connect"}for(let o=0;o<n.length;o+=1){let s=n[o];if(!s.startsWith("--"))throw new Error(`Unexpected argument: ${s}`);let[i,a]=s.slice(2).split(/=(.*)/s,2),u=i.replace(/-([a-z])/g,(f,h)=>h.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==="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}let d=a!==void 0?a:n[++o];if(d==null||d.startsWith("--"))throw new Error(`Missing value for --${i}`);t[u]=d}return t}function no(){return`agensis agent daemon
|
|
43
47
|
|
|
44
48
|
Usage:
|
|
45
49
|
agensis --url <workspace-url> --token <token> --workspace <id> --agent <id> [options]
|
|
@@ -79,7 +83,7 @@ Options:
|
|
|
79
83
|
--profile <name> Save/reuse a local daemon profile, default: default
|
|
80
84
|
--version Print the CLI version
|
|
81
85
|
--help Show this help
|
|
82
|
-
`}async function
|
|
83
|
-
`)}}:e}async function
|
|
84
|
-
`);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
|
|
86
|
+
`}async function ro(e){let t=e.profile!==void 0,n=e.handle||e.name,r=z(e.profile||(Ue(e)&&n?n:"default"));if(!Gt(e)){let o=await Ht(r);if(!o)throw new Error(Wt(r));return Jt(o,e)}return Ue(e)?{...e,cursorBuddyBridge:e.cursorBuddyBridge===!0,onRegistered:async o=>{await be(r,o);let s=t||r!=="default"?`agensis connect --profile ${r}`:"agensis connect";Y.stdout.write(`[agensis] Saved daemon profile "${r}". Restart with: ${s}
|
|
87
|
+
`)}}:e}async function oo(){let e=to(Y.argv.slice(2));if(e.help){Y.stdout.write(no());return}if(e.version){Y.stdout.write(`${oe}
|
|
88
|
+
`);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 qt(e);n.cursorBuddyBridge=e.cursorBuddyBridge!==!1,n.cursorBuddyRuntime=!0,n.exitOnOnce=!0,await Se(n),n.once&&Y.exit(0);return}if(e.command==="setup"){let n=await Yt(e);n.exitOnOnce=!0,await Se({...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 ro(e);t.exitOnOnce=!0,await Se(t),t.once&&Y.exit(0)}oo().catch(e=>{Y.stderr.write(`${e?.message||e}
|
|
85
89
|
`),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.24",
|
|
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": {
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"ws": "^8.20.0"
|
|
39
39
|
},
|
|
40
|
+
"optionalDependencies": {
|
|
41
|
+
"e2b": "^2.35.0"
|
|
42
|
+
},
|
|
40
43
|
"devDependencies": {
|
|
41
44
|
"esbuild": "^0.21.5"
|
|
42
45
|
},
|