broods 0.54.1 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account.d.ts +51 -490
- package/dist/{chunk-aqcx0cwa.js → chunk-2vxrctp1.js} +5 -5
- package/dist/{chunk-7nrh4nqb.js → chunk-6e95e9kc.js} +7 -7
- package/dist/{chunk-j55y24fb.js → chunk-dgm6742m.js} +1 -1
- package/dist/{chunk-wamkxgcg.js → chunk-fka39yjm.js} +2 -2
- package/dist/cli/index.js +90 -62
- package/dist/index.d.ts +124 -1048
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
import{M}from"./chunk-
|
|
1
|
+
import{M}from"./chunk-2vxrctp1.js";import{ge,e,n,t,s}from"./chunk-pjvyrwbt.js";import{readFileSync as d}from"node:fs";import{dirname as g,resolve as m}from"node:path";import{Client as h}from"@modelcontextprotocol/client";import{StdioClientTransport as f}from"@modelcontextprotocol/client/stdio";var p="2026-07-28";var u={name:"broods-machine",version:"1.0.0"},w=1e4,S=t({command:e().min(1),args:n(e()).default([]),env:s(e(),e()).optional(),cwd:e().optional()}),y=t({mcpServers:s(e(),S).refine((r)=>Object.keys(r).length>0,"lists no MCP servers")});class v{#t=new Map;#e;#r;constructor(r,o){this.#r=r,this.#e=o}async callTool(r,o,i){return await(await this.#n(r)).callTool({name:o,arguments:i})}async listTools(r){return(await(await this.#n(r)).listTools()).tools}names(){return[...this.#r.keys()]}async stop(){let r=[...this.#t.values()];this.#t.clear(),await Promise.all(r.map((o)=>o.then((i)=>i.close()).catch(()=>{})))}#n(r){let o=this.#r.get(r);if(!o)return Promise.reject(Error(`no MCP server named "${r}" in the --mcp file`));let i=this.#t.get(r);if(i)return i;let c=(async()=>{this.#e(`mcp ${r}: ${[o.command,...o.args].join(" ")}`);let a=new f({...o,env:{...M(),...o.env},stderr:"inherit"});a.onclose=()=>{if(this.#e(`mcp ${r}: exited`),this.#t.get(r)===c)this.#t.delete(r)};let l=new h(u,{versionNegotiation:{mode:{pin:p},probe:{timeoutMs:w}}});return await l.connect(a),l})();return c.catch(()=>{if(this.#t.get(r)===c)this.#t.delete(r)}),this.#t.set(r,c),c}}function I(r){let o=m(r),i=y.safeParse(C(o));if(!i.success)throw Error(`${o}: ${ge(i.error)}`);return new Map(Object.entries(i.data.mcpServers).map(([c,a])=>[c,a.cwd?{...a,cwd:m(g(o),a.cwd)}:a]))}function C(r){try{return JSON.parse(d(r,"utf8"))}catch(o){throw Error(`could not read ${r}: ${o instanceof Error?o.message:String(o)}`)}}export{v as McpHost,I as readMcpServersFile};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{M,E}from"./chunk-
|
|
1
|
+
import{M,E}from"./chunk-2vxrctp1.js";import{e,o,i,c,n,t,u,w,s,d,r}from"./chunk-pjvyrwbt.js";import{ee,ie,A}from"./cli/index.js";import{spawn as ne}from"node:child_process";import{statfsSync as se}from"node:fs";import{availableParallelism as ae,homedir as ce,hostname as le,totalmem as pe}from"node:os";import{performance as j}from"node:perf_hooks";var P=["cursor_position","double_click","hold_key","key","left_click","left_click_drag","left_mouse_down","left_mouse_up","middle_click","mouse_move","right_click","screenshot","scroll","triple_click","type","wait","zoom"];var T={badFrame:{code:4400,reason:"Malformed frame"},expired:{code:4419,reason:"Credential expired"},occupied:{code:4423,reason:"Already connected from another daemon"},replaced:{code:4409,reason:"Replaced by a newer connection"},unauthorized:{code:4401,reason:"Unauthorized; run broods login"},unknownSandbox:{code:4404,reason:"No machine sandbox with that name in this account"}};var U="/v1/machines/ws",B=t({action:d(P),coordinate:n(o().int()).length(2).optional().describe("[x, y] in screenshot pixels for mouse actions."),start_coordinate:n(o().int()).length(2).optional().describe("[x, y] where a left_click_drag starts."),text:e().optional().describe("Text for type, the key chord for key and hold_key, or modifiers to hold during a click, drag or scroll."),scroll_direction:d(["down","left","right","up"]).optional(),scroll_amount:o().int().min(1).optional().describe("Scroll clicks, default 3."),duration:o().min(0).max(300).optional().describe("Seconds for wait and hold_key."),region:n(o().int()).length(4).optional().describe("[x0, y0, x1, y1] of the screenshot to zoom into."),repeat:o().int().min(1).max(100).optional().describe("How many times to press the key.")}),G=B.extend({type:r("computer"),id:e()}),W=t({type:r("computer-result"),id:e(),text:e().optional(),image:t({data:e(),mediaType:e()}).optional(),app:e().optional(),error:e().optional()}),J=t({type:r("credential"),token:e().min(1)}),K=t({type:r("exec"),id:e(),code:e(),cwd:e().optional(),env:s(e(),e()).optional(),timeoutSeconds:o().positive(),outputLimitBytes:o().positive()}),X=t({type:r("hello"),sandbox:e().min(1),hostname:e().optional(),platform:e().optional(),computer:i().optional(),mcp:n(e()).optional(),instance:e().optional(),force:i().optional(),specs:t({vcpu:o().positive(),memoryMb:o().positive(),storageGb:o().positive().optional()}).optional().catch(void 0)}),Y=t({type:r("mcp-call"),id:e(),server:e(),tool:e(),args:s(e(),c())}),q=t({type:r("mcp-list"),id:e(),server:e()}),Z=t({type:r("mcp-result"),id:e(),result:u({content:n(c())}).optional(),error:e().optional()}),Q=t({type:r("mcp-tools"),id:e(),tools:n(u({name:e(),inputSchema:s(e(),c())})).optional(),error:e().optional()}),V=t({type:r("ready"),sandboxId:e(),expiresInMs:o().optional()}),te=t({type:r("result"),id:e(),exitCode:o().nullable(),stdout:e(),stderr:e(),durationMs:o(),timedOut:i(),truncated:i()}),oe=w("type",[G,K,Y,q,V]),xe=w("type",[W,J,X,Z,Q,te]);function z(a){let l=new URL(U,a);return l.protocol=l.protocol==="https:"?"wss:":"ws:",l.toString()}function I(a){return re(oe,a)}function re(a,l){if(typeof l!=="string")return null;try{let y=a.safeParse(JSON.parse(l));return y.success?y.data:null}catch{return null}}var de=new Set([T.occupied.code,T.replaced.code,T.unauthorized.code,T.unknownSandbox.code]),H=72,O=30000,R=1000;function me(a,l,y){return new Promise((f)=>{let h=j.now(),g=new L(a.outputLimitBytes),k=new L(a.outputLimitBytes),b=!1,F=!1,x=(m,p)=>{if(F)return;if(F=!0,clearTimeout(D),y?.removeEventListener("abort",C),p)k.append(Buffer.from(`${p}
|
|
2
2
|
`));f({type:"result",id:a.id,exitCode:m,stdout:g.text(),stderr:k.text(),durationMs:Math.round(j.now()-h),timedOut:b,truncated:g.truncated||k.truncated})},v=ne("bash",["-lc",a.code],{cwd:a.cwd??l,env:{...M(),...a.env},detached:!0,stdio:["ignore","pipe","pipe"]}),_=()=>{if(!v.pid)return;try{process.kill(-v.pid,"SIGKILL")}catch{v.kill("SIGKILL")}},D=setTimeout(()=>{b=!0,_()},a.timeoutSeconds*1000),C=()=>{_(),x(null,"stopped: the daemon closed its socket")};if(y?.addEventListener("abort",C,{once:!0}),v.stdout.on("data",(m)=>g.append(m)),v.stderr.on("data",(m)=>k.append(m)),v.on("error",(m)=>x(null,m.message)),v.on("close",(m)=>x(m)),y?.aborted)C()})}async function Oe(a){let l=ie(),y=crypto.randomUUID(),f=a.mcpFile?await fe(a.mcpFile,a.log):null,h=a.computer?await ge(a.log):null,g=R;try{while(!a.signal.aborted){let k=Date.now(),b;try{b=await a.credential()}catch(x){if(x instanceof A)throw x;a.log(`stage session unavailable (${x instanceof Error?x.message:String(x)}), retrying in ${Math.round(g/1000)}s`),await ee(g,a.signal),g=Math.min(g*2,O);continue}let F=await Me(a,b,y,l,h,f);if(a.signal.aborted)return;if(de.has(F.code))throw Error(F.reason||`core closed the socket (${F.code})`);if(Date.now()-k>O)g=R;a.log(`disconnected (${F.reason||F.code}), reconnecting in ${Math.round(g/1000)}s`),await ee(g,a.signal),g=Math.min(g*2,O)}}finally{h?.stop(),await f?.stop()}}class L{#o=[];#e;#t=0;truncated=!1;constructor(a){this.#e=a}append(a){if(this.#t>=this.#e){this.truncated=!0;return}let l=this.#e-this.#t;if(a.byteLength>l){this.#o.push(a.subarray(0,l)),this.#t=this.#e,this.truncated=!0;return}this.#o.push(a),this.#t+=a.byteLength}text(){let a=Buffer.concat(this.#o).toString("utf8");return this.truncated?`${a}
|
|
3
3
|
[output truncated]`:a}}function ue(a){let l=[a.action];if(a.coordinate)l.push(`at ${a.coordinate.join(",")}`);if(a.text!==void 0)l.push(JSON.stringify(N(a.text)));if(a.region)l.push(`region ${a.region.join(",")}`);return l.join(" ")}function he(){let a=ye();return{vcpu:ae(),memoryMb:Math.round(pe()/1048576),...a?{storageGb:a}:{}}}function ye(){try{let a=se(ce());return Math.round(a.blocks*a.bsize/1073741824)}catch{return}}function N(a){let l=a.trim().split(`
|
|
4
|
-
`)[0]??"";return l.length>H?`${l.slice(0,H)}…`:l}async function ge(a){let{startDesktop:l}=await import("./chunk-5tnnqapc.js"),{display:y,driver:f,permissions:h}=await l(!1);if(a(`computer use on, ${y.width}x${y.height} screenshots`),!h.screenRecording||!h.accessibility)a(" screen recording or accessibility is missing, run `broods machine --doctor --request`");return f}async function fe(a,l){let{McpHost:y,readMcpServersFile:f}=await import("./chunk-
|
|
4
|
+
`)[0]??"";return l.length>H?`${l.slice(0,H)}…`:l}async function ge(a){let{startDesktop:l}=await import("./chunk-5tnnqapc.js"),{display:y,driver:f,permissions:h}=await l(!1);if(a(`computer use on, ${y.width}x${y.height} screenshots`),!h.screenRecording||!h.accessibility)a(" screen recording or accessibility is missing, run `broods machine --doctor --request`");return f}async function fe(a,l){let{McpHost:y,readMcpServersFile:f}=await import("./chunk-dgm6742m.js"),h=new y(f(a),l);return l(`mcp servers from ${a}: ${h.names().join(", ")}`),h}async function be(a,l,y){try{if(a.type==="mcp-list"){let h=await l.listTools(a.server);return y(` mcp ${a.server}: ${h.length} tools`),{type:"mcp-tools",id:a.id,tools:h}}y(` mcp ${a.server}.${a.tool}`);let f=await l.callTool(a.server,a.tool,a.args);return{type:"mcp-result",id:a.id,result:f}}catch(f){let h=f instanceof Error?f.message:String(f);return y(` mcp ${a.server}: ${h}`),{type:a.type==="mcp-call"?"mcp-result":"mcp-tools",id:a.id,error:h}}}function Me(a,l,y,f,h,g){return new Promise((k)=>{let b=new f(z(a.baseUrl),E(l)),F=new AbortController,x=()=>b.close(1000,"daemon stopped"),v=(m)=>{if(b.readyState===b.OPEN)b.send(JSON.stringify(m))},_,D=(m)=>{if(clearTimeout(_),F.signal.aborted)return;_=setTimeout(()=>{a.credential().then((p)=>v({type:"credential",token:p}),(p)=>a.log(`credential refresh failed (${p instanceof Error?p.message:String(p)}), retrying`)).finally(()=>D(m))},Math.max((m-Date.now())/2,R))},C=(m,p)=>{a.signal.removeEventListener("abort",x),clearTimeout(_),F.abort(),k({code:m,reason:p})};a.signal.addEventListener("abort",x,{once:!0}),b.onopen=()=>v({type:"hello",sandbox:a.sandbox,hostname:le(),platform:process.platform,computer:h!==null,mcp:g?.names(),instance:y,force:a.force,specs:he()}),b.onmessage=(m)=>{let p=I(m.data);if(p?.type==="ready"){if(_===void 0)a.log(`connected as ${a.sandbox} (${p.sandboxId})`);if(p.expiresInMs!==void 0)D(Date.now()+p.expiresInMs);return}if(p?.type==="computer"&&h){a.log(` ${ue(p)}`),h.run(p).then((S)=>{if(S.error)a.log(` error: ${S.error}`);v(S)});return}if((p?.type==="mcp-call"||p?.type==="mcp-list")&&g){be(p,g,a.log).then(v);return}if(p?.type!=="exec")return;a.log(`$ ${N(p.code)}`),me(p,a.cwd,F.signal).then((S)=>{a.log(` exit ${S.exitCode??"none"} in ${S.durationMs}ms${S.timedOut?" (timed out)":""}`),v(S)})},b.onerror=()=>C(1006,"connection failed"),b.onclose=(m)=>C(m.code,m.reason)})}export{Oe as runMachineDaemon};
|