broods 0.1.1 → 0.2.1
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/cli/index.js +579 -152
- package/dist/index.d.ts +464 -89
- package/dist/index.js +54 -38
- package/package.json +10 -2
package/dist/index.js
CHANGED
|
@@ -47,6 +47,8 @@ function isObservabilityClientMessage(v) {
|
|
|
47
47
|
const backfill = msg["backfill"];
|
|
48
48
|
if (backfill !== undefined && (typeof backfill !== "number" || !Number.isSafeInteger(backfill) || backfill < 0 || backfill > MAX_OBSERVABILITY_BACKFILL))
|
|
49
49
|
return false;
|
|
50
|
+
if (msg["liveOnly"] !== undefined && typeof msg["liveOnly"] !== "boolean")
|
|
51
|
+
return false;
|
|
50
52
|
const minLevel = msg["minLevel"];
|
|
51
53
|
if (minLevel !== undefined && minLevel !== "INFO" && minLevel !== "WARN" && minLevel !== "ERROR")
|
|
52
54
|
return false;
|
|
@@ -59,7 +61,7 @@ function isObservabilityClientMessage(v) {
|
|
|
59
61
|
return false;
|
|
60
62
|
}
|
|
61
63
|
// src/runtime-config.ts
|
|
62
|
-
import { existsSync, readFileSync } from "fs";
|
|
64
|
+
import { existsSync, readFileSync, statSync } from "fs";
|
|
63
65
|
import { join as join2, resolve } from "path";
|
|
64
66
|
|
|
65
67
|
// src/config.ts
|
|
@@ -71,16 +73,19 @@ var GENERATED_DIR = "_generated";
|
|
|
71
73
|
var USER_CONFIG_PATH = join(homedir(), ".broods", "config.json");
|
|
72
74
|
async function readStoredAuth() {
|
|
73
75
|
const envToken = process.env.BROODS_TOKEN;
|
|
74
|
-
const
|
|
75
|
-
if (envToken &&
|
|
76
|
+
const envConvexUrl = process.env.BROODS_BASE_URL;
|
|
77
|
+
if (envToken && envConvexUrl) {
|
|
76
78
|
return {
|
|
77
|
-
|
|
79
|
+
baseUrl: stripTrailingSlash(envConvexUrl),
|
|
78
80
|
token: envToken,
|
|
79
81
|
createdAt: new Date().toISOString()
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
try {
|
|
83
|
-
|
|
85
|
+
const stored = JSON.parse(await readFile(USER_CONFIG_PATH, "utf8"));
|
|
86
|
+
if (typeof stored.baseUrl !== "string" || !stored.baseUrl)
|
|
87
|
+
return null;
|
|
88
|
+
return stored;
|
|
84
89
|
} catch {
|
|
85
90
|
return null;
|
|
86
91
|
}
|
|
@@ -95,12 +100,15 @@ function stripTrailingSlash(value) {
|
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
// src/runtime-config.ts
|
|
98
|
-
var
|
|
103
|
+
var envFileCache = new Map;
|
|
104
|
+
var realEnvSnapshot = new Set(Object.keys(process.env));
|
|
105
|
+
var loadedFromFiles = new Set;
|
|
99
106
|
function loadBroodsRuntimeConfig(cwd = process.cwd()) {
|
|
100
107
|
loadEnvFiles(cwd);
|
|
101
108
|
const stored = readStoredAuthSync();
|
|
102
109
|
return {
|
|
103
110
|
dashboardUrl: process.env.BROODS_DASHBOARD_URL ?? stored?.dashboardUrl,
|
|
111
|
+
baseUrl: process.env.BROODS_BASE_URL ?? stored?.baseUrl,
|
|
104
112
|
token: process.env.BROODS_TOKEN ?? stored?.token,
|
|
105
113
|
project: process.env.BROODS_PROJECT,
|
|
106
114
|
environment: process.env.BROODS_ENVIRONMENT
|
|
@@ -108,17 +116,23 @@ function loadBroodsRuntimeConfig(cwd = process.cwd()) {
|
|
|
108
116
|
}
|
|
109
117
|
function loadEnvFiles(cwd) {
|
|
110
118
|
const root = resolve(cwd);
|
|
111
|
-
|
|
112
|
-
return;
|
|
113
|
-
loadedEnvForCwd = root;
|
|
114
|
-
const originallySet = new Set(Object.keys(process.env));
|
|
119
|
+
const forceReload = process.env.BROODS_RELOAD_ENV === "1";
|
|
115
120
|
for (const file of [".env", ".env.local"]) {
|
|
116
121
|
const path = join2(root, file);
|
|
117
|
-
if (!existsSync(path))
|
|
122
|
+
if (!existsSync(path)) {
|
|
123
|
+
envFileCache.delete(path);
|
|
118
124
|
continue;
|
|
125
|
+
}
|
|
126
|
+
const mtimeMs = statSync(path).mtimeMs;
|
|
127
|
+
const cached = envFileCache.get(path);
|
|
128
|
+
if (cached && cached.mtimeMs === mtimeMs)
|
|
129
|
+
continue;
|
|
130
|
+
envFileCache.set(path, { mtimeMs });
|
|
119
131
|
for (const [key, value] of Object.entries(parseEnv(readFileSync(path, "utf8")))) {
|
|
120
|
-
if (!
|
|
132
|
+
if (forceReload || !realEnvSnapshot.has(key) || loadedFromFiles.has(key)) {
|
|
121
133
|
process.env[key] = value;
|
|
134
|
+
loadedFromFiles.add(key);
|
|
135
|
+
}
|
|
122
136
|
}
|
|
123
137
|
}
|
|
124
138
|
}
|
|
@@ -153,10 +167,11 @@ function unquoteEnvValue(value) {
|
|
|
153
167
|
function readStoredAuthSync() {
|
|
154
168
|
try {
|
|
155
169
|
const value = JSON.parse(readFileSync(USER_CONFIG_PATH, "utf8"));
|
|
156
|
-
if (typeof value.
|
|
170
|
+
if (typeof value.baseUrl !== "string" || typeof value.token !== "string")
|
|
157
171
|
return null;
|
|
158
172
|
return {
|
|
159
|
-
|
|
173
|
+
baseUrl: stripTrailingSlash(value.baseUrl),
|
|
174
|
+
...typeof value.dashboardUrl === "string" ? { dashboardUrl: stripTrailingSlash(value.dashboardUrl) } : {},
|
|
160
175
|
token: value.token
|
|
161
176
|
};
|
|
162
177
|
} catch {
|
|
@@ -185,7 +200,7 @@ class BroodsClient {
|
|
|
185
200
|
const name = refOrName;
|
|
186
201
|
const id = agentId ?? "";
|
|
187
202
|
if (!id)
|
|
188
|
-
throw new Error(`Agent ${name} is missing a generated id. Run broods deploy first.`);
|
|
203
|
+
throw new Error(`Agent ${name} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);
|
|
189
204
|
return {
|
|
190
205
|
id,
|
|
191
206
|
run: (input) => this.run({ ...input, agentName: name, agentId: id }),
|
|
@@ -195,7 +210,7 @@ class BroodsClient {
|
|
|
195
210
|
}
|
|
196
211
|
const ref = refOrName;
|
|
197
212
|
if (!ref.id)
|
|
198
|
-
throw new Error(`Agent ${ref.name} is missing a generated id. Run broods deploy first.`);
|
|
213
|
+
throw new Error(`Agent ${ref.name} is missing a generated id. Run broods dev --once or broods deploy to sync it first.`);
|
|
199
214
|
return {
|
|
200
215
|
id: ref.id,
|
|
201
216
|
run: (input) => this.run(ref, input),
|
|
@@ -246,7 +261,8 @@ class BroodsClient {
|
|
|
246
261
|
agentName: refOrInput.name
|
|
247
262
|
} : refOrInput;
|
|
248
263
|
const body = directRunBody(input, "async");
|
|
249
|
-
const
|
|
264
|
+
const targetUrl = maybeInput ? this.scopedUrl(refOrInput, "/async") : `${this.baseUrl}/async`;
|
|
265
|
+
const response = await this.fetchJson(targetUrl, {
|
|
250
266
|
method: "POST",
|
|
251
267
|
headers: this.apiKeyHeaders(),
|
|
252
268
|
body: JSON.stringify(body)
|
|
@@ -289,7 +305,7 @@ class BroodsClient {
|
|
|
289
305
|
throw new Error("Polling timeout");
|
|
290
306
|
}
|
|
291
307
|
async createCron(input) {
|
|
292
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
308
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons`, {
|
|
293
309
|
method: "POST",
|
|
294
310
|
headers: this.apiKeyHeaders(),
|
|
295
311
|
body: JSON.stringify(resolveCronInput(input))
|
|
@@ -299,7 +315,7 @@ class BroodsClient {
|
|
|
299
315
|
return await response.json();
|
|
300
316
|
}
|
|
301
317
|
async listCrons() {
|
|
302
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
318
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons`, {
|
|
303
319
|
method: "GET",
|
|
304
320
|
headers: this.apiKeyHeaders()
|
|
305
321
|
});
|
|
@@ -309,7 +325,7 @@ class BroodsClient {
|
|
|
309
325
|
return payload.crons;
|
|
310
326
|
}
|
|
311
327
|
async getCron(cronId) {
|
|
312
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
328
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(cronId)}`, {
|
|
313
329
|
method: "GET",
|
|
314
330
|
headers: this.apiKeyHeaders()
|
|
315
331
|
});
|
|
@@ -324,7 +340,7 @@ class BroodsClient {
|
|
|
324
340
|
if (options.limit !== undefined)
|
|
325
341
|
params.set("limit", String(options.limit));
|
|
326
342
|
const suffix = params.size > 0 ? `?${params}` : "";
|
|
327
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
343
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(cronId)}/runs${suffix}`, {
|
|
328
344
|
method: "GET",
|
|
329
345
|
headers: this.apiKeyHeaders()
|
|
330
346
|
});
|
|
@@ -334,7 +350,7 @@ class BroodsClient {
|
|
|
334
350
|
return payload.runs;
|
|
335
351
|
}
|
|
336
352
|
async updateCron(cronId, patch) {
|
|
337
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
353
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(cronId)}`, {
|
|
338
354
|
method: "PATCH",
|
|
339
355
|
headers: this.apiKeyHeaders(),
|
|
340
356
|
body: JSON.stringify(patch)
|
|
@@ -344,7 +360,7 @@ class BroodsClient {
|
|
|
344
360
|
return await response.json();
|
|
345
361
|
}
|
|
346
362
|
async deleteCron(cronId) {
|
|
347
|
-
const response = await this.fetchJson(`${this.baseUrl}/
|
|
363
|
+
const response = await this.fetchJson(`${this.baseUrl}/v1/crons/${encodeURIComponent(cronId)}`, {
|
|
348
364
|
method: "DELETE",
|
|
349
365
|
headers: this.apiKeyHeaders()
|
|
350
366
|
});
|
|
@@ -355,11 +371,11 @@ class BroodsClient {
|
|
|
355
371
|
const payload = await response.json();
|
|
356
372
|
return payload.deleted;
|
|
357
373
|
}
|
|
358
|
-
scopedUrl(ref) {
|
|
374
|
+
scopedUrl(ref, suffix = "") {
|
|
359
375
|
if (ref.projectSlug && ref.environmentSlug && ref.endpointId) {
|
|
360
|
-
return `${this.baseUrl}/v1/${encodeURIComponent(ref.projectSlug)}` + `/agents/${encodeURIComponent(ref.environmentSlug)}/${encodeURIComponent(ref.endpointId)}`;
|
|
376
|
+
return `${this.baseUrl}/v1/${encodeURIComponent(ref.projectSlug)}` + `/agents/${encodeURIComponent(ref.environmentSlug)}/${encodeURIComponent(ref.endpointId)}${suffix}`;
|
|
361
377
|
}
|
|
362
|
-
return this.baseUrl
|
|
378
|
+
return `${this.baseUrl}${suffix}`;
|
|
363
379
|
}
|
|
364
380
|
async openStream(body, targetUrl) {
|
|
365
381
|
if (this.apiKey) {
|
|
@@ -515,7 +531,6 @@ function formatStreamError(error) {
|
|
|
515
531
|
var DEFAULT_CONNECT_TIMEOUT_MS = 2000;
|
|
516
532
|
var WS_CONNECTING = 0;
|
|
517
533
|
var WS_OPEN = 1;
|
|
518
|
-
var LAMBDA_FUNCTION_URL_HOST_RE = /\.lambda-url\.[a-z0-9-]+\.on\.aws$/i;
|
|
519
534
|
|
|
520
535
|
class BroodsWebSocketClient {
|
|
521
536
|
baseUrl;
|
|
@@ -524,7 +539,7 @@ class BroodsWebSocketClient {
|
|
|
524
539
|
connectTimeoutMs;
|
|
525
540
|
constructor(options = {}) {
|
|
526
541
|
loadBroodsRuntimeConfig();
|
|
527
|
-
this.baseUrl = normalizeWebSocketServiceUrl(options.baseUrl ||
|
|
542
|
+
this.baseUrl = normalizeWebSocketServiceUrl(options.baseUrl || options.host || process.env.BROODS_BASE_URL || process.env.BROODS_HOST || DEFAULT_CORE_BASE_URL);
|
|
528
543
|
this.apiKey = options.apiKey || process.env.BROODS_API_KEY || "";
|
|
529
544
|
if (!this.apiKey)
|
|
530
545
|
throw new Error("BroodsWebSocketClient requires apiKey or BROODS_API_KEY.");
|
|
@@ -706,10 +721,6 @@ function normalizeWebSocketServiceUrl(value) {
|
|
|
706
721
|
return normalizeHttpServiceUrl(trimmed);
|
|
707
722
|
}
|
|
708
723
|
function webSocketAccessError(baseUrl) {
|
|
709
|
-
const host = new URL(baseUrl).hostname;
|
|
710
|
-
if (LAMBDA_FUNCTION_URL_HOST_RE.test(host)) {
|
|
711
|
-
return new Error(`Cannot access the WebSocket service at ${baseUrl}. AWS Lambda Function URLs do not support WebSocket upgrades; ` + "set BROODS_WEBSOCKET_URL or BROODS_HOST to the deployed WebSocket gateway URL instead.");
|
|
712
|
-
}
|
|
713
724
|
return new Error(`Cannot access the WebSocket service at ${baseUrl}.`);
|
|
714
725
|
}
|
|
715
726
|
function parseServerMessage(data) {
|
|
@@ -754,11 +765,16 @@ function defineResource(kind, input) {
|
|
|
754
765
|
};
|
|
755
766
|
}
|
|
756
767
|
function defineChannel(type, config) {
|
|
768
|
+
const { workspaceScope, ...channelConfig } = config;
|
|
757
769
|
return {
|
|
758
770
|
[CHANNEL_MARKER]: true,
|
|
759
771
|
kind: "channel",
|
|
760
772
|
type,
|
|
761
|
-
|
|
773
|
+
...workspaceScope ? { workspaceScope } : {},
|
|
774
|
+
config: {
|
|
775
|
+
...channelConfig,
|
|
776
|
+
...workspaceScope ? { workspaceScope } : {}
|
|
777
|
+
}
|
|
762
778
|
};
|
|
763
779
|
}
|
|
764
780
|
function defineTelegramChannel(config) {
|
|
@@ -774,11 +790,7 @@ function defineDiscordChannel(config) {
|
|
|
774
790
|
return defineChannel("discord", config);
|
|
775
791
|
}
|
|
776
792
|
function definePancakeChannel(config) {
|
|
777
|
-
|
|
778
|
-
return defineChannel("pancake", {
|
|
779
|
-
...channelConfig,
|
|
780
|
-
...ignoreTagIds === undefined ? {} : { options: { ignoreTagIds } }
|
|
781
|
-
});
|
|
793
|
+
return defineChannel("pancake", config);
|
|
782
794
|
}
|
|
783
795
|
function defineZaloChannel(config) {
|
|
784
796
|
return defineChannel("zalo", config);
|
|
@@ -801,6 +813,9 @@ function defineSkill(input) {
|
|
|
801
813
|
function defineTool(input) {
|
|
802
814
|
return defineResource("tool", input);
|
|
803
815
|
}
|
|
816
|
+
function definePolicy(input) {
|
|
817
|
+
return defineResource("policy", input);
|
|
818
|
+
}
|
|
804
819
|
function defineCron(input) {
|
|
805
820
|
return defineResource("cron", input);
|
|
806
821
|
}
|
|
@@ -830,6 +845,7 @@ export {
|
|
|
830
845
|
defineSlackChannel,
|
|
831
846
|
defineSkill,
|
|
832
847
|
defineSandbox,
|
|
848
|
+
definePolicy,
|
|
833
849
|
definePancakeChannel,
|
|
834
850
|
defineGitHubChannel,
|
|
835
851
|
defineDiscordChannel,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "broods",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "CLI + TypeScript SDK for the broods agent platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,12 +42,20 @@
|
|
|
42
42
|
"pack:check": "bun run build && npm pack --dry-run",
|
|
43
43
|
"test": "bun test"
|
|
44
44
|
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22"
|
|
47
|
+
},
|
|
45
48
|
"dependencies": {
|
|
46
|
-
"
|
|
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"
|
|
47
54
|
},
|
|
48
55
|
"devDependencies": {
|
|
49
56
|
"@types/bun": "^1.3.14",
|
|
50
57
|
"rollup": "^4.53.3",
|
|
58
|
+
"typescript": "^6.0.3",
|
|
51
59
|
"rollup-plugin-dts": "^6.3.0"
|
|
52
60
|
}
|
|
53
61
|
}
|