broods 0.45.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account.d.ts +51 -17
- package/dist/chunk-agza3wkj.js +5 -0
- package/dist/{chunk-b3q14j68.js → chunk-b68w0qr7.js} +1 -1
- package/dist/{chunk-7e3meadv.js → chunk-cz62v9cj.js} +2 -2
- package/dist/cli/index.js +51 -51
- package/dist/index.d.ts +93 -29
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-hdcy74kj.js +0 -5
package/dist/account.d.ts
CHANGED
|
@@ -45,7 +45,7 @@ declare const MODEL_PROVIDERS: {
|
|
|
45
45
|
readonly modelPlaceholder: "gpt-5.5";
|
|
46
46
|
};
|
|
47
47
|
readonly cloudflare: {
|
|
48
|
-
readonly label: "Cloudflare
|
|
48
|
+
readonly label: "Cloudflare";
|
|
49
49
|
readonly modelPlaceholder: "@cf/meta/llama-3.3-70b-instruct-fp8-fast";
|
|
50
50
|
};
|
|
51
51
|
readonly cohere: {
|
|
@@ -155,8 +155,9 @@ declare const AGENT_LIFECYCLE_EVENT_NAMES: readonly ["agent.started", "agent.ste
|
|
|
155
155
|
* Shared validation for MCP server registrations (#331). One normalizer
|
|
156
156
|
* serves every write path (CLI sync, direct API, dashboard). A `url` makes an "http" row
|
|
157
157
|
* core connects to over the stateless 2026-07-28 transport; a `bundle` makes
|
|
158
|
-
* a "hosted" row
|
|
159
|
-
*
|
|
158
|
+
* a "hosted" row, hashed here so sha256 always travels with the bundle; the
|
|
159
|
+
* S3 bundle writer (aws/bundles.ts) marks whether Cloudflare Dynamic Workers
|
|
160
|
+
* can run it. Auth header values may carry ${NAME}
|
|
160
161
|
* account env refs; they resolve into the encrypted agent config at sync
|
|
161
162
|
* time, never on this row, and credential-bearing headers must use one
|
|
162
163
|
* instead of an inline secret. `oauth` follows the same rule: clientSecret
|
|
@@ -208,6 +209,10 @@ interface AgentConfig {
|
|
|
208
209
|
skills?: AgentSkillsConfig;
|
|
209
210
|
subagent?: AgentSubagentConfig;
|
|
210
211
|
scheduler?: AgentSchedulerConfig;
|
|
212
|
+
/** Registers the `browse` tool, which runs Obscura on the first sandbox. */
|
|
213
|
+
browser?: {
|
|
214
|
+
enabled?: boolean;
|
|
215
|
+
};
|
|
211
216
|
/** Policies that gate this agent. Each one carries its own enforcement mode. */
|
|
212
217
|
policies?: string[];
|
|
213
218
|
publicAccess?: boolean;
|
|
@@ -304,6 +309,8 @@ interface AgentProviderSettings {
|
|
|
304
309
|
base_url?: string;
|
|
305
310
|
/** OpenAI-compatible endpoint (`custom`). AI-SDK form; the dashboard writes both. */
|
|
306
311
|
baseURL?: string;
|
|
312
|
+
/** Cloudflare AI Gateway id (`cloudflare`). Set, requests go through the gateway. */
|
|
313
|
+
gatewayId?: string;
|
|
307
314
|
headers?: Record<string, string>;
|
|
308
315
|
/** Endpoint label; becomes the provider id and the pi harness env prefix. */
|
|
309
316
|
name?: string;
|
|
@@ -327,8 +334,9 @@ interface AgentSessionPruningConfig {
|
|
|
327
334
|
}
|
|
328
335
|
/**
|
|
329
336
|
* Compaction after a finished turn, on unless `enabled: false`. It runs once
|
|
330
|
-
* the turn's last model call
|
|
331
|
-
*
|
|
337
|
+
* the turn's last model call reaches the lower of `maxContextLength` (default
|
|
338
|
+
* 500000) and 80% of the model's context window. `/compact` works whatever
|
|
339
|
+
* this says.
|
|
332
340
|
*/
|
|
333
341
|
interface AgentSessionAutoCompactionConfig {
|
|
334
342
|
enabled?: boolean;
|
|
@@ -721,7 +729,7 @@ type UpdateCronInput = {
|
|
|
721
729
|
* rules, core's executor registry and the SDK derive from. A leaf on purpose,
|
|
722
730
|
* so `schema.ts` can read it without pulling the rules' import graph.
|
|
723
731
|
*/
|
|
724
|
-
declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel", "machine", "custom"];
|
|
732
|
+
declare const SANDBOX_PROVIDERS: readonly ["sandbox", "lambda", "e2b", "daytona", "vercel", "cloudflare", "machine", "custom"];
|
|
725
733
|
type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
|
|
726
734
|
|
|
727
735
|
/**
|
|
@@ -730,6 +738,7 @@ type SandboxProvider = (typeof SANDBOX_PROVIDERS)[number];
|
|
|
730
738
|
* is unchanged. The public projection lives in ./responses.ts.
|
|
731
739
|
*/
|
|
732
740
|
|
|
741
|
+
declare const SANDBOX_IMAGES: readonly ["browser", "obscura"];
|
|
733
742
|
declare const SANDBOX_RUNTIMES: readonly ["bash", "python", "node"];
|
|
734
743
|
declare const SANDBOX_PERMISSION_MODES: readonly ["edit", "ask", "bypass"];
|
|
735
744
|
declare const SANDBOX_NETWORK_MODES: readonly ["allow-all", "deny-all", "restricted"];
|
|
@@ -738,6 +747,7 @@ type RuntimeName = (typeof SANDBOX_RUNTIMES)[number];
|
|
|
738
747
|
type PermissionMode = (typeof SANDBOX_PERMISSION_MODES)[number];
|
|
739
748
|
type NetworkMode = (typeof SANDBOX_NETWORK_MODES)[number];
|
|
740
749
|
type SandboxSize = (typeof SANDBOX_SIZE_NAMES)[number];
|
|
750
|
+
type SandboxImage = (typeof SANDBOX_IMAGES)[number];
|
|
741
751
|
/**
|
|
742
752
|
* Idle and maximum lifetime controls for a persistent sandbox.
|
|
743
753
|
*/
|
|
@@ -757,6 +767,7 @@ interface SandboxConfig {
|
|
|
757
767
|
provider: SandboxProvider;
|
|
758
768
|
fallbackProvider?: SandboxProvider;
|
|
759
769
|
size?: SandboxSize;
|
|
770
|
+
image?: SandboxImage;
|
|
760
771
|
snapshot?: string;
|
|
761
772
|
runtimes?: RuntimeName[];
|
|
762
773
|
network?: SandboxNetworkConfig;
|
|
@@ -789,7 +800,8 @@ type WorkspaceIsolation = (typeof WORKSPACE_ISOLATION_LEVELS)[number];
|
|
|
789
800
|
* Workspace-config validation for the Convex config plane. Ports core's
|
|
790
801
|
* former storage/workspace-config.ts normalizer so the public /v1/workspaces
|
|
791
802
|
* contract is unchanged. Workspace config holds no secrets (a roleArn is not
|
|
792
|
-
* a secret), so it is stored and returned
|
|
803
|
+
* a secret, and R2 keys are `${NAME}` env refs), so it is stored and returned
|
|
804
|
+
* in plaintext. Pure module, safe
|
|
793
805
|
* for the default Convex runtime. The public projection lives in
|
|
794
806
|
* ./responses.ts. Core runs the storage access rule too, so it reads the env
|
|
795
807
|
* names of both sides.
|
|
@@ -803,6 +815,12 @@ type WorkspaceStorageAuth = {
|
|
|
803
815
|
type: "assumeRole";
|
|
804
816
|
roleArn: string;
|
|
805
817
|
externalId?: string;
|
|
818
|
+
} | {
|
|
819
|
+
type: "r2";
|
|
820
|
+
/** `${NAME}` ref to the parent R2 token's access key id. */
|
|
821
|
+
accessKeyId: string;
|
|
822
|
+
/** `${NAME}` ref to the parent R2 token's secret access key. */
|
|
823
|
+
secretAccessKey: string;
|
|
806
824
|
};
|
|
807
825
|
interface WorkspaceStorageConfig {
|
|
808
826
|
provider: WorkspaceStorageProvider;
|
|
@@ -812,10 +830,6 @@ interface WorkspaceStorageConfig {
|
|
|
812
830
|
prefix?: string;
|
|
813
831
|
auth?: WorkspaceStorageAuth;
|
|
814
832
|
}
|
|
815
|
-
/** What the API accepts: the boolean spelling of isolation is stored as its level. */
|
|
816
|
-
type WorkspaceConfigInput = Omit<WorkspaceConfig, "isolation"> & {
|
|
817
|
-
isolation?: WorkspaceIsolation | boolean;
|
|
818
|
-
};
|
|
819
833
|
interface WorkspaceConfig {
|
|
820
834
|
storage: WorkspaceStorageConfig;
|
|
821
835
|
isolation?: WorkspaceIsolation;
|
|
@@ -1283,6 +1297,8 @@ interface McpOauthInput {
|
|
|
1283
1297
|
refreshToken: string;
|
|
1284
1298
|
tokenUrl?: string;
|
|
1285
1299
|
}
|
|
1300
|
+
/** Where a hosted MCP server may run. */
|
|
1301
|
+
type McpRuntime = "auto" | "lambda";
|
|
1286
1302
|
/** Public MCP server registration returned by the `/v1/mcp` routes (#331). */
|
|
1287
1303
|
interface AccountMcp {
|
|
1288
1304
|
accountId: string;
|
|
@@ -1294,10 +1310,14 @@ interface AccountMcp {
|
|
|
1294
1310
|
transport: "http" | "hosted" | "machine";
|
|
1295
1311
|
/** External servers only; a hosted row has no endpoint of its own. */
|
|
1296
1312
|
url?: string;
|
|
1297
|
-
/** Machine servers only: the
|
|
1313
|
+
/** Machine servers only: the sandbox (by name) that serves it. */
|
|
1298
1314
|
sandbox?: string;
|
|
1315
|
+
/** Machine servers only: argv of the stdio server a lambda sandbox runs. */
|
|
1316
|
+
command?: string[];
|
|
1299
1317
|
/** Hosted servers only: content hash of the uploaded bundle. */
|
|
1300
1318
|
sha256?: string;
|
|
1319
|
+
/** Hosted servers only: "auto" or "lambda". */
|
|
1320
|
+
runtime?: McpRuntime;
|
|
1301
1321
|
headers?: Record<string, string>;
|
|
1302
1322
|
oauth?: McpOauthInput;
|
|
1303
1323
|
allowedTools?: string[];
|
|
@@ -1310,19 +1330,26 @@ interface AccountMcp {
|
|
|
1310
1330
|
/**
|
|
1311
1331
|
* Fields accepted by `POST /v1/mcp`: `url` connects, `bundle` uploads inline
|
|
1312
1332
|
* (≤10 MB); a larger bundle goes through `uploadMcpBundle` first; `sandbox`
|
|
1313
|
-
* runs it on that machine
|
|
1333
|
+
* runs it on that sandbox: a machine's daemon, or `command` on a lambda VM.
|
|
1314
1334
|
*/
|
|
1315
1335
|
interface CreateMcpInput {
|
|
1316
1336
|
name: string;
|
|
1317
1337
|
description?: string;
|
|
1318
1338
|
url?: string;
|
|
1319
1339
|
sandbox?: string;
|
|
1340
|
+
command?: string[];
|
|
1320
1341
|
bundle?: string;
|
|
1321
1342
|
bundleStorageId?: string;
|
|
1322
1343
|
sha256?: string;
|
|
1323
1344
|
headers?: Record<string, string>;
|
|
1324
1345
|
oauth?: McpOauthInput;
|
|
1325
1346
|
allowedTools?: string[];
|
|
1347
|
+
/**
|
|
1348
|
+
* Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
|
|
1349
|
+
* when its bundle can run there, on Lambda otherwise; "lambda" always runs
|
|
1350
|
+
* it on Lambda.
|
|
1351
|
+
*/
|
|
1352
|
+
runtime?: McpRuntime;
|
|
1326
1353
|
}
|
|
1327
1354
|
/** Fields accepted by `PATCH /v1/mcp/{serverId}`; every field is optional. */
|
|
1328
1355
|
interface UpdateMcpInput {
|
|
@@ -1330,12 +1357,19 @@ interface UpdateMcpInput {
|
|
|
1330
1357
|
description?: string;
|
|
1331
1358
|
url?: string;
|
|
1332
1359
|
sandbox?: string;
|
|
1360
|
+
command?: string[];
|
|
1333
1361
|
bundle?: string;
|
|
1334
1362
|
bundleStorageId?: string;
|
|
1335
1363
|
sha256?: string;
|
|
1336
1364
|
headers?: Record<string, string>;
|
|
1337
1365
|
oauth?: McpOauthInput;
|
|
1338
1366
|
allowedTools?: string[];
|
|
1367
|
+
/**
|
|
1368
|
+
* Hosted servers only. "auto" (the default) runs it on Cloudflare Workers
|
|
1369
|
+
* when its bundle can run there, on Lambda otherwise; "lambda" always runs
|
|
1370
|
+
* it on Lambda.
|
|
1371
|
+
*/
|
|
1372
|
+
runtime?: McpRuntime;
|
|
1339
1373
|
disabled?: boolean;
|
|
1340
1374
|
}
|
|
1341
1375
|
/**
|
|
@@ -1476,13 +1510,13 @@ declare class BroodsAccountClient {
|
|
|
1476
1510
|
createWorkspace(input: {
|
|
1477
1511
|
name: string;
|
|
1478
1512
|
description?: string;
|
|
1479
|
-
config?:
|
|
1513
|
+
config?: WorkspaceConfig;
|
|
1480
1514
|
}): Promise<AccountWorkspace>;
|
|
1481
1515
|
getWorkspace(workspaceId: string): Promise<AccountWorkspace | null>;
|
|
1482
1516
|
updateWorkspace(workspaceId: string, patch: {
|
|
1483
1517
|
name?: string;
|
|
1484
1518
|
description?: string | null;
|
|
1485
|
-
config?: ConfigPatch<
|
|
1519
|
+
config?: ConfigPatch<WorkspaceConfig>;
|
|
1486
1520
|
}): Promise<AccountWorkspace | null>;
|
|
1487
1521
|
deleteWorkspace(workspaceId: string): Promise<boolean>;
|
|
1488
1522
|
/** Flat listing of every file in the workspace's S3-backed filesystem. Returns [] when the workspace is gone. */
|
|
@@ -1521,7 +1555,7 @@ declare class BroodsAccountClient {
|
|
|
1521
1555
|
terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
|
|
1522
1556
|
/** Snapshot a persistent sandbox reservation into a reusable image (self-hosted `sandbox` provider). Throws on 404/403/409. */
|
|
1523
1557
|
snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
|
|
1524
|
-
/** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda` providers). Throws on 404/403/409. */
|
|
1558
|
+
/** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda`/`cloudflare` providers). Throws on 404/403/409. */
|
|
1525
1559
|
openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
|
|
1526
1560
|
/** MCP servers live in one stage, so the collection routes need a scope. */
|
|
1527
1561
|
listMcp(scope: StageScope): Promise<AccountMcp[]>;
|
|
@@ -1629,4 +1663,4 @@ declare class BroodsAccountClient {
|
|
|
1629
1663
|
}
|
|
1630
1664
|
|
|
1631
1665
|
export { BroodsAccountApiError, BroodsAccountClient, envPlaceholder, resolveEnvCredential };
|
|
1632
|
-
export type { AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, AssumeRoleResult, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, ChannelRecordConfig, ConfigPatch, Connection, ConnectionCode, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateMcpInput, DeleteAccountResult, McpOauthInput, RotateSecretResult, SandboxLifecycleResult, SandboxSnapshotResult, SandboxTerminalTicket, SkillUploadInput, StageScope, UpdateAgentInput, UpdateMcpInput, WorkspaceFileEntry };
|
|
1666
|
+
export type { AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, AssumeRoleResult, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, ChannelRecordConfig, ConfigPatch, Connection, ConnectionCode, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateMcpInput, DeleteAccountResult, McpOauthInput, McpRuntime, RotateSecretResult, SandboxLifecycleResult, SandboxSnapshotResult, SandboxTerminalTicket, SkillUploadInput, StageScope, UpdateAgentInput, UpdateMcpInput, WorkspaceFileEntry };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
function V(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*ge(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
|
+
`);o=s.pop()??"";for(let a of s)if(a.startsWith("data: "))yield a.slice(6)}}finally{n.releaseLock()}}var Me=500,Ce=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,he=/^(?!0{32}$)[0-9a-f]{32}$/;function Pe(e){return e==="DEBUG"||e==="INFO"||e==="WARN"||e==="ERROR"}function Ne(e){if(typeof e!=="object"||e===null)return!1;let n=e;if(n.type==="subscribe")return Re(n);if(n.type==="unsubscribe")return k(n.stream);if(n.type==="fetchTrace")return Ie(n.traceId);return!1}function je(e){return e==="task"||e==="cron"||e==="subtask"}function G(e){return typeof e==="string"&&Ce.test(e)}function Ie(e){return typeof e==="string"&&he.test(e)}function k(e){return e==="logs"||e==="traces"}function Re(e){let n=e.stream;if(!k(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&&!Pe(o))return!1;let r=e.sandboxId;return r===void 0||n==="logs"&&G(r)}import{readFileSync as Se}from"node:fs";import{chmod as B,mkdir as be,writeFile as Ae}from"node:fs/promises";import{homedir as ke}from"node:os";import{dirname as D,join as ve}from"node:path";var y="broods",_="_generated",O=ve(ke(),".broods","config.json"),N="broods.app",P="dashboard",we="gateway";function T(e){let n=process.env.BROODS_TOKEN,t=e??process.env.BROODS_BASE_URL;if(n&&t)return{baseUrl:f(t),token:n,createdAt:new Date().toISOString()};let o=H();if(!o)return null;if(t)return o.logins[f(t)]??null;let r=process.env.BROODS_DASHBOARD_URL;if(r){let i=f(r);return Object.values(o.logins).find((s)=>s.dashboardUrl===i)??null}return o.logins[o.current]??null}async function W(e){let n=H()?.logins??{},t={current:e.baseUrl,logins:{...n,[e.baseUrl]:e}};await be(D(O),{recursive:!0,mode:448}),await B(D(O),448),await K(O,`${JSON.stringify(t,null,2)}
|
|
3
|
+
`)}async function K(e,n){await Ae(e,n,{encoding:"utf8",mode:384}),await B(e,384)}function v(){return process.env.BROODS_STAGE}function f(e){let n=e.length;while(n>0&&e.charCodeAt(n-1)===47)n-=1;return e.slice(0,n)}function L(e){try{let n=new URL(e);if(!n.hostname.startsWith(`${P}.`))return;let t=n.hostname.slice(P.length+1);if(t!==N&&!t.endsWith(`.${N}`))return;return n.hostname=`${we}.${t}`,f(n.origin)}catch{return}}function H(){try{let e=JSON.parse(Se(O,"utf8"));if(typeof e.current!=="string"||!e.logins)return null;return{current:e.current,logins:e.logins}}catch{return null}}import{existsSync as q,readFileSync as Z,statSync as Ee}from"node:fs";import{join as X,resolve as Q}from"node:path";var A=new Map,Te=new Set(Object.keys(process.env)),j=new Set;function h(e=process.cwd()){Oe(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:v()}}function U(){let e={};for(let[n,t]of Object.entries(process.env))if(typeof t==="string"&&!n.startsWith("BROODS_"))e[n]=t;return e}function M(e,n=process.cwd()){let t=process.env[e];if(t===void 0)return!1;let o=Q(n);for(let r of[".env.local",".env"]){let i=X(o,r);if(!q(i))continue;let s=ee(Z(i,"utf8"));if(s[e]!==void 0)return s[e]!==t}return!0}function Oe(e){let n=Q(e),t=process.env.BROODS_RELOAD_ENV==="1";for(let o of[".env",".env.local"]){let r=X(n,o);if(!q(r)){A.delete(r);continue}let i=Ee(r).mtimeMs,s=A.get(r);if(s&&s.mtimeMs===i)continue;A.set(r,{mtimeMs:i});for(let[a,p]of Object.entries(ee(Z(r,"utf8"))))if(t||!Te.has(a)||j.has(a))process.env[a]=p,j.add(a)}}function ee(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]=_e(r.slice(i+1).trim())}return n}function _e(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 E="https://gateway.broods.app";class ye extends Error{accepted;constructor(e){super(`Ingress ${e.eventId} was accepted asynchronously with status ${e.status??"queued"}`);this.accepted=e;this.name="IngressAcceptedError"}}class F{baseUrl;apiKey;fetchImpl;constructor(e={}){h(),this.baseUrl=J(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||E),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||void 0,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=ne(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 ye(te(await i.json(),o));if(!i.body)throw Error("Run response has no body");for await(let s of ge(i.body)){let a;try{a=JSON.parse(s)}catch{continue}if(a.type==="error")throw Error(`Agent run failed: ${$e(a.error)}`);yield a}}async runAsync(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o={...ne(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: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 en(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:this.apiKeyHeaders(),body:JSON.stringify(n)});if(o.status!==202)throw Error(`${t} failed: ${o.status} ${await ze(o,"202 JSON")}`);return this.asyncAgentRun(te(await o.json(),n),n.conversationKey)}async openStream(e,n){if(this.apiKey)return await this.fetchCore(e,n,{Authorization:`Bearer ${this.apiKey}`});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 ${E} 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)}`)}}apiKeyHeaders(){if(!this.apiKey)throw Error("BroodsClient requires apiKey or BROODS_API_KEY.");return{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}}async fetchJson(e,n){let t=n.headers instanceof Headers||Array.isArray(n.headers)?Object.fromEntries(new Headers(n.headers).entries()):Object.fromEntries(Object.entries(n.headers??{}).map(([o,r])=>[o,typeof r==="string"?r:r.join(", ")]));if(!Object.keys(t).some((o)=>o.toLowerCase()==="content-type"))t["Content-Type"]="application/json";try{return await this.fetchImpl(e,{...n,headers:t})}catch(o){throw Error(`Cannot access the broods core service at ${e}. Cause: ${o instanceof Error?o.message:String(o)}`)}}resolveStatusUrl(e){if(typeof e!=="string")return e.statusUrl;if(/^https?:\/\//.test(e))return e;return nn(this.baseUrl,e)}}function J(e){let n=e.trim(),t=/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(n)?n:`https://${n}`;return f(t)}function ne(e,n){let t=e.eventId??`${n}-${crypto.randomUUID()}`;return{agentId:e.agentId,eventId:t,conversationKey:e.conversationKey??t,events:V(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 $e(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 te(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 ze(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 en(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 nn(e,n){return`${J(e)}/v1/runs/${encodeURIComponent(n)}`}var tn=2000,oe=0,R=1;class xe{baseUrl;apiKey;WebSocketImpl;connectTimeoutMs;constructor(e={}){if(h(),this.baseUrl=ue(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||E),this.apiKey=e.apiKey||process.env.BROODS_API_KEY||"",!this.apiKey)throw Error("BroodsWebSocketClient requires apiKey or BROODS_API_KEY.");this.WebSocketImpl=e.WebSocket,this.connectTimeoutMs=e.connectTimeoutMs??tn}subscribe(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=on(e),i=ce(this.baseUrl),s=new t(o,z(this.apiKey)),a=!1,p=!1,d=setTimeout(()=>{if(!a)C(i)},this.connectTimeoutMs),x=(l=1000,b="client closed")=>{if(p)return;if(p=!0,clearTimeout(d),e.signal?.removeEventListener("abort",S),s.readyState===R||s.readyState===oe)s.close(l,b)},C=(l)=>{n.onError?.(l),x(1011,"websocket error")},me=()=>{n.onDone?.(),x(1000,"done")},S=()=>{if(s.readyState===R)s.send(JSON.stringify({type:"cancel"}));C(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",S,{once:!0}),s.onopen=()=>{if(a=!0,clearTimeout(d),e.signal?.aborted){S();return}s.send(JSON.stringify({type:"execute",agentId:r,...e.answers?{answers:e.answers}:{events:V(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=(l)=>{if(typeof l.data!=="string")return;let b=se(l.data);if(!b)return;let I=ae(b,n);switch(n.onMessage?.(I),I.type){case"meta":n.onMeta?.(I);break;case"done":me();break;case"error":C(Error(re(I.error)));break}},s.onerror=()=>{C(i)},s.onclose=(l)=>{if(clearTimeout(d),e.signal?.removeEventListener("abort",S),p||l.code===1000)return;C(Error(l.reason||"WebSocket connection closed."))},{url:o,sendControl:function(l){if(s.readyState!==R)throw Error("WebSocket is not open");s.send(JSON.stringify({type:"control",...l}))},close:x}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o,z(this.apiKey)),i=!1,s=(a=1000,p="client closed")=>{if(i)return;if(i=!0,r.readyState===R||r.readyState===oe)r.close(a,p)};return r.onopen=()=>r.send(JSON.stringify({type:"attach",...e,signal:void 0,agent:void 0})),r.onmessage=(a)=>{if(typeof a.data!=="string")return;let p=se(a.data);if(!p)return;let d=ae(p,n);if(n.onMessage?.(d),d.type==="done")n.onDone?.();if(d.type==="error")n.onError?.(Error(re(d.error)))},r.onerror=()=>n.onError?.(ce(this.baseUrl)),r.onclose=(a)=>{if(!i&&a.code!==1000)n.onError?.(Error(a.reason||"WebSocket connection closed."))},{url:o,sendControl:function(a){if(r.readyState!==R)throw Error("WebSocket is not open");r.send(JSON.stringify({type:"control",...a}))},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=rn(e),t=e.projectSlug??e.agent?.projectSlug,o=e.stageSlug??e.agent?.stageSlug,r=t&&o?`/projects/${encodeURIComponent(t)}/stages/${encodeURIComponent(o)}`:"";return`${Y(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 Y(e){let n=new URL(ue(e));if(n.protocol==="https:")n.protocol="wss:";if(n.protocol==="http:")n.protocol="ws:";return f(n.toString())}function z(e){return["broods.v1",`broods.token.${e}`]}function re(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 ue(e){let n=e.trim();if(/^wss?:\/\//.test(n))return f(n);return J(n)}function se(e){try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}function on(e){let n=e.agentId??e.agent?.id??e.endpointId;if(!n)throw Error("WebSocket run requires agent, agentId, or endpointId.");return n}function rn(e){let n=e.endpointId??e.agent?.endpointId??e.agent?.id;if(!n)throw Error("WebSocket run requires agent or endpointId.");return n}function ae(e,n){if(e.type!=="output")return e;let t=e;return n.onOutput?.(t),t.data}function ce(e){return Error(`Cannot access the WebSocket service at ${e}.`)}var pe=Symbol.for("broods.resource"),de=Symbol.for("broods.config"),fe=Symbol.for("broods.connection"),le=/^[A-Z][A-Z0-9_]{0,63}$/,qe=new Proxy((e)=>{if(!le.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"&&le.test(n))throw Error(`env.${n} is not supported; use env("${n}")`);return Reflect.get(e,n,t)}});function De(e){let{name:n,description:t,...o}=e;return m("agent",n,t,o)}function Le(e){return{[de]:!0,config:e}}function Ue(e){let{name:n,description:t,...o}=e;return m("cron",n,t,o)}function Fe(e){return e}function Be(e){let{name:n,description:t,...o}=e;return m("mcp",n,t,o)}function Ze(e){let{name:n,description:t,...o}=e;return m("policy",n,t,o)}function He(e){let{name:n,description:t,...o}=e;return m("sandbox",n,t,o)}function Ve(e){let{name:n,description:t,...o}=e;return m("skill",n,t,o)}function Ge(e){let{name:n,description:t,...o}=e;return m("workspace",n,t,o)}function We(e){return u("discord",e)}function Ke(e){return u("github",e)}function Je(e){return u("gchat",e)}function Ye(e){return u("instagram",e)}function Xe(e){return u("linear",e)}function Qe(e){return u("matrix",e)}function et(e){return u("messenger",e)}function tt(e){return u("pancake",e)}function nt(e){return u("slack",e)}function rt(e){return u("teams",e)}function ot(e){return u("telegram",e)}function st(e){return u("twilio",e)}function it(e){return u("whatsapp",e)}function at(e){return u("zalo",e)}function ct(e){let{name:n,description:t,channelId:o,guildId:r,...i}=e;return c(n,t,o,r,i)}function lt(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 c(n,t,o,i,r)}function ut(e){let{name:n,description:t,spaceName:o,...r}=e;return c(n,t,o,void 0,r)}function dt(e){let{name:n,description:t,igsid:o,...r}=e;return c(n,t,o,void 0,r)}function pt(e){let{name:n,description:t,team:o,...r}=e;return c(n,t,o,void 0,r)}function mt(e){let{name:n,description:t,channelId:o,...r}=e;return c(n,t,o,void 0,r)}function ht(e){let{name:n,description:t,psid:o,...r}=e;return c(n,t,o,void 0,r)}function ft(e){let{name:n,description:t,conversationId:o,...r}=e;return c(n,t,o,void 0,r)}function gt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return c(n,t,o,r,i)}function yt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return c(n,t,o,r,i)}function St(e){let{name:n,description:t,chatId:o,...r}=e;return c(n,t,o,void 0,r)}function bt(e){let{name:n,description:t,from:o,...r}=e;return c(n,t,o,void 0,r)}function vt(e){let{name:n,description:t,waId:o,...r}=e;return c(n,t,o,void 0,r)}function _t(e){let{name:n,description:t,chatId:o,...r}=e;return c(n,t,o,void 0,r)}function ie(e){return Boolean(e&&typeof e==="object"&&e[de])}function w(e){return Boolean(e&&typeof e==="object"&&e[fe])}function g(e){return Boolean(e&&typeof e==="object"&&e[pe])}function c(e,n,t,o,r){return m("channelRecord",e,n,{...r,externalId:t,...o?{workspaceRef:o}:{}})}function u(e,n){let{partition:t,...o}=n;return{[fe]:!0,kind:"connection",type:e,...t?{partition:t}:{},config:o}}function m(e,n,t,o){return{[pe]:!0,kind:e,name:n,...t?{description:t}:{},config:o}}
|
|
5
|
+
export{V,ge,Me,Pe,Ne,je,G,Ie,y,_,O,T,W,K,v,f,L,h,U,M,E,ye,F,J,xe,Y,z,qe,De,Le,Ue,Fe,Be,Ze,He,Ve,Ge,We,Ke,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,it,at,ct,lt,ut,dt,pt,mt,ht,ft,gt,yt,St,bt,vt,_t,ie,w,g};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{U}from"./chunk-
|
|
1
|
+
import{U}from"./chunk-agza3wkj.js";import{Oe,e,n,t,s}from"./chunk-n890pdvc.js";import{readFileSync as m}from"node:fs";import{dirname as d,resolve as p}from"node:path";import{Client as g}from"@modelcontextprotocol/client";import{StdioClientTransport as h}from"@modelcontextprotocol/client/stdio";var f={name:"broods-machine",version:"1.0.0"},u=t({command:e().min(1),args:n(e()).default([]),env:s(e(),e()).optional(),cwd:e().optional()}),w=t({mcpServers:s(e(),u).refine((r)=>Object.keys(r).length>0,"lists no MCP servers")});class y{#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 h({...o,env:{...U(),...o.env},stderr:"inherit"});a.onclose=()=>{if(this.#e(`mcp ${r}: exited`),this.#t.get(r)===c)this.#t.delete(r)};let l=new g(f);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 b(r){let o=p(r),i=w.safeParse(v(o));if(!i.success)throw Error(`${o}: ${Oe(i.error)}`);return new Map(Object.entries(i.data.mcpServers).map(([c,a])=>[c,a.cwd?{...a,cwd:p(d(o),a.cwd)}:a]))}function v(r){try{return JSON.parse(m(r,"utf8"))}catch(o){throw Error(`could not read ${r}: ${o instanceof Error?o.message:String(o)}`)}}export{y as McpHost,b as readMcpServersFile};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{U,z}from"./chunk-
|
|
1
|
+
import{U,z}from"./chunk-agza3wkj.js";import{e,o,a,l,n,t,d,C,s,p,r}from"./chunk-n890pdvc.js";import{se,fe,D}from"./cli/index.js";import{spawn as te}from"node:child_process";import{hostname as oe}from"node:os";import{performance as L}from"node:perf_hooks";var N=["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 _={badFrame:{code:4400,reason:"Malformed frame"},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 H="/v1/machines/ws",P=t({action:p(N),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:p(["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.")}),B=P.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()}),G=t({type:r("exec"),id:e(),code:e(),cwd:e().optional(),env:s(e(),e()).optional(),timeoutSeconds:o().positive(),outputLimitBytes:o().positive()}),J=t({type:r("hello"),sandbox:e().min(1),hostname:e().optional(),platform:e().optional(),computer:a().optional(),mcp:n(e()).optional(),instance:e().optional(),force:a().optional()}),K=t({type:r("mcp-call"),id:e(),server:e(),tool:e(),args:s(e(),l())}),X=t({type:r("mcp-list"),id:e(),server:e()}),Y=t({type:r("mcp-result"),id:e(),result:d({content:n(l())}).optional(),error:e().optional()}),q=t({type:r("mcp-tools"),id:e(),tools:n(d({name:e(),inputSchema:s(e(),l())})).optional(),error:e().optional()}),Z=t({type:r("ready"),sandboxId:e()}),Q=t({type:r("result"),id:e(),exitCode:o().nullable(),stdout:e(),stderr:e(),durationMs:o(),timedOut:a(),truncated:a()}),V=C("type",[B,G,K,X,Z]),ue=C("type",[W,J,Y,q,Q]);function T(i){let c=new URL(H,i);return c.protocol=c.protocol==="https:"?"wss:":"ws:",c.toString()}function R(i){return ee(V,i)}function ee(i,c){if(typeof c!=="string")return null;try{let u=i.safeParse(JSON.parse(c));return u.success?u.data:null}catch{return null}}var re=new Set([_.occupied.code,_.replaced.code,_.unauthorized.code,_.unknownSandbox.code]),A=72,k=30000,I=1000;function ne(i,c,u){return new Promise((f)=>{let m=L.now(),h=new E(i.outputLimitBytes),w=new E(i.outputLimitBytes),b=!1,x=!1,M=(y,O)=>{if(x)return;if(x=!0,clearTimeout(v),u?.removeEventListener("abort",g),O)w.append(Buffer.from(`${O}
|
|
2
2
|
`));f({type:"result",id:i.id,exitCode:y,stdout:h.text(),stderr:w.text(),durationMs:Math.round(L.now()-m),timedOut:b,truncated:h.truncated||w.truncated})},F=te("bash",["-lc",i.code],{cwd:i.cwd??c,env:{...U(),...i.env},detached:!0,stdio:["ignore","pipe","pipe"]}),S=()=>{if(!F.pid)return;try{process.kill(-F.pid,"SIGKILL")}catch{F.kill("SIGKILL")}},v=setTimeout(()=>{b=!0,S()},i.timeoutSeconds*1000),g=()=>{S(),M(null,"stopped: the daemon closed its socket")};if(u?.addEventListener("abort",g,{once:!0}),F.stdout.on("data",(y)=>h.append(y)),F.stderr.on("data",(y)=>w.append(y)),F.on("error",(y)=>M(null,y.message)),F.on("close",(y)=>M(y)),u?.aborted)g()})}async function we(i){let c=fe(),u=crypto.randomUUID(),f=i.mcpFile?await ce(i.mcpFile,i.log):null,m=i.computer?await ae(i.log):null,h=I;try{while(!i.signal.aborted){let w=Date.now(),b;try{b=await i.credential()}catch(M){if(M instanceof D)throw M;i.log(`stage session unavailable (${M instanceof Error?M.message:String(M)}), retrying in ${Math.round(h/1000)}s`),await se(h,i.signal),h=Math.min(h*2,k);continue}let x=await pe(i,b,u,c,m,f);if(i.signal.aborted)return;if(re.has(x.code))throw Error(x.reason||`core closed the socket (${x.code})`);if(Date.now()-w>k)h=I;i.log(`disconnected (${x.reason||x.code}), reconnecting in ${Math.round(h/1000)}s`),await se(h,i.signal),h=Math.min(h*2,k)}}finally{m?.stop(),await f?.stop()}}class E{#o=[];#e;#t=0;truncated=!1;constructor(i){this.#e=i}append(i){if(this.#t>=this.#e){this.truncated=!0;return}let c=this.#e-this.#t;if(i.byteLength>c){this.#o.push(i.subarray(0,c)),this.#t=this.#e,this.truncated=!0;return}this.#o.push(i),this.#t+=i.byteLength}text(){let i=Buffer.concat(this.#o).toString("utf8");return this.truncated?`${i}
|
|
3
3
|
[output truncated]`:i}}function ie(i){let c=[i.action];if(i.coordinate)c.push(`at ${i.coordinate.join(",")}`);if(i.text!==void 0)c.push(JSON.stringify(j(i.text)));if(i.region)c.push(`region ${i.region.join(",")}`);return c.join(" ")}function j(i){let c=i.trim().split(`
|
|
4
|
-
`)[0]??"";return c.length>A?`${c.slice(0,A)}…`:c}async function ae(i){let{startDesktop:c}=await import("./chunk-5tnnqapc.js"),{display:u,driver:f,permissions:m}=await c(!1);if(i(`computer use on, ${u.width}x${u.height} screenshots`),!m.screenRecording||!m.accessibility)i(" screen recording or accessibility is missing, run `broods machine --doctor --request`");return f}async function ce(i,c){let{McpHost:u,readMcpServersFile:f}=await import("./chunk-
|
|
4
|
+
`)[0]??"";return c.length>A?`${c.slice(0,A)}…`:c}async function ae(i){let{startDesktop:c}=await import("./chunk-5tnnqapc.js"),{display:u,driver:f,permissions:m}=await c(!1);if(i(`computer use on, ${u.width}x${u.height} screenshots`),!m.screenRecording||!m.accessibility)i(" screen recording or accessibility is missing, run `broods machine --doctor --request`");return f}async function ce(i,c){let{McpHost:u,readMcpServersFile:f}=await import("./chunk-b68w0qr7.js"),m=new u(f(i),c);return c(`mcp servers from ${i}: ${m.names().join(", ")}`),m}async function le(i,c,u){try{if(i.type==="mcp-list"){let m=await c.listTools(i.server);return u(` mcp ${i.server}: ${m.length} tools`),{type:"mcp-tools",id:i.id,tools:m}}u(` mcp ${i.server}.${i.tool}`);let f=await c.callTool(i.server,i.tool,i.args);return{type:"mcp-result",id:i.id,result:f}}catch(f){let m=f instanceof Error?f.message:String(f);return u(` mcp ${i.server}: ${m}`),{type:i.type==="mcp-call"?"mcp-result":"mcp-tools",id:i.id,error:m}}}function pe(i,c,u,f,m,h){return new Promise((w)=>{let b=new f(T(i.baseUrl),z(c)),x=new AbortController,M=()=>b.close(1000,"daemon stopped"),F=(v)=>{if(b.readyState===b.OPEN)b.send(JSON.stringify(v))},S=(v,g)=>{i.signal.removeEventListener("abort",M),x.abort(),w({code:v,reason:g})};i.signal.addEventListener("abort",M,{once:!0}),b.onopen=()=>F({type:"hello",sandbox:i.sandbox,hostname:oe(),platform:process.platform,computer:m!==null,mcp:h?.names(),instance:u,force:i.force}),b.onmessage=(v)=>{let g=R(v.data);if(g?.type==="ready"){i.log(`connected as ${i.sandbox} (${g.sandboxId})`);return}if(g?.type==="computer"&&m){i.log(` ${ie(g)}`),m.run(g).then((y)=>{if(y.error)i.log(` error: ${y.error}`);F(y)});return}if((g?.type==="mcp-call"||g?.type==="mcp-list")&&h){le(g,h,i.log).then(F);return}if(g?.type!=="exec")return;i.log(`$ ${j(g.code)}`),ne(g,i.cwd,x.signal).then((y)=>{i.log(` exit ${y.exitCode??"none"} in ${y.durationMs}ms${y.timedOut?" (timed out)":""}`),F(y)})},b.onerror=()=>S(1006,"connection failed"),b.onclose=(v)=>S(v.code,v.reason)})}export{we as runMachineDaemon};
|