broods 0.2.1 → 0.4.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.js CHANGED
@@ -1,4 +1,288 @@
1
1
  // @bun
2
+ // src/account.ts
3
+ var DEFAULT_ACCOUNT_BASE_URL = "https://gateway.broods.app";
4
+ var ACCOUNT_ENV_VAR_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
5
+ function envPlaceholder(name) {
6
+ if (!ACCOUNT_ENV_VAR_NAME_PATTERN.test(name) || name.length > 64) {
7
+ throw new Error("envPlaceholder name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");
8
+ }
9
+ return `\${${name}}`;
10
+ }
11
+
12
+ class BroodsAccountApiError extends Error {
13
+ status;
14
+ body;
15
+ constructor(method, path, status, body) {
16
+ super(`${method} ${path} failed with ${status}: ${body}`);
17
+ this.name = "BroodsAccountApiError";
18
+ this.status = status;
19
+ this.body = body;
20
+ }
21
+ }
22
+ function envVar(name) {
23
+ return typeof process !== "undefined" ? process?.env?.[name] : undefined;
24
+ }
25
+
26
+ class BroodsAccountClient {
27
+ baseUrl;
28
+ accountSecret;
29
+ fetchImpl;
30
+ constructor(options = {}) {
31
+ const baseUrl = options.baseUrl ?? envVar("BROODS_BASE_URL") ?? DEFAULT_ACCOUNT_BASE_URL;
32
+ const accountSecret = options.accountSecret ?? envVar("BROODS_ACCOUNT_SECRET");
33
+ if (!accountSecret)
34
+ throw new Error("BroodsAccountClient requires an accountSecret (or BROODS_ACCOUNT_SECRET).");
35
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
36
+ this.accountSecret = accountSecret;
37
+ this.fetchImpl = options.fetch ?? fetch;
38
+ }
39
+ async getAccount() {
40
+ const result = await this.request("GET", "/v1/account");
41
+ if (!result)
42
+ throw new BroodsAccountApiError("GET", "/v1/account", 404, "Account not found");
43
+ return result.account;
44
+ }
45
+ async updateAccount(patch) {
46
+ const result = await this.request("PATCH", "/v1/account", patch);
47
+ return result?.account ?? null;
48
+ }
49
+ async rotateSecret() {
50
+ const result = await this.request("POST", "/v1/account/rotate-secret");
51
+ if (!result)
52
+ throw new BroodsAccountApiError("POST", "/v1/account/rotate-secret", 404, "Account not found");
53
+ return result;
54
+ }
55
+ async deleteAccount() {
56
+ const result = await this.request("DELETE", "/v1/account");
57
+ return result ?? { deleted: false };
58
+ }
59
+ webhookUrl(accountId, agentId, channelType) {
60
+ const segments = [accountId, agentId, channelType].map(encodeURIComponent);
61
+ return `${this.baseUrl}/webhooks/${segments.join("/")}`;
62
+ }
63
+ async listAgents() {
64
+ const result = await this.request("GET", "/v1/agents");
65
+ return result?.agents ?? [];
66
+ }
67
+ async createAgent(input) {
68
+ const result = await this.request("POST", "/v1/agents", input);
69
+ if (!result)
70
+ throw new BroodsAccountApiError("POST", "/v1/agents", 404, "Not found");
71
+ return result;
72
+ }
73
+ async getAgent(agentId) {
74
+ return await this.request("GET", `/v1/agents/${encodeURIComponent(agentId)}`);
75
+ }
76
+ async updateAgent(agentId, patch) {
77
+ return await this.request("PATCH", `/v1/agents/${encodeURIComponent(agentId)}`, patch);
78
+ }
79
+ async deleteAgent(agentId) {
80
+ const result = await this.request("DELETE", `/v1/agents/${encodeURIComponent(agentId)}`);
81
+ return result?.deleted ?? false;
82
+ }
83
+ async listEnvVars() {
84
+ const result = await this.request("GET", "/v1/env");
85
+ return result?.env ?? [];
86
+ }
87
+ async setEnvVar(name, value) {
88
+ await this.request("PUT", `/v1/env/${encodeURIComponent(name)}`, { value });
89
+ }
90
+ async deleteEnvVar(name) {
91
+ const result = await this.request("DELETE", `/v1/env/${encodeURIComponent(name)}`);
92
+ return result?.deleted ?? false;
93
+ }
94
+ async listCrons() {
95
+ const result = await this.request("GET", "/v1/crons");
96
+ return result?.crons ?? [];
97
+ }
98
+ async createCron(input) {
99
+ const result = await this.request("POST", "/v1/crons", input);
100
+ if (!result)
101
+ throw new BroodsAccountApiError("POST", "/v1/crons", 404, "Not found");
102
+ return result;
103
+ }
104
+ async getCron(cronId) {
105
+ return await this.request("GET", `/v1/crons/${encodeURIComponent(cronId)}`);
106
+ }
107
+ async updateCron(cronId, patch) {
108
+ return await this.request("PATCH", `/v1/crons/${encodeURIComponent(cronId)}`, patch);
109
+ }
110
+ async deleteCron(cronId) {
111
+ const result = await this.request("DELETE", `/v1/crons/${encodeURIComponent(cronId)}`);
112
+ return result?.deleted ?? false;
113
+ }
114
+ async listCronRuns(cronId, options = {}) {
115
+ const query = options.limit !== undefined ? `?limit=${options.limit}` : "";
116
+ const result = await this.request("GET", `/v1/crons/${encodeURIComponent(cronId)}/runs${query}`);
117
+ return result?.runs ?? [];
118
+ }
119
+ async listWorkspaces() {
120
+ const result = await this.request("GET", "/v1/workspaces");
121
+ return result?.workspaces ?? [];
122
+ }
123
+ async createWorkspace(input) {
124
+ const result = await this.request("POST", "/v1/workspaces", input);
125
+ if (!result)
126
+ throw new BroodsAccountApiError("POST", "/v1/workspaces", 404, "Not found");
127
+ return result;
128
+ }
129
+ async getWorkspace(workspaceId) {
130
+ return await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}`);
131
+ }
132
+ async updateWorkspace(workspaceId, patch) {
133
+ return await this.request("PATCH", `/v1/workspaces/${encodeURIComponent(workspaceId)}`, patch);
134
+ }
135
+ async deleteWorkspace(workspaceId) {
136
+ const result = await this.request("DELETE", `/v1/workspaces/${encodeURIComponent(workspaceId)}`);
137
+ return result?.deleted ?? false;
138
+ }
139
+ async listWorkspaceFiles(workspaceId) {
140
+ const result = await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`);
141
+ return result?.files ?? [];
142
+ }
143
+ async getWorkspaceFileUrl(workspaceId, path) {
144
+ const query = `?path=${encodeURIComponent(path)}`;
145
+ const result = await this.request("GET", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files${query}`);
146
+ return result?.url ?? null;
147
+ }
148
+ async uploadWorkspaceFile(workspaceId, input) {
149
+ const path = `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`;
150
+ const result = await this.request("POST", path, input);
151
+ if (!result)
152
+ throw new BroodsAccountApiError("POST", path, 404, "Workspace not found");
153
+ return result.file;
154
+ }
155
+ async renameWorkspaceFile(workspaceId, path, newPath) {
156
+ const result = await this.request("PATCH", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`, { path, newPath });
157
+ return result?.renamed ?? false;
158
+ }
159
+ async deleteWorkspaceFile(workspaceId, path) {
160
+ const result = await this.request("DELETE", `/v1/workspaces/${encodeURIComponent(workspaceId)}/files`, { path });
161
+ return result?.deleted ?? false;
162
+ }
163
+ async listSandboxes() {
164
+ const result = await this.request("GET", "/v1/sandboxes");
165
+ return result?.sandboxes ?? [];
166
+ }
167
+ async createSandbox(input) {
168
+ const result = await this.request("POST", "/v1/sandboxes", input);
169
+ if (!result)
170
+ throw new BroodsAccountApiError("POST", "/v1/sandboxes", 404, "Not found");
171
+ return result;
172
+ }
173
+ async getSandbox(sandboxId) {
174
+ return await this.request("GET", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`);
175
+ }
176
+ async updateSandbox(sandboxId, patch) {
177
+ return await this.request("PATCH", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`, patch);
178
+ }
179
+ async deleteSandbox(sandboxId) {
180
+ const result = await this.request("DELETE", `/v1/sandboxes/${encodeURIComponent(sandboxId)}`);
181
+ return result?.deleted ?? false;
182
+ }
183
+ async suspendSandbox(sandboxId, reservationKey) {
184
+ return await this.sandboxAction(sandboxId, "suspend", { reservationKey });
185
+ }
186
+ async resumeSandbox(sandboxId, reservationKey) {
187
+ return await this.sandboxAction(sandboxId, "resume", { reservationKey });
188
+ }
189
+ async terminateSandbox(sandboxId, reservationKey) {
190
+ return await this.sandboxAction(sandboxId, "terminate", { reservationKey });
191
+ }
192
+ async snapshotSandbox(sandboxId, reservationKey, name) {
193
+ return await this.sandboxAction(sandboxId, "snapshot", { reservationKey, name });
194
+ }
195
+ async openSandboxTerminal(sandboxId, reservationKey) {
196
+ return await this.sandboxAction(sandboxId, "terminal", { reservationKey });
197
+ }
198
+ async listTools() {
199
+ const result = await this.request("GET", "/v1/tools");
200
+ return result?.tools ?? [];
201
+ }
202
+ async createTool(input) {
203
+ const result = await this.request("POST", "/v1/tools", input);
204
+ if (!result)
205
+ throw new BroodsAccountApiError("POST", "/v1/tools", 404, "Not found");
206
+ return result;
207
+ }
208
+ async getTool(toolId) {
209
+ return await this.request("GET", `/v1/tools/${encodeURIComponent(toolId)}`);
210
+ }
211
+ async updateTool(toolId, patch) {
212
+ return await this.request("PATCH", `/v1/tools/${encodeURIComponent(toolId)}`, patch);
213
+ }
214
+ async deleteTool(toolId) {
215
+ const result = await this.request("DELETE", `/v1/tools/${encodeURIComponent(toolId)}`);
216
+ return result?.deleted ?? false;
217
+ }
218
+ async listPolicies() {
219
+ const result = await this.request("GET", "/v1/policies");
220
+ return result?.policies ?? [];
221
+ }
222
+ async createPolicy(input) {
223
+ const result = await this.request("POST", "/v1/policies", input);
224
+ if (!result)
225
+ throw new BroodsAccountApiError("POST", "/v1/policies", 404, "Not found");
226
+ return result;
227
+ }
228
+ async getPolicy(policyId) {
229
+ return await this.request("GET", `/v1/policies/${encodeURIComponent(policyId)}`);
230
+ }
231
+ async updatePolicy(policyId, patch) {
232
+ return await this.request("PATCH", `/v1/policies/${encodeURIComponent(policyId)}`, patch);
233
+ }
234
+ async deletePolicy(policyId) {
235
+ const result = await this.request("DELETE", `/v1/policies/${encodeURIComponent(policyId)}`);
236
+ return result?.deleted ?? false;
237
+ }
238
+ async listSkills() {
239
+ const result = await this.request("GET", "/v1/skills");
240
+ return result?.skills ?? [];
241
+ }
242
+ async createSkill(input) {
243
+ const result = await this.request("POST", "/v1/skills", input);
244
+ if (!result)
245
+ throw new BroodsAccountApiError("POST", "/v1/skills", 404, "Not found");
246
+ return result;
247
+ }
248
+ async getSkill(skillName) {
249
+ return await this.request("GET", `/v1/skills/${encodeURIComponent(skillName)}`);
250
+ }
251
+ async uploadSkill(skillName, input) {
252
+ const path = `/v1/skills/${encodeURIComponent(skillName)}`;
253
+ const result = await this.request("PUT", path, input);
254
+ if (!result)
255
+ throw new BroodsAccountApiError("PUT", path, 404, "Skill not found");
256
+ return result;
257
+ }
258
+ async deleteSkill(skillName) {
259
+ const result = await this.request("DELETE", `/v1/skills/${encodeURIComponent(skillName)}`);
260
+ return result?.deleted ?? false;
261
+ }
262
+ async sandboxAction(sandboxId, action, body) {
263
+ const path = `/v1/sandboxes/${encodeURIComponent(sandboxId)}/${action}`;
264
+ const result = await this.request("POST", path, body);
265
+ if (!result)
266
+ throw new BroodsAccountApiError("POST", path, 404, "Sandbox not found");
267
+ return result;
268
+ }
269
+ async request(method, path, body) {
270
+ const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
271
+ method,
272
+ headers: {
273
+ Authorization: `Bearer ${this.accountSecret}`,
274
+ ...body !== undefined ? { "Content-Type": "application/json" } : {}
275
+ },
276
+ ...body !== undefined ? { body: JSON.stringify(body) } : {}
277
+ });
278
+ if (response.status === 404)
279
+ return null;
280
+ if (!response.ok) {
281
+ throw new BroodsAccountApiError(method, path, response.status, await response.text());
282
+ }
283
+ return await response.json();
284
+ }
285
+ }
2
286
  // src/run-input.ts
3
287
  function resolveRunEvents(input) {
4
288
  if (input.events && input.input !== undefined) {
@@ -71,6 +355,9 @@ import { dirname, join } from "path";
71
355
  var PROJECT_DIR = "broods";
72
356
  var GENERATED_DIR = "_generated";
73
357
  var USER_CONFIG_PATH = join(homedir(), ".broods", "config.json");
358
+ var BROODS_APEX_DOMAIN = "broods.app";
359
+ var DASHBOARD_HOST_PREFIX = "dashboard";
360
+ var GATEWAY_HOST_PREFIX = "gateway";
74
361
  async function readStoredAuth() {
75
362
  const envToken = process.env.BROODS_TOKEN;
76
363
  const envConvexUrl = process.env.BROODS_BASE_URL;
@@ -98,6 +385,20 @@ async function writeStoredAuth(config) {
98
385
  function stripTrailingSlash(value) {
99
386
  return value.replace(/\/+$/, "");
100
387
  }
388
+ function gatewayUrlForDashboard(dashboardUrl) {
389
+ try {
390
+ const url = new URL(dashboardUrl);
391
+ if (!url.hostname.startsWith(`${DASHBOARD_HOST_PREFIX}.`))
392
+ return;
393
+ const rest = url.hostname.slice(DASHBOARD_HOST_PREFIX.length + 1);
394
+ if (rest !== BROODS_APEX_DOMAIN && !rest.endsWith(`.${BROODS_APEX_DOMAIN}`))
395
+ return;
396
+ url.hostname = `${GATEWAY_HOST_PREFIX}.${rest}`;
397
+ return stripTrailingSlash(url.origin);
398
+ } catch {
399
+ return;
400
+ }
401
+ }
101
402
 
102
403
  // src/runtime-config.ts
103
404
  var envFileCache = new Map;
@@ -182,6 +483,15 @@ function readStoredAuthSync() {
182
483
  // src/client.ts
183
484
  var DEFAULT_CORE_BASE_URL = "https://gateway.broods.app";
184
485
 
486
+ class IngressAcceptedError extends Error {
487
+ accepted;
488
+ constructor(accepted) {
489
+ super(`Ingress ${accepted.eventId} was accepted asynchronously with status ${accepted.status ?? "queued"}`);
490
+ this.accepted = accepted;
491
+ this.name = "IngressAcceptedError";
492
+ }
493
+ }
494
+
185
495
  class BroodsClient {
186
496
  baseUrl;
187
497
  apiKey;
@@ -240,6 +550,9 @@ class BroodsClient {
240
550
  const response = await this.openStream(body, targetUrl);
241
551
  if (!response.ok)
242
552
  throw new Error(`Run failed: ${response.status} ${await response.text()}`);
553
+ if (response.status === 202) {
554
+ throw new IngressAcceptedError(normalizeAsyncAccepted(await response.json(), body));
555
+ }
243
556
  if (!response.body)
244
557
  throw new Error("Run response has no body");
245
558
  for await (const data of readSseStream(response.body)) {
@@ -297,7 +610,7 @@ class BroodsClient {
297
610
  if (options.signal?.aborted)
298
611
  throw new Error("Async status polling aborted.");
299
612
  const payload = await this.getAsyncStatus(status, options);
300
- if (payload.status === "awaiting_approval" || payload.status === "completed" || payload.status === "failed" || payload.status === "not_found") {
613
+ if (payload.status === "awaiting_approval" || payload.status === "completed" || payload.status === "failed" || payload.status === "expired" || payload.status === "not_found") {
301
614
  return payload;
302
615
  }
303
616
  await sleep(intervalMs, options.signal);
@@ -444,6 +757,8 @@ function directRunBody(input, prefix) {
444
757
  eventId,
445
758
  conversationKey: input.conversationKey ?? eventId,
446
759
  events: resolveRunEvents(input),
760
+ ...input.mode !== undefined ? { mode: input.mode } : {},
761
+ ...input.idempotencyKey !== undefined ? { idempotencyKey: input.idempotencyKey } : {},
447
762
  ...input.system !== undefined ? { system: input.system } : {},
448
763
  ...input.model !== undefined ? { model: input.model } : {}
449
764
  };
@@ -459,11 +774,16 @@ function normalizeAsyncAccepted(payload, requestBody) {
459
774
  const status = parseStatusUrl(statusUrl);
460
775
  if (!status.statusId)
461
776
  throw new Error("Async response statusUrl missing status id");
777
+ const eventId = typeof payload.eventId === "string" ? payload.eventId : status.statusId;
778
+ const acceptedStatus = payload.status;
779
+ const requestedMode = payload.requestedMode;
462
780
  return {
463
781
  statusUrl,
464
782
  statusId: status.statusId,
465
- eventId: status.statusId,
466
- agentId: status.agentId ?? requestBody.agentId
783
+ eventId,
784
+ agentId: status.agentId ?? requestBody.agentId,
785
+ ...acceptedStatus === "accepted" || acceptedStatus === "queued" || acceptedStatus === "applied" || acceptedStatus === "processing" ? { status: acceptedStatus } : {},
786
+ ...requestedMode === "reject" || requestedMode === "followup" || requestedMode === "collect" || requestedMode === "steer" ? { requestedMode } : {}
467
787
  };
468
788
  }
469
789
  function parseStatusUrl(statusUrl) {
@@ -596,6 +916,8 @@ class BroodsWebSocketClient {
596
916
  events: resolveRunEvents(input),
597
917
  sessionId: input.sessionId,
598
918
  ...input.eventId !== undefined ? { eventId: input.eventId } : {},
919
+ ...input.mode !== undefined ? { mode: input.mode } : {},
920
+ ...input.idempotencyKey !== undefined ? { idempotencyKey: input.idempotencyKey } : {},
599
921
  ...input.system !== undefined ? { system: input.system } : {},
600
922
  ...input.model !== undefined ? { model: input.model } : {}
601
923
  }));
@@ -606,16 +928,17 @@ class BroodsWebSocketClient {
606
928
  const payload = parseServerMessage(event.data);
607
929
  if (!payload)
608
930
  return;
609
- handlers.onMessage?.(payload);
610
- switch (payload.type) {
931
+ const effective = unwrapServerMessage(payload, handlers);
932
+ handlers.onMessage?.(effective);
933
+ switch (effective.type) {
611
934
  case "meta":
612
- handlers.onMeta?.(payload);
935
+ handlers.onMeta?.(effective);
613
936
  break;
614
937
  case "done":
615
938
  finish();
616
939
  break;
617
940
  case "error":
618
- fail(new Error(formatWireError(payload.error)));
941
+ fail(new Error(formatWireError(effective.error)));
619
942
  break;
620
943
  }
621
944
  };
@@ -631,6 +954,57 @@ class BroodsWebSocketClient {
631
954
  };
632
955
  return {
633
956
  url,
957
+ sendControl(message) {
958
+ if (socket.readyState !== WS_OPEN)
959
+ throw new Error("WebSocket is not open");
960
+ socket.send(JSON.stringify({ type: "control", ...message }));
961
+ },
962
+ close
963
+ };
964
+ }
965
+ attach(input, handlers = {}) {
966
+ const WebSocketImpl = this.resolveWebSocket();
967
+ const url = this.buildUrl(input);
968
+ const socket = new WebSocketImpl(url);
969
+ let closed = false;
970
+ const close = (code = 1000, reason = "client closed") => {
971
+ if (closed)
972
+ return;
973
+ closed = true;
974
+ if (socket.readyState === WS_OPEN || socket.readyState === WS_CONNECTING)
975
+ socket.close(code, reason);
976
+ };
977
+ socket.onopen = () => socket.send(JSON.stringify({
978
+ type: "attach",
979
+ ...input,
980
+ signal: undefined,
981
+ agent: undefined
982
+ }));
983
+ socket.onmessage = (event) => {
984
+ if (typeof event.data !== "string")
985
+ return;
986
+ const payload = parseServerMessage(event.data);
987
+ if (!payload)
988
+ return;
989
+ const effective = unwrapServerMessage(payload, handlers);
990
+ handlers.onMessage?.(effective);
991
+ if (effective.type === "done")
992
+ handlers.onDone?.();
993
+ if (effective.type === "error")
994
+ handlers.onError?.(new Error(formatWireError(effective.error)));
995
+ };
996
+ socket.onerror = () => handlers.onError?.(webSocketAccessError(this.baseUrl));
997
+ socket.onclose = (event) => {
998
+ if (!closed && event.code !== 1000)
999
+ handlers.onError?.(new Error(event.reason || "WebSocket connection closed."));
1000
+ };
1001
+ return {
1002
+ url,
1003
+ sendControl(message) {
1004
+ if (socket.readyState !== WS_OPEN)
1005
+ throw new Error("WebSocket is not open");
1006
+ socket.send(JSON.stringify({ type: "control", ...message }));
1007
+ },
634
1008
  close
635
1009
  };
636
1010
  }
@@ -723,6 +1097,13 @@ function normalizeWebSocketServiceUrl(value) {
723
1097
  function webSocketAccessError(baseUrl) {
724
1098
  return new Error(`Cannot access the WebSocket service at ${baseUrl}.`);
725
1099
  }
1100
+ function unwrapServerMessage(payload, handlers) {
1101
+ if (payload.type !== "output")
1102
+ return payload;
1103
+ const output = payload;
1104
+ handlers.onOutput?.(output);
1105
+ return output.data;
1106
+ }
726
1107
  function parseServerMessage(data) {
727
1108
  try {
728
1109
  const value = JSON.parse(data);
@@ -743,25 +1124,27 @@ function formatWireError(error) {
743
1124
  var RESOURCE_MARKER = Symbol.for("broods.resource");
744
1125
  var CONFIG_MARKER = Symbol.for("broods.config");
745
1126
  var CHANNEL_MARKER = Symbol.for("broods.channel");
746
- var env = new Proxy(function env2(name) {
1127
+ var ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
1128
+ var env = new Proxy((name) => {
1129
+ if (!ENV_NAME_PATTERN.test(name)) {
1130
+ throw new Error("env name must match /^[A-Z][A-Z0-9_]*$/ and be at most 64 characters.");
1131
+ }
747
1132
  return { __beeblastEnv: true, name };
748
1133
  }, {
749
1134
  get(target, property, receiver) {
750
- if (typeof property === "string")
751
- return { __beeblastEnv: true, name: property };
1135
+ if (typeof property === "string" && ENV_NAME_PATTERN.test(property)) {
1136
+ throw new Error(`env.${property} is not supported; use env("${property}")`);
1137
+ }
752
1138
  return Reflect.get(target, property, receiver);
753
1139
  }
754
1140
  });
755
- function defineResource(kind, input) {
756
- if (input.config === undefined) {
757
- throw new Error(`Resource "${input.name}" must include config`);
758
- }
1141
+ function defineResource(kind, name, description, config) {
759
1142
  return {
760
1143
  [RESOURCE_MARKER]: true,
761
1144
  kind,
762
- name: input.name,
763
- ...input.description ? { description: input.description } : {},
764
- config: input.config
1145
+ name,
1146
+ ...description ? { description } : {},
1147
+ config
765
1148
  };
766
1149
  }
767
1150
  function defineChannel(type, config) {
@@ -799,25 +1182,32 @@ function defineBroods(config) {
799
1182
  return { [CONFIG_MARKER]: true, config };
800
1183
  }
801
1184
  function defineAgent(input) {
802
- return defineResource("agent", input);
1185
+ const { name, description, ...config } = input;
1186
+ return defineResource("agent", name, description, config);
803
1187
  }
804
1188
  function defineWorkspace(input) {
805
- return defineResource("workspace", input);
1189
+ const { name, description, ...config } = input;
1190
+ return defineResource("workspace", name, description, config);
806
1191
  }
807
1192
  function defineSandbox(input) {
808
- return defineResource("sandbox", input);
1193
+ const { name, description, ...config } = input;
1194
+ return defineResource("sandbox", name, description, config);
809
1195
  }
810
1196
  function defineSkill(input) {
811
- return defineResource("skill", input);
1197
+ const { name, description, ...config } = input;
1198
+ return defineResource("skill", name, description, config);
812
1199
  }
813
1200
  function defineTool(input) {
814
- return defineResource("tool", input);
1201
+ const { name, ...config } = input;
1202
+ return defineResource("tool", name, undefined, config);
815
1203
  }
816
1204
  function definePolicy(input) {
817
- return defineResource("policy", input);
1205
+ const { name, description, ...config } = input;
1206
+ return defineResource("policy", name, description, config);
818
1207
  }
819
1208
  function defineCron(input) {
820
- return defineResource("cron", input);
1209
+ const { name, description, ...config } = input;
1210
+ return defineResource("cron", name, description, config);
821
1211
  }
822
1212
  function isResource(value) {
823
1213
  return Boolean(value && typeof value === "object" && value[RESOURCE_MARKER]);
@@ -837,6 +1227,7 @@ export {
837
1227
  isObservabilityClientMessage,
838
1228
  isChannelDefinition,
839
1229
  isBroodsConfig,
1230
+ envPlaceholder,
840
1231
  env,
841
1232
  defineZaloChannel,
842
1233
  defineWorkspace,
@@ -855,7 +1246,10 @@ export {
855
1246
  BroodsWebSocketClient as WebsocketClient,
856
1247
  BroodsWebSocketClient as WebSocketClient,
857
1248
  MAX_OBSERVABILITY_BACKFILL,
1249
+ IngressAcceptedError,
858
1250
  DEFAULT_CORE_BASE_URL,
859
1251
  BroodsWebSocketClient,
860
- BroodsClient
1252
+ BroodsClient,
1253
+ BroodsAccountClient,
1254
+ BroodsAccountApiError
861
1255
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "broods",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "CLI + TypeScript SDK for the broods agent platform.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,6 +27,10 @@
27
27
  ".": {
28
28
  "types": "./dist/index.d.ts",
29
29
  "import": "./dist/index.js"
30
+ },
31
+ "./account": {
32
+ "types": "./dist/account.d.ts",
33
+ "import": "./dist/account.js"
30
34
  }
31
35
  },
32
36
  "main": "./dist/index.js",
@@ -46,16 +50,16 @@
46
50
  "node": ">=22"
47
51
  },
48
52
  "dependencies": {
49
- "@chat-adapter/discord": "^4.31.0",
50
- "@chat-adapter/github": "^4.31.0",
51
- "@chat-adapter/slack": "^4.31.0",
52
- "@chat-adapter/telegram": "^4.31.0",
53
- "ai": "^7.0.11"
53
+ "@chat-adapter/discord": "^4.35.0",
54
+ "@chat-adapter/github": "^4.35.0",
55
+ "@chat-adapter/slack": "^4.35.0",
56
+ "@chat-adapter/telegram": "^4.35.0",
57
+ "ai": "^7.0.37"
54
58
  },
55
59
  "devDependencies": {
56
60
  "@types/bun": "^1.3.14",
57
- "rollup": "^4.53.3",
61
+ "rollup": "^4.62.2",
58
62
  "typescript": "^6.0.3",
59
- "rollup-plugin-dts": "^6.3.0"
63
+ "rollup-plugin-dts": "^6.4.1"
60
64
  }
61
65
  }