broods 0.3.0 → 0.5.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/README.md CHANGED
@@ -41,8 +41,8 @@ writes `BROODS_API_KEY` to `.env.local`; the SDK also accepts `apiKey`,
41
41
  ## Two ways to configure agents
42
42
 
43
43
  **Config-first (`broods dev` / `broods deploy`).** Resources declared in your
44
- `broods/` folder with `defineAgent`, `defineWorkspace`, etc. are *predefined
45
- configs*: the CLI syncs them to your project on deploy and codegen gives you
44
+ `broods/` folder with `defineAgent`, `defineWorkspace`, etc. are _predefined
45
+ configs_: the CLI syncs them to your project on deploy and codegen gives you
46
46
  typed references. Use this when the set of agents is fixed and versioned with
47
47
  your code.
48
48
 
@@ -59,7 +59,7 @@ such as Convex actions and Cloudflare Workers where the main SDK entry (which
59
59
  reads `.env` files from disk) cannot load:
60
60
 
61
61
  ```ts
62
- import { BroodsAccountClient } from "broods/account";
62
+ import { BroodsAccountClient, envPlaceholder } from "broods/account";
63
63
 
64
64
  // baseUrl defaults to https://gateway.broods.app (override with BROODS_BASE_URL);
65
65
  // the secret falls back to BROODS_ACCOUNT_SECRET from the runtime's environment.
@@ -76,6 +76,13 @@ const created = await account.createAgent({
76
76
  publicAccess: true,
77
77
  },
78
78
  });
79
+
80
+ // Store an account secret once, then reference it from any dynamic agent.
81
+ // Reads list only names/timestamps; secret values are never returned.
82
+ await account.setEnvVar("OVH_API_KEY", process.env.OVH_API_KEY!);
83
+ await account.updateAgent(created.agentId, {
84
+ config: { provider: { custom: { apiKey: envPlaceholder("OVH_API_KEY") } } },
85
+ });
79
86
  await account.updateAgent(created.agentId, {
80
87
  config: { channels: { slack: { id: "conn-1", botToken: "xoxb-…" } } },
81
88
  });
@@ -96,8 +103,16 @@ const sandbox = await account.createSandbox({
96
103
  name: "reserved",
97
104
  config: { provider: "lambda", persistent: true, permissionMode: "ask" },
98
105
  });
99
- await account.uploadWorkspaceFile("ws_1", { path: "memory/seed.md", contentBase64: "IyBTZWVk" });
100
- await account.createSkill({ source: "json", name: "triage", description: "Triage flow", content: "# Triage" });
106
+ await account.uploadWorkspaceFile("ws_1", {
107
+ path: "memory/seed.md",
108
+ contentBase64: "IyBTZWVk",
109
+ });
110
+ await account.createSkill({
111
+ source: "json",
112
+ name: "triage",
113
+ description: "Triage flow",
114
+ content: "# Triage",
115
+ });
101
116
  const runs = await account.listCronRuns("cron_1", { limit: 20 });
102
117
 
103
118
  // Persistent sandbox lifecycle is driven by reservationKey.
package/dist/account.d.ts CHANGED
@@ -1,8 +1,19 @@
1
1
  import { SystemModelMessage, LanguageModelCallOptions, RequestOptions, streamText, JSONSchema7, ModelMessage } from 'ai';
2
- import { DiscordAdapterConfig } from '@chat-adapter/discord';
3
- import { GitHubAdapterConfig } from '@chat-adapter/github';
4
- import { SlackAdapterConfig } from '@chat-adapter/slack';
5
- import { TelegramAdapterConfig } from '@chat-adapter/telegram';
2
+
3
+ /**
4
+ * Supported account model provider names.
5
+ * Keep provider identifiers here so config validation and model resolution share one source.
6
+ */
7
+ declare const ACCOUNT_MODEL_PROVIDERS: {
8
+ readonly google: true;
9
+ readonly openai: true;
10
+ readonly anthropic: true;
11
+ readonly bedrock: true;
12
+ readonly gateway: true;
13
+ readonly minimax: true;
14
+ readonly custom: true;
15
+ };
16
+ type AccountModelProviderName = keyof typeof ACCOUNT_MODEL_PROVIDERS;
6
17
 
7
18
  /**
8
19
  * Agent policy contracts and validation.
@@ -43,21 +54,6 @@ interface AgentPolicyConfig {
43
54
  mode?: AgentPolicyMode;
44
55
  }
45
56
 
46
- /**
47
- * Supported account model provider names.
48
- * Keep provider identifiers here so config validation and model resolution share one source.
49
- */
50
- declare const ACCOUNT_MODEL_PROVIDERS: {
51
- readonly google: true;
52
- readonly openai: true;
53
- readonly anthropic: true;
54
- readonly bedrock: true;
55
- readonly gateway: true;
56
- readonly minimax: true;
57
- readonly custom: true;
58
- };
59
- type AccountModelProviderName = keyof typeof ACCOUNT_MODEL_PROVIDERS;
60
-
61
57
  /**
62
58
  * Agent configuration: types for the per-agent settings object, input
63
59
  * normalization, encryption helpers, patch-merge, and redaction.
@@ -97,6 +93,11 @@ interface AgentSubagentConfig {
97
93
  allowed?: string[];
98
94
  context?: "new" | "inherited";
99
95
  mode?: "ephemeral" | "persistent";
96
+ /**
97
+ * Publishes child reasoning, text, and tool stream parts to the existing
98
+ * WebSocket/JetStream response path. Off by default.
99
+ */
100
+ stream?: boolean;
100
101
  /**
101
102
  * Controls what the parent agent sees from a finished subagent (AI SDK
102
103
  * "controlling what the model sees"): `full` = the child's whole transcript,
@@ -232,9 +233,9 @@ type AgentChannelWorkspaceScope = {
232
233
  };
233
234
  interface AgentTelegramChannelConfig {
234
235
  id?: string;
235
- apiUrl?: TelegramAdapterConfig["apiUrl"];
236
- botToken?: TelegramAdapterConfig["botToken"];
237
- webhookSecret?: TelegramAdapterConfig["secretToken"];
236
+ apiUrl?: string;
237
+ botToken?: string;
238
+ webhookSecret?: string;
238
239
  allowedChatIds?: number[];
239
240
  reactionEmoji?: string;
240
241
  workspaceScope?: AgentChannelWorkspaceScope;
@@ -242,18 +243,10 @@ interface AgentTelegramChannelConfig {
242
243
  }
243
244
  interface AgentGitHubChannelConfig {
244
245
  id?: string;
245
- apiUrl?: Extract<GitHubAdapterConfig, {
246
- appId: string;
247
- }>["apiUrl"];
248
- webhookSecret?: Extract<GitHubAdapterConfig, {
249
- appId: string;
250
- }>["webhookSecret"];
251
- appId?: Extract<GitHubAdapterConfig, {
252
- appId: string;
253
- }>["appId"];
254
- privateKey?: Extract<GitHubAdapterConfig, {
255
- appId: string;
256
- }>["privateKey"];
246
+ apiUrl?: string;
247
+ webhookSecret?: string;
248
+ appId?: string;
249
+ privateKey?: string;
257
250
  allowedRepos?: string[];
258
251
  /** Bot username for @-mention detection (e.g. "my-bot" or "my-bot[bot]"). */
259
252
  userName?: string;
@@ -268,9 +261,9 @@ interface AgentGitHubChannelConfig {
268
261
  }
269
262
  interface AgentSlackChannelConfig {
270
263
  id?: string;
271
- apiUrl?: SlackAdapterConfig["apiUrl"];
264
+ apiUrl?: string;
272
265
  botToken?: string;
273
- signingSecret?: SlackAdapterConfig["signingSecret"];
266
+ signingSecret?: string;
274
267
  allowedChannelIds?: string[];
275
268
  reactionEmoji?: string;
276
269
  workspaceScope?: AgentChannelWorkspaceScope;
@@ -278,9 +271,9 @@ interface AgentSlackChannelConfig {
278
271
  }
279
272
  interface AgentDiscordChannelConfig {
280
273
  id?: string;
281
- apiUrl?: DiscordAdapterConfig["apiUrl"];
282
- botToken?: DiscordAdapterConfig["botToken"];
283
- publicKey?: DiscordAdapterConfig["publicKey"];
274
+ apiUrl?: string;
275
+ botToken?: string;
276
+ publicKey?: string;
284
277
  allowedGuildIds?: string[];
285
278
  workspaceScope?: AgentChannelWorkspaceScope;
286
279
  [key: string]: unknown;
@@ -304,10 +297,7 @@ interface AgentZaloChannelConfig {
304
297
  }
305
298
 
306
299
  /**
307
- * Cron-job types, input normalization, and patch-merge helpers.
308
- * Provider-agnostic — both the DynamoDB and Convex stores import the
309
- * normalizer at their create/update entry points so behaviour is
310
- * symmetric across modes.
300
+ * Cron-job records, input normalization, and patch-merge helpers.
311
301
  */
312
302
 
313
303
  type CronStatus = "active" | "paused";
@@ -366,9 +356,8 @@ type SandboxSize = "tiny" | "xsmall" | "small" | "medium" | "large";
366
356
  /**
367
357
  * Sandbox config: account-scoped, reusable sandbox definitions referenced by
368
358
  * agents via `config.sandbox`. A sandbox is a collection of Claude-Code-style
369
- * tools (bash/read/write/edit/glob/grep) backed by a provider. Validation +
370
- * the public projection live here; the
371
- * DynamoDB / Convex stores call these at their create/update entry points.
359
+ * tools (bash/read/write/edit/glob/grep) backed by a provider. Validation and
360
+ * the public projection live here.
372
361
  * Stored encrypted at rest because `envVars`/`options` may hold secrets.
373
362
  */
374
363
 
@@ -408,8 +397,8 @@ interface SandboxConfig {
408
397
  * agents via `config.workspaces[].workspaceId`. A workspace is the persistent
409
398
  * S3-backed filesystem mounted into a sandbox; agents referencing the same
410
399
  * workspaceId share the same files. Holds no secrets, so it is stored in
411
- * plaintext (unlike sandbox config). Validation + the public projection live
412
- * here; the DynamoDB / Convex stores call these at create/update.
400
+ * plaintext (unlike sandbox config). Validation and the public projection live
401
+ * here.
413
402
  */
414
403
  declare const WORKSPACE_STORAGE_PROVIDERS: readonly ["s3"];
415
404
  type WorkspaceStorageProvider = (typeof WORKSPACE_STORAGE_PROVIDERS)[number];
@@ -428,12 +417,18 @@ interface WorkspaceStorageConfig {
428
417
  prefix?: string;
429
418
  auth?: WorkspaceStorageAuth;
430
419
  }
420
+ interface WorkspaceHarnessConfig {
421
+ workspace?: {
422
+ enabled?: boolean;
423
+ };
424
+ memory?: {
425
+ enabled?: boolean;
426
+ };
427
+ }
431
428
  interface WorkspaceConfig {
432
429
  storage: WorkspaceStorageConfig;
433
430
  isolation?: boolean;
434
- harness?: {
435
- enabled?: boolean;
436
- };
431
+ harness?: WorkspaceHarnessConfig;
437
432
  }
438
433
 
439
434
  /**
@@ -534,6 +529,13 @@ interface CreateAgentResult {
534
529
  name: string;
535
530
  description?: string;
536
531
  }
532
+ /** Write-only account environment variable metadata. */
533
+ interface AccountEnvVar {
534
+ name: string;
535
+ updatedAt: number;
536
+ }
537
+ /** Build a validated account env-var reference for use in an agent config. */
538
+ declare function envPlaceholder(name: string): string;
537
539
  /** Fields accepted by `PATCH /v1/agents/{id}`. `config` is deep-merged; `null` values delete keys. */
538
540
  interface UpdateAgentInput {
539
541
  name?: string;
@@ -701,6 +703,12 @@ declare class BroodsAccountClient {
701
703
  /** PATCH an agent. `config` deep-merges into the stored config; `null` leaves delete keys. Returns null when the agent is gone. */
702
704
  updateAgent(agentId: string, patch: UpdateAgentInput): Promise<AccountAgent | null>;
703
705
  deleteAgent(agentId: string): Promise<boolean>;
706
+ /** List account environment variable names and update timestamps; values are never returned. */
707
+ listEnvVars(): Promise<AccountEnvVar[]>;
708
+ /** Create or replace one write-only account environment variable. */
709
+ setEnvVar(name: string, value: string): Promise<void>;
710
+ /** Delete one account environment variable. Returns false when it is already absent. */
711
+ deleteEnvVar(name: string): Promise<boolean>;
704
712
  listCrons(): Promise<Cron[]>;
705
713
  createCron(input: CreateCronInput): Promise<Cron>;
706
714
  getCron(cronId: string): Promise<Cron | null>;
@@ -795,5 +803,5 @@ declare class BroodsAccountClient {
795
803
  private request;
796
804
  }
797
805
 
798
- export { BroodsAccountApiError, BroodsAccountClient };
799
- export type { AccountAgent, AccountPolicy, AccountSandbox, AccountTool, AccountWorkspace, BroodsAccount, BroodsAccountClientOptions, CreateAgentResult, CreateToolInput, DeleteAccountResult, RotateSecretResult, SandboxLifecycleResult, SandboxSnapshotResult, SandboxTerminalTicket, SkillUploadInput, UpdateAgentInput, UpdateToolInput, WorkspaceFileEntry };
806
+ export { BroodsAccountApiError, BroodsAccountClient, envPlaceholder };
807
+ export type { AccountAgent, AccountEnvVar, AccountPolicy, AccountSandbox, AccountTool, AccountWorkspace, BroodsAccount, BroodsAccountClientOptions, CreateAgentResult, CreateToolInput, DeleteAccountResult, RotateSecretResult, SandboxLifecycleResult, SandboxSnapshotResult, SandboxTerminalTicket, SkillUploadInput, UpdateAgentInput, UpdateToolInput, WorkspaceFileEntry };
package/dist/account.js CHANGED
@@ -1,271 +1 @@
1
- // @bun
2
- // src/account.ts
3
- var DEFAULT_ACCOUNT_BASE_URL = "https://gateway.broods.app";
4
-
5
- class BroodsAccountApiError extends Error {
6
- status;
7
- body;
8
- constructor(method, path, status, body) {
9
- super(`${method} ${path} failed with ${status}: ${body}`);
10
- this.name = "BroodsAccountApiError";
11
- this.status = status;
12
- this.body = body;
13
- }
14
- }
15
- function envVar(name) {
16
- return typeof process !== "undefined" ? process?.env?.[name] : undefined;
17
- }
18
-
19
- class BroodsAccountClient {
20
- baseUrl;
21
- accountSecret;
22
- fetchImpl;
23
- constructor(options = {}) {
24
- const baseUrl = options.baseUrl ?? envVar("BROODS_BASE_URL") ?? DEFAULT_ACCOUNT_BASE_URL;
25
- const accountSecret = options.accountSecret ?? envVar("BROODS_ACCOUNT_SECRET");
26
- if (!accountSecret)
27
- throw new Error("BroodsAccountClient requires an accountSecret (or BROODS_ACCOUNT_SECRET).");
28
- this.baseUrl = baseUrl.replace(/\/+$/, "");
29
- this.accountSecret = accountSecret;
30
- this.fetchImpl = options.fetch ?? fetch;
31
- }
32
- async getAccount() {
33
- const result = await this.request("GET", "/v1/account");
34
- if (!result)
35
- throw new BroodsAccountApiError("GET", "/v1/account", 404, "Account not found");
36
- return result.account;
37
- }
38
- async updateAccount(patch) {
39
- const result = await this.request("PATCH", "/v1/account", patch);
40
- return result?.account ?? null;
41
- }
42
- async rotateSecret() {
43
- const result = await this.request("POST", "/v1/account/rotate-secret");
44
- if (!result)
45
- throw new BroodsAccountApiError("POST", "/v1/account/rotate-secret", 404, "Account not found");
46
- return result;
47
- }
48
- async deleteAccount() {
49
- const result = await this.request("DELETE", "/v1/account");
50
- return result ?? { deleted: false };
51
- }
52
- webhookUrl(accountId, agentId, channelType) {
53
- const segments = [accountId, agentId, channelType].map(encodeURIComponent);
54
- return `${this.baseUrl}/webhooks/${segments.join("/")}`;
55
- }
56
- async listAgents() {
57
- const result = await this.request("GET", "/v1/agents");
58
- return result?.agents ?? [];
59
- }
60
- async createAgent(input) {
61
- const result = await this.request("POST", "/v1/agents", input);
62
- if (!result)
63
- throw new BroodsAccountApiError("POST", "/v1/agents", 404, "Not found");
64
- return result;
65
- }
66
- async getAgent(agentId) {
67
- return await this.request("GET", `/v1/agents/${encodeURIComponent(agentId)}`);
68
- }
69
- async updateAgent(agentId, patch) {
70
- return await this.request("PATCH", `/v1/agents/${encodeURIComponent(agentId)}`, patch);
71
- }
72
- async deleteAgent(agentId) {
73
- const result = await this.request("DELETE", `/v1/agents/${encodeURIComponent(agentId)}`);
74
- return result?.deleted ?? false;
75
- }
76
- async listCrons() {
77
- const result = await this.request("GET", "/v1/crons");
78
- return result?.crons ?? [];
79
- }
80
- async createCron(input) {
81
- const result = await this.request("POST", "/v1/crons", input);
82
- if (!result)
83
- throw new BroodsAccountApiError("POST", "/v1/crons", 404, "Not found");
84
- return result;
85
- }
86
- async getCron(cronId) {
87
- return await this.request("GET", `/v1/crons/${encodeURIComponent(cronId)}`);
88
- }
89
- async updateCron(cronId, patch) {
90
- return await this.request("PATCH", `/v1/crons/${encodeURIComponent(cronId)}`, patch);
91
- }
92
- async deleteCron(cronId) {
93
- const result = await this.request("DELETE", `/v1/crons/${encodeURIComponent(cronId)}`);
94
- return result?.deleted ?? false;
95
- }
96
- async listCronRuns(cronId, options = {}) {
97
- const query = options.limit !== undefined ? `?limit=${options.limit}` : "";
98
- const result = await this.request("GET", `/v1/crons/${encodeURIComponent(cronId)}/runs${query}`);
99
- return result?.runs ?? [];
100
- }
101
- async listWorkspaces() {
102
- const result = await this.request("GET", "/v1/workspaces");
103
- return result?.workspaces ?? [];
104
- }
105
- async createWorkspace(input) {
106
- const result = await this.request("POST", "/v1/workspaces", input);
107
- if (!result)
108
- throw new BroodsAccountApiError("POST", "/v1/workspaces", 404, "Not found");
109
- return result;
110
- }
111
- async getWorkspace(workspaceId) {
112
- return await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}`);
113
- }
114
- async updateWorkspace(workspaceId, patch) {
115
- return await this.request("PATCH", `/v1/workspaces/${encodeURIComponent(workspaceId)}`, patch);
116
- }
117
- async deleteWorkspace(workspaceId) {
118
- const result = await this.request("DELETE", `/v1/workspaces/${encodeURIComponent(workspaceId)}`);
119
- return result?.deleted ?? false;
120
- }
121
- async listWorkspaceFiles(workspaceId) {
122
- const result = await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`);
123
- return result?.files ?? [];
124
- }
125
- async getWorkspaceFileUrl(workspaceId, path) {
126
- const query = `?path=${encodeURIComponent(path)}`;
127
- const result = await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files${query}`);
128
- return result?.url ?? null;
129
- }
130
- async uploadWorkspaceFile(workspaceId, input) {
131
- const path = `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`;
132
- const result = await this.request("POST", path, input);
133
- if (!result)
134
- throw new BroodsAccountApiError("POST", path, 404, "Workspace not found");
135
- return result.file;
136
- }
137
- async renameWorkspaceFile(workspaceId, path, newPath) {
138
- const result = await this.request("PATCH", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`, { path, newPath });
139
- return result?.renamed ?? false;
140
- }
141
- async deleteWorkspaceFile(workspaceId, path) {
142
- const result = await this.request("DELETE", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`, { path });
143
- return result?.deleted ?? false;
144
- }
145
- async listSandboxes() {
146
- const result = await this.request("GET", "/v1/sandboxes");
147
- return result?.sandboxes ?? [];
148
- }
149
- async createSandbox(input) {
150
- const result = await this.request("POST", "/v1/sandboxes", input);
151
- if (!result)
152
- throw new BroodsAccountApiError("POST", "/v1/sandboxes", 404, "Not found");
153
- return result;
154
- }
155
- async getSandbox(sandboxId) {
156
- return await this.request("GET", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`);
157
- }
158
- async updateSandbox(sandboxId, patch) {
159
- return await this.request("PATCH", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`, patch);
160
- }
161
- async deleteSandbox(sandboxId) {
162
- const result = await this.request("DELETE", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`);
163
- return result?.deleted ?? false;
164
- }
165
- async suspendSandbox(sandboxId, reservationKey) {
166
- return await this.sandboxAction(sandboxId, "suspend", { reservationKey });
167
- }
168
- async resumeSandbox(sandboxId, reservationKey) {
169
- return await this.sandboxAction(sandboxId, "resume", { reservationKey });
170
- }
171
- async terminateSandbox(sandboxId, reservationKey) {
172
- return await this.sandboxAction(sandboxId, "terminate", { reservationKey });
173
- }
174
- async snapshotSandbox(sandboxId, reservationKey, name) {
175
- return await this.sandboxAction(sandboxId, "snapshot", { reservationKey, name });
176
- }
177
- async openSandboxTerminal(sandboxId, reservationKey) {
178
- return await this.sandboxAction(sandboxId, "terminal", { reservationKey });
179
- }
180
- async listTools() {
181
- const result = await this.request("GET", "/v1/tools");
182
- return result?.tools ?? [];
183
- }
184
- async createTool(input) {
185
- const result = await this.request("POST", "/v1/tools", input);
186
- if (!result)
187
- throw new BroodsAccountApiError("POST", "/v1/tools", 404, "Not found");
188
- return result;
189
- }
190
- async getTool(toolId) {
191
- return await this.request("GET", `/v1/tools/${encodeURIComponent(toolId)}`);
192
- }
193
- async updateTool(toolId, patch) {
194
- return await this.request("PATCH", `/v1/tools/${encodeURIComponent(toolId)}`, patch);
195
- }
196
- async deleteTool(toolId) {
197
- const result = await this.request("DELETE", `/v1/tools/${encodeURIComponent(toolId)}`);
198
- return result?.deleted ?? false;
199
- }
200
- async listPolicies() {
201
- const result = await this.request("GET", "/v1/policies");
202
- return result?.policies ?? [];
203
- }
204
- async createPolicy(input) {
205
- const result = await this.request("POST", "/v1/policies", input);
206
- if (!result)
207
- throw new BroodsAccountApiError("POST", "/v1/policies", 404, "Not found");
208
- return result;
209
- }
210
- async getPolicy(policyId) {
211
- return await this.request("GET", `/v1/policies/${encodeURIComponent(policyId)}`);
212
- }
213
- async updatePolicy(policyId, patch) {
214
- return await this.request("PATCH", `/v1/policies/${encodeURIComponent(policyId)}`, patch);
215
- }
216
- async deletePolicy(policyId) {
217
- const result = await this.request("DELETE", `/v1/policies/${encodeURIComponent(policyId)}`);
218
- return result?.deleted ?? false;
219
- }
220
- async listSkills() {
221
- const result = await this.request("GET", "/v1/skills");
222
- return result?.skills ?? [];
223
- }
224
- async createSkill(input) {
225
- const result = await this.request("POST", "/v1/skills", input);
226
- if (!result)
227
- throw new BroodsAccountApiError("POST", "/v1/skills", 404, "Not found");
228
- return result;
229
- }
230
- async getSkill(skillName) {
231
- return await this.request("GET", `/v1/skills/${encodeURIComponent(skillName)}`);
232
- }
233
- async uploadSkill(skillName, input) {
234
- const path = `/v1/skills/${encodeURIComponent(skillName)}`;
235
- const result = await this.request("PUT", path, input);
236
- if (!result)
237
- throw new BroodsAccountApiError("PUT", path, 404, "Skill not found");
238
- return result;
239
- }
240
- async deleteSkill(skillName) {
241
- const result = await this.request("DELETE", `/v1/skills/${encodeURIComponent(skillName)}`);
242
- return result?.deleted ?? false;
243
- }
244
- async sandboxAction(sandboxId, action, body) {
245
- const path = `/v1/sandboxes/${encodeURIComponent(sandboxId)}/${action}`;
246
- const result = await this.request("POST", path, body);
247
- if (!result)
248
- throw new BroodsAccountApiError("POST", path, 404, "Sandbox not found");
249
- return result;
250
- }
251
- async request(method, path, body) {
252
- const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
253
- method,
254
- headers: {
255
- Authorization: `Bearer ${this.accountSecret}`,
256
- ...body !== undefined ? { "Content-Type": "application/json" } : {}
257
- },
258
- ...body !== undefined ? { body: JSON.stringify(body) } : {}
259
- });
260
- if (response.status === 404)
261
- return null;
262
- if (!response.ok) {
263
- throw new BroodsAccountApiError(method, path, response.status, await response.text());
264
- }
265
- return await response.json();
266
- }
267
- }
268
- export {
269
- BroodsAccountClient,
270
- BroodsAccountApiError
271
- };
1
+ import{a,b,c}from"./chunk-9qtppg6j.js";import"./chunk-xv4t40dh.js";export{a as envPlaceholder,c as BroodsAccountClient,b as BroodsAccountApiError};
@@ -0,0 +1,5 @@
1
+ function b(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*x(e){let n=e.getReader(),t=new TextDecoder,o="";try{while(!0){let{done:r,value:s}=await n.read();if(r)break;o+=t.decode(s,{stream:!0});let i=o.split(`
2
+ `);o=i.pop()??"";for(let a of i)if(a.startsWith("data: "))yield a.slice(6)}}finally{n.releaseLock()}}import{mkdir as J,readFile as F,writeFile as Z}from"node:fs/promises";import{homedir as z}from"node:os";import{dirname as V,join as Y}from"node:path";var we="broods",Ie="_generated",m=Y(z(),".broods","config.json"),E="broods.app",T="dashboard",X="gateway";async function xe(){let e=process.env.BROODS_TOKEN,n=process.env.BROODS_BASE_URL;if(e&&n)return{baseUrl:u(n),token:e,createdAt:new Date().toISOString()};try{let t=JSON.parse(await F(m,"utf8"));if(typeof t.baseUrl!=="string"||!t.baseUrl)return null;return t}catch{return null}}async function Ee(e){await J(V(m),{recursive:!0}),await Z(m,`${JSON.stringify(e,null,2)}
3
+ `,"utf8")}function u(e){return e.replace(/\/+$/,"")}function Te(e){try{let n=new URL(e);if(!n.hostname.startsWith(`${T}.`))return;let t=n.hostname.slice(T.length+1);if(t!==E&&!t.endsWith(`.${E}`))return;return n.hostname=`${X}.${t}`,u(n.origin)}catch{return}}import{existsSync as Q,readFileSync as P,statSync as ee}from"node:fs";import{join as ne,resolve as te}from"node:path";var I=new Map,oe=new Set(Object.keys(process.env)),D=new Set;function k(e=process.cwd()){re(e);let n=ae();return{dashboardUrl:process.env.BROODS_DASHBOARD_URL??n?.dashboardUrl,baseUrl:process.env.BROODS_BASE_URL??n?.baseUrl,token:process.env.BROODS_TOKEN??n?.token,project:process.env.BROODS_PROJECT,environment:process.env.BROODS_ENVIRONMENT}}function re(e){let n=te(e),t=process.env.BROODS_RELOAD_ENV==="1";for(let o of[".env",".env.local"]){let r=ne(n,o);if(!Q(r)){I.delete(r);continue}let s=ee(r).mtimeMs,i=I.get(r);if(i&&i.mtimeMs===s)continue;I.set(r,{mtimeMs:s});for(let[a,l]of Object.entries(se(P(r,"utf8"))))if(t||!oe.has(a)||D.has(a))process.env[a]=l,D.add(a)}}function se(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,s=r.indexOf("=");if(s<=0)continue;let i=r.slice(0,s).trim();if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(i))continue;n[i]=ie(r.slice(s+1).trim())}return n}function ie(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}function ae(){try{let e=JSON.parse(P(m,"utf8"));if(typeof e.baseUrl!=="string"||typeof e.token!=="string")return null;return{baseUrl:u(e.baseUrl),...typeof e.dashboardUrl==="string"?{dashboardUrl:u(e.dashboardUrl)}:{},token:e.token}}catch{return null}}var A="https://gateway.broods.app";class U extends Error{accepted;constructor(e){super(`Ingress ${e.eventId} was accepted asynchronously with status ${e.status??"queued"}`);this.accepted=e;this.name="IngressAcceptedError"}}class ce{baseUrl;apiKey;fetchImpl;constructor(e={}){k(),this.baseUrl=v(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||A),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}`}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:(s)=>this.run({...s,agentName:o,agentId:r}),runAsync:(s)=>this.runAsync({...s,agentName:o,agentId:r}),stream:(s)=>this.stream({...s,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),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 s of r)if(t.push(s),s.type==="text-delta")o+=s.text;return{text:o,events:t}}async*stream(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o=O(t,"cli"),r=n?this.scopedUrl(e):this.baseUrl,s=await this.openStream(o,r);if(!s.ok)throw Error(`Run failed: ${s.status} ${await s.text()}`);if(s.status===202)throw new U(N(await s.json(),o));if(!s.body)throw Error("Run response has no body");for await(let i of x(s.body)){let a;try{a=JSON.parse(i)}catch{continue}if(a.type==="error")throw Error(`Agent run failed: ${fe(a.error)}`);yield a}}async runAsync(e,n){let t=n?{...n,agentId:e.id,agentName:e.name}:e,o=O(t,"async"),r=n?this.scopedUrl(e,"/async"):`${this.baseUrl}/async`,s=await this.fetchJson(r,{method:"POST",headers:this.apiKeyHeaders(),body:JSON.stringify(o)});if(s.status!==202)throw Error(`Async run failed: ${s.status} ${await ge(s,"202 JSON")}`);let i=N(await s.json(),o);return{...i,conversationKey:o.conversationKey,poll:()=>this.getAsyncStatus(i),wait:(a)=>this.waitForAsyncStatus(i,a)}}async getAsyncStatus(e,n={}){let t=this.resolveStatusUrl(e,n),o=await this.fetchJson(t,{method:"GET",headers:this.apiKeyHeaders()});if(o.status===404)return{status:"not_found"};if(!o.ok)throw Error(`Status check failed: ${o.status} ${await o.text()}`);return await o.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,n);if(r.status==="awaiting_approval"||r.status==="completed"||r.status==="failed"||r.status==="expired"||r.status==="not_found")return r;await pe(o,n.signal)}throw Error("Polling timeout")}async createCron(e){let n=await this.fetchJson(`${this.baseUrl}/v1/crons`,{method:"POST",headers:this.apiKeyHeaders(),body:JSON.stringify(de(e))});if(n.status!==201)throw Error(`Create cron job failed: ${n.status} ${await p(n)}`);return await n.json()}async listCrons(){let e=await this.fetchJson(`${this.baseUrl}/v1/crons`,{method:"GET",headers:this.apiKeyHeaders()});if(!e.ok)throw Error(`List cron jobs failed: ${e.status} ${await p(e)}`);return(await e.json()).crons}async getCron(e){let n=await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(e)}`,{method:"GET",headers:this.apiKeyHeaders()});if(n.status===404)return null;if(!n.ok)throw Error(`Get cron job failed: ${n.status} ${await p(n)}`);return await n.json()}async listCronRuns(e,n={}){let t=new URLSearchParams;if(n.limit!==void 0)t.set("limit",String(n.limit));let o=t.size>0?`?${t}`:"",r=await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(e)}/runs${o}`,{method:"GET",headers:this.apiKeyHeaders()});if(!r.ok)throw Error(`List cron job runs failed: ${r.status} ${await p(r)}`);return(await r.json()).runs}async updateCron(e,n){let t=await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(e)}`,{method:"PATCH",headers:this.apiKeyHeaders(),body:JSON.stringify(n)});if(!t.ok)throw Error(`Update cron job failed: ${t.status} ${await p(t)}`);return await t.json()}async deleteCron(e){let n=await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(e)}`,{method:"DELETE",headers:this.apiKeyHeaders()});if(n.status===404)return!1;if(!n.ok)throw Error(`Delete cron job failed: ${n.status} ${await p(n)}`);return(await n.json()).deleted}scopedUrl(e,n=""){if(e.projectSlug&&e.environmentSlug&&e.endpointId)return`${this.baseUrl}/v1/${encodeURIComponent(e.projectSlug)}/agents/${encodeURIComponent(e.environmentSlug)}/${encodeURIComponent(e.endpointId)}${n}`;return`${this.baseUrl}${n}`}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 ${A} 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,headers:{"Content-Type":"application/json",...n.headers??{}}})}catch(t){throw Error(`Cannot access the broods core service at ${e}. Cause: ${t instanceof Error?t.message:String(t)}`)}}resolveStatusUrl(e,n){if(typeof e!=="string")return e.statusUrl;if(/^https?:\/\//.test(e))return e;if(!n.agentId)throw Error("Polling by status id requires agentId.");return ue(this.baseUrl,e,n.agentId)}}function v(e){let n=e.trim(),t=/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(n)?n:`https://${n}`;return u(t)}function O(e,n){let t=e.eventId??`${n}-${Date.now()}`;return{agentId:e.agentId,eventId:t,conversationKey:e.conversationKey??t,events:b(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 N(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=le(t);if(!o.statusId)throw Error("Async response statusUrl missing status id");let r=typeof e.eventId==="string"?e.eventId:o.statusId,s=e.status,i=e.requestedMode;return{statusUrl:t,statusId:o.statusId,eventId:r,agentId:o.agentId??n.agentId,...s==="accepted"||s==="queued"||s==="applied"||s==="processing"?{status:s}:{},...i==="reject"||i==="followup"||i==="collect"||i==="steer"?{requestedMode:i}:{}}}function le(e){let n=new URL(e),t=n.pathname.match(/\/status\/([^/]+)$/);return{statusId:t?.[1]?decodeURIComponent(t[1]):void 0,agentId:n.searchParams.get("agentId")??void 0}}function ue(e,n,t){return`${v(e)}/status/${encodeURIComponent(n)}?agentId=${encodeURIComponent(t)}`}async function ge(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 routed /async to the direct streaming runner instead of the async handler.`;let o=await e.text();if(o.length<=2000)return o;return`${o.slice(0,2000)}... [truncated ${o.length-2000} chars]`}async function p(e){let n=await e.text();if(n.includes("Request body must include eventId and conversationKey"))return`${n}. Cron job APIs must be served by the configured baseUrl. Prefer defining stable cron jobs with defineCron(...) in broods/ and syncing with \`broods dev\` or \`broods deploy\`.`;return n}function de(e){if("agentId"in e)return e;let n=e.agent,t=typeof n==="string"?n:n.id,{agent:o,...r}=e;return{...r,agentId:t}}function pe(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 fe(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}`}var ye=2000,W=0,h=1;class me{baseUrl;apiKey;WebSocketImpl;connectTimeoutMs;constructor(e={}){if(k(),this.baseUrl=B(e.baseUrl||e.host||process.env.BROODS_BASE_URL||process.env.BROODS_HOST||A),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??ye}subscribe(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=he(e),s=M(this.baseUrl),i=new t(o),a=!1,l=!1,g=setTimeout(()=>{if(!a)y(s)},this.connectTimeoutMs),w=(c=1000,R="client closed")=>{if(l)return;if(l=!0,clearTimeout(g),e.signal?.removeEventListener("abort",S),i.readyState===h||i.readyState===W)i.close(c,R)},y=(c)=>{n.onError?.(c),w(1011,"websocket error")},G=()=>{n.onDone?.(),w(1000,"done")},S=()=>{if(i.readyState===h)i.send(JSON.stringify({type:"cancel"}));y(Error("WebSocket run aborted."))};return e.signal?.addEventListener("abort",S,{once:!0}),i.onopen=()=>{if(a=!0,clearTimeout(g),e.signal?.aborted){S();return}i.send(JSON.stringify({type:"execute",agentId:r,events:b(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}:{}}))},i.onmessage=(c)=>{if(typeof c.data!=="string")return;let R=_(c.data);if(!R)return;let C=$(R,n);switch(n.onMessage?.(C),C.type){case"meta":n.onMeta?.(C);break;case"done":G();break;case"error":y(Error(K(C.error)));break}},i.onerror=()=>{y(s)},i.onclose=(c)=>{if(clearTimeout(g),e.signal?.removeEventListener("abort",S),l||c.code===1000)return;y(Error(c.reason||"WebSocket connection closed."))},{url:o,sendControl(c){if(i.readyState!==h)throw Error("WebSocket is not open");i.send(JSON.stringify({type:"control",...c}))},close:w}}attach(e,n={}){let t=this.resolveWebSocket(),o=this.buildUrl(e),r=new t(o),s=!1,i=(a=1000,l="client closed")=>{if(s)return;if(s=!0,r.readyState===h||r.readyState===W)r.close(a,l)};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 l=_(a.data);if(!l)return;let g=$(l,n);if(n.onMessage?.(g),g.type==="done")n.onDone?.();if(g.type==="error")n.onError?.(Error(K(g.error)))},r.onerror=()=>n.onError?.(M(this.baseUrl)),r.onclose=(a)=>{if(!s&&a.code!==1000)n.onError?.(Error(a.reason||"WebSocket connection closed."))},{url:o,sendControl(a){if(r.readyState!==h)throw Error("WebSocket is not open");r.send(JSON.stringify({type:"control",...a}))},close:i}}async*stream(e){let n=[],t=!1,o=null,r=null,s=()=>{r?.(),r=null},i=this.subscribe(e,{onMessage(a){n.push(a),s()},onDone(){t=!0,s()},onError(a){o=a,s()}});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{i.close()}}buildUrl(e){let n=Se(e),t=e.projectSlug??e.agent?.projectSlug,o=e.environmentSlug??e.agent?.environmentSlug,r=t?`/${t}`:"",s=o?`/${o}`:"";return`${Re(this.baseUrl)}/v1${r}/agents${s}/${encodeURIComponent(n)}/ws?token=${encodeURIComponent(this.apiKey)}`}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 he(e){let n=e.agentId??e.agent?.id??e.endpointId;if(!n)throw Error("WebSocket run requires agent, agentId, or endpointId.");return n}function Se(e){let n=e.endpointId??e.agent?.endpointId??e.agent?.id;if(!n)throw Error("WebSocket run requires agent or endpointId.");return n}function Re(e){let n=new URL(B(e));if(n.protocol==="https:")n.protocol="wss:";if(n.protocol==="http:")n.protocol="ws:";return u(n.toString())}function B(e){let n=e.trim();if(/^wss?:\/\//.test(n))return u(n);return v(n)}function M(e){return Error(`Cannot access the WebSocket service at ${e}.`)}function $(e,n){if(e.type!=="output")return e;let t=e;return n.onOutput?.(t),t.data}function _(e){try{let n=JSON.parse(e);return typeof n==="object"&&n!==null&&typeof n.type==="string"?n:null}catch{return null}}function K(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)}var j=Symbol.for("broods.resource"),L=Symbol.for("broods.config"),q=Symbol.for("broods.channel"),H=/^[A-Z][A-Z0-9_]{0,63}$/;var Ge=new Proxy((e)=>{if(!H.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(e,n,t){if(typeof n==="string"&&H.test(n))throw Error(`env.${n} is not supported; use env("${n}")`);return Reflect.get(e,n,t)}});function d(e,n,t,o){return{[j]:!0,kind:e,name:n,...t?{description:t}:{},config:o}}function f(e,n){let{workspaceScope:t,...o}=n;return{[q]:!0,kind:"channel",type:e,...t?{workspaceScope:t}:{},config:{...o,...t?{workspaceScope:t}:{}}}}function Je(e){return f("telegram",e)}function Fe(e){return f("github",e)}function Ze(e){return f("slack",e)}function ze(e){return f("discord",e)}function Ve(e){return f("pancake",e)}function Ye(e){return f("zalo",e)}function Xe(e){return{[L]:!0,config:e}}function Qe(e){let{name:n,description:t,...o}=e;return d("agent",n,t,o)}function en(e){let{name:n,description:t,...o}=e;return d("workspace",n,t,o)}function nn(e){let{name:n,description:t,...o}=e;return d("sandbox",n,t,o)}function tn(e){let{name:n,description:t,...o}=e;return d("skill",n,t,o)}function on(e){let{name:n,...t}=e;return d("tool",n,void 0,t)}function rn(e){let{name:n,description:t,...o}=e;return d("policy",n,t,o)}function sn(e){let{name:n,description:t,...o}=e;return d("cron",n,t,o)}function an(e){return Boolean(e&&typeof e==="object"&&e[j])}function cn(e){return Boolean(e&&typeof e==="object"&&e[q])}function ln(e){return Boolean(e&&typeof e==="object"&&e[L])}
5
+ export{b as d,x as e,we as f,Ie as g,m as h,xe as i,Ee as j,u as k,Te as l,k as m,A as n,U as o,ce as p,v as q,me as r,Re as s,Ge as t,Je as u,Fe as v,Ze as w,ze as x,Ve as y,Ye as z,Xe as A,Qe as B,en as C,nn as D,tn as E,on as F,rn as G,sn as H,an as I,cn as J,ln as K};
@@ -0,0 +1 @@
1
+ import{M as a}from"./chunk-m6935tq1.js";import"./chunk-xv4t40dh.js";export default a();
@@ -0,0 +1 @@
1
+ import{L as _,M as k}from"./chunk-m6935tq1.js";import{N as s}from"./chunk-xv4t40dh.js";var T=s(function(w,f){var{defineProperty:i,getOwnPropertyDescriptor:l,getOwnPropertyNames:u}=Object,d=Object.prototype.hasOwnProperty,O=(t,e)=>{for(var o in e)i(t,o,{get:e[o],enumerable:!0})},j=(t,e,o,n)=>{if(e&&typeof e==="object"||typeof e==="function"){for(let r of u(e))if(!d.call(t,r)&&r!==o)i(t,r,{get:()=>e[r],enumerable:!(n=l(e,r))||n.enumerable})}return t},v=(t)=>j(i({},"__esModule",{value:!0}),t),p={};O(p,{refreshToken:()=>y});f.exports=v(p);var c=_(),a=k();async function y(t){let e=t?.project,o=t?.team;if(!e&&!o){let r=(0,a.findProjectInfo)();e=r.projectId,o=r.teamId}else if(!e||!o){let r=(0,a.findProjectInfo)();e=e??r.projectId,o=o??r.teamId}if(!e)throw new c.VercelOidcTokenError("Failed to refresh OIDC token: No project specified. Try re-linking your project with `vc link`");let n=(0,a.loadToken)(e);if(!n||(0,a.isExpired)((0,a.getTokenPayload)(n.token),t?.expirationBufferMs)){let r=await(0,a.getVercelToken)({expirationBufferMs:t?.expirationBufferMs});if(n=await(0,a.getVercelOidcToken)(r,e,o),!n)throw new c.VercelOidcTokenError("Failed to refresh OIDC token");(0,a.saveToken)(n,e)}process.env.VERCEL_OIDC_TOKEN=n.token;return}});export default T();
@@ -0,0 +1,2 @@
1
+ var a=/^[A-Z][A-Z0-9_]*$/;function u(e){if(!a.test(e)||e.length>64)throw Error("envPlaceholder name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");return`\${${e}}`}class o 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 i(e){return typeof process<"u"?process?.env?.[e]:void 0}class c{baseUrl;accountSecret;fetchImpl;constructor(e={}){let t=e.baseUrl??i("BROODS_BASE_URL")??"https://gateway.broods.app",n=e.accountSecret??i("BROODS_ACCOUNT_SECRET");if(!n)throw Error("BroodsAccountClient requires an accountSecret (or BROODS_ACCOUNT_SECRET).");this.baseUrl=t.replace(/\/+$/,""),this.accountSecret=n,this.fetchImpl=e.fetch??fetch}async getAccount(){let e=await this.request("GET","/v1/account");if(!e)throw new o("GET","/v1/account",404,"Account not found");return e.account}async updateAccount(e){return(await this.request("PATCH","/v1/account",e))?.account??null}async rotateSecret(){let e=await this.request("POST","/v1/account/rotate-secret");if(!e)throw new o("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,n){let s=[e,t,n].map(encodeURIComponent);return`${this.baseUrl}/webhooks/${s.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 o("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 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 o("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 o("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 o("POST",n,404,"Workspace not found");return s.file}async renameWorkspaceFile(e,t,n){return(await this.request("PATCH",`/v1/workspaces/${encodeURIComponent(e)}/files`,{path:t,newPath:n}))?.renamed??!1}async deleteWorkspaceFile(e,t){return(await this.request("DELETE",`/v1/workspaces/${encodeURIComponent(e)}/files`,{path:t}))?.deleted??!1}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 o("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 listTools(){return(await this.request("GET","/v1/tools"))?.tools??[]}async createTool(e){let t=await this.request("POST","/v1/tools",e);if(!t)throw new o("POST","/v1/tools",404,"Not found");return t}async getTool(e){return await this.request("GET",`/v1/tools/${encodeURIComponent(e)}`)}async updateTool(e,t){return await this.request("PATCH",`/v1/tools/${encodeURIComponent(e)}`,t)}async deleteTool(e){return(await this.request("DELETE",`/v1/tools/${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 o("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 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 o("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 o("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 o("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.accountSecret}`,...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 o(e,t,s.status,await s.text());return await s.json()}}
2
+ export{u as a,o as b,c};
@@ -0,0 +1,2 @@
1
+ import{N as c,P as s}from"./chunk-xv4t40dh.js";var g=c(function(ur,A){var{defineProperty:w,getOwnPropertyDescriptor:oe,getOwnPropertyNames:ne}=Object,se=Object.prototype.hasOwnProperty,ie=(e,r)=>{for(var t in r)w(e,t,{get:r[t],enumerable:!0})},ae=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of ne(r))if(!se.call(e,o)&&o!==t)w(e,o,{get:()=>r[o],enumerable:!(n=oe(r,o))||n.enumerable})}return e},ce=(e)=>ae(w({},"__esModule",{value:!0}),e),D={};ie(D,{VercelOidcTokenError:()=>x});A.exports=ce(D);class x extends Error{constructor(e,r){super(e);this.name="VercelOidcTokenError",this.cause=r}toString(){if(this.cause)return`${this.name}: ${this.message}: ${this.cause}`;return`${this.name}: ${this.message}`}}});var R=c(function(pr,C){var{create:ue,defineProperty:h,getOwnPropertyDescriptor:pe,getOwnPropertyNames:le,getPrototypeOf:fe}=Object,_e=Object.prototype.hasOwnProperty,de=(e,r)=>{for(var t in r)h(e,t,{get:r[t],enumerable:!0})},S=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of le(r))if(!_e.call(e,o)&&o!==t)h(e,o,{get:()=>r[o],enumerable:!(n=pe(r,o))||n.enumerable})}return e},P=(e,r,t)=>(t=e!=null?ue(fe(e)):{},S(r||!e||!e.__esModule?h(t,"default",{value:e,enumerable:!0}):t,e)),he=(e)=>S(h({},"__esModule",{value:!0}),e),V={};de(V,{findRootDir:()=>ye,getUserDataDir:()=>we});C.exports=he(V);var f=P(s("path")),ve=P(s("fs")),O=P(s("os")),ke=g();function ye(){try{let e=process.cwd();while(e!==f.default.dirname(e)){let r=f.default.join(e,".vercel");if(ve.default.existsSync(r))return e;e=f.default.dirname(e)}}catch(e){throw new ke.VercelOidcTokenError("Token refresh only supported in node server environments")}return null}function we(){if(process.env.XDG_DATA_HOME)return process.env.XDG_DATA_HOME;switch(O.default.platform()){case"darwin":return f.default.join(O.default.homedir(),"Library/Application Support");case"linux":return f.default.join(O.default.homedir(),".local/share");case"win32":if(process.env.LOCALAPPDATA)return process.env.LOCALAPPDATA;return null;default:return null}}});var U=c(function(lr,$){var{create:ge,defineProperty:v,getOwnPropertyDescriptor:Oe,getOwnPropertyNames:Pe,getPrototypeOf:be}=Object,je=Object.prototype.hasOwnProperty,Te=(e,r)=>{for(var t in r)v(e,t,{get:r[t],enumerable:!0})},M=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of Pe(r))if(!je.call(e,o)&&o!==t)v(e,o,{get:()=>r[o],enumerable:!(n=Oe(r,o))||n.enumerable})}return e},I=(e,r,t)=>(t=e!=null?ge(be(e)):{},M(r||!e||!e.__esModule?v(t,"default",{value:e,enumerable:!0}):t,e)),Ee=(e)=>M(v({},"__esModule",{value:!0}),e),N={};Te(N,{isValidAccessToken:()=>Ae,readAuthConfig:()=>De,writeAuthConfig:()=>xe});$.exports=Ee(N);var _=I(s("fs")),q=I(s("path")),me=J();function F(){let e=(0,me.getVercelDataDir)();if(!e)throw Error(`Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`);return q.join(e,"auth.json")}function De(){try{let e=F();if(!_.existsSync(e))return null;let r=_.readFileSync(e,"utf8");if(!r)return null;return JSON.parse(r)}catch(e){return null}}function xe(e){let r=F(),t=q.dirname(r);if(!_.existsSync(t))_.mkdirSync(t,{mode:504,recursive:!0});_.writeFileSync(r,JSON.stringify(e,null,2),{mode:384})}function Ae(e,r=0){if(!e.token)return!1;if(typeof e.expiresAt!=="number")return!0;let t=Math.floor(Date.now()/1000),n=r/1000;return e.expiresAt>=t+n}});var z=c(function(fr,H){var{defineProperty:T,getOwnPropertyDescriptor:Se,getOwnPropertyNames:Ve}=Object,Ce=Object.prototype.hasOwnProperty,Re=(e,r)=>{for(var t in r)T(e,t,{get:r[t],enumerable:!0})},Me=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of Ve(r))if(!Ce.call(e,o)&&o!==t)T(e,o,{get:()=>r[o],enumerable:!(n=Se(r,o))||n.enumerable})}return e},Ie=(e)=>Me(T({},"__esModule",{value:!0}),e),L={};Re(L,{processTokenResponse:()=>Ue,refreshTokenRequest:()=>$e});H.exports=Ie(L);var b=s("os"),Ne="https://vercel.com",qe="cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp",B=`@vercel/oidc node-${process.version} ${(0,b.platform)()} (${(0,b.arch)()}) ${(0,b.hostname)()}`,j=null;async function Fe(){if(j)return j;let e=`${Ne}/.well-known/openid-configuration`,r=await fetch(e,{headers:{"user-agent":B}});if(!r.ok)throw Error("Failed to discover OAuth endpoints");let t=await r.json();if(!t||typeof t.token_endpoint!=="string")throw Error("Invalid OAuth discovery response");let n=t.token_endpoint;return j=n,n}async function $e(e){let r=await Fe();return await fetch(r,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded","user-agent":B},body:new URLSearchParams({client_id:qe,grant_type:"refresh_token",...e})})}async function Ue(e){let r=await e.json();if(!e.ok){let t=typeof r==="object"&&r&&"error"in r?String(r.error):"Token refresh failed";return[Error(t)]}if(typeof r!=="object"||r===null)return[Error("Invalid token response")];if(typeof r.access_token!=="string")return[Error("Missing access_token in response")];if(r.token_type!=="Bearer")return[Error("Invalid token_type in response")];if(typeof r.expires_in!=="number")return[Error("Missing expires_in in response")];return[null,r]}});var Z=c(function(_r,Q){var{defineProperty:E,getOwnPropertyDescriptor:Je,getOwnPropertyNames:Le}=Object,Be=Object.prototype.hasOwnProperty,He=(e,r)=>{for(var t in r)E(e,t,{get:r[t],enumerable:!0})},ze=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of Le(r))if(!Be.call(e,o)&&o!==t)E(e,o,{get:()=>r[o],enumerable:!(n=Je(r,o))||n.enumerable})}return e},Ge=(e)=>ze(E({},"__esModule",{value:!0}),e),G={};He(G,{AccessTokenMissingError:()=>X,RefreshAccessTokenFailedError:()=>Y});Q.exports=Ge(G);class X extends Error{constructor(){super("No authentication found. Please log in with the Vercel CLI (vercel login).");this.name="AccessTokenMissingError"}}class Y extends Error{constructor(e){super("Failed to refresh authentication token.",{cause:e});this.name="RefreshAccessTokenFailedError"}}});var J=c(function(dr,te){var{create:Xe,defineProperty:k,getOwnPropertyDescriptor:Ye,getOwnPropertyNames:Qe,getPrototypeOf:Ze}=Object,Ke=Object.prototype.hasOwnProperty,We=(e,r)=>{for(var t in r)k(e,t,{get:r[t],enumerable:!0})},W=(e,r,t,n)=>{if(r&&typeof r==="object"||typeof r==="function"){for(let o of Qe(r))if(!Ke.call(e,o)&&o!==t)k(e,o,{get:()=>r[o],enumerable:!(n=Ye(r,o))||n.enumerable})}return e},ee=(e,r,t)=>(t=e!=null?Xe(Ze(e)):{},W(r||!e||!e.__esModule?k(t,"default",{value:e,enumerable:!0}):t,e)),er=(e)=>W(k({},"__esModule",{value:!0}),e),re={};We(re,{assertVercelOidcTokenResponse:()=>m,findProjectInfo:()=>nr,getTokenPayload:()=>ar,getVercelDataDir:()=>rr,getVercelOidcToken:()=>or,getVercelToken:()=>tr,isExpired:()=>cr,loadToken:()=>ir,saveToken:()=>sr});te.exports=er(re);var d=ee(s("path")),i=ee(s("fs")),l=g(),y=R(),u=U(),K=z(),p=Z();function rr(){let r=(0,y.getUserDataDir)();if(!r)return null;return d.join(r,"com.vercel.cli")}async function tr(e){let r=(0,u.readAuthConfig)();if(!r?.token)throw new p.AccessTokenMissingError;if((0,u.isValidAccessToken)(r,e?.expirationBufferMs))return r.token;if(!r.refreshToken)throw(0,u.writeAuthConfig)({}),new p.RefreshAccessTokenFailedError("No refresh token available");try{let t=await(0,K.refreshTokenRequest)({refresh_token:r.refreshToken}),[n,o]=await(0,K.processTokenResponse)(t);if(n||!o)throw(0,u.writeAuthConfig)({}),new p.RefreshAccessTokenFailedError(n);let a={token:o.access_token,expiresAt:Math.floor(Date.now()/1000)+o.expires_in};if(o.refresh_token)a.refreshToken=o.refresh_token;return(0,u.writeAuthConfig)(a),a.token}catch(t){if((0,u.writeAuthConfig)({}),t instanceof p.AccessTokenMissingError||t instanceof p.RefreshAccessTokenFailedError)throw t;throw new p.RefreshAccessTokenFailedError(t)}}async function or(e,r,t){let n=`https://api.vercel.com/v1/projects/${r}/token?source=vercel-oidc-refresh${t?`&teamId=${t}`:""}`,o=await fetch(n,{method:"POST",headers:{Authorization:`Bearer ${e}`}});if(!o.ok)throw new l.VercelOidcTokenError(`Failed to refresh OIDC token: ${o.statusText}`);let a=await o.json();return m(a),a}function m(e){if(!e||typeof e!=="object")throw TypeError("Vercel OIDC token is malformed. Expected an object. Please run `vc env pull` and try again");if(!("token"in e)||typeof e.token!=="string")throw TypeError("Vercel OIDC token is malformed. Expected a string-valued token property. Please run `vc env pull` and try again")}function nr(){let e=(0,y.findRootDir)();if(!e)throw new l.VercelOidcTokenError("Unable to find project root directory. Have you linked your project with `vc link?`");let r=d.join(e,".vercel","project.json");if(!i.existsSync(r))throw new l.VercelOidcTokenError("project.json not found, have you linked your project with `vc link?`");let t=JSON.parse(i.readFileSync(r,"utf8"));if(typeof t.projectId!=="string"&&typeof t.orgId!=="string")throw TypeError("Expected a string-valued projectId property. Try running `vc link` to re-link your project.");return{projectId:t.projectId,teamId:t.orgId}}function sr(e,r){let t=(0,y.getUserDataDir)();if(!t)throw new l.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");let n=d.join(t,"com.vercel.token",`${r}.json`),o=JSON.stringify(e);i.mkdirSync(d.dirname(n),{mode:504,recursive:!0}),i.writeFileSync(n,o),i.chmodSync(n,432);return}function ir(e){let r=(0,y.getUserDataDir)();if(!r)throw new l.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");let t=d.join(r,"com.vercel.token",`${e}.json`);if(!i.existsSync(t))return null;let n=JSON.parse(i.readFileSync(t,"utf8"));return m(n),n}function ar(e){let r=e.split(".");if(r.length!==3)throw new l.VercelOidcTokenError("Invalid token. Please run `vc env pull` and try again");let t=r[1].replace(/-/g,"+").replace(/_/g,"/"),n=t.padEnd(t.length+(4-t.length%4)%4,"=");return JSON.parse(Buffer.from(n,"base64").toString("utf8"))}function cr(e,r=0){return e.exp*1000<Date.now()+r}});
2
+ export{g as L,J as M};
@@ -0,0 +1,2 @@
1
+ import{createRequire as g}from"node:module";var d=Object.defineProperty;var h=(b,a)=>()=>(a||b((a={exports:{}}).exports,a),a.exports);var e=(b)=>b;function f(b,a){this[b]=e.bind(null,a)}var i=(b,a)=>{for(var c in a)d(b,c,{get:a[c],enumerable:!0,configurable:!0,set:f.bind(a,c)})};var k=g(import.meta.url);
2
+ export{h as N,i as O,k as P};