broods 0.2.1 → 0.3.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,270 @@
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
+ }
2
268
  // src/run-input.ts
3
269
  function resolveRunEvents(input) {
4
270
  if (input.events && input.input !== undefined) {
@@ -857,5 +1123,7 @@ export {
857
1123
  MAX_OBSERVABILITY_BACKFILL,
858
1124
  DEFAULT_CORE_BASE_URL,
859
1125
  BroodsWebSocketClient,
860
- BroodsClient
1126
+ BroodsClient,
1127
+ BroodsAccountClient,
1128
+ BroodsAccountApiError
861
1129
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "broods",
3
- "version": "0.2.1",
3
+ "version": "0.3.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",