@agensis/agensis-agent 0.1.25 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/bin/agensis.mjs +36 -29
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -60,6 +60,9 @@ Optional:
|
|
|
60
60
|
- `--name <name>` — display name
|
|
61
61
|
- `--cwd <path>` — folder where the coding CLI runs
|
|
62
62
|
- `--coding-cmd <command>` — command used for jobs (default `claude -p`)
|
|
63
|
+
- `--full-cli-context` — opt out of the default isolated Claude/Codex launch
|
|
64
|
+
- `--sync-memory` — opt in to mirroring Claude memory files to Agensis
|
|
65
|
+
- `--max-concurrency <n>` — simultaneous coding CLI jobs (default `2`)
|
|
63
66
|
- `--model <id>` — default model passed to supported coding CLIs
|
|
64
67
|
- `--permission-mode <mode>` — `default`, `accept_edits`, or `yolo`
|
|
65
68
|
- `--yolo` / `--no-sandbox` — alias for `--permission-mode yolo`
|
|
@@ -73,18 +76,30 @@ Environment fallbacks: `AGENSIS_URL`, `AGENSIS_TOKEN`,
|
|
|
73
76
|
`AGENSIS_WORKSPACE` / `AGENSIS_WORKSPACE_ID`, `AGENSIS_AGENT` / `AGENSIS_AGENT_ID`,
|
|
74
77
|
`AGENSIS_HANDLE`, `AGENSIS_NAME`, `AGENSIS_CWD`, `AGENSIS_CODING_CMD` / `CODING_CMD`,
|
|
75
78
|
`AGENSIS_MODEL` / `CLAUDE_MODEL`, `AGENSIS_PERMISSION_MODE`, `AGENSIS_TIMEOUT_MS`,
|
|
76
|
-
`AGENSIS_HEARTBEAT_MS`, `AGENSIS_ONCE=1`.
|
|
79
|
+
`AGENSIS_HEARTBEAT_MS`, `AGENSIS_SYNC_MEMORY=1`, `AGENSIS_ONCE=1`.
|
|
77
80
|
|
|
78
81
|
## Security
|
|
79
82
|
|
|
80
83
|
The daemon runs on your machine and executes the configured coding command in
|
|
81
|
-
the working directory you start it in.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
the working directory you start it in. Agensis sends the job payload and
|
|
85
|
+
receives streamed CLI output and the final result. Local credentials are not
|
|
86
|
+
intentionally uploaded, but the coding CLI can read files allowed by its own
|
|
87
|
+
permission mode, so treat it like any local coding agent with access to that
|
|
88
|
+
folder.
|
|
89
|
+
|
|
90
|
+
Claude memory synchronization is off by default. `--sync-memory` opts in to
|
|
91
|
+
uploading the selected project's memory file names, contents, sizes, and
|
|
92
|
+
absolute memory-root path to the connected Agensis workspace. Reads are
|
|
93
|
+
restricted to that root and each file is capped at 256 KiB.
|
|
84
94
|
|
|
85
95
|
Keep `aga_...` tokens out of shared logs and shell history. Generate a fresh
|
|
86
96
|
token from agensis if one is exposed.
|
|
87
97
|
|
|
98
|
+
By default, Claude runs in safe mode and Codex skips user configuration,
|
|
99
|
+
project instructions, memories, plugins, hooks, and skill search. Both are
|
|
100
|
+
given only the Agensis MCP configuration, and the complete daemon prompt is
|
|
101
|
+
bounded. `--full-cli-context` deliberately restores normal CLI discovery.
|
|
102
|
+
|
|
88
103
|
## Requirements
|
|
89
104
|
|
|
90
105
|
- Node.js >= 18
|
package/bin/agensis.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var en=Object.defineProperty;var tn=(e,t)=>()=>(e&&(t=e(e=0)),t);var nn=(e,t)=>{for(var n in t)en(e,n,{get:t[n],enumerable:!0})};var We={};nn(We,{createE2bProvider:()=>an});function Ee(e){return`'${String(e).replace(/'/g,"'\\''")}'`}function an({apiKey:e,anthropicApiKey:t,gitToken:n="",repoUrl:r="",template:s=""}={}){if(!e)throw new Error("E2B_API_KEY is not set on the daemon host.");if(!r)throw new Error("Sandbox needs a repo URL (set sandbox_config.repoUrl or the agent's repo).");return{async ensureEnv(){let o={apiKey:e,envs:t?{ANTHROPIC_API_KEY:t}:{}},i;try{({Sandbox:i}=await import("e2b"))}catch(l){if(l&&(l.code==="ERR_MODULE_NOT_FOUND"||l.code==="MODULE_NOT_FOUND"||/Cannot find package 'e2b'/.test(String(l&&l.message)))){let c=Number(String(process.versions.node).split(".")[0])||0,m=c<20||c===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.${m}`)}throw l}let a=s?await i.create(s,o):await i.create(o);return await a.commands.run("bash -lc 'command -v claude >/dev/null || npm i -g @anthropic-ai/claude-code'"),{sbx:a,dir:sn}},async putRepo(o){let i=n?r.replace(/^https:\/\//,`https://x-access-token:${n}@`):r;try{let a=await o.sbx.commands.run(`git clone ${Ee(i)} ${Ee(o.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 l=a&&(a.stderr||a.exitCode!=null)?a.stderr||`exit ${a.exitCode}`:String(a?.message||a);throw new Error(`git clone failed: ${l}`)}},async exec(o,{cmd:i,args:a=[],env:l={},onData:c}){let m=`${i} ${a.map(Ee).join(" ")}`,g={cwd:o.dir,envs:{...l,IS_SANDBOX:"1",AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS:"1"},onStdout:y=>{try{c?.(y)}catch{}}};try{let y=await o.sbx.commands.run(m,g);return{status:y.exitCode,stdout:y.stdout||"",stderr:y.stderr||"",error:null}}catch(y){return y&&typeof y.exitCode=="number"?{status:y.exitCode,stdout:y.stdout||"",stderr:y.stderr||"",error:null}:{status:null,stdout:"",stderr:String(y?.message||y),error:y}}},async getResult(o){try{return{patch:(await o.sbx.commands.run("git add -A && git diff --cached",{cwd:o.dir})).stdout||""}}catch(i){return{patch:i&&i.stdout||""}}},async destroy(o){await o.sbx.kill()}}}var sn,ze=tn(()=>{sn="/home/user/repo"});import q from"node:process";import ue from"node:fs";import le from"node:path";import de from"node:os";import Zn from"node:crypto";import _ from"node:process";import ce from"ws";import{spawn as rn}from"node:child_process";function Ke(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 on=50*1024*1024;function se(e){let{cmd:t,args:n=[],env:r={},cwd:s,timeoutMs:o=0,label:i="working",heartbeatMs:a=15e3,input:l="",now:c=Date.now,log:m=console,signal:g,onData:y}=e||{};return new Promise(w=>{if(g?.aborted){w({status:null,stdout:"",stderr:"",aborted:!0,error:new Error("cancelled")});return}let S;try{let h=n.some(A=>A==="--dangerously-skip-permissions"),E=typeof process.getuid=="function"&&process.getuid()===0,T={...process.env,...r};delete T.AGENSIS_TOKEN,delete T.ANTHROPIC_API_KEY,delete T.ANTHROPIC_AUTH_TOKEN,h&&E&&(T.IS_SANDBOX="1"),S=rn(t,n,{cwd:s,detached:!0,env:T})}catch(h){w({status:null,stdout:"",stderr:"",error:h});return}l?S.stdin?.end(String(l)):S.stdin?.end();let $="",k="";S.stdout?.setEncoding("utf8"),S.stderr?.setEncoding("utf8");let b=(h,E)=>h.length>=on?h:h+E;S.stdout?.on("data",h=>{if($=b($,h),y)try{y(h)}catch{}}),S.stderr?.on("data",h=>k=b(k,h));let O=c(),N=a>0?setInterval(()=>{m.log(` \u2026 still ${i} (${Ke(c()-O)}) \u2014 Ctrl+C to cancel`)},a):null;N?.unref&&N.unref();let M=h=>{if(S.pid!=null)try{process.kill(-S.pid,h)}catch{try{S.kill(h)}catch{}}},J=!1,L=o>0?setTimeout(()=>{J=!0,M("SIGKILL")},o):null;L?.unref&&L.unref();let d=!1,p=null,v=()=>{d=!0,M("SIGTERM"),p=setTimeout(()=>M("SIGKILL"),3e3),p?.unref&&p.unref()};g&&g.addEventListener("abort",v,{once:!0});let u=(h,E)=>{N&&clearInterval(N),L&&clearTimeout(L),p&&clearTimeout(p),g&&g.removeEventListener("abort",v),w({status:h,stdout:$,stderr:k,aborted:d,error:E||(d?new Error("cancelled"):J?new Error(`timed out after ${Ke(o)}`):null)})};S.on("error",h=>u(null,h)),S.on("close",h=>u(h,null))})}function cn({run:e=se}={}){return{run:t=>e(t)}}function un(e){return{async run({cmd:t,args:n=[],env:r={},onData:s,signal:o,job:i}){let a=null;try{a=await e.ensureEnv({job:i,signal:o}),await e.putRepo(a,{job:i,signal:o});let l=await e.exec(a,{cmd:t,args:n,env:r,onData:s,signal:o}),c=await e.getResult(a,{job:i}).catch(()=>({})),m=c&&c.patch?String(c.patch).trim():"",g=m?`${l.stdout||""}
|
|
3
3
|
|
|
4
4
|
\`\`\`diff
|
|
5
|
-
${
|
|
6
|
-
\`\`\``:
|
|
5
|
+
${m}
|
|
6
|
+
\`\`\``:l.stdout||"";return{status:l.status,stdout:g,stderr:l.stderr||"",error:l.error||null}}catch(l){return{status:null,stdout:"",stderr:"",error:l}}finally{if(a)try{await e.destroy(a)}catch{}}}}}function Ye(e,{makeProvider:t}={}){return(e&&e.agent&&e.agent.run_mode)==="sandbox"?un((t||ln)(e)):cn()}function ln(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 mn({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 dn(e=process.versions.node){let[t,n,r]=String(e).split(".").map(s=>Number(s)||0);return t===21?!1:t>=22?!0:t!==20?!1:n>18?!0:n<18?!1:r>=1}function mn(e){let t=null,n=async()=>{if(!t){if(!dn())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(()=>(ze(),We))).createE2bProvider(e)}return t};return{ensureEnv:async r=>(await n()).ensureEnv(r),putRepo:async(r,s)=>(await n()).putRepo(r,s),exec:async(r,s)=>(await n()).exec(r,s),getResult:async(r,s)=>(await n()).getResult(r,s),destroy:async r=>(await n()).destroy(r)}}function qe(e={}){let{runJob:t}=e,n=Math.max(1,Number(e.concurrency)||1),r=new Map,s=0,o=[];function i(k){let b=r.get(k);return b||(b={queued:[],active:null},r.set(k,b)),b}function a(k){if(k==null)return!1;for(let b of r.values())if(b.active&&!b.active.cancelled&&b.active.job.key===k||b.queued.some(O=>O.key===k))return!0;return!1}function l(){for(let[k,b]of r){if(s>=n)break;if(b.active||b.queued.length===0)continue;let O=b.queued.shift(),N=new AbortController;b.active={job:O,controller:N,cancelled:!1},s+=1,Promise.resolve().then(()=>N.signal.aborted?void 0:t(O,{signal:N.signal})).catch(()=>{}).finally(()=>{b.active=null,s-=1,b.queued.length===0&&!b.active&&r.delete(k),l(),c()})}}function c(){if(s>0)return;for(let b of r.values())if(b.queued.length)return;let k=o;o=[];for(let b of k)b()}function m(k){if(k&&k.key!=null&&a(k.key))return{accepted:!1,deduped:!0,position:0,startedImmediately:!1};let b=k&&k.lane!=null?String(k.lane):"",O=i(b),N=!O.active&&O.queued.length===0&&s<n;O.queued.push(k);let M=O.queued.length+(O.active?1:0);return l(),{accepted:!0,deduped:!1,position:M,startedImmediately:N}}function g(k,b){let O=!1;for(let[N,M]of r)b!=null&&N!==String(b)||M.active&&(M.active.cancelled=!0,M.active.controller.abort(k||"cancelled"),O=!0);return O}function y(k,b){if(k==null)return!1;let O=!1;for(let[N,M]of[...r]){M.active?.job?.key===k&&(M.active.cancelled=!0,M.active.controller.abort(b||"cancelled"),O=!0);let J=M.queued.length;M.queued=M.queued.filter(L=>L.key!==k),M.queued.length!==J&&(O=!0),!M.active&&M.queued.length===0&&r.delete(N)}return c(),O}function w(){let k=0;for(let b of r.values())k+=b.queued.length;return k}function S(){return s}function $(){return s===0&&w()===0?Promise.resolve():new Promise(k=>o.push(k))}return{enqueue:m,cancel:y,cancelActive:g,has:a,size:w,active:S,idle:$}}import tt from"node:crypto";import fn from"node:http";import nt from"node:os";import X from"node:process";var Xe=8787,Ae="claude-haiku-4-5",pn=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/,hn=100,gn=new Set(["say","wave","hush","open","choose"]),ge="x-agensis-bridge-secret";function yn(){return`cbs_${tt.randomBytes(24).toString("base64url")}`}function Sn(e){let t=e?.headers||{},n=String(t[ge]||t[ge.toLowerCase()]||"").trim();if(n)return n;let s=String(t.authorization||t.Authorization||"").trim().match(/^Bearer\s+(.+)$/i);return s?s[1].trim():""}function wn(e,t){let n=String(t||""),r=Sn(e);if(!n||!r)return!1;let s=Buffer.from(r),o=Buffer.from(n);return s.length!==o.length?!1:tt.timingSafeEqual(s,o)}function bn(e={},t={}){let n=String(t.authSecret||"").trim();if(n)return n;let r=String(e.cursorBuddyBridgeSecret||"").trim();if(r)return r;let s=String(X.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim();return s||yn()}function _n(e,t){return e==="OPTIONS"||e==="GET"&&t==="/cursorbuddy/health"}function F(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 Ve(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 G(e,t){e.write(`data: ${typeof t=="string"?t:JSON.stringify(t)}
|
|
7
7
|
|
|
8
|
-
`)}function ie(e){return new Promise((t,n)=>{let r="";e.on("data",
|
|
9
|
-
${
|
|
8
|
+
`)}function ie(e){return new Promise((t,n)=>{let r="";e.on("data",s=>{r+=s,r.length>256*1024&&(n(new Error("request body is too large")),e.destroy())}),e.on("error",n),e.on("end",()=>t(r))})}function kn(e){let t=[],n="",r="",s=!1;for(let o of String(e||"")){if(s){n+=o,s=!1;continue}if(o==="\\"){s=!0;continue}if(r){o===r?r="":n+=o;continue}if(o==='"'||o==="'"){r=o;continue}if(/\s/.test(o)){n&&(t.push(n),n="");continue}n+=o}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function vn(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function pe(e,t){return e.some(n=>n===t||String(n).startsWith(`${t}=`))}function Qe(e,t){let n=[];t&&n.push("CursorBuddy local runtime context:",JSON.stringify(t,null,2),"");for(let r of Array.isArray(e)?e:[]){let s=String(r?.role||"user"),o=String(r?.content||"");o.trim()&&n.push(`${s.toUpperCase()}:
|
|
9
|
+
${o}`)}return n.join(`
|
|
10
10
|
|
|
11
|
-
`).trim()||"Say that the local Agensis runtime is connected."}function
|
|
12
|
-
`))>=0;)d(t.slice(0,m)),t=t.slice(m+1)},end(){t&&(d(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 An(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function Cn(e){return String(e||"").slice(0,18)}function R(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function xn(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 Mn(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function On(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!ln.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=An(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(Mn(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=yn(e,t),o=new Date().toISOString(),s=[],i=[],a=new Set,d=t.fetchImpl||globalThis.fetch,u=1,m=null,g=n,_=null,h=(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}},b=()=>{let l=$();return l?.connected===!1?l:_?{...x(),...l||{},..._,connected:!0,updatedAt:l?.updatedAt||_.updatedAt}:l||x()};function S(l={}){if(!l||typeof l!="object"||Array.isArray(l))return null;let p=String(l.action||l.type||"").trim().toLowerCase();if(!fn.has(p))return null;let k={id:u++,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>mn;)i.shift();h("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=vn(l);if(p){let k=S(p.command);return k&&(M(k),h("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,m),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 j(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]"),h("chat_fast",{chars:c.content.length,model:C}),{content:c.content,model:C,fast:!0}}let y=Xe(l?.messages,m),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?In(I):null,f=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(f.error||f.status!==0){let C=f.error?.message||String(f.stderr||"").trim()||`Command exited with status ${f.status}`;throw new Error(C)}let E=A?P:Ve(P||f.stdout||f.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=dn.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(g||qe));if(!Sn(l.method,k.pathname)&&!gn(l,r)){F(p,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/health"){let c=he(g);F(p,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:Ie(e),daemonModel:e.model,port:g,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:b(),context:m,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"){F(p,200,{ok:!0,events:s.slice(-100)});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/context"){F(p,200,{ok:!0,context:m});return}if(l.method==="GET"&&k.pathname==="/cursorbuddy/control"){let c=Number(k.searchParams.get("after")||0),y=i.filter(v=>v.id>c);F(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=S(c);if(!y){F(p,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let v=M(y);F(p,200,{ok:!0,command:v})}catch(c){h("control_error",{error:String(c?.message||c)}),F(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)||"{}");m={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()},h("context",{url:m.url,surface:m.surface,instanceId:m.instanceId}),F(p,200,{ok:!0,context:m})}catch(c){h("context_error",{error:String(c?.message||c)}),F(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 On(e,c,d),v=y.data||{};_={connected:!0,mode:"agensis-claimed",keyId:Cn(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()},m=xn(c,_,e),h("connect",{mode:_.mode,keyId:_.keyId,agentId:_.agentId,workspaceId:_.workspaceId,url:m.url}),F(p,200,{ok:!0,connection:_,claim:v})}catch(c){h("connect_error",{error:String(c?.message||c)}),F(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)}];h("edit_request",{selector:c?.target?.selector||""});let v=await O({messages:y,model:c?.model});h("edit_done",{chars:v.content.length}),F(p,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:v.content})}catch(c){h("edit_error",{error:String(c?.message||c)}),F(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(h("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 j(c,p);h("chat_done",{chars:v.content.length,stream:!0,fast:v.fast===!0}),p.end();return}let y=await O(c);h("chat_done",{chars:y.content.length,fast:y.fast===!0}),F(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){h("chat_error",{error:String(c?.message||c)}),F(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",()=>{g=U.address().port,U.off("error",p),l()})}),h("listening",{url:`${he(g)}/cursorbuddy/health`}),{port:g,url:he(g),secret:r,authHeader:ge,close(){return new Promise(l=>U.close(()=>l()))},getContext(){return m}}}import te from"node:fs/promises";import Nn from"node:os";import J from"node:path";var ot=200,st=256*1024,Bn=2,$n=new Set([".md",".markdown",".txt"]);function Tn(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function Ae({cwd:e,memoryDir:t,homedir:n=Nn.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",Tn(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 Dn(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 Rn(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>Bn||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()&&$n.has(J.extname(s.name).toLowerCase())){let a=J.relative(e,i);r.push({path:a,kind:Rn(a)})}}}async function Pn(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 Ln(e,t){let n=await Ce(e),r=await Dn(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 Pn(e),n=[];for(let r of t)try{let{content:o,byteSize:s}=await Ln(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 Un(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 d=a?`${a}:${i}`:i;r.has(d)||(r.add(d),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 d=ne.join(i,a.name);if(a.isDirectory()||a.isSymbolicLink()&&Un(d))for(let u of Me(d))u.name.startsWith(".")||u.name.endsWith(".md")&&s(u.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 Fn}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 Gn(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 Fn(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(Gn).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(S=>S.id===t?.model);if(!a)throw new Error(`Shared model '${t?.model||""}' is not available.`);let d={"content-type":"application/json"},u=a.apiKeyEnv?s[a.apiKeyEnv]:"";u&&(d.authorization=`Bearer ${u}`),n({action:"agent_inference_started",requestId:i,model:a.id});let{requestId:m,model:g,type:_,action:h,...x}=t,$=await o(`${a.baseUrl}/chat/completions`,{method:"POST",headers:d,body:JSON.stringify({...x,model:a.upstreamModel,stream:t.stream===!0}),signal:r});if(!$.ok){let S=await $.text().catch(()=>"");throw new Error(S||`Local model returned HTTP ${$.status}.`)}if(t.stream===!0){if(!$.body)throw new Error("Local model returned an empty stream.");let S=$.body.getReader(),M=new TextDecoder,N="",O,j=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 S.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(j(y)){U=!0;break}if(p)break}N&&j(N);let l={action:"agent_inference_result",requestId:i,model:a.id,...O?{usage:O}:{}};return n(l),l}let b=await $.json();return n({action:"agent_inference_result",requestId:i,model:a.id,response:b}),b}import gt from"node:fs";import K from"node:fs/promises";import Hn from"node:os";import W from"node:path";var wt="status.json",bt="heartbeat.json",Oe="heartbeat.md",Jn="agent.json",Wn="soul.md",Kn=16*1024,zn=`# Heartbeat
|
|
11
|
+
`).trim()||"Say that the local Agensis runtime is connected."}function Ze(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 En(e){let t=Array.isArray(e?.messages)?e.messages:[];for(let n=t.length-1;n>=0;n-=1){let r=t[n];if(String(r?.role||"user")!=="user")continue;let s=String(r?.content||"").trim();if(s)return s}return""}function An(e,t=280){let n=En(e).replace(/\s+/g," ").trim();if(!n)return"";if(n.length<=t)return n;let r=[/\b(tell me (?:a )?joke)\b/i,/\b(make (?:him|the buddy|cursorbuddy|avatar) wave|wave(?: hello)?|say hi|say hello)\b/i,/\b(what site|which site|what page|where am i|where are you|current url)\b/i,/\b(are you connected|connected|working|online|there)\b/i,/\b(show|guide|tour|walk|around|sections?|features?|important|highlight|what can i do|what should i do|help me)\b/i,/\b(open|show|bring up|get back|display)\b.{0,80}\b(prompt|bubble|dialog|panel|options|menu)\b/i,/\b(hide|hush|close|dismiss|clear|stop|cancel|be quiet)\b.{0,80}\b(bubble|prompt|dialog|panel|options|menu)?\b/i,/^(hi|hello|hey|yo|sup)\b/i];for(let s of r){let o=n.match(s);if(o?.[0])return o[0].trim()}return n.slice(-t).trim()}function In(e){let t=An(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 Cn(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 rt(e,t){let n=String(e||"").trim();return!n||Cn(n)?t:n}function ot(e){let t=String(e||"").trim();return!t||t==="haiku-4.5"||t==="claude-haiku-4.5"?Ae:t}function Ie(e={}){return ot(e.cursorBuddyModel||X.env.AGENSIS_CURSORBUDDY_MODEL||Ae)}function et(e,t,n,r={}){let{cmd:s,args:o}=kn(e.codingCmd||"claude -p"),i=[...o],a=ot(rt(n,Ie(e))),l="",c=!1;return vn(s)?(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"),c=!0):(pe(i,"--output-format")||i.push("--output-format","json"),c=i.some(g=>String(g).includes("stream-json"))),l=t):i.push(t),{cmd:s,args:i,model:a,stdin:l,streamJson:c}}function xn(e=()=>{}){let t="",n="",r=!1,s="",o=null,i=c=>{c&&e(c)},a=c=>{if(!c||typeof c!="object")return;let m=c.event&&c.event.delta||c.delta;if(m&&m.type==="text_delta"&&typeof m.text=="string"){r=!0,n+=m.text,i(m.text);return}if(c.type==="result"&&typeof c.result=="string"){o=c.result;return}if(c.type==="assistant"&&c.message&&Array.isArray(c.message.content)){let g=c.message.content.filter(y=>y&&y.type==="text"&&typeof y.text=="string").map(y=>y.text).join("");g&&(s+=g)}},l=c=>{let m=String(c).trim();if(m)try{a(JSON.parse(m))}catch{}};return{feed(c){t+=String(c||"");let m;for(;(m=t.indexOf(`
|
|
12
|
+
`))>=0;)l(t.slice(0,m)),t=t.slice(m+1)},end(){t&&(l(t),t="")},get live(){return r?n:s},get result(){return o??(r?n:s)}}}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 Mn(e={},t={}){return String(t.agensisUrl||t.baseUrl||e.url||X.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function Nn(e){return String(e||"").slice(0,18)}function P(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function On(e={},t={},n={}){let r=P(e.metadata)||{},s=P(e.page)||P(r.page)||{},o=P(e.client)||P(r.client)||{},i=P(r.runtime)||{},a=P(e.manifest)||P(r.manifest)||null;return{url:String(e.url||s.url||r.websiteSource||e.websiteSource||"").slice(0,2048),title:String(e.title||s.title||"").slice(0,300),surface:String(e.surface||i.surface||t.surface||"").slice(0,80),instanceId:String(e.instanceId||i.instanceId||"").slice(0,140),workspaceId:String(t.workspaceId||e.workspaceId||n.workspace||"").slice(0,120),agentId:String(t.agentId||e.agentId||n.agent||"").slice(0,120),runtime:{...i,local:!0,connected:!0,connection:t},page:s,client:o,project:P(e.project)||P(r.project)||null,manifest:a,selection:P(e.selection)||null,updatedAt:new Date().toISOString()}}function Bn(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function $n(e,t={},n=globalThis.fetch){let r=String(t.key||"").trim();if(!pn.test(r))throw new Error("Connection key format is invalid. Create a fresh CursorBuddy key first.");if(typeof n!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let s=Mn(e,t),o=await n(`${s}/backend/cursorbuddy/connection-keys/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:r,baseUrl:s,host:nt.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:P(t.metadata)||null,websiteSource:t.websiteSource||t.metadata?.websiteSource||"",page:P(t.page)||P(t.metadata?.page)||null,client:P(t.client)||P(t.metadata?.client)||null,manifest:P(t.manifest)||P(t.metadata?.manifest)||null})}),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(Bn(o,i));return{key:r,baseUrl:s,data:i?.data||i}}async function st(e,t={}){let n=Number(t.port??e.cursorBuddyPort??X.env.AGENSIS_CURSORBUDDY_PORT??Xe),r=bn(e,t),s=new Date().toISOString(),o=[],i=[],a=new Set,l=t.fetchImpl||globalThis.fetch,c=1,m=null,g=n,y=null,w=(d,p={})=>{let v={ts:new Date().toISOString(),event:d,detail:p};return o.push(v),o.length>200&&o.shift(),t.log?.(`CursorBuddy local bridge: ${d}${Object.keys(p).length?` ${JSON.stringify(p)}`:""}`),v},S=()=>({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 d=t.connectionProvider();return!d||typeof d!="object"||Array.isArray(d)?null:{...S(),...d,connected:d.connected===!0}}catch{return null}},k=()=>{let d=$();return d?.connected===!1?d:y?{...S(),...d||{},...y,connected:!0,updatedAt:d?.updatedAt||y.updatedAt}:d||S()};function b(d={}){if(!d||typeof d!="object"||Array.isArray(d))return null;let p=String(d.action||d.type||"").trim().toLowerCase();if(!gn.has(p))return null;let v={id:c++,ts:new Date().toISOString(),action:p,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(u=>({label:String(u?.label||"").slice(0,80),value:String(u?.value||u?.task||"").slice(0,1200)})).filter(u=>u.label).slice(0,6)),v}function O(d){for(i.push(d);i.length>hn;)i.shift();w("control",{id:d.id,action:d.action,chars:d.text.length});for(let p of[...a])try{G(p,{type:"command",command:d})}catch{a.delete(p)}return d}function N(d){let p=In(d);if(p){let v=b(p.command);return v&&(O(v),w("chat_control",{id:v.id,action:v.action})),{content:p.content,model:"cursorbuddy-local-control",fast:!0}}return null}async function M(d){let p=N(d);if(p)return p;let v=Qe(d?.messages,m),u=et(e,v,d?.model),h=await se({cmd:u.cmd,args:u.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:u.stdin});if(h.error||h.status!==0)throw new Error(h.error?.message||String(h.stderr||"").trim()||`Command exited with status ${h.status}`);return{content:Ze(h.stdout||h.stderr),model:u.model}}async function J(d,p){let v=`agensis-cursorbuddy-${Date.now()}`,u=N(d);if(u){let x=u.model||"cursorbuddy-local-control";return G(p,ee(v,x,u.content)),G(p,ee(v,x,"","stop")),G(p,"[DONE]"),w("chat_fast",{chars:u.content.length,model:x}),{content:u.content,model:x,fast:!0}}let h=Qe(d?.messages,m),E=et(e,h,d?.model,{stream:!0}),T="",A=x=>{x&&(T+=x,G(p,ee(v,E.model||e.model,x)))},C=E.streamJson?xn(A):null,f=await se({cmd:E.cmd,args:E.args,cwd:e.cwd,timeoutMs:Math.min(Number(e.timeoutMs||18e5),5*60*1e3),heartbeatMs:e.heartbeatMs,label:"cursorbuddy local chat",input:E.stdin,onData:x=>{if(C)C.feed(x);else{let U=String(x||"");T+=U,G(p,ee(v,E.model||e.model,U))}}});if(C){C.end();let x=C.result||"";!T&&x?A(x):T=x||T}if(f.error||f.status!==0){let x=f.error?.message||String(f.stderr||"").trim()||`Command exited with status ${f.status}`;throw new Error(x)}let I=C?T:Ze(T||f.stdout||f.stderr);return!C&&I&&I!==T&&(G(p,ee(v,E.model||e.model,I)),T=I),G(p,ee(v,E.model||e.model,"","stop")),G(p,"[DONE]"),{content:T||I,model:E.model}}let L=fn.createServer(async(d,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"),d.method==="OPTIONS"){p.writeHead(204),p.end();return}let v=new URL(d.url||"/",he(g||Xe));if(!_n(d.method,v.pathname)&&!wn(d,r)){F(p,401,{ok:!1,error:"Authentication required",code:"bridge_auth_required"});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/health"){let u=he(g);F(p,200,{ok:!0,runtime:"agensis-cli",backend:e.codingCmd,model:Ie(e),daemonModel:e.model,port:g,host:nt.hostname(),pid:X.pid,bootedAt:s,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:k(),context:m,endpoints:{chat:`${u}/v1/chat/completions`,chatStream:`${u}/v1/chat/completions`,edit:`${u}/cursorbuddy/edit`,context:`${u}/cursorbuddy/context`,control:`${u}/cursorbuddy/control`,controlStream:`${u}/cursorbuddy/control/stream`,logs:`${u}/cursorbuddy/logs`}});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/logs"){F(p,200,{ok:!0,events:o.slice(-100)});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/context"){F(p,200,{ok:!0,context:m});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/control"){let u=Number(v.searchParams.get("after")||0),h=i.filter(E=>E.id>u);F(p,200,{ok:!0,commands:h,latestId:i.at(-1)?.id||0});return}if(d.method==="GET"&&v.pathname==="/cursorbuddy/control/stream"){let u=Number(v.searchParams.get("after")||0);Ve(p),a.add(p),G(p,{type:"ready",latestId:i.at(-1)?.id||0});for(let E of i.filter(T=>T.id>u))G(p,{type:"command",command:E});let h=setInterval(()=>{try{G(p,{type:"ping",ts:new Date().toISOString()})}catch{a.delete(p),clearInterval(h)}},15e3);h.unref&&h.unref(),d.on("close",()=>{a.delete(p),clearInterval(h)});return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/control"){try{let u=JSON.parse(await ie(d)||"{}"),h=b(u);if(!h){F(p,400,{ok:!1,error:"unsupported CursorBuddy control command"});return}let E=O(h);F(p,200,{ok:!0,command:E})}catch(u){w("control_error",{error:String(u?.message||u)}),F(p,400,{ok:!1,error:String(u?.message||u)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/context"){try{let u=JSON.parse(await ie(d)||"{}");m={url:String(u.url||"").slice(0,2048),title:String(u.title||"").slice(0,300),surface:String(u.surface||"").slice(0,80),instanceId:String(u.instanceId||"").slice(0,140),workspaceId:String(u.workspaceId||e.workspace||"").slice(0,120),agentId:String(u.agentId||e.agent||"").slice(0,120),runtime:u.runtime&&typeof u.runtime=="object"?u.runtime:null,page:u.page&&typeof u.page=="object"?u.page:null,client:u.client&&typeof u.client=="object"?u.client:null,project:u.project&&typeof u.project=="object"?u.project:null,manifest:u.manifest&&typeof u.manifest=="object"?u.manifest:null,selection:u.selection&&typeof u.selection=="object"?u.selection:null,updatedAt:new Date().toISOString()},w("context",{url:m.url,surface:m.surface,instanceId:m.instanceId}),F(p,200,{ok:!0,context:m})}catch(u){w("context_error",{error:String(u?.message||u)}),F(p,400,{ok:!1,error:String(u?.message||u)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/connect"){try{let u=JSON.parse(await ie(d)||"{}"),h=await $n(e,u,l),E=h.data||{};y={connected:!0,mode:"agensis-claimed",keyId:Nn(h.key),agentId:String(E.agentId||E.agent?.id||e.agent||""),workspaceId:String(E.workspaceId||E.workspace_id||E.agent?.workspace_id||e.workspace||""),agensisUrl:h.baseUrl,handle:String(E.handle||E.agent?.handle||e.handle||""),name:String(E.agent?.name||u.name||e.name||"CursorBuddy runtime"),cwd:String(u.cwd||e.cwd||X.cwd()),surface:String(u.surface||"browser_extension"),command:String(E.command||E.localCommand||""),updatedAt:new Date().toISOString()},m=On(u,y,e),w("connect",{mode:y.mode,keyId:y.keyId,agentId:y.agentId,workspaceId:y.workspaceId,url:m.url}),F(p,200,{ok:!0,connection:y,claim:E})}catch(u){w("connect_error",{error:String(u?.message||u)}),F(p,400,{ok:!1,error:String(u?.message||u)})}return}if(d.method==="POST"&&v.pathname==="/cursorbuddy/edit"){try{let u=JSON.parse(await ie(d)||"{}"),h=[{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(u,null,2)}];w("edit_request",{selector:u?.target?.selector||""});let E=await M({messages:h,model:u?.model});w("edit_done",{chars:E.content.length}),F(p,200,{ok:!0,backend:e.codingCmd,cwd:e.cwd,content:E.content})}catch(u){w("edit_error",{error:String(u?.message||u)}),F(p,500,{ok:!1,error:String(u?.message||u)})}return}if(d.method==="POST"&&v.pathname.endsWith("/chat/completions")){try{let u=JSON.parse(await ie(d)||"{}");if(w("chat_request",{messages:Array.isArray(u.messages)?u.messages.length:0,model:rt(u.model,Ie(e))}),u.stream===!0){Ve(p);let E=await J(u,p);w("chat_done",{chars:E.content.length,stream:!0,fast:E.fast===!0}),p.end();return}let h=await M(u);w("chat_done",{chars:h.content.length,fast:h.fast===!0}),F(p,200,{id:`agensis-cursorbuddy-${Date.now()}`,object:"chat.completion",model:h.model||u.model||e.model,choices:[{index:0,message:{role:"assistant",content:h.content},finish_reason:"stop"}],usage:{prompt_tokens:0,completion_tokens:0,total_tokens:0}})}catch(u){w("chat_error",{error:String(u?.message||u)}),F(p,500,{error:{message:String(u?.message||u)}})}return}p.writeHead(404),p.end("CursorBuddy local bridge")});return await new Promise((d,p)=>{L.once("error",p),L.listen(n,"127.0.0.1",()=>{g=L.address().port,L.off("error",p),d()})}),w("listening",{url:`${he(g)}/cursorbuddy/health`}),{port:g,url:he(g),secret:r,authHeader:ge,close(){return new Promise(d=>L.close(()=>d()))},getContext(){return m}}}import te from"node:fs/promises";import Tn from"node:os";import H from"node:path";var it=200,at=256*1024,Dn=2,Rn=new Set([".md",".markdown",".txt"]);function Pn(e){return String(e||"").replace(/[^a-zA-Z0-9]/g,"-")}function Ce({cwd:e,memoryDir:t,homedir:n=Tn.homedir()}={}){let r=String(t||"").trim();if(r)return r.startsWith("~")?H.join(n,r.slice(1)):H.resolve(r);let s=String(e||"").trim();return s?H.join(n,".claude","projects",Pn(s),"memory"):null}async function xe(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 Ln(e,t){if(!e)throw new Error("memory root unavailable");let n=H.isAbsolute(String(t))?String(t):H.join(e,String(t)),r=await te.realpath(n),s=e.endsWith(H.sep)?e:e+H.sep;if(r!==e&&!r.startsWith(s))throw new Error(`path escapes memory root: ${t}`);return r}function Un(e){let t=H.basename(e).toLowerCase();return t==="memory.md"?"index":t==="claude.md"?"instructions":"memory"}async function Me(e,t,n,r){if(n>Dn||r.length>=it)return;let s;try{s=await te.readdir(t,{withFileTypes:!0})}catch{return}for(let o of s){if(r.length>=it)break;if(o.name.startsWith("."))continue;let i=H.join(t,o.name);if(o.isDirectory())await Me(e,i,n+1,r);else if(o.isFile()&&Rn.has(H.extname(o.name).toLowerCase())){let a=H.relative(e,i);r.push({path:a,kind:Un(a)})}}}async function Fn(e){let t=await xe(e);if(!t)return[];let n=[];return await Me(t,t,0,n),n.sort((r,s)=>r.kind==="index"?-1:s.kind==="index"?1:r.path.localeCompare(s.path)),n}async function jn(e,t){let n=await xe(e),r=await Ln(n,t),s=await te.readFile(r),o=s.length>at;return{content:s.subarray(0,at).toString("utf8"),byteSize:s.length,truncated:o}}async function ct(e){let t=await xe(e);if(!t)return"";let n=[];await Me(t,t,0,n),n.sort((s,o)=>s.path.localeCompare(o.path));let r=[];for(let s of n)try{let o=await te.stat(H.join(t,s.path));r.push(`${s.path}:${o.size}:${Math.floor(o.mtimeMs)}`)}catch{}return r.join("|")}async function ut(e){let t=await Fn(e),n=[];for(let r of t)try{let{content:s,byteSize:o}=await jn(e,r.path);n.push({path:r.path,kind:r.kind,content:s,byteSize:o})}catch{}return n}import lt from"node:fs";import ne from"node:path";import dt from"node:os";function Gn(e){try{return lt.statSync(e).isDirectory()}catch{return!1}}function Ne(e){try{return lt.readdirSync(e,{withFileTypes:!0})}catch{return[]}}function mt({home:e=dt.homedir(),cwd:t=process.cwd()}={}){let n=[e&&ne.join(e,".claude","commands"),t&&ne.join(t,".claude","commands")].filter(Boolean),r=new Set,s=[],o=(i,a)=>{if(!i)return;let l=a?`${a}:${i}`:i;r.has(l)||(r.add(l),s.push({name:i,parent:a||null}))};for(let i of n)for(let a of Ne(i)){if(a.name.startsWith("."))continue;if(a.name.endsWith(".md")){o(a.name.slice(0,-3),null);continue}let l=ne.join(i,a.name);if(a.isDirectory()||a.isSymbolicLink()&&Gn(l))for(let c of Ne(l))c.name.startsWith(".")||c.name.endsWith(".md")&&o(c.name.slice(0,-3),a.name)}return s}function ft({home:e=dt.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 s of n)for(let o of Ne(s))o.name.startsWith(".")||(o.name.endsWith(".md")?r.add(o.name.slice(0,-3)):(o.isDirectory()||o.isSymbolicLink())&&r.add(o.name));return[...r].sort()}import{readFile as Hn}from"node:fs/promises";var Jn=new Set(["127.0.0.1","localhost","::1","[::1]"]);function pt(e,t,n){let r=Number(e);return Number.isFinite(r)?Math.max(1,Math.min(n,Math.trunc(r))):t}function Kn(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(s=>String(s||"").trim().toLowerCase()).filter(Boolean))].slice(0,16),...e.contextWindow?{contextWindow:pt(e.contextWindow,void 0,1e7)}:{},maxConcurrency:pt(e.maxConcurrency,1,64),shared:!0}}async function ht(e){if(!e)return[];let t=JSON.parse(await Hn(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(Kn).filter(Boolean)}function gt(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 yt({models:e,request:t,send:n,signal:r,fetchImpl:s=fetch,env:o=process.env}){let i=String(t?.requestId||"").trim();if(!i)throw new Error("Inference requestId is required.");let a=(Array.isArray(e)?e:[]).find(b=>b.id===t?.model);if(!a)throw new Error(`Shared model '${t?.model||""}' is not available.`);let l={"content-type":"application/json"},c=a.apiKeyEnv?o[a.apiKeyEnv]:"";c&&(l.authorization=`Bearer ${c}`),n({action:"agent_inference_started",requestId:i,model:a.id});let{requestId:m,model:g,type:y,action:w,...S}=t,$=await s(`${a.baseUrl}/chat/completions`,{method:"POST",headers:l,body:JSON.stringify({...S,model:a.upstreamModel,stream:t.stream===!0}),signal:r});if(!$.ok){let b=await $.text().catch(()=>"");throw new Error(b||`Local model returned HTTP ${$.status}.`)}if(t.stream===!0){if(!$.body)throw new Error("Local model returned an empty stream.");let b=$.body.getReader(),O=new TextDecoder,N="",M,J=p=>{let v=p.trim();if(!v.startsWith("data:"))return!1;let u=v.slice(5).trim();if(!u)return!1;if(u==="[DONE]")return!0;try{let h=JSON.parse(u);h?.usage&&(M=h.usage),n({action:"agent_inference_delta",requestId:i,model:a.id,chunk:h})}catch{}return!1},L=!1;for(;!L;){let{done:p,value:v}=await b.read();N+=O.decode(v||new Uint8Array,{stream:!p});let u=N.split(/\r?\n/);N=p?"":u.pop()||"";for(let h of u)if(J(h)){L=!0;break}if(p)break}N&&J(N);let d={action:"agent_inference_result",requestId:i,model:a.id,...M?{usage:M}:{}};return n(d),d}let k=await $.json();return n({action:"agent_inference_result",requestId:i,model:a.id,response:k}),k}import St from"node:fs";import W from"node:fs/promises";import Wn from"node:os";import K from"node:path";var _t="status.json",kt="heartbeat.json",Oe="heartbeat.md",zn="agent.json",Yn="soul.md",qn=16*1024,Xn=`# Heartbeat
|
|
13
13
|
|
|
14
14
|
This file tells you what to do on each heartbeat \u2014 the recurring "still here, still
|
|
15
15
|
working" moment. Edit it freely; the daemon reads it but never overwrites your edits.
|
|
@@ -22,28 +22,30 @@ On each heartbeat:
|
|
|
22
22
|
- If you've finished and there's nothing to do, a short idle note is fine.
|
|
23
23
|
|
|
24
24
|
Add your own recurring checks below.
|
|
25
|
-
`,
|
|
26
|
-
`),
|
|
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>qn)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,Yn)}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,zn)}async function Ct(e){let t=W.join(re(e),Oe);try{let n=await K.stat(t);return!n.isFile()||n.size>Kn?null:(await K.readFile(t,"utf8")).trim()||null}catch{return null}}var Vn=30*60*1e3,Qn=15*1e3,xt=8,Zn="claude-opus-4-8",oe="0.1.25";async function Se(e={}){let t=er(e);t.sharedModels=t.share?await ft(t.sharedModelsFile):[];let n=!1,r=null,o=null,s=null,i=null,a=0,d=null,u=null,m="",g=null,_=!1,h=null,x=new Map,$=null,b={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},S=new Map,M=new Map,N=[],O=()=>b,j=()=>({connected:_&&!!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()}),U=()=>{$||!t.lanListener||($=new ce.Server({port:0}),$.on("listening",()=>{let{port:I}=$.address();b={transport:"ws",listening:!0,addrs:Er(I),auth:"hub-pairwise"},B(`Agent-mesh LAN listener on port ${I}`),ae(r,t,O())}),$.on("connection",I=>{let A=!1,f=setTimeout(()=>{if(!A)try{I.close(1008,"peer auth required")}catch{}},5e3);I.once("message",E=>{clearTimeout(f);let C=De(E),L=C?.type==="peer_auth"?S.get(C.ticket):null;if(!L||L.fromAgentId!==C.fromAgentId||Date.now()>L.exp){try{I.close(1008,"invalid ticket")}catch{}return}S.delete(C.ticket),A=!0,I.on("message",G=>{let T=De(G);T?.type==="agent_job"&&T.job?.id&&u.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}b={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},p=I=>new Promise((A,f)=>{if(!D(r,{action:"peer_ticket_request",targetAgentId:I})){f(new Error("hub socket not open"));return}let E=M.get(I)||[];E.push({resolve:A,reject:f}),M.set(I,E),setTimeout(()=>{let C=M.get(I)||[],L=C.findIndex(G=>G.resolve===A);L>=0&&(C.splice(L,1),f(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 f=N.indexOf(I);f>=0&&(N.splice(f,1),I([]))},1e4)}),c=async(I,A)=>{let f=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:(f=new ce(`ws://${G.host}:${G.port}`),await new Promise((T,ke)=>{f.once("open",T),f.once("error",ke),setTimeout(()=>ke(new Error("peer connect timed out")),5e3)}),D(f,{type:"peer_auth",ticket:L.ticket,fromAgentId:t.agent}),D(f,{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{f?.close()}catch{}}},y=()=>{n=!0,$t(x),o&&clearTimeout(o),s&&clearInterval(s),i&&clearInterval(i),g&&(g.close().catch(()=>{}),g=null),l(),Et(t,{status:"stopped",connected:!1});try{r?.close()}catch{}d&&d()};if(u=ze({concurrency:t.once?1:t.maxConcurrency,runJob:async(I,A)=>{await hr(t,I,A),t.once&&y()}}),t.cursorBuddyBridge)try{g=await rt(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:B,connectionProvider:j}),g?.secret&&(t.cursorBuddyBridgeSecret=g.secret)}catch(I){if(Or(I)){let A=await Nr(t.cursorBuddyPort);if(A?.ok){let f=A.pid?` pid ${A.pid}`:"";B(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${f}`)}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}`);g=null}w.once("SIGINT",y),w.once("SIGTERM",y);let v=()=>{if(n)return;let I=nr(t.url,t.token,t);m="",B(`Connecting to ${I.replace(t.token,"redacted")}`),r=new ce(I),r.on("open",()=>{_=!1,h=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([Ut(t,O()).catch(()=>null),$e(t).catch(()=>null)]).then(([A,f])=>{D(r,{action:"agent_heartbeat",...A?{capabilitiesHash:A.capabilitiesHash,memoryHash:A.memoryHash}:{},metadata:Te(t,u,f,Dt(t)?g?.getContext?.():null,x)})})},t.heartbeatMs),s.unref&&s.unref()}),r.on("message",A=>{let f=De(A);if(f){if(f.type==="agent_registered"){_=!0,h=f.connection||f.agent||null,Ot(t,f.agent),B(`Registered as ${f.connection?.name||t.name} on ${f.connection?.host||le.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,f)).catch(E=>{B(`Profile save failed: ${E?.message||E}`)}),Be(t,f.agent).catch(()=>{}),At(t).catch(()=>{}),Bt(r,t),U(),ae(r,t,O());return}if(f.type==="agent_config"){Ot(t,f.agent),B(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),Be(t,f.agent).catch(()=>{});return}if(f.type==="agent_memory_refresh"){Bt(r,t),ae(r,t,O());return}if(f.type==="agent_capabilities_refresh"){ae(r,t,O());return}if(f.type==="agent_inference_cancel"){x.get(String(f.requestId||""))?.abort();return}if(f.type==="agent_job_cancel"){let E=String(f.jobId||"");E&&u.cancel(E,f.reason||"Cancelled by Agensis")&&B(`Cancelled job ${E}`);return}if(f.type==="agent_inference_request"&&f.requestId){let E=String(f.requestId),C=t.sharedModels.find(T=>T.id===f.model),L=[...x.values()].filter(T=>T.model===f.model).length;if(!C){D(r,{action:"agent_inference_error",requestId:E,error:`Shared model '${f.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,u,null,null,x)}),ht({models:t.sharedModels,request:f,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,u,null,null,x)})});return}if(f.type==="peer_ticket"){let E=f.peer?.agentId,C=M.get(E)||[],L=C.shift();C.length?M.set(E,C):M.delete(E),L&&L.resolve(f);return}if(f.type==="peer_ticket_grant"){S.set(f.ticket,{fromAgentId:f.fromAgentId,exp:f.exp});return}if(f.type==="peer_list"){let E=N.shift();E&&E(Array.isArray(f.peers)?f.peers:[]);return}if(f.type==="agent_reach_disable"){l(),ae(r,t,O());return}if(f.type==="error"){B(`Server rejected request: ${f.message||"unknown error"}`);return}if(f.type==="agent_disabled"){_=!1,h=null,B(`Agent disabled by Agensis: ${f.reason||"deactivated"}`),y();return}if(f.type==="agent_job"&&f.job?.id){let E=u.enqueue({...f.job,key:f.job.id,lane:Mt(f.job),ws:r});E.accepted&&(a+=1,B(`Queued job ${f.job.id} at position ${E.position}`),t.once&&u.idle().then(()=>y()))}}}),r.on("close",(A,f)=>{$t(x),_=!1,h=null;let E=String(f||"");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(m==="ECONNREFUSED"&&or(t.url)){B("Local agent backend is not running on 127.0.0.1:3142."),B("Start it in another terminal with: npm run backend"),B("Then rerun this connect command."),y();return}t.once&&a>0&&u.active()===0&&u.size()===0&&y(),!(n||t.once)&&(o=setTimeout(v,2e3),o.unref&&o.unref())}),r.on("error",A=>{m=A?.code||"",B(`Socket error: ${A?.message||A}`)})},P=async()=>{let I=await $e(t).catch(()=>null);await vt(t,{busy:u.active()>0,active:u.active(),queueSize:u.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&&u.active()===0&&u.size()===0&&y(),n&&y()},500);d=()=>{clearInterval(A),I()}}),d=null,w.off("SIGINT",y),w.off("SIGTERM",y)}function er(e){let t=tr(e.cursorBuddyBridge),n=e.noCoding===!0||w.env.AGENSIS_NO_CODING==="1",r={url:String(e.url||e.baseUrl||w.env.AGENSIS_URL||"").trim(),token:String(e.token||w.env.AGENSIS_TOKEN||"").trim(),workspace:String(e.workspace||e.workspaceId||w.env.AGENSIS_WORKSPACE||w.env.AGENSIS_WORKSPACE_ID||"").trim(),agent:String(e.agent||e.agentId||w.env.AGENSIS_AGENT||w.env.AGENSIS_AGENT_ID||"").trim(),handle:Ft(e.handle||w.env.AGENSIS_HANDLE||e.name||w.env.AGENSIS_NAME||"agent"),name:String(e.name||w.env.AGENSIS_NAME||e.handle||w.env.AGENSIS_HANDLE||"agensis Agent").trim(),cwd:String(e.cwd||w.env.AGENSIS_CWD||w.cwd()).trim(),codingCmd:n?"":String(e.codingCmd||w.env.AGENSIS_CODING_CMD||w.env.CODING_CMD||"claude -p").trim(),model:Re(e.model||w.env.AGENSIS_MODEL||w.env.CLAUDE_MODEL||""),permissionMode:we(e.permissionMode||e.permission_mode||e.permission||w.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||w.env.AGENSIS_TIMEOUT_MS||Vn),heartbeatMs:Number(e.heartbeatMs||w.env.AGENSIS_HEARTBEAT_MS||Qn),maxConcurrency:Math.max(1,Number(e.maxConcurrency||w.env.AGENSIS_MAX_CONCURRENCY||xt)||xt),once:!!(e.once||w.env.AGENSIS_ONCE==="1"),exitOnOnce:!!e.exitOnOnce,onRegistered:typeof e.onRegistered=="function"?e.onRegistered:null,primaryDaemon:!!(e.primaryDaemon||w.env.AGENSIS_PRIMARY_DAEMON==="1"),cursorBuddyRuntime:!!(e.cursorBuddyRuntime||w.env.AGENSIS_CURSORBUDDY_RUNTIME==="1"),cursorBuddyBridge:t,cursorBuddyPort:Number(e.cursorBuddyPort||w.env.AGENSIS_CURSORBUDDY_PORT||8787),cursorBuddyBridgeSecret:String(e.cursorBuddyBridgeSecret||w.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),cursorBuddyModel:String(e.cursorBuddyModel||w.env.AGENSIS_CURSORBUDDY_MODEL||"haiku-4.5").trim(),lanListener:!!(e.lanListener||e.lan||w.env.AGENSIS_LAN==="1"),share:!!(e.share||w.env.AGENSIS_SHARE==="1"),sharedModelsFile:String(e.sharedModelsFile||w.env.AGENSIS_SHARED_MODELS_FILE||"").trim(),noCoding:n,hostFolders:Lt(e.hostFolders??e.host_folders??w.env.AGENSIS_HOST_FOLDERS)};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 tr(e){let t=w.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 nr(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 rr(t)&&(t.protocol="http:",t.hostname="127.0.0.1",t.port="3142"),t}function rr(e){if(!(e.hostname==="localhost"||e.hostname==="127.0.0.1"||e.hostname==="0.0.0.0")||e.port==="3142")return!1;if(e.port==="5173"||e.port==="8888")return!0;let t=Number(e.port||0);return t>=49152&&t<=65535}function or(e){try{let t=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 sr=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,ir=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function ar(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function cr(e){for(let t of ir){let n=String(e||"").match(t),r=ar(n?.[1]||"");if(r)return r}return""}function ur(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 dr(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=ur(t)||t;if(!r)return"";if(r.length<=500)return r;let o=[/\b(?:can you\s+)?(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:wave|waves|waving|say|speak)\b.{0,160}/i,/\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b.{0,120}\b(?:wave|waves|waving|say|speak|open|show|hide|hush|close|dismiss|clear)\b.{0,160}/i,/\b(?:wave|open|show|hide|hush|close|dismiss|clear)\b.{0,120}\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy|bubble|prompt|dialog|panel|options|menu)\b/i,/\b(?:say|speak)\s+[`"'“”‘’]?.{1,180}/i];for(let s of o){let i=r.match(s);if(i?.[0])return i[0].trim()}return""}function lr(e){let t=dr(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=sr.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=cr(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 mr(e,t){let r=`http://127.0.0.1:${Number(e.cursorBuddyPort||8787)}/cursorbuddy/control`,o=String(e.cursorBuddyBridgeSecret||w.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 fr(e){return e.action==="wave"?"Sent CursorBuddy a wave command.":e.action==="say"?`Sent CursorBuddy speech: ${e.text||""}`.trim():e.action==="open"?"Opened CursorBuddy's prompt.":e.action==="hush"?"Dismissed CursorBuddy's bubble.":e.action==="choose"?"Sent CursorBuddy options.":"Sent CursorBuddy control command."}function Dt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function pr(e,t,n,r){let o="cursorbuddy-control",s="native",i=[],a=(m="")=>{D(t.ws,{action:"agent_job_delta",jobId:t.id,content:m,elapsedMs:Date.now()-r,model:o,permissionMode:s,permissionFlags:i})};a("");let d="",u="";try{await mr(e,n),d=fr(n),a(d)}catch(m){u=String(m?.message||m),d=`CursorBuddy control failed: ${u}`,a(d)}D(t.ws,{action:"agent_job_result",jobId:t.id,response:d,error:u,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 hr(e,t,{signal:n}){let r=Date.now();B(`Starting job ${t.id}`);let o=lr(t.prompt);if(o&&Dt(e)){await pr(e,t,o,r),e.once&&(B("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>w.exit(0),150));return}let s=yr(e,t),i=await gr(e,t),a="",d="",u=0,m=(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})};m("");let g=s.streamJson?Sr():null,_=setInterval(()=>m(a),1e3);_.unref&&_.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=>{g?(g.feed(N),a=g.live):(a+=String(N||""),d=Mr(`${d}
|
|
28
|
-
${N}`));let
|
|
29
|
-
${a}`:""
|
|
25
|
+
`,Vn=8*1024,Qn=400;function wt(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=Wn.homedir()}={}){return K.join(n,".agensis",wt(e,"workspace"),wt(t,"agent"))}function vt(e){return K.join(re(e),_t)}function Et(e){return K.join(re(e),Oe)}async function Be(e){let t=re(e);try{return await W.mkdir(t,{recursive:!0}),t}catch{return null}}async function ye(e,t){let n=`${e}.tmp-${process.pid}`;try{return await W.writeFile(n,t),await W.rename(n,e),!0}catch{try{await W.rm(n,{force:!0})}catch{}return!1}}async function $e(e,t){if(!t||typeof t!="object")return!1;let n=await Be(e);if(!n)return!1;let r={id:t.id??e.agent??"",workspace:t.workspace_id??e.workspace??"",name:t.name??e.name??"",handle:t.handle??e.handle??"",model:t.model??e.model??"",permissionMode:t.permissionMode??t.permission_mode??e.permissionMode??"",description:t.description??"",instructions:t.instructions??"",systemPrompt:t.system_prompt??t.systemPrompt??"",tools:Array.isArray(t.tools)?t.tools:[],skills:Array.isArray(t.skills)?t.skills:[],memoryDir:t.memory_dir??t.memoryDir??"",version:Number(t.version||0),updatedAt:new Date().toISOString()},s=await ye(K.join(n,zn),`${JSON.stringify(r,null,2)}
|
|
26
|
+
`),o=String(t.soul??""),i=await ye(K.join(n,Yn),o);return s&&i}async function At(e,t={}){let n=await Be(e);return n?ye(K.join(n,kt),Ct(e,t)):!1}function It(e,t={}){let n=re(e);try{return St.mkdirSync(n,{recursive:!0}),St.writeFileSync(K.join(n,kt),Ct(e,t)),!0}catch{return!1}}function Ct(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 Te(e){let t=K.join(re(e),_t),n;try{let a=await W.stat(t);if(!a.isFile()||a.size>Vn)return null;n=await W.readFile(t,"utf8")}catch{return null}let r;try{r=JSON.parse(n)}catch{return null}if(!r||typeof r!="object"||Array.isArray(r))return null;let s=bt(r.status),o=bt(r.note??r.message);if(!s&&!o)return null;let i={};return s&&(i.status=s),o&&(i.note=o),r.ts!=null&&Number.isFinite(Number(r.ts))&&(i.ts=Number(r.ts)),i}function bt(e){return e==null?"":String(e).trim().replace(/\s+/g," ").slice(0,Qn)}async function xt(e){let t=await Be(e);if(!t)return!1;let n=K.join(t,Oe);try{return await W.access(n),!0}catch{}return ye(n,Xn)}async function Mt(e){let t=K.join(re(e),Oe);try{let n=await W.stat(t);return!n.isFile()||n.size>qn?null:(await W.readFile(t,"utf8")).trim()||null}catch{return null}}var er=30*60*1e3,tr=15*1e3,Nt=2,nr=10*1024,rr="claude-opus-4-8",oe="0.1.26";async function we(e={}){let t=or(e);t.sharedModels=t.share?await ht(t.sharedModelsFile):[];let n=!1,r=null,s=null,o=null,i=null,a=0,l=null,c=null,m="",g=null,y=!1,w=null,S=new Map,$=null,k={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"},b=new Map,O=new Map,N=[],M=()=>k,J=()=>({connected:y&&!!t.cursorBuddyRuntime,mode:t.cursorBuddyRuntime?"agensis-cli":"agensis-cli-unclaimed",agentId:w?.agentId||w?.agent_id||t.agent,workspaceId:w?.workspaceId||w?.workspace_id||t.workspace,agensisUrl:t.url,handle:w?.handle||t.handle,name:w?.name||t.name,cwd:t.cwd,updatedAt:new Date().toISOString()}),L=()=>{$||!t.lanListener||($=new ce.Server({port:0}),$.on("listening",()=>{let{port:A}=$.address();k={transport:"ws",listening:!0,addrs:Mr(A),auth:"hub-pairwise"},B(`Agent-mesh LAN listener on port ${A}`),ae(r,t,M())}),$.on("connection",A=>{let C=!1,f=setTimeout(()=>{if(!C)try{A.close(1008,"peer auth required")}catch{}},5e3);A.once("message",I=>{clearTimeout(f);let x=Re(I),U=x?.type==="peer_auth"?b.get(x.ticket):null;if(!U||U.fromAgentId!==x.fromAgentId||Date.now()>U.exp){try{A.close(1008,"invalid ticket")}catch{}return}b.delete(x.ticket),C=!0,A.on("message",j=>{let D=Re(j);D?.type==="agent_job"&&D.job?.id&&c.enqueue({...D.job,key:D.job.id,lane:Ot(D.job),ws:r}).accepted&&B(`Queued peer-handoff job ${D.job.id} from ${x.fromAgentId}`)})})}),$.on("error",A=>B(`LAN listener error: ${A?.message||A}`)))},d=()=>{if($){try{$.close()}catch{}$=null}k={transport:"ws",listening:!1,addrs:[],auth:"hub-pairwise"}},p=A=>new Promise((C,f)=>{if(!R(r,{action:"peer_ticket_request",targetAgentId:A})){f(new Error("hub socket not open"));return}let I=O.get(A)||[];I.push({resolve:C,reject:f}),O.set(A,I),setTimeout(()=>{let x=O.get(A)||[],U=x.findIndex(j=>j.resolve===C);U>=0&&(x.splice(U,1),f(new Error("peer ticket request timed out")))},1e4)}),v=()=>new Promise((A,C)=>{if(!R(r,{action:"peer_list_request"})){C(new Error("hub socket not open"));return}N.push(A),setTimeout(()=>{let f=N.indexOf(A);f>=0&&(N.splice(f,1),A([]))},1e4)}),u=async(A,C)=>{let f=null;try{let x=(await v()).find(D=>D.agentId===A&&D.reach?.listening&&D.reach.addrs?.length);if(!x)return!1;let U=await p(A),j=U.peer?.addrs?.[0]||x.reach.addrs[0];return!j?.host||!j?.port?!1:(f=new ce(`ws://${j.host}:${j.port}`),await new Promise((D,ve)=>{f.once("open",D),f.once("error",ve),setTimeout(()=>ve(new Error("peer connect timed out")),5e3)}),R(f,{type:"peer_auth",ticket:U.ticket,fromAgentId:t.agent}),R(f,{type:"agent_job",job:C}),!0)}catch(I){return B(`Peer handoff to ${A} failed, falling back to hub relay: ${I?.message||I}`),!1}finally{try{f?.close()}catch{}}},h=()=>{n=!0,Rt(S),s&&clearTimeout(s),o&&clearInterval(o),i&&clearInterval(i),g&&(g.close().catch(()=>{}),g=null),d(),It(t,{status:"stopped",connected:!1});try{r?.close()}catch{}l&&l()};if(c=qe({concurrency:t.once?1:t.maxConcurrency,runJob:async(A,C)=>{await wr(t,A,C),t.once&&h()}}),t.cursorBuddyBridge)try{g=await st(t,{port:t.cursorBuddyPort,authSecret:t.cursorBuddyBridgeSecret||void 0,log:B,connectionProvider:J}),g?.secret&&(t.cursorBuddyBridgeSecret=g.secret)}catch(A){if(Dr(A)){let C=await Rr(t.cursorBuddyPort);if(C?.ok){let f=C.pid?` pid ${C.pid}`:"";B(`CursorBuddy local bridge already running on http://127.0.0.1:${t.cursorBuddyPort}${f}`)}else B(`CursorBuddy local bridge port ${t.cursorBuddyPort} is in use but did not answer health`)}else B(`CursorBuddy local bridge unavailable: ${A?.message||A}`);g=null}_.once("SIGINT",h),_.once("SIGTERM",h);let E=()=>{if(n)return;let A=ir(t.url,t.token,t);m="",B(`Connecting to ${A.replace(t.token,"redacted")}`),r=new ce(A),r.on("open",()=>{y=!1,w=null,B(`Connected. Registering @${t.handle||"agent"} from ${t.cwd}`),R(r,{type:"auth",token:t.token}),R(r,{action:"agent_register",workspaceId:t.workspace,agentId:t.agent,handle:t.handle,name:t.name,host:de.hostname(),cwd:t.cwd,metadata:{codingCmd:t.codingCmd,model:t.model,permissionMode:t.permissionMode,permissionFlags:Ue(t.permissionMode),once:t.once,runtime:"agensis",version:oe}}),o=setInterval(()=>{Promise.all([jt(t,M()).catch(()=>null),Te(t).catch(()=>null)]).then(([C,f])=>{R(r,{action:"agent_heartbeat",...C?{capabilitiesHash:C.capabilitiesHash,memoryHash:C.memoryHash}:{},metadata:De(t,c,f,Pt(t)?g?.getContext?.():null,S)})})},t.heartbeatMs),o.unref&&o.unref()}),r.on("message",C=>{let f=Re(C);if(f){if(f.type==="agent_registered"){y=!0,w=f.connection||f.agent||null,$t(t,f.agent),B(`Registered as ${f.connection?.name||t.name} on ${f.connection?.host||de.hostname()}`),t.onRegistered&&Promise.resolve(t.onRegistered(t,f)).catch(I=>{B(`Profile save failed: ${I?.message||I}`)}),$e(t,f.agent).catch(()=>{}),xt(t).catch(()=>{}),Dt(r,t),L(),ae(r,t,M());return}if(f.type==="agent_config"){$t(t,f.agent),B(`Updated config for @${t.handle||"agent"}: model=${t.model}, permission=${t.permissionMode}`),$e(t,f.agent).catch(()=>{});return}if(f.type==="agent_memory_refresh"){Dt(r,t),ae(r,t,M());return}if(f.type==="agent_capabilities_refresh"){ae(r,t,M());return}if(f.type==="agent_inference_cancel"){S.get(String(f.requestId||""))?.abort();return}if(f.type==="agent_job_cancel"){let I=String(f.jobId||"");I&&c.cancel(I,f.reason||"Cancelled by Agensis")&&B(`Cancelled job ${I}`);return}if(f.type==="agent_inference_request"&&f.requestId){let I=String(f.requestId),x=t.sharedModels.find(D=>D.id===f.model),U=[...S.values()].filter(D=>D.model===f.model).length;if(!x){R(r,{action:"agent_inference_error",requestId:I,error:`Shared model '${f.model||""}' is not available.`});return}if(U>=x.maxConcurrency){R(r,{action:"agent_inference_error",requestId:I,error:"Shared model is at capacity.",code:"capacity_exhausted"});return}let j=new AbortController;S.set(I,{abort:()=>j.abort(),model:x.id}),R(r,{action:"agent_heartbeat",metadata:De(t,c,null,null,S)}),yt({models:t.sharedModels,request:f,signal:j.signal,send:D=>R(r,D)}).catch(D=>{R(r,{action:"agent_inference_error",requestId:I,error:j.signal.aborted?"Inference cancelled.":D?.message||String(D),code:j.signal.aborted?"cancelled":"inference_failed"})}).finally(()=>{S.delete(I),R(r,{action:"agent_heartbeat",metadata:De(t,c,null,null,S)})});return}if(f.type==="peer_ticket"){let I=f.peer?.agentId,x=O.get(I)||[],U=x.shift();x.length?O.set(I,x):O.delete(I),U&&U.resolve(f);return}if(f.type==="peer_ticket_grant"){b.set(f.ticket,{fromAgentId:f.fromAgentId,exp:f.exp});return}if(f.type==="peer_list"){let I=N.shift();I&&I(Array.isArray(f.peers)?f.peers:[]);return}if(f.type==="agent_reach_disable"){d(),ae(r,t,M());return}if(f.type==="error"){B(`Server rejected request: ${f.message||"unknown error"}`);return}if(f.type==="agent_disabled"){y=!1,w=null,B(`Agent disabled by Agensis: ${f.reason||"deactivated"}`),h();return}if(f.type==="agent_job"&&f.job?.id){let I=c.enqueue({...f.job,key:f.job.id,lane:Ot(f.job),ws:r});I.accepted&&(a+=1,B(`Queued job ${f.job.id} at position ${I.position}`),t.once&&c.idle().then(()=>h()))}}}),r.on("close",(C,f)=>{Rt(S),y=!1,w=null;let I=String(f||"");if(B(`Socket closed (${C||"no-code"}${I?`: ${I}`:""})`),o&&(clearInterval(o),o=null),C===1008&&/agent deactivated|authentication failed/i.test(I)){B("Stopping daemon because Agensis rejected this agent connection."),h();return}if(m==="ECONNREFUSED"&&cr(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."),h();return}t.once&&a>0&&c.active()===0&&c.size()===0&&h(),!(n||t.once)&&(s=setTimeout(E,2e3),s.unref&&s.unref())}),r.on("error",C=>{m=C?.code||"",B(`Socket error: ${C?.message||C}`)})},T=async()=>{let A=await Te(t).catch(()=>null);await At(t,{busy:c.active()>0,active:c.active(),queueSize:c.size(),connected:r?.readyState===ce.OPEN,agentStatus:A?.status,agentNote:A?.note}).catch(()=>{})};T(),i=setInterval(()=>{T()},t.heartbeatMs),i.unref&&i.unref(),E(),await new Promise(A=>{let C=setInterval(async()=>{t.once&&a>0&&c.active()===0&&c.size()===0&&h(),n&&h()},500);l=()=>{clearInterval(C),A()}}),l=null,_.off("SIGINT",h),_.off("SIGTERM",h)}function or(e){let t=sr(e.cursorBuddyBridge),n=e.noCoding===!0||_.env.AGENSIS_NO_CODING==="1",s=!Se(e.fullCliContext,Se(_.env.AGENSIS_FULL_CLI_CONTEXT,!1))&&Se(e.leanCli,!0),o={url:String(e.url||e.baseUrl||_.env.AGENSIS_URL||"").trim(),token:String(e.token||_.env.AGENSIS_TOKEN||"").trim(),workspace:String(e.workspace||e.workspaceId||_.env.AGENSIS_WORKSPACE||_.env.AGENSIS_WORKSPACE_ID||"").trim(),agent:String(e.agent||e.agentId||_.env.AGENSIS_AGENT||_.env.AGENSIS_AGENT_ID||"").trim(),handle:Gt(e.handle||_.env.AGENSIS_HANDLE||e.name||_.env.AGENSIS_NAME||"agent"),name:String(e.name||_.env.AGENSIS_NAME||e.handle||_.env.AGENSIS_HANDLE||"agensis Agent").trim(),cwd:String(e.cwd||_.env.AGENSIS_CWD||_.cwd()).trim(),codingCmd:n?"":String(e.codingCmd||_.env.AGENSIS_CODING_CMD||_.env.CODING_CMD||"claude -p").trim(),model:Le(e.model||_.env.AGENSIS_MODEL||_.env.CLAUDE_MODEL||""),permissionMode:be(e.permissionMode||e.permission_mode||e.permission||_.env.AGENSIS_PERMISSION_MODE||"default"),timeoutMs:Number(e.timeoutMs||_.env.AGENSIS_TIMEOUT_MS||er),heartbeatMs:Number(e.heartbeatMs||_.env.AGENSIS_HEARTBEAT_MS||tr),maxConcurrency:Math.max(1,Number(e.maxConcurrency||_.env.AGENSIS_MAX_CONCURRENCY||Nt)||Nt),once:!!(e.once||_.env.AGENSIS_ONCE==="1"),exitOnOnce:!!e.exitOnOnce,onRegistered:typeof e.onRegistered=="function"?e.onRegistered:null,primaryDaemon:!!(e.primaryDaemon||_.env.AGENSIS_PRIMARY_DAEMON==="1"),cursorBuddyRuntime:!!(e.cursorBuddyRuntime||_.env.AGENSIS_CURSORBUDDY_RUNTIME==="1"),cursorBuddyBridge:t,cursorBuddyPort:Number(e.cursorBuddyPort||_.env.AGENSIS_CURSORBUDDY_PORT||8787),cursorBuddyBridgeSecret:String(e.cursorBuddyBridgeSecret||_.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),cursorBuddyModel:String(e.cursorBuddyModel||_.env.AGENSIS_CURSORBUDDY_MODEL||"haiku-4.5").trim(),lanListener:!!(e.lanListener||e.lan||_.env.AGENSIS_LAN==="1"),share:!!(e.share||_.env.AGENSIS_SHARE==="1"),sharedModelsFile:String(e.sharedModelsFile||_.env.AGENSIS_SHARED_MODELS_FILE||"").trim(),noCoding:n,leanCli:s,syncMemory:Se(e.syncMemory,_.env.AGENSIS_SYNC_MEMORY==="1"),hostFolders:Ft(e.hostFolders??e.host_folders??_.env.AGENSIS_HOST_FOLDERS)};o.sharedModelsFile&&!le.isAbsolute(o.sharedModelsFile)&&(o.sharedModelsFile=le.resolve(o.cwd,o.sharedModelsFile));let i=[];if(o.url||i.push("--url"),o.token||i.push("--token"),o.workspace||i.push("--workspace"),o.agent||i.push("--agent"),o.share&&!o.sharedModelsFile&&i.push("--shared-models-file"),i.length)throw new Error(`Missing required option(s): ${i.join(", ")}`);return o}function Se(e,t){return e==null||e===""?t:typeof e=="boolean"?e:!/^(0|false|off|no)$/i.test(String(e).trim())}function sr(e){let t=_.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 ir(e,t,n={}){let r=Pe(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 Pe(e){let t=new URL(e);return ar(t)&&(t.protocol="http:",t.hostname="127.0.0.1",t.port="3142"),t}function ar(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 cr(e){try{let t=Pe(e);return(t.hostname==="localhost"||t.hostname==="127.0.0.1"||t.hostname==="0.0.0.0")&&t.port==="3142"}catch{return!1}}function Ot(e){let t=String(e?.sessionId||""),n=String(e?.threadParentId||"");return`${t}::${n}`}var ur=/\b(cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b/i,lr=[/\b(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:say|speak)\s+(.+)$/i];function dr(e){return String(e||"").trim().replace(/^[`"'“”‘’]+|[`"'“”‘’?.!]+$/g,"").trim().slice(0,1200)}function mr(e){for(let t of lr){let n=String(e||"").match(t),r=dr(n?.[1]||"");if(r)return r}return""}function fr(e){let t=String(e||"").replace(/\s+/g," ").trim();if(!t)return"";let n=/latest user message\s*:\s*/gi,r=null,s=null;for(;r=n.exec(t);)s=r;if(!s)return"";let o=t.slice(s.index+s[0].length).trim(),i=o.search(/\b(Return a useful response|Conversation context follows|Previous user|Previous assistant|Diagnostic notes|System prompt|Developer message)\b/i);return(i>=0?o.slice(0,i):o).trim().replace(/^["'“”‘’]+|["'“”‘’]+$/g,"").trim()}function pr(e){let t=String(e||"").replace(/\s+/g," ").trim(),r=fr(t)||t;if(!r)return"";if(r.length<=500)return r;let s=[/\b(?:can you\s+)?(?:make|have|tell)\s+(?:the\s+)?(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\s+(?:wave|waves|waving|say|speak)\b.{0,160}/i,/\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy)\b.{0,120}\b(?:wave|waves|waving|say|speak|open|show|hide|hush|close|dismiss|clear)\b.{0,160}/i,/\b(?:wave|open|show|hide|hush|close|dismiss|clear)\b.{0,120}\b(?:cursorbuddy|cursor buddy|avatar|buddy|pet|character|him|guy|bubble|prompt|dialog|panel|options|menu)\b/i,/\b(?:say|speak)\s+[`"'“”‘’]?.{1,180}/i];for(let o of s){let i=r.match(o);if(i?.[0])return i[0].trim()}return""}function hr(e){let t=pr(e);if(!t)return null;let n=/^(open|show|hide|hush|close|dismiss)\b/i.test(t),r=ur.test(t);if(!n&&!r)return null;let s="agensis-native-control";if(/\b(hide|hush|close|dismiss|clear)\b.*\b(bubble|prompt|dialog|panel|options|menu)\b/i.test(t)||/^hush\b/i.test(t))return{action:"hush",source:s};if(/\b(open|show|bring up|get back|display)\b.*\b(prompt|bubble|dialog|panel|options|menu)\b/i.test(t)||/^open\b/i.test(t))return{action:"open",source:s};let o=mr(t);return o&&r?{action:"say",text:o,source:s}:r&&/\b(wave|waves|waving)\b/i.test(t)?{action:"wave",text:o,source:s}:null}async function gr(e,t){let r=`http://127.0.0.1:${Number(e.cursorBuddyPort||8787)}/cursorbuddy/control`,s=String(e.cursorBuddyBridgeSecret||_.env.AGENSIS_CURSORBUDDY_BRIDGE_SECRET||"").trim(),o={"content-type":"application/json"};s&&(o.authorization=`Bearer ${s}`,o["x-agensis-bridge-secret"]=s);let i=await fetch(r,{method:"POST",headers:o,body:JSON.stringify(t)}),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 yr(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 Pt(e={}){return e.cursorBuddyBridge===!1?!1:!!(e.cursorBuddyRuntime||e.primaryDaemon)}async function Sr(e,t,n,r){let s="cursorbuddy-control",o="native",i=[],a=(m="")=>{R(t.ws,{action:"agent_job_delta",jobId:t.id,content:m,elapsedMs:Date.now()-r,model:s,permissionMode:o,permissionFlags:i})};a("");let l="",c="";try{await gr(e,n),l=yr(n),a(l)}catch(m){c=String(m?.message||m),l=`CursorBuddy control failed: ${c}`,a(l)}R(t.ws,{action:"agent_job_result",jobId:t.id,response:l,error:c,elapsedMs:Date.now()-r,model:s,permissionMode:o,permissionFlags:i}),B(`Finished native CursorBuddy ${n.action} job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`)}async function wr(e,t,{signal:n}){let r=Date.now();B(`Starting job ${t.id}`);let s=hr(t.prompt);if(s&&Pt(e)){await Sr(e,t,s,r),e.once&&(B("One-shot CursorBuddy control job complete; exiting."),setTimeout(()=>_.exit(0),150));return}let o=kr(e,t),i=await br(e,t),a="",l="",c=0,m=(N="")=>{R(t.ws,{action:"agent_job_delta",jobId:t.id,content:N,elapsedMs:Date.now()-r,model:o.model,permissionMode:o.permissionMode,permissionFlags:o.permissionFlags})};m("");let g=o.streamJson?vr():null,y=setInterval(()=>m(a),1e3);y.unref&&y.unref();let S=await Ye(t).run({cmd:o.cmd,args:[...o.args,i],env:o.env,cwd:t.cwd||e.cwd,timeoutMs:e.timeoutMs,heartbeatMs:e.heartbeatMs,label:"agent job",signal:n,job:t,onData:N=>{g?(g.feed(N),a=g.live):(a+=String(N||""),l=Tr(`${l}
|
|
28
|
+
${N}`));let M=Date.now();M-c>150&&(c=M,m(a))}});clearInterval(y),g&&(g.end(),a=g.live,m(a));let $=String(S.stdout||"").trim(),k=String(S.stderr||"").trim(),b=S.error?S.error.message:S.status===0?"":k||`Command exited with status ${S.status}`,O=g?g.result||(b?"":k):$||(b?"":k)||l||"";R(t.ws,{action:"agent_job_result",jobId:t.id,response:O,error:b,elapsedMs:Date.now()-r,model:o.model,permissionMode:o.permissionMode,permissionFlags:o.permissionFlags}),B(`Finished job ${t.id} in ${Math.round((Date.now()-r)/1e3)}s`),e.once&&(B("One-shot job complete; exiting."),setTimeout(()=>_.exit(0),150))}async function br(e,t){let n=t.agent||{},r=Array.isArray(n.skills)?n.skills.join(", "):String(n.skills||""),s=Array.isArray(n.tools)?n.tools.join(", "):String(n.tools||""),o=Lt(e,t),i=Ut(e,t),a=await Mt(e).catch(()=>null),l=a?`Heartbeat (recurring instructions \u2014 edit at ${Et(e)}):
|
|
29
|
+
${a}`:"",m=["You are running as a local agensis workspace agent daemon.",`Workspace: ${t.workspaceId||e.workspace}`,`Channel session: ${t.sessionId||""}`,`Agent: ${n.name||e.name} (@${n.handle||e.handle})`,`Requested model: ${o}`,`Permission mode: ${i}`,n.description?`Description:
|
|
30
30
|
${n.description}`:"",n.soul?`Soul:
|
|
31
31
|
${n.soul}`:"",n.system_prompt?`System instructions:
|
|
32
32
|
${n.system_prompt}`:"",n.instructions?`Additional instructions:
|
|
33
|
-
${n.instructions}`:"",
|
|
34
|
-
${
|
|
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 ${
|
|
33
|
+
${n.instructions}`:"",s?`Enabled tools:
|
|
34
|
+
${s}`:"",r?`Enabled skills:
|
|
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 ${vt(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.`,l,"User message:",String(t.prompt||""),"Identity boundary: answer as the workspace agent named above. Do not adopt the identity of any browser, desktop, avatar, pet, widget, or UI surface.","Respond with a clear channel-ready result. Use markdown for structure \u2014 bullets, headers, and code blocks where appropriate. If you changed files, summarize the files and verification. If you cannot complete it, say exactly why."].filter(Boolean).join(`
|
|
36
36
|
|
|
37
|
-
`)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`)}import
|
|
42
|
-
`,{mode:384}),await
|
|
43
|
-
`),
|
|
44
|
-
${
|
|
45
|
-
`),
|
|
46
|
-
|
|
37
|
+
`);return e.leanCli?_r(m,nr):m}function _r(e,t){let n=String(e||"");if(Buffer.byteLength(n,"utf8")<=t)return n;let r=`[... older or optional Agensis context omitted ...]
|
|
38
|
+
|
|
39
|
+
`,s=Math.max(0,t-Buffer.byteLength(r,"utf8")),o=[...n],i=0,a=o.length;for(;i<a;){let l=Math.ceil((i+a)/2),c=o.slice(o.length-l).join("");Buffer.byteLength(c,"utf8")<=s?i=l:a=l-1}return r+o.slice(o.length-i).join("")}function kr(e,t){let{cmd:n,args:r}=$r(e.codingCmd),s=Lt(e,t),o=Ut(e,t),i=Nr(r),a=Ue(o),l=Er(e,t);if(Or(n)){let c=[...i];s&&c.push("--model",s);let m;if(e.leanCli){let S=Bt(e);c.push("--no-session-persistence","--safe-mode","--mcp-config",JSON.stringify({mcpServers:{agensis:{type:"http",url:S.url,headers:{Authorization:"Bearer ${AGENSIS_MCP_TOKEN}"}}}}),"--strict-mcp-config"),m=S.env}if(o==="accept_edits"&&c.push("--permission-mode","acceptEdits"),o==="yolo"){let S=t&&t.agent&&t.agent.run_mode==="sandbox",$=typeof _.getuid=="function"&&_.getuid()===0,k=S||Ar(),b=_.env.AGENSIS_ALLOW_ROOT_SKIP_PERMISSIONS==="1";k||!$||b?c.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 g=i.some(S=>S==="--output-format"||String(S).startsWith("--output-format=")),y=i.includes("-p")||i.includes("--print"),w=!1;!g&&y?(c.push("--output-format","stream-json","--include-partial-messages"),i.includes("--verbose")||c.push("--verbose"),w=!0):g&&(w=i.some(S=>/stream-json/.test(String(S))));for(let S of l)c.push("--add-dir",S);return{cmd:n,args:c,model:s,permissionMode:o,permissionFlags:a,streamJson:w,env:m}}if(Br(n)){let c=[...i];s&&c.push("--model",s);let m;if(e.leanCli&&i.includes("exec")){let g=Bt(e);c.push("--ephemeral","--ignore-user-config","--ignore-rules","--disable","plugins","--disable","memories","--disable","hooks","--disable","skill_search","-c","project_doc_max_bytes=0","-c",`mcp_servers.agensis.url=${JSON.stringify(g.url)}`,"-c",'mcp_servers.agensis.bearer_token_env_var="AGENSIS_MCP_TOKEN"'),m=g.env}return o==="yolo"&&c.push("--sandbox","danger-full-access","--ask-for-approval","never"),{cmd:n,args:c,model:s,permissionMode:o,permissionFlags:a,env:m}}return{cmd:n,args:r,model:s,permissionMode:o,permissionFlags:a}}function Bt(e){let t=Pe(e.url);return t.pathname="/backend/mcp",t.search="",t.hash="",{url:t.toString(),env:{AGENSIS_MCP_TOKEN:e.token}}}function vr(){let e="",t="",n=!1,r="",s=null,o=a=>{if(!a||typeof a!="object")return;let l=a.event&&a.event.delta||a.delta;if(l&&l.type==="text_delta"&&typeof l.text=="string"){n=!0,t+=l.text;return}if(a.type==="result"&&typeof a.result=="string"){s=a.result;return}if(a.type==="assistant"&&a.message&&Array.isArray(a.message.content)){let c=a.message.content.filter(m=>m&&m.type==="text"&&typeof m.text=="string").map(m=>m.text).join("");c&&(r+=c)}},i=a=>{let l=String(a).trim();if(l)try{o(JSON.parse(l))}catch{}};return{feed(a){e+=String(a||"");let l;for(;(l=e.indexOf(`
|
|
40
|
+
`))>=0;)i(e.slice(0,l)),e=e.slice(l+1)},end(){e&&(i(e),e="")},get live(){return n?t:r},get result(){return s??(n?t:r)}}}function Lt(e,t){return Le(t?.agent?.model||t?.model||e.model)}function Le(e){let t=String(e||"").trim();return!t||t==="auto"||t==="claude-fable-5"?rr:t}function Ut(e,t){return be(t?.agent?.permissionMode||t?.agent?.permission_mode||t?.permissionMode||t?.permission_mode||e.permissionMode)}function be(e){let t=String(e||"").trim().toLowerCase().replace(/[-\s]+/g,"_");return["yolo","no_sandbox","danger","danger_full_access","dangerously_skip_permissions"].includes(t)?"yolo":["accept_edits","acceptedits","auto_approve","auto_approve_edits"].includes(t)?"accept_edits":"default"}function Ue(e){return be(e)==="yolo"?["--no-sandbox","--yolo"]:[]}function Ft(e){let t=Array.isArray(e)?e:String(e||"").split(/[,\n]/),n=new Set,r=[];for(let s of t){let o=String(s||"").trim();!o||n.has(o)||(n.add(o),r.push(o))}return r}function Er(e,t){let n=t?.agent?.metadata?.host_folders??t?.agent?.hostFolders??t?.hostFolders??t?.host_folders,r=Ft(n);return r.length>0?r:e.hostFolders||[]}var Q;function Ar(){if(Q!==void 0)return Q;let e=_.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 De(e,t,n,r=null,s=null){let o={busy:t.active()>0,queueSize:t.size(),cwd:e.cwd,model:e.model,permissionMode:e.permissionMode,permissionFlags:Ue(e.permissionMode),daemon:{runtime:"agensis-cli",version:oe,pid:_.pid,node:_.version,platform:_.platform,arch:_.arch,host:de.hostname(),cwd:e.cwd}};if(s instanceof Map){let i={};for(let a of s.values()){let l=String(a?.model||"");l&&(i[l]=(i[l]||0)+1)}o.activeInferenceByModel=i}return r&&typeof r=="object"&&(o.cursorBuddy=Ir(r)),n?.status&&(o.agentStatus=n.status),n?.note&&(o.agentNote=n.note),(n?.status||n?.note)&&(o.agentStatusAt=new Date().toISOString()),o}function Ir(e={}){let t=e.client&&typeof e.client=="object"?e.client:{},n=e.page&&typeof e.page=="object"?e.page:{},r=e.runtime&&typeof e.runtime=="object"?e.runtime:{},s=e.manifest&&typeof e.manifest=="object"?e.manifest:{},o=e.project&&typeof e.project=="object"?e.project:{};return{surface:String(e.surface||"").slice(0,80),instanceId:String(e.instanceId||"").slice(0,140),url:String(e.url||"").slice(0,2048),title:String(e.title||"").slice(0,300),origin:String(n.origin||"").slice(0,300),hostname:String(n.hostname||"").slice(0,200),pathname:String(n.pathname||"").slice(0,500),visibilityState:String(n.visibilityState||"").slice(0,40),focused:n.focused===!0,userAgent:String(t.userAgent||"").slice(0,500),platform:String(t.platform||"").slice(0,120),language:String(t.language||"").slice(0,80),viewport:t.viewport&&typeof t.viewport=="object"?{width:Number(t.viewport.width)||0,height:Number(t.viewport.height)||0,devicePixelRatio:Number(t.viewport.devicePixelRatio)||0}:null,runtimeMarker:String(r.marker||"").slice(0,120),extensionMarker:String(r.extensionMarker||"").slice(0,120),manifest:{name:String(s.name||"").slice(0,120),version:String(s.version||"").slice(0,80),source:String(s.source||"").slice(0,500)},project:{name:String(o.name||"").slice(0,120),root:String(o.root||"").slice(0,500),agent:String(o.agent||"").slice(0,80)},updatedAt:String(e.updatedAt||"").slice(0,80)}}function $t(e,t){if(!t||typeof t!="object")return;t.name&&(e.name=String(t.name).trim()||e.name),(t.handle||t.name)&&(e.handle=Gt(t.handle||t.name||e.handle)),t.model&&(e.model=Le(t.model));let n=t.permissionMode||t.permission_mode;n&&(e.permissionMode=be(n)),(t.memory_dir!==void 0||t.memoryDir!==void 0)&&(e.memoryDir=String(t.memory_dir??t.memoryDir??"").trim())}function Cr(){let e=["claude","codex","gh","node","npm","python3","git","fly","vercel"],t=(_.env.PATH||"").split(le.delimiter).filter(Boolean);return e.filter(n=>t.some(r=>{try{return ue.existsSync(le.join(r,n))}catch{return!1}}))}function xr(){try{let e=ue.readFileSync(le.join(de.homedir(),".claude.json"),"utf8"),n=JSON.parse(e)?.mcpServers;if(n&&typeof n=="object")return Object.keys(n).sort()}catch{}return[]}function Tt(e){return Zn.createHash("sha1").update(String(e)).digest("hex").slice(0,16)}async function jt(e,t=null){let n=ft({cwd:e.cwd}),r=mt({cwd:e.cwd}),s=Cr(),o=xr(),i=e.syncMemory&&Ce({cwd:e.cwd,memoryDir:e.memoryDir})||null,a=gt(e.sharedModels),l=Tt(JSON.stringify({skills:n,commands:r,clis:s,mcpServers:o,memoryRoot:i,sharedModels:a,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null})),c=Tt(await ct(i));return{skills:n,commands:r,clis:s,mcpServers:o,memoryRoot:i,sharedModels:a,codingRoute:!!e.codingCmd,shared:e.share,reach:t||null,capabilitiesHash:l,memoryHash:c}}async function ae(e,t,n=null){try{let r=await jt(t,n);R(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 Mr(e){let t=de.networkInterfaces(),n=[];for(let r of Object.values(t))for(let s of r||[])s.family==="IPv4"&&!s.internal&&n.push({host:s.address,port:e,scope:"lan"});return n.slice(0,4)}async function Dt(e,t){try{if(!t.syncMemory)return;let n=Ce({cwd:t.cwd,memoryDir:t.memoryDir});if(!n)return;let r=await ut(n);R(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 Nr(e){let t=new Set(["--model","-m","--permission-mode","--sandbox","--ask-for-approval","--approval-policy"]),n=new Set(["--dangerously-skip-permissions","--no-sandbox","--yolo","--accept-edits"]),r=[];for(let s=0;s<e.length;s+=1){let o=e[s],[i]=String(o).split("=",1);if(!n.has(o)){if(t.has(i)){String(o).includes("=")||(s+=1);continue}r.push(o)}}return r}function Or(e){return/(^|\/)claude(?:$|\.)/.test(String(e||""))}function Br(e){return/(^|\/)codex(?:$|\.)/.test(String(e||""))}function $r(e){let t=[],n="",r="",s=!1;for(let o of e){if(s){n+=o,s=!1;continue}if(o==="\\"){s=!0;continue}if(r){o===r?r="":n+=o;continue}if(o==='"'||o==="'"){r=o;continue}if(/\s/.test(o)){n&&(t.push(n),n="");continue}n+=o}if(n&&t.push(n),!t.length)throw new Error("coding command is empty");return{cmd:t[0],args:t.slice(1)}}function Re(e){try{return JSON.parse(String(e))}catch{return null}}function R(e,t){return!e||e.readyState!==ce.OPEN?!1:(e.send(JSON.stringify(t)),!0)}function Tr(e){return String(e||"").split(/\r?\n/).map(t=>t.trim()).filter(Boolean).slice(-1)[0]||""}function Gt(e){return String(e||"").trim().toLowerCase().replace(/^@+/,"").replace(/[^a-z0-9_.-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)}function Dr(e){return e?.code==="EADDRINUSE"||/\bEADDRINUSE\b/.test(String(e?.message||e))}async function Rr(e){let t=new AbortController,n=setTimeout(()=>t.abort(),700);try{let r=await fetch(`http://127.0.0.1:${Number(e||8787)}/cursorbuddy/health`,{cache:"no-store",signal:t.signal}),s=await r.json().catch(()=>({}));return!r.ok||!s?.ok?null:s}catch{return null}finally{clearTimeout(n)}}function B(e){_.stderr.write(`[agensis] ${e}
|
|
41
|
+
`)}function Rt(e){if(e instanceof Map)for(let t of e.values())try{t?.abort?.()}catch{}}import Pr from"node:crypto";import me from"node:fs/promises";import Lr from"node:os";import Ht from"node:path";var Z="default",Jt=2,Ur=/^[a-zA-Z0-9_.-]{1,64}$/,Fr=["url","token","workspace","agent","handle","name","cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","leanCli","fullCliContext","syncMemory","lanListener","primaryDaemon","cursorBuddyBridge","cursorBuddyPort","hostFolders"];function z(e=Z){let t=String(e||Z).trim();if(!Ur.test(t))throw new Error("Daemon profile names may only contain letters, numbers, dot, dash, and underscore.");return t}function Kt(e=Z,t={}){let n=t.homedir||Lr.homedir();return Ht.join(n,".agensis","daemon-profiles",`${z(e)}.json`)}function Fe(e={}){let t={};for(let n of Fr){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 Wt(e={}){return!!(V(e,["url","baseUrl"],["AGENSIS_URL"])||V(e,["token"],["AGENSIS_TOKEN"])||V(e,["workspace","workspaceId"],["AGENSIS_WORKSPACE","AGENSIS_WORKSPACE_ID"])||V(e,["agent","agentId"],["AGENSIS_AGENT","AGENSIS_AGENT_ID"]))}function je(e={}){return!!(V(e,["url","baseUrl"],["AGENSIS_URL"])&&V(e,["token"],["AGENSIS_TOKEN"])&&V(e,["workspace","workspaceId"],["AGENSIS_WORKSPACE","AGENSIS_WORKSPACE_ID"])&&V(e,["agent","agentId"],["AGENSIS_AGENT","AGENSIS_AGENT_ID"]))}async function zt(e=Z,t={}){let n=Kt(e,t),r;try{r=await me.readFile(n,"utf8")}catch(a){if(a?.code==="ENOENT")return null;throw a}let s;try{s=JSON.parse(r)}catch(a){throw new Error(`Daemon profile "${z(e)}" is unreadable: ${a?.message||a}`)}let o=s?.config;if(!o?.url||!o?.token||!o?.workspace||!o?.agent)return null;let i=Fe(o);return Number(s.version||1)<Jt&&Number(i.maxConcurrency)===8&&(i.maxConcurrency=2),i}async function _e(e=Z,t={},n={}){let r=Fe(t);if(!r.url||!r.token||!r.workspace||!r.agent)return null;let s=Kt(e,n),o=Ht.dirname(s);await me.mkdir(o,{recursive:!0,mode:448});let i=`${s}.${process.pid}.${Date.now()}.tmp`,a={version:Jt,savedAt:new Date().toISOString(),profile:z(e),tokenHash:Pr.createHash("sha256").update(r.token).digest("hex"),config:r};return await me.writeFile(i,`${JSON.stringify(a,null,2)}
|
|
42
|
+
`,{mode:384}),await me.rename(i,s),await me.chmod(s,384).catch(()=>{}),s}function Yt(e,t={}){let n={...e,...Fe(t),command:"connect"};return t.fullCliContext===!0&&(n.leanCli=!1),t.codingCmd!==void 0&&t.noCoding===void 0&&(n.noCoding=!1),t.cursorBuddyBridge===void 0&&!n.primaryDaemon&&(n.cursorBuddyBridge=!1),t.once!==void 0&&(n.once=t.once),t.exitOnOnce!==void 0&&(n.exitOnOnce=t.exitOnOnce),n}function qt(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(`
|
|
43
|
+
`)}import jr from"node:crypto";import fe from"node:fs/promises";import Xt from"node:os";import Ge from"node:path";import He from"node:process";var Gr=/^cbk_[a-z0-9_]+_[A-Z2-9]{18}$/;function Hr(e={}){return String(e.url||e.baseUrl||He.env.AGENSIS_URL||"https://agensis.io").trim().replace(/\/+$/,"")}function Vt(e,t={}){let n=t.homedir||Xt.homedir(),r=jr.createHash("sha256").update(String(e)).digest("hex");return Ge.join(n,".agensis","cursorbuddy","connection-keys",`${r}.json`)}function Jr(){return new Error("Missing or invalid --key. Create a CursorBuddy connection key in Agensis first.")}function Je(e){let t=String(e||"").trim();if(!Gr.test(t))throw Jr();return t}function Kr(e,t,n,r){let s=t?.token,o=t?.workspaceId||t?.workspace_id||t?.agent?.workspace_id,i=t?.agentId||t?.agent?.id;if(!s||!o||!i)throw new Error("CursorBuddy key claim did not return a complete daemon connection payload");let{key:a,subcommand:l,...c}=e;return{...c,command:"connect",url:t.baseUrl||n,token:s,workspace:o,agent:i,handle:t.handle||e.handle,name:t.agent?.name||e.name||"CursorBuddy runtime",model:t.model||e.model,permissionMode:t.permissionMode||t.permission_mode||e.permissionMode,cwd:e.cwd||r,cursorBuddyRuntime:!0}}async function Wr(e,t={}){Je(e);let n=Vt(e,t),r;try{r=await fe.readFile(n,"utf8")}catch(i){if(i?.code==="ENOENT")return null;throw i}let s;try{s=JSON.parse(r)}catch(i){throw new Error(`Cached CursorBuddy daemon config is unreadable: ${i?.message||i}`)}let o=s?.daemonArgs;return!o?.token||!o?.workspace||!o?.agent||!o?.url?null:o}async function zr(e,t,n={}){if(Je(e),!t?.token||!t?.workspace||!t?.agent||!t?.url)return;let r=Vt(e,n),s=Ge.dirname(r);await fe.mkdir(s,{recursive:!0,mode:448});let o=`${r}.${He.pid}.${Date.now()}.tmp`,i={version:1,savedAt:new Date().toISOString(),keyHash:Ge.basename(r,".json"),daemonArgs:t};await fe.writeFile(o,`${JSON.stringify(i,null,2)}
|
|
44
|
+
`,{mode:384}),await fe.rename(o,r),await fe.chmod(r,384).catch(()=>{})}function Yr(e,t,n){let r={...e,command:"connect"};for(let s of["cwd","codingCmd","model","permissionMode","timeoutMs","heartbeatMs","maxConcurrency","share","sharedModelsFile","noCoding","leanCli","lanListener","once"])t[s]!==void 0&&(r[s]=t[s]);return t.codingCmd!==void 0&&t.noCoding===void 0&&(r.noCoding=!1),r.cwd||(r.cwd=n),r.cursorBuddyRuntime=!0,r}function qr(e,t){return t?.error?.message||t?.message||`CursorBuddy key claim failed with HTTP ${e.status}`}async function Xr(e){return e.json().catch(()=>({}))}async function Qt(e,t={}){let n=Je(e?.key),r=Hr(e),s=t.fetchImpl||globalThis.fetch;if(typeof s!="function")throw new Error("This Node.js runtime does not provide fetch; use a current Node.js release.");let o=t.cwd||He.cwd(),i=t.hostname||Xt.hostname(),a=t.version||oe,l={homedir:t.homedir},c=await s(`${r}/backend/cursorbuddy/connection-keys/claim`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({key:n,baseUrl:r,host:i,cwd:e.cwd||o,name:e.name,surface:e.surface||"local_cli",scope:e.scope||"machine",runtimeKind:"agensis-cli",version:a,permissionMode:e.permissionMode,model:e.model})}),m=await Xr(c);if(!c.ok){let y=qr(c,m);if(c.status===409||/already been claimed/i.test(y)){let w=await Wr(n,l);if(w)return Yr(w,e,o);throw new Error(`${y}. 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(y)}let g=Kr(e,m?.data||m,r,o);return await zr(n,g,l),g}import Vr from"node:crypto";import Qr from"node:http";import Zr from"node:os";import Y from"node:process";import{spawn as eo}from"node:child_process";var to="https://agensis.io",no=10*60*1e3;function ke(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 ro(e){return new Promise((t,n)=>{let r="";e.on("data",s=>{r+=s,r.length>128*1024&&(n(new Error("setup callback body is too large")),e.destroy())}),e.on("error",n),e.on("end",()=>t(r))})}function oo(e){let t=String(e||Y.env.AGENSIS_URL||to).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 so(e){let t=Y.platform==="darwin"?"open":Y.platform==="win32"?"cmd":"xdg-open",n=Y.platform==="win32"?["/c","start","",e]:[e],r=eo(t,n,{detached:!0,stdio:"ignore"});r.on("error",()=>{}),r.unref()}function io(e){let t=e?.daemonArgs||e?.data?.daemonArgs||e?.data||{},r=["url","token","workspace","agent"].filter(s=>!String(t[s]||"").trim());if(r.length)throw new Error(`Setup callback did not include ${r.join(", ")}`);return{...t,command:"connect"}}function ao(e,t,n){let r=new URL(oo(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",Zr.hostname()),r.searchParams.set("cwd",String(e.cwd||Y.cwd())),e.handle&&r.searchParams.set("handle",String(e.handle)),e.name&&r.searchParams.set("name",String(e.name)),r.toString()}async function Zt(e={}){let t=z(e.profile||"default"),n=Vr.randomBytes(24).toString("base64url"),r=Number(e.setupTimeoutMs||Y.env.AGENSIS_SETUP_TIMEOUT_MS||no),s,o=new Promise((c,m)=>{let g=setTimeout(()=>m(new Error("Agensis setup timed out waiting for browser login.")),r);g.unref&&g.unref(),s=Qr.createServer(async(y,w)=>{if(w.setHeader("access-control-allow-origin","*"),w.setHeader("access-control-allow-methods","POST, OPTIONS"),w.setHeader("access-control-allow-headers","content-type"),y.method==="OPTIONS"){w.writeHead(204),w.end();return}if(y.method!=="POST"||y.url!=="/agensis/setup-callback"){ke(w,404,{ok:!1,error:"Unknown Agensis setup callback route"});return}try{let S=JSON.parse(await ro(y)||"{}");if(S?.state!==n){ke(w,403,{ok:!1,error:"Setup state did not match"});return}let $={...io(S),primaryDaemon:!0,cursorBuddyBridge:e.cursorBuddyBridge!==!1};await _e(t,$),clearTimeout(g),ke(w,200,{ok:!0,profile:t}),c($)}catch(S){ke(w,400,{ok:!1,error:String(S?.message||S)})}}),s.once("error",m)});await new Promise((c,m)=>{s.listen(0,"127.0.0.1",g=>g?m(g):c())});let{port:i}=s.address(),a=`http://127.0.0.1:${i}/agensis/setup-callback`,l=ao(e,a,n);Y.stdout.write(`[agensis] Opening Agensis to sign in and connect this machine.
|
|
45
|
+
`),Y.stdout.write(`[agensis] If the browser did not open, visit:
|
|
46
|
+
${l}
|
|
47
|
+
`),so(l);try{let c=await o;return Y.stdout.write(`[agensis] Saved daemon profile "${t}". Starting primary agent daemon.
|
|
48
|
+
`),c}finally{await new Promise(c=>s.close(()=>c())).catch(()=>{})}}function co(e){let t={command:"connect"},n=[...e],r=n[0];if(r&&!r.startsWith("-")&&(t.command=n.shift(),t.command==="buddy")){let s=n[0];s&&!s.startsWith("-")?t.subcommand=n.shift():t.subcommand="connect"}for(let s=0;s<n.length;s+=1){let o=n[s];if(!o.startsWith("--"))throw new Error(`Unexpected argument: ${o}`);let[i,a]=o.slice(2).split(/=(.*)/s,2),l=i.replace(/-([a-z])/g,(m,g)=>g.toUpperCase());if(l==="help"){t.help=!0;continue}if(l==="version"){t.version=!0;continue}if(l==="once"){t.once=!0;continue}if(l==="lan"){t.lanListener=!0;continue}if(l==="share"){t.share=!0;continue}if(l==="noCoding"){t.noCoding=!0;continue}if(l==="fullCliContext"){t.fullCliContext=!0;continue}if(l==="syncMemory"){t.syncMemory=!0;continue}if(l==="cursorbuddyBridge"){t.cursorBuddyBridge=!0;continue}if(l==="noCursorbuddyBridge"){t.cursorBuddyBridge=!1;continue}if(l==="yolo"||l==="noSandbox"){t.permissionMode="yolo";continue}if(l==="acceptEdits"){t.permissionMode="accept_edits";continue}if(l==="hostFolder"||l==="hostFolders"||l==="addDir"){let m=a!==void 0?a:n[++s];if(m==null||m.startsWith("--"))throw new Error(`Missing value for --${i}`);t.hostFolders=[...t.hostFolders||[],m];continue}let c=a!==void 0?a:n[++s];if(c==null||c.startsWith("--"))throw new Error(`Missing value for --${i}`);t[l]=c}return t}function uo(){return`agensis agent daemon
|
|
47
49
|
|
|
48
50
|
Usage:
|
|
49
51
|
agensis --url <workspace-url> --token <token> --workspace <id> --agent <id> [options]
|
|
@@ -66,12 +68,17 @@ Options:
|
|
|
66
68
|
--host-folder <path> Extra folder the coding CLI may read/write (repeatable; passed as --add-dir)
|
|
67
69
|
--coding-cmd <command> Command used for jobs, default: claude -p
|
|
68
70
|
--no-coding Disable coding jobs; keep presence/shared inference only
|
|
71
|
+
--full-cli-context Load all user CLI skills, plugins, hooks, memory, and MCPs
|
|
72
|
+
(default isolates Claude/Codex to project + Agensis context)
|
|
73
|
+
--sync-memory Opt in to mirroring this project's Claude memory files
|
|
74
|
+
to the connected Agensis workspace (default: off)
|
|
69
75
|
--model <id> Default model to pass to supported coding CLIs
|
|
70
76
|
--permission-mode <m> default, accept_edits, or yolo
|
|
71
77
|
--yolo Alias for --permission-mode yolo
|
|
72
78
|
--no-sandbox Alias for --permission-mode yolo
|
|
73
79
|
--timeout-ms <ms> Kill a job after this time, default: 1800000
|
|
74
80
|
--heartbeat-ms <ms> Local terminal heartbeat interval, default: 15000
|
|
81
|
+
--max-concurrency <n> Maximum simultaneous coding CLI jobs, default: 2
|
|
75
82
|
--cursorbuddy-port <n> Local CursorBuddy discovery/chat port, default: 8787
|
|
76
83
|
--cursorbuddy-bridge Enable local CursorBuddy discovery/chat bridge
|
|
77
84
|
--no-cursorbuddy-bridge Disable local CursorBuddy discovery/chat bridge
|
|
@@ -84,7 +91,7 @@ Options:
|
|
|
84
91
|
--profile <name> Save/reuse a local daemon profile, default: default
|
|
85
92
|
--version Print the CLI version
|
|
86
93
|
--help Show this help
|
|
87
|
-
`}async function
|
|
88
|
-
`)}}:e}async function
|
|
89
|
-
`);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
|
|
90
|
-
`),
|
|
94
|
+
`}async function lo(e){let t=e.profile!==void 0,n=e.handle||e.name,r=z(e.profile||(je(e)&&n?n:"default"));if(!Wt(e)){let s=await zt(r);if(!s)throw new Error(qt(r));return Yt(s,e)}return je(e)?{...e,cursorBuddyBridge:e.cursorBuddyBridge===!0,onRegistered:async s=>{await _e(r,s);let o=t||r!=="default"?`agensis connect --profile ${r}`:"agensis connect";q.stdout.write(`[agensis] Saved daemon profile "${r}". Restart with: ${o}
|
|
95
|
+
`)}}:e}async function mo(){let e=co(q.argv.slice(2));if(e.help){q.stdout.write(uo());return}if(e.version){q.stdout.write(`${oe}
|
|
96
|
+
`);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 we(n),n.once&&q.exit(0);return}if(e.command==="setup"){let n=await Zt(e);n.exitOnOnce=!0,await we({...e,...n}),n.once&&q.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 lo(e);t.exitOnOnce=!0,await we(t),t.once&&q.exit(0)}mo().catch(e=>{q.stderr.write(`${e?.message||e}
|
|
97
|
+
`),q.exitCode=1});
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agensis/agensis-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
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": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/jasonkneen/agensis.git",
|
|
9
|
-
"directory": "
|
|
8
|
+
"url": "git+https://github.com/jasonkneen/agensis-agent.git",
|
|
9
|
+
"directory": "packages/agensis-agent"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/jasonkneen/agensis/issues"
|
|
12
|
+
"url": "https://github.com/jasonkneen/agensis-agent/issues"
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
15
|
"bin": {
|