broods 0.49.3 → 0.51.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/index.d.ts CHANGED
@@ -888,10 +888,14 @@ declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
888
888
  type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
889
889
  type WorkspaceStorageAuth = {
890
890
  type: "managed";
891
- } | {
891
+ }
892
+ /**
893
+ * The role's trust policy requires the account's Broods-assigned
894
+ * sts:ExternalId (`storageTrust.ts`); a customer never sets one here.
895
+ */
896
+ | {
892
897
  type: "assumeRole";
893
898
  roleArn: string;
894
- externalId?: string;
895
899
  } | {
896
900
  type: "r2";
897
901
  /** `${NAME}` ref to the parent R2 token's access key id. */
@@ -1288,8 +1292,9 @@ type MessengerSource = MetaSource;
1288
1292
  * Canonical CLI manifest wire types, the single source of truth shared by the
1289
1293
  * backend (cliSync.ts, cliHttp.ts) and the SDK/CLI (packages/broods).
1290
1294
  *
1291
- * This file is intentionally type-only with no runtime imports so the SDK can
1292
- * import it without pulling the Convex server module graph into its typecheck.
1295
+ * This file intentionally has no runtime imports (its values are plain
1296
+ * lists) so the SDK can import it without pulling the Convex server module
1297
+ * graph into its typecheck.
1293
1298
  */
1294
1299
  type CliManifestResource = {
1295
1300
  kind: "agent" | "workspace" | "sandbox" | "cron" | "skill" | "hook" | "mcp" | "policy" | "channelRecord";
@@ -1308,10 +1313,18 @@ type GeneratedIds = {
1308
1313
  policies: Record<string, string>;
1309
1314
  channelRecords: Record<string, string>;
1310
1315
  };
1316
+ /** Where a Production stage runs. */
1317
+ declare const DEPLOYMENT_REGIONS: readonly ["ap-southeast-1", "eu-west-1", "us-east-1"];
1318
+ type DeploymentRegion = (typeof DEPLOYMENT_REGIONS)[number];
1311
1319
  type CliManifest = {
1312
1320
  version: 1;
1313
1321
  project: string;
1314
1322
  stage: string;
1323
+ /**
1324
+ * Production only: the region its first deploy pins (eu-west-1 when unset).
1325
+ * A later deploy naming another region is refused.
1326
+ */
1327
+ region?: DeploymentRegion;
1315
1328
  resources: CliManifestResource[];
1316
1329
  };
1317
1330
 
@@ -1774,6 +1787,13 @@ interface BroodsClientOptions {
1774
1787
  host?: string;
1775
1788
  /** Runtime key used as the Bearer token for direct runtime calls. */
1776
1789
  apiKey?: string;
1790
+ /**
1791
+ * The signed-in user's token, sent beside the runtime key on every call.
1792
+ * Pass a function to get a fresh one per call (a browser fetches it from
1793
+ * your backend, which signs it with `signUserToken`). An agent that
1794
+ * requires one refuses the runtime key without it.
1795
+ */
1796
+ userToken?: string | (() => string | Promise<string>);
1777
1797
  fetch?: typeof fetch;
1778
1798
  }
1779
1799
  type AgentHandle = {
@@ -1786,6 +1806,7 @@ type AgentHandle = {
1786
1806
  declare class BroodsClient {
1787
1807
  private readonly baseUrl;
1788
1808
  private readonly apiKey?;
1809
+ private readonly userToken?;
1789
1810
  private readonly fetchImpl;
1790
1811
  constructor(options?: BroodsClientOptions);
1791
1812
  /** Return the public provider webhook URL for a generated channel reference. */
@@ -1848,11 +1869,52 @@ declare class BroodsClient {
1848
1869
  private openStream;
1849
1870
  private fetchCore;
1850
1871
  private apiKeyHeaders;
1872
+ private userTokenHeaders;
1851
1873
  private fetchJson;
1852
1874
  private resolveStatusUrl;
1853
1875
  }
1854
1876
  declare function normalizeHttpServiceUrl(value: string): string;
1855
1877
 
1878
+ /** The HTTP header a token rides on. */
1879
+ declare const USER_TOKEN_HEADER = "x-broods-user-token";
1880
+ /** A token naming a later expiry is refused: it is a bearer for its whole life. */
1881
+ declare const USER_TOKEN_MAX_TTL_MS: number;
1882
+
1883
+ /**
1884
+ * Server-side signing of end-user tokens. The runtime key (`bsk_`) sits in a
1885
+ * frontend, so it cannot say who is using it; your backend, which knows the
1886
+ * signed-in user, signs a short-lived token with the stage's signing secret
1887
+ * (`bsig_`, from the dashboard's Runtime key tab) and hands it to the
1888
+ * frontend. Core then keeps every conversation that request touches under
1889
+ * that user, so one visitor can never read or steer another's. Never ship the
1890
+ * signing secret to a browser.
1891
+ */
1892
+
1893
+ /**
1894
+ * The env var `signUserToken` reads the signing secret from, and the one
1895
+ * `broods dev` / `broods deploy` write it to in `.env.local`.
1896
+ */
1897
+ declare const USER_TOKEN_SECRET_ENV = "BROODS_USER_TOKEN_SECRET";
1898
+ interface SignUserTokenInput {
1899
+ /** Your own id for the signed-in user. Letters, digits and `._@+=-`, at most 128. */
1900
+ userId: string;
1901
+ /**
1902
+ * The conversation keys this user may use. Omit to allow any key, which
1903
+ * still lands under this user only.
1904
+ */
1905
+ conversations?: string[];
1906
+ /** Lifetime in ms. Defaults to 10 minutes, at most 60. */
1907
+ ttlMs?: number;
1908
+ /** The stage's `bsig_` signing secret. Defaults to `BROODS_USER_TOKEN_SECRET`. */
1909
+ secret?: string;
1910
+ }
1911
+ /**
1912
+ * A user token for the runtime key: pass it as `userToken` to `BroodsClient`
1913
+ * or `BroodsWebSocketClient`, or send it in the `X-Broods-User-Token` header.
1914
+ * @throws when no signing secret is set or an input is out of range
1915
+ */
1916
+ declare function signUserToken(input: SignUserTokenInput): Promise<string>;
1917
+
1856
1918
  /**
1857
1919
  * Connections: external accounts an agent acts through, one of each type per
1858
1920
  * Broods account. `broods connect <type>` opens the provider's sign-in; the
@@ -2285,6 +2347,18 @@ interface RotateSecretResult {
2285
2347
  account: BroodsAccount;
2286
2348
  secret: string;
2287
2349
  }
2350
+ /**
2351
+ * Result of `GET /v1/account/storage-trust`: what a workspace's own AWS role
2352
+ * must trust. Broods assigns `externalId` per account and sends it on every
2353
+ * AssumeRole of an `assumeRole` workspace's role; it is never set in config.
2354
+ */
2355
+ interface StorageTrust {
2356
+ externalId: string;
2357
+ /** The Broods AWS principal to trust; absent on a deployment with no AWS. */
2358
+ principalArn?: string;
2359
+ /** A ready-to-paste trust policy JSON; absent on a deployment with no AWS. */
2360
+ trustPolicy?: string;
2361
+ }
2288
2362
  /** Result of `DELETE /v1/account`: the account and all account-scoped data are removed; `cleanup` reports per-resource deletion counts. */
2289
2363
  interface DeleteAccountResult {
2290
2364
  deleted: boolean;
@@ -2334,6 +2408,8 @@ declare class BroodsAccountClient {
2334
2408
  constructor(options?: BroodsAccountClientOptions);
2335
2409
  /** The account this secret belongs to. Its `accountId` is the first segment of channel webhook URLs. */
2336
2410
  getAccount(): Promise<BroodsAccount>;
2411
+ /** The external id and Broods principal this account's own storage roles must trust. */
2412
+ getStorageTrust(): Promise<StorageTrust>;
2337
2413
  /** Update account metadata (username/description). Returns null when the account is gone. Runtime config is managed through the agent endpoints. */
2338
2414
  updateAccount(patch: {
2339
2415
  username?: string;
@@ -2444,7 +2520,7 @@ declare class BroodsAccountClient {
2444
2520
  resumeSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
2445
2521
  /** Terminate a persistent sandbox reservation and drop its live-instance row. Throws on 404/403/409. */
2446
2522
  terminateSandbox(sandboxId: string, reservationKey: string): Promise<SandboxLifecycleResult>;
2447
- /** Snapshot a persistent sandbox reservation into an image any sandbox of that provider can pin with `snapshot` (`sandbox`, `daytona`, `e2b`, `vercel`, or `lambda`, which answers `building` until its image build lands). Throws on 404/403/409. */
2523
+ /** Snapshot a persistent sandbox reservation into an image any sandbox of that provider on the same stage can pin with `snapshot` (`sandbox`, `daytona`, `e2b`, `vercel`, or `lambda`, which answers `building` until its image build lands). The snapshot is locked to the stage of the sandbox it was taken from: pinning it on another stage throws a 400. Throws on 404/403/409. */
2448
2524
  snapshotSandbox(sandboxId: string, reservationKey: string, name: string): Promise<SandboxSnapshotResult>;
2449
2525
  /** Mint a short-lived sealed ticket for an interactive PTY session on a persistent sandbox (`sandbox`/`lambda`/`cloudflare` providers). Throws on 404/403/409. */
2450
2526
  openSandboxTerminal(sandboxId: string, reservationKey: string): Promise<SandboxTerminalTicket>;
@@ -2570,6 +2646,8 @@ type WebSocketRunInput = {
2570
2646
  /** Defaults to "steer": join the live run at its next step boundary. */
2571
2647
  mode?: "reject" | "followup" | "collect" | "steer";
2572
2648
  idempotencyKey?: string;
2649
+ /** This socket's user token, over the client's `userToken`. */
2650
+ userToken?: string;
2573
2651
  } & (AgentRunEventInput | AgentRunAnswerInput) & AgentRunOverrides;
2574
2652
  type WebSocketAttachInput = Omit<WebSocketClientAttachMessage, "type"> & {
2575
2653
  endpointId?: string;
@@ -2577,6 +2655,8 @@ type WebSocketAttachInput = Omit<WebSocketClientAttachMessage, "type"> & {
2577
2655
  projectSlug?: string;
2578
2656
  stageSlug?: string;
2579
2657
  signal?: AbortSignal;
2658
+ /** This socket's user token, over the client's `userToken`. */
2659
+ userToken?: string;
2580
2660
  };
2581
2661
  interface WebSocketHandlers {
2582
2662
  /**
@@ -2605,6 +2685,13 @@ interface BroodsWebSocketClientOptions {
2605
2685
  host?: string;
2606
2686
  /** Runtime key used as the WebSocket token. Defaults to BROODS_API_KEY from the environment or local .env files. */
2607
2687
  apiKey?: string;
2688
+ /**
2689
+ * The signed-in user's token (from `signUserToken` on your backend). Each
2690
+ * socket carries it from its upgrade on; an agent that requires one refuses
2691
+ * the runtime key without it. Tokens are short-lived, so a long-lived client
2692
+ * passes a fresh one per run as `userToken` on the input instead.
2693
+ */
2694
+ userToken?: string;
2608
2695
  WebSocket?: WebSocketConstructorLike;
2609
2696
  connectTimeoutMs?: number;
2610
2697
  }
@@ -2628,6 +2715,7 @@ interface WebSocketLike {
2628
2715
  declare class BroodsWebSocketClient {
2629
2716
  private readonly baseUrl;
2630
2717
  private readonly apiKey;
2718
+ private readonly userToken?;
2631
2719
  private readonly WebSocketImpl?;
2632
2720
  private readonly connectTimeoutMs;
2633
2721
  constructor(options?: BroodsWebSocketClientOptions);
@@ -2641,11 +2729,11 @@ declare class BroodsWebSocketClient {
2641
2729
  declare function toWebSocketBaseUrl(url: string): string;
2642
2730
  /**
2643
2731
  * The credential travels as a `Sec-WebSocket-Protocol` entry rather than in
2644
- * the URL, so it never lands in proxy or access logs. The gateway answers
2645
- * with `broods.v1`, which is what completes a handshake that offered
2646
- * subprotocols.
2732
+ * the URL, so it never lands in proxy or access logs, and so does the user
2733
+ * token. The gateway answers with `broods.v1`, which is what completes a
2734
+ * handshake that offered subprotocols.
2647
2735
  */
2648
- declare function webSocketSubprotocols(apiKey: string): string[];
2736
+ declare function webSocketSubprotocols(apiKey: string, userToken?: string): string[];
2649
2737
 
2650
2738
  /**
2651
2739
  * Resource definition helpers for the code-first `broods/` project folder.
@@ -3340,5 +3428,5 @@ declare function isBroodsConfig(value: unknown): value is BroodsConfigDefinition
3340
3428
  declare function isConnectionDefinition(value: unknown): value is AnyConnectionDefinition;
3341
3429
  declare function isResource(value: unknown): value is AnyResource;
3342
3430
 
3343
- export { BroodsAccountApiError, BroodsAccountClient, BroodsClient, BroodsWebSocketClient, DEFAULT_CORE_BASE_URL, IngressAcceptedError, MAX_OBSERVABILITY_BACKFILL, BroodsWebSocketClient as WebSocketClient, BroodsWebSocketClient as WebsocketClient, defineAgent, defineBroods, defineCron, defineDiscordChannel, defineDiscordConnection, defineGitHubChannel, defineGitHubConnection, defineGoogleChatChannel, defineGoogleChatConnection, defineHarness, defineInstagramChannel, defineInstagramConnection, defineLinearChannel, defineLinearConnection, defineMatrixChannel, defineMatrixConnection, defineMcp, defineMessengerChannel, defineMessengerConnection, definePancakeChannel, definePancakeConnection, definePolicy, defineSandbox, defineSkill, defineSlackChannel, defineSlackConnection, defineTeamsChannel, defineTeamsConnection, defineTelegramChannel, defineTelegramConnection, defineTwilioChannel, defineTwilioConnection, defineWhatsAppChannel, defineWhatsAppConnection, defineWorkspace, defineZaloChannel, defineZaloConnection, env, envPlaceholder, isBroodsConfig, isConnectionDefinition, isLogLevel, isObservabilityClientMessage, isResource, isRootSpanKind, isSandboxLogId, isTraceId, normalizeHttpServiceUrl, readSseStream, resolveEnvCredential, resolveRunEvents, toWebSocketBaseUrl, webSocketSubprotocols };
3344
- export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentContinueInput, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentGoogleChatChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentInstagramChannelConfig, AgentLinearChannelConfig, AgentMatrixChannelConfig, AgentMessengerChannelConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunAnswerInput, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTeamsChannelConfig, AgentTelegramChannelConfig, AgentTwilioChannelConfig, AgentWebhookHookConfig, AgentWhatsAppChannelConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AssumeRoleResult, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, ConfigPatch, Connection, ConnectionCode, ConnectionDefinition, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateCronInput, CreateMcpInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, DeleteAccountResult, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, GoogleChatChannelInput, GoogleChatConnectionDefinition, GoogleChatConnectionInput, GoogleChatMessageSource, GoogleChatSource, HarnessDefinition, HarnessType, HookAgentConfig, HookContext, Id, IngressMode, IngressStatus, InstagramChannelInput, InstagramConnectionDefinition, InstagramConnectionInput, InstagramMessageSource, InstagramSource, LinearChannelInput, LinearConnectionDefinition, LinearConnectionInput, LinearMessageSource, LinearSource, LogLevel, MatrixChannelInput, MatrixConnectionDefinition, MatrixConnectionInput, MatrixMessageSource, MatrixSource, McpDefinitionConfig, McpHandler, McpOauthInput, McpResource, McpRuntime, MessengerChannelInput, MessengerConnectionDefinition, MessengerConnectionInput, MessengerMessageSource, MessengerSource, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityFetchTraceMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PendingQuestion, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, QuestionAnswer, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxDefinitionOptions, SandboxExecRequest, SandboxExecResponse, SandboxLifecycleResult, SandboxProvider, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, StageScope, TaskWaitingOn, TeamsChannelInput, TeamsConnectionDefinition, TeamsConnectionInput, TeamsMessageSource, TeamsSource, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, TwilioChannelInput, TwilioConnectionDefinition, TwilioConnectionInput, TwilioMessageSource, TwilioSource, UpdateAgentInput, UpdateCronInput, UpdateMcpInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, WhatsAppChannelInput, WhatsAppConnectionDefinition, WhatsAppConnectionInput, WhatsAppMessageSource, WhatsAppSource, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceIsolation, WorkspaceResource, WorkspaceStorageDefinition, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
3431
+ export { BroodsAccountApiError, BroodsAccountClient, BroodsClient, BroodsWebSocketClient, DEFAULT_CORE_BASE_URL, IngressAcceptedError, MAX_OBSERVABILITY_BACKFILL, USER_TOKEN_HEADER, USER_TOKEN_MAX_TTL_MS, USER_TOKEN_SECRET_ENV, BroodsWebSocketClient as WebSocketClient, BroodsWebSocketClient as WebsocketClient, defineAgent, defineBroods, defineCron, defineDiscordChannel, defineDiscordConnection, defineGitHubChannel, defineGitHubConnection, defineGoogleChatChannel, defineGoogleChatConnection, defineHarness, defineInstagramChannel, defineInstagramConnection, defineLinearChannel, defineLinearConnection, defineMatrixChannel, defineMatrixConnection, defineMcp, defineMessengerChannel, defineMessengerConnection, definePancakeChannel, definePancakeConnection, definePolicy, defineSandbox, defineSkill, defineSlackChannel, defineSlackConnection, defineTeamsChannel, defineTeamsConnection, defineTelegramChannel, defineTelegramConnection, defineTwilioChannel, defineTwilioConnection, defineWhatsAppChannel, defineWhatsAppConnection, defineWorkspace, defineZaloChannel, defineZaloConnection, env, envPlaceholder, isBroodsConfig, isConnectionDefinition, isLogLevel, isObservabilityClientMessage, isResource, isRootSpanKind, isSandboxLogId, isTraceId, normalizeHttpServiceUrl, readSseStream, resolveEnvCredential, resolveRunEvents, signUserToken, toWebSocketBaseUrl, webSocketSubprotocols };
3432
+ export type { Account, AccountAgent, AccountChannel, AccountEnvVar, AccountMcp, AccountPolicy, AccountRole, AccountSandbox, AccountWorkspace, Agent, AgentChannelsConfig, AgentCodeHookConfig, AgentConfig, AgentConfigDoc, AgentContinueInput, AgentDefinitionConfig, AgentDiscordChannelConfig, AgentGitHubChannelConfig, AgentGoogleChatChannelConfig, AgentHandle, AgentHookEventName, AgentHooks, AgentHooksConfig, AgentInstagramChannelConfig, AgentLinearChannelConfig, AgentMatrixChannelConfig, AgentMessengerChannelConfig, AgentPancakeChannelConfig, AgentProviderSettings, AgentReference, AgentResource, AgentRunAnswerInput, AgentRunEventInput, AgentRunInput, AgentRunModelOverrides, AgentRunOverrides, AgentRunResult, AgentSkillsDefinitionConfig, AgentSlackChannelConfig, AgentStreamPart, AgentSubagentDefinitionConfig, AgentTeamsChannelConfig, AgentTelegramChannelConfig, AgentTwilioChannelConfig, AgentWebhookHookConfig, AgentWhatsAppChannelConfig, AgentWorkspaceInput, AgentWorkspaceRef, AgentWorkspaceRefInput, AgentZaloChannelConfig, AnyConnectionDefinition, AnyResource, AssumeRoleResult, AsyncAgentRun, AsyncPollOptions, AsyncRequestAccepted, AsyncStatus, AuditEvent, AuditPage, AuditPrincipalLink, AuditSink, AuditVerification, BroodsAccount, BroodsAccountClientOptions, BroodsClientOptions, BroodsConfigDefinition, BroodsProjectConfig, BroodsWebSocketClientOptions, ChannelAgentInput, ChannelDefinitionConfig, ChannelMessageReceived, ChannelPartition, ChannelRecordConfig, ChannelReference, ChannelReplyIn, ChannelResource, ChannelType, CliManifest, CliManifestResource, ConfigPatch, Connection, ConnectionCode, ConnectionDefinition, ConnectionStart, ConnectionStartResult, ConnectionType, CreateAgentResult, CreateCronInput, CreateMcpInput, Cron, CronDefinitionConfig, CronDoc, CronLastStatus, CronResource, CronRun, CronStatus, DeleteAccountResult, DeploymentRegion, DiscordChannelInput, DiscordConnectionDefinition, DiscordConnectionInput, DiscordMessageSource, DiscordSource, Doc, EnvAccessor, EnvRef, EnvRefString, GeneratedIds, GitHubChannelInput, GitHubConnectionDefinition, GitHubConnectionInput, GitHubMessageSource, GitHubSource, GoogleChatChannelInput, GoogleChatConnectionDefinition, GoogleChatConnectionInput, GoogleChatMessageSource, GoogleChatSource, HarnessDefinition, HarnessType, HookAgentConfig, HookContext, Id, IngressMode, IngressStatus, InstagramChannelInput, InstagramConnectionDefinition, InstagramConnectionInput, InstagramMessageSource, InstagramSource, LinearChannelInput, LinearConnectionDefinition, LinearConnectionInput, LinearMessageSource, LinearSource, LogLevel, MatrixChannelInput, MatrixConnectionDefinition, MatrixConnectionInput, MatrixMessageSource, MatrixSource, McpDefinitionConfig, McpHandler, McpOauthInput, McpResource, McpRuntime, MessengerChannelInput, MessengerConnectionDefinition, MessengerConnectionInput, MessengerMessageSource, MessengerSource, ObservabilityBackfillMessage, ObservabilityClientMessage, ObservabilityErrorMessage, ObservabilityFetchTraceMessage, ObservabilityLogEntry, ObservabilityLogMessage, ObservabilityReadyMessage, ObservabilityServerMessage, ObservabilitySpanMessage, ObservabilitySpanRow, ObservabilitySubscribeMessage, ObservabilityUnsubscribeMessage, PancakeChannelInput, PancakeConnectionDefinition, PancakeConnectionInput, PancakeMessageSource, PancakeSource, PendingQuestion, PolicyDefinitionConfig, PolicyDocument, PolicyResource, ProjectDoc, ProviderConfigInput, ProviderSettingsInput, QuestionAnswer, ResourceApi, ResourceDefinition, ResourceInput, ResourceKind, RotateSecretResult, Sandbox, SandboxConfig, SandboxConfigDoc, SandboxDefinitionConfig, SandboxDefinitionOptions, SandboxExecRequest, SandboxExecResponse, SandboxLifecycleResult, SandboxProvider, SandboxResource, SandboxSnapshotResult, SandboxTerminalTicket, SignUserTokenInput, Skill, SkillDefinitionConfig, SkillResource, SkillUploadInput, SlackChannelInput, SlackConnectionDefinition, SlackConnectionInput, SlackMessageSource, SlackSource, StageDoc, StageScope, StorageTrust, TaskWaitingOn, TeamsChannelInput, TeamsConnectionDefinition, TeamsConnectionInput, TeamsMessageSource, TeamsSource, TelegramChannelInput, TelegramConnectionDefinition, TelegramConnectionInput, TelegramMessageSource, TelegramSource, ToolApprovalSummary, TwilioChannelInput, TwilioConnectionDefinition, TwilioConnectionInput, TwilioMessageSource, TwilioSource, UpdateAgentInput, UpdateCronInput, UpdateMcpInput, WebSocketAttachInput, WebSocketClientAttachMessage, WebSocketClientCancelMessage, WebSocketClientControlMessage, WebSocketClientExecuteMessage, WebSocketClientMessage, WebSocketConstructorLike, WebSocketHandlers, WebSocketLike, WebSocketOutputMessage, WebSocketRunInput, WebSocketServerMessage, WebSocketStreamMessage, WebSocketSubscription, WhatsAppChannelInput, WhatsAppConnectionDefinition, WhatsAppConnectionInput, WhatsAppMessageSource, WhatsAppSource, Workspace, WorkspaceConfig, WorkspaceConfigDoc, WorkspaceDefinitionConfig, WorkspaceFileEntry, WorkspaceIsolation, WorkspaceResource, WorkspaceStorageDefinition, ZaloChannelInput, ZaloConnectionDefinition, ZaloConnectionInput, ZaloMessageSource, ZaloSource };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{V,ge,Me,Pe,Ne,je,G,Ie,T,ye,B,J,xe,Y,E,qe,De,Le,Ue,Be,Fe,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}from"./chunk-6kgtx9kv.js";import{m,Ae,Z,R}from"./chunk-bb3jfhv3.js";export{m as BroodsAccountApiError,R as BroodsAccountClient,B as BroodsClient,xe as BroodsWebSocketClient,T as DEFAULT_CORE_BASE_URL,ye as IngressAcceptedError,Me as MAX_OBSERVABILITY_BACKFILL,xe as WebSocketClient,xe as WebsocketClient,De as defineAgent,Le as defineBroods,Ue as defineCron,ct as defineDiscordChannel,We as defineDiscordConnection,lt as defineGitHubChannel,Ke as defineGitHubConnection,ut as defineGoogleChatChannel,Je as defineGoogleChatConnection,Be as defineHarness,dt as defineInstagramChannel,Ye as defineInstagramConnection,pt as defineLinearChannel,Xe as defineLinearConnection,mt as defineMatrixChannel,Qe as defineMatrixConnection,Fe as defineMcp,ht as defineMessengerChannel,et as defineMessengerConnection,ft as definePancakeChannel,tt as definePancakeConnection,Ze as definePolicy,He as defineSandbox,Ve as defineSkill,gt as defineSlackChannel,nt as defineSlackConnection,yt as defineTeamsChannel,rt as defineTeamsConnection,St as defineTelegramChannel,ot as defineTelegramConnection,bt as defineTwilioChannel,st as defineTwilioConnection,vt as defineWhatsAppChannel,it as defineWhatsAppConnection,Ge as defineWorkspace,_t as defineZaloChannel,at as defineZaloConnection,qe as env,Ae as envPlaceholder,ie as isBroodsConfig,w as isConnectionDefinition,Pe as isLogLevel,Ne as isObservabilityClientMessage,g as isResource,je as isRootSpanKind,G as isSandboxLogId,Ie as isTraceId,J as normalizeHttpServiceUrl,ge as readSseStream,Z as resolveEnvCredential,V as resolveRunEvents,Y as toWebSocketBaseUrl,E as webSocketSubprotocols};
1
+ import{G,we,Le,Ne,Ue,Fe,W,K,de,ee,y,Be,I,Re,B,te,je,ne,z,He,Ze,Ve,Ge,We,Ke,Je,Ye,Xe,Qe,et,tt,nt,rt,ot,st,it,at,ct,lt,ut,dt,pt,mt,ft,ht,gt,yt,St,bt,vt,_t,wt,Rt,$t,Ct,Et,kt,pe,R,g}from"./chunk-f19xvx4b.js";import{m,qe,Z,C}from"./chunk-njxsdp91.js";export{m as BroodsAccountApiError,C as BroodsAccountClient,B as BroodsClient,je as BroodsWebSocketClient,I as DEFAULT_CORE_BASE_URL,Re as IngressAcceptedError,Le as MAX_OBSERVABILITY_BACKFILL,de as USER_TOKEN_HEADER,ee as USER_TOKEN_MAX_TTL_MS,y as USER_TOKEN_SECRET_ENV,je as WebSocketClient,je as WebsocketClient,Ze as defineAgent,Ve as defineBroods,Ge as defineCron,ft as defineDiscordChannel,et as defineDiscordConnection,ht as defineGitHubChannel,tt as defineGitHubConnection,gt as defineGoogleChatChannel,nt as defineGoogleChatConnection,We as defineHarness,yt as defineInstagramChannel,rt as defineInstagramConnection,St as defineLinearChannel,ot as defineLinearConnection,bt as defineMatrixChannel,st as defineMatrixConnection,Ke as defineMcp,vt as defineMessengerChannel,it as defineMessengerConnection,_t as definePancakeChannel,at as definePancakeConnection,Je as definePolicy,Ye as defineSandbox,Xe as defineSkill,wt as defineSlackChannel,ct as defineSlackConnection,Rt as defineTeamsChannel,lt as defineTeamsConnection,$t as defineTelegramChannel,ut as defineTelegramConnection,Ct as defineTwilioChannel,dt as defineTwilioConnection,Et as defineWhatsAppChannel,pt as defineWhatsAppConnection,Qe as defineWorkspace,kt as defineZaloChannel,mt as defineZaloConnection,He as env,qe as envPlaceholder,pe as isBroodsConfig,R as isConnectionDefinition,Ne as isLogLevel,Ue as isObservabilityClientMessage,g as isResource,Fe as isRootSpanKind,W as isSandboxLogId,K as isTraceId,te as normalizeHttpServiceUrl,we as readSseStream,Z as resolveEnvCredential,G as resolveRunEvents,Be as signUserToken,ne as toWebSocketBaseUrl,z as webSocketSubprotocols};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "broods",
3
- "version": "0.49.3",
3
+ "version": "0.51.0",
4
4
  "description": "CLI + TypeScript SDK for the broods agent platform.",
5
5
  "keywords": [
6
6
  "agents",
@@ -1 +0,0 @@
1
- import{P,i,F,N,X,Q,ee,b,I,te,ae,ce,Se,be,ve,_e,le,ue,we,Re,$e,j}from"./chunk-kx38nst5.js";var D=Symbol("swallowsErrorsAfterClose"),z=class{_readBuffer;_started=!1;_closed=!1;constructor(t=le.stdin,o=le.stdout,c){this._stdin=t,this._stdout=o,this._readBuffer=new ve({maxBufferSize:c?.maxBufferSize})}onclose;onerror;onmessage;_ondata=(t)=>{try{this._readBuffer.append(t),this.processReadBuffer()}catch(o){this.onerror?.(o),this.close().catch(()=>{})}};_onerror=(t)=>{this.onerror?.(t)};_onstdouterror=(t)=>{if(this._closed)return;this.onerror?.(t),this.close().catch(()=>{})};_onstdinclose=()=>{this.close().catch(()=>{})};async start(){if(this._started)throw Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0;for(let t of this._stdout.listeners("error"))if(t[D])this._stdout.off("error",t);if(this._stdin.readableEnded||this._stdin.destroyed)setImmediate(this._onstdinclose);this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror),this._stdin.on("end",this._onstdinclose),this._stdin.on("close",this._onstdinclose),this._stdout.on("error",this._onstdouterror)}processReadBuffer(){while(!0)try{let t=this._readBuffer.readMessage();if(t===null)break;this.onmessage?.(t)}catch(t){this.onerror?.(t)}}async close(){if(this._closed)return;if(this._closed=!0,this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.off("end",this._onstdinclose),this._stdin.off("close",this._onstdinclose),this._onstdouterror[D]=!0,this._stdin.listenerCount("data")===0)this._stdin.pause();this._readBuffer.clear(),this.onclose?.()}send(t){if(this._closed)return Promise.reject(Error("StdioServerTransport is closed"));return new Promise((o,c)=>{let l=_e(t),r=!1,f=(_)=>{if(r)return;r=!0,this._stdout.off("error",f),this._stdout.off("drain",p),c(_)},p=()=>{if(r)return;r=!0,this._stdout.off("error",f),this._stdout.off("drain",p),o()};if(this._stdout.once("error",f),this._stdout.write(l)){if(r)return;r=!0,this._stdout.off("error",f),o()}else if(!r)this._stdout.once("drain",p)})}},M=3000,J=class{onclose;onerror;onmessage;_closed=!1;_pendingRequests=new Set;_drainWaiters=[];constructor(t,o,c){this._wire=t,this._onInstanceClose=o,this._outboundIntercept=c}async start(){}async send(t,o){if(te(t)||ae(t)){let{id:c}=t;if(c!==void 0)this._settle(c)}if(this._closed)return;if(this._outboundIntercept?.(t)==="handled")return;return this._wire.send(t,o)}setProtocolVersion=(t)=>{this._wire.setProtocolVersion?.(t)};deliver(t,o){if(this._closed)return;if(b(t))this._pendingRequests.add(t.id);else if(I(t)&&t.method==="notifications/cancelled"){let c=t.params?.requestId;if(c!==void 0)this._settle(c)}this.onmessage?.(t,o)}async whenRequestsAnswered(t){if(this._closed||this._pendingRequests.size===0)return!0;return await new Promise((o)=>{let c=()=>{clearTimeout(l),o(!0)},l=setTimeout(()=>{this._drainWaiters=this._drainWaiters.filter((r)=>r!==c),o(!1)},t);this._drainWaiters.push(c)})}async close(){if(this._closed)return;this._closed=!0,this._pendingRequests.clear(),this._releaseDrainWaiters();try{this._onInstanceClose()}finally{this.onclose?.()}}_settle(t){if(this._pendingRequests.delete(t),this._pendingRequests.size===0)this._releaseDrainWaiters()}_releaseDrainWaiters(){let t=this._drainWaiters;this._drainWaiters=[];for(let o of t)o()}};function L(t){let o=t.params;if(t.method==="initialize"&&!ce(o)){let f=o!==null&&typeof o==="object"&&typeof o.protocolVersion==="string"?o.protocolVersion:void 0;return{kind:"legacy",reason:"initialize",...f!==void 0&&{requestedVersion:f}}}if(!X(o))return{kind:"legacy",reason:"no-claim"};let c=N(o),l=(c===void 0?[]:ee(c))[0];if(l!==void 0)return{kind:"invalid-envelope",issue:l};let r=Q(o);if(r===void 0||!P.includes(r))return{kind:"unsupported-revision",requested:r??"unknown"};return{kind:"modern",revision:r,classification:{era:"modern",revision:r}}}function H(t,o={}){let c=o.legacy??"serve",l=o.transport??new z,r={phase:"opening"},f,p=!1,_=()=>p||r.phase==="closed",d=(e)=>{try{o.onerror?.(e)}catch{}},y=(e,n,s,a)=>l.send({jsonrpc:"2.0",id:e,error:{code:n,message:s,...a!==void 0&&{data:a}}}).catch((u)=>d(h(u))),w=new we(o.maxSubscriptions??ue),V=(e)=>{if(!I(e))return;let n=w.routeOutbound(e);if(n==="passthrough")return;for(let s of n)l.send({jsonrpc:"2.0",...s}).catch((a)=>d(h(a)));return"handled"},q=async(e)=>{if(b(e)&&e.method==="subscriptions/listen"){let n=N(e.params),s=X(e.params)?(n===void 0?[]:ee(n))[0]:{key:"_meta",problem:"the per-request envelope is required on protocol revision 2026-07-28"},a=Q(e.params),u;if(s!==void 0)u={jsonrpc:"2.0",id:e.id,error:{code:-32602,message:`Invalid _meta envelope: ${s.key}: ${s.problem}`}};else if(a===void 0||!P.includes(a)){let v=new F({supported:[...P],requested:a??"unknown"});u={jsonrpc:"2.0",id:e.id,error:{code:v.code,message:v.message,data:v.data}}}else u=w.serve(e);return await l.send("error"in u?u:{jsonrpc:"2.0",method:u.method,params:u.params}).catch((v)=>d(h(v))),!0}if(I(e)&&e.method==="notifications/cancelled"){let n=e.params?.requestId;if(n!==void 0&&w.cancel(n))return!0}return!1},C=(e,n,s)=>{let a=Se({kind:"legacy",reason:n,...s!==void 0&&{requestedVersion:s}},P);if(a===void 0)return Promise.resolve();return d(Error(`Rejected 2025-era request on a modern-only stdio connection (${a.cell}): ${a.message}`)),y(e.id,a.code,a.message,a.data)},T=(e)=>{if(p||e===f)return;O()},m=async(e,n)=>{let s=await t({era:e}),a=s instanceof j?s.server:s;if(e==="modern")be(a,n),Re(a,P),w.setServerCapabilities(a.getCapabilities(),$e(a));let u=new J(l,()=>T(u),e==="modern"?V:void 0);return await s.connect(u),{product:s,channel:u}},R=(e)=>e.product.close().catch((n)=>d(h(n))),B=async(e)=>{f=e.channel;try{if(!await e.channel.whenRequestsAnswered(M))d(Error(`Discarded the probe instance with requests still unanswered after ${M}ms; continuing with the fallback`));await e.product.close()}catch(n){d(h(n))}finally{f=void 0}},A=async(e)=>{if(r.phase==="closed")return;if(r.phase==="pinned"){if(r.era==="modern"&&b(e)&&e.method==="initialize"&&!ce(e.params)){await C(e,"initialize",e.params!==null&&typeof e.params==="object"&&typeof e.params.protocolVersion==="string"?e.params.protocolVersion:void 0);return}if(r.era==="modern"&&await q(e))return;if(_())return;r.instance.channel.deliver(e);return}if(!b(e)&&!I(e)){d(Error("Discarded a JSON-RPC response received before the connection negotiated an era"));return}let n=L(e);switch(n.kind){case"invalid-envelope":{let s=`Invalid _meta envelope for protocol revision 2026-07-28: ${n.issue.key}: ${n.issue.problem}`;if(b(e))await y(e.id,i.InvalidParams,s,{envelope:n.issue});else d(Error(`Discarded a notification with a malformed envelope: ${s}`));return}case"unsupported-revision":if(b(e)){let s=new F({supported:[...P],requested:n.requested});d(s),await y(e.id,s.code,s.message,s.data)}else d(Error(`Discarded a notification claiming unsupported protocol revision ${n.requested}`));return;case"modern":if(b(e)&&e.method==="server/discover"){if(r.phase==="probe"){r.instance.channel.deliver(e,{classification:n.classification});return}let s=await m("modern",n.revision);if(_()){await R(s);return}r={phase:"probe",instance:s},s.channel.deliver(e,{classification:n.classification});return}if(r.phase==="probe"){if(I(e)){r.instance.channel.deliver(e,{classification:n.classification});return}r={phase:"pinned",era:"modern",instance:r.instance}}else{let s=await m("modern",n.revision);if(_()){await R(s);return}r={phase:"pinned",era:"modern",instance:s}}if(await q(e))return;if(_())return;r.instance.channel.deliver(e,{classification:n.classification});return;case"legacy":{if(c==="reject"){if(b(e))await C(e,n.reason,n.requestedVersion);return}if(r.phase==="probe"){if(await B(r.instance),_())return;r={phase:"opening"}}let s=await m("legacy");if(_()){await R(s);return}r={phase:"pinned",era:"legacy",instance:s},r.instance.channel.deliver(e);return}}},S=[],E=!1,W=async()=>{if(E)return;E=!0;try{while(S.length>0){let e=S.shift();try{await A(e)}catch(n){if(b(e))await y(e.id,i.InternalError,"Internal server error");d(h(n))}}}finally{E=!1}},O=async()=>{if(p||r.phase==="closed")return;p=!0;let e=r;r={phase:"closed"};for(let n of w.teardownAll())await l.send(n).catch((s)=>d(h(s)));if(e.phase==="probe"||e.phase==="pinned")await e.instance.product.close().catch((n)=>d(h(n)));await l.close().catch((n)=>d(h(n)))};l.onmessage=(e)=>{S.push(e),W()},l.onerror=(e)=>{if(d(e),r.phase==="probe"||r.phase==="pinned")r.instance.channel.onerror?.(e)},l.onclose=()=>{if(p||r.phase==="closed")return;p=!0;let e=r;if(r={phase:"closed"},e.phase==="probe"||e.phase==="pinned")e.instance.product.close().catch((n)=>d(h(n)))};let k=l.start().catch((e)=>{throw d(h(e)),e});return k.catch(()=>{}),{close:async()=>{await k.catch(()=>{}),await O()}}}function h(t){return t instanceof Error?t:Error(String(t))}export{H as serveStdio};
@@ -1,4 +0,0 @@
1
- import{U,E}from"./chunk-6kgtx9kv.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 re}from"node:child_process";import{statfsSync as ne}from"node:fs";import{availableParallelism as ie,homedir as ae,hostname as ce,totalmem as le}from"node:os";import{performance as A}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"},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 P="/v1/machines/ws",B=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.")}),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:a().optional(),mcp:n(e()).optional(),instance:e().optional(),force:a().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(),l())}),q=t({type:r("mcp-list"),id:e(),server:e()}),Z=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()}),V=t({type:r("ready"),sandboxId:e(),expiresInMs:o().optional()}),ee=t({type:r("result"),id:e(),exitCode:o().nullable(),stdout:e(),stderr:e(),durationMs:o(),timedOut:a(),truncated:a()}),te=C("type",[G,K,Y,q,V]),xe=C("type",[W,J,X,Z,Q,ee]);function z(i){let c=new URL(P,i);return c.protocol=c.protocol==="https:"?"wss:":"ws:",c.toString()}function I(i){return oe(te,i)}function oe(i,c){if(typeof c!=="string")return null;try{let y=i.safeParse(JSON.parse(c));return y.success?y.data:null}catch{return null}}var pe=new Set([_.occupied.code,_.replaced.code,_.unauthorized.code,_.unknownSandbox.code]),j=72,O=30000,R=1000;function de(i,c,y){return new Promise((g)=>{let h=A.now(),f=new L(i.outputLimitBytes),x=new L(i.outputLimitBytes),b=!1,v=!1,F=(u,m)=>{if(v)return;if(v=!0,clearTimeout(T),y?.removeEventListener("abort",S),m)x.append(Buffer.from(`${m}
2
- `));g({type:"result",id:i.id,exitCode:u,stdout:f.text(),stderr:x.text(),durationMs:Math.round(A.now()-h),timedOut:b,truncated:f.truncated||x.truncated})},M=re("bash",["-lc",i.code],{cwd:i.cwd??c,env:{...U(),...i.env},detached:!0,stdio:["ignore","pipe","pipe"]}),k=()=>{if(!M.pid)return;try{process.kill(-M.pid,"SIGKILL")}catch{M.kill("SIGKILL")}},T=setTimeout(()=>{b=!0,k()},i.timeoutSeconds*1000),S=()=>{k(),F(null,"stopped: the daemon closed its socket")};if(y?.addEventListener("abort",S,{once:!0}),M.stdout.on("data",(u)=>f.append(u)),M.stderr.on("data",(u)=>x.append(u)),M.on("error",(u)=>F(null,u.message)),M.on("close",(u)=>F(u)),y?.aborted)S()})}async function Oe(i){let c=fe(),y=crypto.randomUUID(),g=i.mcpFile?await ge(i.mcpFile,i.log):null,h=i.computer?await ye(i.log):null,f=R;try{while(!i.signal.aborted){let x=Date.now(),b;try{b=await i.credential()}catch(F){if(F instanceof D)throw F;i.log(`stage session unavailable (${F instanceof Error?F.message:String(F)}), retrying in ${Math.round(f/1000)}s`),await se(f,i.signal),f=Math.min(f*2,O);continue}let v=await Me(i,b,y,c,h,g);if(i.signal.aborted)return;if(pe.has(v.code))throw Error(v.reason||`core closed the socket (${v.code})`);if(Date.now()-x>O)f=R;i.log(`disconnected (${v.reason||v.code}), reconnecting in ${Math.round(f/1000)}s`),await se(f,i.signal),f=Math.min(f*2,O)}}finally{h?.stop(),await g?.stop()}}class L{#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
- [output truncated]`:i}}function me(i){let c=[i.action];if(i.coordinate)c.push(`at ${i.coordinate.join(",")}`);if(i.text!==void 0)c.push(JSON.stringify(H(i.text)));if(i.region)c.push(`region ${i.region.join(",")}`);return c.join(" ")}function ue(){let i=he();return{vcpu:ie(),memoryMb:Math.round(le()/1048576),...i?{storageGb:i}:{}}}function he(){try{let i=ne(ae());return Math.round(i.blocks*i.bsize/1073741824)}catch{return}}function H(i){let c=i.trim().split(`
4
- `)[0]??"";return c.length>j?`${c.slice(0,j)}…`:c}async function ye(i){let{startDesktop:c}=await import("./chunk-5tnnqapc.js"),{display:y,driver:g,permissions:h}=await c(!1);if(i(`computer use on, ${y.width}x${y.height} screenshots`),!h.screenRecording||!h.accessibility)i(" screen recording or accessibility is missing, run `broods machine --doctor --request`");return g}async function ge(i,c){let{McpHost:y,readMcpServersFile:g}=await import("./chunk-ctt7r720.js"),h=new y(g(i),c);return c(`mcp servers from ${i}: ${h.names().join(", ")}`),h}async function be(i,c,y){try{if(i.type==="mcp-list"){let h=await c.listTools(i.server);return y(` mcp ${i.server}: ${h.length} tools`),{type:"mcp-tools",id:i.id,tools:h}}y(` mcp ${i.server}.${i.tool}`);let g=await c.callTool(i.server,i.tool,i.args);return{type:"mcp-result",id:i.id,result:g}}catch(g){let h=g instanceof Error?g.message:String(g);return y(` mcp ${i.server}: ${h}`),{type:i.type==="mcp-call"?"mcp-result":"mcp-tools",id:i.id,error:h}}}function Me(i,c,y,g,h,f){return new Promise((x)=>{let b=new g(z(i.baseUrl),E(c)),v=new AbortController,F=()=>b.close(1000,"daemon stopped"),M=(u)=>{if(b.readyState===b.OPEN)b.send(JSON.stringify(u))},k,T=(u)=>{if(clearTimeout(k),v.signal.aborted)return;k=setTimeout(()=>{i.credential().then((m)=>M({type:"credential",token:m}),(m)=>i.log(`credential refresh failed (${m instanceof Error?m.message:String(m)}), retrying`)).finally(()=>T(u))},Math.max((u-Date.now())/2,R))},S=(u,m)=>{i.signal.removeEventListener("abort",F),clearTimeout(k),v.abort(),x({code:u,reason:m})};i.signal.addEventListener("abort",F,{once:!0}),b.onopen=()=>M({type:"hello",sandbox:i.sandbox,hostname:ce(),platform:process.platform,computer:h!==null,mcp:f?.names(),instance:y,force:i.force,specs:ue()}),b.onmessage=(u)=>{let m=I(u.data);if(m?.type==="ready"){if(k===void 0)i.log(`connected as ${i.sandbox} (${m.sandboxId})`);if(m.expiresInMs!==void 0)T(Date.now()+m.expiresInMs);return}if(m?.type==="computer"&&h){i.log(` ${me(m)}`),h.run(m).then((w)=>{if(w.error)i.log(` error: ${w.error}`);M(w)});return}if((m?.type==="mcp-call"||m?.type==="mcp-list")&&f){be(m,f,i.log).then(M);return}if(m?.type!=="exec")return;i.log(`$ ${H(m.code)}`),de(m,i.cwd,v.signal).then((w)=>{i.log(` exit ${w.exitCode??"none"} in ${w.durationMs}ms${w.timedOut?" (timed out)":""}`),M(w)})},b.onerror=()=>S(1006,"connection failed"),b.onclose=(u)=>S(u.code,u.reason)})}export{Oe as runMachineDaemon};
@@ -1,5 +0,0 @@
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{await n.cancel().catch(()=>{return}),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 Se(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 Se(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 Re}from"node:fs";import{chmod as H,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 z(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=j();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=j()?.logins??{},t={current:e.baseUrl,logins:{...n,[e.baseUrl]:e}};await be(D(O),{recursive:!0,mode:448}),await H(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 H(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 j(){try{let e=JSON.parse(Re(O,"utf8"));if(typeof e.current!=="string"||!e.logins)return null;return{current:e.current,logins:e.logins}}catch{return null}}import{existsSync as F,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)),q=new Set;function h(e=process.cwd()){Oe(e);let n=z();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(!F(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(!F(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,c]of Object.entries(ee(Z(r,"utf8"))))if(t||!Te.has(a)||q.has(a))process.env[a]=c,q.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 T="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 B{baseUrl;apiKey;fetchImpl;constructor(e={}){h(),this.baseUrl=J(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||T),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 ${T} 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){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 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||T),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,E(this.apiKey)),a=!1,c=!1,d=setTimeout(()=>{if(!a)S(i)},this.connectTimeoutMs),m=(p=1000,I="client closed")=>{if(c)return;if(c=!0,clearTimeout(d),e.signal?.removeEventListener("abort",b),s.readyState===R||s.readyState===oe)s.close(p,I)},S=(p)=>{n.onError?.(p),m(1011,"websocket error")},me=()=>{n.onDone?.(),m(1000,"done")},b=()=>{if(s.readyState===R)s.send(JSON.stringify({type:"cancel"}));S(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",b,{once:!0}),s.onopen=()=>{if(a=!0,clearTimeout(d),e.signal?.aborted){b();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=(p)=>{if(typeof p.data!=="string")return;let I=se(p.data);if(!I)return;let x=ae(I,n);switch(n.onMessage?.(x),x.type){case"meta":n.onMeta?.(x);break;case"done":me();break;case"error":S(Error(re(x.error)));break}},s.onerror=()=>{S(i)},s.onclose=(p)=>{if(clearTimeout(d),e.signal?.removeEventListener("abort",b),c||p.code===1000)return;S(Error(p.reason||"WebSocket connection closed."))},{url:o,sendControl:function(p){if(s.readyState!==R)throw Error("WebSocket is not open");s.send(JSON.stringify({type:"control",...p}))},close:m}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o,E(this.apiKey)),i=!1,s=(c=1000,d="client closed")=>{if(i)return;if(i=!0,e.signal?.removeEventListener("abort",a),r.readyState===R||r.readyState===oe)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}))},r.onmessage=(c)=>{if(i||typeof c.data!=="string")return;let d=se(c.data);if(!d)return;let m=ae(d,n);if(i)return;if(n.onMessage?.(m),i)return;if(m.type==="done")n.onDone?.();if(m.type==="error")n.onError?.(Error(re(m.error)))},r.onerror=()=>{if(i)return;s(1011,"websocket error"),n.onError?.(ce(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!==R)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=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 E(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 C("agent",n,t,o)}function Le(e){return{[de]:!0,config:e}}function Ue(e){let{name:n,description:t,...o}=e;return C("cron",n,t,o)}function Be(e){return e}function Fe(e){let{name:n,description:t,...o}=e;return C("mcp",n,t,o)}function Ze(e){let{name:n,description:t,...o}=e;return C("policy",n,t,o)}function He(e){let{name:n,description:t,...o}=e;return C("sandbox",n,t,o)}function Ve(e){let{name:n,description:t,...o}=e;return C("skill",n,t,o)}function Ge(e){let{name:n,description:t,...o}=e;return C("workspace",n,t,o)}function We(e){return l("discord",e)}function Ke(e){return l("github",e)}function Je(e){return l("gchat",e)}function Ye(e){return l("instagram",e)}function Xe(e){return l("linear",e)}function Qe(e){return l("matrix",e)}function et(e){return l("messenger",e)}function tt(e){return l("pancake",e)}function nt(e){return l("slack",e)}function rt(e){return l("teams",e)}function ot(e){return l("telegram",e)}function st(e){return l("twilio",e)}function it(e){return l("whatsapp",e)}function at(e){return l("zalo",e)}function ct(e){let{name:n,description:t,channelId:o,guildId:r,...i}=e;return u(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 u(n,t,o,i,r)}function ut(e){let{name:n,description:t,spaceName:o,...r}=e;return u(n,t,o,void 0,r)}function dt(e){let{name:n,description:t,igsid:o,...r}=e;return u(n,t,o,void 0,r)}function pt(e){let{name:n,description:t,team:o,...r}=e;return u(n,t,o,void 0,r)}function mt(e){let{name:n,description:t,channelId:o,...r}=e;return u(n,t,o,void 0,r)}function ht(e){let{name:n,description:t,psid:o,...r}=e;return u(n,t,o,void 0,r)}function ft(e){let{name:n,description:t,conversationId:o,...r}=e;return u(n,t,o,void 0,r)}function gt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function yt(e){let{name:n,description:t,channelId:o,teamId:r,...i}=e;return u(n,t,o,r,i)}function St(e){let{name:n,description:t,chatId:o,...r}=e;return u(n,t,o,void 0,r)}function bt(e){let{name:n,description:t,from:o,...r}=e;return u(n,t,o,void 0,r)}function vt(e){let{name:n,description:t,waId:o,...r}=e;return u(n,t,o,void 0,r)}function _t(e){let{name:n,description:t,chatId:o,...r}=e;return u(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 u(e,n,t,o,r){return C("channelRecord",e,n,{...r,externalId:t,...o?{workspaceRef:o}:{}})}function l(e,n){let{partition:t,...o}=n;return{[fe]:!0,kind:"connection",type:e,...t?{partition:t}:{},config:o}}function C(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,z,W,K,v,f,L,h,U,M,T,ye,B,J,xe,Y,E,qe,De,Le,Ue,Be,Fe,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,2 +0,0 @@
1
- var d=/^[A-Z][A-Z0-9_]*$/;class m extends Error{status;body;constructor(e,t,n,s){super(`${e} ${t} failed with ${n}: ${s}`);this.name="BroodsAccountApiError",this.status=n,this.body=s}}function Ae(e){if(!d.test(e)||e.length>64)throw Error("envPlaceholder name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");return`\${${e}}`}function Z(){return o("BROODS_SESSION_TOKEN")??o("BROODS_ACCOUNT_SECRET")}class R{baseUrl;bearerToken;fetchImpl;constructor(e={}){let t=e.baseUrl??o("BROODS_BASE_URL")??"https://gateway.broods.app",n=e.sessionToken??e.accountSecret??Z();if(!n)throw Error("BroodsAccountClient requires an accountSecret or sessionToken (or BROODS_ACCOUNT_SECRET / BROODS_SESSION_TOKEN).");let s=t.length;while(s>0&&t.charCodeAt(s-1)===47)s-=1;this.baseUrl=t.slice(0,s),this.bearerToken=n,this.fetchImpl=e.fetch??fetch}async getAccount(){let e=await this.request("GET","/v1/account");if(!e)throw new m("GET","/v1/account",404,"Account not found");return e.account}async updateAccount(e){return(await this.request("PATCH","/v1/account",e))?.account??null}async assumeRole(e,t={}){let n=await this.request("POST","/v1/account/assume-role",{roleId:e,...t.ttlSeconds!==void 0?{ttlSeconds:t.ttlSeconds}:{}});if(!n)throw new m("POST","/v1/account/assume-role",404,"Role not found");return n}async rotateSecret(){let e=await this.request("POST","/v1/account/rotate-secret");if(!e)throw new m("POST","/v1/account/rotate-secret",404,"Account not found");return e}async deleteAccount(){return await this.request("DELETE","/v1/account")??{deleted:!1}}webhookUrl(e,t){let n=[e,t].map(encodeURIComponent);return`${this.baseUrl}/v1/webhooks/${n.join("/")}`}async listAgents(){return(await this.request("GET","/v1/agents"))?.agents??[]}async createAgent(e){let t=await this.request("POST","/v1/agents",e);if(!t)throw new m("POST","/v1/agents",404,"Not found");return t}async getAgent(e){return await this.request("GET",`/v1/agents/${encodeURIComponent(e)}`)}async updateAgent(e,t){return await this.request("PATCH",`/v1/agents/${encodeURIComponent(e)}`,t)}async deleteAgent(e){return(await this.request("DELETE",`/v1/agents/${encodeURIComponent(e)}`))?.deleted??!1}async listEnvVars(){return(await this.request("GET","/v1/env"))?.env??[]}async setEnvVar(e,t){await this.request("PUT",`/v1/env/${encodeURIComponent(e)}`,{value:t})}async deleteEnvVar(e){return(await this.request("DELETE",`/v1/env/${encodeURIComponent(e)}`))?.deleted??!1}async listConnections(){return(await this.request("GET","/v1/account/connections"))?.connections??[]}async getConnection(e){return await this.request("GET",`/v1/account/connections/${e}`)}async startConnection(e,t){let n=await this.request("POST",`/v1/account/connections/${e}/start`,t);if(!n)throw new m("POST",`/v1/account/connections/${e}/start`,404,"This deployment has no /v1/account/connections yet");return n}async connect(e,t){let n=await this.request("PUT",`/v1/account/connections/${e}`,t);if(!n)throw new m("PUT",`/v1/account/connections/${e}`,404,"This deployment has no /v1/account/connections yet");return n}async disconnect(e){return(await this.request("DELETE",`/v1/account/connections/${e}`))?.deleted??!1}async listCrons(){return(await this.request("GET","/v1/crons"))?.crons??[]}async createCron(e){let t=await this.request("POST","/v1/crons",e);if(!t)throw new m("POST","/v1/crons",404,"Not found");return t}async getCron(e){return await this.request("GET",`/v1/crons/${encodeURIComponent(e)}`)}async updateCron(e,t){return await this.request("PATCH",`/v1/crons/${encodeURIComponent(e)}`,t)}async deleteCron(e){return(await this.request("DELETE",`/v1/crons/${encodeURIComponent(e)}`))?.deleted??!1}async listCronRuns(e,t={}){let n=t.limit!==void 0?`?limit=${t.limit}`:"";return(await this.request("GET",`/v1/crons/${encodeURIComponent(e)}/runs${n}`))?.runs??[]}async listWorkspaces(){return(await this.request("GET","/v1/workspaces"))?.workspaces??[]}async createWorkspace(e){let t=await this.request("POST","/v1/workspaces",e);if(!t)throw new m("POST","/v1/workspaces",404,"Not found");return t}async getWorkspace(e){return await this.request("GET",`/v1/workspaces/${encodeURIComponent(e)}`)}async updateWorkspace(e,t){return await this.request("PATCH",`/v1/workspaces/${encodeURIComponent(e)}`,t)}async deleteWorkspace(e){return(await this.request("DELETE",`/v1/workspaces/${encodeURIComponent(e)}`))?.deleted??!1}async listWorkspaceFiles(e){return(await this.request("GET",`/v1/workspaces/${encodeURIComponent(e)}/files`))?.files??[]}async getWorkspaceFileUrl(e,t){let n=`?path=${encodeURIComponent(t)}`;return(await this.request("GET",`/v1/workspaces/${encodeURIComponent(e)}/files${n}`))?.url??null}async uploadWorkspaceFile(e,t){let n=`/v1/workspaces/${encodeURIComponent(e)}/files`,s=await this.request("POST",n,t);if(!s)throw new m("POST",n,404,"Workspace not found");return s.file}async renameWorkspaceFile(e,t,n){let s=`/v1/workspaces/${encodeURIComponent(e)}/files`,r=await this.request("PATCH",s,{path:t,newPath:n});if(!r)throw new m("PATCH",s,404,"Workspace not found");return r.renamed}async deleteWorkspaceFile(e,t){return(await this.request("DELETE",`/v1/workspaces/${encodeURIComponent(e)}/files`,{path:t}))?.deleted??0}async listSandboxes(){return(await this.request("GET","/v1/sandboxes"))?.sandboxes??[]}async createSandbox(e){let t=await this.request("POST","/v1/sandboxes",e);if(!t)throw new m("POST","/v1/sandboxes",404,"Not found");return t}async getSandbox(e){return await this.request("GET",`/v1/sandboxes/${encodeURIComponent(e)}`)}async updateSandbox(e,t){return await this.request("PATCH",`/v1/sandboxes/${encodeURIComponent(e)}`,t)}async deleteSandbox(e){return(await this.request("DELETE",`/v1/sandboxes/${encodeURIComponent(e)}`))?.deleted??!1}async suspendSandbox(e,t){return await this.sandboxAction(e,"suspend",{reservationKey:t})}async resumeSandbox(e,t){return await this.sandboxAction(e,"resume",{reservationKey:t})}async terminateSandbox(e,t){return await this.sandboxAction(e,"terminate",{reservationKey:t})}async snapshotSandbox(e,t,n){return await this.sandboxAction(e,"snapshot",{reservationKey:t,name:n})}async openSandboxTerminal(e,t){return await this.sandboxAction(e,"terminal",{reservationKey:t})}async listMcp(e){let t=`/v1/mcp${a(e)}`,n=await this.request("GET",t);if(!n)throw new m("GET",t,404,"Not found");return n.servers??[]}async createMcp(e,t){let n=`/v1/mcp${a(e)}`,s=await this.request("POST",n,t);if(!s)throw new m("POST",n,404,"Not found");return s}async uploadMcpBundle(e){let n=await this.request("POST","/v1/mcp/uploads");if(!n?.uploadUrl)throw new m("POST","/v1/mcp/uploads",502,"response omitted uploadUrl");let s=await this.fetchImpl(n.uploadUrl,{method:"POST",headers:{"Content-Type":"application/javascript"},body:e});if(!s.ok)throw new m("POST","/v1/mcp/uploads",s.status,await s.text());let{storageId:r}=await s.json();if(!r)throw new m("POST","/v1/mcp/uploads",502,"upload response omitted storageId");let c=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e)),u=Array.from(new Uint8Array(c)).map((l)=>l.toString(16).padStart(2,"0")).join("");return{bundleStorageId:r,sha256:u}}async getMcp(e){return await this.request("GET",`/v1/mcp/${encodeURIComponent(e)}`)}async updateMcp(e,t){return await this.request("PATCH",`/v1/mcp/${encodeURIComponent(e)}`,t)}async deleteMcp(e){return(await this.request("DELETE",`/v1/mcp/${encodeURIComponent(e)}`))?.deleted??!1}async listPolicies(){return(await this.request("GET","/v1/policies"))?.policies??[]}async createPolicy(e){let t=await this.request("POST","/v1/policies",e);if(!t)throw new m("POST","/v1/policies",404,"Not found");return t}async getPolicy(e){return await this.request("GET",`/v1/policies/${encodeURIComponent(e)}`)}async updatePolicy(e,t){return await this.request("PATCH",`/v1/policies/${encodeURIComponent(e)}`,t)}async deletePolicy(e){return(await this.request("DELETE",`/v1/policies/${encodeURIComponent(e)}`))?.deleted??!1}async listRoles(){return(await this.request("GET","/v1/roles"))?.roles??[]}async createRole(e){let t=await this.request("POST","/v1/roles",e);if(!t)throw new m("POST","/v1/roles",404,"Not found");return t}async getRole(e){return await this.request("GET",`/v1/roles/${encodeURIComponent(e)}`)}async updateRole(e,t){return await this.request("PATCH",`/v1/roles/${encodeURIComponent(e)}`,t)}async deleteRole(e){return(await this.request("DELETE",`/v1/roles/${encodeURIComponent(e)}`))?.deleted??!1}audit={list:async(e={})=>{let t=await this.request("GET",`/v1/audit${i(e)}`);if(!t)throw new m("GET","/v1/audit",404,"Not found");return t},verify:async(e={})=>{let t=await this.request("GET",`/v1/audit/verify${i(e)}`);if(!t)throw new m("GET","/v1/audit/verify",404,"Not found");return t},getSink:async()=>await this.request("GET","/v1/audit/sink"),setSink:async(e)=>{let t=await this.request("PUT","/v1/audit/sink",e);if(!t)throw new m("PUT","/v1/audit/sink",404,"Not found");return t},deleteSink:async()=>(await this.request("DELETE","/v1/audit/sink"))?.deleted??!1};async listChannels(){return(await this.request("GET","/v1/channels"))?.channels??[]}async createChannel(e){let t=await this.request("POST","/v1/channels",e);if(!t)throw new m("POST","/v1/channels",404,"Not found");return t}async getChannel(e){return await this.request("GET",`/v1/channels/${encodeURIComponent(e)}`)}async updateChannel(e,t){return await this.request("PATCH",`/v1/channels/${encodeURIComponent(e)}`,t)}async deleteChannel(e){return(await this.request("DELETE",`/v1/channels/${encodeURIComponent(e)}`))?.deleted??!1}async listSkills(){return(await this.request("GET","/v1/skills"))?.skills??[]}async createSkill(e){let t=await this.request("POST","/v1/skills",e);if(!t)throw new m("POST","/v1/skills",404,"Not found");return t}async getSkill(e){return await this.request("GET",`/v1/skills/${encodeURIComponent(e)}`)}async uploadSkill(e,t){let n=`/v1/skills/${encodeURIComponent(e)}`,s=await this.request("PUT",n,t);if(!s)throw new m("PUT",n,404,"Skill not found");return s}async deleteSkill(e){return(await this.request("DELETE",`/v1/skills/${encodeURIComponent(e)}`))?.deleted??!1}async sandboxAction(e,t,n){let s=`/v1/sandboxes/${encodeURIComponent(e)}/${t}`,r=await this.request("POST",s,n);if(!r)throw new m("POST",s,404,"Sandbox not found");return r}async request(e,t,n){let s=await this.fetchImpl(`${this.baseUrl}${t}`,{method:e,headers:{Authorization:`Bearer ${this.bearerToken}`,...n!==void 0?{"Content-Type":"application/json"}:{}},...n!==void 0?{body:JSON.stringify(n)}:{}});if(s.status===404)return null;if(!s.ok)throw new m(e,t,s.status,await s.text());return await s.json()}}function o(e){return typeof process<"u"?process?.env?.[e]:void 0}function i(e){let t=new URLSearchParams;for(let[n,s]of Object.entries(e))if(s!==void 0)t.set(n,String(s));return t.size>0?`?${t.toString()}`:""}function a(e){return`?${new URLSearchParams({project:e.project,stage:e.stage}).toString()}`}
2
- export{m,Ae,Z,R};