broods 0.52.0 → 0.52.1
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{N,k}from"./chunk-
|
|
1
|
+
import{N,k}from"./chunk-yqbtb9cd.js";import{e,o,i,c,n,t,u,R,s,d,r}from"./chunk-9th6spww.js";import{Q,ie,O}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 A}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 C={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()}),V=t({type:r("mcp-tools"),id:e(),tools:n(u({name:e(),inputSchema:s(e(),c())})).optional(),error:e().optional()}),ee=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=R("type",[G,K,Y,q,ee]),xe=R("type",[W,J,X,Z,V,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([C.occupied.code,C.replaced.code,C.unauthorized.code,C.unknownSandbox.code]),j=72,T=30000,D=1000;function me(a,l,y){return new Promise((g)=>{let h=A.now(),f=new L(a.outputLimitBytes),x=new L(a.outputLimitBytes),b=!1,v=!1,F=(m,p)=>{if(v)return;if(v=!0,clearTimeout(E),y?.removeEventListener("abort",_),p)x.append(Buffer.from(`${p}
|
|
2
2
|
`));g({type:"result",id:a.id,exitCode:m,stdout:f.text(),stderr:x.text(),durationMs:Math.round(A.now()-h),timedOut:b,truncated:f.truncated||x.truncated})},M=ne("bash",["-lc",a.code],{cwd:a.cwd??l,env:{...N(),...a.env},detached:!0,stdio:["ignore","pipe","pipe"]}),S=()=>{if(!M.pid)return;try{process.kill(-M.pid,"SIGKILL")}catch{M.kill("SIGKILL")}},E=setTimeout(()=>{b=!0,S()},a.timeoutSeconds*1000),_=()=>{S(),F(null,"stopped: the daemon closed its socket")};if(y?.addEventListener("abort",_,{once:!0}),M.stdout.on("data",(m)=>f.append(m)),M.stderr.on("data",(m)=>x.append(m)),M.on("error",(m)=>F(null,m.message)),M.on("close",(m)=>F(m)),y?.aborted)_()})}async function Oe(a){let l=ie(),y=crypto.randomUUID(),g=a.mcpFile?await ge(a.mcpFile,a.log):null,h=a.computer?await fe(a.log):null,f=D;try{while(!a.signal.aborted){let x=Date.now(),b;try{b=await a.credential()}catch(F){if(F instanceof O)throw F;a.log(`stage session unavailable (${F instanceof Error?F.message:String(F)}), retrying in ${Math.round(f/1000)}s`),await Q(f,a.signal),f=Math.min(f*2,T);continue}let v=await Me(a,b,y,l,h,g);if(a.signal.aborted)return;if(de.has(v.code))throw Error(v.reason||`core closed the socket (${v.code})`);if(Date.now()-x>T)f=D;a.log(`disconnected (${v.reason||v.code}), reconnecting in ${Math.round(f/1000)}s`),await Q(f,a.signal),f=Math.min(f*2,T)}}finally{h?.stop(),await g?.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(H(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 H(a){let l=a.trim().split(`
|
|
4
|
-
`)[0]??"";return l.length>j?`${l.slice(0,j)}…`:l}async function fe(a){let{startDesktop:l}=await import("./chunk-5tnnqapc.js"),{display:y,driver:g,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 g}async function ge(a,l){let{McpHost:y,readMcpServersFile:g}=await import("./chunk-
|
|
4
|
+
`)[0]??"";return l.length>j?`${l.slice(0,j)}…`:l}async function fe(a){let{startDesktop:l}=await import("./chunk-5tnnqapc.js"),{display:y,driver:g,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 g}async function ge(a,l){let{McpHost:y,readMcpServersFile:g}=await import("./chunk-pfvvdwms.js"),h=new y(g(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 g=await l.callTool(a.server,a.tool,a.args);return{type:"mcp-result",id:a.id,result:g}}catch(g){let h=g instanceof Error?g.message:String(g);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,g,h,f){return new Promise((x)=>{let b=new g(z(a.baseUrl),k(l)),v=new AbortController,F=()=>b.close(1000,"daemon stopped"),M=(m)=>{if(b.readyState===b.OPEN)b.send(JSON.stringify(m))},S,E=(m)=>{if(clearTimeout(S),v.signal.aborted)return;S=setTimeout(()=>{a.credential().then((p)=>M({type:"credential",token:p}),(p)=>a.log(`credential refresh failed (${p instanceof Error?p.message:String(p)}), retrying`)).finally(()=>E(m))},Math.max((m-Date.now())/2,D))},_=(m,p)=>{a.signal.removeEventListener("abort",F),clearTimeout(S),v.abort(),x({code:m,reason:p})};a.signal.addEventListener("abort",F,{once:!0}),b.onopen=()=>M({type:"hello",sandbox:a.sandbox,hostname:le(),platform:process.platform,computer:h!==null,mcp:f?.names(),instance:y,force:a.force,specs:he()}),b.onmessage=(m)=>{let p=I(m.data);if(p?.type==="ready"){if(S===void 0)a.log(`connected as ${a.sandbox} (${p.sandboxId})`);if(p.expiresInMs!==void 0)E(Date.now()+p.expiresInMs);return}if(p?.type==="computer"&&h){a.log(` ${ue(p)}`),h.run(p).then((w)=>{if(w.error)a.log(` error: ${w.error}`);M(w)});return}if((p?.type==="mcp-call"||p?.type==="mcp-list")&&f){be(p,f,a.log).then(M);return}if(p?.type!=="exec")return;a.log(`$ ${H(p.code)}`),me(p,a.cwd,v.signal).then((w)=>{a.log(` exit ${w.exitCode??"none"} in ${w.durationMs}ms${w.timedOut?" (timed out)":""}`),M(w)})},b.onerror=()=>_(1006,"connection failed"),b.onclose=(m)=>_(m.code,m.reason)})}export{Oe as runMachineDaemon};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{N}from"./chunk-
|
|
1
|
+
import{N}from"./chunk-yqbtb9cd.js";import{ye,e,n,t,s}from"./chunk-9th6spww.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:{...N(),...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 x(r){let o=m(r),i=y.safeParse(M(o));if(!i.success)throw Error(`${o}: ${ye(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 M(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,x as readMcpServersFile};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function L(e){if(e.events&&e.input!==void 0)throw Error("Run input accepts either `input` or `events`, not both");if(e.events&&e.events.length>0)return e.events;if(typeof e.input==="string")return[{role:"user",content:[{type:"text",text:e.input}]}];throw Error("Run input requires `input` (string) or a non-empty `events` array")}async function*ae(e){let n=e.getReader(),t=new TextDecoder,o="";try{while(!0){let{done:r,value:i}=await n.read();if(r)break;o+=t.decode(i,{stream:!0});let s=o.split(`
|
|
2
2
|
`);o=s.pop()??"";for(let a of s)if(a.startsWith("data: "))yield a.slice(6)}}finally{await n.cancel().catch(()=>{return}),n.releaseLock()}}var Se=500,mn=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,Cn=/^(?!0{32}$)[0-9a-f]{32}$/;function he(e){return e==="DEBUG"||e==="INFO"||e==="WARN"||e==="ERROR"}function be(e){if(typeof e!=="object"||e===null)return!1;let n=e;if(n.type==="subscribe")return hn(n);if(n.type==="unsubscribe")return q(n.stream);if(n.type==="fetchTrace")return F(n.traceId);return!1}function ve(e){return e==="task"||e==="cron"||e==="subtask"}function U(e){return typeof e==="string"&&mn.test(e)}function F(e){return typeof e==="string"&&Cn.test(e)}function q(e){return e==="logs"||e==="traces"}function hn(e){let n=e.stream;if(!q(n))return!1;let t=e.backfill;if(t!==void 0&&(typeof t!=="number"||!Number.isSafeInteger(t)||t<0||t>500))return!1;if(e.liveOnly!==void 0&&typeof e.liveOnly!=="boolean")return!1;let o=e.minLevel;if(o!==void 0&&!he(o))return!1;let r=e.sandboxId;return r===void 0||n==="logs"&&U(r)}import{readFileSync as Sn}from"node:fs";import{chmod as Q,mkdir as Rn,writeFile as bn}from"node:fs/promises";import{homedir as In}from"node:os";import{dirname as J,join as xn}from"node:path";var y="broods",v="_generated",x=xn(In(),".broods","config.json"),X="broods.app",Y="dashboard",kn="gateway";function T(e){let n=process.env.BROODS_TOKEN,t=e??process.env.BROODS_BASE_URL;if(n&&t)return{baseUrl:h(t),token:n,createdAt:new Date().toISOString()};let o=ne();if(!o)return null;if(t)return o.logins[h(t)]??null;let r=process.env.BROODS_DASHBOARD_URL;if(r){let i=h(r);return Object.values(o.logins).find((s)=>s.dashboardUrl===i)??null}return o.logins[o.current]??null}async function B(e){let n=ne()?.logins??{},t={current:e.baseUrl,logins:{...n,[e.baseUrl]:e}};await Rn(J(x),{recursive:!0,mode:448}),await Q(J(x),448),await H(x,`${JSON.stringify(t,null,2)}
|
|
3
3
|
`)}async function H(e,n){await bn(e,n,{encoding:"utf8",mode:384}),await Q(e,384)}function b(){return process.env.BROODS_STAGE}function h(e){let n=e.length;while(n>0&&e.charCodeAt(n-1)===47)n-=1;return e.slice(0,n)}function M(e){try{let n=new URL(e);if(!n.hostname.startsWith(`${Y}.`))return;let t=n.hostname.slice(Y.length+1);if(t!==X&&!t.endsWith(`.${X}`))return;return n.hostname=`${kn}.${t}`,h(n.origin)}catch{return}}function ne(){try{let e=JSON.parse(Sn(x,"utf8"));if(typeof e.current!=="string"||!e.logins)return null;return{current:e.current,logins:e.logins}}catch{return null}}import{existsSync as re,readFileSync as ie,statSync as An}from"node:fs";import{join as se,resolve as ue}from"node:path";var O=new Map,vn=new Set(Object.keys(process.env)),oe=new Set;function m(e=process.cwd()){wn(e);let n=T();return{dashboardUrl:process.env.BROODS_DASHBOARD_URL??n?.dashboardUrl,baseUrl:process.env.BROODS_BASE_URL??n?.baseUrl,token:n?.token,project:process.env.BROODS_PROJECT,stage:b()}}function N(){let e={};for(let[n,t]of Object.entries(process.env))if(typeof t==="string"&&!n.startsWith("BROODS_"))e[n]=t;return e}function E(e,n=process.cwd()){let t=process.env[e];if(t===void 0)return!1;let o=ue(n);for(let r of[".env.local",".env"]){let i=se(o,r);if(!re(i))continue;let s=Z(ie(i,"utf8"));if(s[e]!==void 0)return s[e]!==t}return!0}function wn(e){let n=ue(e),t=process.env.BROODS_RELOAD_ENV==="1";for(let o of[".env",".env.local"]){let r=se(n,o);if(!re(r)){O.delete(r);continue}let i=An(r).mtimeMs,s=O.get(r);if(s&&s.mtimeMs===i)continue;O.set(r,{mtimeMs:i});for(let[a,c]of Object.entries(Z(ie(r,"utf8"))))if(t||!vn.has(a)||oe.has(a))process.env[a]=c,oe.add(a)}}function Z(e){let n={};for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;let r=o.startsWith("export ")?o.slice(7).trim():o,i=r.indexOf("=");if(i<=0)continue;let s=r.slice(0,i).trim();if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(s))continue;n[s]=Tn(r.slice(i+1).trim())}return n}function Tn(e){if(e.startsWith('"')&&e.endsWith('"'))return e.slice(1,-1).replace(/\\n/g,`
|
|
4
|
-
`).replace(/\\"/g,'"');if(e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);let n=e.indexOf(" #");return n>=0?e.slice(0,n).trimEnd():e}var P=new TextEncoder,le={name:"HMAC",hash:"SHA-256"};async function pe(e,n,t,o){let r=ge(P.encode(JSON.stringify(t))),i=await crypto.subtle.sign(le,await En(n,o),P.encode(r));return`${e}${r}.${ge(new Uint8Array(i))}`}function ge(e){let n="";for(let t of e)n+=String.fromCharCode(t);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function En(e,n){let t=await crypto.subtle.digest("SHA-256",P.encode(`${e}${n}`));return crypto.subtle.importKey("raw",t,le,!1,["sign","verify"])}var Nn="buat_",V="bsig_",ee="x-broods-user-token",de="broods.user.";var ye=600000,G=3600000,Dn="broods-user-token:",me=/^[A-Za-z0-9._@+=-]{1,128}$/,en=100,On=256,Mn=60000;async function nn(e,n,t=Date.now()){if(!n.startsWith(V))throw Error(`The user token signing secret must start with ${V}. It is not the bsk_ runtime key.`);let o=_n(e,t);if(!o||e.expiresAt>t+G)throw Error(`Invalid user token: userId must match ${me.source}, conversations must be at most ${en} non-empty keys, and expiresAt must be in the next ${G/60000} minutes.`);return await pe(Nn,Dn,o,n)}function _n(e,n){if(!e||typeof e!=="object")return null;let{userId:t,conversations:o,expiresAt:r}=e;if(typeof t!=="string"||!me.test(t)||typeof r!=="number"||!Number.isFinite(r)||r<=n||r>n+G+Mn)return null;if(o===void 0)return{userId:t,expiresAt:r};if(!Array.isArray(o)||o.length>en||!o.every((i)=>typeof i==="string"&&i.trim()===i&&i.length>0&&i.length<=On))return null;return{userId:t,conversations:o,expiresAt:r}}var g="BROODS_USER_TOKEN_SECRET";async function _e(e){let n=e.secret??process.env[g];if(!n)throw Error(`signUserToken needs the stage's signing secret: pass secret or set ${g}. \`broods dev\` and \`broods deploy\` write it to .env.local; the dashboard's Runtime key tab rotates it.`);return await nn({userId:e.userId,...e.conversations?{conversations:e.conversations}:{},expiresAt:Date.now()+(e.ttlMs??ye)},n)}var z="https://gateway.broods.app";class ce extends Error{accepted;constructor(e){super(`Ingress ${e.eventId} was accepted asynchronously with status ${e.status??"queued"}`);this.accepted=e;this.name="IngressAcceptedError"}}class j{baseUrl;apiKey;userToken;fetchImpl;constructor(e={}){m(),this.baseUrl=W(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||z),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||void 0,this.userToken=e.userToken,this.fetchImpl=e.fetch??fetch}channelWebhookUrl(e){return`${this.baseUrl}${e.webhookPath.startsWith("/")?"":"/"}${e.webhookPath}`}accountWebhookUrl(e,n){let t=[e,n].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${t.join("/")}`}stageWebhookUrl(e,n,t){let o=[e,"dev",n,t].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${o.join("/")}`}agent(e,n){if(typeof e==="string"){let o=e,r=n??"";if(!r)throw Error(`Agent ${o} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:r,run:(i)=>this.run({...i,agentName:o,agentId:r}),runAsync:(i)=>this.runAsync({...i,agentName:o,agentId:r}),continue:(i)=>this.continue({...i,agentId:r}),stream:(i)=>this.stream({...i,agentName:o,agentId:r})}}let t=e;if(!t.id)throw Error(`Agent ${t.name} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:t.id,run:(o)=>this.run(t,o),runAsync:(o)=>this.runAsync(t,o),continue:(o)=>this.continue(t,o),stream:(o)=>this.stream(t,o)}}async run(e,n){let t=[],o="",r=n?this.stream(e,n):this.stream(e);for await(let i of r)if(t.push(i),i.type==="text-delta")o+=i.text;return{text:o,events:t}}async*stream(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o=tn(t,"cli"),r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`,i=await this.openStream(o,r);if(!i.ok)throw Error(`Run failed: ${i.status} ${await i.text()}`);if(i.status===202)throw new ce(on(await i.json(),o));if(!i.body)throw Error("Run response has no body");for await(let s of ae(i.body)){let a;try{a=JSON.parse(s)}catch{continue}if(a.type==="error")throw Error(`Agent run failed: ${Un(a.error)}`);yield a}}async runAsync(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o={...tn(t,"async"),background:!0},r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(r,o,"Async run")}async continue(e,n){let t=n?e:null,o=n??e,r={agentId:t?t.id:e.agentId,eventId:o.eventId??`continue-${crypto.randomUUID()}`,conversationKey:o.conversationKey,continue:!0},i=t?this.scopedUrl(t):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(i,r,"Continue")}async getAsyncStatus(e){let n=this.resolveStatusUrl(e),t=await this.fetchJson(n,{method:"GET",headers:await this.apiKeyHeaders()});if(t.status===404)return{status:"not_found"};if(!t.ok)throw Error(`Status check failed: ${t.status} ${await t.text()}`);return await t.json()}async waitForAsyncStatus(e,n={}){let t=Date.now()+(n.timeoutMs??180000),o=n.intervalMs??2000;while(Date.now()<t){if(n.signal?.aborted)throw Error("Async status polling aborted.");let r=await this.getAsyncStatus(e);if(r.status==="awaiting_approval"||r.status==="awaiting_input"||r.status==="completed"||r.status==="failed"||r.status==="expired"||r.status==="not_found")return r;await Wn(o,n.signal)}throw Error("Polling timeout")}scopedUrl(e){if(e.projectSlug&&e.stageSlug&&e.endpointId)return`${this.baseUrl}/v1/projects/${encodeURIComponent(e.projectSlug)}/stages/${encodeURIComponent(e.stageSlug)}/agents/${encodeURIComponent(e.endpointId)}`;return`${this.baseUrl}/v1/runs`}asyncAgentRun(e,n){return{...e,conversationKey:n,poll:()=>this.getAsyncStatus(e),wait:(t)=>this.waitForAsyncStatus(e,t)}}async postAcceptedRun(e,n,t){let o=await this.fetchJson(e,{method:"POST",headers:await this.apiKeyHeaders(),body:JSON.stringify(n)});if(o.status!==202)throw Error(`${t} failed: ${o.status} ${await Pn(o,"202 JSON")}`);return this.asyncAgentRun(on(await o.json(),n),n.conversationKey)}async openStream(e,n){if(this.apiKey)return await this.fetchCore(e,n,{Authorization:`Bearer ${this.apiKey}`,...await this.userTokenHeaders()});throw Error(`BroodsClient streams directly from the core service at ${this.baseUrl}. Provide apiKey. For a self-hosted core service, set host/baseUrl or BROODS_HOST/BROODS_BASE_URL.`)}async fetchCore(e,n,t){try{return await this.fetchImpl(n,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t},body:JSON.stringify(e)})}catch(o){throw Error(`Cannot access the broods core service at ${n}. The SDK uses ${z} by default; set host/baseUrl or BROODS_HOST/BROODS_BASE_URL to your own core service URL if your account uses a custom deployment. Cause: ${o instanceof Error?o.message:String(o)}`)}}async apiKeyHeaders(){if(!this.apiKey)throw Error("BroodsClient requires apiKey or BROODS_API_KEY.");return{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...await this.userTokenHeaders()}}async userTokenHeaders(){let e=typeof this.userToken==="function"?await this.userToken():this.userToken;return e?{[ee]:e}:{}}async fetchJson(e,n){try{return await this.fetchImpl(e,n)}catch(t){throw Error(`Cannot access the broods core service at ${e}. Cause: ${t instanceof Error?t.message:String(t)}`)}}resolveStatusUrl(e){if(typeof e!=="string")return e.statusUrl;if(/^https?:\/\//.test(e))return e;return Kn(this.baseUrl,e)}}function W(e){let n=e.trim(),t=/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(n)?n:`https://${n}`;return h(t)}function tn(e,n){let t=e.eventId??`${n}-${crypto.randomUUID()}`;return{agentId:e.agentId,eventId:t,conversationKey:e.conversationKey??t,events:L(e),...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}}function Un(e){if(typeof e==="string")return e;if(!e||typeof e!=="object")return String(e);let n=e,t=n.data?.error?.message??n.message??n.responseBody??JSON.stringify(e),o=n.name?`${n.name}: `:"",r=n.statusCode?` (HTTP ${n.statusCode})`:"";return`${o}${t}${r}`}function on(e,n){if(!e||typeof e!=="object")throw Error("Async response must be an object");let t=e.statusUrl;if(typeof t!=="string"||t.length===0)throw Error("Async response missing statusUrl");let o=e.runId;if(typeof o!=="string"||o.length===0)throw Error("Async response missing runId");let r=typeof e.eventId==="string"?e.eventId:o,{status:i,requestedMode:s}=e;return{statusUrl:t,runId:o,eventId:r,agentId:n.agentId,...i==="accepted"||i==="queued"||i==="applied"||i==="processing"?{status:i}:{},...s==="reject"||s==="followup"||s==="collect"||s==="steer"?{requestedMode:s}:{}}}async function Pn(e,n){if((e.headers.get("content-type")??"").toLowerCase().includes("text/event-stream"))return await e.body?.cancel().catch(()=>{}),`expected ${n}, but the server returned an SSE stream. This usually means the core deployment ignored the background flag and ran the request on the direct streaming runner.`;let o=await e.text();if(o.length<=2000)return o;return`${o.slice(0,2000)}... [truncated ${o.length-2000} chars]`}function Wn(e,n){return new Promise((t,o)=>{if(n?.aborted){o(Error("Async status polling aborted."));return}let r=setTimeout(t,e);n?.addEventListener("abort",()=>{clearTimeout(r),o(Error("Async status polling aborted."))},{once:!0})})}function Kn(e,n){return`${W(e)}/v1/runs/${encodeURIComponent(n)}`}var Ln=2000,rn=0,I=1;class fe{baseUrl;apiKey;userToken;WebSocketImpl;connectTimeoutMs;constructor(e={}){if(m(),this.baseUrl=gn(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||z),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||"",!this.apiKey)throw Error("BroodsWebSocketClient requires apiKey or BROODS_API_KEY.");this.userToken=e.userToken,this.WebSocketImpl=e.WebSocket,this.connectTimeoutMs=e.connectTimeoutMs??Ln}subscribe(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=$n(e),i=un(this.baseUrl),s=new t(o,k(this.apiKey,e.userToken??this.userToken)),a=!1,c=!1,d=setTimeout(()=>{if(!a)R(i)},this.connectTimeoutMs),C=(p=1000,w="client closed")=>{if(c)return;if(c=!0,clearTimeout(d),e.signal?.removeEventListener("abort",A),s.readyState===I||s.readyState===rn)s.close(p,w)},R=(p)=>{n.onError?.(p),C(1000,"websocket error")},yn=()=>{n.onDone?.(),C(1000,"done")},A=()=>{if(s.readyState===I)s.send(JSON.stringify({type:"cancel"}));R(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",A,{once:!0}),s.onopen=()=>{if(a=!0,clearTimeout(d),e.signal?.aborted){A();return}s.send(JSON.stringify({type:"execute",agentId:r,...e.answers?{answers:e.answers}:{events:L(e)},sessionId:e.sessionId,...e.eventId!==void 0?{eventId:e.eventId}:{},...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}))},s.onmessage=(p)=>{if(typeof p.data!=="string")return;let w=an(p.data);if(!w)return;let D=cn(w,n);switch(n.onMessage?.(D),D.type){case"meta":n.onMeta?.(D);break;case"done":yn();break;case"error":R(Error(sn(D.error)));break}},s.onerror=()=>{R(i)},s.onclose=(p)=>{if(clearTimeout(d),e.signal?.removeEventListener("abort",A),c||p.code===1000)return;R(Error(p.reason||"WebSocket connection closed."))},{url:o,sendControl:function(p){if(s.readyState!==I)throw Error("WebSocket is not open");s.send(JSON.stringify({type:"control",...p}))},close:C}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o,k(this.apiKey,e.userToken??this.userToken)),i=!1,s=(c=1000,d="client closed")=>{if(i)return;if(i=!0,e.signal?.removeEventListener("abort",a),r.readyState===I||r.readyState===rn)r.close(c,d)},a=()=>{s(1000,"aborted"),n.onError?.(Error("WebSocket attach aborted."))};if(e.signal?.aborted)a();else e.signal?.addEventListener("abort",a,{once:!0});return r.onopen=()=>{if(i)return;r.send(JSON.stringify({type:"attach",...e,signal:void 0,agent:void 0,userToken:void 0}))},r.onmessage=(c)=>{if(i||typeof c.data!=="string")return;let d=an(c.data);if(!d)return;let C=cn(d,n);if(i)return;if(n.onMessage?.(C),i)return;if(C.type==="done")n.onDone?.();if(C.type==="error")n.onError?.(Error(sn(C.error)))},r.onerror=()=>{if(i)return;s(1000,"websocket error"),n.onError?.(un(this.baseUrl))},r.onclose=(c)=>{if(e.signal?.removeEventListener("abort",a),!i&&c.code!==1000)n.onError?.(Error(c.reason||"WebSocket connection closed."))},{url:o,sendControl:function(c){if(r.readyState!==I)throw Error("WebSocket is not open");r.send(JSON.stringify({type:"control",...c}))},close:s}}async*stream(e){let n=[],t=!1,o=null,r=null,i=()=>{r?.(),r=null},s=this.subscribe(e,{onMessage:function(a){n.push(a),i()},onDone:function(){t=!0,i()},onError:function(a){o=a,i()}});try{while(!0){if(n.length>0){yield n.shift();continue}if(o)throw o;if(t)return;await new Promise((a)=>{r=a})}}finally{s.close()}}buildUrl(e){let n=Bn(e),t=e.projectSlug??e.agent?.projectSlug,o=e.stageSlug??e.agent?.stageSlug,r=t&&o?`/projects/${encodeURIComponent(t)}/stages/${encodeURIComponent(o)}`:"";return`${K(this.baseUrl)}/v1${r}/agents/${encodeURIComponent(n)}/ws`}resolveWebSocket(){let e=this.WebSocketImpl??globalThis.WebSocket;if(!e)throw Error("WebSocket is not available. Pass a WebSocket implementation in BroodsWebSocketClient options.");return e}}function K(e){let n=new URL(gn(e));if(n.protocol==="https:")n.protocol="wss:";if(n.protocol==="http:")n.protocol="ws:";return h(n.toString())}function k(e,n){return["broods.v1",`broods.token.${e}`,...n?[`${de}${n}`]:[]]}function sn(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&typeof e.message==="string")return e.message;return e===void 0?"WebSocket stream error.":JSON.stringify(e)}function gn(e){let n=e.trim();if(/^wss?:\/\//.test(n))return h(n);return W(n)}function an(e){try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}function $n(e){let n=e.agentId??e.agent?.id??e.endpointId;if(!n)throw Error("WebSocket run requires agent, agentId, or endpointId.");return n}function Bn(e){let n=e.endpointId??e.agent?.endpointId??e.agent?.id;if(!n)throw Error("WebSocket run requires agent or endpointId.");return n}function cn(e,n){if(e.type!=="output")return e;let t=e;return n.onOutput?.(t),t.data}function un(e){return Error(`Cannot access the WebSocket service at ${e}.`)}var pn=Symbol.for("broods.resource"),dn=Symbol.for("broods.config"),fn=Symbol.for("broods.connection"),ln=/^[A-Z][A-Z0-9_]{0,63}$/,we=new Proxy((e)=>{if(!ln.test(e))throw Error("env name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");return{__beeblastEnv:!0,name:e}},{get:function(e,n,t){if(typeof n==="string"&&ln.test(n))throw Error(`env.${n} is not supported; use env("${n}")`);return Reflect.get(e,n,t)}});function Re(e){let{name:n,description:t,...o}=e;return S("agent",n,t,o)}function $e(e){return{[dn]:!0,config:e}}function Ce(e){let{name:n,description:t,...o}=e;return S("cron",n,t,o)}function Ee(e){return e}function ke(e){let{name:n,description:t,...o}=e;return S("mcp",n,t,o)}function Te(e){let{name:n,description:t,...o}=e;return S("policy",n,t,o)}function ze(e){let{name:n,description:t,...o}=e;return S("sandbox",n,t,o)}function Pe(e){let{name:n,description:t,...o}=e;return S("skill",n,t,o)}function Ie(e){let{name:n,description:t,...o}=e;return S("workspace",n,t,o)}function xe(e){return l("discord",e)}function Ae(e){return l("github",e)}function Oe(e){return l("gchat",e)}function Me(e){return l("instagram",e)}function Ne(e){return l("linear",e)}function je(e){return l("matrix",e)}function qe(e){return l("messenger",e)}function De(e){return l("pancake",e)}function Le(e){return l("slack",e)}function Ue(e){return l("teams",e)}function Fe(e){return l("telegram",e)}function Be(e){return l("twilio",e)}function He(e){return l("whatsapp",e)}function Ze(e){return l("zalo",e)}function Ve(e){let{name:n,description:t,channelId:o,guildId:r,...i}=e;return u(n,t,o,r,i)}function Ge(e){let{name:n,description:t,repo:o,...r}=e,[i,...s]=o.split("/");if(!i||s.length!==1||!s[0])throw Error(`Channel "${n}" repo must be "owner/name", not "${o}"`);return u(n,t,o,i,r)}function We(e){let{name:n,description:t,spaceName:o,...r}=e;return u(n,t,o,void 0,r)}function Ke(e){let{name:n,description:t,igsid:o,...r}=e;return u(n,t,o,void 0,r)}function Je(e){let{name:n,description:t,team:o,...r}=e;return u(n,t,o,void 0,r)}function Ye(e){let{name:n,description:t,channelId:o,...r}=e;return u(n,t,o,void 0,r)}function Xe(e){let{name:n,description:t,psid:o,...r}=e;return u(n,t,o,void 0,r)}function Qe(e){let{name:n,description:t,conversationId:o,...r}=e;return u(n,t,o,void 0,r)}function et(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function tt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function nt(e){let{name:n,description:t,chatId:o,...r}=e;return u(n,t,o,void 0,r)}function rt(e){let{name:n,description:t,from:o,...r}=e;return u(n,t,o,void 0,r)}function ot(e){let{name:n,description:t,waId:o,...r}=e;return u(n,t,o,void 0,r)}function st(e){let{name:n,description:t,chatId:o,...r}=e;return u(n,t,o,void 0,r)}function te(e){return Boolean(e&&typeof e==="object"&&e[dn])}function _(e){return Boolean(e&&typeof e==="object"&&e[fn])}function f(e){return Boolean(e&&typeof e==="object"&&e[pn])}function u(e,n,t,o,r){return S("channelRecord",e,n,{...r,externalId:t,...o?{workspaceRef:o}:{}})}function l(e,n){let{partition:t,...o}=n;return{[fn]:!0,kind:"connection",type:e,...t?{partition:t}:{},config:o}}function S(e,n,t,o){return{[pn]:!0,kind:e,name:n,...t?{description:t}:{},config:o}}
|
|
5
|
-
export{L,ae,Se,he,be,ve,U,F,y,v,x,T,B,H,b,h,M,m,N,E,Z,V,ee,G,g,_e,z,ce,j,
|
|
4
|
+
`).replace(/\\"/g,'"');if(e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);let n=e.indexOf(" #");return n>=0?e.slice(0,n).trimEnd():e}var P=new TextEncoder,le={name:"HMAC",hash:"SHA-256"};async function pe(e,n,t,o){let r=ge(P.encode(JSON.stringify(t))),i=await crypto.subtle.sign(le,await En(n,o),P.encode(r));return`${e}${r}.${ge(new Uint8Array(i))}`}function ge(e){let n="";for(let t of e)n+=String.fromCharCode(t);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function En(e,n){let t=await crypto.subtle.digest("SHA-256",P.encode(`${e}${n}`));return crypto.subtle.importKey("raw",t,le,!1,["sign","verify"])}var Nn="buat_",V="bsig_",ee="x-broods-user-token",de="broods.user.";var ye=600000,G=3600000,Dn="broods-user-token:",me=/^[A-Za-z0-9._@+=-]{1,128}$/,en=100,On=256,Mn=60000;async function nn(e,n,t=Date.now()){if(!n.startsWith(V))throw Error(`The user token signing secret must start with ${V}. It is not the bsk_ runtime key.`);let o=_n(e,t);if(!o||e.expiresAt>t+G)throw Error(`Invalid user token: userId must match ${me.source}, conversations must be at most ${en} non-empty keys, and expiresAt must be in the next ${G/60000} minutes.`);return await pe(Nn,Dn,o,n)}function _n(e,n){if(!e||typeof e!=="object")return null;let{userId:t,conversations:o,expiresAt:r}=e;if(typeof t!=="string"||!me.test(t)||typeof r!=="number"||!Number.isFinite(r)||r<=n||r>n+G+Mn)return null;if(o===void 0)return{userId:t,expiresAt:r};if(!Array.isArray(o)||o.length>en||!o.every((i)=>typeof i==="string"&&i.trim()===i&&i.length>0&&i.length<=On))return null;return{userId:t,conversations:o,expiresAt:r}}var g="BROODS_USER_TOKEN_SECRET";async function _e(e){let n=e.secret??process.env[g];if(!n)throw Error(`signUserToken needs the stage's signing secret: pass secret or set ${g}. \`broods dev\` and \`broods deploy\` write it to .env.local; the dashboard's Runtime key tab rotates it.`);return await nn({userId:e.userId,...e.conversations?{conversations:e.conversations}:{},expiresAt:Date.now()+(e.ttlMs??ye)},n)}var z="https://gateway.broods.app";class ce extends Error{accepted;constructor(e){super(`Ingress ${e.eventId} was accepted asynchronously with status ${e.status??"queued"}`);this.accepted=e;this.name="IngressAcceptedError"}}class j{baseUrl;apiKey;userToken;fetchImpl;constructor(e={}){m(),this.baseUrl=K(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||z),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||void 0,this.userToken=e.userToken,this.fetchImpl=e.fetch??fetch}channelWebhookUrl(e){return`${this.baseUrl}${e.webhookPath.startsWith("/")?"":"/"}${e.webhookPath}`}accountWebhookUrl(e,n){let t=[e,n].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${t.join("/")}`}stageWebhookUrl(e,n,t){let o=[e,"dev",n,t].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${o.join("/")}`}agent(e,n){if(typeof e==="string"){let o=e,r=n??"";if(!r)throw Error(`Agent ${o} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:r,run:(i)=>this.run({...i,agentName:o,agentId:r}),runAsync:(i)=>this.runAsync({...i,agentName:o,agentId:r}),continue:(i)=>this.continue({...i,agentId:r}),stream:(i)=>this.stream({...i,agentName:o,agentId:r})}}let t=e;if(!t.id)throw Error(`Agent ${t.name} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);return{id:t.id,run:(o)=>this.run(t,o),runAsync:(o)=>this.runAsync(t,o),continue:(o)=>this.continue(t,o),stream:(o)=>this.stream(t,o)}}async run(e,n){let t=[],o="",r=n?this.stream(e,n):this.stream(e);for await(let i of r)if(t.push(i),i.type==="text-delta")o+=i.text;return{text:o,events:t}}async*stream(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o=tn(t,"cli"),r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`,i=await this.openStream(o,r);if(!i.ok)throw Error(`Run failed: ${i.status} ${await i.text()}`);if(i.status===202)throw new ce(on(await i.json(),o));if(!i.body)throw Error("Run response has no body");for await(let s of ae(i.body)){let a;try{a=JSON.parse(s)}catch{continue}if(a.type==="error")throw Error(`Agent run failed: ${Un(a.error)}`);yield a}}async runAsync(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o={...tn(t,"async"),background:!0},r=n?this.scopedUrl(e):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(r,o,"Async run")}async continue(e,n){let t=n?e:null,o=n??e,r={agentId:t?t.id:e.agentId,eventId:o.eventId??`continue-${crypto.randomUUID()}`,conversationKey:o.conversationKey,continue:!0},i=t?this.scopedUrl(t):`${this.baseUrl}/v1/runs`;return this.postAcceptedRun(i,r,"Continue")}async getAsyncStatus(e){let n=this.resolveStatusUrl(e),t=await this.fetchJson(n,{method:"GET",headers:await this.apiKeyHeaders()});if(t.status===404)return{status:"not_found"};if(!t.ok)throw Error(`Status check failed: ${t.status} ${await t.text()}`);return await t.json()}async waitForAsyncStatus(e,n={}){let t=Date.now()+(n.timeoutMs??180000),o=n.intervalMs??2000;while(Date.now()<t){if(n.signal?.aborted)throw Error("Async status polling aborted.");let r=await this.getAsyncStatus(e);if(r.status==="awaiting_approval"||r.status==="awaiting_input"||r.status==="completed"||r.status==="failed"||r.status==="expired"||r.status==="not_found")return r;await Wn(o,n.signal)}throw Error("Polling timeout")}scopedUrl(e){if(e.projectSlug&&e.stageSlug&&e.endpointId)return`${this.baseUrl}/v1/projects/${encodeURIComponent(e.projectSlug)}/stages/${encodeURIComponent(e.stageSlug)}/agents/${encodeURIComponent(e.endpointId)}`;return`${this.baseUrl}/v1/runs`}asyncAgentRun(e,n){return{...e,conversationKey:n,poll:()=>this.getAsyncStatus(e),wait:(t)=>this.waitForAsyncStatus(e,t)}}async postAcceptedRun(e,n,t){let o=await this.fetchJson(e,{method:"POST",headers:await this.apiKeyHeaders(),body:JSON.stringify(n)});if(o.status!==202)throw Error(`${t} failed: ${o.status} ${await Pn(o,"202 JSON")}`);return this.asyncAgentRun(on(await o.json(),n),n.conversationKey)}async openStream(e,n){if(this.apiKey)return await this.fetchCore(e,n,{Authorization:`Bearer ${this.apiKey}`,...await this.userTokenHeaders()});throw Error(`BroodsClient streams directly from the core service at ${this.baseUrl}. Provide apiKey. For a self-hosted core service, set host/baseUrl or BROODS_HOST/BROODS_BASE_URL.`)}async fetchCore(e,n,t){try{return await this.fetchImpl(n,{method:"POST",headers:{"Content-Type":"application/json",Accept:"text/event-stream",...t},body:JSON.stringify(e)})}catch(o){throw Error(`Cannot access the broods core service at ${n}. The SDK uses ${z} by default; set host/baseUrl or BROODS_HOST/BROODS_BASE_URL to your own core service URL if your account uses a custom deployment. Cause: ${o instanceof Error?o.message:String(o)}`)}}async apiKeyHeaders(){if(!this.apiKey)throw Error("BroodsClient requires apiKey or BROODS_API_KEY.");return{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...await this.userTokenHeaders()}}async userTokenHeaders(){let e=typeof this.userToken==="function"?await this.userToken():this.userToken;return e?{[ee]:e}:{}}async fetchJson(e,n){try{return await this.fetchImpl(e,n)}catch(t){throw Error(`Cannot access the broods core service at ${e}. Cause: ${t instanceof Error?t.message:String(t)}`)}}resolveStatusUrl(e){if(typeof e!=="string")return e.statusUrl;if(/^https?:\/\//.test(e))return e;return Kn(this.baseUrl,e)}}function K(e){let n=e.trim(),t=/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(n)?n:`https://${n}`;return h(t)}function tn(e,n){let t=e.eventId??`${n}-${crypto.randomUUID()}`;return{agentId:e.agentId,eventId:t,conversationKey:e.conversationKey??t,events:L(e),...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}}function Un(e){if(typeof e==="string")return e;if(!e||typeof e!=="object")return String(e);let n=e,t=n.data?.error?.message??n.message??n.responseBody??JSON.stringify(e),o=n.name?`${n.name}: `:"",r=n.statusCode?` (HTTP ${n.statusCode})`:"";return`${o}${t}${r}`}function on(e,n){if(!e||typeof e!=="object")throw Error("Async response must be an object");let t=e.statusUrl;if(typeof t!=="string"||t.length===0)throw Error("Async response missing statusUrl");let o=e.runId;if(typeof o!=="string"||o.length===0)throw Error("Async response missing runId");let r=typeof e.eventId==="string"?e.eventId:o,{status:i,requestedMode:s}=e;return{statusUrl:t,runId:o,eventId:r,agentId:n.agentId,...i==="accepted"||i==="queued"||i==="applied"||i==="processing"?{status:i}:{},...s==="reject"||s==="followup"||s==="collect"||s==="steer"?{requestedMode:s}:{}}}async function Pn(e,n){if((e.headers.get("content-type")??"").toLowerCase().includes("text/event-stream"))return await e.body?.cancel().catch(()=>{}),`expected ${n}, but the server returned an SSE stream. This usually means the core deployment ignored the background flag and ran the request on the direct streaming runner.`;let o=await e.text();if(o.length<=2000)return o;return`${o.slice(0,2000)}... [truncated ${o.length-2000} chars]`}function Wn(e,n){return new Promise((t,o)=>{if(n?.aborted){o(Error("Async status polling aborted."));return}let r=setTimeout(t,e);n?.addEventListener("abort",()=>{clearTimeout(r),o(Error("Async status polling aborted."))},{once:!0})})}function Kn(e,n){return`${K(e)}/v1/runs/${encodeURIComponent(n)}`}var Ln=2000,rn=0,I=1;class fe{baseUrl;apiKey;userToken;WebSocketImpl;connectTimeoutMs;constructor(e={}){if(m(),this.baseUrl=gn(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||z),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||"",!this.apiKey)throw Error("BroodsWebSocketClient requires apiKey or BROODS_API_KEY.");this.userToken=e.userToken,this.WebSocketImpl=e.WebSocket,this.connectTimeoutMs=e.connectTimeoutMs??Ln}subscribe(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=$n(e),i=un(this.baseUrl),s=new t(o,k(this.apiKey,e.userToken??this.userToken)),a=!1,c=!1,d=setTimeout(()=>{if(!a)R(i)},this.connectTimeoutMs),C=(p=1000,w="client closed")=>{if(c)return;if(c=!0,clearTimeout(d),e.signal?.removeEventListener("abort",A),s.readyState===I||s.readyState===rn)s.close(p,w)},R=(p)=>{n.onError?.(p),C(1000,"websocket error")},yn=()=>{n.onDone?.(),C(1000,"done")},A=()=>{if(s.readyState===I)s.send(JSON.stringify({type:"cancel"}));R(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",A,{once:!0}),s.onopen=()=>{if(a=!0,clearTimeout(d),e.signal?.aborted){A();return}s.send(JSON.stringify({type:"execute",agentId:r,...e.answers?{answers:e.answers}:{events:L(e)},sessionId:e.sessionId,...e.eventId!==void 0?{eventId:e.eventId}:{},...e.mode!==void 0?{mode:e.mode}:{},...e.idempotencyKey!==void 0?{idempotencyKey:e.idempotencyKey}:{},...e.system!==void 0?{system:e.system}:{},...e.model!==void 0?{model:e.model}:{}}))},s.onmessage=(p)=>{if(typeof p.data!=="string")return;let w=an(p.data);if(!w)return;let D=cn(w,n);switch(n.onMessage?.(D),D.type){case"meta":n.onMeta?.(D);break;case"done":yn();break;case"error":R(Error(sn(D.error)));break}},s.onerror=()=>{R(i)},s.onclose=(p)=>{if(clearTimeout(d),e.signal?.removeEventListener("abort",A),c||p.code===1000)return;R(Error(p.reason||"WebSocket connection closed."))},{url:o,sendControl:function(p){if(s.readyState!==I)throw Error("WebSocket is not open");s.send(JSON.stringify({type:"control",...p}))},close:C}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o,k(this.apiKey,e.userToken??this.userToken)),i=!1,s=(c=1000,d="client closed")=>{if(i)return;if(i=!0,e.signal?.removeEventListener("abort",a),r.readyState===I||r.readyState===rn)r.close(c,d)},a=()=>{s(1000,"aborted"),n.onError?.(Error("WebSocket attach aborted."))};if(e.signal?.aborted)a();else e.signal?.addEventListener("abort",a,{once:!0});return r.onopen=()=>{if(i)return;r.send(JSON.stringify({type:"attach",...e,signal:void 0,agent:void 0,userToken:void 0}))},r.onmessage=(c)=>{if(i||typeof c.data!=="string")return;let d=an(c.data);if(!d)return;let C=cn(d,n);if(i)return;if(n.onMessage?.(C),i)return;if(C.type==="done")n.onDone?.();if(C.type==="error")n.onError?.(Error(sn(C.error)))},r.onerror=()=>{if(i)return;s(1000,"websocket error"),n.onError?.(un(this.baseUrl))},r.onclose=(c)=>{if(e.signal?.removeEventListener("abort",a),!i&&c.code!==1000)n.onError?.(Error(c.reason||"WebSocket connection closed."))},{url:o,sendControl:function(c){if(r.readyState!==I)throw Error("WebSocket is not open");r.send(JSON.stringify({type:"control",...c}))},close:s}}async*stream(e){let n=[],t=!1,o=null,r=null,i=()=>{r?.(),r=null},s=this.subscribe(e,{onMessage:function(a){n.push(a),i()},onDone:function(){t=!0,i()},onError:function(a){o=a,i()}});try{while(!0){if(n.length>0){yield n.shift();continue}if(o)throw o;if(t)return;await new Promise((a)=>{r=a})}}finally{s.close()}}buildUrl(e){let n=Bn(e),t=e.projectSlug??e.agent?.projectSlug,o=e.stageSlug??e.agent?.stageSlug,r=t&&o?`/projects/${encodeURIComponent(t)}/stages/${encodeURIComponent(o)}`:"";return`${W(this.baseUrl)}/v1${r}/agents/${encodeURIComponent(n)}/ws`}resolveWebSocket(){let e=this.WebSocketImpl??globalThis.WebSocket;if(!e)throw Error("WebSocket is not available. Pass a WebSocket implementation in BroodsWebSocketClient options.");return e}}function W(e){let n=new URL(gn(e));if(n.protocol==="https:")n.protocol="wss:";if(n.protocol==="http:")n.protocol="ws:";return h(n.toString())}function k(e,n){return["broods.v1",`broods.token.${e}`,...n?[`${de}${n}`]:[]]}function sn(e){if(typeof e==="string")return e;if(e&&typeof e==="object"&&typeof e.message==="string")return e.message;return e===void 0?"WebSocket stream error.":JSON.stringify(e)}function gn(e){let n=e.trim();if(/^wss?:\/\//.test(n))return h(n);return K(n)}function an(e){try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}function $n(e){let n=e.agentId??e.agent?.id??e.endpointId;if(!n)throw Error("WebSocket run requires agent, agentId, or endpointId.");return n}function Bn(e){let n=e.endpointId??e.agent?.endpointId??e.agent?.id;if(!n)throw Error("WebSocket run requires agent or endpointId.");return n}function cn(e,n){if(e.type!=="output")return e;let t=e;return n.onOutput?.(t),t.data}function un(e){return Error(`Cannot access the WebSocket service at ${e}.`)}var pn=Symbol.for("broods.resource"),dn=Symbol.for("broods.config"),fn=Symbol.for("broods.connection"),ln=/^[A-Z][A-Z0-9_]{0,63}$/,we=new Proxy((e)=>{if(!ln.test(e))throw Error("env name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");return{__beeblastEnv:!0,name:e}},{get:function(e,n,t){if(typeof n==="string"&&ln.test(n))throw Error(`env.${n} is not supported; use env("${n}")`);return Reflect.get(e,n,t)}});function Re(e){let{name:n,description:t,...o}=e;return S("agent",n,t,o)}function $e(e){return{[dn]:!0,config:e}}function Ce(e){let{name:n,description:t,...o}=e;return S("cron",n,t,o)}function Ee(e){return e}function ke(e){let{name:n,description:t,...o}=e;return S("mcp",n,t,o)}function Te(e){let{name:n,description:t,...o}=e;return S("policy",n,t,o)}function ze(e){let{name:n,description:t,...o}=e;return S("sandbox",n,t,o)}function Pe(e){let{name:n,description:t,...o}=e;return S("skill",n,t,o)}function Ie(e){let{name:n,description:t,...o}=e;return S("workspace",n,t,o)}function xe(e){return l("discord",e)}function Ae(e){return l("github",e)}function Oe(e){return l("gchat",e)}function Me(e){return l("instagram",e)}function Ne(e){return l("linear",e)}function je(e){return l("matrix",e)}function qe(e){return l("messenger",e)}function De(e){return l("pancake",e)}function Le(e){return l("slack",e)}function Ue(e){return l("teams",e)}function Fe(e){return l("telegram",e)}function Be(e){return l("twilio",e)}function He(e){return l("whatsapp",e)}function Ze(e){return l("zalo",e)}function Ve(e){let{name:n,description:t,channelId:o,guildId:r,...i}=e;return u(n,t,o,r,i)}function Ge(e){let{name:n,description:t,repo:o,...r}=e,[i,...s]=o.split("/");if(!i||s.length!==1||!s[0])throw Error(`Channel "${n}" repo must be "owner/name", not "${o}"`);return u(n,t,o,i,r)}function Ke(e){let{name:n,description:t,spaceName:o,...r}=e;return u(n,t,o,void 0,r)}function We(e){let{name:n,description:t,igsid:o,...r}=e;return u(n,t,o,void 0,r)}function Je(e){let{name:n,description:t,team:o,...r}=e;return u(n,t,o,void 0,r)}function Ye(e){let{name:n,description:t,channelId:o,...r}=e;return u(n,t,o,void 0,r)}function Xe(e){let{name:n,description:t,psid:o,...r}=e;return u(n,t,o,void 0,r)}function Qe(e){let{name:n,description:t,conversationId:o,...r}=e;return u(n,t,o,void 0,r)}function et(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function tt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function nt(e){let{name:n,description:t,chatId:o,...r}=e;return u(n,t,o,void 0,r)}function rt(e){let{name:n,description:t,from:o,...r}=e;return u(n,t,o,void 0,r)}function ot(e){let{name:n,description:t,waId:o,...r}=e;return u(n,t,o,void 0,r)}function st(e){let{name:n,description:t,chatId:o,...r}=e;return u(n,t,o,void 0,r)}function te(e){return Boolean(e&&typeof e==="object"&&e[dn])}function _(e){return Boolean(e&&typeof e==="object"&&e[fn])}function f(e){return Boolean(e&&typeof e==="object"&&e[pn])}function u(e,n,t,o,r){return S("channelRecord",e,n,{...r,externalId:t,...o?{workspaceRef:o}:{}})}function l(e,n){let{partition:t,...o}=n;return{[fn]:!0,kind:"connection",type:e,...t?{partition:t}:{},config:o}}function S(e,n,t,o){return{[pn]:!0,kind:e,name:n,...t?{description:t}:{},config:o}}
|
|
5
|
+
export{L,ae,Se,he,be,ve,U,F,y,v,x,T,B,H,b,h,M,m,N,E,Z,V,ee,G,g,_e,z,ce,j,K,fe,W,k,we,Re,$e,Ce,Ee,ke,Te,ze,Pe,Ie,xe,Ae,Oe,Me,Ne,je,qe,De,Le,Ue,Fe,Be,He,Ze,Ve,Ge,Ke,We,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,te,_,f};
|
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{U,F,y,v,x,T,B,H,b,h,M,m,E,Z,V,g,z,j,
|
|
2
|
+
import{U,F,y,v,x,T,B,H,b,h,M,m,E,Z,V,g,z,j,W,k,te,_,f}from"../chunk-yqbtb9cd.js";import{p,w}from"../chunk-a8zhzzj7.js";import{chmod as Ws,lstat as Fs,mkdir as Wn,readFile as ro,readdir as Ks,stat as Hs,writeFile as ve}from"node:fs/promises";import{createHash as so}from"node:crypto";import Ys from"node:module";import{basename as Vs,join as Me,relative as zs,resolve as N,sep as Js}from"node:path";import{watch as qs}from"node:fs";import{spawn as io}from"node:child_process";import{tmpdir as Zs}from"node:os";import{performance as Qt}from"node:perf_hooks";import{stripVTControlCharacters as Un}from"node:util";import{fileURLToPath as Po,pathToFileURL as ut}from"node:url";import{createHash as Io}from"node:crypto";import{existsSync as _o,readFileSync as jo}from"node:fs";import{mkdtemp as Do,readdir as gt,readFile as Uo,rm as No,writeFile as Lo}from"node:fs/promises";import nt from"node:module";import{tmpdir as Mo}from"node:os";import{basename as Bo,isAbsolute as Go,join as Ke,relative as $e,resolve as He}from"node:path";import{build as Wo,transformSync as pt}from"esbuild";var Jn=/\$\{([A-Z][A-Z0-9_]*)\}/;var qn={alibaba:{label:"Alibaba Qwen",modelPlaceholder:"qwen3-max"},anthropic:{label:"Anthropic",modelPlaceholder:"claude-sonnet-4-5-20250929"},azure:{label:"Azure OpenAI",modelPlaceholder:"gpt-4.1-mini"},baseten:{label:"Baseten",modelPlaceholder:"deepseek-ai/DeepSeek-V3"},bedrock:{label:"Amazon Bedrock",modelPlaceholder:"anthropic.claude-sonnet-4-5-20250929-v1:0"},cerebras:{label:"Cerebras",modelPlaceholder:"llama3.1-8b"},chatgpt:{label:"ChatGPT plan",modelPlaceholder:"gpt-5.5"},cloudflare:{label:"Cloudflare",modelPlaceholder:"@cf/meta/llama-3.3-70b-instruct-fp8-fast"},cohere:{label:"Cohere",modelPlaceholder:"command-a-03-2025"},custom:{label:"Custom OpenAI-compatible",modelPlaceholder:"gpt-oss-120b"},deepinfra:{label:"DeepInfra",modelPlaceholder:"deepseek-ai/DeepSeek-V3"},deepseek:{label:"DeepSeek",modelPlaceholder:"deepseek-chat"},fireworks:{label:"Fireworks",modelPlaceholder:"accounts/fireworks/models/deepseek-v3"},google:{label:"Google",modelPlaceholder:"gemini-2.5-flash"},groq:{label:"Groq",modelPlaceholder:"llama-3.3-70b-versatile"},huggingface:{label:"Hugging Face",modelPlaceholder:"meta-llama/Llama-3.3-70B-Instruct"},llmgateway:{label:"LLM Gateway",modelPlaceholder:"openai/gpt-4.1-mini"},minimax:{label:"MiniMax",modelPlaceholder:"MiniMax-M2.7"},mistral:{label:"Mistral",modelPlaceholder:"mistral-large-latest"},moonshotai:{label:"Moonshot AI Kimi",modelPlaceholder:"kimi-k2.6"},ollama:{label:"Ollama",modelPlaceholder:"gpt-oss:120b"},openai:{label:"OpenAI",modelPlaceholder:"gpt-4.1-mini"},openrouter:{label:"OpenRouter",modelPlaceholder:"anthropic/claude-sonnet-4.5"},perplexity:{label:"Perplexity",modelPlaceholder:"low"},togetherai:{label:"Together.ai",modelPlaceholder:"deepseek-ai/DeepSeek-V3"},v0:{label:"Vercel v0",modelPlaceholder:"v0-1.0-md"},vercel:{label:"Vercel AI Gateway",modelPlaceholder:"openai/gpt-4.1-mini"},vertex:{label:"Google Vertex AI",modelPlaceholder:"gemini-2.5-flash"},xai:{label:"xAI Grok",modelPlaceholder:"grok-4"},zai:{label:"Z.ai GLM",modelPlaceholder:"glm-4.7"}},Zn=Object.keys(qn);function Xn(e){return Object.hasOwn(qn,e)}var Co=/(?:^|[\n;])\s*import\s+(?:[^;"'`]*?\s+from\s*)?["'](?!\.{1,2}\/|\/|node:)[^"']+["']|import\s*\(\s*["'](?!\.{1,2}\/|\/|node:)[^"']+["']\s*\)/,Oo=/(?:import\s+(?:[^;"'`]*?\s+from\s*)?["']node:|import\s*\(\s*["']node:)/,Ao=/(?<![.\w$])(?:process|Buffer)\s*(?:\?\.|\.|\[)/,xo=[/\b(?:__)?require\s*\(/,/(?<![.\w$])setImmediate\s*\(/,Oo,Ao,/\b__dirname\b/,Co],To=/(?<![.\w$])eval\s*\(|\bnew\s+Function\s*\(/;function Qn(e){return![...xo,To].some((n)=>n.test(e))}var dn=32;var un=["conversation","agent"];function et(e){return un.some((n)=>n===e)}var xe="*",Fo=new RegExp(Jn.source,"g"),Ko=`const passthrough = (input) => input;
|
|
3
3
|
export const defineAgent = passthrough;
|
|
4
4
|
export const defineBroods = passthrough;
|
|
5
5
|
export const defineCron = passthrough;
|
|
@@ -81,13 +81,13 @@ export const manifest = ${JSON.stringify(e,null,2)} as const;
|
|
|
81
81
|
`}function _e(e,n,t){let o=Object.keys(n);if(o.length===0)return"{}";return`{
|
|
82
82
|
${o.map((s)=>` ${hn(t?.[s]??s)}: ids.${e}[${JSON.stringify(s)}],`).join(`
|
|
83
83
|
`)}
|
|
84
|
-
}`}function hn(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?e:JSON.stringify(e)}function St(e,n){return`${e}…${n.slice(-4)}`}var wn=["ap-southeast-1","eu-west-1","us-east-1"],$t=["eu-west-1"];var Ct=1,Ot=0,Rt=60000,Je=15000;function Q(e,n){return new Promise((t)=>{if(n?.aborted)return t();let o=setTimeout(t,e);n?.addEventListener("abort",()=>{clearTimeout(o),t()},{once:!0})})}function ie(){let e=globalThis.WebSocket;if(!e)throw Error("WebSocket is not available in this environment.");return e}class O extends Error{}async function*qe(e,n={}){let t=new Set,o=500,r=0,s=Date.now();while(!n.signal?.aborted){let i=!1,a="the log stream closed";try{for await(let c of zr(e,n,()=>{i=!0})){let d=`${c.ts}|${c.eventType}|${c.message}`;if(t.has(d))continue;if(t.add(d),t.size>5000)t.delete(t.values().next().value);yield c}}catch(c){if(n.signal?.aborted)return;if(a=c instanceof Error?c.message:String(c),c instanceof O||/unauthorized|invalid websocket token|scope does not match/i.test(a))throw c}if(n.signal?.aborted)return;if(i)o=500,r=0,s=Date.now();if(!n.keepReconnecting&&Date.now()-s>=Rt)throw Error(`Gave up reconnecting to the live logs after ${Rt/1000} s. Last error: ${a}`);r+=1,n.onReconnect?.(r,a),await Q(o,n.signal),o=Math.min(o*2,5000)}}async function*zr(e,n,t){let{backfill:o=0,minLevel:r,sandboxId:s,signal:i}=n,a=n.liveOnly??o<=0;if(i?.aborted)return;let c=[],d=null,l=!1,u=null,S=()=>{u?.(),u=null},{socket:C,url:P}=xt(e,await e.credential()),A=setTimeout(()=>{d=Error(`The observability gateway did not answer within ${Je/1000} s.`),l=!0,S()},Je),I=()=>{if(clearTimeout(A),C.readyState===Ct||C.readyState===Ot)C.close(1000,"client closed");i?.removeEventListener("abort",me)},me=()=>{l=!0,S(),I()};i?.addEventListener("abort",me,{once:!0}),C.onopen=()=>{if(i?.aborted){I();return}let X={type:"subscribe",stream:"logs",...o>0?{backfill:o}:{},...a?{liveOnly:!0}:{},...r!==void 0?{minLevel:r}:{},...s!==void 0?{sandboxId:s}:{}};C.send(JSON.stringify(X))},C.onmessage=(X)=>{let he=Pt(X.data);if(!he)return;if(clearTimeout(A),he.type!=="error")t();switch(he.type){case"backfill":if(he.stream==="logs"){for(let Ro of he.entries)c.push(Ro);S()}break;case"log":c.push(he.entry),S();break;case"error":d=Error(`Observability gateway error: ${he.error}`),l=!0,S();break;case"ready":break;default:break}},C.onerror=()=>{d=Error(`Cannot connect to the observability gateway at ${P}.`),l=!0,S()},C.onclose=(X)=>{if(!l){if(X.code!==1000)d=Tt(X);l=!0,S()}};try{while(!0){if(c.length>0){yield c.shift();continue}if(d)throw d;if(l)return;await new Promise((X)=>{u=X})}}finally{I()}}async function At(e,n){let{socket:t,url:o}=xt(e,await e.credential());return new Promise((r,s)=>{let i=!1,a=(l)=>{if(i)return;if(i=!0,clearTimeout(d),t.readyState===Ct||t.readyState===Ot)t.close(1000,"client closed");l()},c=(l)=>a(()=>s(l)),d=setTimeout(()=>{c(Error(`The observability gateway did not answer within ${Je/1000} s.`))},Je);t.onopen=()=>{let l={type:"fetchTrace",traceId:n};t.send(JSON.stringify(l))},t.onmessage=(l)=>{let u=Pt(l.data);if(u?.type==="error")c(Error(`Observability gateway error: ${u.error}`));else if(u?.type==="backfill"&&u.stream==="traces"){let S=u.entries;if(u.error)c(Error(u.error));else a(()=>r(S))}},t.onerror=()=>{c(Error(`Cannot connect to the observability gateway at ${o}.`))},t.onclose=(l)=>c(Tt(l))})}function xt(e,n){let t=Jr(e.baseUrl,e.project,e.stage);return{socket:new(ie())(t,k(n)),url:t}}function Tt(e){return Error(e.reason?`Observability WebSocket closed: ${e.reason}`:`Observability WebSocket closed with code ${e.code}.`)}function Jr(e,n,t){return`${K(e)}/v1/projects/${encodeURIComponent(n)}/stages/${encodeURIComponent(t)}/observability/ws`}function Pt(e){if(typeof e!=="string")return null;try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}var qr=new Set(["bundle","bundleStorageId","contentBase64"]),Zr=new Set(["hook","mcp","skill"]),Xr=30000;class Xe extends Error{}class Qe extends Error{}class J{baseUrl;token;fetchImpl;constructor(e){this.baseUrl=h(e.baseUrl),this.token=e.token,this.fetchImpl=e.fetch??fetch}async getManifest(e,n){let t=await this.request(e,n,"/manifest",{method:"GET"});if(t.status===404)return null;return await W(t,"Fetch manifest failed"),await t.json()}async putManifest(e,n,t=!1,o){let r=await this.externalizeLargeMcpBundles(e),s=await this.request(e.project,e.stage,"/manifest",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({manifest:r,prune:n,rotateRuntimeKey:t,...o!==void 0?{revision:o}:{}})},null);return await W(s,"Sync manifest failed"),await s.json()}async externalizeLargeMcpBundles(e){if(e.resources.every((t)=>jt(t)===null))return e;let n=await Promise.all(e.resources.map(async(t)=>{let o=jt(t);if(o===null)return t;let{bundle:r,...s}=t.config,i=await this.uploadMcpBundle(e.project,e.stage,o);return{...t,config:{...s,bundleStorageId:i,sha256:Pe(o)}}}));return{...e,resources:n}}async uploadMcpBundle(e,n,t){let o=await this.request(e,n,"/mcp-bundle-uploads",{method:"POST"});await W(o,"Mint bundle upload URL failed");let{uploadUrl:r}=await o.json();if(!r)throw Error("Mint bundle upload URL failed: response omitted uploadUrl");let s=await this.send(r,{method:"POST",headers:{"Content-Type":"application/javascript"},body:t},null);await W(s,"Bundle upload failed");let{storageId:i}=await s.json();if(!i)throw Error("Bundle upload failed: response omitted storageId");return i}async getRuntimeKey(e,n){let t=await this.request(e,n,"/runtime-key",{method:"GET"});if(t.status===404)return null;await W(t,"Fetch runtime key failed");let o=await t.json();if(!o.apiKey)throw Error("Fetch runtime key failed: response omitted apiKey");return{apiKey:o.apiKey,keyHint:o.keyHint??"",...o.endpointId?{endpointId:o.endpointId}:{},...o.projectSlug?{projectSlug:o.projectSlug}:{},...o.stageSlug?{stageSlug:o.stageSlug}:{}}}async rotateUserTokenSecret(e,n){let t=await this.request(e,n,"/user-token-secret",{method:"POST"});if(t.status===404)return null;await W(t,"Rotate user token signing secret failed");let o=await t.json();if(!o.secret||!o.hint)throw Error("Rotate user token signing secret failed: response omitted the secret");return{secret:o.secret,hint:o.hint}}async setEnv(e,n,t,o){let r=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({value:o})});await W(r,"Set environment variable failed")}async listEnv(e,n){let t=await this.request(e,n,"/env",{method:"GET"});return await W(t,"List environment variables failed"),(await t.json()).variables??[]}async getEnv(e,n,t){let o=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"GET"});if(o.status===404)return null;return await W(o,"Read environment variable failed"),(await o.json()).value??null}async removeEnv(e,n,t){let o=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"DELETE"});await W(o,"Remove environment variable failed")}async getOnboarding(){let e=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(e,"/v1/account/onboarding","broods org"),await W(e,"Fetch CLI onboarding context failed"),await e.json()}async selectOnboardingOrg(e){let n=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({orgId:e})});return await W(n,"Select CLI org failed"),await n.json()}async listStages(e){let n=await this.send(`${this.baseUrl}/v1/account/stages?project=${encodeURIComponent(e)}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(n,"/v1/account/stages","broods stage"),await W(n,"List stages failed"),(await n.json()).stages??[]}async createStage(e,n,t){let o=await this.send(`${this.baseUrl}/v1/account/stages`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({project:e,name:n,...t?{from:t}:{}})});return Re(o,"/v1/account/stages","broods stage"),await W(o,"Create stage failed"),await o.json()}async mintStageSession(e,n){let t=await this.send(`${this.baseUrl}/v1/account/stage-session`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({project:e,stage:n})});Re(t,"/v1/account/stage-session","broods logs");try{await W(t,"Open stage session failed")}catch(o){if(t.status===401||t.status===404)throw new O(o instanceof Error?o.message:String(o));throw o}return await t.json()}async listProjects(){let e=await this.send(`${this.baseUrl}/v1/account/projects`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(e,"/v1/account/projects","broods project"),await W(e,"List projects failed"),(await e.json()).projects??[]}async deleteProject(e){let n=await this.send(`${this.baseUrl}/v1/account/projects?projectId=${encodeURIComponent(e)}`,{method:"DELETE",headers:{Authorization:`Bearer ${this.token}`}});if(Re(n,"/v1/account/projects","broods project"),n.status===404)return null;return await W(n,"Delete project failed"),(await n.json()).deleted??null}async createOnboardingOrg(e){let n=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({createOrgName:e})});return await W(n,"Create CLI org failed"),await n.json()}async request(e,n,t,o,r){let s=`${this.baseUrl}/v1/account/projects/${encodeURIComponent(e)}/stages/${encodeURIComponent(n)}${t}`;return await this.send(s,{...o,headers:{Authorization:`Bearer ${this.token}`,...o.headers}},r)}async send(e,n,t){return await en(e,n,{fetch:this.fetchImpl,timeoutMs:t})}}async function en(e,n,t={}){let o=t.fetch??fetch,r=t.timeoutMs===void 0?Xr:t.timeoutMs;try{return await o(e,r===null?n:{...n,signal:AbortSignal.timeout(r)})}catch(s){throw Error(`Cannot reach ${new URL(e).origin}: ${ns(s,r)}`,{cause:s})}}function kn(e,n){let t=new Map((n?.resources??[]).map((d)=>[`${d.kind}:${d.name}`,d])),o=new Map(e.resources.map((d)=>[`${d.kind}:${d.name}`,d])),r=[],s=[],i=[];for(let[d,l]of o){let u=t.get(d);if(!u)s.push({key:d,resource:l});else if(Ze(yn(u))!==Ze(yn(l)))r.push({operation:"update",kind:l.kind,name:l.name})}for(let[d,l]of t)if(!o.has(d))i.push({key:d,resource:l});let a=new Set,c=new Set;for(let d of s){let l=i.find((u)=>!a.has(u.key)&&Qr(d.resource.kind)&&d.resource.kind===u.resource.kind&&Ze(_t(d.resource))===Ze(_t(u.resource)));if(!l)continue;c.add(d.key),a.add(l.key),r.push({operation:"rename",kind:d.resource.kind,name:d.resource.name,previousName:l.resource.name})}for(let{key:d,resource:l}of s)if(!c.has(d))r.push({operation:"create",kind:l.kind,name:l.name});for(let{key:d,resource:l}of i)if(!a.has(d))r.push({operation:"delete",kind:l.kind,name:l.name});return r.sort((d,l)=>It(d).localeCompare(It(l)))}function It(e){return`${{create:0,rename:1,update:2,delete:3}[e.operation]}:${e.kind}:${e.previousName??""}:${e.name}`}function Qr(e){return e==="agent"||e==="workspace"||e==="sandbox"||e==="policy"}function bn(e){if(Array.isArray(e))return e.map(bn);if(e&&typeof e==="object"){let n=e;if(n.__beeblastEnv===!0&&typeof n.name==="string")return`\${${n.name}}`;return Object.fromEntries(Object.entries(n).map(([t,o])=>[t,bn(o)]))}return e}function _t(e){let n=yn(e),{name:t,...o}=n;return o}function yn(e){let n=bn(e);if(!Zr.has(e.kind))return n;return{...n,config:En(n.config)}}function vn(e){if(Array.isArray(e))return e.map(vn);if(e&&typeof e==="object")return Object.fromEntries(Object.entries(e).sort(([n],[t])=>n.localeCompare(t)).map(([n,t])=>[n,vn(t)]));return e}function Ze(e){return JSON.stringify(vn(e))}function En(e){if(Array.isArray(e))return e.map(En);if(e&&typeof e==="object")return Object.fromEntries(Object.entries(e).flatMap(([n,t])=>{if(qr.has(n))return[];return[[n,En(t)]]}));return e}async function W(e,n){if(e.ok)return;let t=await e.text(),{message:o=t,code:r}=es(t);if(r==="manifest_conflict")throw new Xe(o);let s=e.status===401?"\nRun `broods login` to sign in again.":"";throw Error(`${n}: ${e.status} ${o}${s}`)}function es(e){let n;try{n=JSON.parse(e)}catch{return{}}let t=typeof n==="object"&&n!==null&&"error"in n?n.error:void 0;if(typeof t!=="object"||t===null)return{};return{..."message"in t&&typeof t.message==="string"?{message:t.message}:{},..."code"in t&&typeof t.code==="string"?{code:t.code}:{}}}function Re(e,n,t){if(e.status!==404)return;if((e.headers.get("Content-Type")??"").includes("application/json"))return;throw new Qe(`This broods server is older than your CLI and does not support \`${t}\` yet (no ${n} route).`)}function ns(e,n){if(!(e instanceof Error))return String(e);if(e.name==="TimeoutError"&&n!==null)return`no answer within ${n/1000} s`;let t=e.cause;if(!(t instanceof Error))return e.message;if(t.message)return t.message;return"code"in t&&typeof t.code==="string"?t.code:e.message}function jt(e){if(e.kind!=="mcp")return null;let n=e.config?.bundle;if(typeof n!=="string")return null;return Buffer.byteLength(n)>mn?n:null}var nn=["chatgpt"];var we={chatgpt:{label:"ChatGPT plan",description:"Run agents on model.provider chatgpt with your ChatGPT plan",authorizeUrl:"https://auth.openai.com/api/accounts/authorize",tokenUrl:"https://auth.openai.com/api/accounts/oauth/token",revokeUrl:"https://auth.openai.com/api/accounts/oauth/revoke",jwksUrl:"https://auth.openai.com/.well-known/jwks.json",issuer:"https://auth.openai.com",scopes:["openid","profile","email","offline_access","resource.invoke","chatgpt.tokens.use.direct"],resource:"https://api.openai.com/v1",requiredScope:"chatgpt.tokens.use.direct",selfHostedOnly:"ChatGPT plan usage is only available on self-hosted Broods for now. Use an OpenAI API key with the `openai` provider instead.",managedOptIn:"CHATGPT_PLAN_ENABLED",modelsUrl:"https://api.openai.com/v1/models",usageUrl:"https://chatgpt.com/settings/usage"}};function Sn(e){return nn.some((n)=>n===e)}import{createHash as Es,randomBytes as ks,randomUUID as Ht}from"node:crypto";import{createServer as ls}from"node:http";import{createHash as ds,randomBytes as us,randomUUID as gs}from"node:crypto";import{spawn as ps}from"node:child_process";import{createInterface as De}from"node:readline/promises";import{stdin as ce,stdout as ae}from"node:process";import{Writable as fs}from"node:stream";function Ce(e,n,t={}){let o=`${n?"*":" "} ${e}`;return n?L(o,"\x1B[1m\x1B[36m",ne(t)):o}function Dt(e,n={}){let t=ne(n),o=(i)=>L(i.padEnd(9),"\x1B[2m",t),r=!e.loggedIn?L("not logged in","\x1B[33m",t):e.org??L("unknown, run broods whoami","\x1B[2m",t),s=e.project??`none ${L(`(${e.projectGuess} from folder name)`,"\x1B[2m",t)}`;return[` ${o("org")}${r}`,` ${o("project")}${s}`,` ${o("stage")}${Bt(e.stage,t)}`,` ${o("server")}${e.server}`]}function ts(e,n={}){let t=ne(n),o=Gt(e.stage),r=o==="Development",s=L("▌",r?"\x1B[32m":"\x1B[33m",t),i=t?`${r?"\x1B[42m\x1B[30m\x1B[1m":"\x1B[43m\x1B[30m\x1B[1m"} ${o} \x1B[0m`:`[${o}]`,a=t?L("dashboard","\x1B[4m",t):"dashboard",c=`${e.dashboardUrl}?project=${encodeURIComponent(e.project)}&stage=${encodeURIComponent(e.stage)}`,d=L(c,"\x1B[2m\x1B[4m",t);return[`${s} Syncing ${o}: ${L(e.project,"",t)}`,`${s} ${i} ${e.stage} (${a})`,`${s} ${L("└─","\x1B[2m",t)} ${d}`].join(`
|
|
84
|
+
}`}function hn(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?e:JSON.stringify(e)}function St(e,n){return`${e}…${n.slice(-4)}`}var wn=["ap-southeast-1","eu-west-1","us-east-1"],$t=["eu-west-1"];var Ct=1,Ot=0,Rt=60000,Je=15000;function Q(e,n){return new Promise((t)=>{if(n?.aborted)return t();let o=setTimeout(t,e);n?.addEventListener("abort",()=>{clearTimeout(o),t()},{once:!0})})}function ie(){let e=globalThis.WebSocket;if(!e)throw Error("WebSocket is not available in this environment.");return e}class O extends Error{}async function*qe(e,n={}){let t=new Set,o=500,r=0,s=Date.now();while(!n.signal?.aborted){let i=!1,a="the log stream closed";try{for await(let c of zr(e,n,()=>{i=!0})){let d=`${c.ts}|${c.eventType}|${c.message}`;if(t.has(d))continue;if(t.add(d),t.size>5000)t.delete(t.values().next().value);yield c}}catch(c){if(n.signal?.aborted)return;if(a=c instanceof Error?c.message:String(c),c instanceof O||/unauthorized|invalid websocket token|scope does not match/i.test(a))throw c}if(n.signal?.aborted)return;if(i)o=500,r=0,s=Date.now();if(!n.keepReconnecting&&Date.now()-s>=Rt)throw Error(`Gave up reconnecting to the live logs after ${Rt/1000} s. Last error: ${a}`);r+=1,n.onReconnect?.(r,a),await Q(o,n.signal),o=Math.min(o*2,5000)}}async function*zr(e,n,t){let{backfill:o=0,minLevel:r,sandboxId:s,signal:i}=n,a=n.liveOnly??o<=0;if(i?.aborted)return;let c=[],d=null,l=!1,u=null,S=()=>{u?.(),u=null},{socket:C,url:P}=xt(e,await e.credential()),A=setTimeout(()=>{d=Error(`The observability gateway did not answer within ${Je/1000} s.`),l=!0,S()},Je),I=()=>{if(clearTimeout(A),C.readyState===Ct||C.readyState===Ot)C.close(1000,"client closed");i?.removeEventListener("abort",me)},me=()=>{l=!0,S(),I()};i?.addEventListener("abort",me,{once:!0}),C.onopen=()=>{if(i?.aborted){I();return}let X={type:"subscribe",stream:"logs",...o>0?{backfill:o}:{},...a?{liveOnly:!0}:{},...r!==void 0?{minLevel:r}:{},...s!==void 0?{sandboxId:s}:{}};C.send(JSON.stringify(X))},C.onmessage=(X)=>{let he=Pt(X.data);if(!he)return;if(clearTimeout(A),he.type!=="error")t();switch(he.type){case"backfill":if(he.stream==="logs"){for(let Ro of he.entries)c.push(Ro);S()}break;case"log":c.push(he.entry),S();break;case"error":d=Error(`Observability gateway error: ${he.error}`),l=!0,S();break;case"ready":break;default:break}},C.onerror=()=>{d=Error(`Cannot connect to the observability gateway at ${P}.`),l=!0,S()},C.onclose=(X)=>{if(!l){if(X.code!==1000)d=Tt(X);l=!0,S()}};try{while(!0){if(c.length>0){yield c.shift();continue}if(d)throw d;if(l)return;await new Promise((X)=>{u=X})}}finally{I()}}async function At(e,n){let{socket:t,url:o}=xt(e,await e.credential());return new Promise((r,s)=>{let i=!1,a=(l)=>{if(i)return;if(i=!0,clearTimeout(d),t.readyState===Ct||t.readyState===Ot)t.close(1000,"client closed");l()},c=(l)=>a(()=>s(l)),d=setTimeout(()=>{c(Error(`The observability gateway did not answer within ${Je/1000} s.`))},Je);t.onopen=()=>{let l={type:"fetchTrace",traceId:n};t.send(JSON.stringify(l))},t.onmessage=(l)=>{let u=Pt(l.data);if(u?.type==="error")c(Error(`Observability gateway error: ${u.error}`));else if(u?.type==="backfill"&&u.stream==="traces"){let S=u.entries;if(u.error)c(Error(u.error));else a(()=>r(S))}},t.onerror=()=>{c(Error(`Cannot connect to the observability gateway at ${o}.`))},t.onclose=(l)=>c(Tt(l))})}function xt(e,n){let t=Jr(e.baseUrl,e.project,e.stage);return{socket:new(ie())(t,k(n)),url:t}}function Tt(e){return Error(e.reason?`Observability WebSocket closed: ${e.reason}`:`Observability WebSocket closed with code ${e.code}.`)}function Jr(e,n,t){return`${W(e)}/v1/projects/${encodeURIComponent(n)}/stages/${encodeURIComponent(t)}/observability/ws`}function Pt(e){if(typeof e!=="string")return null;try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}var qr=new Set(["bundle","bundleStorageId","contentBase64"]),Zr=new Set(["hook","mcp","skill"]),Xr=30000;class Xe extends Error{}class Qe extends Error{}class J{baseUrl;token;fetchImpl;constructor(e){this.baseUrl=h(e.baseUrl),this.token=e.token,this.fetchImpl=e.fetch??fetch}async getManifest(e,n){let t=await this.request(e,n,"/manifest",{method:"GET"});if(t.status===404)return null;return await K(t,"Fetch manifest failed"),await t.json()}async putManifest(e,n,t=!1,o){let r=await this.externalizeLargeMcpBundles(e),s=await this.request(e.project,e.stage,"/manifest",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({manifest:r,prune:n,rotateRuntimeKey:t,...o!==void 0?{revision:o}:{}})},null);return await K(s,"Sync manifest failed"),await s.json()}async externalizeLargeMcpBundles(e){if(e.resources.every((t)=>jt(t)===null))return e;let n=await Promise.all(e.resources.map(async(t)=>{let o=jt(t);if(o===null)return t;let{bundle:r,...s}=t.config,i=await this.uploadMcpBundle(e.project,e.stage,o);return{...t,config:{...s,bundleStorageId:i,sha256:Pe(o)}}}));return{...e,resources:n}}async uploadMcpBundle(e,n,t){let o=await this.request(e,n,"/mcp-bundle-uploads",{method:"POST"});await K(o,"Mint bundle upload URL failed");let{uploadUrl:r}=await o.json();if(!r)throw Error("Mint bundle upload URL failed: response omitted uploadUrl");let s=await this.send(r,{method:"POST",headers:{"Content-Type":"application/javascript"},body:t},null);await K(s,"Bundle upload failed");let{storageId:i}=await s.json();if(!i)throw Error("Bundle upload failed: response omitted storageId");return i}async getRuntimeKey(e,n){let t=await this.request(e,n,"/runtime-key",{method:"GET"});if(t.status===404)return null;await K(t,"Fetch runtime key failed");let o=await t.json();if(!o.apiKey)throw Error("Fetch runtime key failed: response omitted apiKey");return{apiKey:o.apiKey,keyHint:o.keyHint??"",...o.endpointId?{endpointId:o.endpointId}:{},...o.projectSlug?{projectSlug:o.projectSlug}:{},...o.stageSlug?{stageSlug:o.stageSlug}:{}}}async rotateUserTokenSecret(e,n){let t=await this.request(e,n,"/user-token-secret",{method:"POST"});if(t.status===404)return null;await K(t,"Rotate user token signing secret failed");let o=await t.json();if(!o.secret||!o.hint)throw Error("Rotate user token signing secret failed: response omitted the secret");return{secret:o.secret,hint:o.hint}}async setEnv(e,n,t,o){let r=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({value:o})});await K(r,"Set environment variable failed")}async listEnv(e,n){let t=await this.request(e,n,"/env",{method:"GET"});return await K(t,"List environment variables failed"),(await t.json()).variables??[]}async getEnv(e,n,t){let o=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"GET"});if(o.status===404)return null;return await K(o,"Read environment variable failed"),(await o.json()).value??null}async removeEnv(e,n,t){let o=await this.request(e,n,`/env/${encodeURIComponent(t)}`,{method:"DELETE"});await K(o,"Remove environment variable failed")}async getOnboarding(){let e=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(e,"/v1/account/onboarding","broods org"),await K(e,"Fetch CLI onboarding context failed"),await e.json()}async selectOnboardingOrg(e){let n=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({orgId:e})});return await K(n,"Select CLI org failed"),await n.json()}async listStages(e){let n=await this.send(`${this.baseUrl}/v1/account/stages?project=${encodeURIComponent(e)}`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(n,"/v1/account/stages","broods stage"),await K(n,"List stages failed"),(await n.json()).stages??[]}async createStage(e,n,t){let o=await this.send(`${this.baseUrl}/v1/account/stages`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({project:e,name:n,...t?{from:t}:{}})});return Re(o,"/v1/account/stages","broods stage"),await K(o,"Create stage failed"),await o.json()}async mintStageSession(e,n){let t=await this.send(`${this.baseUrl}/v1/account/stage-session`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({project:e,stage:n})});Re(t,"/v1/account/stage-session","broods logs");try{await K(t,"Open stage session failed")}catch(o){if(t.status===401||t.status===404)throw new O(o instanceof Error?o.message:String(o));throw o}return await t.json()}async listProjects(){let e=await this.send(`${this.baseUrl}/v1/account/projects`,{method:"GET",headers:{Authorization:`Bearer ${this.token}`}});return Re(e,"/v1/account/projects","broods project"),await K(e,"List projects failed"),(await e.json()).projects??[]}async deleteProject(e){let n=await this.send(`${this.baseUrl}/v1/account/projects?projectId=${encodeURIComponent(e)}`,{method:"DELETE",headers:{Authorization:`Bearer ${this.token}`}});if(Re(n,"/v1/account/projects","broods project"),n.status===404)return null;return await K(n,"Delete project failed"),(await n.json()).deleted??null}async createOnboardingOrg(e){let n=await this.send(`${this.baseUrl}/v1/account/onboarding`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"},body:JSON.stringify({createOrgName:e})});return await K(n,"Create CLI org failed"),await n.json()}async request(e,n,t,o,r){let s=`${this.baseUrl}/v1/account/projects/${encodeURIComponent(e)}/stages/${encodeURIComponent(n)}${t}`;return await this.send(s,{...o,headers:{Authorization:`Bearer ${this.token}`,...o.headers}},r)}async send(e,n,t){return await en(e,n,{fetch:this.fetchImpl,timeoutMs:t})}}async function en(e,n,t={}){let o=t.fetch??fetch,r=t.timeoutMs===void 0?Xr:t.timeoutMs;try{return await o(e,r===null?n:{...n,signal:AbortSignal.timeout(r)})}catch(s){throw Error(`Cannot reach ${new URL(e).origin}: ${ns(s,r)}`,{cause:s})}}function kn(e,n){let t=new Map((n?.resources??[]).map((d)=>[`${d.kind}:${d.name}`,d])),o=new Map(e.resources.map((d)=>[`${d.kind}:${d.name}`,d])),r=[],s=[],i=[];for(let[d,l]of o){let u=t.get(d);if(!u)s.push({key:d,resource:l});else if(Ze(yn(u))!==Ze(yn(l)))r.push({operation:"update",kind:l.kind,name:l.name})}for(let[d,l]of t)if(!o.has(d))i.push({key:d,resource:l});let a=new Set,c=new Set;for(let d of s){let l=i.find((u)=>!a.has(u.key)&&Qr(d.resource.kind)&&d.resource.kind===u.resource.kind&&Ze(_t(d.resource))===Ze(_t(u.resource)));if(!l)continue;c.add(d.key),a.add(l.key),r.push({operation:"rename",kind:d.resource.kind,name:d.resource.name,previousName:l.resource.name})}for(let{key:d,resource:l}of s)if(!c.has(d))r.push({operation:"create",kind:l.kind,name:l.name});for(let{key:d,resource:l}of i)if(!a.has(d))r.push({operation:"delete",kind:l.kind,name:l.name});return r.sort((d,l)=>It(d).localeCompare(It(l)))}function It(e){return`${{create:0,rename:1,update:2,delete:3}[e.operation]}:${e.kind}:${e.previousName??""}:${e.name}`}function Qr(e){return e==="agent"||e==="workspace"||e==="sandbox"||e==="policy"}function bn(e){if(Array.isArray(e))return e.map(bn);if(e&&typeof e==="object"){let n=e;if(n.__beeblastEnv===!0&&typeof n.name==="string")return`\${${n.name}}`;return Object.fromEntries(Object.entries(n).map(([t,o])=>[t,bn(o)]))}return e}function _t(e){let n=yn(e),{name:t,...o}=n;return o}function yn(e){let n=bn(e);if(!Zr.has(e.kind))return n;return{...n,config:En(n.config)}}function vn(e){if(Array.isArray(e))return e.map(vn);if(e&&typeof e==="object")return Object.fromEntries(Object.entries(e).sort(([n],[t])=>n.localeCompare(t)).map(([n,t])=>[n,vn(t)]));return e}function Ze(e){return JSON.stringify(vn(e))}function En(e){if(Array.isArray(e))return e.map(En);if(e&&typeof e==="object")return Object.fromEntries(Object.entries(e).flatMap(([n,t])=>{if(qr.has(n))return[];return[[n,En(t)]]}));return e}async function K(e,n){if(e.ok)return;let t=await e.text(),{message:o=t,code:r}=es(t);if(r==="manifest_conflict")throw new Xe(o);let s=e.status===401?"\nRun `broods login` to sign in again.":"";throw Error(`${n}: ${e.status} ${o}${s}`)}function es(e){let n;try{n=JSON.parse(e)}catch{return{}}let t=typeof n==="object"&&n!==null&&"error"in n?n.error:void 0;if(typeof t!=="object"||t===null)return{};return{..."message"in t&&typeof t.message==="string"?{message:t.message}:{},..."code"in t&&typeof t.code==="string"?{code:t.code}:{}}}function Re(e,n,t){if(e.status!==404)return;if((e.headers.get("Content-Type")??"").includes("application/json"))return;throw new Qe(`This broods server is older than your CLI and does not support \`${t}\` yet (no ${n} route).`)}function ns(e,n){if(!(e instanceof Error))return String(e);if(e.name==="TimeoutError"&&n!==null)return`no answer within ${n/1000} s`;let t=e.cause;if(!(t instanceof Error))return e.message;if(t.message)return t.message;return"code"in t&&typeof t.code==="string"?t.code:e.message}function jt(e){if(e.kind!=="mcp")return null;let n=e.config?.bundle;if(typeof n!=="string")return null;return Buffer.byteLength(n)>mn?n:null}var nn=["chatgpt"];var we={chatgpt:{label:"ChatGPT plan",description:"Run agents on model.provider chatgpt with your ChatGPT plan",authorizeUrl:"https://auth.openai.com/api/accounts/authorize",tokenUrl:"https://auth.openai.com/api/accounts/oauth/token",revokeUrl:"https://auth.openai.com/api/accounts/oauth/revoke",jwksUrl:"https://auth.openai.com/.well-known/jwks.json",issuer:"https://auth.openai.com",scopes:["openid","profile","email","offline_access","resource.invoke","chatgpt.tokens.use.direct"],resource:"https://api.openai.com/v1",requiredScope:"chatgpt.tokens.use.direct",selfHostedOnly:"ChatGPT plan usage is only available on self-hosted Broods for now. Use an OpenAI API key with the `openai` provider instead.",managedOptIn:"CHATGPT_PLAN_ENABLED",modelsUrl:"https://api.openai.com/v1/models",usageUrl:"https://chatgpt.com/settings/usage"}};function Sn(e){return nn.some((n)=>n===e)}import{createHash as Es,randomBytes as ks,randomUUID as Ht}from"node:crypto";import{createServer as ls}from"node:http";import{createHash as ds,randomBytes as us,randomUUID as gs}from"node:crypto";import{spawn as ps}from"node:child_process";import{createInterface as De}from"node:readline/promises";import{stdin as ce,stdout as ae}from"node:process";import{Writable as fs}from"node:stream";function Ce(e,n,t={}){let o=`${n?"*":" "} ${e}`;return n?L(o,"\x1B[1m\x1B[36m",ne(t)):o}function Dt(e,n={}){let t=ne(n),o=(i)=>L(i.padEnd(9),"\x1B[2m",t),r=!e.loggedIn?L("not logged in","\x1B[33m",t):e.org??L("unknown, run broods whoami","\x1B[2m",t),s=e.project??`none ${L(`(${e.projectGuess} from folder name)`,"\x1B[2m",t)}`;return[` ${o("org")}${r}`,` ${o("project")}${s}`,` ${o("stage")}${Bt(e.stage,t)}`,` ${o("server")}${e.server}`]}function ts(e,n={}){let t=ne(n),o=Gt(e.stage),r=o==="Development",s=L("▌",r?"\x1B[32m":"\x1B[33m",t),i=t?`${r?"\x1B[42m\x1B[30m\x1B[1m":"\x1B[43m\x1B[30m\x1B[1m"} ${o} \x1B[0m`:`[${o}]`,a=t?L("dashboard","\x1B[4m",t):"dashboard",c=`${e.dashboardUrl}?project=${encodeURIComponent(e.project)}&stage=${encodeURIComponent(e.stage)}`,d=L(c,"\x1B[2m\x1B[4m",t);return[`${s} Syncing ${o}: ${L(e.project,"",t)}`,`${s} ${i} ${e.stage} (${a})`,`${s} ${L("└─","\x1B[2m",t)} ${d}`].join(`
|
|
85
85
|
`)}function os(e,n={}){let t=ne(n);return e.map((o)=>{let r=cs(o.operation,t);if(o.operation==="rename"&&o.previousName)return` ${r} ${o.kind}:${o.previousName} -> ${o.name}`;return` ${r} ${o.kind}:${o.name}`})}function rs(e,n={}){let t=ne(n),o=L("▌","\x1B[32m",t),r=L("↑","\x1B[32m",t);return`${o} ${r} Synced ${e.length} env var(s) from .env.local: ${e.join(", ")}`}function ss(e,n={}){return`${L("✖","\x1B[31m",ne(n))} ${e}`}function Ut(e,n={}){let t=ne(n),o=Math.max(...e.map(([r])=>r.length))+2;return e.map(([r,s])=>` ${r.padEnd(o)}${L(s,"\x1B[2m",t)}`)}function is(e,n={}){let t=(n.now??new Date).toTimeString().slice(0,8);return`${L("✔","\x1B[32m",ne(n))} ${t} Resources ready! (${Cn(e)})`}function as(e,n={}){return`${L("✔","\x1B[32m",ne(n))} ${e}`}function $n(e,n,t={}){let o=ne(t),r=t.note?` ${L(`(${t.note})`,"\x1B[2m",o)}`:"";return` ${L("now","\x1B[2m",o)} ${e} → ${Bt(n,o)}${r}`}function je(e,n={}){return L(`! ${e}`,"\x1B[33m",ne(n))}function Nt(e){console.error(ts(e))}function tn(e){for(let n of os(e))console.log(n)}function Rn(e){console.error(rs(e))}function Lt(e){console.error(ss(e,{stream:"stderr"}))}function Mt(e){console.error(is(e))}function q(e){console.log(as(e,{stream:"stdout"}))}function D(e){console.log(je(e,{stream:"stdout"}))}function cs(e,n){if(e==="create")return`[${L("+","\x1B[32m",n)}]`;if(e==="rename")return`[${L("~","\x1B[33m",n)}]`;if(e==="update")return`[${L("*","\x1B[36m",n)}]`;return`[${L("-","\x1B[31m",n)}]`}function Cn(e){if(e>=1000)return`${(e/1000).toFixed(2)}s`;return`${Math.max(e,0).toFixed(1)}ms`}function L(e,n,t){return t?`${n}${e}\x1B[0m`:e}function Bt(e,n){let t=Gt(e)==="Development";return L(e,t?"\x1B[32m":"\x1B[33m",n)}function ne(e){if(e.color!==void 0)return e.color;if(Object.hasOwn(process.env,"NO_COLOR"))return!1;if(process.env.FORCE_COLOR&&process.env.FORCE_COLOR!=="0")return!0;return(e.stream==="stdout"?process.stdout:process.stderr).isTTY&&process.env.TERM!=="dumb"}function Gt(e){let n=e.trim().toLowerCase();if(n==="development")return"Development";if(n==="production")return"Production";return e.trim()}var ms=180000,hs=`Timed out waiting for browser login to complete.
|
|
86
86
|
Check the browser tab and the dashboard logs for an error. If the browser shows
|
|
87
87
|
404 on /cli-auth/start, deploy the dashboard build that includes CLI auth or pass
|
|
88
88
|
--dashboard-url for the environment you deployed. Other common causes are missing
|
|
89
89
|
cliAuth Convex functions or no active API account (Organization settings -> API access).`,Wt=new Set(["--base-url","--cwd","--dashboard-url","--stage","--from","--level","--limit","--mcp","--project","--region","--sandbox","-n"]);function ws(e,n=process.platform){if(n==="darwin")return{command:"open",args:[e]};if(n==="win32")return{command:"rundll32",args:["url.dll,FileProtocolHandler",e]};return{command:"xdg-open",args:[e]}}function G(e,n){let t=Wt.has(n)?`${n}=`:null;return e.some((o)=>o===n||t!==null&&o.startsWith(t))}function be(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function R(e,n){for(let t=0;t<e.length;t+=1){let o=e[t];if(o===n)return e[t+1];if(o?.startsWith(`${n}=`))return o.slice(n.length+1)||void 0}return}function oe(e){let n=[];for(let t=0;t<e.length;t+=1){let o=e[t];if(o===void 0)continue;if(Wt.has(o)){t+=1;continue}if(o.startsWith("-"))continue;n.push(o)}return n}async function On(e){let n=gs(),t=us(32).toString("base64url"),o=ds("sha256").update(t).digest("base64url"),{code:r,close:s}=await xn(n,{port:ys(),fixedPort:Boolean(process.env.BROODS_LOGIN_PORT),path:"/callback",read:vs,done:"broods CLI login complete. You can close this tab."});try{let i=r.callbackUrl,a=`${h(e)}/cli-auth/start?`+new URLSearchParams({callback:i,state:n,code_challenge:o});await bs(a),console.log(`Opening ${a}`),An(a);let c=await Tn(r.promise),d=await en(`${c.baseUrl}/v1/account/auth/exchange`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:c.code,code_verifier:t})});if(!d.ok)throw Error(`Login exchange failed: ${d.status} ${await d.text()}`);let l=await d.json(),u={baseUrl:c.baseUrl,dashboardUrl:h(e),token:l.token,createdAt:new Date().toISOString(),...l.user?{user:l.user}:{},...l.org?{org:l.org}:{},...l.account?{account:l.account}:{}};return await B(u),u}finally{s()}}async function re(e){m();let n=T(e);if(!n){let t=process.env.BROODS_DASHBOARD_URL,o=e??process.env.BROODS_BASE_URL??(t?M(t):void 0);throw Error(o?`Not logged in to ${h(o)}. Run \`broods login\`.`:"Run `broods login` first, or set BROODS_TOKEN and BROODS_BASE_URL.")}return n}async function on(e){if(!ce.isTTY)return!1;let n=De({input:ce,output:ae});try{let t=(await n.question(`${e} [y/N] `)).trim().toLowerCase();return t==="y"||t==="yes"}finally{n.close()}}async function Ft(e){ae.write(`${e}: `);let n=new fs({write:(o,r,s)=>s()}),t=De({input:ce,output:n,terminal:ce.isTTY===!0});try{let o=await t.question("");if(!o)throw Error(`${e} is required`);return o}finally{t.close(),ae.write(`
|
|
90
|
-
`)}}async function Ue(e,n,t,o){if(n.length===0)throw Error(`${e}: no options available`);if(n.length===1)return n[0];let r=o!==void 0&&o>=0&&o<n.length?o:void 0;console.log(e),n.forEach((a,c)=>{console.log(Ce(`${c+1}. ${t(a)}`,c===r))});let s=r===void 0?`Choose 1-${n.length}: `:`Choose 1-${n.length} [${r+1}]: `,i=De({input:ce,output:ae});try{for(;;){let a=(await i.question(s)).trim();if(a===""&&r!==void 0)return n[r];let c=Number(a);if(Number.isInteger(c)&&c>=1&&c<=n.length)return n[c-1];console.log(`Enter a number from 1 to ${n.length}.`)}}finally{i.close()}}async function Kt(e,n,t,o){console.log(e),n.forEach((i,a)=>{console.log(` ${a+1}. ${t(i)}`)});let r=n.length>0?`Choose 1-${n.length}, or `:"",s=De({input:ce,output:ae});try{let i=(await s.question(`${r}${o.hint} [${o.defaultValue}]: `)).trim();if(i==="")return o.defaultValue;let a=Number(i);if(Number.isInteger(a)&&a>=1&&a<=n.length)return n[a-1];return i}finally{s.close()}}async function ye(e,n){if(!ce.isTTY)return n??"";let t=De({input:ce,output:ae});try{let o=t.question(`${e}: `);if(n){if(ce.isTTY&&ae.isTTY)ae.write("\x1B[90m");if(t.write(n),ce.isTTY&&ae.isTTY)ae.write("\x1B[0m")}return(await o).trim()||n||""}finally{t.close()}}function An(e){let{command:n,args:t}=ws(e),o=ps(n,t,{stdio:"ignore",detached:!0});o.on("error",(r)=>{console.error(je(`Could not open a browser (${r.message}). Open the URL above to continue.`,{stream:"stderr"}))}),o.unref()}function xn(e,n){return new Promise((t,o)=>{let r=ls((c,d)=>{let l=new URL(c.url??"/","http://127.0.0.1");if(l.pathname!==n.path||l.searchParams.get("state")!==e){d.writeHead(400).end("Invalid callback.");return}try{let u=n.read(l.searchParams);d.writeHead(200,{"Content-Type":"text/plain"}).end(n.done),s(u)}catch(u){d.writeHead(400,{"Content-Type":"text/plain"}).end(u instanceof Error?u.message:String(u)),i(u)}}),s,i,a=new Promise((c,d)=>{s=c,i=d});r.on("error",(c)=>{if(!n.fixedPort&&n.port!==0&&c.code==="EADDRINUSE"){r.listen(0,"127.0.0.1");return}o(c)}),r.listen(n.port,"127.0.0.1",()=>{let c=r.address();if(!c||typeof c==="string"){o(Error("Failed to allocate callback port"));return}t({code:{callbackUrl:`http://127.0.0.1:${c.port}${n.path}`,promise:a},close:()=>r.close()})})})}async function Tn(e,n=hs){let t,o=new Promise((r,s)=>{t=setTimeout(()=>s(Error(n)),ms)});try{return await Promise.race([e,o])}finally{if(t)clearTimeout(t)}}async function bs(e){let n=await en(e,{method:"GET",redirect:"manual"});if(n.status===404){let t=new URL(e);throw Error(`${t.origin} has no broods login page. Check that --dashboard-url points at your broods dashboard.`)}if(n.status>=500)throw Error(`The broods login page failed: ${n.status} ${await n.text()}`)}function ys(){let e=process.env.BROODS_LOGIN_PORT;if(e){let n=Number(e);if(Number.isInteger(n)&&n>0&&n<65536)return n;throw Error("BROODS_LOGIN_PORT must be a TCP port number")}return 18987}function vs(e){let n=e.get("error");if(n)throw Error(`Login failed: ${n}`);let t=e.get("code");if(!t)throw Error("Login callback carried no code.");let o=e.get("base_url");if(!o)throw Error("Login callback did not advertise the API base URL (base_url). Deploy a dashboard build that includes the Convex-direct CLI auth flow.");return{code:t,baseUrl:h(o)}}var Ss=1455,$s="/auth/callback";async function Yt(e,n,t=An){let o=we[n].label,r=Ht(),s=Ht(),i=ks(32).toString("base64url"),{code:a,close:c}=await xn(r,{port:Ss,fixedPort:!1,path:$s,read:Rs,done:`${o} is connected to broods. You can close this tab.`});try{let d=a.callbackUrl,l=await e.startConnection(n,{redirectUri:d,codeChallenge:Es("sha256").update(i).digest("base64url"),state:r,nonce:s});t(l.authorizeUrl),console.log(`Opening ${l.authorizeUrl}`);let u=await Tn(a.promise,`Timed out waiting for the ${o} sign-in to finish in the browser.`);return await e.connect(n,{code:u.code,codeVerifier:i,redirectUri:d,nonce:s,clientId:u.clientId??l.clientId,hostId:l.hostId})}finally{c()}}function Rs(e){let n=e.get("error");if(n)throw Error(`Sign-in failed: ${e.get("error_description")??n}`);let t=e.get("code");if(!t)throw Error("Sign-in callback carried no code.");return{code:t,clientId:e.get("client_id")??void 0}}import{existsSync as zt}from"node:fs";import{mkdir as Os,readFile as As,writeFile as xs}from"node:fs/promises";import{dirname as Jt,join as _n,resolve as Ts,sep as fe}from"node:path";import{fileURLToPath as Ps}from"node:url";var Ne={name:"broods",version:"0.52.
|
|
90
|
+
`)}}async function Ue(e,n,t,o){if(n.length===0)throw Error(`${e}: no options available`);if(n.length===1)return n[0];let r=o!==void 0&&o>=0&&o<n.length?o:void 0;console.log(e),n.forEach((a,c)=>{console.log(Ce(`${c+1}. ${t(a)}`,c===r))});let s=r===void 0?`Choose 1-${n.length}: `:`Choose 1-${n.length} [${r+1}]: `,i=De({input:ce,output:ae});try{for(;;){let a=(await i.question(s)).trim();if(a===""&&r!==void 0)return n[r];let c=Number(a);if(Number.isInteger(c)&&c>=1&&c<=n.length)return n[c-1];console.log(`Enter a number from 1 to ${n.length}.`)}}finally{i.close()}}async function Kt(e,n,t,o){console.log(e),n.forEach((i,a)=>{console.log(` ${a+1}. ${t(i)}`)});let r=n.length>0?`Choose 1-${n.length}, or `:"",s=De({input:ce,output:ae});try{let i=(await s.question(`${r}${o.hint} [${o.defaultValue}]: `)).trim();if(i==="")return o.defaultValue;let a=Number(i);if(Number.isInteger(a)&&a>=1&&a<=n.length)return n[a-1];return i}finally{s.close()}}async function ye(e,n){if(!ce.isTTY)return n??"";let t=De({input:ce,output:ae});try{let o=t.question(`${e}: `);if(n){if(ce.isTTY&&ae.isTTY)ae.write("\x1B[90m");if(t.write(n),ce.isTTY&&ae.isTTY)ae.write("\x1B[0m")}return(await o).trim()||n||""}finally{t.close()}}function An(e){let{command:n,args:t}=ws(e),o=ps(n,t,{stdio:"ignore",detached:!0});o.on("error",(r)=>{console.error(je(`Could not open a browser (${r.message}). Open the URL above to continue.`,{stream:"stderr"}))}),o.unref()}function xn(e,n){return new Promise((t,o)=>{let r=ls((c,d)=>{let l=new URL(c.url??"/","http://127.0.0.1");if(l.pathname!==n.path||l.searchParams.get("state")!==e){d.writeHead(400).end("Invalid callback.");return}try{let u=n.read(l.searchParams);d.writeHead(200,{"Content-Type":"text/plain"}).end(n.done),s(u)}catch(u){d.writeHead(400,{"Content-Type":"text/plain"}).end(u instanceof Error?u.message:String(u)),i(u)}}),s,i,a=new Promise((c,d)=>{s=c,i=d});r.on("error",(c)=>{if(!n.fixedPort&&n.port!==0&&c.code==="EADDRINUSE"){r.listen(0,"127.0.0.1");return}o(c)}),r.listen(n.port,"127.0.0.1",()=>{let c=r.address();if(!c||typeof c==="string"){o(Error("Failed to allocate callback port"));return}t({code:{callbackUrl:`http://127.0.0.1:${c.port}${n.path}`,promise:a},close:()=>r.close()})})})}async function Tn(e,n=hs){let t,o=new Promise((r,s)=>{t=setTimeout(()=>s(Error(n)),ms)});try{return await Promise.race([e,o])}finally{if(t)clearTimeout(t)}}async function bs(e){let n=await en(e,{method:"GET",redirect:"manual"});if(n.status===404){let t=new URL(e);throw Error(`${t.origin} has no broods login page. Check that --dashboard-url points at your broods dashboard.`)}if(n.status>=500)throw Error(`The broods login page failed: ${n.status} ${await n.text()}`)}function ys(){let e=process.env.BROODS_LOGIN_PORT;if(e){let n=Number(e);if(Number.isInteger(n)&&n>0&&n<65536)return n;throw Error("BROODS_LOGIN_PORT must be a TCP port number")}return 18987}function vs(e){let n=e.get("error");if(n)throw Error(`Login failed: ${n}`);let t=e.get("code");if(!t)throw Error("Login callback carried no code.");let o=e.get("base_url");if(!o)throw Error("Login callback did not advertise the API base URL (base_url). Deploy a dashboard build that includes the Convex-direct CLI auth flow.");return{code:t,baseUrl:h(o)}}var Ss=1455,$s="/auth/callback";async function Yt(e,n,t=An){let o=we[n].label,r=Ht(),s=Ht(),i=ks(32).toString("base64url"),{code:a,close:c}=await xn(r,{port:Ss,fixedPort:!1,path:$s,read:Rs,done:`${o} is connected to broods. You can close this tab.`});try{let d=a.callbackUrl,l=await e.startConnection(n,{redirectUri:d,codeChallenge:Es("sha256").update(i).digest("base64url"),state:r,nonce:s});t(l.authorizeUrl),console.log(`Opening ${l.authorizeUrl}`);let u=await Tn(a.promise,`Timed out waiting for the ${o} sign-in to finish in the browser.`);return await e.connect(n,{code:u.code,codeVerifier:i,redirectUri:d,nonce:s,clientId:u.clientId??l.clientId,hostId:l.hostId})}finally{c()}}function Rs(e){let n=e.get("error");if(n)throw Error(`Sign-in failed: ${e.get("error_description")??n}`);let t=e.get("code");if(!t)throw Error("Sign-in callback carried no code.");return{code:t,clientId:e.get("client_id")??void 0}}import{existsSync as zt}from"node:fs";import{mkdir as Os,readFile as As,writeFile as xs}from"node:fs/promises";import{dirname as Jt,join as _n,resolve as Ts,sep as fe}from"node:path";import{fileURLToPath as Ps}from"node:url";var Ne={name:"broods",version:"0.52.1",description:"CLI + TypeScript SDK for the broods agent platform.",keywords:["agents","ai","broods","cli","sdk"],homepage:"https://github.com/beeblastco/broods#readme",bugs:{url:"https://github.com/beeblastco/broods/issues"},license:"MIT",repository:{type:"git",url:"git+https://github.com/beeblastco/broods.git",directory:"packages/broods"},bin:{broods:"dist/cli/index.js"},files:["dist","README.md","LICENSE.md"],type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",typesVersions:{"*":{account:["./dist/account.d.ts"]}},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js"},"./account":{types:"./dist/account.d.ts",import:"./dist/account.js"}},scripts:{build:"bun scripts/build.ts && rollup -c rollup.dts.config.mjs && rm -rf .dts-temp",check:"tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json","pack:check":"bun run build && publint && attw --pack .",prepublishOnly:"bun run build",test:"bun test","test:desktop":"BROODS_TEST_DESKTOP=1 bun test tests/cli-desktop.test.ts"},dependencies:{"@modelcontextprotocol/client":"^2.2.0",esbuild:"^0.28.2"},devDependencies:{"@ai-sdk/tui":"1.0.138","@arethetypeswrong/cli":"^0.18.5","@chat-adapter/discord":"^4.38.1","@chat-adapter/github":"^4.38.1","@chat-adapter/slack":"^4.38.1","@chat-adapter/telegram":"^4.38.1","@modelcontextprotocol/server":"2.3.1","@types/bun":"^1.3.14","@typescript/typescript6":"6.0.2",ai:"^7.0.137",publint:"^0.3.23",rollup:"^4.62.4","rollup-plugin-dts":"^6.5.1",typescript:"^7.0.2",zod:"^4.4.3"},peerDependencies:{ai:"^7.0.137"},engines:{node:">=22.15"}};var Pn=_n(Jt(x),"update-check.json"),Is=86400000,_s="https://registry.npmjs.org/broods/latest",js=2000,Ds=[["bun.lock","bun"],["bun.lockb","bun"],["pnpm-lock.yaml","pnpm"],["yarn.lock","yarn"]];function jn(e,n){let t=In(e),o=In(n);for(let r=0;r<3;r+=1){let s=t[r]??0,i=o[r]??0;if(s!==i)return s>i}return!Vt(e)&&Vt(n)}async function Dn(e={}){let n=await Ns(),t=e.maxAgeMs??Is;if(n&&Date.now()-n.checkedAt<t)return n.latest;let o=await Us();if(o===null)return n?.latest??null;return await Ms({checkedAt:Date.now(),latest:o}),o}function Le(e){return In(e)[0]??0}function qt(e=Ts(process.cwd()),n=Ps(import.meta.url),t=Ne.version){let o=`${fe}node_modules${fe}`,r=n.indexOf(o),s=r===-1?null:n.slice(0,r),i=s===null?n.startsWith(`${e}${fe}`):e===s||e.startsWith(`${s}${fe}`),a=n.includes(`${fe}.bun${fe}install${fe}global${fe}`),c=s??e,d=i?Ls(c):a?"bun":"npm",l=d==="npm"?"install":"add",u=d==="pnpm"&&zt(_n(c,"pnpm-workspace.yaml"))?["-w"]:[],S=`broods@${Le(t)}`;return{manager:d,global:!i,command:d,cwd:i?c:e,args:i?[l,...u,S]:[l,"-g",S]}}async function Us(){try{let e=await fetch(_s,{signal:AbortSignal.timeout(js),headers:{accept:"application/json"}});if(!e.ok)return null;let n=await e.json();return typeof n.version==="string"?n.version:null}catch{return null}}function Vt(e){return e.includes("-")}async function Ns(){try{let e=JSON.parse(await As(Pn,"utf8"));if(typeof e.latest!=="string")return null;if(typeof e.checkedAt!=="number")return null;return{checkedAt:e.checkedAt,latest:e.latest}}catch{return null}}function Ls(e){return Ds.find(([t])=>zt(_n(e,t)))?.[1]??"npm"}function In(e){let[n]=e.trim().replace(/^v/,"").split("-");return(n??"").split(".").slice(0,3).map((t)=>Number.parseInt(t,10)||0)}async function Ms(e){try{await Os(Jt(Pn),{recursive:!0}),await xs(Pn,`${JSON.stringify(e)}
|
|
91
91
|
`,"utf8")}catch{}}var Zt=`---
|
|
92
92
|
name: broods
|
|
93
93
|
description: Work on a broods account alongside a developer from Claude Code or a development agent. Covers onboarding and sign-in, creating a broods project, defining and deploying agents and their resources with the CLI, and integrating a deployed agent into existing code with the SDK. Use when asked to set up broods, create or work on a broods project, create or manage agents or any account resource, or call a deployed agent from application code.
|
|
@@ -419,7 +419,7 @@ ${ee("stage")}`);let i=m(),a=R(e,"--dashboard-url")??i.dashboardUrl??le,c=ln(e),
|
|
|
419
419
|
|
|
420
420
|
${ee("env")}`);if(a&&!t)throw Error(`broods env ${n} needs a variable name.
|
|
421
421
|
|
|
422
|
-
${ee("env")}`);let{manifest:c,config:d}=await ue({project:R(e,"--project"),stage:R(e,"--stage"),command:"dev"}),l=await re(R(e,"--base-url")??d.baseUrl),u=new J({baseUrl:l.baseUrl,token:l.token}),S=`${c.project}/${c.stage}`;if(i){await Fi(u,c,S);return}if(o){let P=await u.listEnv(c.project,c.stage);if(P.length===0){console.log(`No environment variables set for ${S}.`);return}console.log(`Environment variables for ${S} (values hidden):`);for(let A of P)console.log(` ${A.name}`);return}if(s){let P=await u.getEnv(c.project,c.stage,t);if(P===null){console.error(`${t} is not set for ${S}`),process.exitCode=1;return}console.log(P);return}if(r){await u.removeEnv(c.project,c.stage,t),q(`Removed ${t} from ${S}`);return}let C=await Ft(t);await u.setEnv(c.project,c.stage,t,C),q(`Stored ${t} for ${S}`)}async function Fi(e,n,t){let o=await Fn(e,n);if(o.length===0){console.log('No env("NAME") references in this project.');return}let r=await wo(e,n,o);if(r.length>0)Rn(r);let s=sn(o,"synced").length;console.log(r.length>0?`${s} other referenced variable(s) already in step with ${t}.`:`${s} referenced variable(s) already in step with ${t}.`);let i=sn(o,"stage-only");if(i.length>0)console.log(`${i.length} referenced variable(s) live only on ${t}: ${i.join(", ")}`);let a=sn(o,"unresolved");if(a.length>0)D(`${a.length} referenced variable(s) with no value here or on ${t}: ${a.join(", ")}. Put them in .env.local, or run \`broods env set <NAME> --stage ${n.stage}\`.`)}function Kn(e){if(G(e,"--all"))return"DEBUG";let n=R(e,"--level");if(n===void 0&&G(e,"--level"))throw Error("Missing value for --level. Use DEBUG, INFO, WARN, or ERROR.");if(!n)return"WARN";let t=n.toUpperCase();if(t==="DEBUG")return"DEBUG";if(t==="INFO")return"INFO";if(t==="WARN"||t==="WARNING")return"WARN";if(t==="ERROR")return"ERROR";throw Error(`Unknown log level: ${n}. Use DEBUG, INFO, WARN, or ERROR.`)}async function Ki(e){m();let n=R(e,"--project")??process.env.BROODS_PROJECT,t=R(e,"--stage")??b();if(!n)throw Error("Project name is required. Pass --project <name> or set BROODS_PROJECT in .env.local.");if(!t)throw Error("Stage name is required. Pass --stage <name> or set BROODS_STAGE in .env.local.");return{project:n,stage:t}}async function Fe(e){let n=await Ki(e),t=m(),o=await We(R(e,"--dashboard-url")??t.dashboardUrl??le,R(e,"--base-url")),r=new J({baseUrl:o.baseUrl,token:o.token}),s=await r.mintStageSession(n.project,n.stage),i=s,a=async()=>{let c=i??await r.mintStageSession(n.project,n.stage);return i=void 0,c.token};return{baseUrl:o.baseUrl,credential:a,project:s.projectSlug,stage:s.stageSlug}}function bo(e){return e==="WARN"?" (--all for INFO too)":""}function Hn(e,n){console.error(je(`Reconnecting to live logs (attempt ${e}): ${n}`,{stream:"stderr"}))}function Yn(e){let n=new Date(e.ts).toISOString().slice(11,23),t=e.level.padEnd(5),o=Un(e.message);return`${n} ${t} ${e.eventType} ${o}`}async function Hi(e){let n=await Fe(e),{project:t,stage:o}=n,r=Kn(e),s=new AbortController,i=()=>s.abort();process.on("SIGINT",i),console.log(`Streaming live logs for ${t}/${o} [${r}+]`+bo(r)+", Ctrl+C to stop");try{for await(let a of qe(n,{backfill:0,minLevel:r,signal:s.signal,onReconnect:Hn}))console.log(Yn(a))}catch(a){if(!s.signal.aborted)console.error(a instanceof Error?a.message:String(a)),process.exitCode=1}finally{process.off("SIGINT",i)}}async function Yi(e){if(G(e,"--doctor")){await Vi(G(e,"--request"));return}let n=oe(e)[0];if(!n){console.log(ke("machine",e));return}let{runMachineDaemon:t}=await import("../chunk-
|
|
422
|
+
${ee("env")}`);let{manifest:c,config:d}=await ue({project:R(e,"--project"),stage:R(e,"--stage"),command:"dev"}),l=await re(R(e,"--base-url")??d.baseUrl),u=new J({baseUrl:l.baseUrl,token:l.token}),S=`${c.project}/${c.stage}`;if(i){await Fi(u,c,S);return}if(o){let P=await u.listEnv(c.project,c.stage);if(P.length===0){console.log(`No environment variables set for ${S}.`);return}console.log(`Environment variables for ${S} (values hidden):`);for(let A of P)console.log(` ${A.name}`);return}if(s){let P=await u.getEnv(c.project,c.stage,t);if(P===null){console.error(`${t} is not set for ${S}`),process.exitCode=1;return}console.log(P);return}if(r){await u.removeEnv(c.project,c.stage,t),q(`Removed ${t} from ${S}`);return}let C=await Ft(t);await u.setEnv(c.project,c.stage,t,C),q(`Stored ${t} for ${S}`)}async function Fi(e,n,t){let o=await Fn(e,n);if(o.length===0){console.log('No env("NAME") references in this project.');return}let r=await wo(e,n,o);if(r.length>0)Rn(r);let s=sn(o,"synced").length;console.log(r.length>0?`${s} other referenced variable(s) already in step with ${t}.`:`${s} referenced variable(s) already in step with ${t}.`);let i=sn(o,"stage-only");if(i.length>0)console.log(`${i.length} referenced variable(s) live only on ${t}: ${i.join(", ")}`);let a=sn(o,"unresolved");if(a.length>0)D(`${a.length} referenced variable(s) with no value here or on ${t}: ${a.join(", ")}. Put them in .env.local, or run \`broods env set <NAME> --stage ${n.stage}\`.`)}function Kn(e){if(G(e,"--all"))return"DEBUG";let n=R(e,"--level");if(n===void 0&&G(e,"--level"))throw Error("Missing value for --level. Use DEBUG, INFO, WARN, or ERROR.");if(!n)return"WARN";let t=n.toUpperCase();if(t==="DEBUG")return"DEBUG";if(t==="INFO")return"INFO";if(t==="WARN"||t==="WARNING")return"WARN";if(t==="ERROR")return"ERROR";throw Error(`Unknown log level: ${n}. Use DEBUG, INFO, WARN, or ERROR.`)}async function Ki(e){m();let n=R(e,"--project")??process.env.BROODS_PROJECT,t=R(e,"--stage")??b();if(!n)throw Error("Project name is required. Pass --project <name> or set BROODS_PROJECT in .env.local.");if(!t)throw Error("Stage name is required. Pass --stage <name> or set BROODS_STAGE in .env.local.");return{project:n,stage:t}}async function Fe(e){let n=await Ki(e),t=m(),o=await We(R(e,"--dashboard-url")??t.dashboardUrl??le,R(e,"--base-url")),r=new J({baseUrl:o.baseUrl,token:o.token}),s=await r.mintStageSession(n.project,n.stage),i=s,a=async()=>{let c=i??await r.mintStageSession(n.project,n.stage);return i=void 0,c.token};return{baseUrl:o.baseUrl,credential:a,project:s.projectSlug,stage:s.stageSlug}}function bo(e){return e==="WARN"?" (--all for INFO too)":""}function Hn(e,n){console.error(je(`Reconnecting to live logs (attempt ${e}): ${n}`,{stream:"stderr"}))}function Yn(e){let n=new Date(e.ts).toISOString().slice(11,23),t=e.level.padEnd(5),o=Un(e.message);return`${n} ${t} ${e.eventType} ${o}`}async function Hi(e){let n=await Fe(e),{project:t,stage:o}=n,r=Kn(e),s=new AbortController,i=()=>s.abort();process.on("SIGINT",i),console.log(`Streaming live logs for ${t}/${o} [${r}+]`+bo(r)+", Ctrl+C to stop");try{for await(let a of qe(n,{backfill:0,minLevel:r,signal:s.signal,onReconnect:Hn}))console.log(Yn(a))}catch(a){if(!s.signal.aborted)console.error(a instanceof Error?a.message:String(a)),process.exitCode=1}finally{process.off("SIGINT",i)}}async function Yi(e){if(G(e,"--doctor")){await Vi(G(e,"--request"));return}let n=oe(e)[0];if(!n){console.log(ke("machine",e));return}let{runMachineDaemon:t}=await import("../chunk-d960xefn.js"),{baseUrl:o,credential:r}=await Fe(e),s=N(R(e,"--cwd")??process.cwd()),i=G(e,"--computer"),a=R(e,"--mcp"),c=G(e,"--force"),d=new AbortController,l=()=>d.abort();process.on("SIGINT",l),console.log(`Connecting ${n} to ${o} (cwd ${s}${i?", computer use on":""}), Ctrl+C to stop`);try{await t({baseUrl:o,computer:i,credential:r,cwd:s,force:c,log:(u)=>console.log(u),mcpFile:a?N(a):void 0,sandbox:n,signal:d.signal})}catch(u){console.error(u instanceof Error?u.message:String(u)),process.exitCode=1}finally{process.off("SIGINT",l)}}async function Vi(e){try{let{startDesktop:n}=await import("../chunk-5tnnqapc.js"),{display:t,driver:o,permissions:r}=await n(e);o.stop();let s=(i)=>i?"granted":"missing";if(console.log(`screenshot frame ${t.width}x${t.height} (scale ${t.scale.toFixed(2)})`),console.log(`screen recording ${s(r.screenRecording)}`),console.log(`accessibility ${s(r.accessibility)}`),!r.screenRecording||!r.accessibility)console.log(e?"Approve the prompts, or add this terminal under System Settings > Privacy & Security, then run again.":"Run `broods machine --doctor --request` to show the macOS prompts."),process.exitCode=1}catch(n){console.error(n instanceof Error?n.message:String(n)),process.exitCode=1}}async function zi(e){let n=await Fe(e),{project:t,stage:o}=n,r=R(e,"--sandbox");if(G(e,"--sandbox")&&!U(r))throw Error("--sandbox needs the instance log id, the UUID shown in the dashboard Instances sheet.");let s=r?"DEBUG":Kn(e),i=Number(R(e,"--limit")??R(e,"-n")??100),a=G(e,"--json"),c=new AbortController,d=()=>c.abort();process.on("SIGINT",d),console.log(`Logs for ${t}/${o}`+(r?` sandbox ${r}`:"")+` [${s}+]`+bo(s)+` (backfill ${i}), Ctrl+C to stop`);try{for await(let l of qe(n,{backfill:i,minLevel:s,...r?{sandboxId:r}:{},signal:c.signal,onReconnect:Hn}))if(a)console.log(JSON.stringify(l));else console.log(Yn(l))}catch(l){if(!c.signal.aborted)console.error(l instanceof Error?l.message:String(l)),process.exitCode=1}finally{process.off("SIGINT",d)}}async function Ji(e){let[n]=oe(e);if(!F(n))throw Error(`Missing or malformed trace id: 32 lowercase hex characters, as the dashboard copies it.
|
|
423
423
|
|
|
424
424
|
${ee("trace")}`);let t=await Fe(e),o=(await At(t,n)).toSorted((a,c)=>a.startTimeMs-c.startTimeMs);if(G(e,"--json")){console.log(JSON.stringify(o,null,2));return}console.log(`Trace ${n} in ${t.project}/${t.stage}`);let r=new Set(o.map((a)=>a.spanId)),s=Map.groupBy(o,(a)=>a.parentSpanId&&a.parentSpanId!==a.spanId&&r.has(a.parentSpanId)?a.parentSpanId:""),i=(a,c)=>{for(let d of s.get(a)??[])console.log(qi(d,c)),i(d.spanId,c+1)};i("",0)}function qi(e,n){let t=new Date(e.startTimeMs).toISOString().slice(11,23),o=" ".repeat(n),r=e.attributes?.["tool.name"],s=typeof r==="string"?`${e.name} ${r}`:e.name,i=`${t} ${e.status.padEnd(11)} ${o}`,a=`${i}${s} ${Cn(e.durationMs)}`;if(!e.error)return Un(a);let c=" ".repeat(i.length),d=e.error.replaceAll(/\r\n?|\n/g,`
|
|
425
425
|
${c} `);return Un(`${a}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{L,ae,Se,he,be,ve,U,F,ee,G,g,_e,z,ce,j,
|
|
1
|
+
import{L,ae,Se,he,be,ve,U,F,ee,G,g,_e,z,ce,j,K,fe,W,k,we,Re,$e,Ce,Ee,ke,Te,ze,Pe,Ie,xe,Ae,Oe,Me,Ne,je,qe,De,Le,Ue,Fe,Be,He,Ze,Ve,Ge,Ke,We,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,te,_,f}from"./chunk-yqbtb9cd.js";import{p,ge,q,w}from"./chunk-a8zhzzj7.js";export{p as BroodsAccountApiError,w as BroodsAccountClient,j as BroodsClient,fe as BroodsWebSocketClient,z as DEFAULT_CORE_BASE_URL,ce as IngressAcceptedError,Se as MAX_OBSERVABILITY_BACKFILL,ee as USER_TOKEN_HEADER,G as USER_TOKEN_MAX_TTL_MS,g as USER_TOKEN_SECRET_ENV,fe as WebSocketClient,fe as WebsocketClient,Re as defineAgent,$e as defineBroods,Ce as defineCron,Ve as defineDiscordChannel,xe as defineDiscordConnection,Ge as defineGitHubChannel,Ae as defineGitHubConnection,Ke as defineGoogleChatChannel,Oe as defineGoogleChatConnection,Ee as defineHarness,We as defineInstagramChannel,Me as defineInstagramConnection,Je as defineLinearChannel,Ne as defineLinearConnection,Ye as defineMatrixChannel,je as defineMatrixConnection,ke as defineMcp,Xe as defineMessengerChannel,qe as defineMessengerConnection,Qe as definePancakeChannel,De as definePancakeConnection,Te as definePolicy,ze as defineSandbox,Pe as defineSkill,et as defineSlackChannel,Le as defineSlackConnection,tt as defineTeamsChannel,Ue as defineTeamsConnection,nt as defineTelegramChannel,Fe as defineTelegramConnection,rt as defineTwilioChannel,Be as defineTwilioConnection,ot as defineWhatsAppChannel,He as defineWhatsAppConnection,Ie as defineWorkspace,st as defineZaloChannel,Ze as defineZaloConnection,we as env,ge as envPlaceholder,te as isBroodsConfig,_ as isConnectionDefinition,he as isLogLevel,be as isObservabilityClientMessage,f as isResource,ve as isRootSpanKind,U as isSandboxLogId,F as isTraceId,K as normalizeHttpServiceUrl,ae as readSseStream,q as resolveEnvCredential,L as resolveRunEvents,_e as signUserToken,W as toWebSocketBaseUrl,k as webSocketSubprotocols};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "broods",
|
|
3
|
-
"version": "0.52.
|
|
3
|
+
"version": "0.52.1",
|
|
4
4
|
"description": "CLI + TypeScript SDK for the broods agent platform.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"check": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json",
|
|
53
53
|
"pack:check": "bun run build && publint && attw --pack .",
|
|
54
54
|
"prepublishOnly": "bun run build",
|
|
55
|
-
"test": "bun test"
|
|
55
|
+
"test": "bun test",
|
|
56
|
+
"test:desktop": "BROODS_TEST_DESKTOP=1 bun test tests/cli-desktop.test.ts"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"@modelcontextprotocol/client": "^2.2.0",
|