@nodus-ai/equile 0.0.1-preview

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.
@@ -0,0 +1,59 @@
1
+ import {spawn,execFile}from'child_process';import {createReadStream,realpathSync,writeFileSync}from'fs';import {platform,homedir,hostname,tmpdir}from'os';import u from'path';import {readFile,mkdir,writeFile,chmod,readdir,stat}from'fs/promises';var F=[".ssh",".aws",".gnupg",".config/gcloud",".kube",".docker/config.json",".netrc",".npmrc",".pypirc",".git-credentials","Library/Keychains",".config/gh/hosts.yml",".config/nodus",".nodus/desktop.json"],le=/(\/\.ssh\b|\bid_rsa\b|\bid_ed25519\b|\/\.aws\b|\/\.gnupg\b|\.config\/gcloud|\/\.kube\b|\.docker\/config\.json|\.git-credentials|\/\.netrc\b|\bsecurity\s+(find|dump)-(generic|internet)-password|\baws\s+configure\s+get|\bgcloud\s+auth\s+print|\bgh\s+auth\s+token|\bgit\s+credential\s+fill)/i;function H(e){let r=homedir(),s=(e===r?"":e.startsWith(r+u.sep)?e.slice(r.length+1):e).replace(/\\/g,"/").toLowerCase();return F.some(o=>{let n=o.toLowerCase();return s===n||s.startsWith(n+"/")})}function G(e){if(process.env.NODUS_DESKTOP_ALLOW_SECRETS==="1")return false;if(H(e))return true;let r=e;for(let t=0;t<40&&r&&r!==u.dirname(r);t++)try{return H(realpathSync(r))}catch{r=u.dirname(r);}return false}function K(e){if(process.env.NODUS_DESKTOP_ALLOW_SECRETS!=="1"&&le.test(e))throw new Error("Command references a credential path and was blocked by the desktop agent.")}var ue=process.env.NODUS_DESKTOP_CONFINE==="1"&&platform()==="darwin",de=[".ssh",".aws",".gnupg",".config/gcloud",".kube",".config/gh",".git-credentials","Library/Keychains",".nodus/desktop.json"],$=null;function pe(){if($)return $;let e=homedir(),t=`(version 1)
2
+ (allow default)
3
+ (deny file-read* file-read-metadata file-write* file-write-unlink
4
+ ${de.map(o=>` (subpath ${JSON.stringify(u.join(e,o))})`).join(`
5
+ `)})
6
+ `,s=u.join(tmpdir(),`nodus-confine-${process.pid}.sb`);return writeFileSync(s,t,{mode:384}),$=s,s}function U(e,r){return ue?{file:"/usr/bin/sandbox-exec",args:["-f",pe(),e,"-lc",r]}:{file:e,args:["-lc",r]}}var fe=platform()==="darwin"&&process.env.NODUS_DESKTOP_NO_SANDBOX!=="1",he=[".npm",".cache",".bun","Library/Caches"],P=null;function ge(){if(P)return P;let e=F.map(s=>` (subpath (string-append (param "HOME") ${JSON.stringify("/"+s)}))`).join(`
7
+ `),r=he.map(s=>` (subpath (string-append (param "HOME") ${JSON.stringify("/"+s)}))`).join(`
8
+ `);return P=`(version 1)
9
+ (allow default)
10
+ ${process.env.NODUS_DESKTOP_ALLOW_SECRETS==="1"?"":`(deny file-read* file-read-metadata
11
+ ${e})
12
+ `}(deny file-write* file-write-unlink
13
+ (require-not (require-any
14
+ (subpath (param "CWD"))
15
+ (subpath "/tmp")
16
+ (subpath "/private/tmp")
17
+ (subpath "/private/var/folders")
18
+ (subpath "/dev")
19
+ ${r})))
20
+ `,P}function q(e,r,t){if(!fe)return U(e,r);let s=t;try{s=realpathSync(t);}catch{}return {file:"/usr/bin/sandbox-exec",args:["-p",ge(),"-D",`CWD=${s}`,"-D",`HOME=${homedir()}`,e,"-lc",r]}}function O(e){let r=String(e||"");if(!r||r.includes("/")||r.includes("\\")||r.includes("..")||r.startsWith("."))throw new Error("Invalid catalog name.");return r}var re=u.join(homedir(),".nodus"),j=u.join(re,"desktop.json"),B=e=>new Promise(r=>setTimeout(r,e)),w=(...e)=>console.log(new Date().toISOString().slice(11,19),...e);async function ve(e,r){let t=await x(e,"/desktop-devices/pair/start",{name:r,platform:platform()}),s=process.env.NODUS_CONSOLE_URL??"https://ondus-web.yuanbopang.workers.dev";console.log(""),console.log(" Pair this Mac with Nodus \u2014 approve it in the console:"),console.log(` code: ${t.userCode}`),console.log(` open: ${s}/#/desktops?code=${t.userCode}`),console.log("");let o=Date.now()+(t.expiresIn??600)*1e3;for(;Date.now()<o;){let n=await x(e,"/desktop-devices/pair/poll",{deviceCode:t.deviceCode});if(n.status==="complete")return {credential:n.credential,deviceId:n.deviceId,runtimeId:n.runtimeId};await B(3e3);}throw new Error("Pairing timed out \u2014 run connect again.")}async function x(e,r,t,s){let o=await fetch(`${e}${r}`,{method:"POST",headers:{"content-type":"application/json",...s?{authorization:`Bearer ${s}`}:{}},body:JSON.stringify(t)}),n=await o.json().catch(()=>({}));if(!o.ok)throw new Error(n.error||`${r} \u2192 ${o.status}`);return n}async function ke(){try{return JSON.parse(await readFile(j,"utf8"))}catch{return null}}async function V(e){await mkdir(re,{recursive:true}),await writeFile(j,JSON.stringify(e,null,2)),await chmod(j,384);}function b(e,r){let t=String(r||"."),s=t==="~"?homedir():t.startsWith("~/")?u.join(homedir(),t.slice(2)):t,o=u.isAbsolute(s)?u.resolve(s):u.resolve(e,s),n=homedir();if(o!==n&&!o.startsWith(n+u.sep)&&!o.startsWith("/tmp/"))throw new Error(`Path escapes the home directory: ${t}`);if(G(o))throw new Error(`Access to a credential path is blocked: ${t}`);return o}function Ee(e,r,t=120){let{file:s,args:o}=q("/bin/bash",e,r);return new Promise(n=>{execFile(s,o,{cwd:r,timeout:Math.min(Math.max(t,1),600)*1e3,maxBuffer:8*1024*1024,env:{...process.env,NODUS_DESKTOP:"1"}},(i,c,d)=>{n({exitCode:i?typeof i.code=="number"?i.code:1:0,stdout:String(c).slice(0,1024*1024),stderr:String(d).slice(0,256*1024)});});})}async function xe(e,r=false){let s=(await readdir(e,{withFileTypes:true})).filter(o=>(!r||o.isDirectory())&&!o.name.startsWith("."));return {path:e,entries:await Promise.all(s.map(async o=>{let n=await stat(u.join(e,o.name)).catch(()=>null);return {name:o.name,type:o.isDirectory()?"dir":"file",sizeBytes:n?.size??0}}))}}var ne=[u.join(homedir(),".claude","skills"),u.join(homedir(),".codex","skills")],L=u.join(homedir(),".claude","plugins","cache");async function se(){let e=[];for(let r of ne){let t=await readdir(r).catch(()=>[]);for(let s of t){let o=await readFile(u.join(r,s,"SKILL.md"),"utf8").catch(()=>null);if(!o)continue;let n=/description:\s*(.+)/.exec(o)?.[1]?.slice(0,200)??"";e.push({name:s,description:n,root:r});}}return {skills:e}}async function X(e){for(let r of ne){let t=u.join(r,e);if(await stat(u.join(t,"SKILL.md")).then(()=>true).catch(()=>false))return t}throw new Error(`Skill not found: ${e}`)}var Ce=[process.env.CHROME_BIN??"","/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium",`${homedir()}/Library/Caches/ms-playwright/chromium_headless_shell-1228/chrome-headless-shell-mac-arm64/chrome-headless-shell`,`${homedir()}/Library/Caches/ms-playwright/chromium_headless_shell-1217/chrome-headless-shell-mac-arm64/chrome-headless-shell`].filter(Boolean),g={session:null,starting:null},Y=9223;async function Oe(){for(let e of Ce)if(await stat(e).then(()=>true).catch(()=>false))return e;throw new Error("No Chrome/Chromium found on this machine (set CHROME_BIN).")}async function _e(){let e=await Oe(),{spawn:r}=await import('child_process'),t=r(e,["--headless=new",`--remote-debugging-port=${Y}`,"--user-data-dir=/tmp/nodus-desktop-browser","--no-first-run","--window-size=1400,1000","about:blank"],{stdio:"ignore"}),s=null;for(let l=0;l<40;l++)try{s=await(await fetch(`http://127.0.0.1:${Y}/json/list`)).json();break}catch{await B(250);}let o=s?.find(l=>l.type==="page");if(!o){try{t.kill();}catch{}throw new Error("Local browser did not expose CDP.")}let n=new WebSocket(o.webSocketDebuggerUrl);await new Promise((l,a)=>{n.onopen=l,n.onerror=a;});let i=0,c=new Map;n.onmessage=l=>{let a=JSON.parse(String(l.data));if(a.id&&c.has(a.id)){let S=c.get(a.id);c.delete(a.id),a.error?S.reject(new Error(a.error.message)):S.resolve(a.result);}};let d=l=>{for(let[,a]of c)try{a.reject(new Error(l));}catch{}c.clear();};n.onclose=()=>{g.session=null,d("browser CDP socket closed");try{t.kill();}catch{}},n.onerror=()=>{g.session=null,d("browser CDP socket error");try{t.kill();}catch{}};let f={send:(l,a={})=>new Promise((S,v)=>{let y=++i;c.set(y,{resolve:S,reject:v}),n.send(JSON.stringify({id:y,method:l,params:a}));}),kill:()=>{try{n.close();}catch{}try{t.kill();}catch{}}};return await f.send("Page.enable"),f}var Z=false;function Pe(){if(Z)return;Z=true;let e=()=>{try{g.session?.kill();}catch{}g.session=null;};process.once("exit",e),process.once("SIGINT",()=>{e(),process.exit(130);}),process.once("SIGTERM",()=>{e(),process.exit(143);});}async function Ne(){return Pe(),g.session?g.session:(g.starting||(g.starting=_e().then(e=>(g.session=e,g.starting=null,e),e=>{throw g.starting=null,e})),g.starting)}var De=[{name:"open",description:"Open a URL in the local browser (CDP). Waits for load.",inputSchema:{type:"object",properties:{url:{type:"string"}},required:["url"]}},{name:"screenshot",description:"Screenshot the current page of the local browser (PNG).",inputSchema:{type:"object",properties:{}}},{name:"eval",description:"Evaluate JavaScript in the local browser page; returns the JSON result.",inputSchema:{type:"object",properties:{expression:{type:"string"}},required:["expression"]}},{name:"text",description:"Get the visible text of the current page in the local browser.",inputSchema:{type:"object",properties:{}}}];async function $e(e,r){let t=await Ne();if(e==="open"){await t.send("Page.navigate",{url:String(r.url)}),await B(2500);let s=await t.send("Runtime.evaluate",{expression:"document.title",returnByValue:true});return {content:[{type:"text",text:`Opened ${r.url} \u2014 title: ${s?.result?.value??""}`}]}}if(e==="screenshot"){let s=await t.send("Page.captureScreenshot",{format:"png"}),o=String(s?.data??"");if(o.length>8*1024*1024)throw new Error("Screenshot exceeds the 8 MB limit.");return {content:[{type:"image",data:o,mimeType:"image/png"}]}}if(e==="eval"){let s=`(async()=>{try{const v=await (${String(r.expression)});return JSON.stringify(v===undefined?null:v).slice(0,100000);}catch(e){return "__NODUS_EVAL_ERROR__"+String(e&&e.message||e)}})()`,o=await t.send("Runtime.evaluate",{expression:s,awaitPromise:true,returnByValue:true});if(o.exceptionDetails)throw new Error(String(o.exceptionDetails.exception?.description??"evaluation failed").slice(0,500));let n=String(o.result?.value??"null");if(n.startsWith("__NODUS_EVAL_ERROR__"))throw new Error(n.slice(20,500));return {content:[{type:"text",text:n}]}}if(e==="text"){let s=await t.send("Runtime.evaluate",{expression:"document.body ? document.body.innerText.slice(0, 60000) : ''",returnByValue:true});return {content:[{type:"text",text:String(s.result?.value??"")}]}}throw new Error(`Unknown browser tool: ${e}`)}async function oe(){return {servers:[{server:"browser",tools:De,resources:[],prompts:[]}]}}async function Ie(e){let r=String(e.server??"");if(r==="browser"&&e.method==="tools/call")return $e(String(e.name),e.arguments??{});throw new Error(`Unknown local MCP server: ${r}`)}var Ue=`
21
+ import os,pty,sys,fcntl,termios,struct,select,signal,json
22
+ argv=json.loads(sys.argv[1]);cols=int(sys.argv[2]);rows=int(sys.argv[3])
23
+ pid,fd=pty.fork()
24
+ if pid==0:
25
+ os.environ['TERM']='xterm-256color'
26
+ os.execvp(argv[0],argv)
27
+ def setsize(c,r):
28
+ try:
29
+ fcntl.ioctl(fd,termios.TIOCSWINSZ,struct.pack('HHHH',r,c,0,0))
30
+ os.kill(pid,signal.SIGWINCH)
31
+ except Exception:pass
32
+ setsize(cols,rows)
33
+ ctl=3;buf=b''
34
+ try:
35
+ while True:
36
+ rl,_,_=select.select([0,ctl,fd],[],[])
37
+ if fd in rl:
38
+ try:data=os.read(fd,65536)
39
+ except OSError:break
40
+ if not data:break
41
+ os.write(1,data)
42
+ if 0 in rl:
43
+ data=os.read(0,65536)
44
+ if not data:break
45
+ os.write(fd,data)
46
+ if ctl in rl:
47
+ chunk=os.read(ctl,4096)
48
+ if not chunk:continue
49
+ buf+=chunk
50
+ while b'\\n' in buf:
51
+ line,buf=buf.split(b'\\n',1)
52
+ try:
53
+ m=json.loads(line);setsize(int(m['columns']),int(m['rows']))
54
+ except Exception:pass
55
+ finally:
56
+ try:os.kill(pid,signal.SIGHUP)
57
+ except Exception:pass
58
+ `,N=new Map,Q=8;function Le(e,r){let t=String(r?.ptyId??"");if(!t||N.has(t))return;if(N.size>=Q){w(`pty ${t.slice(0,8)} refused \u2014 ${Q} already active`);return}let s=r?.cwd?b(e.folder,String(r.cwd)):e.folder,o=Math.max(2,Math.min(500,Number(r?.cols??80)||80)),n=Math.max(2,Math.min(300,Number(r?.rows??24)||24)),i=process.env.SHELL||"/bin/zsh",c=U(i,":"),d=JSON.stringify(c.file===i?[i,"-il"]:[c.file,...c.args.slice(0,-1),i,"-il"]),f=spawn("/usr/bin/python3",["-c",Ue,d,String(o),String(n)],{cwd:s,stdio:["pipe","pipe","ignore","pipe"]}),l=new URL(e.baseUrl);l.protocol=l.protocol==="https:"?"wss:":"ws:",l.pathname=`/desktop-devices/agent/pty/${t}`;let a,S=0,v=false,y=()=>{v=true,N.delete(t);try{a?.close();}catch{}try{f.kill("SIGHUP");}catch{}},T=()=>{if(v||S++>40){v||y();return}a=new WebSocket(l.toString(),{headers:{authorization:`Bearer ${e.credential}`}}),a.binaryType="arraybuffer";let k=false,p=ie;a.onmessage=h=>{k=true,p(h);},a.onclose=h=>{if(!v&&!k&&h?.code!==1e3){setTimeout(T,300);return}y();},a.onerror=()=>{};},ie=async k=>{let p,h=k.data;if(typeof h=="string"||h instanceof ArrayBuffer?p=Buffer.from(h):h?.arrayBuffer?p=Buffer.from(await h.arrayBuffer()):p=Buffer.from(h),!p.length)return;let M=String.fromCharCode(p[0]),W=p.subarray(1);if(M==="0")f.stdin?.write(W);else if(M==="1")try{f.stdio[3]&&f.stdio[3].write(W.toString()+`
59
+ `);}catch{}};T(),N.set(t,y),f.stdout?.on("data",k=>{if(!a||a.readyState!==1)return;let p=Buffer.concat([Buffer.from("0"),k]);if(a.send(p.buffer.slice(p.byteOffset,p.byteOffset+p.byteLength)),typeof a.bufferedAmount=="number"&&a.bufferedAmount>4*1024*1024){f.stdout?.pause();let h=setInterval(()=>{(!a||a.readyState!==1||a.bufferedAmount<1024*1024)&&(clearInterval(h),f.stdout?.resume());},50);}}),f.on("exit",y),w(`pty ${t.slice(0,8)} started in ${s}`);}async function Re(e,r,t){let s=new Set(["list","read","read-upload","write","write-download"]);if(t?.__nodusPermission==="files_only"&&!s.has(r))throw new Error("Desktop Runtime file-only permission rejected this request locally.");let o=t?.cwd?b(e.folder,String(t.cwd)):e.folder;switch(r){case "exec":{let n=String(t.cmd??"");return K(n),Ee(n,o,t.timeoutSeconds)}case "pty":return Le(e,t),{ok:true};case "list":return xe(b(o,t.path??"."),!!t.dirsOnly);case "read":{let n=b(o,t.path),i=await readFile(n);if(i.length>5*1024*1024)throw new Error("File exceeds the 5 MB read limit \u2014 use exec instead.");return {path:n,sizeBytes:i.length,contentBase64:i.toString("base64")}}case "read-upload":{let n=b(o,t.path),i=await stat(n),c=await fetch(String(t.uploadUrl),{method:"PUT",headers:{"content-type":"application/octet-stream","content-length":String(i.size)},body:createReadStream(n),duplex:"half"});if(!c.ok)throw new Error(`Upload failed: ${c.status}`);return {ok:true,path:n,sizeBytes:i.size}}case "write":{let n=b(o,t.path);return await mkdir(u.dirname(n),{recursive:true}),await writeFile(n,Buffer.from(String(t.contentBase64??""),"base64")),{ok:true,path:n}}case "write-download":{let n=b(o,t.path),i=await fetch(String(t.downloadUrl));if(!i.ok)throw new Error(`Download failed: ${i.status}`);return await mkdir(u.dirname(n),{recursive:true}),await writeFile(n,Buffer.from(await i.arrayBuffer())),{ok:true,path:n}}case "skills/list":return se();case "skills/read":return {name:t.name,content:await readFile(u.join(await X(O(t.name)),"SKILL.md"),"utf8")};case "skills/resource":{let n=await X(O(t.name)),i=u.resolve(n,String(t.path));if(!i.startsWith(n+u.sep))throw new Error("Path escapes the skill directory.");return {path:i,content:await readFile(i,"utf8")}}case "plugins/list":return {plugins:(await readdir(L).catch(()=>[])).map(i=>({name:i}))};case "plugins/read":{let n=u.join(L,O(t.name)),i=await readdir(n).catch(()=>[]);return {name:t.name,components:i}}case "plugins/resource":{let n=u.join(L,O(t.name)),i=u.resolve(n,String(t.path));if(!i.startsWith(n+u.sep))throw new Error("Path escapes the plugin directory.");return {path:i,content:await readFile(i,"utf8")}}case "mcp/catalog":return oe();case "mcp/close":return {ok:true};case "mcp":return Ie(t);default:throw new Error(`Unknown desktop request type: ${r}`)}}var Ae=200*1024;async function ee(e,r,t,s,o){if(!o&&t?.resultUploadUrl){let n=JSON.stringify(s);if(n.length>Ae&&(await fetch(String(t.resultUploadUrl),{method:"PUT",headers:{"content-type":"application/json"},body:n})).ok){await x(e.baseUrl,"/desktop-devices/agent/complete",{requestId:r,result:{resultUploaded:true}},e.credential);return}}await x(e.baseUrl,"/desktop-devices/agent/complete",{requestId:r,...o?{error:o}:{result:s}},e.credential);}async function je(e){let r=new Set,t=Math.max(1,Math.min(16,Number(process.env.NODUS_DESKTOP_CONCURRENCY??4)||4));w(`desktop agent online \u2014 workspace: ${e.folder}`),w(`runtime ${e.runtimeId} on ${hostname()}`);let s=async()=>{let i=homedir();await x(e.baseUrl,"/desktop-devices/agent/heartbeat",{capabilities:{exec:true,files:true,skills:true,concurrency:t},defaultCwd:e.folder,homeDisplay:e.folder.startsWith(i)?`~${e.folder.slice(i.length)}`:e.folder,skillCatalog:(await se()).skills.slice(0,100),mcpCatalog:(await oe()).servers},e.credential).catch(c=>w("heartbeat failed:",c.message));},o=async()=>{let i=[],c=Math.max(0,t-r.size);if(c){try{i=(await x(e.baseUrl,"/desktop-devices/agent/claim",{limit:c},e.credential)).requests??[];}catch(d){w("claim failed:",d.message);return}for(let d of i)r.has(d.id)||(r.add(d.id),(async()=>{let f=Date.now();try{let l=await Re(e,d.type,d.payload??{});await ee(e,d.id,d.payload,l),w(`\u2713 ${d.type} (${Date.now()-f}ms)`);}catch(l){await ee(e,d.id,d.payload,null,l?.message??String(l)).catch(()=>{}),w(`\u2717 ${d.type}: ${l?.message??l}`);}finally{r.delete(d.id);}})());}},n=()=>{try{let i=new URL(e.baseUrl);i.protocol=i.protocol==="https:"?"wss:":"ws:",i.pathname="/desktop-devices/agent/connect";let c=new WebSocket(i.toString(),{headers:{authorization:`Bearer ${e.credential}`}});c.onmessage=d=>{try{JSON.parse(String(d.data)).type==="wake"&&o();}catch{}},c.onclose=()=>setTimeout(n,5e3),c.onerror=()=>{try{c.close();}catch{}};}catch{setTimeout(n,1e4);}};return await s(),n(),o(),setInterval(s,2e4),setInterval(o,5e3),new Promise(()=>{})}async function Ve(e){let r=u.resolve(e.folder.replace(/^~(?=\/|$)/,homedir()));if(!(await stat(r).catch(()=>null))?.isDirectory())throw new Error(`Not a folder: ${r}`);let s=await ke();if(!s||s.baseUrl!==e.baseUrl){let o=await ve(e.baseUrl,e.name??`${hostname()}`);s={baseUrl:e.baseUrl,...o,folder:r},await V(s),w("paired \u2014 credential saved to ~/.nodus/desktop.json");}else s.folder=r,await V(s);return je(s)}export{Ve as connect,Re as handleRequest,ke as loadConfig,ve as pair,je as runAgent,V as saveConfig};
package/dist/nodus.cjs ADDED
@@ -0,0 +1 @@
1
+ 'use strict';var u=class extends Error{constructor(p,a,n){super(p);this.status=a;this.data=n;this.name="NodusError";let d=n&&typeof n=="object"?n:null;this.code=typeof d?.code=="string"?d.code:null,this.retryAt=typeof d?.retryAt=="string"?d.retryAt:null;}status;data;code;retryAt},k=new Set(["completed","failed","cancelled","timed_out"]);function I(m){let R=m.baseUrl.replace(/\/+$/,""),p=m.fetch??globalThis.fetch,a=m.requestTimeoutMs??9e5,n=async(e,t,s,r={})=>{let o=new AbortController,i=r.timeoutMs??a,l=()=>o.abort(r.signal?.reason);r.signal?.addEventListener("abort",l,{once:true});let g=setTimeout(()=>o.abort(new Error("Nodus request timed out.")),i);try{let c=await p(`${R}${t}`,{method:e,headers:{authorization:`Bearer ${m.apiKey}`,...s===void 0?{}:{"content-type":"application/json"}},...s===void 0?{}:{body:JSON.stringify(s)},signal:o.signal}),y=await c.json().catch(()=>({}));if(!c.ok)throw new u(String(y.error??`Nodus request failed: ${c.status}`),c.status,y);return y}catch(c){throw r.signal?.aborted?new u("Nodus request was aborted.",499,null):o.signal.aborted?new u("Nodus request timed out.",504,{method:e,path:t,timeoutMs:i}):c}finally{clearTimeout(g),r.signal?.removeEventListener("abort",l);}},d=async(e,t={})=>{let s=Date.now()+(t.timeoutMs??18e5),r=t.pollIntervalMs??1e3;for(;Date.now()<s;){if(t.signal?.aborted)throw new u("Nodus agent run was aborted.",499,null);let{run:o}=await n("GET",`/agent-runs/${encodeURIComponent(e)}?view=status`,void 0,{signal:t.signal});if(k.has(o.status)&&!o.cleanupCompletedAt){await new Promise(i=>setTimeout(i,r));continue}if(o.status==="completed")return (await n("GET",`/agent-runs/${encodeURIComponent(e)}`)).run;if(k.has(o.status))throw new u(o.error??`Nodus agent run ${o.status}.`,502,{run:o});await new Promise(i=>setTimeout(i,r));}throw new u("Timed out waiting for Nodus agent run.",504,{runId:e})},b=(e,t={})=>n("GET",`/agent-runs/${encodeURIComponent(e)}/events?after=${t.after??0}&detail=full`),f=(e,t={})=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}/events?after=${t.after??0}&detail=full`),w=async(e,t)=>{let s=Date.now()+(t.timeoutMs??144e5),r=t.afterSequence??0,o=[];for(;Date.now()<s;){if(t.signal?.aborted)throw new u("Nodus session turn was aborted.",499,null);let i=Math.max(10,Math.ceil((s-Date.now())/1e3)),l=Math.min(840,t.waitSeconds??840,i),g=await n("POST",`/runtime-sessions/${encodeURIComponent(e)}/wait?detail=full`,{turnId:t.turnId,afterSequence:r,timeoutSeconds:l},{signal:t.signal,timeoutMs:Math.max(a,(l+30)*1e3)});o.push(...g.events),r=Math.max(r,g.lastSequence);let c={...g,events:o};if(g.status==="completed")return c;if(g.status==="failed")throw new u(g.error??"Nodus session turn failed.",502,c)}throw new u("Timed out waiting for Nodus session turn.",504,{sessionId:e,turnId:t.turnId,afterSequence:r})},h=async function*(e,t={},s){let r=t.after??0,o=t.pollIntervalMs??1e3;for(;!t.signal?.aborted;){let{events:i}=await e(r,t.signal);for(let l of i)r=Math.max(r,l.sequence),yield l;if(s&&await s())return;await new Promise(l=>setTimeout(l,o));}};return {agents:{list:async()=>(await n("GET","/agent-runs/agents")).agents,create:e=>n("POST","/agent-runs/agents",e),update:(e,t)=>n("PATCH",`/agent-runs/agents/${encodeURIComponent(e)}/configuration`,t),setRunConcurrency:(e,t)=>n("POST",`/agent-runs/agents/${encodeURIComponent(e)}/concurrency`,{maxConcurrency:t}),quota:(e,t)=>n("GET",`/agent-runs/agents/${encodeURIComponent(e)}/quota${t?.refresh?"?refresh=1":""}`),setConcurrency:(e,t)=>n("POST",`/agent-runs/agents/${encodeURIComponent(e)}/concurrency`,{maxConcurrency:t})},agentRuns:{list:(e={})=>{let t=new URLSearchParams;e.agentId&&t.set("agentId",e.agentId),e.status&&t.set("status",e.status),e.cursor&&t.set("cursor",e.cursor),e.limit&&t.set("limit",String(e.limit));for(let[s,r]of Object.entries(e.metadata??{}))t.append("metadata",`${s}=${r}`);return n("GET",`/agent-runs?${t}`)},queueStats:()=>n("GET","/agent-runs/queue-stats"),create:e=>n("POST","/agent-runs",e),get:e=>n("GET",`/agent-runs/${encodeURIComponent(e)}`),events:b,stream:(e,t)=>h((s,r)=>n("GET",`/agent-runs/${encodeURIComponent(e)}/events?after=${s}&detail=full`,void 0,{signal:r}),t,async()=>{let{run:s}=await n("GET",`/agent-runs/${encodeURIComponent(e)}?view=status`);return k.has(s.status)&&!!s.cleanupCompletedAt}),cancel:e=>n("POST",`/agent-runs/${encodeURIComponent(e)}/cancel`),cancelMany:e=>Promise.all(e.map(async t=>(await n("POST",`/agent-runs/${encodeURIComponent(t)}/cancel`)).run)),getArtifactDownloadUrl:(e,t)=>n("GET",`/agent-runs/${encodeURIComponent(e)}/artifacts/${encodeURIComponent(t)}/download`),wait:d,createAndWait:async(e,t)=>{let{run:s}=await n("POST","/agent-runs",e);return s.status==="completed"&&s.cleanupCompletedAt?s:d(s.id,t)}},sessions:{create:e=>n("POST","/runtime-sessions",e),list:(e={})=>{let t=new URLSearchParams(Object.entries(e).filter(s=>s[1]!==void 0).map(([s,r])=>[s,String(r)]));return n("GET",`/runtime-sessions${t.size?`?${t}`:""}`)},get:e=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}`),telemetry:e=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}/telemetry`),telemetryHistory:(e,t={})=>{let s=new URLSearchParams(Object.entries(t).filter(r=>r[1]!==void 0).map(([r,o])=>[r,String(o)]));return n("GET",`/runtime-sessions/${encodeURIComponent(e)}/telemetry-history${s.size?`?${s}`:""}`)},diff:(e,t)=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}/diff${t?`?known=${encodeURIComponent(t)}`:""}`),terminalTicket:e=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/terminal-ticket`),ports:(e,t)=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}/ports${t?`?known=${encodeURIComponent(t)}`:""}`),git:(e,t)=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/git`,t),run:(e,t,s={})=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/messages`,{text:t,...s.attachments?.length?{attachments:s.attachments}:{}}),execWorkspace:(e,t,s)=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/workspace/exec`,{cmd:t,...s?{timeoutSeconds:s}:{}},{timeoutMs:s?Math.max(a,(s+30)*1e3):a}),waitForIdle:w,runAndWait:async(e,t,s={})=>{let{attachments:r,...o}=s,{turn:i}=await n("POST",`/runtime-sessions/${encodeURIComponent(e)}/messages`,{text:t,...r?.length?{attachments:r}:{}});return w(e,{...o,turnId:i.id,afterSequence:i.acceptedSequence})},events:f,stream:(e,t)=>h((s,r)=>n("GET",`/runtime-sessions/${encodeURIComponent(e)}/events?after=${s}&detail=full`,void 0,{signal:r}),t),pause:e=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/pause`),resume:e=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/resume`),activate:e=>n("POST",`/runtime-sessions/${encodeURIComponent(e)}/activate`),destroy:e=>n("DELETE",`/runtime-sessions/${encodeURIComponent(e)}`)},workspaces:{create:e=>n("POST","/workspace-runtimes",e),list:async()=>(await n("GET","/workspace-runtimes")).workspaces,get:e=>n("GET",`/workspace-runtimes/${encodeURIComponent(e)}`),archive:e=>n("DELETE",`/workspace-runtimes/${encodeURIComponent(e)}`),revisions:async e=>{let t=await n("GET",`/workspace-runtimes/${encodeURIComponent(e)}/revisions`);if(!Array.isArray(t.revisions))throw new Error("Invalid Workspace revisions response.");return t.revisions},startBuilder:(e,t={})=>n("POST",`/workspace-runtimes/${encodeURIComponent(e)}/builds`,{mode:"interactive",...t}),getBuild:e=>n("GET",`/workspace-builds/${encodeURIComponent(e)}`),exec:(e,t,s)=>n("POST",`/workspace-builds/${encodeURIComponent(e)}/exec`,{cmd:t,...s?{timeoutSeconds:s}:{}},{timeoutMs:s?Math.max(a,(s+30)*1e3):a}),listFiles:(e,t="/")=>n("GET",`/workspace-builds/${encodeURIComponent(e)}/files?path=${encodeURIComponent(t)}`),readFile:(e,t)=>n("GET",`/workspace-builds/${encodeURIComponent(e)}/file?path=${encodeURIComponent(t)}`),writeFile:(e,t,s)=>n("PUT",`/workspace-builds/${encodeURIComponent(e)}/file`,{path:t,contentBase64:Buffer.from(s).toString("base64")}),upload:(e,t,s)=>n("PUT",`/workspace-builds/${encodeURIComponent(e)}/file`,{path:t,contentBase64:Buffer.from(s).toString("base64")}),download:async(e,t)=>Buffer.from((await n("GET",`/workspace-builds/${encodeURIComponent(e)}/file?path=${encodeURIComponent(t)}`)).contentBase64,"base64"),publish:e=>n("POST",`/workspace-builds/${encodeURIComponent(e)}/publish`),destroyBuilder:e=>n("DELETE",`/workspace-builds/${encodeURIComponent(e)}`),createContextUpload:e=>n("POST",`/workspace-runtimes/${encodeURIComponent(e)}/context-upload`),buildFromDockerfile:(e,t)=>n("POST",`/workspace-runtimes/${encodeURIComponent(e)}/builds`,{mode:"dockerfile",...t}),buildFromContext:(e,t)=>n("POST",`/workspace-runtimes/${encodeURIComponent(e)}/builds`,{mode:"dockerfile",...t})},desktopRuntimes:{list:async(e={})=>(await n("GET",`/desktop-runtimes${e.agentId?`?agentId=${encodeURIComponent(e.agentId)}`:""}`)).desktopRuntimes,get:e=>n("GET",`/desktop-runtimes/${encodeURIComponent(e)}`),rename:(e,t)=>n("PATCH",`/desktop-runtimes/${encodeURIComponent(e)}`,{name:t}),bind:(e,t)=>n("PATCH",`/desktop-runtimes/${encodeURIComponent(e)}/bind`,{agentId:t}),grants:e=>n("GET",`/desktop-runtimes/${encodeURIComponent(e)}/grants`),grant:(e,t,s)=>n("PUT",`/desktop-runtimes/${encodeURIComponent(e)}/grants/${encodeURIComponent(t)}`,{permission:s}),revokeGrant:(e,t)=>n("DELETE",`/desktop-runtimes/${encodeURIComponent(e)}/grants/${encodeURIComponent(t)}`),browse:(e,t={})=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/browse`,t),read:(e,t)=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/read`,{path:t}),ports:(e,t)=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/ports`,t?{known:t}:{}),attach:(e,t)=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/attach`,t),terminalTicket:e=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/terminal-ticket`),reveal:(e,t)=>n("POST",`/desktop-runtimes/${encodeURIComponent(e)}/reveal`,t),disconnect:e=>n("DELETE",`/desktop-runtimes/${encodeURIComponent(e)}`)}}}var A="0.4.0-preview.47";function v(){return {workspaceCredentialFailover:true,fixedSessionIdentity:true,persistentSessionSnapshots:true,runtimeResourceTelemetry:true,cliIntrospection:true,inlineRunResources:true,sessionAttachments:true,providers:["claude","codex","grok","gemini","cursor","factory"]}}function T(){return [{command:"nodus login|auth status|logout",description:"Authorize the CLI in a browser and manage local credential profiles."},{command:"nodus sdk",description:"List installed SDK methods, features, and CLI commands."},{command:"nodus capabilities",description:"Alias for `nodus sdk`."},{command:"nodus agents list|quota|configure|concurrency",description:"Inspect and configure every Agent available to the SDK key."},{command:"nodus agents deploy --provider <provider> --api-key <key> [--name <displayName>] [--owner-tag <tag>]",description:"Create an Agent in the key's Workspace and authenticate it with a provider API key."},{command:"nodus run --agent <id> --prompt <text> [--goal-file <markdown>] [--attach <file>]... [--wait]",description:"Run one task on a specific Agent. Goal Markdown is stored separately from the initial prompt."},{command:"nodus run --provider <provider> [--model <model>] --prompt <text> [--goal-file <markdown>] [--attach <file>]... [--wait]",description:"Let a Workspace key route a task; --goal-file enables Codex Goal mode."},{command:"nodus runs list|get|events|cancel|artifact",description:"Inspect and control existing Agent Runs, including artifact download URLs."},{command:"nodus session list|create|get|run|exec|events|telemetry|telemetry-history|diff|ports|git|terminal-ticket|pause|resume|destroy",description:"List, create, observe, and control persistent or temporary runtime Sessions."},{command:"nodus workspace create|list|get|revisions|archive|build",description:"Create, inspect, archive, and build persistent Workspace runtimes."},{command:"nodus workspace builder start|exec|put|get|files|status|publish|destroy",description:"Build and publish Workspace revisions interactively."},{command:"nodus desktop connect|list|get|rename|browse|read|ports|attach|reveal|terminal-ticket|disconnect",description:"Attach, inspect, control, or disconnect a local Desktop runtime."},{command:"nodus desktop bind --desktop <id> [--agent <id>|--none]",description:"Bind a Desktop runtime to one Agent (only that Agent's runs/sessions may use it) or unbind it."}]}function C(m){let R=[],p=(a,n="")=>{if(!(!a||typeof a!="object"))for(let[d,b]of Object.entries(a)){let f=n?`${n}.${d}`:d;typeof b=="function"?R.push(f):p(b,f);}};return p(m),R.sort()}exports.NODUS_SDK_VERSION=A;exports.NodusError=u;exports.createNodus=I;exports.getNodusCliManifest=T;exports.getNodusFeatureManifest=v;exports.listNodusCapabilities=C;