@brainbase-labs/cli 0.28.0 → 0.29.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 +7 -0
- package/dist/index.js +2217 -526
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -35141,7 +35141,7 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
35141
35141
|
});
|
|
35142
35142
|
|
|
35143
35143
|
// src/index.ts
|
|
35144
|
-
var
|
|
35144
|
+
var import_picocolors61 = __toESM(require_picocolors(), 1);
|
|
35145
35145
|
import process14 from "node:process";
|
|
35146
35146
|
import fs87 from "node:fs";
|
|
35147
35147
|
|
|
@@ -35949,6 +35949,16 @@ function me() {
|
|
|
35949
35949
|
return new RegExp(r2, "g");
|
|
35950
35950
|
}
|
|
35951
35951
|
|
|
35952
|
+
// src/ui/fail.ts
|
|
35953
|
+
function fail(message) {
|
|
35954
|
+
f2.error(message);
|
|
35955
|
+
process.exitCode = 1;
|
|
35956
|
+
}
|
|
35957
|
+
function failWarn(message) {
|
|
35958
|
+
f2.warn(message);
|
|
35959
|
+
process.exitCode = 1;
|
|
35960
|
+
}
|
|
35961
|
+
|
|
35952
35962
|
// src/cli/pack.ts
|
|
35953
35963
|
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
35954
35964
|
|
|
@@ -36008,7 +36018,7 @@ function padStart(s, n) {
|
|
|
36008
36018
|
// package.json
|
|
36009
36019
|
var package_default = {
|
|
36010
36020
|
name: "@brainbase-labs/cli",
|
|
36011
|
-
version: "0.
|
|
36021
|
+
version: "0.29.0",
|
|
36012
36022
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36023
|
type: "module",
|
|
36014
36024
|
bin: {
|
|
@@ -36024,7 +36034,7 @@ var package_default = {
|
|
|
36024
36034
|
build: "bun run scripts/build.ts",
|
|
36025
36035
|
test: "bun test",
|
|
36026
36036
|
typecheck: "tsc --noEmit",
|
|
36027
|
-
verify: "bun run typecheck && bun test && bun run build",
|
|
36037
|
+
verify: "bun run scripts/check-bun-version.ts && bun run typecheck && bun test && bun run build",
|
|
36028
36038
|
prepublishOnly: "bun run verify"
|
|
36029
36039
|
},
|
|
36030
36040
|
repository: {
|
|
@@ -36051,6 +36061,7 @@ var package_default = {
|
|
|
36051
36061
|
dependencies: {
|
|
36052
36062
|
"@modelcontextprotocol/sdk": "^1.18.2",
|
|
36053
36063
|
"@clack/prompts": "^0.7.0",
|
|
36064
|
+
eventsource: "^3.0.2",
|
|
36054
36065
|
ink: "^5.1.0",
|
|
36055
36066
|
picocolors: "^1.0.0",
|
|
36056
36067
|
react: "^18.3.1",
|
|
@@ -36156,6 +36167,13 @@ function requireInteractive(flagHint) {
|
|
|
36156
36167
|
function autoProceed(yes) {
|
|
36157
36168
|
return Boolean(yes) || !isInteractive();
|
|
36158
36169
|
}
|
|
36170
|
+
function autoProceedDestructive(yes, opts) {
|
|
36171
|
+
if (yes)
|
|
36172
|
+
return true;
|
|
36173
|
+
if (isInteractive())
|
|
36174
|
+
return false;
|
|
36175
|
+
throw new NonInteractiveError(`${opts.action} is destructive and needs confirmation, but there is no interactive terminal to ask. ` + (opts.flagHint ?? "Pass --yes to confirm."));
|
|
36176
|
+
}
|
|
36159
36177
|
|
|
36160
36178
|
// src/ui/symbols.ts
|
|
36161
36179
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
@@ -53628,7 +53646,7 @@ async function runPack(cwd2) {
|
|
|
53628
53646
|
packSpinner.stop(`Packed ${packed.length} component${packed.length === 1 ? "" : "s"}.`);
|
|
53629
53647
|
const dest = registry.templateDir(name, version);
|
|
53630
53648
|
if (exists(dest)) {
|
|
53631
|
-
|
|
53649
|
+
fail(`A template at ${name}@${version} already exists. Bump the version.`);
|
|
53632
53650
|
$e("Aborted.");
|
|
53633
53651
|
return;
|
|
53634
53652
|
}
|
|
@@ -54017,6 +54035,8 @@ var DEFINITELY_UNSENT_NETWORK_CODES = new Set([
|
|
|
54017
54035
|
"FailedToOpenSocket",
|
|
54018
54036
|
"UND_ERR_CONNECT_TIMEOUT"
|
|
54019
54037
|
]);
|
|
54038
|
+
var LEGACY_DEFAULT_PAGE = 200;
|
|
54039
|
+
var LEGACY_MAX_PAGE = 500;
|
|
54020
54040
|
|
|
54021
54041
|
class ApiError extends Error {
|
|
54022
54042
|
status;
|
|
@@ -54354,6 +54374,127 @@ async function masRequest(pathname, init) {
|
|
|
54354
54374
|
return body;
|
|
54355
54375
|
}
|
|
54356
54376
|
}
|
|
54377
|
+
async function masReadRequest(pathname, callerSignal) {
|
|
54378
|
+
const credential = await resolveMasCredential();
|
|
54379
|
+
let currentSession = credential.session;
|
|
54380
|
+
let refreshSessionAvailable = credential.source === "session";
|
|
54381
|
+
let res;
|
|
54382
|
+
let text2;
|
|
54383
|
+
for (let attempt2 = 0;; attempt2 += 1) {
|
|
54384
|
+
if (callerSignal?.aborted)
|
|
54385
|
+
throw callerSignal.reason;
|
|
54386
|
+
try {
|
|
54387
|
+
res = await sendWithAuthRetry(refreshSessionAvailable ? currentSession : null, async (refreshed) => {
|
|
54388
|
+
if (refreshed) {
|
|
54389
|
+
currentSession = refreshed;
|
|
54390
|
+
refreshSessionAvailable = false;
|
|
54391
|
+
}
|
|
54392
|
+
return await sendRequest(`${masApiBase(currentSession)}${pathname}`, {
|
|
54393
|
+
method: "GET",
|
|
54394
|
+
signal: withRequestDeadline(callerSignal, MAS_REQUEST_TIMEOUT_MS)
|
|
54395
|
+
}, currentSession?.access_token ?? credential.bearer);
|
|
54396
|
+
});
|
|
54397
|
+
try {
|
|
54398
|
+
text2 = await res.text();
|
|
54399
|
+
} catch (error) {
|
|
54400
|
+
throw new NetworkApiError(`Network error while reading response: ${error.message}`, false);
|
|
54401
|
+
}
|
|
54402
|
+
break;
|
|
54403
|
+
} catch (error) {
|
|
54404
|
+
if (callerSignal?.aborted || !(error instanceof NetworkApiError) || attempt2 >= GET_NETWORK_RETRY_DELAYS_MS.length) {
|
|
54405
|
+
throw error;
|
|
54406
|
+
}
|
|
54407
|
+
await new Promise((resolve) => setTimeout(resolve, GET_NETWORK_RETRY_DELAYS_MS[attempt2]));
|
|
54408
|
+
}
|
|
54409
|
+
}
|
|
54410
|
+
let body = text2;
|
|
54411
|
+
try {
|
|
54412
|
+
body = text2 ? JSON.parse(text2) : null;
|
|
54413
|
+
} catch {}
|
|
54414
|
+
if (!res.ok) {
|
|
54415
|
+
const message = masApiErrorMessage(body, res.status);
|
|
54416
|
+
throw new ApiError(res.status === 401 ? withRejectedSessionHint(message, credential.source, "managed-task") : message, res.status, body);
|
|
54417
|
+
}
|
|
54418
|
+
return body;
|
|
54419
|
+
}
|
|
54420
|
+
function withRequestDeadline(callerSignal, timeoutMs) {
|
|
54421
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
54422
|
+
if (!callerSignal)
|
|
54423
|
+
return deadline;
|
|
54424
|
+
if (callerSignal.aborted)
|
|
54425
|
+
return callerSignal;
|
|
54426
|
+
const combined = new AbortController;
|
|
54427
|
+
const abort = (reason) => combined.abort(reason);
|
|
54428
|
+
deadline.addEventListener("abort", () => abort(deadline.reason), { once: true });
|
|
54429
|
+
callerSignal.addEventListener("abort", () => abort(callerSignal.reason), {
|
|
54430
|
+
once: true
|
|
54431
|
+
});
|
|
54432
|
+
return combined.signal;
|
|
54433
|
+
}
|
|
54434
|
+
async function masResourceRequest(pathname, init = {}) {
|
|
54435
|
+
const credential = await resolveMasCredential();
|
|
54436
|
+
let currentSession = credential.session;
|
|
54437
|
+
const res = await sendWithAuthRetry(credential.source === "session" ? currentSession : null, async (refreshed) => {
|
|
54438
|
+
if (refreshed)
|
|
54439
|
+
currentSession = refreshed;
|
|
54440
|
+
return await sendRequest(`${masApiBase(currentSession)}${pathname}`, {
|
|
54441
|
+
...init,
|
|
54442
|
+
signal: withRequestDeadline(init.signal ?? undefined, MAS_REQUEST_TIMEOUT_MS)
|
|
54443
|
+
}, currentSession?.access_token ?? credential.bearer);
|
|
54444
|
+
});
|
|
54445
|
+
let text2;
|
|
54446
|
+
try {
|
|
54447
|
+
text2 = await res.text();
|
|
54448
|
+
} catch (error) {
|
|
54449
|
+
throw new NetworkApiError(`Network error while reading response: ${error.message}`, false);
|
|
54450
|
+
}
|
|
54451
|
+
let body = text2;
|
|
54452
|
+
try {
|
|
54453
|
+
body = text2 ? JSON.parse(text2) : null;
|
|
54454
|
+
} catch {}
|
|
54455
|
+
if (!res.ok) {
|
|
54456
|
+
const message = masApiErrorMessage(body, res.status);
|
|
54457
|
+
throw new ApiError(res.status === 401 ? withRejectedSessionHint(message, credential.source, "managed-task") : res.status === 404 && isUnroutedPath(body) ? `This control plane does not serve ${pathname} yet. Update the server, or use the web app.` : message, res.status, body);
|
|
54458
|
+
}
|
|
54459
|
+
return body;
|
|
54460
|
+
}
|
|
54461
|
+
|
|
54462
|
+
class StreamHostMovedError extends ApiError {
|
|
54463
|
+
}
|
|
54464
|
+
async function masStreamTarget(pathname) {
|
|
54465
|
+
const credential = await resolveMasCredential();
|
|
54466
|
+
const base2 = masApiBase(credential.session);
|
|
54467
|
+
return {
|
|
54468
|
+
url: `${base2}${pathname}`,
|
|
54469
|
+
resolveBearer: async () => {
|
|
54470
|
+
const fresh = await resolveMasCredential();
|
|
54471
|
+
const freshBase = masApiBase(fresh.session);
|
|
54472
|
+
if (freshBase !== base2) {
|
|
54473
|
+
throw new StreamHostMovedError(`The control plane moved from ${base2} to ${freshBase} while this stream was open, so the current credential was not sent. Re-run the command to follow against the new host.`);
|
|
54474
|
+
}
|
|
54475
|
+
return fresh.session?.access_token ?? fresh.bearer;
|
|
54476
|
+
}
|
|
54477
|
+
};
|
|
54478
|
+
}
|
|
54479
|
+
function masListQuery(params) {
|
|
54480
|
+
const search = new URLSearchParams;
|
|
54481
|
+
for (const [key2, value] of Object.entries(params)) {
|
|
54482
|
+
if (value !== undefined)
|
|
54483
|
+
search.set(key2, value);
|
|
54484
|
+
}
|
|
54485
|
+
const qs = search.toString();
|
|
54486
|
+
return qs ? `?${qs}` : "";
|
|
54487
|
+
}
|
|
54488
|
+
function masItems(body, what) {
|
|
54489
|
+
if (Array.isArray(body))
|
|
54490
|
+
return body;
|
|
54491
|
+
if (body && typeof body === "object") {
|
|
54492
|
+
const items = body.items;
|
|
54493
|
+
if (Array.isArray(items))
|
|
54494
|
+
return items;
|
|
54495
|
+
}
|
|
54496
|
+
throw new ApiError(`MAS returned an unreadable ${what} response.`, undefined, body);
|
|
54497
|
+
}
|
|
54357
54498
|
var masApi = {
|
|
54358
54499
|
async createTask(input, options) {
|
|
54359
54500
|
const body = await masRequest("/tasks", {
|
|
@@ -54362,6 +54503,49 @@ var masApi = {
|
|
|
54362
54503
|
body: JSON.stringify(input)
|
|
54363
54504
|
});
|
|
54364
54505
|
return parseMasTaskCreateResponse(body);
|
|
54506
|
+
},
|
|
54507
|
+
async listTasks(options = {}) {
|
|
54508
|
+
const params = new URLSearchParams;
|
|
54509
|
+
if (options.agentId)
|
|
54510
|
+
params.set("agent_id", options.agentId);
|
|
54511
|
+
if (options.limit !== undefined)
|
|
54512
|
+
params.set("limit", String(options.limit));
|
|
54513
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
54514
|
+
return masItems(await masReadRequest(`/tasks${qs}`), "task list");
|
|
54515
|
+
},
|
|
54516
|
+
async getTask(taskId, options = {}) {
|
|
54517
|
+
const body = await masReadRequest(`/tasks/${encodeURIComponent(taskId)}`, options.signal);
|
|
54518
|
+
if (!body || typeof body !== "object" || typeof body.id !== "string" || typeof body.status !== "string") {
|
|
54519
|
+
throw new ApiError("MAS returned an unreadable task response.", undefined, body);
|
|
54520
|
+
}
|
|
54521
|
+
return body;
|
|
54522
|
+
},
|
|
54523
|
+
async listTaskEvents(taskId, options = {}) {
|
|
54524
|
+
const params = new URLSearchParams({ order_by_received: "true" });
|
|
54525
|
+
if (options.limit !== undefined)
|
|
54526
|
+
params.set("limit", String(options.limit));
|
|
54527
|
+
if (options.after) {
|
|
54528
|
+
params.set("after_received_at", options.after.receivedAt);
|
|
54529
|
+
params.set("after_id", options.after.id);
|
|
54530
|
+
}
|
|
54531
|
+
if (options.desc !== undefined)
|
|
54532
|
+
params.set("desc", String(options.desc));
|
|
54533
|
+
const body = await masReadRequest(`/tasks/${encodeURIComponent(taskId)}/events?${params.toString()}`);
|
|
54534
|
+
return masItems(body, "task events");
|
|
54535
|
+
},
|
|
54536
|
+
async listMachines(options = {}) {
|
|
54537
|
+
const body = await masResourceRequest(`/machines${masListQuery({
|
|
54538
|
+
kind: options.kind,
|
|
54539
|
+
include_dead: options.includeDead === undefined ? undefined : String(options.includeDead),
|
|
54540
|
+
limit: options.limit === undefined ? undefined : String(options.limit)
|
|
54541
|
+
})}`);
|
|
54542
|
+
if (!body || !Array.isArray(body.items)) {
|
|
54543
|
+
throw new ApiError("The control plane returned an unreadable machine list", undefined, body);
|
|
54544
|
+
}
|
|
54545
|
+
return body.items;
|
|
54546
|
+
},
|
|
54547
|
+
deleteMachine(machineId) {
|
|
54548
|
+
return masResourceRequest(`/machines/${encodeURIComponent(machineId)}`, { method: "DELETE" });
|
|
54365
54549
|
}
|
|
54366
54550
|
};
|
|
54367
54551
|
function isUnroutedPath(body) {
|
|
@@ -54391,20 +54575,48 @@ var api = {
|
|
|
54391
54575
|
});
|
|
54392
54576
|
},
|
|
54393
54577
|
async listAgents(orgId, teamId) {
|
|
54394
|
-
const
|
|
54395
|
-
|
|
54578
|
+
const base2 = `/orgs/${encodeURIComponent(orgId)}/teams/${encodeURIComponent(teamId)}/agents`;
|
|
54579
|
+
const fetchPage = async (limit) => {
|
|
54580
|
+
const path58 = limit === undefined ? base2 : `${base2}?limit=${limit}`;
|
|
54581
|
+
let body;
|
|
54582
|
+
try {
|
|
54583
|
+
body = await request(path58);
|
|
54584
|
+
} catch (err) {
|
|
54585
|
+
if (err instanceof ApiError && err.status === 404) {
|
|
54586
|
+
throw new ApiError("This control plane does not support listing agents yet. Update the server, or use the web app to find the agent id.", 404, err.body);
|
|
54587
|
+
}
|
|
54588
|
+
throw err;
|
|
54589
|
+
}
|
|
54590
|
+
if (!Array.isArray(body)) {
|
|
54591
|
+
throw new ApiError(`Unexpected response listing agents: expected an array from ${path58}.`, undefined, body);
|
|
54592
|
+
}
|
|
54593
|
+
return body;
|
|
54594
|
+
};
|
|
54595
|
+
const agents = await fetchPage();
|
|
54596
|
+
if (agents.length !== LEGACY_DEFAULT_PAGE)
|
|
54597
|
+
return { agents, complete: true };
|
|
54598
|
+
let retried;
|
|
54396
54599
|
try {
|
|
54397
|
-
|
|
54600
|
+
retried = await fetchPage(LEGACY_MAX_PAGE);
|
|
54398
54601
|
} catch (err) {
|
|
54399
|
-
if (err instanceof ApiError && err.status ===
|
|
54400
|
-
throw
|
|
54602
|
+
if (err instanceof ApiError && (err.status === 401 || err.status === 403)) {
|
|
54603
|
+
throw err;
|
|
54401
54604
|
}
|
|
54402
|
-
|
|
54403
|
-
|
|
54404
|
-
|
|
54405
|
-
|
|
54605
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
54606
|
+
return {
|
|
54607
|
+
agents,
|
|
54608
|
+
complete: false,
|
|
54609
|
+
warning: `Warning: showing ${agents.length} agents, and could not confirm that is all of them — ` + `the follow-up request failed (${detail}). ` + "Re-run to check; if it keeps failing, the control plane may need updating."
|
|
54610
|
+
};
|
|
54406
54611
|
}
|
|
54407
|
-
|
|
54612
|
+
const best = retried.length > agents.length ? retried : agents;
|
|
54613
|
+
if (best.length < LEGACY_MAX_PAGE)
|
|
54614
|
+
return { agents: best, complete: true };
|
|
54615
|
+
return {
|
|
54616
|
+
agents: best,
|
|
54617
|
+
complete: false,
|
|
54618
|
+
warning: `Warning: this control plane caps agent listings at ${best.length} and offers no way ` + "to read past that, so this list may be incomplete. Update the control plane to see every agent."
|
|
54619
|
+
};
|
|
54408
54620
|
},
|
|
54409
54621
|
createAgent(input) {
|
|
54410
54622
|
if (usesLegacyControlPlane() && (input.machine_kind !== undefined || input.default_model !== undefined)) {
|
|
@@ -58918,7 +59130,7 @@ async function runOnboard(cwd2, args) {
|
|
|
58918
59130
|
try {
|
|
58919
59131
|
templateRef = await resolveWithRemoteFallback(registry, name, version);
|
|
58920
59132
|
} catch (err) {
|
|
58921
|
-
|
|
59133
|
+
fail(err.message);
|
|
58922
59134
|
$e("Aborted.");
|
|
58923
59135
|
return;
|
|
58924
59136
|
}
|
|
@@ -59380,7 +59592,10 @@ async function runRemove(cwd2, args) {
|
|
|
59380
59592
|
text: c2.slug
|
|
59381
59593
|
}))
|
|
59382
59594
|
});
|
|
59383
|
-
if (!
|
|
59595
|
+
if (!autoProceedDestructive(args.yes, {
|
|
59596
|
+
action: `Uninstalling ${inst.name}@${inst.version} from ${inst.harness} (${inst.scope})`,
|
|
59597
|
+
flagHint: "Pass --yes to uninstall without a prompt."
|
|
59598
|
+
})) {
|
|
59384
59599
|
const ans = await se({ message: "Proceed?", initialValue: true });
|
|
59385
59600
|
if (!ensureNotCancelled(ans))
|
|
59386
59601
|
continue;
|
|
@@ -59842,11 +60057,11 @@ async function publishSkillForTemplate(opts) {
|
|
|
59842
60057
|
try {
|
|
59843
60058
|
probe = await skillsApi.canPublish(creator, pkgSlug);
|
|
59844
60059
|
} catch (err) {
|
|
59845
|
-
|
|
60060
|
+
fail(err.message);
|
|
59846
60061
|
return false;
|
|
59847
60062
|
}
|
|
59848
60063
|
if (probe.exists && !probe.can_write) {
|
|
59849
|
-
|
|
60064
|
+
fail(`You can't publish to ${import_picocolors11.default.bold(creator + "/" + pkgSlug)}.`);
|
|
59850
60065
|
return false;
|
|
59851
60066
|
}
|
|
59852
60067
|
if (!probe.exists) {
|
|
@@ -59862,7 +60077,7 @@ async function publishSkillForTemplate(opts) {
|
|
|
59862
60077
|
});
|
|
59863
60078
|
} catch (err) {
|
|
59864
60079
|
if (!(err instanceof ApiError && err.status === 409)) {
|
|
59865
|
-
|
|
60080
|
+
fail(err.message);
|
|
59866
60081
|
return false;
|
|
59867
60082
|
}
|
|
59868
60083
|
}
|
|
@@ -59895,7 +60110,7 @@ async function publishSkillForTemplate(opts) {
|
|
|
59895
60110
|
sp.stop(`Published ${creator}/${pkgSlug}@${version}.`);
|
|
59896
60111
|
} catch (err) {
|
|
59897
60112
|
sp.stop("Skill publish failed.");
|
|
59898
|
-
|
|
60113
|
+
fail(err.message);
|
|
59899
60114
|
return false;
|
|
59900
60115
|
}
|
|
59901
60116
|
} finally {
|
|
@@ -59916,7 +60131,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
59916
60131
|
const registry = new LocalRegistry;
|
|
59917
60132
|
const localList = await registry.list();
|
|
59918
60133
|
if (localList.length === 0) {
|
|
59919
|
-
|
|
60134
|
+
fail("No templates in your local registry. Run `brainbase template pack` first.");
|
|
59920
60135
|
return;
|
|
59921
60136
|
}
|
|
59922
60137
|
let name;
|
|
@@ -59926,7 +60141,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
59926
60141
|
name = parsed.name;
|
|
59927
60142
|
const v3 = parsed.version ?? await registry.latest(name);
|
|
59928
60143
|
if (!v3) {
|
|
59929
|
-
|
|
60144
|
+
fail(`No versions of ${name} in your local registry.`);
|
|
59930
60145
|
return;
|
|
59931
60146
|
}
|
|
59932
60147
|
version = v3;
|
|
@@ -59965,7 +60180,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
59965
60180
|
`), import_picocolors11.default.yellow("Findings"));
|
|
59966
60181
|
}
|
|
59967
60182
|
if (report.hasBlocker) {
|
|
59968
|
-
|
|
60183
|
+
fail("Blocking issues found. Fix them and re-pack before publishing.");
|
|
59969
60184
|
return;
|
|
59970
60185
|
}
|
|
59971
60186
|
if (report.findings.some((f4) => f4.severity === "warn") && !autoProceed(args.yes)) {
|
|
@@ -59980,7 +60195,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
59980
60195
|
}
|
|
59981
60196
|
const status = authStatus();
|
|
59982
60197
|
if (!status.ok || !status.session) {
|
|
59983
|
-
|
|
60198
|
+
fail("Not logged in. Run `brainbase login` first.");
|
|
59984
60199
|
return;
|
|
59985
60200
|
}
|
|
59986
60201
|
const me3 = status.session;
|
|
@@ -60024,6 +60239,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
60024
60239
|
}
|
|
60025
60240
|
const skillEntries = ref.manifest.components.filter((c2) => c2.type === "skill");
|
|
60026
60241
|
let manifestMutated = false;
|
|
60242
|
+
const inlinedAfterFailure = [];
|
|
60027
60243
|
for (const entry of skillEntries) {
|
|
60028
60244
|
const src = entry.source ?? { type: "inline" };
|
|
60029
60245
|
if (src.type === "github" || src.type === "git" || src.type === "brainbase") {
|
|
@@ -60051,6 +60267,8 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
60051
60267
|
});
|
|
60052
60268
|
if (ok)
|
|
60053
60269
|
manifestMutated = true;
|
|
60270
|
+
else
|
|
60271
|
+
inlinedAfterFailure.push(entry.slug);
|
|
60054
60272
|
}
|
|
60055
60273
|
if (manifestMutated) {
|
|
60056
60274
|
fs57.writeFileSync(path65.join(ref.rootDir, "brainbase.json"), JSON.stringify(ref.manifest, null, 2));
|
|
@@ -60064,7 +60282,7 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
60064
60282
|
await pack({ rootDir: ref.rootDir, outFile: tarPath });
|
|
60065
60283
|
} catch (err) {
|
|
60066
60284
|
buildSpinner.stop("Bundle failed.");
|
|
60067
|
-
|
|
60285
|
+
fail(err.message);
|
|
60068
60286
|
return;
|
|
60069
60287
|
}
|
|
60070
60288
|
const sha = await sha256OfFile(tarPath);
|
|
@@ -60141,15 +60359,25 @@ async function runTemplatePublish(_cwd, args) {
|
|
|
60141
60359
|
fs57.rmSync(tmpDir, { recursive: true, force: true });
|
|
60142
60360
|
} catch {}
|
|
60143
60361
|
}
|
|
60144
|
-
|
|
60362
|
+
const partial2 = inlinedAfterFailure.length > 0;
|
|
60363
|
+
if (partial2) {
|
|
60364
|
+
const plural = inlinedAfterFailure.length === 1 ? "" : "s";
|
|
60365
|
+
f2.warn(`${import_picocolors11.default.bold(name)}@${version} published, but ${inlinedAfterFailure.length} skill${plural} never reached the registry and shipped inline instead: ${inlinedAfterFailure.map((s3) => import_picocolors11.default.bold(s3)).join(", ")}. Re-run ${import_picocolors11.default.cyan("brainbase skill publish")} for ${inlinedAfterFailure.length === 1 ? "it" : "them"}, then publish the template again to swap the inline bytes for a reference.`);
|
|
60366
|
+
$e(`${import_picocolors11.default.bold(name)}@${version} published with ${inlinedAfterFailure.length} skill failure${plural}.`);
|
|
60367
|
+
} else {
|
|
60368
|
+
$e(`${import_picocolors11.default.bold(name)}@${version} published.`);
|
|
60369
|
+
}
|
|
60145
60370
|
await showResultCard({
|
|
60146
|
-
title: "PUBLISHED",
|
|
60147
|
-
tone: "ok",
|
|
60371
|
+
title: partial2 ? "PUBLISHED (PARTIAL)" : "PUBLISHED",
|
|
60372
|
+
tone: partial2 ? "warn" : "ok",
|
|
60148
60373
|
subtitle: `${name}@${version}`,
|
|
60149
60374
|
meta: [
|
|
60150
60375
|
["id", result2.id],
|
|
60151
60376
|
["sha256", sha],
|
|
60152
60377
|
["visibility", visibility],
|
|
60378
|
+
...partial2 ? [
|
|
60379
|
+
["skills inlined after failure", inlinedAfterFailure.join(", ")]
|
|
60380
|
+
] : [],
|
|
60153
60381
|
...visibility === "public" ? [["note", "Quarantined for review on first public publish."]] : []
|
|
60154
60382
|
],
|
|
60155
60383
|
hint: `brainbase template info ${name}`
|
|
@@ -60440,7 +60668,7 @@ async function runTemplateInfo(args) {
|
|
|
60440
60668
|
const { name, version } = parseRef2(args.ref);
|
|
60441
60669
|
const [creator, slug] = name.split("/");
|
|
60442
60670
|
if (!creator || !slug) {
|
|
60443
|
-
|
|
60671
|
+
fail("Expected creator/slug.");
|
|
60444
60672
|
return;
|
|
60445
60673
|
}
|
|
60446
60674
|
const spinner = de();
|
|
@@ -60748,17 +60976,17 @@ async function runSkillAdd(cwd2, args) {
|
|
|
60748
60976
|
ensureSkillResolversRegistered();
|
|
60749
60977
|
const source = parseSkillSource(args.source);
|
|
60750
60978
|
if (source.type === "local" || source.type === "inline") {
|
|
60751
|
-
|
|
60979
|
+
fail(`${describeSource(source)} sources are not fetchable. Use a github / git / brainbase source.`);
|
|
60752
60980
|
return;
|
|
60753
60981
|
}
|
|
60754
60982
|
const resolver = getSkillResolver(source.type);
|
|
60755
60983
|
if (!resolver) {
|
|
60756
|
-
|
|
60984
|
+
fail(`No resolver registered for ${source.type}.`);
|
|
60757
60985
|
return;
|
|
60758
60986
|
}
|
|
60759
60987
|
const slug = args.as ?? defaultSkillSlug(source);
|
|
60760
60988
|
if (!/^[a-zA-Z0-9_-]+$/.test(slug)) {
|
|
60761
|
-
|
|
60989
|
+
fail(`Invalid slug ${import_picocolors13.default.bold(slug)}; pass --as <slug>.`);
|
|
60762
60990
|
return;
|
|
60763
60991
|
}
|
|
60764
60992
|
let adapterId = args.harness;
|
|
@@ -60793,7 +61021,10 @@ async function runSkillAdd(cwd2, args) {
|
|
|
60793
61021
|
const skillsRoot = skillsRootFor(adapterId, cwd2, scope);
|
|
60794
61022
|
const dest = path68.join(skillsRoot, slug);
|
|
60795
61023
|
if (exists(dest)) {
|
|
60796
|
-
if (!
|
|
61024
|
+
if (!autoProceedDestructive(args.yes, {
|
|
61025
|
+
action: `Overwriting the existing skill at ${dest}`,
|
|
61026
|
+
flagHint: "Pass --yes to overwrite it without a prompt."
|
|
61027
|
+
})) {
|
|
60797
61028
|
const confirm = await se({
|
|
60798
61029
|
message: `${import_picocolors13.default.bold(slug)} already exists at ${dest}. Overwrite?`,
|
|
60799
61030
|
initialValue: false
|
|
@@ -60813,7 +61044,7 @@ async function runSkillAdd(cwd2, args) {
|
|
|
60813
61044
|
sp.stop("Fetched.");
|
|
60814
61045
|
} catch (err) {
|
|
60815
61046
|
sp.stop("Fetch failed.");
|
|
60816
|
-
|
|
61047
|
+
fail(err.message);
|
|
60817
61048
|
return;
|
|
60818
61049
|
}
|
|
60819
61050
|
writeSkillMarker(dest, source);
|
|
@@ -60908,7 +61139,10 @@ async function runSkillRemove(cwd2, args) {
|
|
|
60908
61139
|
});
|
|
60909
61140
|
target = candidates[Number(choice)];
|
|
60910
61141
|
}
|
|
60911
|
-
if (!
|
|
61142
|
+
if (!autoProceedDestructive(args.yes, {
|
|
61143
|
+
action: `Deleting ${target.dir}`,
|
|
61144
|
+
flagHint: "Pass --yes to delete it without a prompt."
|
|
61145
|
+
})) {
|
|
60912
61146
|
const ok = await se({
|
|
60913
61147
|
message: `Delete ${import_picocolors15.default.bold(target.dir)}?`,
|
|
60914
61148
|
initialValue: false
|
|
@@ -60937,11 +61171,11 @@ async function runSkillPublish(cwd2, args) {
|
|
|
60937
61171
|
banner("skill publish — send a skill to the registry");
|
|
60938
61172
|
const skillDir = path71.resolve(cwd2, args.dir ?? ".");
|
|
60939
61173
|
if (!exists(skillDir) || !fs63.statSync(skillDir).isDirectory()) {
|
|
60940
|
-
|
|
61174
|
+
fail(`Not a directory: ${import_picocolors16.default.bold(skillDir)}`);
|
|
60941
61175
|
return;
|
|
60942
61176
|
}
|
|
60943
61177
|
if (!exists(path71.join(skillDir, "SKILL.md"))) {
|
|
60944
|
-
|
|
61178
|
+
fail(`No ${import_picocolors16.default.bold("SKILL.md")} in ${import_picocolors16.default.bold(skillDir)}. Point at a folder that contains one, or create the file first.`);
|
|
60945
61179
|
return;
|
|
60946
61180
|
}
|
|
60947
61181
|
const folderSlug = path71.basename(skillDir).toLowerCase();
|
|
@@ -60955,12 +61189,12 @@ async function runSkillPublish(cwd2, args) {
|
|
|
60955
61189
|
}
|
|
60956
61190
|
let name = args.name ?? suggestedName;
|
|
60957
61191
|
if (name && !parseName(name)) {
|
|
60958
|
-
|
|
61192
|
+
fail(`Invalid --name "${name}". Use creator/slug.`);
|
|
60959
61193
|
return;
|
|
60960
61194
|
}
|
|
60961
61195
|
if (!name) {
|
|
60962
61196
|
if (args.yes) {
|
|
60963
|
-
|
|
61197
|
+
fail("Non-interactive publish (--yes) requires --name <creator/slug>.");
|
|
60964
61198
|
return;
|
|
60965
61199
|
}
|
|
60966
61200
|
const ans = await text({
|
|
@@ -60975,12 +61209,12 @@ async function runSkillPublish(cwd2, args) {
|
|
|
60975
61209
|
const { creator, slug: pkgSlug } = parseName(name);
|
|
60976
61210
|
let version = args.version;
|
|
60977
61211
|
if (version && !/^\d+\.\d+\.\d+$/.test(version)) {
|
|
60978
|
-
|
|
61212
|
+
fail(`Invalid --skill-version "${version}". Use MAJOR.MINOR.PATCH.`);
|
|
60979
61213
|
return;
|
|
60980
61214
|
}
|
|
60981
61215
|
if (!version) {
|
|
60982
61216
|
if (args.yes) {
|
|
60983
|
-
|
|
61217
|
+
fail("Non-interactive publish (--yes) requires --skill-version <MAJOR.MINOR.PATCH>.");
|
|
60984
61218
|
return;
|
|
60985
61219
|
}
|
|
60986
61220
|
const ans = await text({
|
|
@@ -60995,17 +61229,17 @@ async function runSkillPublish(cwd2, args) {
|
|
|
60995
61229
|
try {
|
|
60996
61230
|
probe = await skillsApi.canPublish(creator, pkgSlug);
|
|
60997
61231
|
} catch (err) {
|
|
60998
|
-
|
|
61232
|
+
fail(`can-publish probe failed: ${err.message}`);
|
|
60999
61233
|
return;
|
|
61000
61234
|
}
|
|
61001
61235
|
if (probe.exists && !probe.can_write) {
|
|
61002
|
-
|
|
61236
|
+
fail(`You can't publish to ${import_picocolors16.default.bold(creator + "/" + pkgSlug)}. Pick a name you own.`);
|
|
61003
61237
|
return;
|
|
61004
61238
|
}
|
|
61005
61239
|
if (!probe.exists) {
|
|
61006
61240
|
const status = authStatus();
|
|
61007
61241
|
if (!status.ok || !status.session) {
|
|
61008
|
-
|
|
61242
|
+
fail("Not logged in. Run `brainbase login` first.");
|
|
61009
61243
|
return;
|
|
61010
61244
|
}
|
|
61011
61245
|
let owner;
|
|
@@ -61052,7 +61286,7 @@ async function runSkillPublish(cwd2, args) {
|
|
|
61052
61286
|
});
|
|
61053
61287
|
} catch (err) {
|
|
61054
61288
|
if (err instanceof ApiError && err.status === 409) {} else {
|
|
61055
|
-
|
|
61289
|
+
fail(err.message);
|
|
61056
61290
|
return;
|
|
61057
61291
|
}
|
|
61058
61292
|
}
|
|
@@ -61062,7 +61296,7 @@ async function runSkillPublish(cwd2, args) {
|
|
|
61062
61296
|
try {
|
|
61063
61297
|
const files = collectSkillFiles(skillDir).filter((f4) => f4 !== SKILL_MARKER_FILE);
|
|
61064
61298
|
if (files.length === 0) {
|
|
61065
|
-
|
|
61299
|
+
fail("Skill folder is empty.");
|
|
61066
61300
|
return;
|
|
61067
61301
|
}
|
|
61068
61302
|
const buildSp = de();
|
|
@@ -61194,7 +61428,7 @@ async function runSkillUpdate(cwd2, args) {
|
|
|
61194
61428
|
candidates.push({ harness: r2.harness, scope: r2.scope, dir });
|
|
61195
61429
|
}
|
|
61196
61430
|
if (candidates.length === 0) {
|
|
61197
|
-
|
|
61431
|
+
failWarn(`No skill named ${import_picocolors17.default.bold(args.slug)} found.`);
|
|
61198
61432
|
return;
|
|
61199
61433
|
}
|
|
61200
61434
|
let target = candidates[0];
|
|
@@ -61211,16 +61445,16 @@ async function runSkillUpdate(cwd2, args) {
|
|
|
61211
61445
|
}
|
|
61212
61446
|
const marker = readSkillMarker(target.dir);
|
|
61213
61447
|
if (!marker) {
|
|
61214
|
-
|
|
61448
|
+
fail("No marker file. Skills without provenance can't be updated automatically.");
|
|
61215
61449
|
return;
|
|
61216
61450
|
}
|
|
61217
61451
|
if (marker.source.type === "inline" || marker.source.type === "local") {
|
|
61218
|
-
|
|
61452
|
+
fail(`Skill source is ${describeSource(marker.source)} — nothing to update from.`);
|
|
61219
61453
|
return;
|
|
61220
61454
|
}
|
|
61221
61455
|
const resolver = getSkillResolver(marker.source.type);
|
|
61222
61456
|
if (!resolver) {
|
|
61223
|
-
|
|
61457
|
+
fail(`No resolver for ${marker.source.type}.`);
|
|
61224
61458
|
return;
|
|
61225
61459
|
}
|
|
61226
61460
|
if (!autoProceed(args.yes)) {
|
|
@@ -61241,7 +61475,7 @@ async function runSkillUpdate(cwd2, args) {
|
|
|
61241
61475
|
sp.stop("Fetched.");
|
|
61242
61476
|
} catch (err) {
|
|
61243
61477
|
sp.stop("Fetch failed.");
|
|
61244
|
-
|
|
61478
|
+
fail(err.message);
|
|
61245
61479
|
return;
|
|
61246
61480
|
}
|
|
61247
61481
|
writeSkillMarker(target.dir, marker.source, marker.component);
|
|
@@ -62176,9 +62410,7 @@ var EvalSchema = exports_external.object({
|
|
|
62176
62410
|
path: ["classification_values"]
|
|
62177
62411
|
});
|
|
62178
62412
|
var MODEL_ID_RE = /^[A-Za-z0-9._:/-]{1,128}$/;
|
|
62179
|
-
var UNSYNCED_MANIFEST_KEYS = ["commands", "hooks", "files"];
|
|
62180
62413
|
var UnsyncedBlockSchema = exports_external.array(exports_external.record(exports_external.unknown())).optional();
|
|
62181
|
-
var UnsyncedBlocksShape = Object.fromEntries(UNSYNCED_MANIFEST_KEYS.map((key2) => [key2, UnsyncedBlockSchema]));
|
|
62182
62414
|
var AgentManifestSchema = exports_external.object({
|
|
62183
62415
|
schema: exports_external.literal(1),
|
|
62184
62416
|
id: exports_external.string().min(1).optional(),
|
|
@@ -62205,8 +62437,29 @@ var AgentManifestSchema = exports_external.object({
|
|
|
62205
62437
|
});
|
|
62206
62438
|
}).default([]),
|
|
62207
62439
|
capabilities: CapabilitiesSchema.optional(),
|
|
62208
|
-
|
|
62440
|
+
commands: UnsyncedBlockSchema,
|
|
62441
|
+
hooks: UnsyncedBlockSchema,
|
|
62442
|
+
files: UnsyncedBlockSchema
|
|
62209
62443
|
});
|
|
62444
|
+
var MANIFEST_KEY_SYNC = {
|
|
62445
|
+
schema: "local",
|
|
62446
|
+
id: "synced",
|
|
62447
|
+
harness: "synced",
|
|
62448
|
+
machine_kind: "synced",
|
|
62449
|
+
default_model: "synced",
|
|
62450
|
+
agent: "synced",
|
|
62451
|
+
instructions: "synced",
|
|
62452
|
+
entrypoint: "synced",
|
|
62453
|
+
playbooks: "synced",
|
|
62454
|
+
skills: "synced",
|
|
62455
|
+
mcp: "synced",
|
|
62456
|
+
evals: "synced",
|
|
62457
|
+
capabilities: "synced",
|
|
62458
|
+
commands: "unsynced",
|
|
62459
|
+
hooks: "unsynced",
|
|
62460
|
+
files: "unsynced"
|
|
62461
|
+
};
|
|
62462
|
+
var UNSYNCED_MANIFEST_KEYS = Object.keys(AgentManifestSchema.shape).filter((key2) => (MANIFEST_KEY_SYNC[key2] ?? "unsynced") === "unsynced");
|
|
62210
62463
|
function manifestPath(cwd2) {
|
|
62211
62464
|
return path73.join(cwd2, AGENT_MANIFEST_FILE);
|
|
62212
62465
|
}
|
|
@@ -62879,7 +63132,10 @@ async function handleAlreadyLinked(cwd2, link2, args) {
|
|
|
62879
63132
|
return;
|
|
62880
63133
|
}
|
|
62881
63134
|
if (next === "unlink") {
|
|
62882
|
-
if (!
|
|
63135
|
+
if (!autoProceedDestructive(args.yes, {
|
|
63136
|
+
action: `Unlinking this folder from ${link2.name}`,
|
|
63137
|
+
flagHint: "Pass --yes to unlink without a prompt."
|
|
63138
|
+
})) {
|
|
62883
63139
|
const confirmed = await se({
|
|
62884
63140
|
message: "Remove the link from this folder? (the cloud agent will stay)",
|
|
62885
63141
|
initialValue: true
|
|
@@ -62901,7 +63157,10 @@ async function handleAlreadyLinked(cwd2, link2, args) {
|
|
|
62901
63157
|
flagHint: "Pass --agent <id>."
|
|
62902
63158
|
});
|
|
62903
63159
|
const newId = ans.trim();
|
|
62904
|
-
if (!
|
|
63160
|
+
if (!autoProceedDestructive(args.yes, {
|
|
63161
|
+
action: `Replacing this folder's link to ${link2.name} with ${newId}`,
|
|
63162
|
+
flagHint: "Pass --yes to re-link without a prompt."
|
|
63163
|
+
})) {
|
|
62905
63164
|
const confirmed = await se({
|
|
62906
63165
|
message: "This will replace the current link. Continue?",
|
|
62907
63166
|
initialValue: false
|
|
@@ -63072,7 +63331,10 @@ async function runUnlink(cwd2, args) {
|
|
|
63072
63331
|
return;
|
|
63073
63332
|
}
|
|
63074
63333
|
f2.info(`Currently linked to ${import_picocolors23.default.bold(link2.name)} ${import_picocolors23.default.dim(`(${link2.slug})`)}.`);
|
|
63075
|
-
if (!
|
|
63334
|
+
if (!autoProceedDestructive(args.yes, {
|
|
63335
|
+
action: `Unlinking this folder from ${link2.name}`,
|
|
63336
|
+
flagHint: "Pass --yes to unlink without a prompt."
|
|
63337
|
+
})) {
|
|
63076
63338
|
const ok = await se({
|
|
63077
63339
|
message: "Remove the link from this folder? (the cloud agent will stay)",
|
|
63078
63340
|
initialValue: true
|
|
@@ -63366,7 +63628,7 @@ async function runSync(cwd2, args) {
|
|
|
63366
63628
|
banner("sync — bring in the latest changes from your team");
|
|
63367
63629
|
const link2 = readLink(cwd2);
|
|
63368
63630
|
if (!link2) {
|
|
63369
|
-
|
|
63631
|
+
failWarn("This folder is not linked to any agent.");
|
|
63370
63632
|
f2.info(`Run ${import_picocolors24.default.cyan("brainbase link")} first.`);
|
|
63371
63633
|
return;
|
|
63372
63634
|
}
|
|
@@ -63379,9 +63641,9 @@ async function runSync(cwd2, args) {
|
|
|
63379
63641
|
} catch (err) {
|
|
63380
63642
|
manifestSpinner.stop("Failed.");
|
|
63381
63643
|
if (err instanceof ApiError && err.status === 401) {
|
|
63382
|
-
|
|
63644
|
+
fail("Your session is invalid. Run `brainbase login` and try again.");
|
|
63383
63645
|
} else {
|
|
63384
|
-
|
|
63646
|
+
fail(err.message);
|
|
63385
63647
|
}
|
|
63386
63648
|
return;
|
|
63387
63649
|
}
|
|
@@ -64418,7 +64680,7 @@ function componentsForNativeInstall(components, acp) {
|
|
|
64418
64680
|
async function runAgentUnpack(cwd2, args) {
|
|
64419
64681
|
banner("agent unpack — install this agent into a harness layout");
|
|
64420
64682
|
if (!hasManifest(cwd2)) {
|
|
64421
|
-
|
|
64683
|
+
fail(`No ${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} here.`);
|
|
64422
64684
|
f2.info(`Run ${import_picocolors25.default.cyan("brainbase agent pull <id>")} to bring an agent into this folder first.`);
|
|
64423
64685
|
return;
|
|
64424
64686
|
}
|
|
@@ -64431,7 +64693,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
64431
64693
|
return;
|
|
64432
64694
|
}
|
|
64433
64695
|
if (!manifest.id) {
|
|
64434
|
-
|
|
64696
|
+
fail(`${import_picocolors25.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors25.default.cyan("id")}).`);
|
|
64435
64697
|
f2.info(`Run ${import_picocolors25.default.cyan("brainbase agent create")} to claim it, ` + `or ${import_picocolors25.default.cyan("brainbase agent pull <id>")} to link it to an existing agent.`);
|
|
64436
64698
|
return;
|
|
64437
64699
|
}
|
|
@@ -64440,7 +64702,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
64440
64702
|
harness = normalizeHarnessId(args.harness);
|
|
64441
64703
|
} else if (args.yes) {
|
|
64442
64704
|
if (!manifest.harness) {
|
|
64443
|
-
|
|
64705
|
+
fail(`--yes mode but no harness — set ${import_picocolors25.default.cyan("harness")} in the manifest or pass ${import_picocolors25.default.cyan("--harness")}.`);
|
|
64444
64706
|
return;
|
|
64445
64707
|
}
|
|
64446
64708
|
harness = normalizeHarnessId(manifest.harness);
|
|
@@ -64540,7 +64802,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
64540
64802
|
runHarnessRemoveMcp(harness, builtinRemoveSlugs, { cwd: cwd2, scope });
|
|
64541
64803
|
}
|
|
64542
64804
|
} catch (err) {
|
|
64543
|
-
|
|
64805
|
+
fail(`Install failed: ${err.message}`);
|
|
64544
64806
|
return;
|
|
64545
64807
|
} finally {
|
|
64546
64808
|
try {
|
|
@@ -64989,7 +65251,7 @@ function resolveTargetAgentId(cwd2, args) {
|
|
|
64989
65251
|
const manifestId = manifest?.id;
|
|
64990
65252
|
if (arg && manifestId && arg !== manifestId) {
|
|
64991
65253
|
if (!args.force) {
|
|
64992
|
-
|
|
65254
|
+
fail(`This folder is already linked to a different agent (${import_picocolors26.default.dim(manifestId)}).`);
|
|
64993
65255
|
f2.info(`Run ${import_picocolors26.default.cyan(`brainbase agent pull ${arg} --force`)} to override. ` + import_picocolors26.default.yellow("This will overwrite brainbase.agent.yaml and any local progress will be lost."));
|
|
64994
65256
|
return null;
|
|
64995
65257
|
}
|
|
@@ -65000,10 +65262,10 @@ function resolveTargetAgentId(cwd2, args) {
|
|
|
65000
65262
|
if (manifestId)
|
|
65001
65263
|
return { agentId: manifestId, override: false };
|
|
65002
65264
|
if (manifest) {
|
|
65003
|
-
|
|
65265
|
+
fail(`${import_picocolors26.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors26.default.cyan("id")}).`);
|
|
65004
65266
|
f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent create")} to create a new agent from this manifest, ` + `or ${import_picocolors26.default.cyan("brainbase agent pull <id>")} to pull an existing one.`);
|
|
65005
65267
|
} else {
|
|
65006
|
-
|
|
65268
|
+
fail(`No ${import_picocolors26.default.bold(AGENT_MANIFEST_FILE)} here and no ${import_picocolors26.default.cyan("<id>")} given.`);
|
|
65007
65269
|
f2.info(`Run ${import_picocolors26.default.cyan("brainbase agent pull <id>")} to pull an existing agent into this folder.`);
|
|
65008
65270
|
}
|
|
65009
65271
|
return null;
|
|
@@ -65366,42 +65628,87 @@ async function pullSecrets(cwd2, agentId) {
|
|
|
65366
65628
|
function handleApiError2(err) {
|
|
65367
65629
|
if (err instanceof ApiError) {
|
|
65368
65630
|
if (err.status === 401) {
|
|
65369
|
-
|
|
65631
|
+
fail("Your session is invalid. Run `brainbase login` and try again.");
|
|
65370
65632
|
} else if (err.status === 404) {
|
|
65371
|
-
|
|
65633
|
+
fail(`Agent not found, or you don't have access. Double-check the id.`);
|
|
65372
65634
|
} else {
|
|
65373
|
-
|
|
65635
|
+
fail(err.message);
|
|
65374
65636
|
}
|
|
65375
65637
|
} else {
|
|
65376
|
-
|
|
65638
|
+
fail(err.message);
|
|
65377
65639
|
}
|
|
65378
65640
|
}
|
|
65379
65641
|
|
|
65380
65642
|
// src/cli/agent-push.ts
|
|
65381
65643
|
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
65382
65644
|
|
|
65383
|
-
// src/core/
|
|
65384
|
-
function
|
|
65385
|
-
|
|
65386
|
-
|
|
65387
|
-
|
|
65388
|
-
|
|
65389
|
-
|
|
65390
|
-
const
|
|
65391
|
-
const
|
|
65392
|
-
|
|
65645
|
+
// src/core/collection-reconcile.ts
|
|
65646
|
+
function untouchedRows(decision) {
|
|
65647
|
+
if (decision.kind === "reconcile")
|
|
65648
|
+
return [];
|
|
65649
|
+
return [...decision.unseen, ...decision.cloudModified].sort();
|
|
65650
|
+
}
|
|
65651
|
+
function decideCollectionReconcile(input) {
|
|
65652
|
+
const rows = input.rows.filter((r2) => r2.type === input.type);
|
|
65653
|
+
const unseen = rows.filter((r2) => r2.status === "added-cloud").map((r2) => r2.slug).sort();
|
|
65654
|
+
const cloudModified = rows.filter((r2) => r2.status === "modified-cloud" || r2.status === "modified-both" || r2.status === "added-local" && r2.localHash !== undefined && r2.cloudHash !== undefined && r2.localHash !== r2.cloudHash).map((r2) => r2.slug).sort();
|
|
65655
|
+
const removedLocal = rows.filter((r2) => r2.status === "removed-local");
|
|
65656
|
+
const archives = removedLocal.map((r2) => r2.slug).sort();
|
|
65657
|
+
const staleArchives = removedLocal.filter((r2) => r2.cloudHash !== undefined && r2.lockHash !== undefined && r2.cloudHash !== r2.lockHash).map((r2) => r2.slug).sort();
|
|
65658
|
+
if (!input.claims && archives.length === 0) {
|
|
65393
65659
|
if (unseen.length > 0 || cloudModified.length > 0) {
|
|
65394
|
-
return { kind: "skip", unseen
|
|
65660
|
+
return { kind: "skip", unseen, cloudModified };
|
|
65395
65661
|
}
|
|
65396
65662
|
return { kind: "reconcile", archives: [] };
|
|
65397
65663
|
}
|
|
65398
65664
|
if (input.force) {
|
|
65399
65665
|
return { kind: "reconcile", archives: [...archives, ...unseen].sort() };
|
|
65400
65666
|
}
|
|
65401
|
-
if (unseen.length === 0 && cloudModified.length === 0) {
|
|
65667
|
+
if (unseen.length === 0 && cloudModified.length === 0 && staleArchives.length === 0) {
|
|
65402
65668
|
return { kind: "reconcile", archives };
|
|
65403
65669
|
}
|
|
65404
|
-
return { kind: "blocked", unseen, cloudModified, archives };
|
|
65670
|
+
return { kind: "blocked", unseen, cloudModified, staleArchives, archives };
|
|
65671
|
+
}
|
|
65672
|
+
|
|
65673
|
+
// src/core/eval-reconcile.ts
|
|
65674
|
+
function manifestClaimsEvals(manifest) {
|
|
65675
|
+
return (manifest.evals ?? []).length > 0;
|
|
65676
|
+
}
|
|
65677
|
+
function decideEvalReconcile(input) {
|
|
65678
|
+
return decideCollectionReconcile({
|
|
65679
|
+
rows: input.rows,
|
|
65680
|
+
type: "eval",
|
|
65681
|
+
claims: input.claimsEvals,
|
|
65682
|
+
force: input.force
|
|
65683
|
+
});
|
|
65684
|
+
}
|
|
65685
|
+
|
|
65686
|
+
// src/core/playbook-reconcile.ts
|
|
65687
|
+
function manifestClaimsPlaybooks(manifest) {
|
|
65688
|
+
return (manifest.playbooks ?? []).length > 0;
|
|
65689
|
+
}
|
|
65690
|
+
function decidePlaybookReconcile(input) {
|
|
65691
|
+
return decideCollectionReconcile({
|
|
65692
|
+
rows: input.rows,
|
|
65693
|
+
type: "playbook",
|
|
65694
|
+
claims: input.claimsPlaybooks,
|
|
65695
|
+
force: input.force
|
|
65696
|
+
});
|
|
65697
|
+
}
|
|
65698
|
+
function playbookLabels(slugs, cloudComponents) {
|
|
65699
|
+
const titleBySlug = new Map;
|
|
65700
|
+
for (const c2 of cloudComponents) {
|
|
65701
|
+
if (c2.type !== "playbook")
|
|
65702
|
+
continue;
|
|
65703
|
+
const title = c2.meta?.playbook?.title;
|
|
65704
|
+
if (typeof title === "string" && title.trim()) {
|
|
65705
|
+
titleBySlug.set(c2.slug, title);
|
|
65706
|
+
}
|
|
65707
|
+
}
|
|
65708
|
+
return slugs.map((slug) => {
|
|
65709
|
+
const title = titleBySlug.get(slug);
|
|
65710
|
+
return title && title !== slug ? `${title} (${slug})` : slug;
|
|
65711
|
+
});
|
|
65405
65712
|
}
|
|
65406
65713
|
|
|
65407
65714
|
// src/core/agent-outgoing.ts
|
|
@@ -65606,7 +65913,7 @@ function planRegistrySkillUpdates(skills, cloudComponents, latestByName) {
|
|
|
65606
65913
|
async function runAgentPush(cwd2, args) {
|
|
65607
65914
|
banner("agent push — send your local changes to the cloud");
|
|
65608
65915
|
if (!hasManifest(cwd2)) {
|
|
65609
|
-
|
|
65916
|
+
failWarn(`No ${import_picocolors28.default.bold(AGENT_MANIFEST_FILE)} here.`);
|
|
65610
65917
|
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent create")} to claim a new agent from a manifest, ` + `or ${import_picocolors28.default.cyan("brainbase agent pull <id>")} to pull an existing one.`);
|
|
65611
65918
|
return;
|
|
65612
65919
|
}
|
|
@@ -65623,7 +65930,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65623
65930
|
return;
|
|
65624
65931
|
}
|
|
65625
65932
|
if (!manifest.id) {
|
|
65626
|
-
|
|
65933
|
+
failWarn(`${import_picocolors28.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors28.default.cyan("id")}). Nothing to push to.`);
|
|
65627
65934
|
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent create")} first — that creates the cloud agent and stamps an id here.`);
|
|
65628
65935
|
return;
|
|
65629
65936
|
}
|
|
@@ -65791,7 +66098,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65791
66098
|
force: !!args.force
|
|
65792
66099
|
});
|
|
65793
66100
|
if (evalDecision.kind === "blocked") {
|
|
65794
|
-
const { unseen, cloudModified } = evalDecision;
|
|
66101
|
+
const { unseen, cloudModified, staleArchives } = evalDecision;
|
|
65795
66102
|
f2.error(unseen.length > 0 ? "Cannot push: the cloud has eval changes this folder has never seen." : "Cannot push: evals changed both locally and in the cloud.");
|
|
65796
66103
|
for (const slug of unseen) {
|
|
65797
66104
|
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("eval")} ${import_picocolors28.default.bold(slug)} ${import_picocolors28.default.dim("(only in the cloud — pushing would archive it)")}`);
|
|
@@ -65799,12 +66106,17 @@ async function runAgentPush(cwd2, args) {
|
|
|
65799
66106
|
for (const slug of cloudModified) {
|
|
65800
66107
|
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("eval")} ${import_picocolors28.default.bold(slug)} ${import_picocolors28.default.dim("(edited in the cloud — pushing would overwrite that edit)")}`);
|
|
65801
66108
|
}
|
|
65802
|
-
|
|
66109
|
+
for (const slug of staleArchives) {
|
|
66110
|
+
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("eval")} ${import_picocolors28.default.bold(slug)} ${import_picocolors28.default.dim("(deleted here, edited in the cloud since — pushing would archive that edit)")}`);
|
|
66111
|
+
}
|
|
66112
|
+
const total = unseen.length + cloudModified.length + staleArchives.length;
|
|
66113
|
+
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} to bring ${total === 1 ? "it" : "them"} into ${import_picocolors28.default.bold("brainbase.agent.yaml")}, then push — or ${import_picocolors28.default.cyan("brainbase agent push --force")} to make your local evals authoritative and archive the rest.`);
|
|
65803
66114
|
process.exitCode = 1;
|
|
65804
66115
|
return;
|
|
65805
66116
|
}
|
|
65806
66117
|
if (evalDecision.kind === "skip") {
|
|
65807
|
-
|
|
66118
|
+
const left = untouchedRows(evalDecision);
|
|
66119
|
+
f2.warn(`${left.length} cloud eval${left.length === 1 ? "" : "s"} (${left.map((s3) => import_picocolors28.default.bold(s3)).join(", ")}) ${left.length === 1 ? "is" : "are"} not managed by ${import_picocolors28.default.bold("brainbase.agent.yaml")} and will be left untouched. Run ${import_picocolors28.default.cyan("brainbase agent pull")} to manage ${left.length === 1 ? "it" : "them"} from here.`);
|
|
65808
66120
|
}
|
|
65809
66121
|
for (const entry of manifest.skills) {
|
|
65810
66122
|
let parsed;
|
|
@@ -65831,6 +66143,32 @@ async function runAgentPush(cwd2, args) {
|
|
|
65831
66143
|
process.exitCode = 1;
|
|
65832
66144
|
return;
|
|
65833
66145
|
}
|
|
66146
|
+
const playbookDecision = decidePlaybookReconcile({
|
|
66147
|
+
rows,
|
|
66148
|
+
claimsPlaybooks: manifestClaimsPlaybooks(manifest),
|
|
66149
|
+
force: !!args.force
|
|
66150
|
+
});
|
|
66151
|
+
if (playbookDecision.kind === "blocked") {
|
|
66152
|
+
const { unseen, cloudModified, staleArchives } = playbookDecision;
|
|
66153
|
+
f2.error(unseen.length > 0 ? "Cannot push: the cloud has playbooks this folder has never seen." : "Cannot push: playbooks changed both locally and in the cloud.");
|
|
66154
|
+
for (const label of playbookLabels(unseen, cloud.components)) {
|
|
66155
|
+
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("playbook")} ${import_picocolors28.default.bold(label)} ${import_picocolors28.default.dim("(only in the cloud — pushing would archive it)")}`);
|
|
66156
|
+
}
|
|
66157
|
+
for (const label of playbookLabels(cloudModified, cloud.components)) {
|
|
66158
|
+
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("playbook")} ${import_picocolors28.default.bold(label)} ${import_picocolors28.default.dim("(edited in the cloud — pushing would overwrite that edit)")}`);
|
|
66159
|
+
}
|
|
66160
|
+
for (const label of playbookLabels(staleArchives, cloud.components)) {
|
|
66161
|
+
console.error(` ${import_picocolors28.default.red("!")} ${fmtType("playbook")} ${import_picocolors28.default.bold(label)} ${import_picocolors28.default.dim("(deleted here, edited in the cloud since — pushing would archive that edit)")}`);
|
|
66162
|
+
}
|
|
66163
|
+
const total = unseen.length + cloudModified.length + staleArchives.length;
|
|
66164
|
+
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} to bring ${total === 1 ? "it" : "them"} into ${import_picocolors28.default.bold(AGENT_MANIFEST_FILE)}, then push — or ${import_picocolors28.default.cyan("brainbase agent push --force")} to make your local playbooks authoritative and archive the rest.`);
|
|
66165
|
+
process.exitCode = 1;
|
|
66166
|
+
return;
|
|
66167
|
+
}
|
|
66168
|
+
if (playbookDecision.kind === "skip") {
|
|
66169
|
+
const labels = playbookLabels(untouchedRows(playbookDecision), cloud.components);
|
|
66170
|
+
f2.warn(`${labels.length} cloud playbook${labels.length === 1 ? "" : "s"} (${labels.map((s3) => import_picocolors28.default.bold(s3)).join(", ")}) ${labels.length === 1 ? "is" : "are"} not managed by ${import_picocolors28.default.bold(AGENT_MANIFEST_FILE)} and will be left untouched. Run ${import_picocolors28.default.cyan("brainbase agent pull")} to manage ${labels.length === 1 ? "it" : "them"} from here.`);
|
|
66171
|
+
}
|
|
65834
66172
|
const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
|
|
65835
66173
|
const forcedOverrides = args.force ? rows.filter((r2) => r2.status === "modified-both") : [];
|
|
65836
66174
|
if (conflicts.length > 0) {
|
|
@@ -65964,6 +66302,15 @@ async function runAgentPush(cwd2, args) {
|
|
|
65964
66302
|
text: `${evalArchives.length} · ${evalArchives.join(", ")}`
|
|
65965
66303
|
});
|
|
65966
66304
|
}
|
|
66305
|
+
const playbookArchives = playbookDecision.kind === "reconcile" ? playbookDecision.archives : [];
|
|
66306
|
+
const playbookArchiveLabels = playbookLabels(playbookArchives, cloud.components);
|
|
66307
|
+
if (playbookArchives.length) {
|
|
66308
|
+
resultRows.push({
|
|
66309
|
+
type: "rem",
|
|
66310
|
+
label: "archive",
|
|
66311
|
+
text: `${playbookArchives.length} playbook${playbookArchives.length === 1 ? "" : "s"} · ${playbookArchiveLabels.join(", ")}`
|
|
66312
|
+
});
|
|
66313
|
+
}
|
|
65967
66314
|
await showResultCard({
|
|
65968
66315
|
title: "PUSH",
|
|
65969
66316
|
tone: "info",
|
|
@@ -65973,10 +66320,14 @@ async function runAgentPush(cwd2, args) {
|
|
|
65973
66320
|
if (evalArchives.length) {
|
|
65974
66321
|
f2.warn(`${evalArchives.length} cloud eval${evalArchives.length === 1 ? "" : "s"} ${evalArchives.length === 1 ? "is" : "are"} missing from ${import_picocolors28.default.bold("brainbase.agent.yaml")} and will be archived: ${evalArchives.map((s3) => import_picocolors28.default.bold(s3)).join(", ")}. ${import_picocolors28.default.dim("Archived, not deleted — past verdicts are kept, and re-adding the eval restores it.")}`);
|
|
65975
66322
|
}
|
|
66323
|
+
if (playbookArchives.length) {
|
|
66324
|
+
f2.warn(`${playbookArchives.length} cloud playbook${playbookArchives.length === 1 ? "" : "s"} ${playbookArchives.length === 1 ? "is" : "are"} missing from ${import_picocolors28.default.bold("brainbase.agent.yaml")} and will be archived: ${playbookArchiveLabels.map((s3) => import_picocolors28.default.bold(s3)).join(", ")}. ${import_picocolors28.default.dim("Archived, not deleted — the row is kept, and re-adding the playbook restores it.")}`);
|
|
66325
|
+
}
|
|
66326
|
+
const destructive = evalArchives.length + playbookArchives.length;
|
|
65976
66327
|
if (!autoProceed(args.yes)) {
|
|
65977
66328
|
const ok = await se({
|
|
65978
|
-
message:
|
|
65979
|
-
initialValue:
|
|
66329
|
+
message: destructive ? `Send these changes, archiving ${describeArchiveSet(evalArchives.length, playbookArchives.length)}?` : "Send these changes?",
|
|
66330
|
+
initialValue: destructive === 0
|
|
65980
66331
|
});
|
|
65981
66332
|
if (!ensureNotCancelled(ok)) {
|
|
65982
66333
|
$e("Aborted.");
|
|
@@ -66043,11 +66394,12 @@ async function runAgentPush(cwd2, args) {
|
|
|
66043
66394
|
let updatedCloud;
|
|
66044
66395
|
try {
|
|
66045
66396
|
const reconcileEvals = evalDecision.kind !== "skip";
|
|
66046
|
-
const
|
|
66397
|
+
const reconcilePlaybooks = playbookDecision.kind !== "skip";
|
|
66398
|
+
const components = outgoing.filter((c2) => (reconcileEvals || c2.type !== "eval") && (reconcilePlaybooks || c2.type !== "playbook"));
|
|
66047
66399
|
updatedCloud = await api.pushAgentManifest(agentId, {
|
|
66048
66400
|
components,
|
|
66049
66401
|
base_revision: cloud.revision,
|
|
66050
|
-
reconcile_playbooks:
|
|
66402
|
+
reconcile_playbooks: reconcilePlaybooks,
|
|
66051
66403
|
reconcile_evals: reconcileEvals
|
|
66052
66404
|
});
|
|
66053
66405
|
pushSpinner.stop(`Pushed. New revision ${updatedCloud.revision}.`);
|
|
@@ -66095,16 +66447,21 @@ async function runAgentPush(cwd2, args) {
|
|
|
66095
66447
|
localHashByKey.set(`eval/${entry.slug}`, hashEvalEntry(entry));
|
|
66096
66448
|
}
|
|
66097
66449
|
}
|
|
66098
|
-
const
|
|
66099
|
-
|
|
66100
|
-
|
|
66450
|
+
const skipped = new Set;
|
|
66451
|
+
if (evalDecision.kind === "skip")
|
|
66452
|
+
skipped.add("eval");
|
|
66453
|
+
if (playbookDecision.kind === "skip")
|
|
66454
|
+
skipped.add("playbook");
|
|
66455
|
+
const lockSource = skipped.size === 0 ? updatedCloud.components : [
|
|
66456
|
+
...updatedCloud.components.filter((c2) => !skipped.has(c2.type)),
|
|
66457
|
+
...(lock?.components ?? []).filter((c2) => skipped.has(c2.type)).map((c2) => ({
|
|
66101
66458
|
type: c2.type,
|
|
66102
66459
|
slug: c2.slug,
|
|
66103
66460
|
hash: c2.hash,
|
|
66104
66461
|
files: [],
|
|
66105
66462
|
meta: undefined
|
|
66106
66463
|
}))
|
|
66107
|
-
]
|
|
66464
|
+
];
|
|
66108
66465
|
const newLock = {
|
|
66109
66466
|
schemaVersion: 1,
|
|
66110
66467
|
agent_id: agentId,
|
|
@@ -66186,6 +66543,15 @@ async function pushSecrets(agentId, plan) {
|
|
|
66186
66543
|
return false;
|
|
66187
66544
|
}
|
|
66188
66545
|
}
|
|
66546
|
+
function describeArchiveSet(evals, playbooks) {
|
|
66547
|
+
const parts = [];
|
|
66548
|
+
if (evals)
|
|
66549
|
+
parts.push(`${evals} eval${evals === 1 ? "" : "s"}`);
|
|
66550
|
+
if (playbooks) {
|
|
66551
|
+
parts.push(`${playbooks} playbook${playbooks === 1 ? "" : "s"}`);
|
|
66552
|
+
}
|
|
66553
|
+
return parts.join(" and ");
|
|
66554
|
+
}
|
|
66189
66555
|
function secretDiffSummary(diff2) {
|
|
66190
66556
|
return `${diff2.localOnly.length} added, ${diff2.changed.length} updated, ${diff2.cloudOnly.length} removed`;
|
|
66191
66557
|
}
|
|
@@ -66216,9 +66582,10 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66216
66582
|
if (!link2) {
|
|
66217
66583
|
if (json) {
|
|
66218
66584
|
emitJson({ linked: false, ignored: [], unchecked: [] });
|
|
66585
|
+
process.exitCode = 1;
|
|
66219
66586
|
return;
|
|
66220
66587
|
}
|
|
66221
|
-
|
|
66588
|
+
failWarn("This folder is not linked to any agent.");
|
|
66222
66589
|
f2.info(`Run ${import_picocolors29.default.cyan("brainbase link")} first.`);
|
|
66223
66590
|
return;
|
|
66224
66591
|
}
|
|
@@ -66243,9 +66610,9 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66243
66610
|
} catch (err) {
|
|
66244
66611
|
const unauthorized = err instanceof ApiError && err.status === 401;
|
|
66245
66612
|
const message = unauthorized ? "Your session is invalid. Run `brainbase login` and try again." : err.message;
|
|
66613
|
+
process.exitCode = 1;
|
|
66246
66614
|
if (json) {
|
|
66247
66615
|
console.error(message);
|
|
66248
|
-
process.exitCode = 1;
|
|
66249
66616
|
return;
|
|
66250
66617
|
}
|
|
66251
66618
|
sp?.stop("Failed to reach brainbase.");
|
|
@@ -66310,20 +66677,25 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66310
66677
|
};
|
|
66311
66678
|
let secretsChecked = true;
|
|
66312
66679
|
let secretsUncheckedReason = "";
|
|
66680
|
+
let cloudSecretNames = null;
|
|
66313
66681
|
try {
|
|
66314
|
-
const localSecrets = readLocalSecrets(cwd2);
|
|
66315
66682
|
const cloudRes = await api.getAgentSecrets(link2.agent_id);
|
|
66316
|
-
|
|
66683
|
+
cloudSecretNames = new Set(Object.keys(cloudRes.secrets));
|
|
66684
|
+
secretDrift = diffSecrets(readLocalSecrets(cwd2), cloudRes.secrets);
|
|
66317
66685
|
} catch (err) {
|
|
66318
|
-
|
|
66319
|
-
|
|
66320
|
-
secretsUncheckedReason = describeSecretsFailure(err);
|
|
66321
|
-
}
|
|
66686
|
+
secretsChecked = false;
|
|
66687
|
+
secretsUncheckedReason = describeSecretsFailure(err);
|
|
66322
66688
|
}
|
|
66323
66689
|
const componentsDrifted = conflicts.length > 0 || toPush.length > 0 || toPull.length > 0;
|
|
66324
66690
|
const metaDrifted = meta.localChanged || meta.cloudChanged;
|
|
66325
66691
|
const configDrifted = config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged || capabilityDrifted(config.memory) || capabilityDrifted(config.browser);
|
|
66326
66692
|
const secretsDrifted = secretDrift.localOnly.length > 0 || secretDrift.cloudOnly.length > 0 || secretDrift.changed.length > 0;
|
|
66693
|
+
const secretConflicts = cloudAgent.secret_conflicts ?? [];
|
|
66694
|
+
const inheritedSecrets = (cloudAgent.inherited_secret_keys ?? []).map((entry) => ({
|
|
66695
|
+
...entry,
|
|
66696
|
+
overridden: entry.overridden ?? cloudSecretNames?.has(entry.key) ?? false
|
|
66697
|
+
}));
|
|
66698
|
+
const hasInheritedSecrets = inheritedSecrets.length > 0 || secretConflicts.length > 0;
|
|
66327
66699
|
const everythingInSync = !componentsDrifted && !metaDrifted && !configDrifted && !secretsDrifted;
|
|
66328
66700
|
const unchecked = secretsChecked ? [] : [{ signal: "secrets", reason: secretsUncheckedReason }];
|
|
66329
66701
|
const evalPlan = decideEvalReconcile({
|
|
@@ -66331,12 +66703,13 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66331
66703
|
claimsEvals: manifestClaimsEvals(manifest),
|
|
66332
66704
|
force: false
|
|
66333
66705
|
});
|
|
66334
|
-
const evalReport =
|
|
66335
|
-
|
|
66336
|
-
|
|
66337
|
-
|
|
66338
|
-
|
|
66339
|
-
};
|
|
66706
|
+
const evalReport = reconcileReport(evalPlan);
|
|
66707
|
+
const playbookPlan = decidePlaybookReconcile({
|
|
66708
|
+
rows,
|
|
66709
|
+
claimsPlaybooks: manifestClaimsPlaybooks(manifest),
|
|
66710
|
+
force: false
|
|
66711
|
+
});
|
|
66712
|
+
const playbookReport = reconcileReport(playbookPlan);
|
|
66340
66713
|
if (json) {
|
|
66341
66714
|
emitJson({
|
|
66342
66715
|
linked: true,
|
|
@@ -66358,17 +66731,26 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66358
66731
|
secrets: secretsChecked ? {
|
|
66359
66732
|
localOnly: secretDrift.localOnly,
|
|
66360
66733
|
cloudOnly: secretDrift.cloudOnly,
|
|
66361
|
-
changed: secretDrift.changed
|
|
66734
|
+
changed: secretDrift.changed,
|
|
66735
|
+
inherited: inheritedSecrets,
|
|
66736
|
+
conflicts: secretConflicts
|
|
66362
66737
|
} : null,
|
|
66738
|
+
orchestrationSecrets: {
|
|
66739
|
+
inherited: inheritedSecrets,
|
|
66740
|
+
conflicts: secretConflicts
|
|
66741
|
+
},
|
|
66363
66742
|
components: {
|
|
66364
66743
|
push: toPush.map(rowJson),
|
|
66365
66744
|
pull: toPull.map(rowJson),
|
|
66366
66745
|
conflicts: conflicts.map(rowJson)
|
|
66367
66746
|
},
|
|
66368
66747
|
evals: evalReport,
|
|
66748
|
+
playbooks: playbookReport,
|
|
66369
66749
|
inSync: everythingInSync,
|
|
66370
66750
|
unchecked
|
|
66371
66751
|
});
|
|
66752
|
+
if (!secretsChecked)
|
|
66753
|
+
process.exitCode = 1;
|
|
66372
66754
|
return;
|
|
66373
66755
|
}
|
|
66374
66756
|
const lines = [];
|
|
@@ -66430,7 +66812,7 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66430
66812
|
}
|
|
66431
66813
|
lines.push("");
|
|
66432
66814
|
}
|
|
66433
|
-
if (secretsDrifted || !secretsChecked) {
|
|
66815
|
+
if (secretsDrifted || !secretsChecked || hasInheritedSecrets) {
|
|
66434
66816
|
lines.push(` ${import_picocolors29.default.bold("secrets")}`);
|
|
66435
66817
|
if (!secretsChecked) {
|
|
66436
66818
|
lines.push(` ${import_picocolors29.default.dim("? unchecked")} ${secretsUncheckedReason}`);
|
|
@@ -66441,16 +66823,34 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66441
66823
|
lines.push(` ${import_picocolors29.default.yellow("→ push")} values changed: ${secretDrift.changed.join(", ")}`);
|
|
66442
66824
|
if (secretDrift.cloudOnly.length)
|
|
66443
66825
|
lines.push(` ${import_picocolors29.default.cyan("← pull")} new on cloud: ${secretDrift.cloudOnly.join(", ")}`);
|
|
66826
|
+
for (const entry of inheritedSecrets) {
|
|
66827
|
+
const source = entry.orchestration_name || entry.orchestration_id;
|
|
66828
|
+
const pendingOverride = !entry.overridden && (secretDrift.localOnly.includes(entry.key) || secretDrift.changed.includes(entry.key));
|
|
66829
|
+
lines.push(entry.overridden ? ` ${entry.key} ${import_picocolors29.default.dim(`(inherited from ${source}, overridden by this agent's own secret)`)}` : pendingOverride ? ` ${entry.key} ${import_picocolors29.default.dim(`(inherited from ${source}, will be overridden once pushed)`)}` : ` ${entry.key} ${import_picocolors29.default.dim(`(inherited from ${source})`)}`);
|
|
66830
|
+
}
|
|
66831
|
+
for (const entry of secretConflicts) {
|
|
66832
|
+
lines.push(` ${import_picocolors29.default.dim("! conflict")} ${entry.key} ${import_picocolors29.default.dim(`has different values ${conflictSources(entry)}; neither value is applied until you set one on this agent`)}`);
|
|
66833
|
+
}
|
|
66834
|
+
if (secretConflicts.length > 0 && everythingInSync) {
|
|
66835
|
+
lines.push(` ${import_picocolors29.default.dim("conflicts are informational; they never block sync")}`);
|
|
66836
|
+
}
|
|
66444
66837
|
lines.push("");
|
|
66445
66838
|
}
|
|
66446
66839
|
if (everythingInSync) {
|
|
66447
|
-
|
|
66448
|
-
|
|
66840
|
+
if (secretsChecked) {
|
|
66841
|
+
lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync`);
|
|
66842
|
+
} else {
|
|
66843
|
+
lines.push(` ${import_picocolors29.default.yellow("?")} cannot confirm sync — secrets were not compared`);
|
|
66844
|
+
lines.push(` ${import_picocolors29.default.dim('everything else came back clean; the reason is under "secrets" above')}`);
|
|
66845
|
+
process.exitCode = 1;
|
|
66846
|
+
}
|
|
66449
66847
|
lines.push("");
|
|
66450
66848
|
console.log(lines.join(`
|
|
66451
66849
|
`));
|
|
66452
66850
|
return;
|
|
66453
66851
|
}
|
|
66852
|
+
if (!secretsChecked)
|
|
66853
|
+
process.exitCode = 1;
|
|
66454
66854
|
if (toPush.length) {
|
|
66455
66855
|
lines.push(` ${import_picocolors29.default.bold("changes to push")} ${import_picocolors29.default.dim(`(${toPush.length})`)}`);
|
|
66456
66856
|
for (const r2 of toPush)
|
|
@@ -66485,13 +66885,55 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66485
66885
|
for (const slug of evalReport.cloudModified) {
|
|
66486
66886
|
lines.push(` ${import_picocolors29.default.red("!")} ${import_picocolors29.default.bold(slug)} ${import_picocolors29.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
66487
66887
|
}
|
|
66888
|
+
for (const slug of evalReport.staleArchives) {
|
|
66889
|
+
lines.push(` ${import_picocolors29.default.red("!")} ${import_picocolors29.default.bold(slug)} ${import_picocolors29.default.dim("— deleted here, edited in the cloud since; pushing would archive that edit")}`);
|
|
66890
|
+
}
|
|
66488
66891
|
lines.push(` ${import_picocolors29.default.dim("run")} ${import_picocolors29.default.cyan("brainbase agent pull")} ${import_picocolors29.default.dim("first")}`);
|
|
66489
66892
|
lines.push("");
|
|
66490
|
-
} else if (evalReport.unseen.length) {
|
|
66491
|
-
|
|
66893
|
+
} else if (evalReport.unseen.length || evalReport.cloudModified.length) {
|
|
66894
|
+
const total = evalReport.unseen.length + evalReport.cloudModified.length;
|
|
66895
|
+
lines.push(` ${import_picocolors29.default.bold("evals this manifest does not manage")} ${import_picocolors29.default.dim(`(${total})`)}`);
|
|
66492
66896
|
for (const slug of evalReport.unseen) {
|
|
66493
|
-
lines.push(` ${import_picocolors29.default.cyan("←")} ${import_picocolors29.default.bold(slug)} ${import_picocolors29.default.dim("—
|
|
66897
|
+
lines.push(` ${import_picocolors29.default.cyan("←")} ${import_picocolors29.default.bold(slug)} ${import_picocolors29.default.dim("— only in the cloud; left untouched by push")}`);
|
|
66898
|
+
}
|
|
66899
|
+
for (const slug of evalReport.cloudModified) {
|
|
66900
|
+
lines.push(` ${import_picocolors29.default.cyan("←")} ${import_picocolors29.default.bold(slug)} ${import_picocolors29.default.dim("— edited in the cloud; left untouched by push")}`);
|
|
66901
|
+
}
|
|
66902
|
+
lines.push(` ${import_picocolors29.default.dim("run")} ${import_picocolors29.default.cyan("brainbase agent pull")} ${import_picocolors29.default.dim("to manage them from here")}`);
|
|
66903
|
+
lines.push("");
|
|
66904
|
+
}
|
|
66905
|
+
const pbLabel = (slug) => playbookLabels([slug], cloud.components)[0] ?? slug;
|
|
66906
|
+
if (playbookReport.archive.length) {
|
|
66907
|
+
lines.push(` ${import_picocolors29.default.bold("playbooks a push would archive")} ${import_picocolors29.default.dim(`(${playbookReport.archive.length})`)}`);
|
|
66908
|
+
for (const slug of playbookReport.archive) {
|
|
66909
|
+
lines.push(` ${import_picocolors29.default.yellow("⨯")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— in the cloud, not in this manifest")}`);
|
|
66910
|
+
}
|
|
66911
|
+
lines.push(` ${import_picocolors29.default.dim("archived, not deleted: re-adding the playbook restores it")}`);
|
|
66912
|
+
lines.push("");
|
|
66913
|
+
}
|
|
66914
|
+
if (playbookReport.pushBlocked) {
|
|
66915
|
+
lines.push(` ${import_picocolors29.default.bold(import_picocolors29.default.red("playbooks: push blocked"))}`);
|
|
66916
|
+
for (const slug of playbookReport.unseen) {
|
|
66917
|
+
lines.push(` ${import_picocolors29.default.red("!")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— only in the cloud; pushing would archive it")}`);
|
|
66918
|
+
}
|
|
66919
|
+
for (const slug of playbookReport.cloudModified) {
|
|
66920
|
+
lines.push(` ${import_picocolors29.default.red("!")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
66921
|
+
}
|
|
66922
|
+
for (const slug of playbookReport.staleArchives) {
|
|
66923
|
+
lines.push(` ${import_picocolors29.default.red("!")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— deleted here, edited in the cloud since; pushing would archive that edit")}`);
|
|
66924
|
+
}
|
|
66925
|
+
lines.push(` ${import_picocolors29.default.dim("run")} ${import_picocolors29.default.cyan("brainbase agent pull")} ${import_picocolors29.default.dim("first")}`);
|
|
66926
|
+
lines.push("");
|
|
66927
|
+
} else if (playbookReport.unseen.length || playbookReport.cloudModified.length) {
|
|
66928
|
+
const total = playbookReport.unseen.length + playbookReport.cloudModified.length;
|
|
66929
|
+
lines.push(` ${import_picocolors29.default.bold("playbooks this manifest does not manage")} ${import_picocolors29.default.dim(`(${total})`)}`);
|
|
66930
|
+
for (const slug of playbookReport.unseen) {
|
|
66931
|
+
lines.push(` ${import_picocolors29.default.cyan("←")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— only in the cloud; left untouched by push")}`);
|
|
66494
66932
|
}
|
|
66933
|
+
for (const slug of playbookReport.cloudModified) {
|
|
66934
|
+
lines.push(` ${import_picocolors29.default.cyan("←")} ${import_picocolors29.default.bold(pbLabel(slug))} ${import_picocolors29.default.dim("— edited in the cloud; left untouched by push")}`);
|
|
66935
|
+
}
|
|
66936
|
+
lines.push(` ${import_picocolors29.default.dim("run")} ${import_picocolors29.default.cyan("brainbase agent pull")} ${import_picocolors29.default.dim("to manage them from here")}`);
|
|
66495
66937
|
lines.push("");
|
|
66496
66938
|
}
|
|
66497
66939
|
lines.push(` ${import_picocolors29.default.dim("run")} ${import_picocolors29.default.cyan("brainbase agent pull")} ${import_picocolors29.default.dim("to apply cloud changes,")} ${import_picocolors29.default.cyan("brainbase agent push")} ${import_picocolors29.default.dim("to send yours")}`);
|
|
@@ -66499,6 +66941,25 @@ async function runAgentStatus(cwd2, args = {}) {
|
|
|
66499
66941
|
console.log(lines.join(`
|
|
66500
66942
|
`));
|
|
66501
66943
|
}
|
|
66944
|
+
function reconcileReport(decision) {
|
|
66945
|
+
return {
|
|
66946
|
+
archive: decision.kind === "reconcile" ? decision.archives : [],
|
|
66947
|
+
unseen: decision.kind === "reconcile" ? [] : decision.unseen,
|
|
66948
|
+
cloudModified: decision.kind === "reconcile" ? [] : decision.cloudModified,
|
|
66949
|
+
staleArchives: decision.kind === "blocked" ? decision.staleArchives : [],
|
|
66950
|
+
pushBlocked: decision.kind === "blocked"
|
|
66951
|
+
};
|
|
66952
|
+
}
|
|
66953
|
+
function conflictSources(entry) {
|
|
66954
|
+
const names = (entry.orchestration_names ?? []).filter((name) => name);
|
|
66955
|
+
if (names.length > 1) {
|
|
66956
|
+
return `in ${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
|
|
66957
|
+
}
|
|
66958
|
+
if (names.length === 1)
|
|
66959
|
+
return `in ${names[0]}`;
|
|
66960
|
+
const count = entry.orchestration_ids?.length ?? 0;
|
|
66961
|
+
return count > 0 ? `in ${count} orchestrations` : "in its orchestrations";
|
|
66962
|
+
}
|
|
66502
66963
|
function emitJson(report) {
|
|
66503
66964
|
console.log(JSON.stringify(report, null, 2));
|
|
66504
66965
|
}
|
|
@@ -66515,6 +66976,9 @@ function describeSecretsFailure(err) {
|
|
|
66515
66976
|
if (remote && err.status === 401) {
|
|
66516
66977
|
return "could not fetch secrets: your session is invalid — run `brainbase login`";
|
|
66517
66978
|
}
|
|
66979
|
+
if (remote && err.status === 404) {
|
|
66980
|
+
return "could not fetch secrets: the control plane answered 404 — no secrets " + "route on this deployment, no access to this agent, or the agent is " + "pinned to a benchmark thread";
|
|
66981
|
+
}
|
|
66518
66982
|
const where = remote ? "could not fetch secrets from the control plane" : `could not read ${path81.join(LINK_DIR, SECRETS_FILE)}`;
|
|
66519
66983
|
const detail = oneLine(err instanceof Error ? err.message : typeof err === "string" ? err : "");
|
|
66520
66984
|
return detail ? `${where}: ${detail}` : where;
|
|
@@ -66920,7 +67384,7 @@ async function runAgentCreate(cwd2, args) {
|
|
|
66920
67384
|
if (!manifest)
|
|
66921
67385
|
return;
|
|
66922
67386
|
if (manifest.id) {
|
|
66923
|
-
|
|
67387
|
+
failWarn(`This folder already belongs to an agent — ${import_picocolors32.default.bold(manifest.agent.name)} (${import_picocolors32.default.dim(manifest.id)}).`);
|
|
66924
67388
|
f2.info(`If you want to detach it, run ${import_picocolors32.default.cyan("brainbase unlink")} first; or move to a different directory.`);
|
|
66925
67389
|
return;
|
|
66926
67390
|
}
|
|
@@ -66974,9 +67438,9 @@ async function runAgentCreate(cwd2, args) {
|
|
|
66974
67438
|
const body = resolveEntrypoint(cwd2, manifest);
|
|
66975
67439
|
if (body === null) {
|
|
66976
67440
|
if (manifest.entrypoint.file) {
|
|
66977
|
-
|
|
67441
|
+
fail(`Entrypoint file ${import_picocolors32.default.bold(manifest.entrypoint.file)} not found.`);
|
|
66978
67442
|
} else {
|
|
66979
|
-
|
|
67443
|
+
fail("Entrypoint block is empty.");
|
|
66980
67444
|
}
|
|
66981
67445
|
return;
|
|
66982
67446
|
}
|
|
@@ -67000,7 +67464,6 @@ async function runAgentCreate(cwd2, args) {
|
|
|
67000
67464
|
} catch (err) {
|
|
67001
67465
|
createSpinner.stop("Failed.");
|
|
67002
67466
|
handleApiError4(err);
|
|
67003
|
-
process.exitCode = 1;
|
|
67004
67467
|
return;
|
|
67005
67468
|
}
|
|
67006
67469
|
const machineConfigMissing = manifest.machine_kind !== undefined && agent.machine_kind !== manifest.machine_kind;
|
|
@@ -67097,10 +67560,12 @@ async function runAgentCreate(cwd2, args) {
|
|
|
67097
67560
|
manifest = readManifest(cwd2);
|
|
67098
67561
|
let updatedCloud = null;
|
|
67099
67562
|
const hasContent = !!manifest.instructions || manifest.skills.length > 0 || (manifest.mcp ?? []).length > 0 || (manifest.playbooks ?? []).length > 0 || (manifest.evals ?? []).length > 0;
|
|
67563
|
+
let contentUploadFailed = false;
|
|
67100
67564
|
if (hasContent) {
|
|
67101
67565
|
const outgoing = await buildOutgoingComponents(cwd2, manifest, null);
|
|
67102
67566
|
if (outgoing === null) {
|
|
67103
|
-
|
|
67567
|
+
contentUploadFailed = true;
|
|
67568
|
+
failWarn(`Agent created, but local content wasn't uploaded. Fix the issue above and run ${import_picocolors32.default.cyan("brainbase agent push")}.`);
|
|
67104
67569
|
} else if (outgoing.length > 0) {
|
|
67105
67570
|
const pushSpinner = de();
|
|
67106
67571
|
pushSpinner.start("Pushing local content…");
|
|
@@ -67114,10 +67579,11 @@ async function runAgentCreate(cwd2, args) {
|
|
|
67114
67579
|
pushSpinner.stop(`Pushed at revision ${updatedCloud.revision}.`);
|
|
67115
67580
|
} catch (err) {
|
|
67116
67581
|
pushSpinner.stop("Failed.");
|
|
67582
|
+
contentUploadFailed = true;
|
|
67117
67583
|
if (err instanceof ApiError) {
|
|
67118
|
-
|
|
67584
|
+
failWarn(`Agent created and this folder linked, but the content upload failed: ${err.message}. Run ${import_picocolors32.default.cyan("brainbase agent push")} to retry.`);
|
|
67119
67585
|
} else {
|
|
67120
|
-
|
|
67586
|
+
failWarn(`Agent created and this folder linked, but the content upload failed: ${err.message}. Run ${import_picocolors32.default.cyan("brainbase agent push")} to retry.`);
|
|
67121
67587
|
}
|
|
67122
67588
|
}
|
|
67123
67589
|
}
|
|
@@ -67164,15 +67630,18 @@ async function runAgentCreate(cwd2, args) {
|
|
|
67164
67630
|
}
|
|
67165
67631
|
};
|
|
67166
67632
|
writeSyncState(cwd2, state);
|
|
67167
|
-
$e(`Created ${import_picocolors32.default.bold(agent.name)} and linked this folder.`);
|
|
67633
|
+
$e(contentUploadFailed ? `Created ${import_picocolors32.default.bold(agent.name)} and linked this folder, without its local content.` : `Created ${import_picocolors32.default.bold(agent.name)} and linked this folder.`);
|
|
67168
67634
|
await showResultCard({
|
|
67169
|
-
title: "CREATED",
|
|
67170
|
-
tone: "ok",
|
|
67635
|
+
title: contentUploadFailed ? "CREATED (NO CONTENT)" : "CREATED",
|
|
67636
|
+
tone: contentUploadFailed ? "warn" : "ok",
|
|
67171
67637
|
subtitle: link2.tagline ? `${link2.name} — ${link2.tagline}` : link2.name,
|
|
67172
67638
|
meta: [
|
|
67173
67639
|
["slug", link2.slug],
|
|
67174
67640
|
["agent", link2.agent_id],
|
|
67175
|
-
...link2.url ? [["url", link2.url]] : []
|
|
67641
|
+
...link2.url ? [["url", link2.url]] : [],
|
|
67642
|
+
...contentUploadFailed ? [
|
|
67643
|
+
["content", "not uploaded — run `brainbase agent push`"]
|
|
67644
|
+
] : []
|
|
67176
67645
|
]
|
|
67177
67646
|
});
|
|
67178
67647
|
console.log();
|
|
@@ -67239,12 +67708,12 @@ async function pickHarness2(cwd2) {
|
|
|
67239
67708
|
function handleApiError4(err) {
|
|
67240
67709
|
if (err instanceof ApiError) {
|
|
67241
67710
|
if (err.status === 401) {
|
|
67242
|
-
|
|
67711
|
+
fail("Your session is invalid. Run `brainbase login` and try again.");
|
|
67243
67712
|
} else {
|
|
67244
|
-
|
|
67713
|
+
fail(err.message);
|
|
67245
67714
|
}
|
|
67246
67715
|
} else {
|
|
67247
|
-
|
|
67716
|
+
fail(err.message);
|
|
67248
67717
|
}
|
|
67249
67718
|
$e("Aborted.");
|
|
67250
67719
|
}
|
|
@@ -67335,12 +67804,18 @@ async function runAgentList(args) {
|
|
|
67335
67804
|
allowPrompt: !args.json,
|
|
67336
67805
|
announce: !args.json
|
|
67337
67806
|
});
|
|
67338
|
-
const agents = await api.listAgents(org.id, team.id);
|
|
67807
|
+
const { agents, complete, warning } = await api.listAgents(org.id, team.id);
|
|
67808
|
+
if (!complete && warning)
|
|
67809
|
+
console.error(warning);
|
|
67339
67810
|
if (args.json) {
|
|
67340
67811
|
console.log(JSON.stringify(agents, null, 2));
|
|
67341
67812
|
return;
|
|
67342
67813
|
}
|
|
67343
|
-
console.log(formatAgentList(agents, {
|
|
67814
|
+
console.log(formatAgentList(agents, {
|
|
67815
|
+
orgName: org.name,
|
|
67816
|
+
teamName: team.name,
|
|
67817
|
+
complete
|
|
67818
|
+
}));
|
|
67344
67819
|
}
|
|
67345
67820
|
function formatAgentList(agents, labels) {
|
|
67346
67821
|
const lines = [""];
|
|
@@ -67349,6 +67824,8 @@ function formatAgentList(agents, labels) {
|
|
|
67349
67824
|
return lines.join(`
|
|
67350
67825
|
`);
|
|
67351
67826
|
}
|
|
67827
|
+
const count = `${agents.length} agent${agents.length === 1 ? "" : "s"}`;
|
|
67828
|
+
lines.push(` ${import_picocolors34.default.dim(labels.complete ? `${count} in ${labels.orgName} → ${labels.teamName}` : `${count} in ${labels.orgName} → ${labels.teamName} (may be incomplete)`)}`, "");
|
|
67352
67829
|
for (const agent of agents) {
|
|
67353
67830
|
lines.push(` ${import_picocolors34.default.bold(agent.name)} ${import_picocolors34.default.dim(agent.slug)}`);
|
|
67354
67831
|
if (agent.tagline)
|
|
@@ -67738,7 +68215,10 @@ async function disconnect(cwd2, target, args, json) {
|
|
|
67738
68215
|
if (!link2) {
|
|
67739
68216
|
throw new Error("This folder is not linked to any agent. Run `brainbase link` first.");
|
|
67740
68217
|
}
|
|
67741
|
-
if (!json && !
|
|
68218
|
+
if (!json && !autoProceedDestructive(args.yes, {
|
|
68219
|
+
action: `Disconnecting ${target} from ${link2.name}`,
|
|
68220
|
+
flagHint: "Pass --yes to disconnect without a prompt."
|
|
68221
|
+
})) {
|
|
67742
68222
|
const ok = ensureNotCancelled(await se({ message: `Disconnect ${target} from ${link2.name}?` }));
|
|
67743
68223
|
if (!ok) {
|
|
67744
68224
|
f2.info("Nothing changed.");
|
|
@@ -68281,13 +68761,26 @@ var SyncedEdgeSchema = exports_external.object({
|
|
|
68281
68761
|
description: exports_external.string().default(""),
|
|
68282
68762
|
payload_schema: exports_external.record(exports_external.unknown()).default({})
|
|
68283
68763
|
});
|
|
68764
|
+
var SyncedScheduleTriggerSchema = exports_external.object({
|
|
68765
|
+
node_id: exports_external.string(),
|
|
68766
|
+
hash: exports_external.string()
|
|
68767
|
+
});
|
|
68768
|
+
var SyncedOrchestrationMetaSchema = exports_external.object({
|
|
68769
|
+
name: exports_external.string().optional(),
|
|
68770
|
+
description: exports_external.string().optional(),
|
|
68771
|
+
icon: exports_external.string().optional(),
|
|
68772
|
+
icon_color: exports_external.string().optional(),
|
|
68773
|
+
credit_limit: exports_external.number().optional()
|
|
68774
|
+
});
|
|
68284
68775
|
var OrchestrationSyncStateSchema = exports_external.object({
|
|
68285
68776
|
schemaVersion: exports_external.literal(1),
|
|
68286
68777
|
orchestration_id: exports_external.string(),
|
|
68287
68778
|
revision: exports_external.number(),
|
|
68288
68779
|
synced_at: exports_external.string(),
|
|
68289
68780
|
members: exports_external.array(SyncedMemberSchema),
|
|
68290
|
-
edges: exports_external.array(SyncedEdgeSchema)
|
|
68781
|
+
edges: exports_external.array(SyncedEdgeSchema),
|
|
68782
|
+
triggers: exports_external.array(SyncedScheduleTriggerSchema).optional(),
|
|
68783
|
+
meta: SyncedOrchestrationMetaSchema.optional()
|
|
68291
68784
|
});
|
|
68292
68785
|
function orchLinkPath(cwd2) {
|
|
68293
68786
|
return path85.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
|
|
@@ -68629,6 +69122,158 @@ function formatScheduleTriggerLabel(input) {
|
|
|
68629
69122
|
return `schedule ${input.nodeId} (${cron}, ${state})${targetText}`;
|
|
68630
69123
|
}
|
|
68631
69124
|
|
|
69125
|
+
// src/core/orchestration-reconcile.ts
|
|
69126
|
+
import crypto5 from "node:crypto";
|
|
69127
|
+
var SCHEDULE_TRIGGER = "schedule-trigger";
|
|
69128
|
+
function stableJson(value) {
|
|
69129
|
+
if (value == null || typeof value !== "object")
|
|
69130
|
+
return JSON.stringify(value);
|
|
69131
|
+
if (Array.isArray(value))
|
|
69132
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
69133
|
+
const obj = value;
|
|
69134
|
+
return `{${Object.keys(obj).sort().map((key2) => `${JSON.stringify(key2)}:${stableJson(obj[key2])}`).join(",")}}`;
|
|
69135
|
+
}
|
|
69136
|
+
function scheduleTriggerHash(t) {
|
|
69137
|
+
const canonical = {
|
|
69138
|
+
is_active: t.is_active,
|
|
69139
|
+
config: normalizeScheduleTriggerConfig(t.config),
|
|
69140
|
+
targets: t.targets.map((e2) => ({
|
|
69141
|
+
agent: e2.agent,
|
|
69142
|
+
description: e2.description,
|
|
69143
|
+
payload_schema: e2.payload_schema
|
|
69144
|
+
})).sort((a3, b4) => stableJson(a3) < stableJson(b4) ? -1 : 1)
|
|
69145
|
+
};
|
|
69146
|
+
return crypto5.createHash("sha256").update(stableJson(canonical)).digest("hex");
|
|
69147
|
+
}
|
|
69148
|
+
function scheduleTriggerLabel(t) {
|
|
69149
|
+
return formatScheduleTriggerLabel({
|
|
69150
|
+
nodeId: t.node_id,
|
|
69151
|
+
isActive: t.is_active,
|
|
69152
|
+
config: t.config,
|
|
69153
|
+
targets: t.targets.map((e2) => e2.agent)
|
|
69154
|
+
});
|
|
69155
|
+
}
|
|
69156
|
+
function cloudScheduleTriggers(cloud, slugForAgent) {
|
|
69157
|
+
return (cloud.triggers ?? []).filter((t) => t.trigger_type === "schedule").map((t) => ({
|
|
69158
|
+
node_id: t.node_id,
|
|
69159
|
+
is_active: t.is_active ?? false,
|
|
69160
|
+
config: t.config ?? {},
|
|
69161
|
+
targets: t.edges.map((e2) => ({
|
|
69162
|
+
agent: slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id),
|
|
69163
|
+
description: e2.description ?? "",
|
|
69164
|
+
payload_schema: e2.payload_schema ?? {}
|
|
69165
|
+
}))
|
|
69166
|
+
}));
|
|
69167
|
+
}
|
|
69168
|
+
function manifestScheduleTriggers(manifest) {
|
|
69169
|
+
return (manifest?.triggers ?? []).filter((t) => t.type === "schedule").map((t) => ({
|
|
69170
|
+
node_id: t.node_id,
|
|
69171
|
+
is_active: t.is_active ?? false,
|
|
69172
|
+
config: t.config ?? {},
|
|
69173
|
+
targets: t.to.map((e2) => ({
|
|
69174
|
+
agent: e2.agent,
|
|
69175
|
+
description: e2.description ?? "",
|
|
69176
|
+
payload_schema: e2.payload_schema ?? {}
|
|
69177
|
+
}))
|
|
69178
|
+
}));
|
|
69179
|
+
}
|
|
69180
|
+
function decideScheduleTriggerReconcile(input) {
|
|
69181
|
+
const rows = threeWayDiff({
|
|
69182
|
+
local: input.local.map((t) => ({
|
|
69183
|
+
type: SCHEDULE_TRIGGER,
|
|
69184
|
+
slug: t.node_id,
|
|
69185
|
+
hash: scheduleTriggerHash(t)
|
|
69186
|
+
})),
|
|
69187
|
+
lock: (input.baseline ?? []).map((t) => ({
|
|
69188
|
+
type: SCHEDULE_TRIGGER,
|
|
69189
|
+
slug: t.node_id,
|
|
69190
|
+
hash: t.hash,
|
|
69191
|
+
installedPaths: []
|
|
69192
|
+
})),
|
|
69193
|
+
cloud: input.cloud.map((t) => ({
|
|
69194
|
+
type: SCHEDULE_TRIGGER,
|
|
69195
|
+
slug: t.node_id,
|
|
69196
|
+
hash: scheduleTriggerHash(t),
|
|
69197
|
+
files: []
|
|
69198
|
+
}))
|
|
69199
|
+
});
|
|
69200
|
+
return decideCollectionReconcile({
|
|
69201
|
+
rows,
|
|
69202
|
+
type: SCHEDULE_TRIGGER,
|
|
69203
|
+
claims: input.local.length > 0,
|
|
69204
|
+
force: input.force
|
|
69205
|
+
});
|
|
69206
|
+
}
|
|
69207
|
+
function syncedScheduleTriggers(triggers) {
|
|
69208
|
+
return triggers.map((t) => ({
|
|
69209
|
+
node_id: t.node_id,
|
|
69210
|
+
hash: scheduleTriggerHash(t)
|
|
69211
|
+
}));
|
|
69212
|
+
}
|
|
69213
|
+
var ORCH_META_FIELDS = [
|
|
69214
|
+
"name",
|
|
69215
|
+
"description",
|
|
69216
|
+
"icon",
|
|
69217
|
+
"icon_color",
|
|
69218
|
+
"credit_limit"
|
|
69219
|
+
];
|
|
69220
|
+
function metaText(value) {
|
|
69221
|
+
if (value === undefined)
|
|
69222
|
+
return;
|
|
69223
|
+
return value == null ? "" : String(value);
|
|
69224
|
+
}
|
|
69225
|
+
function decideOrchestrationMeta(input) {
|
|
69226
|
+
const meta = input.manifest?.orchestration;
|
|
69227
|
+
if (!meta)
|
|
69228
|
+
return [];
|
|
69229
|
+
const out = [];
|
|
69230
|
+
for (const field of ORCH_META_FIELDS) {
|
|
69231
|
+
const local = metaText(meta[field]);
|
|
69232
|
+
const cloud = metaText(input.cloud[field]) ?? "";
|
|
69233
|
+
if (local === undefined)
|
|
69234
|
+
continue;
|
|
69235
|
+
if (local === cloud)
|
|
69236
|
+
continue;
|
|
69237
|
+
const base2 = input.baseline === undefined ? undefined : metaText(input.baseline[field]) ?? "";
|
|
69238
|
+
let kind;
|
|
69239
|
+
if (base2 === undefined) {
|
|
69240
|
+
kind = "conflict";
|
|
69241
|
+
} else if (local === base2) {
|
|
69242
|
+
kind = "keep";
|
|
69243
|
+
} else if (cloud === base2) {
|
|
69244
|
+
kind = "push";
|
|
69245
|
+
} else {
|
|
69246
|
+
kind = "conflict";
|
|
69247
|
+
}
|
|
69248
|
+
if (kind === "conflict" && input.force)
|
|
69249
|
+
kind = "push";
|
|
69250
|
+
out.push({ field, kind, local, cloud });
|
|
69251
|
+
}
|
|
69252
|
+
return out;
|
|
69253
|
+
}
|
|
69254
|
+
function nextOrchestrationMeta(input) {
|
|
69255
|
+
const kept = new Set(input.decisions.filter((d3) => d3.kind === "keep").map((d3) => d3.field));
|
|
69256
|
+
const out = {};
|
|
69257
|
+
for (const field of ORCH_META_FIELDS) {
|
|
69258
|
+
const value = kept.has(field) ? input.previous?.[field] : input.applied[field];
|
|
69259
|
+
if (value == null)
|
|
69260
|
+
continue;
|
|
69261
|
+
if (field === "credit_limit") {
|
|
69262
|
+
out.credit_limit = typeof value === "number" ? value : Number(value);
|
|
69263
|
+
} else {
|
|
69264
|
+
out[field] = String(value);
|
|
69265
|
+
}
|
|
69266
|
+
}
|
|
69267
|
+
return out;
|
|
69268
|
+
}
|
|
69269
|
+
function syncedOrchestrationMeta(cloud) {
|
|
69270
|
+
return nextOrchestrationMeta({
|
|
69271
|
+
applied: cloud,
|
|
69272
|
+
decisions: [],
|
|
69273
|
+
previous: undefined
|
|
69274
|
+
});
|
|
69275
|
+
}
|
|
69276
|
+
|
|
68632
69277
|
// src/cli/orchestration-pull.ts
|
|
68633
69278
|
function triggersForManifest(triggers, slugFor) {
|
|
68634
69279
|
return triggers.map((trigger) => {
|
|
@@ -68656,7 +69301,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
68656
69301
|
} else if (args.orchestrationId) {
|
|
68657
69302
|
orchId = args.orchestrationId;
|
|
68658
69303
|
} else {
|
|
68659
|
-
|
|
69304
|
+
failWarn("This folder is not linked to any orchestration.");
|
|
68660
69305
|
f2.info(`Run ${import_picocolors42.default.cyan("brainbase orchestration pull <id>")} with an orchestration id,
|
|
68661
69306
|
or ${import_picocolors42.default.cyan("brainbase orchestration list")} to find one.`);
|
|
68662
69307
|
return;
|
|
@@ -68714,13 +69359,15 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
68714
69359
|
const fallbackHarness = args.harness ?? "claude-code";
|
|
68715
69360
|
fs78.mkdirSync(cwd2, { recursive: true });
|
|
68716
69361
|
if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
|
|
68717
|
-
|
|
69362
|
+
fail(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
|
|
68718
69363
|
return;
|
|
68719
69364
|
}
|
|
68720
69365
|
const installedMembers = [];
|
|
69366
|
+
const missingMembers = [];
|
|
68721
69367
|
for (const m3 of cloud.members) {
|
|
68722
69368
|
if (!m3.manifest) {
|
|
68723
|
-
|
|
69369
|
+
missingMembers.push(m3.slug);
|
|
69370
|
+
failWarn(`Skipping member ${m3.slug}: server did not return a manifest.`);
|
|
68724
69371
|
continue;
|
|
68725
69372
|
}
|
|
68726
69373
|
const slug = slugFor(m3.agent_id);
|
|
@@ -68755,7 +69402,8 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
68755
69402
|
});
|
|
68756
69403
|
} catch (err) {
|
|
68757
69404
|
memberSp.stop(`Failed to install ${slug}.`);
|
|
68758
|
-
|
|
69405
|
+
missingMembers.push(slug);
|
|
69406
|
+
fail(err.message);
|
|
68759
69407
|
}
|
|
68760
69408
|
}
|
|
68761
69409
|
const manifestTriggers = triggersForManifest(cloud.triggers ?? [], slugFor);
|
|
@@ -68806,8 +69454,15 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
68806
69454
|
to_slug: slugFor(e2.to_agent_id),
|
|
68807
69455
|
description: e2.description ?? "",
|
|
68808
69456
|
payload_schema: e2.payload_schema ?? {}
|
|
68809
|
-
}))
|
|
69457
|
+
})),
|
|
69458
|
+
triggers: syncedScheduleTriggers(cloudScheduleTriggers(cloud, (agentId, fallback) => slugFor(agentId) || fallback)),
|
|
69459
|
+
meta: syncedOrchestrationMeta(cloud)
|
|
68810
69460
|
});
|
|
69461
|
+
if (missingMembers.length > 0) {
|
|
69462
|
+
f2.warn(`${installedMembers.length} of ${cloud.members.length} members landed in ${path87.basename(cwd2)}/ and the orchestration is linked, but ${missingMembers.length === 1 ? "this member is" : "these members are"} missing: ${missingMembers.map((s3) => import_picocolors42.default.bold(s3)).join(", ")}. ${import_picocolors42.default.cyan("brainbase orchestration push")} will refuse until ${missingMembers.length === 1 ? "it" : "they"} ${missingMembers.length === 1 ? "is" : "are"} pulled, so re-run this after fixing the cause.`);
|
|
69463
|
+
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path87.basename(cwd2)}/ ${import_picocolors42.default.dim(`(${installedMembers.length}/${cloud.members.length} members — incomplete)`)}.`);
|
|
69464
|
+
return;
|
|
69465
|
+
}
|
|
68811
69466
|
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path87.basename(cwd2)}/ ${import_picocolors42.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
|
|
68812
69467
|
}
|
|
68813
69468
|
function handleApiError5(err) {
|
|
@@ -68890,6 +69545,11 @@ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
|
68890
69545
|
}
|
|
68891
69546
|
|
|
68892
69547
|
// src/cli/orchestration-push.ts
|
|
69548
|
+
function joinList(items) {
|
|
69549
|
+
if (items.length <= 1)
|
|
69550
|
+
return items[0] ?? "";
|
|
69551
|
+
return `${items.slice(0, -1).join(", ")} and ${items[items.length - 1]}`;
|
|
69552
|
+
}
|
|
68893
69553
|
function findUnpushableMembers(cwd2, members) {
|
|
68894
69554
|
const blocked = [];
|
|
68895
69555
|
for (const m3 of members) {
|
|
@@ -68922,12 +69582,12 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
68922
69582
|
banner("orchestration push — recursively push each member, then update the graph");
|
|
68923
69583
|
const link2 = readOrchLink(cwd2);
|
|
68924
69584
|
if (!link2) {
|
|
68925
|
-
|
|
69585
|
+
failWarn("This folder is not linked to any orchestration.");
|
|
68926
69586
|
f2.info(`Run ${import_picocolors43.default.cyan("brainbase orchestration pull <id>")} first.`);
|
|
68927
69587
|
return;
|
|
68928
69588
|
}
|
|
68929
69589
|
if (!hasOrchManifest(cwd2)) {
|
|
68930
|
-
|
|
69590
|
+
failWarn(`No ${import_picocolors43.default.bold(ORCH_MANIFEST_FILE)} here.`);
|
|
68931
69591
|
f2.info(`Run ${import_picocolors43.default.cyan("brainbase orchestration pull")} to materialise the manifest before pushing.`);
|
|
68932
69592
|
return;
|
|
68933
69593
|
}
|
|
@@ -68972,6 +69632,95 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
68972
69632
|
return;
|
|
68973
69633
|
}
|
|
68974
69634
|
}
|
|
69635
|
+
const lock = readOrchSyncState(cwd2);
|
|
69636
|
+
const fetchSpinner = de();
|
|
69637
|
+
fetchSpinner.start("Fetching cloud state…");
|
|
69638
|
+
let cloud;
|
|
69639
|
+
try {
|
|
69640
|
+
cloud = await api.getOrchestration(link2.orchestration_id);
|
|
69641
|
+
fetchSpinner.stop(`Cloud revision ${cloud.revision}.`);
|
|
69642
|
+
} catch (err) {
|
|
69643
|
+
fetchSpinner.stop("Failed.");
|
|
69644
|
+
handleApiError6(err);
|
|
69645
|
+
process.exitCode = 1;
|
|
69646
|
+
return;
|
|
69647
|
+
}
|
|
69648
|
+
const agentIdToSlug = new Map([...slugToAgentId.entries()].map(([slug, id]) => [id, slug]));
|
|
69649
|
+
const slugForAgent = (agentId, fallback) => agentIdToSlug.get(agentId) ?? fallback;
|
|
69650
|
+
const localTriggers = manifestScheduleTriggers(manifest);
|
|
69651
|
+
const cloudTriggers = cloudScheduleTriggers(cloud, slugForAgent);
|
|
69652
|
+
const triggerDecision = decideScheduleTriggerReconcile({
|
|
69653
|
+
local: localTriggers,
|
|
69654
|
+
cloud: cloudTriggers,
|
|
69655
|
+
baseline: lock?.triggers,
|
|
69656
|
+
force: !!args.force
|
|
69657
|
+
});
|
|
69658
|
+
const triggerByNode = new Map([...cloudTriggers, ...localTriggers].map((t) => [t.node_id, t]));
|
|
69659
|
+
const labelFor = (nodeId) => {
|
|
69660
|
+
const t = triggerByNode.get(nodeId);
|
|
69661
|
+
return t ? scheduleTriggerLabel(t) : nodeId;
|
|
69662
|
+
};
|
|
69663
|
+
const metaDecisions = decideOrchestrationMeta({
|
|
69664
|
+
manifest,
|
|
69665
|
+
cloud,
|
|
69666
|
+
baseline: lock?.meta,
|
|
69667
|
+
force: !!args.force
|
|
69668
|
+
});
|
|
69669
|
+
const metaConflicts = metaDecisions.filter((d3) => d3.kind === "conflict");
|
|
69670
|
+
const metaOverwrites = metaDecisions.filter((d3) => d3.kind === "push");
|
|
69671
|
+
const metaKept = metaDecisions.filter((d3) => d3.kind === "keep");
|
|
69672
|
+
const blockedTriggers = triggerDecision.kind === "blocked" ? triggerDecision : null;
|
|
69673
|
+
if (blockedTriggers || metaConflicts.length > 0) {
|
|
69674
|
+
const pullTargets = [];
|
|
69675
|
+
const forceEffects = [];
|
|
69676
|
+
if (blockedTriggers) {
|
|
69677
|
+
const { unseen, cloudModified, staleArchives } = blockedTriggers;
|
|
69678
|
+
f2.error(unseen.length > 0 ? "Cannot push: the cloud has schedule triggers this folder has never seen." : "Cannot push: schedule triggers changed both locally and in the cloud.");
|
|
69679
|
+
for (const nodeId of unseen) {
|
|
69680
|
+
console.error(` ${import_picocolors43.default.red("!")} ${import_picocolors43.default.bold(labelFor(nodeId))} ${import_picocolors43.default.dim("(only in the cloud — pushing would delete it)")}`);
|
|
69681
|
+
}
|
|
69682
|
+
for (const nodeId of cloudModified) {
|
|
69683
|
+
console.error(` ${import_picocolors43.default.red("!")} ${import_picocolors43.default.bold(labelFor(nodeId))} ${import_picocolors43.default.dim("(edited in the cloud — pushing would overwrite that edit)")}`);
|
|
69684
|
+
}
|
|
69685
|
+
for (const nodeId of staleArchives) {
|
|
69686
|
+
console.error(` ${import_picocolors43.default.red("!")} ${import_picocolors43.default.bold(labelFor(nodeId))} ${import_picocolors43.default.dim("(deleted here, edited in the cloud since — pushing would delete that edit)")}`);
|
|
69687
|
+
}
|
|
69688
|
+
const total = unseen.length + cloudModified.length + staleArchives.length;
|
|
69689
|
+
pullTargets.push(`${total} schedule trigger${total === 1 ? "" : "s"}`);
|
|
69690
|
+
forceEffects.push("make your local schedule triggers authoritative (deleting the cloud ones above)");
|
|
69691
|
+
}
|
|
69692
|
+
if (metaConflicts.length > 0) {
|
|
69693
|
+
f2.error("Cannot push: orchestration metadata changed both locally and in the cloud.");
|
|
69694
|
+
for (const d3 of metaConflicts) {
|
|
69695
|
+
console.error(` ${import_picocolors43.default.red("!")} ${import_picocolors43.default.bold(d3.field)} ${import_picocolors43.default.dim(`(local "${d3.local}" vs cloud "${d3.cloud}")`)}`);
|
|
69696
|
+
}
|
|
69697
|
+
if (!lock?.meta) {
|
|
69698
|
+
f2.info("This checkout has no metadata baseline, so the CLI cannot tell which side changed.");
|
|
69699
|
+
}
|
|
69700
|
+
const fields = metaConflicts.map((d3) => d3.field);
|
|
69701
|
+
pullTargets.push(`${fields.length} metadata field${fields.length === 1 ? "" : "s"}`);
|
|
69702
|
+
forceEffects.push(`overwrite the cloud's ${joinList(fields)} with the value${fields.length === 1 ? "" : "s"} in ${ORCH_MANIFEST_FILE}`);
|
|
69703
|
+
}
|
|
69704
|
+
f2.info(`Run ${import_picocolors43.default.cyan("brainbase orchestration pull")} to bring the cloud's ${joinList(pullTargets)} into ${import_picocolors43.default.bold(ORCH_MANIFEST_FILE)}, then push.`);
|
|
69705
|
+
f2.info(`Or ${import_picocolors43.default.cyan("brainbase orchestration push --force")} to ${joinList(forceEffects)}.${forceEffects.length > 1 ? " One flag, both of those — it settles everything listed above, not whichever conflict you had in mind." : ""}`);
|
|
69706
|
+
process.exitCode = 1;
|
|
69707
|
+
return;
|
|
69708
|
+
}
|
|
69709
|
+
if (triggerDecision.kind === "skip") {
|
|
69710
|
+
graph.triggers = cloudTriggers.map((t) => ({
|
|
69711
|
+
node_id: t.node_id,
|
|
69712
|
+
type: "schedule",
|
|
69713
|
+
is_active: t.is_active,
|
|
69714
|
+
config: t.config,
|
|
69715
|
+
edges: t.targets.map((e2) => ({
|
|
69716
|
+
to_agent_id: slugToAgentId.get(e2.agent) ?? e2.agent,
|
|
69717
|
+
description: e2.description,
|
|
69718
|
+
payload_schema: e2.payload_schema
|
|
69719
|
+
}))
|
|
69720
|
+
}));
|
|
69721
|
+
f2.warn(`${cloudTriggers.length} cloud schedule trigger${cloudTriggers.length === 1 ? "" : "s"} ${cloudTriggers.length === 1 ? "is" : "are"} not in ${import_picocolors43.default.bold(ORCH_MANIFEST_FILE)} and will be left untouched. Run ${import_picocolors43.default.cyan("brainbase orchestration pull")} to manage ${cloudTriggers.length === 1 ? "it" : "them"} from here.`);
|
|
69722
|
+
}
|
|
69723
|
+
const triggerDeletes = triggerDecision.kind === "reconcile" ? triggerDecision.archives : [];
|
|
68975
69724
|
const plan = [""];
|
|
68976
69725
|
plan.push(` ${import_picocolors43.default.bold(link2.name)} ${import_picocolors43.default.dim(`(${link2.orchestration_id})`)}`);
|
|
68977
69726
|
plan.push(` ${import_picocolors43.default.dim(`${manifest.members.length} member${manifest.members.length === 1 ? "" : "s"}, ${manifest.edges.length} edge${manifest.edges.length === 1 ? "" : "s"}, ${graph.triggers.length} trigger${graph.triggers.length === 1 ? "" : "s"}`)}`);
|
|
@@ -68983,12 +69732,34 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
68983
69732
|
}
|
|
68984
69733
|
plan.push("");
|
|
68985
69734
|
}
|
|
69735
|
+
if (triggerDeletes.length) {
|
|
69736
|
+
plan.push(` ${import_picocolors43.default.bold("schedule triggers this push will delete")} ${import_picocolors43.default.dim(`(${triggerDeletes.length})`)}`);
|
|
69737
|
+
for (const nodeId of triggerDeletes) {
|
|
69738
|
+
plan.push(` ${import_picocolors43.default.yellow("⨯")} ${labelFor(nodeId)}`);
|
|
69739
|
+
}
|
|
69740
|
+
plan.push("");
|
|
69741
|
+
}
|
|
69742
|
+
if (metaOverwrites.length) {
|
|
69743
|
+
plan.push(` ${import_picocolors43.default.bold("orchestration metadata this push will overwrite")}`);
|
|
69744
|
+
for (const m3 of metaOverwrites) {
|
|
69745
|
+
plan.push(` ${import_picocolors43.default.yellow("⤒")} ${import_picocolors43.default.bold(m3.field)} ${import_picocolors43.default.dim(`cloud "${m3.cloud}" → local "${m3.local}"`)}`);
|
|
69746
|
+
}
|
|
69747
|
+
plan.push("");
|
|
69748
|
+
}
|
|
69749
|
+
if (metaKept.length) {
|
|
69750
|
+
plan.push(` ${import_picocolors43.default.bold("orchestration metadata changed in the cloud")}`);
|
|
69751
|
+
for (const m3 of metaKept) {
|
|
69752
|
+
plan.push(` ${import_picocolors43.default.cyan("=")} ${import_picocolors43.default.bold(m3.field)} ${import_picocolors43.default.dim(`keeping cloud "${m3.cloud}"; ${import_picocolors43.default.bold(ORCH_MANIFEST_FILE)} still has "${m3.local}"`)}`);
|
|
69753
|
+
}
|
|
69754
|
+
plan.push(` ${import_picocolors43.default.dim(`run ${import_picocolors43.default.cyan("brainbase orchestration pull")} to bring ${metaKept.length === 1 ? "it" : "them"} into the file`)}`);
|
|
69755
|
+
plan.push("");
|
|
69756
|
+
}
|
|
68986
69757
|
console.log(plan.join(`
|
|
68987
69758
|
`));
|
|
68988
69759
|
if (!autoProceed(args.yes)) {
|
|
68989
69760
|
const ok = await se({
|
|
68990
|
-
message: args.graphOnly ? "Push graph (members, edges + triggers) only?" : "Push each member, then update the graph?",
|
|
68991
|
-
initialValue:
|
|
69761
|
+
message: triggerDeletes.length ? `Push, deleting ${triggerDeletes.length} schedule trigger${triggerDeletes.length === 1 ? "" : "s"}?` : args.graphOnly ? "Push graph (members, edges + triggers) only?" : "Push each member, then update the graph?",
|
|
69762
|
+
initialValue: triggerDeletes.length === 0
|
|
68992
69763
|
});
|
|
68993
69764
|
if (!ensureNotCancelled(ok)) {
|
|
68994
69765
|
$e("Aborted.");
|
|
@@ -69015,16 +69786,22 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
69015
69786
|
}
|
|
69016
69787
|
}
|
|
69017
69788
|
}
|
|
69789
|
+
const keptFields = new Set(metaKept.map((d3) => d3.field));
|
|
69790
|
+
const metaField = (field) => {
|
|
69791
|
+
const value = manifest.orchestration[field];
|
|
69792
|
+
if (value === undefined || keptFields.has(field))
|
|
69793
|
+
return {};
|
|
69794
|
+
return { [field]: value };
|
|
69795
|
+
};
|
|
69018
69796
|
const sp = de();
|
|
69019
69797
|
sp.start("Updating orchestration graph…");
|
|
69020
|
-
const lock = readOrchSyncState(cwd2);
|
|
69021
69798
|
try {
|
|
69022
69799
|
const updated = await api.updateOrchestration(link2.orchestration_id, {
|
|
69023
|
-
name
|
|
69024
|
-
description
|
|
69025
|
-
icon
|
|
69026
|
-
icon_color
|
|
69027
|
-
credit_limit
|
|
69800
|
+
...metaField("name"),
|
|
69801
|
+
...metaField("description"),
|
|
69802
|
+
...metaField("icon"),
|
|
69803
|
+
...metaField("icon_color"),
|
|
69804
|
+
...metaField("credit_limit"),
|
|
69028
69805
|
members: graph.memberIds,
|
|
69029
69806
|
edges: graph.edges,
|
|
69030
69807
|
triggers: graph.triggers,
|
|
@@ -69046,7 +69823,13 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
69046
69823
|
to_slug: e2.to_slug ?? e2.to_agent_id,
|
|
69047
69824
|
description: e2.description ?? "",
|
|
69048
69825
|
payload_schema: e2.payload_schema ?? {}
|
|
69049
|
-
}))
|
|
69826
|
+
})),
|
|
69827
|
+
triggers: triggerDecision.kind === "skip" ? lock?.triggers ?? [] : syncedScheduleTriggers(cloudScheduleTriggers(updated, slugForAgent)),
|
|
69828
|
+
meta: nextOrchestrationMeta({
|
|
69829
|
+
applied: updated,
|
|
69830
|
+
decisions: metaDecisions,
|
|
69831
|
+
previous: lock?.meta
|
|
69832
|
+
})
|
|
69050
69833
|
});
|
|
69051
69834
|
$e(`Pushed ${link2.name} at revision ${updated.revision}.`);
|
|
69052
69835
|
} catch (err) {
|
|
@@ -69078,7 +69861,7 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
69078
69861
|
banner("orchestration status — what changed locally, remotely, both");
|
|
69079
69862
|
const link2 = readOrchLink(cwd2);
|
|
69080
69863
|
if (!link2) {
|
|
69081
|
-
|
|
69864
|
+
failWarn("This folder is not linked to any orchestration.");
|
|
69082
69865
|
f2.info(`Run ${import_picocolors44.default.cyan("brainbase orchestration pull <id>")} first.`);
|
|
69083
69866
|
return;
|
|
69084
69867
|
}
|
|
@@ -69126,8 +69909,8 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
69126
69909
|
}
|
|
69127
69910
|
lines.push("");
|
|
69128
69911
|
}
|
|
69129
|
-
const cloudEdgeKey = (e2) => `${slugForAgent(e2.from_agent_id, e2.from_slug ?? e2.from_agent_id)}->${slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id)}|${e2.description ?? ""}|${
|
|
69130
|
-
const localEdgeKey = (e2) => `${e2.from}->${e2.to}|${e2.description ?? ""}|${
|
|
69912
|
+
const cloudEdgeKey = (e2) => `${slugForAgent(e2.from_agent_id, e2.from_slug ?? e2.from_agent_id)}->${slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id)}|${e2.description ?? ""}|${stableJson2(e2.payload_schema ?? {})}|${stableJson2(e2.settings ?? {})}`;
|
|
69913
|
+
const localEdgeKey = (e2) => `${e2.from}->${e2.to}|${e2.description ?? ""}|${stableJson2(e2.payload_schema ?? {})}|${stableJson2(e2.settings ?? {})}`;
|
|
69131
69914
|
const cloudEdges = new Map;
|
|
69132
69915
|
for (const e2 of cloud.edges)
|
|
69133
69916
|
cloudEdges.set(cloudEdgeKey(e2), true);
|
|
@@ -69144,46 +69927,74 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
69144
69927
|
lines.push(` ${import_picocolors44.default.cyan("← pull")} added on cloud: ${k3}`);
|
|
69145
69928
|
lines.push("");
|
|
69146
69929
|
}
|
|
69147
|
-
const
|
|
69148
|
-
|
|
69149
|
-
|
|
69150
|
-
|
|
69151
|
-
|
|
69152
|
-
nodeId: t.node_id,
|
|
69153
|
-
isActive: t.is_active ?? false,
|
|
69154
|
-
config: t.config,
|
|
69155
|
-
targets: t.edges.map((e2) => slugForAgent(e2.to_agent_id, e2.to_slug ?? e2.to_agent_id))
|
|
69930
|
+
const metaDecisions = decideOrchestrationMeta({
|
|
69931
|
+
manifest: localManifest,
|
|
69932
|
+
cloud,
|
|
69933
|
+
baseline: lock?.meta,
|
|
69934
|
+
force: false
|
|
69156
69935
|
});
|
|
69157
|
-
|
|
69158
|
-
|
|
69159
|
-
|
|
69936
|
+
if (metaDecisions.length) {
|
|
69937
|
+
lines.push(` ${import_picocolors44.default.bold("orchestration metadata")}`);
|
|
69938
|
+
for (const m3 of metaDecisions) {
|
|
69939
|
+
if (m3.kind === "push") {
|
|
69940
|
+
lines.push(` ${import_picocolors44.default.yellow("→ push")} ${import_picocolors44.default.bold(m3.field)}: cloud ${import_picocolors44.default.dim(`"${m3.cloud}"`)} → local ${import_picocolors44.default.dim(`"${m3.local}"`)}`);
|
|
69941
|
+
} else if (m3.kind === "keep") {
|
|
69942
|
+
lines.push(` ${import_picocolors44.default.cyan("← pull")} ${import_picocolors44.default.bold(m3.field)}: changed in the cloud to ${import_picocolors44.default.dim(`"${m3.cloud}"`)}; push leaves it alone ${import_picocolors44.default.dim(`(yaml still has "${m3.local}")`)}`);
|
|
69943
|
+
} else {
|
|
69944
|
+
lines.push(` ${import_picocolors44.default.red("! conflict")} ${import_picocolors44.default.bold(m3.field)}: local ${import_picocolors44.default.dim(`"${m3.local}"`)} vs cloud ${import_picocolors44.default.dim(`"${m3.cloud}"`)} — push refuses until you pull or ${import_picocolors44.default.cyan("--force")}`);
|
|
69945
|
+
}
|
|
69946
|
+
}
|
|
69947
|
+
lines.push(` ${import_picocolors44.default.dim("fields the manifest omits, and fields only the cloud changed, are left alone")}`);
|
|
69948
|
+
lines.push("");
|
|
69949
|
+
}
|
|
69950
|
+
const cloudTriggers = cloudScheduleTriggers(cloud, slugForAgent);
|
|
69951
|
+
const localTriggers = manifestScheduleTriggers(localManifest);
|
|
69952
|
+
const triggerPlan = decideScheduleTriggerReconcile({
|
|
69953
|
+
local: localTriggers,
|
|
69954
|
+
cloud: cloudTriggers,
|
|
69955
|
+
baseline: lock?.triggers,
|
|
69956
|
+
force: false
|
|
69957
|
+
});
|
|
69958
|
+
const triggerByNode = new Map([...cloudTriggers, ...localTriggers].map((t) => [t.node_id, t]));
|
|
69959
|
+
const triggerLabel = (nodeId) => {
|
|
69960
|
+
const t = triggerByNode.get(nodeId);
|
|
69961
|
+
return t ? scheduleTriggerLabel(t) : nodeId;
|
|
69160
69962
|
};
|
|
69161
|
-
const
|
|
69162
|
-
|
|
69163
|
-
|
|
69164
|
-
|
|
69165
|
-
|
|
69963
|
+
const localNodes = new Set(localTriggers.map((t) => t.node_id));
|
|
69964
|
+
const cloudByNode = new Map(cloudTriggers.map((t) => [t.node_id, t]));
|
|
69965
|
+
const triggersToPush = localTriggers.filter((t) => {
|
|
69966
|
+
const remote = cloudByNode.get(t.node_id);
|
|
69967
|
+
return !remote || scheduleTriggerHash(remote) !== scheduleTriggerHash(t);
|
|
69166
69968
|
});
|
|
69167
|
-
const
|
|
69168
|
-
|
|
69169
|
-
|
|
69170
|
-
|
|
69969
|
+
const triggersToPull = cloudTriggers.filter((t) => !localNodes.has(t.node_id));
|
|
69970
|
+
const triggerDeletes = triggerPlan.kind === "reconcile" ? triggerPlan.archives : [];
|
|
69971
|
+
if (triggersToPush.length || triggersToPull.length) {
|
|
69972
|
+
lines.push(` ${import_picocolors44.default.bold("schedule triggers")}`);
|
|
69973
|
+
for (const t of triggersToPush) {
|
|
69974
|
+
lines.push(` ${import_picocolors44.default.yellow("→ push")} added/changed in yaml: ${scheduleTriggerLabel(t)}`);
|
|
69171
69975
|
}
|
|
69172
|
-
|
|
69173
|
-
|
|
69174
|
-
|
|
69175
|
-
if (t.type === "schedule") {
|
|
69176
|
-
localTriggers.set(localTriggerKey(t), localTriggerLabel(t));
|
|
69976
|
+
for (const t of triggersToPull) {
|
|
69977
|
+
const doomed = triggerDeletes.includes(t.node_id);
|
|
69978
|
+
lines.push(doomed ? ` ${import_picocolors44.default.red("⨯ push deletes")} ${scheduleTriggerLabel(t)}` : ` ${import_picocolors44.default.cyan("← pull")} only on cloud: ${scheduleTriggerLabel(t)}`);
|
|
69177
69979
|
}
|
|
69980
|
+
lines.push("");
|
|
69178
69981
|
}
|
|
69179
|
-
|
|
69180
|
-
|
|
69181
|
-
|
|
69182
|
-
|
|
69183
|
-
|
|
69184
|
-
|
|
69185
|
-
|
|
69186
|
-
|
|
69982
|
+
if (triggerPlan.kind === "blocked") {
|
|
69983
|
+
lines.push(` ${import_picocolors44.default.bold(import_picocolors44.default.red("schedule triggers: push blocked"))}`);
|
|
69984
|
+
for (const nodeId of triggerPlan.unseen) {
|
|
69985
|
+
lines.push(` ${import_picocolors44.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors44.default.dim("— only in the cloud; pushing would delete it")}`);
|
|
69986
|
+
}
|
|
69987
|
+
for (const nodeId of triggerPlan.cloudModified) {
|
|
69988
|
+
lines.push(` ${import_picocolors44.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors44.default.dim("— edited in the cloud; pushing would overwrite that edit")}`);
|
|
69989
|
+
}
|
|
69990
|
+
for (const nodeId of triggerPlan.staleArchives) {
|
|
69991
|
+
lines.push(` ${import_picocolors44.default.red("!")} ${triggerLabel(nodeId)} ${import_picocolors44.default.dim("— deleted here, edited in the cloud since; pushing would delete that edit")}`);
|
|
69992
|
+
}
|
|
69993
|
+
lines.push(` ${import_picocolors44.default.dim("run")} ${import_picocolors44.default.cyan("brainbase orchestration pull")} ${import_picocolors44.default.dim("first")}`);
|
|
69994
|
+
lines.push("");
|
|
69995
|
+
} else if (triggerPlan.kind === "skip") {
|
|
69996
|
+
const left = untouchedRows(triggerPlan);
|
|
69997
|
+
lines.push(` ${import_picocolors44.default.dim(`${left.length} cloud schedule trigger${left.length === 1 ? "" : "s"} not managed by this manifest — push leaves ${left.length === 1 ? "it" : "them"} untouched`)}`);
|
|
69187
69998
|
lines.push("");
|
|
69188
69999
|
}
|
|
69189
70000
|
const lockByAgentId = new Map((lock?.members ?? []).map((m3) => [m3.agent_id, m3]));
|
|
@@ -69219,7 +70030,7 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
69219
70030
|
lines.push(` ${import_picocolors44.default.cyan("← pull")} cloud changed since last pull: ${import_picocolors44.default.dim(`lock ${lock.revision} → cloud ${cloud.revision}`)}`);
|
|
69220
70031
|
lines.push("");
|
|
69221
70032
|
}
|
|
69222
|
-
if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !
|
|
70033
|
+
if (!membersAdded.length && !membersRemoved.length && !edgesAdded.length && !edgesRemoved.length && !triggersToPush.length && !triggersToPull.length && !metaDecisions.length && !memberDrift.length && !revisionDrift) {
|
|
69223
70034
|
lines.push(` ${import_picocolors44.default.green("✓")} everything is in sync`);
|
|
69224
70035
|
lines.push("");
|
|
69225
70036
|
console.log(lines.join(`
|
|
@@ -69231,13 +70042,13 @@ async function runOrchestrationStatus(cwd2) {
|
|
|
69231
70042
|
console.log(lines.join(`
|
|
69232
70043
|
`));
|
|
69233
70044
|
}
|
|
69234
|
-
function
|
|
70045
|
+
function stableJson2(value) {
|
|
69235
70046
|
if (value == null || typeof value !== "object")
|
|
69236
70047
|
return JSON.stringify(value);
|
|
69237
70048
|
if (Array.isArray(value))
|
|
69238
|
-
return `[${value.map(
|
|
70049
|
+
return `[${value.map(stableJson2).join(",")}]`;
|
|
69239
70050
|
const obj = value;
|
|
69240
|
-
return `{${Object.keys(obj).sort().map((key2) => `${JSON.stringify(key2)}:${
|
|
70051
|
+
return `{${Object.keys(obj).sort().map((key2) => `${JSON.stringify(key2)}:${stableJson2(obj[key2])}`).join(",")}}`;
|
|
69241
70052
|
}
|
|
69242
70053
|
|
|
69243
70054
|
// src/cli/orchestration-list.ts
|
|
@@ -69343,7 +70154,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69343
70154
|
banner("orchestration add-agent — create a member agent and wire it into the graph");
|
|
69344
70155
|
const link2 = readOrchLink(cwd2);
|
|
69345
70156
|
if (!link2 || !hasOrchManifest(cwd2)) {
|
|
69346
|
-
|
|
70157
|
+
failWarn("This folder is not a linked orchestration.");
|
|
69347
70158
|
f2.info(`Run ${import_picocolors46.default.cyan("brainbase orchestration pull <id>")} first.`);
|
|
69348
70159
|
return;
|
|
69349
70160
|
}
|
|
@@ -69351,7 +70162,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69351
70162
|
try {
|
|
69352
70163
|
manifest = readOrchManifest(cwd2);
|
|
69353
70164
|
} catch (err) {
|
|
69354
|
-
|
|
70165
|
+
fail(err.message);
|
|
69355
70166
|
return;
|
|
69356
70167
|
}
|
|
69357
70168
|
let name = args.name?.trim();
|
|
@@ -69377,7 +70188,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69377
70188
|
try {
|
|
69378
70189
|
payloadSchema = parseEdgeSchema(args.schema);
|
|
69379
70190
|
} catch (err) {
|
|
69380
|
-
|
|
70191
|
+
fail(err.message);
|
|
69381
70192
|
return;
|
|
69382
70193
|
}
|
|
69383
70194
|
let orgId = args.orgId;
|
|
@@ -69394,14 +70205,14 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69394
70205
|
const resolved = resolveOrgIdForGroup(link2.group_id, orgsWithTeams);
|
|
69395
70206
|
if (!resolved) {
|
|
69396
70207
|
sp.stop("Failed.");
|
|
69397
|
-
|
|
70208
|
+
fail(`Could not find an org that owns group ${import_picocolors46.default.bold(link2.group_id)}. ` + `Pass ${import_picocolors46.default.cyan("--org <id>")} explicitly.`);
|
|
69398
70209
|
return;
|
|
69399
70210
|
}
|
|
69400
70211
|
orgId = resolved;
|
|
69401
70212
|
sp.stop("Resolved org.");
|
|
69402
70213
|
} catch (err) {
|
|
69403
70214
|
sp.stop("Failed.");
|
|
69404
|
-
|
|
70215
|
+
fail(err.message);
|
|
69405
70216
|
return;
|
|
69406
70217
|
}
|
|
69407
70218
|
}
|
|
@@ -69434,7 +70245,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69434
70245
|
try {
|
|
69435
70246
|
updated = mergeMemberAndEdges(manifest, { slug, name, from, to: to2, description, payloadSchema });
|
|
69436
70247
|
} catch (err) {
|
|
69437
|
-
|
|
70248
|
+
fail(err.message);
|
|
69438
70249
|
return;
|
|
69439
70250
|
}
|
|
69440
70251
|
const dest = memberDir(cwd2, slug);
|
|
@@ -69452,7 +70263,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
69452
70263
|
try {
|
|
69453
70264
|
fs79.rmSync(dest, { recursive: true, force: true });
|
|
69454
70265
|
} catch {}
|
|
69455
|
-
|
|
70266
|
+
fail(`Failed to create ${slug}: ${err.message}`);
|
|
69456
70267
|
return;
|
|
69457
70268
|
}
|
|
69458
70269
|
writeOrchManifest(cwd2, updated);
|
|
@@ -69468,12 +70279,12 @@ var import_picocolors47 = __toESM(require_picocolors(), 1);
|
|
|
69468
70279
|
async function runOrchestrationCreate(cwd2, args) {
|
|
69469
70280
|
banner("orchestration create — claim a brainbase-orchestration.yaml");
|
|
69470
70281
|
if (readOrchLink(cwd2)) {
|
|
69471
|
-
|
|
70282
|
+
failWarn("This folder is already linked to an orchestration.");
|
|
69472
70283
|
f2.info(`Run ${import_picocolors47.default.cyan("brainbase orchestration push")} to update it.`);
|
|
69473
70284
|
return;
|
|
69474
70285
|
}
|
|
69475
70286
|
if (!hasOrchManifest(cwd2)) {
|
|
69476
|
-
|
|
70287
|
+
failWarn(`No ${import_picocolors47.default.bold(ORCH_MANIFEST_FILE)} here.`);
|
|
69477
70288
|
f2.info(`Create one, or pull an existing orchestration first.`);
|
|
69478
70289
|
return;
|
|
69479
70290
|
}
|
|
@@ -69612,7 +70423,8 @@ async function runOrchestration(cwd2, sub, args, opts) {
|
|
|
69612
70423
|
case "push":
|
|
69613
70424
|
await runOrchestrationPush(cwd2, {
|
|
69614
70425
|
yes: opts.yes,
|
|
69615
|
-
graphOnly: opts.graphOnly
|
|
70426
|
+
graphOnly: opts.graphOnly,
|
|
70427
|
+
force: opts.force
|
|
69616
70428
|
});
|
|
69617
70429
|
return;
|
|
69618
70430
|
case "status":
|
|
@@ -69664,7 +70476,7 @@ function printHelp3() {
|
|
|
69664
70476
|
out.push(` ${import_picocolors48.default.bold("Flags")}`);
|
|
69665
70477
|
out.push(` ${import_picocolors48.default.dim("--yes, -y")} skip confirmations`);
|
|
69666
70478
|
out.push(` ${import_picocolors48.default.dim("--harness <id>")} harness for newly-created member folders (default claude-code)`);
|
|
69667
|
-
out.push(` ${import_picocolors48.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`);
|
|
70479
|
+
out.push(` ${import_picocolors48.default.dim("--graph-only")} for push: only update members + edges, skip per-member push`, ` ${import_picocolors48.default.dim("--force")} for push: settle every conflict in your file's favour — deletes cloud schedule`, ` triggers this folder has never seen, and overwrites cloud-side edits to`, ` name, description, icon, icon_color and credit_limit`);
|
|
69668
70480
|
out.push(` ${import_picocolors48.default.dim("--org <id>")} for create/list: org id or slug (CLI vocab — DB teams.id)`);
|
|
69669
70481
|
out.push(` ${import_picocolors48.default.dim("--team <id>")} for create/list: team id (CLI vocab — DB groups.id)`);
|
|
69670
70482
|
out.push("");
|
|
@@ -70467,7 +71279,10 @@ async function runTokenRevoke(args) {
|
|
|
70467
71279
|
}
|
|
70468
71280
|
const stored = readToken();
|
|
70469
71281
|
const isLocalToken = Boolean(stored && stored.token.startsWith(target.prefix));
|
|
70470
|
-
if (!
|
|
71282
|
+
if (!autoProceedDestructive(args.yes, {
|
|
71283
|
+
action: `Revoking ${target.name} (${args.id})`,
|
|
71284
|
+
flagHint: "Pass --yes to revoke it without a prompt."
|
|
71285
|
+
})) {
|
|
70471
71286
|
const ok = await se({
|
|
70472
71287
|
message: isLocalToken ? `Revoke ${import_picocolors50.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors50.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
|
|
70473
71288
|
initialValue: false
|
|
@@ -77104,10 +77919,10 @@ function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
|
77104
77919
|
}
|
|
77105
77920
|
|
|
77106
77921
|
// node_modules/pkce-challenge/dist/index.node.js
|
|
77107
|
-
var
|
|
77108
|
-
|
|
77922
|
+
var crypto6;
|
|
77923
|
+
crypto6 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m3) => m3.webcrypto);
|
|
77109
77924
|
async function getRandomValues(size2) {
|
|
77110
|
-
return (await
|
|
77925
|
+
return (await crypto6).getRandomValues(new Uint8Array(size2));
|
|
77111
77926
|
}
|
|
77112
77927
|
async function random2(size2) {
|
|
77113
77928
|
const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
|
@@ -77127,7 +77942,7 @@ async function generateVerifier(length) {
|
|
|
77127
77942
|
return await random2(length);
|
|
77128
77943
|
}
|
|
77129
77944
|
async function generateChallenge(code_verifier) {
|
|
77130
|
-
const buffer = await (await
|
|
77945
|
+
const buffer = await (await crypto6).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
77131
77946
|
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
77132
77947
|
}
|
|
77133
77948
|
async function pkceChallenge(length) {
|
|
@@ -79169,10 +79984,99 @@ async function runMcp(cwd2, sub, _argv, options) {
|
|
|
79169
79984
|
}
|
|
79170
79985
|
|
|
79171
79986
|
// src/cli/task.ts
|
|
79172
|
-
var
|
|
79987
|
+
var import_picocolors56 = __toESM(require_picocolors(), 1);
|
|
79173
79988
|
|
|
79174
79989
|
// src/cli/task-create.ts
|
|
79990
|
+
var import_picocolors52 = __toESM(require_picocolors(), 1);
|
|
79175
79991
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
79992
|
+
|
|
79993
|
+
// src/cli/task-status.ts
|
|
79994
|
+
var TERMINAL_TASK_STATUSES = new Set([
|
|
79995
|
+
"success",
|
|
79996
|
+
"fail",
|
|
79997
|
+
"need_more_info"
|
|
79998
|
+
]);
|
|
79999
|
+
var SUCCESS_STATUS = "success";
|
|
80000
|
+
function isTerminalTaskStatus(status) {
|
|
80001
|
+
return TERMINAL_TASK_STATUSES.has(status);
|
|
80002
|
+
}
|
|
80003
|
+
function exitCodeForTaskStatus(status) {
|
|
80004
|
+
return status === SUCCESS_STATUS ? 0 : 1;
|
|
80005
|
+
}
|
|
80006
|
+
var SIGINT_EXIT_CODE = 130;
|
|
80007
|
+
async function waitForTask(taskId, options) {
|
|
80008
|
+
const stop = new AbortController;
|
|
80009
|
+
const onExternalAbort = () => stop.abort();
|
|
80010
|
+
options.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
80011
|
+
if (options.signal?.aborted)
|
|
80012
|
+
stop.abort();
|
|
80013
|
+
const deadlineTimer = options.timeoutMs === undefined ? null : setTimeout(() => stop.abort(), options.timeoutMs);
|
|
80014
|
+
let latest = null;
|
|
80015
|
+
let lastStatus = null;
|
|
80016
|
+
const givenUp = () => options.signal?.aborted ? { kind: "interrupted", task: latest } : { kind: "timeout", task: latest };
|
|
80017
|
+
try {
|
|
80018
|
+
while (true) {
|
|
80019
|
+
if (stop.signal.aborted)
|
|
80020
|
+
return givenUp();
|
|
80021
|
+
const polled = await raceAbort(masApi.getTask(taskId, { signal: stop.signal }), stop.signal);
|
|
80022
|
+
if (polled.kind === "aborted")
|
|
80023
|
+
return givenUp();
|
|
80024
|
+
if (polled.kind === "failed") {
|
|
80025
|
+
if (stop.signal.aborted)
|
|
80026
|
+
return givenUp();
|
|
80027
|
+
throw polled.error;
|
|
80028
|
+
}
|
|
80029
|
+
latest = polled.value;
|
|
80030
|
+
if (latest.status !== lastStatus) {
|
|
80031
|
+
lastStatus = latest.status;
|
|
80032
|
+
options.onStatus?.(latest);
|
|
80033
|
+
}
|
|
80034
|
+
if (isTerminalTaskStatus(latest.status)) {
|
|
80035
|
+
return { kind: "terminal", task: latest };
|
|
80036
|
+
}
|
|
80037
|
+
const cutShort = await sleep2(options.intervalMs, stop.signal);
|
|
80038
|
+
if (cutShort)
|
|
80039
|
+
return givenUp();
|
|
80040
|
+
}
|
|
80041
|
+
} finally {
|
|
80042
|
+
if (deadlineTimer !== null)
|
|
80043
|
+
clearTimeout(deadlineTimer);
|
|
80044
|
+
options.signal?.removeEventListener("abort", onExternalAbort);
|
|
80045
|
+
}
|
|
80046
|
+
}
|
|
80047
|
+
function raceAbort(work, signal) {
|
|
80048
|
+
const settled = work.then((value) => ({ kind: "value", value }), (error2) => ({ kind: "failed", error: error2 }));
|
|
80049
|
+
if (signal.aborted) {
|
|
80050
|
+
settled.catch(() => {});
|
|
80051
|
+
return Promise.resolve({ kind: "aborted" });
|
|
80052
|
+
}
|
|
80053
|
+
return new Promise((resolve) => {
|
|
80054
|
+
const onAbort = () => resolve({ kind: "aborted" });
|
|
80055
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
80056
|
+
settled.then((outcome) => {
|
|
80057
|
+
signal.removeEventListener("abort", onAbort);
|
|
80058
|
+
resolve(outcome);
|
|
80059
|
+
});
|
|
80060
|
+
});
|
|
80061
|
+
}
|
|
80062
|
+
function sleep2(ms2, signal) {
|
|
80063
|
+
if (signal.aborted)
|
|
80064
|
+
return Promise.resolve(true);
|
|
80065
|
+
return new Promise((resolve) => {
|
|
80066
|
+
const onAbort = () => {
|
|
80067
|
+
clearTimeout(timer);
|
|
80068
|
+
resolve(true);
|
|
80069
|
+
};
|
|
80070
|
+
const timer = setTimeout(() => {
|
|
80071
|
+
signal.removeEventListener("abort", onAbort);
|
|
80072
|
+
resolve(false);
|
|
80073
|
+
}, ms2);
|
|
80074
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
80075
|
+
});
|
|
80076
|
+
}
|
|
80077
|
+
|
|
80078
|
+
// src/cli/task-create.ts
|
|
80079
|
+
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
79176
80080
|
async function createTask(input, options) {
|
|
79177
80081
|
return await masApi.createTask(input, options);
|
|
79178
80082
|
}
|
|
@@ -79231,21 +80135,633 @@ async function runTaskCreate(cwd2, options, dependencies = {}) {
|
|
|
79231
80135
|
}
|
|
79232
80136
|
throw error2;
|
|
79233
80137
|
}
|
|
80138
|
+
if (!options.wait) {
|
|
80139
|
+
if (options.json) {
|
|
80140
|
+
console.log(JSON.stringify({
|
|
80141
|
+
task_id: created.id,
|
|
80142
|
+
agent_id: created.agent_id,
|
|
80143
|
+
status: created.status
|
|
80144
|
+
}));
|
|
80145
|
+
return;
|
|
80146
|
+
}
|
|
80147
|
+
console.log([
|
|
80148
|
+
`Task ID: ${created.id}`,
|
|
80149
|
+
`Agent ID: ${created.agent_id}`,
|
|
80150
|
+
`Status: ${created.status}`,
|
|
80151
|
+
"First run accepted."
|
|
80152
|
+
].join(`
|
|
80153
|
+
`));
|
|
80154
|
+
return;
|
|
80155
|
+
}
|
|
80156
|
+
await waitForCreatedTask(created, options, dependencies);
|
|
80157
|
+
}
|
|
80158
|
+
async function waitForCreatedTask(created, options, dependencies) {
|
|
80159
|
+
const setExitCode = dependencies.setExitCode ?? ((code) => process.exitCode = code);
|
|
80160
|
+
const controller = new AbortController;
|
|
80161
|
+
const onSigint = () => controller.abort();
|
|
80162
|
+
process.on("SIGINT", onSigint);
|
|
80163
|
+
if (!options.json) {
|
|
80164
|
+
console.log(`Task ID: ${created.id}`);
|
|
80165
|
+
console.log(`Agent ID: ${created.agent_id}`);
|
|
80166
|
+
}
|
|
80167
|
+
try {
|
|
80168
|
+
const outcome = await waitForTask(created.id, {
|
|
80169
|
+
intervalMs: options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2,
|
|
80170
|
+
timeoutMs: options.timeoutSeconds === undefined ? undefined : options.timeoutSeconds * 1000,
|
|
80171
|
+
signal: controller.signal,
|
|
80172
|
+
onStatus: options.json ? undefined : (task) => console.log(`Status: ${task.status}`)
|
|
80173
|
+
});
|
|
80174
|
+
const status = outcome.task?.status ?? created.status;
|
|
80175
|
+
const code = outcome.kind === "terminal" ? exitCodeForTaskStatus(status) : outcome.kind === "interrupted" ? SIGINT_EXIT_CODE : 1;
|
|
80176
|
+
setExitCode(code);
|
|
80177
|
+
if (options.json) {
|
|
80178
|
+
console.log(JSON.stringify({
|
|
80179
|
+
task_id: created.id,
|
|
80180
|
+
agent_id: created.agent_id,
|
|
80181
|
+
status,
|
|
80182
|
+
outcome: outcome.kind,
|
|
80183
|
+
exit_code: code
|
|
80184
|
+
}));
|
|
80185
|
+
return;
|
|
80186
|
+
}
|
|
80187
|
+
if (outcome.kind === "timeout") {
|
|
80188
|
+
console.log(import_picocolors52.default.yellow(`Timed out after ${options.timeoutSeconds}s with the task still ${status}.`));
|
|
80189
|
+
return;
|
|
80190
|
+
}
|
|
80191
|
+
if (outcome.kind === "interrupted") {
|
|
80192
|
+
console.log(import_picocolors52.default.yellow("Interrupted. The task is still running."));
|
|
80193
|
+
return;
|
|
80194
|
+
}
|
|
80195
|
+
console.log(code === 0 ? import_picocolors52.default.green("Task completed.") : import_picocolors52.default.red(`Task finished as ${status}.`));
|
|
80196
|
+
} finally {
|
|
80197
|
+
process.removeListener("SIGINT", onSigint);
|
|
80198
|
+
}
|
|
80199
|
+
}
|
|
80200
|
+
|
|
80201
|
+
// src/cli/task-get.ts
|
|
80202
|
+
var import_picocolors54 = __toESM(require_picocolors(), 1);
|
|
80203
|
+
|
|
80204
|
+
// src/cli/task-list.ts
|
|
80205
|
+
var import_picocolors53 = __toESM(require_picocolors(), 1);
|
|
80206
|
+
async function runTaskList(options) {
|
|
80207
|
+
if (!options.json)
|
|
80208
|
+
banner("task list — recent tasks");
|
|
80209
|
+
const tasks = await masApi.listTasks({
|
|
80210
|
+
agentId: options.agentId,
|
|
80211
|
+
limit: options.limit
|
|
80212
|
+
});
|
|
79234
80213
|
if (options.json) {
|
|
79235
|
-
console.log(JSON.stringify(
|
|
79236
|
-
task_id: created.id,
|
|
79237
|
-
agent_id: created.agent_id,
|
|
79238
|
-
status: created.status
|
|
79239
|
-
}));
|
|
80214
|
+
console.log(JSON.stringify(tasks, null, 2));
|
|
79240
80215
|
return;
|
|
79241
80216
|
}
|
|
79242
|
-
console.log(
|
|
79243
|
-
|
|
79244
|
-
|
|
79245
|
-
|
|
79246
|
-
|
|
79247
|
-
|
|
79248
|
-
`
|
|
80217
|
+
console.log(formatTaskList(tasks, options.agentId));
|
|
80218
|
+
}
|
|
80219
|
+
function formatTaskList(tasks, agentId) {
|
|
80220
|
+
const lines = [""];
|
|
80221
|
+
if (tasks.length === 0) {
|
|
80222
|
+
lines.push(` ${import_picocolors53.default.dim(agentId ? `No tasks for agent ${agentId}.` : "No tasks yet.")}`, "", ` ${import_picocolors53.default.dim("start one with")} ${import_picocolors53.default.cyan('brainbase task create --message "..."')}`, "");
|
|
80223
|
+
return lines.join(`
|
|
80224
|
+
`);
|
|
80225
|
+
}
|
|
80226
|
+
for (const task of tasks) {
|
|
80227
|
+
const title = task.title?.trim() || import_picocolors53.default.dim("(untitled)");
|
|
80228
|
+
lines.push(` ${statusLabel(task.status)} ${import_picocolors53.default.bold(title)}`);
|
|
80229
|
+
lines.push(` ${import_picocolors53.default.dim(task.id)}`);
|
|
80230
|
+
lines.push(` ${import_picocolors53.default.dim(`agent ${task.agent_id} · created ${task.created_at}`)}`);
|
|
80231
|
+
lines.push("");
|
|
80232
|
+
}
|
|
80233
|
+
lines.push(` ${import_picocolors53.default.dim("inspect one with")} ${import_picocolors53.default.cyan("brainbase task get <id>")}`, "");
|
|
80234
|
+
return lines.join(`
|
|
80235
|
+
`);
|
|
80236
|
+
}
|
|
80237
|
+
function statusLabel(status) {
|
|
80238
|
+
const padded = status.padEnd(14);
|
|
80239
|
+
switch (status) {
|
|
80240
|
+
case "success":
|
|
80241
|
+
return import_picocolors53.default.green(padded);
|
|
80242
|
+
case "fail":
|
|
80243
|
+
return import_picocolors53.default.red(padded);
|
|
80244
|
+
case "need_more_info":
|
|
80245
|
+
return import_picocolors53.default.yellow(padded);
|
|
80246
|
+
case "running":
|
|
80247
|
+
case "initializing":
|
|
80248
|
+
return import_picocolors53.default.cyan(padded);
|
|
80249
|
+
default:
|
|
80250
|
+
return import_picocolors53.default.dim(padded);
|
|
80251
|
+
}
|
|
80252
|
+
}
|
|
80253
|
+
|
|
80254
|
+
// src/cli/task-get.ts
|
|
80255
|
+
async function runTaskGet(taskId, options = {}) {
|
|
80256
|
+
if (!options.json)
|
|
80257
|
+
banner("task get — one task");
|
|
80258
|
+
const task = await masApi.getTask(taskId);
|
|
80259
|
+
const evals = await readEvalRuns(task);
|
|
80260
|
+
if (options.json) {
|
|
80261
|
+
const payload = { task, eval_runs: evals.runs };
|
|
80262
|
+
if (evals.unavailable)
|
|
80263
|
+
payload.eval_runs_unavailable = evals.unavailable;
|
|
80264
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
80265
|
+
return;
|
|
80266
|
+
}
|
|
80267
|
+
console.log(format(task, evals));
|
|
80268
|
+
}
|
|
80269
|
+
async function readEvalRuns(task) {
|
|
80270
|
+
try {
|
|
80271
|
+
return { runs: await api.listAgentEvalRuns(task.agent_id, { taskId: task.id }) };
|
|
80272
|
+
} catch (error2) {
|
|
80273
|
+
if (error2 instanceof ApiError && (error2.status === 401 || error2.status === 403)) {
|
|
80274
|
+
return { runs: [], unavailable: error2.message };
|
|
80275
|
+
}
|
|
80276
|
+
if (error2 instanceof ApiError && error2.status === 404) {
|
|
80277
|
+
return { runs: [], unavailable: "This control plane does not expose eval runs." };
|
|
80278
|
+
}
|
|
80279
|
+
throw error2;
|
|
80280
|
+
}
|
|
80281
|
+
}
|
|
80282
|
+
function format(task, evals) {
|
|
80283
|
+
const lines = [""];
|
|
80284
|
+
const title = task.title?.trim() || import_picocolors54.default.dim("(untitled)");
|
|
80285
|
+
lines.push(` ${statusLabel(task.status)} ${import_picocolors54.default.bold(title)}`);
|
|
80286
|
+
lines.push("");
|
|
80287
|
+
lines.push(` ${import_picocolors54.default.dim("task")} ${task.id}`);
|
|
80288
|
+
lines.push(` ${import_picocolors54.default.dim("agent")} ${task.agent_id}`);
|
|
80289
|
+
lines.push(` ${import_picocolors54.default.dim("created")} ${task.created_at}`);
|
|
80290
|
+
if (task.parent_task_id) {
|
|
80291
|
+
lines.push(` ${import_picocolors54.default.dim("parent")} ${task.parent_task_id}`);
|
|
80292
|
+
}
|
|
80293
|
+
if (task.machine_id) {
|
|
80294
|
+
lines.push(` ${import_picocolors54.default.dim("machine")} ${task.machine_id}${task.machine_size ? ` (${task.machine_size})` : ""}`);
|
|
80295
|
+
}
|
|
80296
|
+
if (task.sandbox_id)
|
|
80297
|
+
lines.push(` ${import_picocolors54.default.dim("sandbox")} ${task.sandbox_id}`);
|
|
80298
|
+
const failure = failureSummary(task);
|
|
80299
|
+
if (failure) {
|
|
80300
|
+
lines.push("");
|
|
80301
|
+
lines.push(` ${import_picocolors54.default.red("failure")} ${failure}`);
|
|
80302
|
+
}
|
|
80303
|
+
const metadata = Object.entries(task.metadata ?? {});
|
|
80304
|
+
if (metadata.length > 0) {
|
|
80305
|
+
lines.push("");
|
|
80306
|
+
lines.push(` ${import_picocolors54.default.bold(import_picocolors54.default.dim("METADATA"))}`);
|
|
80307
|
+
for (const [key2, value] of metadata) {
|
|
80308
|
+
lines.push(` ${import_picocolors54.default.dim(key2)} ${value}`);
|
|
80309
|
+
}
|
|
80310
|
+
}
|
|
80311
|
+
lines.push("");
|
|
80312
|
+
lines.push(` ${import_picocolors54.default.bold(import_picocolors54.default.dim("EVAL VERDICTS"))}`);
|
|
80313
|
+
if (evals.unavailable) {
|
|
80314
|
+
lines.push(` ${import_picocolors54.default.dim(evals.unavailable)}`);
|
|
80315
|
+
} else if (evals.runs.length === 0) {
|
|
80316
|
+
lines.push(` ${import_picocolors54.default.dim("none")}`);
|
|
80317
|
+
} else {
|
|
80318
|
+
for (const run of evals.runs) {
|
|
80319
|
+
const verdict = run.passed === true ? import_picocolors54.default.green("pass") : run.passed === false ? import_picocolors54.default.red("fail") : import_picocolors54.default.dim(run.status);
|
|
80320
|
+
lines.push(` ${verdict} ${run.eval_slug ?? run.eval_id}`);
|
|
80321
|
+
if (run.reasoning)
|
|
80322
|
+
lines.push(` ${import_picocolors54.default.dim(run.reasoning)}`);
|
|
80323
|
+
}
|
|
80324
|
+
}
|
|
80325
|
+
lines.push("");
|
|
80326
|
+
lines.push(` ${import_picocolors54.default.dim("read its transcript with")} ${import_picocolors54.default.cyan(`brainbase task logs ${task.id}`)}`, "");
|
|
80327
|
+
return lines.join(`
|
|
80328
|
+
`);
|
|
80329
|
+
}
|
|
80330
|
+
function failureSummary(task) {
|
|
80331
|
+
const info = task.status_info;
|
|
80332
|
+
if (!info)
|
|
80333
|
+
return;
|
|
80334
|
+
for (const key2 of ["failure_summary", "error"]) {
|
|
80335
|
+
const value = info[key2];
|
|
80336
|
+
if (typeof value === "string" && value.trim())
|
|
80337
|
+
return value.trim();
|
|
80338
|
+
}
|
|
80339
|
+
return;
|
|
80340
|
+
}
|
|
80341
|
+
|
|
80342
|
+
// src/cli/task-logs.ts
|
|
80343
|
+
var import_picocolors55 = __toESM(require_picocolors(), 1);
|
|
80344
|
+
|
|
80345
|
+
// src/core/task-events.ts
|
|
80346
|
+
var DEFAULT_RETRY_BUDGET_MS = 60000;
|
|
80347
|
+
function followTaskEvents(options) {
|
|
80348
|
+
const {
|
|
80349
|
+
url: url2,
|
|
80350
|
+
resolveBearer,
|
|
80351
|
+
onFrame,
|
|
80352
|
+
onOpen,
|
|
80353
|
+
onReconnect,
|
|
80354
|
+
signal,
|
|
80355
|
+
retryBudgetMs = DEFAULT_RETRY_BUDGET_MS
|
|
80356
|
+
} = options;
|
|
80357
|
+
return new Promise((resolve, reject2) => {
|
|
80358
|
+
if (signal?.aborted) {
|
|
80359
|
+
resolve();
|
|
80360
|
+
return;
|
|
80361
|
+
}
|
|
80362
|
+
let source;
|
|
80363
|
+
let settled = false;
|
|
80364
|
+
let closeRequested = false;
|
|
80365
|
+
let downTimer;
|
|
80366
|
+
let lastReason = "connection lost";
|
|
80367
|
+
const clearBudget = () => {
|
|
80368
|
+
if (downTimer !== undefined)
|
|
80369
|
+
clearTimeout(downTimer);
|
|
80370
|
+
downTimer = undefined;
|
|
80371
|
+
};
|
|
80372
|
+
const finish = (error2) => {
|
|
80373
|
+
if (settled)
|
|
80374
|
+
return;
|
|
80375
|
+
settled = true;
|
|
80376
|
+
closeRequested = true;
|
|
80377
|
+
clearBudget();
|
|
80378
|
+
source?.close();
|
|
80379
|
+
if (error2)
|
|
80380
|
+
reject2(error2);
|
|
80381
|
+
else
|
|
80382
|
+
resolve();
|
|
80383
|
+
};
|
|
80384
|
+
source = new EventSource(url2, {
|
|
80385
|
+
fetch: async (input, init) => {
|
|
80386
|
+
let bearer;
|
|
80387
|
+
try {
|
|
80388
|
+
bearer = await resolveBearer();
|
|
80389
|
+
} catch (error2) {
|
|
80390
|
+
if (error2 instanceof StreamHostMovedError) {
|
|
80391
|
+
finish(error2);
|
|
80392
|
+
throw error2;
|
|
80393
|
+
}
|
|
80394
|
+
throw error2;
|
|
80395
|
+
}
|
|
80396
|
+
const headers = new Headers(init?.headers);
|
|
80397
|
+
headers.set("Authorization", `Bearer ${bearer}`);
|
|
80398
|
+
return await fetch(input, { ...init, headers });
|
|
80399
|
+
}
|
|
80400
|
+
});
|
|
80401
|
+
if (closeRequested)
|
|
80402
|
+
source.close();
|
|
80403
|
+
const dispatch = source.dispatchEvent.bind(source);
|
|
80404
|
+
source.dispatchEvent = (event) => {
|
|
80405
|
+
if (event instanceof MessageEvent) {
|
|
80406
|
+
onFrame({
|
|
80407
|
+
id: event.lastEventId,
|
|
80408
|
+
type: event.type,
|
|
80409
|
+
data: parseFrameData(event.data)
|
|
80410
|
+
});
|
|
80411
|
+
}
|
|
80412
|
+
return dispatch(event);
|
|
80413
|
+
};
|
|
80414
|
+
source.addEventListener("open", () => {
|
|
80415
|
+
clearBudget();
|
|
80416
|
+
onOpen?.();
|
|
80417
|
+
});
|
|
80418
|
+
source.addEventListener("error", (event) => {
|
|
80419
|
+
const { message, code } = event;
|
|
80420
|
+
if (source.readyState === source.CLOSED) {
|
|
80421
|
+
finish(streamError(message, code));
|
|
80422
|
+
return;
|
|
80423
|
+
}
|
|
80424
|
+
lastReason = message?.trim() || "connection lost";
|
|
80425
|
+
onReconnect?.(lastReason);
|
|
80426
|
+
if (downTimer === undefined) {
|
|
80427
|
+
downTimer = setTimeout(() => {
|
|
80428
|
+
finish(new ApiError(`The log stream has been unreachable for ${Math.round(retryBudgetMs / 1000)}s (${lastReason}). Giving up — the task may still be running; re-run to reattach.`));
|
|
80429
|
+
}, retryBudgetMs);
|
|
80430
|
+
}
|
|
80431
|
+
});
|
|
80432
|
+
signal?.addEventListener("abort", () => finish(), { once: true });
|
|
80433
|
+
});
|
|
80434
|
+
}
|
|
80435
|
+
function parseFrameData(raw) {
|
|
80436
|
+
if (typeof raw !== "string")
|
|
80437
|
+
return raw;
|
|
80438
|
+
try {
|
|
80439
|
+
return JSON.parse(raw);
|
|
80440
|
+
} catch {
|
|
80441
|
+
return raw;
|
|
80442
|
+
}
|
|
80443
|
+
}
|
|
80444
|
+
function streamError(message, code) {
|
|
80445
|
+
const detail = message?.trim() || "the log stream closed";
|
|
80446
|
+
switch (code) {
|
|
80447
|
+
case 401:
|
|
80448
|
+
return new ApiError(`Not authorized to read this task's events: ${detail}`, 401);
|
|
80449
|
+
case 403:
|
|
80450
|
+
return new ApiError(`Not permitted to read this task's events: ${detail}`, 403);
|
|
80451
|
+
case 404:
|
|
80452
|
+
return new ApiError("No such task, or this control plane does not stream task events yet.", 404);
|
|
80453
|
+
default:
|
|
80454
|
+
return new ApiError(detail, code);
|
|
80455
|
+
}
|
|
80456
|
+
}
|
|
80457
|
+
|
|
80458
|
+
// src/cli/task-logs.ts
|
|
80459
|
+
var MAX_PAGE = 1000;
|
|
80460
|
+
var PAGE_SIZE = 500;
|
|
80461
|
+
async function runTaskLogs(taskId, options = {}, dependencies = {}) {
|
|
80462
|
+
if (options.follow) {
|
|
80463
|
+
await followTranscript(taskId, options, dependencies);
|
|
80464
|
+
return;
|
|
80465
|
+
}
|
|
80466
|
+
const events = await readTranscript(taskId, options.limit);
|
|
80467
|
+
if (options.json) {
|
|
80468
|
+
console.log(JSON.stringify({ items: events }, null, 2));
|
|
80469
|
+
return;
|
|
80470
|
+
}
|
|
80471
|
+
const ordered = [...events].sort((a3, b4) => a3.ts.localeCompare(b4.ts));
|
|
80472
|
+
const rolledUp = rolledUpLanes(ordered);
|
|
80473
|
+
for (const event of ordered) {
|
|
80474
|
+
if (isSupersededChunk(event, rolledUp))
|
|
80475
|
+
continue;
|
|
80476
|
+
console.log(renderEvent(event));
|
|
80477
|
+
}
|
|
80478
|
+
if (ordered.length === 0) {
|
|
80479
|
+
console.log(import_picocolors55.default.dim("No events for this task yet."));
|
|
80480
|
+
}
|
|
80481
|
+
}
|
|
80482
|
+
async function followTranscript(taskId, options, dependencies) {
|
|
80483
|
+
const backfill = options.limit === undefined ? "" : `?backfill=${options.limit}`;
|
|
80484
|
+
const { url: url2, resolveBearer } = await masStreamTarget(`/tasks/${encodeURIComponent(taskId)}/events/stream${backfill}`);
|
|
80485
|
+
if (!options.json) {
|
|
80486
|
+
console.log(import_picocolors55.default.dim(`Following task ${taskId} — Ctrl-C to stop.`));
|
|
80487
|
+
}
|
|
80488
|
+
const setExitCode = dependencies.setExitCode ?? ((code) => process.exitCode = code);
|
|
80489
|
+
const controller = new AbortController;
|
|
80490
|
+
let interruptCode;
|
|
80491
|
+
const stopOn = (code) => () => {
|
|
80492
|
+
interruptCode = code;
|
|
80493
|
+
controller.abort();
|
|
80494
|
+
};
|
|
80495
|
+
const onSigint = stopOn(SIGINT_EXIT_CODE);
|
|
80496
|
+
const onSigterm = stopOn(143);
|
|
80497
|
+
process.once("SIGINT", onSigint);
|
|
80498
|
+
process.once("SIGTERM", onSigterm);
|
|
80499
|
+
try {
|
|
80500
|
+
await followTaskEvents({
|
|
80501
|
+
url: url2,
|
|
80502
|
+
resolveBearer,
|
|
80503
|
+
signal: controller.signal,
|
|
80504
|
+
retryBudgetMs: dependencies.retryBudgetMs,
|
|
80505
|
+
onFrame: (frame) => {
|
|
80506
|
+
const event = frame.data;
|
|
80507
|
+
if (isTaskEvent(event)) {
|
|
80508
|
+
console.log(options.json ? JSON.stringify(event) : renderEvent(event));
|
|
80509
|
+
if (isTaskSettled(event))
|
|
80510
|
+
controller.abort();
|
|
80511
|
+
} else if (options.json) {
|
|
80512
|
+
console.log(JSON.stringify(frame));
|
|
80513
|
+
} else {
|
|
80514
|
+
console.log(import_picocolors55.default.dim(frame.type));
|
|
80515
|
+
}
|
|
80516
|
+
},
|
|
80517
|
+
onReconnect: (reason) => console.error(import_picocolors55.default.dim(`reconnecting — ${reason}`))
|
|
80518
|
+
});
|
|
80519
|
+
if (interruptCode !== undefined)
|
|
80520
|
+
setExitCode(interruptCode);
|
|
80521
|
+
} finally {
|
|
80522
|
+
process.off("SIGINT", onSigint);
|
|
80523
|
+
process.off("SIGTERM", onSigterm);
|
|
80524
|
+
}
|
|
80525
|
+
}
|
|
80526
|
+
function isTaskSettled(event) {
|
|
80527
|
+
if (event.type !== "idle")
|
|
80528
|
+
return false;
|
|
80529
|
+
const status = event.data?.status;
|
|
80530
|
+
return typeof status === "string" && isTerminalTaskStatus(status);
|
|
80531
|
+
}
|
|
80532
|
+
function isTaskEvent(value) {
|
|
80533
|
+
return !!value && typeof value === "object" && typeof value.type === "string" && typeof value.ts === "string";
|
|
80534
|
+
}
|
|
80535
|
+
function rolledUpLanes(events) {
|
|
80536
|
+
const lanes = new Set;
|
|
80537
|
+
for (const event of events) {
|
|
80538
|
+
if (event.type === "assistant.message" || event.type === "subagent.assistant.message") {
|
|
80539
|
+
lanes.add(laneOf(event));
|
|
80540
|
+
}
|
|
80541
|
+
}
|
|
80542
|
+
return lanes;
|
|
80543
|
+
}
|
|
80544
|
+
function isSupersededChunk(event, rolledUp) {
|
|
80545
|
+
return event.type.endsWith(".message.chunk") && rolledUp.has(laneOf(event));
|
|
80546
|
+
}
|
|
80547
|
+
function laneOf(event) {
|
|
80548
|
+
return `${event.subagent_id ?? ""}\x00${event.turn_id ?? ""}`;
|
|
80549
|
+
}
|
|
80550
|
+
async function readTranscript(taskId, limit) {
|
|
80551
|
+
const collected = [];
|
|
80552
|
+
let after2;
|
|
80553
|
+
while (true) {
|
|
80554
|
+
const remaining = limit === undefined ? PAGE_SIZE : limit - collected.length;
|
|
80555
|
+
if (remaining <= 0)
|
|
80556
|
+
break;
|
|
80557
|
+
const pageSize = Math.min(MAX_PAGE, remaining === PAGE_SIZE ? PAGE_SIZE : remaining);
|
|
80558
|
+
const page = await masApi.listTaskEvents(taskId, { limit: pageSize, after: after2 });
|
|
80559
|
+
if (page.length < pageSize) {
|
|
80560
|
+
collected.push(...page);
|
|
80561
|
+
break;
|
|
80562
|
+
}
|
|
80563
|
+
const last2 = page[page.length - 1];
|
|
80564
|
+
const next = { receivedAt: last2.received_at, id: last2.id };
|
|
80565
|
+
if (after2 && next.receivedAt === after2.receivedAt && next.id === after2.id) {
|
|
80566
|
+
break;
|
|
80567
|
+
}
|
|
80568
|
+
collected.push(...page);
|
|
80569
|
+
after2 = next;
|
|
80570
|
+
}
|
|
80571
|
+
return collected;
|
|
80572
|
+
}
|
|
80573
|
+
function renderEvent(event) {
|
|
80574
|
+
const summary = summarize(event);
|
|
80575
|
+
const head3 = `${event.ts} ${event.type}`;
|
|
80576
|
+
return summary ? `${head3} ${summary}` : head3;
|
|
80577
|
+
}
|
|
80578
|
+
function summarize(event) {
|
|
80579
|
+
const data = event.data ?? {};
|
|
80580
|
+
switch (baseType(event.type)) {
|
|
80581
|
+
case "user.message":
|
|
80582
|
+
case "assistant.message":
|
|
80583
|
+
case "assistant.message.chunk":
|
|
80584
|
+
return oneLine2(textOf(data.content));
|
|
80585
|
+
case "assistant.thinking":
|
|
80586
|
+
return oneLine2(asString(data.thought));
|
|
80587
|
+
case "tool_call.start":
|
|
80588
|
+
return oneLine2(`${asString(data.name)} ${compact2(data.args)}`);
|
|
80589
|
+
case "tool_call.end":
|
|
80590
|
+
return oneLine2(`${asString(data.name)} → ${asString(data.status)}`);
|
|
80591
|
+
case "idle":
|
|
80592
|
+
return oneLine2([asString(data.status), asString(data.summary) || asString(data.message)].filter(Boolean).join(" — "));
|
|
80593
|
+
default:
|
|
80594
|
+
return oneLine2(compact2(data));
|
|
80595
|
+
}
|
|
80596
|
+
}
|
|
80597
|
+
function baseType(type) {
|
|
80598
|
+
return type.startsWith("subagent.") ? type.slice("subagent.".length) : type;
|
|
80599
|
+
}
|
|
80600
|
+
function textOf(content) {
|
|
80601
|
+
if (!Array.isArray(content))
|
|
80602
|
+
return "";
|
|
80603
|
+
return content.map((item) => {
|
|
80604
|
+
if (!item || typeof item !== "object")
|
|
80605
|
+
return "";
|
|
80606
|
+
const record3 = item;
|
|
80607
|
+
return record3.type === "text" ? asString(record3.content) : "";
|
|
80608
|
+
}).filter(Boolean).join(" ");
|
|
80609
|
+
}
|
|
80610
|
+
function asString(value) {
|
|
80611
|
+
return typeof value === "string" ? value : "";
|
|
80612
|
+
}
|
|
80613
|
+
function compact2(value) {
|
|
80614
|
+
if (value === undefined || value === null)
|
|
80615
|
+
return "";
|
|
80616
|
+
try {
|
|
80617
|
+
const encoded = JSON.stringify(value);
|
|
80618
|
+
return encoded === "{}" ? "" : encoded ?? "";
|
|
80619
|
+
} catch {
|
|
80620
|
+
return "";
|
|
80621
|
+
}
|
|
80622
|
+
}
|
|
80623
|
+
function oneLine2(value) {
|
|
80624
|
+
const flattened = value.replace(/\s+/g, " ").trim();
|
|
80625
|
+
return flattened.length > 300 ? `${flattened.slice(0, 299)}…` : flattened;
|
|
80626
|
+
}
|
|
80627
|
+
|
|
80628
|
+
// src/core/argv.ts
|
|
80629
|
+
class ArgvParseError extends Error {
|
|
80630
|
+
code = "invalid_arguments";
|
|
80631
|
+
constructor(message) {
|
|
80632
|
+
super(message);
|
|
80633
|
+
this.name = "ArgvParseError";
|
|
80634
|
+
}
|
|
80635
|
+
}
|
|
80636
|
+
function parseBoolean(value, name) {
|
|
80637
|
+
switch (value.trim().toLowerCase()) {
|
|
80638
|
+
case "":
|
|
80639
|
+
case "0":
|
|
80640
|
+
case "false":
|
|
80641
|
+
case "no":
|
|
80642
|
+
case "off":
|
|
80643
|
+
return false;
|
|
80644
|
+
case "1":
|
|
80645
|
+
case "true":
|
|
80646
|
+
case "yes":
|
|
80647
|
+
case "on":
|
|
80648
|
+
return true;
|
|
80649
|
+
default:
|
|
80650
|
+
throw new ArgvParseError(`Unrecognised value for ${name}: ${value}`);
|
|
80651
|
+
}
|
|
80652
|
+
}
|
|
80653
|
+
function validateDefinitions(definitions) {
|
|
80654
|
+
const names = new Map;
|
|
80655
|
+
const keys2 = new Set;
|
|
80656
|
+
for (const definition of definitions) {
|
|
80657
|
+
if (!definition.key) {
|
|
80658
|
+
throw new Error("argv option keys must not be empty");
|
|
80659
|
+
}
|
|
80660
|
+
if (keys2.has(definition.key)) {
|
|
80661
|
+
throw new Error(`duplicate argv option key: ${definition.key}`);
|
|
80662
|
+
}
|
|
80663
|
+
keys2.add(definition.key);
|
|
80664
|
+
for (const name of definition.names) {
|
|
80665
|
+
if (!name.startsWith("-") || name === "-") {
|
|
80666
|
+
throw new Error(`invalid argv option name: ${name}`);
|
|
80667
|
+
}
|
|
80668
|
+
if (name.includes("=")) {
|
|
80669
|
+
throw new Error(`argv option names must not contain "=": ${name}`);
|
|
80670
|
+
}
|
|
80671
|
+
if (names.has(name)) {
|
|
80672
|
+
throw new Error(`duplicate argv option name: ${name}`);
|
|
80673
|
+
}
|
|
80674
|
+
names.set(name, definition);
|
|
80675
|
+
}
|
|
80676
|
+
}
|
|
80677
|
+
return names;
|
|
80678
|
+
}
|
|
80679
|
+
function findDefinition(token, definitions) {
|
|
80680
|
+
const exact = definitions.get(token);
|
|
80681
|
+
if (exact)
|
|
80682
|
+
return { definition: exact, name: token };
|
|
80683
|
+
const equals = token.indexOf("=");
|
|
80684
|
+
if (equals < 1)
|
|
80685
|
+
return null;
|
|
80686
|
+
const name = token.slice(0, equals);
|
|
80687
|
+
const definition = definitions.get(name);
|
|
80688
|
+
return definition ? { definition, name, joined: token.slice(equals + 1) } : null;
|
|
80689
|
+
}
|
|
80690
|
+
function assignOption(options, definition, value, name) {
|
|
80691
|
+
const current = options[definition.key];
|
|
80692
|
+
if (definition.multiple) {
|
|
80693
|
+
if (typeof value !== "string") {
|
|
80694
|
+
throw new Error(`boolean argv option cannot be repeated: ${name}`);
|
|
80695
|
+
}
|
|
80696
|
+
options[definition.key] = [
|
|
80697
|
+
...Array.isArray(current) ? current : [],
|
|
80698
|
+
value
|
|
80699
|
+
];
|
|
80700
|
+
return;
|
|
80701
|
+
}
|
|
80702
|
+
if (current !== undefined) {
|
|
80703
|
+
throw new ArgvParseError(`Option ${name} may only be provided once`);
|
|
80704
|
+
}
|
|
80705
|
+
options[definition.key] = value;
|
|
80706
|
+
}
|
|
80707
|
+
function parseArgv(argv, definitions) {
|
|
80708
|
+
const byName = validateDefinitions(definitions);
|
|
80709
|
+
const options = Object.create(null);
|
|
80710
|
+
const positionals = [];
|
|
80711
|
+
let optionsEnabled = true;
|
|
80712
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
80713
|
+
const token = argv[index];
|
|
80714
|
+
if (!optionsEnabled) {
|
|
80715
|
+
positionals.push(token);
|
|
80716
|
+
continue;
|
|
80717
|
+
}
|
|
80718
|
+
if (token === "--") {
|
|
80719
|
+
optionsEnabled = false;
|
|
80720
|
+
continue;
|
|
80721
|
+
}
|
|
80722
|
+
if (!token.startsWith("-") || token === "-") {
|
|
80723
|
+
positionals.push(token);
|
|
80724
|
+
continue;
|
|
80725
|
+
}
|
|
80726
|
+
const hit = findDefinition(token, byName);
|
|
80727
|
+
if (!hit) {
|
|
80728
|
+
throw new ArgvParseError(`Unknown option: ${token.split("=", 1)[0]}`);
|
|
80729
|
+
}
|
|
80730
|
+
if (hit.definition.kind === "boolean") {
|
|
80731
|
+
assignOption(options, hit.definition, hit.joined === undefined ? true : parseBoolean(hit.joined, hit.name), hit.name);
|
|
80732
|
+
continue;
|
|
80733
|
+
}
|
|
80734
|
+
let value = hit.joined;
|
|
80735
|
+
if (value === undefined) {
|
|
80736
|
+
const next = argv[index + 1];
|
|
80737
|
+
if (next === "--") {
|
|
80738
|
+
value = argv[index + 2];
|
|
80739
|
+
if (value === undefined) {
|
|
80740
|
+
throw new ArgvParseError(`Option ${hit.name} requires a value`);
|
|
80741
|
+
}
|
|
80742
|
+
index += 2;
|
|
80743
|
+
} else {
|
|
80744
|
+
if (next === undefined || next.startsWith("-")) {
|
|
80745
|
+
throw new ArgvParseError(`Option ${hit.name} requires a value; use ${hit.name}=<value> for values beginning with "-"`);
|
|
80746
|
+
}
|
|
80747
|
+
value = next;
|
|
80748
|
+
index += 1;
|
|
80749
|
+
}
|
|
80750
|
+
}
|
|
80751
|
+
assignOption(options, hit.definition, value, hit.name);
|
|
80752
|
+
}
|
|
80753
|
+
return { options, positionals };
|
|
80754
|
+
}
|
|
80755
|
+
function stringOption(parsed, key2) {
|
|
80756
|
+
const value = parsed.options[key2];
|
|
80757
|
+
return typeof value === "string" ? value : undefined;
|
|
80758
|
+
}
|
|
80759
|
+
function stringOptions(parsed, key2) {
|
|
80760
|
+
const value = parsed.options[key2];
|
|
80761
|
+
return Array.isArray(value) ? value : [];
|
|
80762
|
+
}
|
|
80763
|
+
function booleanOption(parsed, key2) {
|
|
80764
|
+
return parsed.options[key2] === true;
|
|
79249
80765
|
}
|
|
79250
80766
|
|
|
79251
80767
|
// src/cli/task.ts
|
|
@@ -79253,13 +80769,16 @@ var VALUE_FLAGS = [
|
|
|
79253
80769
|
["--agent", "agentId"],
|
|
79254
80770
|
["--message", "message"],
|
|
79255
80771
|
["--title", "title"],
|
|
79256
|
-
["--model", "model"]
|
|
80772
|
+
["--model", "model"],
|
|
80773
|
+
["--timeout", "timeout"]
|
|
79257
80774
|
];
|
|
80775
|
+
var BOOLEAN_FLAGS = ["--json", "--wait"];
|
|
79258
80776
|
var TASK_OPTION_NAMES = new Set([
|
|
79259
80777
|
...VALUE_FLAGS.map(([flag]) => flag),
|
|
79260
|
-
|
|
80778
|
+
...BOOLEAN_FLAGS
|
|
79261
80779
|
]);
|
|
79262
80780
|
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
80781
|
+
var LIST_LIMIT_MAX = 200;
|
|
79263
80782
|
function missingValueError(flag) {
|
|
79264
80783
|
if (flag === "--message" || flag === "--agent") {
|
|
79265
80784
|
return new Error(`${flag} is required and must not be blank.`);
|
|
@@ -79275,14 +80794,17 @@ function parseCreateArgs(args) {
|
|
|
79275
80794
|
for (let index = 0;index < args.length; index += 1) {
|
|
79276
80795
|
const arg = args[index];
|
|
79277
80796
|
if (HELP_FLAGS.has(arg)) {
|
|
79278
|
-
return { help: true, options };
|
|
80797
|
+
return { help: true, options: finishCreateArgs(options) };
|
|
79279
80798
|
}
|
|
79280
|
-
if (arg === "--json") {
|
|
80799
|
+
if (arg === "--json" || arg === "--wait") {
|
|
79281
80800
|
if (seen.has(arg)) {
|
|
79282
80801
|
throw new Error(`Duplicate task create option: ${arg}`);
|
|
79283
80802
|
}
|
|
79284
80803
|
seen.add(arg);
|
|
79285
|
-
|
|
80804
|
+
if (arg === "--json")
|
|
80805
|
+
options.json = true;
|
|
80806
|
+
else
|
|
80807
|
+
options.wait = true;
|
|
79286
80808
|
continue;
|
|
79287
80809
|
}
|
|
79288
80810
|
let matched = false;
|
|
@@ -79302,7 +80824,7 @@ function parseCreateArgs(args) {
|
|
|
79302
80824
|
throw missingValueError(flag);
|
|
79303
80825
|
index += 1;
|
|
79304
80826
|
} else if (HELP_FLAGS.has(value) && (option === "agentId" || option === "model")) {
|
|
79305
|
-
return { help: true, options };
|
|
80827
|
+
return { help: true, options: finishCreateArgs(options) };
|
|
79306
80828
|
} else if (TASK_OPTION_NAMES.has(value)) {
|
|
79307
80829
|
throw flagLikeValueError(flag, value);
|
|
79308
80830
|
}
|
|
@@ -79326,7 +80848,38 @@ function parseCreateArgs(args) {
|
|
|
79326
80848
|
throw new Error(`Unknown task create argument: ${arg}`);
|
|
79327
80849
|
}
|
|
79328
80850
|
}
|
|
79329
|
-
return { help: false, options };
|
|
80851
|
+
return { help: false, options: finishCreateArgs(options) };
|
|
80852
|
+
}
|
|
80853
|
+
function finishCreateArgs(raw) {
|
|
80854
|
+
const { timeout, ...rest2 } = raw;
|
|
80855
|
+
if (timeout === undefined)
|
|
80856
|
+
return rest2;
|
|
80857
|
+
const seconds = Number(timeout.trim());
|
|
80858
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
80859
|
+
throw new Error("--timeout must be a positive number of seconds.");
|
|
80860
|
+
}
|
|
80861
|
+
if (!rest2.wait) {
|
|
80862
|
+
throw new Error("--timeout only applies with --wait.");
|
|
80863
|
+
}
|
|
80864
|
+
return { ...rest2, timeoutSeconds: seconds };
|
|
80865
|
+
}
|
|
80866
|
+
function positiveInteger(value, flag, max2) {
|
|
80867
|
+
if (value === undefined)
|
|
80868
|
+
return;
|
|
80869
|
+
const parsed = Number(value.trim());
|
|
80870
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
80871
|
+
throw new Error(`${flag} must be a positive whole number.`);
|
|
80872
|
+
}
|
|
80873
|
+
if (max2 !== undefined && parsed > max2) {
|
|
80874
|
+
throw new Error(`${flag} must be between 1 and ${max2}.`);
|
|
80875
|
+
}
|
|
80876
|
+
return parsed;
|
|
80877
|
+
}
|
|
80878
|
+
function requiredTaskId(positionals, usage) {
|
|
80879
|
+
if (positionals.length !== 1 || !positionals[0]?.trim()) {
|
|
80880
|
+
throw new Error(`Usage: ${usage}`);
|
|
80881
|
+
}
|
|
80882
|
+
return positionals[0].trim();
|
|
79330
80883
|
}
|
|
79331
80884
|
async function runTask(cwd2, sub, args) {
|
|
79332
80885
|
switch (sub) {
|
|
@@ -79339,6 +80892,56 @@ async function runTask(cwd2, sub, args) {
|
|
|
79339
80892
|
await runTaskCreate(cwd2, parsed.options);
|
|
79340
80893
|
return;
|
|
79341
80894
|
}
|
|
80895
|
+
case "list": {
|
|
80896
|
+
if (args.some((arg) => HELP_FLAGS.has(arg))) {
|
|
80897
|
+
printHelp4();
|
|
80898
|
+
return;
|
|
80899
|
+
}
|
|
80900
|
+
const parsed = parseArgv(args, [
|
|
80901
|
+
{ key: "agent", names: ["--agent"], kind: "value" },
|
|
80902
|
+
{ key: "limit", names: ["--limit"], kind: "value" },
|
|
80903
|
+
{ key: "json", names: ["--json"], kind: "boolean" }
|
|
80904
|
+
]);
|
|
80905
|
+
if (parsed.positionals.length > 0) {
|
|
80906
|
+
throw new Error("Usage: brainbase task list [--agent <id>] [--limit <n>] [--json]");
|
|
80907
|
+
}
|
|
80908
|
+
await runTaskList({
|
|
80909
|
+
agentId: stringOption(parsed, "agent"),
|
|
80910
|
+
limit: positiveInteger(stringOption(parsed, "limit"), "--limit", LIST_LIMIT_MAX),
|
|
80911
|
+
json: booleanOption(parsed, "json")
|
|
80912
|
+
});
|
|
80913
|
+
return;
|
|
80914
|
+
}
|
|
80915
|
+
case "get": {
|
|
80916
|
+
if (args.some((arg) => HELP_FLAGS.has(arg))) {
|
|
80917
|
+
printHelp4();
|
|
80918
|
+
return;
|
|
80919
|
+
}
|
|
80920
|
+
const parsed = parseArgv(args, [
|
|
80921
|
+
{ key: "json", names: ["--json"], kind: "boolean" }
|
|
80922
|
+
]);
|
|
80923
|
+
const taskId = requiredTaskId(parsed.positionals, "brainbase task get <task-id> [--json]");
|
|
80924
|
+
await runTaskGet(taskId, { json: booleanOption(parsed, "json") });
|
|
80925
|
+
return;
|
|
80926
|
+
}
|
|
80927
|
+
case "logs": {
|
|
80928
|
+
if (args.some((arg) => HELP_FLAGS.has(arg))) {
|
|
80929
|
+
printHelp4();
|
|
80930
|
+
return;
|
|
80931
|
+
}
|
|
80932
|
+
const parsed = parseArgv(args, [
|
|
80933
|
+
{ key: "limit", names: ["--limit"], kind: "value" },
|
|
80934
|
+
{ key: "json", names: ["--json"], kind: "boolean" },
|
|
80935
|
+
{ key: "follow", names: ["--follow", "-f"], kind: "boolean" }
|
|
80936
|
+
]);
|
|
80937
|
+
const taskId = requiredTaskId(parsed.positionals, "brainbase task logs <task-id> [--limit <n>] [--json] [--follow]");
|
|
80938
|
+
await runTaskLogs(taskId, {
|
|
80939
|
+
limit: positiveInteger(stringOption(parsed, "limit"), "--limit"),
|
|
80940
|
+
json: booleanOption(parsed, "json"),
|
|
80941
|
+
follow: booleanOption(parsed, "follow")
|
|
80942
|
+
});
|
|
80943
|
+
return;
|
|
80944
|
+
}
|
|
79342
80945
|
case undefined:
|
|
79343
80946
|
case "help":
|
|
79344
80947
|
case "-h":
|
|
@@ -79355,18 +80958,220 @@ async function runTask(cwd2, sub, args) {
|
|
|
79355
80958
|
function printHelp4() {
|
|
79356
80959
|
const out = [];
|
|
79357
80960
|
out.push("");
|
|
79358
|
-
out.push(` ${
|
|
80961
|
+
out.push(` ${import_picocolors56.default.bold("brainbase task")} ${import_picocolors56.default.dim("<sub> [options]")}`);
|
|
80962
|
+
out.push("");
|
|
80963
|
+
out.push(` ${import_picocolors56.default.cyan("create")} ${import_picocolors56.default.dim("--message <text>")} ${import_picocolors56.default.dim("create a task and start its first run")}`);
|
|
80964
|
+
out.push(` ${import_picocolors56.default.cyan("list")} ${import_picocolors56.default.dim("recent tasks you can reach (--json for scripts)")}`);
|
|
80965
|
+
out.push(` ${import_picocolors56.default.cyan("get")} ${import_picocolors56.default.dim("<task-id>")} ${import_picocolors56.default.dim("one task: status, agent, machine, eval verdicts")}`);
|
|
80966
|
+
out.push(` ${import_picocolors56.default.cyan("logs")} ${import_picocolors56.default.dim("<task-id> [--follow]")} ${import_picocolors56.default.dim("one line per event in the task's transcript, or tail it live")}`);
|
|
80967
|
+
out.push("");
|
|
80968
|
+
out.push(` ${import_picocolors56.default.bold("create flags")}`);
|
|
80969
|
+
out.push(` ${import_picocolors56.default.dim("--message <text>")} required first user message`);
|
|
80970
|
+
out.push(` ${import_picocolors56.default.dim("--agent <id>")} override the claimed agent in brainbase.agent.yaml`);
|
|
80971
|
+
out.push(` ${import_picocolors56.default.dim("--title <text>")} optional task title`);
|
|
80972
|
+
out.push(` ${import_picocolors56.default.dim("--model <id>")} optional model override`);
|
|
80973
|
+
out.push(` ${import_picocolors56.default.dim("--wait")} block until the task finishes; exit 1 unless it succeeded`);
|
|
80974
|
+
out.push(` ${import_picocolors56.default.dim("--timeout <secs>")} give up waiting after <secs> and exit 1 (needs --wait)`);
|
|
80975
|
+
out.push("");
|
|
80976
|
+
out.push(` ${import_picocolors56.default.bold("list flags")}`);
|
|
80977
|
+
out.push(` ${import_picocolors56.default.dim("--agent <id>")} only this agent's tasks`);
|
|
80978
|
+
out.push(` ${import_picocolors56.default.dim("--limit <n>")} cap the page (1-200, server default 50)`);
|
|
79359
80979
|
out.push("");
|
|
79360
|
-
out.push(` ${
|
|
80980
|
+
out.push(` ${import_picocolors56.default.bold("logs flags")}`);
|
|
80981
|
+
out.push(` ${import_picocolors56.default.dim("--limit <n>")} stop after <n> events instead of the whole transcript; with --follow, the first page size`);
|
|
80982
|
+
out.push(` ${import_picocolors56.default.dim("--follow, -f")} stay attached and print events as they land, until the task finishes`);
|
|
79361
80983
|
out.push("");
|
|
79362
|
-
out.push(` ${
|
|
79363
|
-
out.push(` ${
|
|
79364
|
-
out.push(` ${
|
|
79365
|
-
out.push(` ${import_picocolors52.default.dim("--title <text>")} optional task title`);
|
|
79366
|
-
out.push(` ${import_picocolors52.default.dim("--model <id>")} optional model override`);
|
|
79367
|
-
out.push(` ${import_picocolors52.default.dim("--json")} print task_id, agent_id, and status as JSON`);
|
|
80984
|
+
out.push(` ${import_picocolors56.default.bold("every subcommand")}`);
|
|
80985
|
+
out.push(` ${import_picocolors56.default.dim("--json")} machine-readable output — create prints task_id, agent_id and status; list, get and logs print the raw records`);
|
|
80986
|
+
out.push(` ${import_picocolors56.default.dim(" logs --follow --json prints one record per line, since a live stream has no end to close on")}`);
|
|
79368
80987
|
out.push("");
|
|
79369
|
-
out.push(` ${
|
|
80988
|
+
out.push(` ${import_picocolors56.default.dim("Exit codes with --wait:")} ${import_picocolors56.default.dim("0 succeeded · 1 failed, needs input, or timed out · 130 interrupted")}`);
|
|
80989
|
+
out.push(` ${import_picocolors56.default.dim("Exit codes with --follow:")} ${import_picocolors56.default.dim("0 task reached a terminal state · 1 stream refused, or unreachable for 60s · 130 interrupted (Ctrl-C) · 143 terminated")}`);
|
|
80990
|
+
out.push("");
|
|
80991
|
+
out.push(` ${import_picocolors56.default.dim("Flag-like values:")} use ${import_picocolors56.default.cyan("--flag=value")} or ${import_picocolors56.default.cyan("--flag -- <value>")}`);
|
|
80992
|
+
out.push("");
|
|
80993
|
+
console.log(out.join(`
|
|
80994
|
+
`));
|
|
80995
|
+
}
|
|
80996
|
+
|
|
80997
|
+
// src/cli/machine.ts
|
|
80998
|
+
var import_picocolors59 = __toESM(require_picocolors(), 1);
|
|
80999
|
+
|
|
81000
|
+
// src/cli/machine-list.ts
|
|
81001
|
+
var import_picocolors57 = __toESM(require_picocolors(), 1);
|
|
81002
|
+
async function runMachineList(args = {}) {
|
|
81003
|
+
if (!args.json)
|
|
81004
|
+
banner("machine list — sandboxes you can reach");
|
|
81005
|
+
const machines = await masApi.listMachines({
|
|
81006
|
+
includeDead: Boolean(args.all),
|
|
81007
|
+
limit: args.limit
|
|
81008
|
+
});
|
|
81009
|
+
if (args.json) {
|
|
81010
|
+
console.log(JSON.stringify(machines, null, 2));
|
|
81011
|
+
return;
|
|
81012
|
+
}
|
|
81013
|
+
console.log(formatMachineList(machines, Boolean(args.all)));
|
|
81014
|
+
}
|
|
81015
|
+
function formatMachineList(machines, includedDead) {
|
|
81016
|
+
const lines = [""];
|
|
81017
|
+
if (machines.length === 0) {
|
|
81018
|
+
lines.push(` ${import_picocolors57.default.dim(includedDead ? "No machines." : "No live machines. Pass --all to include torn-down ones.")}`, "");
|
|
81019
|
+
return lines.join(`
|
|
81020
|
+
`);
|
|
81021
|
+
}
|
|
81022
|
+
const rows = machines.map((machine) => ({
|
|
81023
|
+
id: machine.id,
|
|
81024
|
+
kind: machine.kind,
|
|
81025
|
+
status: machine.destroyed_at ? "dead" : machine.status,
|
|
81026
|
+
size: machine.machine_size ?? "",
|
|
81027
|
+
age: age(machine.created_at),
|
|
81028
|
+
dead: Boolean(machine.destroyed_at)
|
|
81029
|
+
}));
|
|
81030
|
+
const width = (pick3) => Math.max(...rows.map((row) => pick3(row).length), 0);
|
|
81031
|
+
const idWidth = width((row) => row.id);
|
|
81032
|
+
const kindWidth = width((row) => row.kind);
|
|
81033
|
+
const statusWidth = width((row) => row.status);
|
|
81034
|
+
const sizeWidth = width((row) => row.size);
|
|
81035
|
+
for (const row of rows) {
|
|
81036
|
+
const status = row.status.padEnd(statusWidth);
|
|
81037
|
+
const cells = [
|
|
81038
|
+
row.id.padEnd(idWidth),
|
|
81039
|
+
row.kind.padEnd(kindWidth),
|
|
81040
|
+
row.dead ? status : statusTint(row.status, status),
|
|
81041
|
+
row.size.padEnd(sizeWidth),
|
|
81042
|
+
import_picocolors57.default.dim(row.age)
|
|
81043
|
+
].join(" ");
|
|
81044
|
+
lines.push(` ${row.dead ? import_picocolors57.default.dim(cells) : cells}`);
|
|
81045
|
+
}
|
|
81046
|
+
lines.push("", ` ${import_picocolors57.default.dim("tear one down with")} ${import_picocolors57.default.cyan("brainbase machine rm <id>")}`, "");
|
|
81047
|
+
return lines.join(`
|
|
81048
|
+
`);
|
|
81049
|
+
}
|
|
81050
|
+
function statusTint(status, padded) {
|
|
81051
|
+
switch (status) {
|
|
81052
|
+
case "running":
|
|
81053
|
+
return import_picocolors57.default.green(padded);
|
|
81054
|
+
case "stopped":
|
|
81055
|
+
case "starting":
|
|
81056
|
+
return import_picocolors57.default.yellow(padded);
|
|
81057
|
+
default:
|
|
81058
|
+
return padded;
|
|
81059
|
+
}
|
|
81060
|
+
}
|
|
81061
|
+
function age(createdAt) {
|
|
81062
|
+
if (!createdAt)
|
|
81063
|
+
return "";
|
|
81064
|
+
const started = new Date(createdAt).getTime();
|
|
81065
|
+
if (Number.isNaN(started))
|
|
81066
|
+
return "";
|
|
81067
|
+
const minutes = Math.floor((Date.now() - started) / 60000);
|
|
81068
|
+
if (minutes < 1)
|
|
81069
|
+
return "just now";
|
|
81070
|
+
if (minutes < 60)
|
|
81071
|
+
return `${minutes}m`;
|
|
81072
|
+
const hours = Math.floor(minutes / 60);
|
|
81073
|
+
if (hours < 24)
|
|
81074
|
+
return `${hours}h`;
|
|
81075
|
+
return `${Math.floor(hours / 24)}d`;
|
|
81076
|
+
}
|
|
81077
|
+
|
|
81078
|
+
// src/cli/machine-rm.ts
|
|
81079
|
+
var import_picocolors58 = __toESM(require_picocolors(), 1);
|
|
81080
|
+
async function runMachineRm(args, dependencies = {}) {
|
|
81081
|
+
const setExitCode = dependencies.setExitCode ?? ((code) => process.exitCode = code);
|
|
81082
|
+
const machineId = args.machineId?.trim();
|
|
81083
|
+
if (!machineId) {
|
|
81084
|
+
throw new Error("A machine id is required: `brainbase machine rm <id>`. List them with `brainbase machine ls`.");
|
|
81085
|
+
}
|
|
81086
|
+
if (!args.json)
|
|
81087
|
+
banner(`machine rm — ${machineId}`);
|
|
81088
|
+
const confirmTeardown = dependencies.confirmTeardown ?? promptForTeardown;
|
|
81089
|
+
if (!await confirmTeardown({ ...args, machineId })) {
|
|
81090
|
+
if (args.json) {
|
|
81091
|
+
console.log(JSON.stringify({ id: machineId, torn_down: false, outcome: "declined" }, null, 2));
|
|
81092
|
+
} else {
|
|
81093
|
+
console.log(` ${import_picocolors58.default.dim("Left alone.")}`);
|
|
81094
|
+
}
|
|
81095
|
+
return;
|
|
81096
|
+
}
|
|
81097
|
+
const machine = await masApi.deleteMachine(machineId);
|
|
81098
|
+
if (!machine.destroyed_at)
|
|
81099
|
+
setExitCode(1);
|
|
81100
|
+
if (args.json) {
|
|
81101
|
+
console.log(JSON.stringify(machine, null, 2));
|
|
81102
|
+
return;
|
|
81103
|
+
}
|
|
81104
|
+
console.log(formatMachineRm(machine));
|
|
81105
|
+
}
|
|
81106
|
+
async function promptForTeardown(args) {
|
|
81107
|
+
if (autoProceed(args.yes))
|
|
81108
|
+
return true;
|
|
81109
|
+
if (!args.json) {
|
|
81110
|
+
console.log(`
|
|
81111
|
+
${import_picocolors58.default.red("This destroys the sandbox.")} ${import_picocolors58.default.dim("Anything not committed out of it is lost. The machine row is kept for cost history.")}
|
|
81112
|
+
`);
|
|
81113
|
+
}
|
|
81114
|
+
const answer = await se({
|
|
81115
|
+
message: `Tear down ${args.machineId}?`,
|
|
81116
|
+
initialValue: false
|
|
81117
|
+
});
|
|
81118
|
+
return ensureNotCancelled(answer);
|
|
81119
|
+
}
|
|
81120
|
+
function formatMachineRm(machine) {
|
|
81121
|
+
const lines = [""];
|
|
81122
|
+
if (machine.destroyed_at) {
|
|
81123
|
+
lines.push(` ${import_picocolors58.default.green("✓")} ${machine.kind} sandbox ${machine.id} is torn down.`, ` ${import_picocolors58.default.dim(`destroyed_at ${machine.destroyed_at}`)}`);
|
|
81124
|
+
} else {
|
|
81125
|
+
lines.push(` ${import_picocolors58.default.yellow("!")} ${machine.id} came back without a teardown timestamp (status ${machine.status}).`, ` ${import_picocolors58.default.dim("Re-check with `brainbase machine ls --all` before assuming it stopped billing.")}`);
|
|
81126
|
+
}
|
|
81127
|
+
lines.push("");
|
|
81128
|
+
return lines.join(`
|
|
81129
|
+
`);
|
|
81130
|
+
}
|
|
81131
|
+
|
|
81132
|
+
// src/cli/machine.ts
|
|
81133
|
+
async function runMachine(sub, args, opts) {
|
|
81134
|
+
if (args.some((arg) => arg === "--help" || arg === "-h")) {
|
|
81135
|
+
printHelp5();
|
|
81136
|
+
return;
|
|
81137
|
+
}
|
|
81138
|
+
switch (sub) {
|
|
81139
|
+
case "ls":
|
|
81140
|
+
case "list":
|
|
81141
|
+
await runMachineList({ all: opts.all, limit: opts.limit, json: opts.json });
|
|
81142
|
+
return;
|
|
81143
|
+
case "rm":
|
|
81144
|
+
await runMachineRm({
|
|
81145
|
+
machineId: args[0],
|
|
81146
|
+
yes: opts.yes,
|
|
81147
|
+
json: opts.json
|
|
81148
|
+
});
|
|
81149
|
+
return;
|
|
81150
|
+
case undefined:
|
|
81151
|
+
case "help":
|
|
81152
|
+
case "-h":
|
|
81153
|
+
case "--help":
|
|
81154
|
+
printHelp5();
|
|
81155
|
+
return;
|
|
81156
|
+
default:
|
|
81157
|
+
console.error(`Unknown machine subcommand: ${sub}
|
|
81158
|
+
`);
|
|
81159
|
+
printHelp5();
|
|
81160
|
+
process.exit(1);
|
|
81161
|
+
}
|
|
81162
|
+
}
|
|
81163
|
+
function printHelp5() {
|
|
81164
|
+
const out = [];
|
|
81165
|
+
out.push("");
|
|
81166
|
+
out.push(` ${import_picocolors59.default.bold("brainbase machine")} ${import_picocolors59.default.dim("<sub> [options]")}`);
|
|
81167
|
+
out.push("");
|
|
81168
|
+
out.push(` ${import_picocolors59.default.cyan("ls")} ${import_picocolors59.default.dim("list your sandboxes — live ones only unless --all")}`);
|
|
81169
|
+
out.push(` ${import_picocolors59.default.cyan("rm")} ${import_picocolors59.default.dim("<id>")} ${import_picocolors59.default.dim("tear a sandbox down (terminal; the row is kept for cost history)")}`);
|
|
81170
|
+
out.push("");
|
|
81171
|
+
out.push(` ${import_picocolors59.default.dim("--all")} ${import_picocolors59.default.dim("for ls: include machines already torn down")}`);
|
|
81172
|
+
out.push(` ${import_picocolors59.default.dim("--limit <n>")} ${import_picocolors59.default.dim("for ls: how many to fetch (1-200, default 50)")}`);
|
|
81173
|
+
out.push(` ${import_picocolors59.default.dim("--yes, -y")} ${import_picocolors59.default.dim("for rm: skip the confirmation")}`);
|
|
81174
|
+
out.push(` ${import_picocolors59.default.dim("--json")} ${import_picocolors59.default.dim("machine-readable output")}`);
|
|
79370
81175
|
out.push("");
|
|
79371
81176
|
console.log(out.join(`
|
|
79372
81177
|
`));
|
|
@@ -79377,7 +81182,7 @@ import {
|
|
|
79377
81182
|
execFileSync as execFileSync3,
|
|
79378
81183
|
spawn as spawn5
|
|
79379
81184
|
} from "node:child_process";
|
|
79380
|
-
import
|
|
81185
|
+
import crypto11 from "node:crypto";
|
|
79381
81186
|
import fs86 from "node:fs";
|
|
79382
81187
|
import os19 from "node:os";
|
|
79383
81188
|
import path94 from "node:path";
|
|
@@ -79387,7 +81192,7 @@ import {
|
|
|
79387
81192
|
execFileSync as execFileSync2,
|
|
79388
81193
|
spawn as spawn4
|
|
79389
81194
|
} from "node:child_process";
|
|
79390
|
-
import
|
|
81195
|
+
import crypto7 from "node:crypto";
|
|
79391
81196
|
import fs81 from "node:fs";
|
|
79392
81197
|
import os16 from "node:os";
|
|
79393
81198
|
import path89 from "node:path";
|
|
@@ -79976,7 +81781,7 @@ function openRegularFileNoFollow(filePath, label, root) {
|
|
|
79976
81781
|
return { fd, stat };
|
|
79977
81782
|
}
|
|
79978
81783
|
async function sha256OfDescriptor(fd) {
|
|
79979
|
-
const hash =
|
|
81784
|
+
const hash = crypto7.createHash("sha256");
|
|
79980
81785
|
const stream = fs81.createReadStream("", {
|
|
79981
81786
|
fd,
|
|
79982
81787
|
autoClose: false,
|
|
@@ -80224,7 +82029,7 @@ async function downloadInputReference(stagingRoot, input, context) {
|
|
|
80224
82029
|
fs81.mkdirSync(path89.dirname(destination), { recursive: true, mode: 448 });
|
|
80225
82030
|
assertNoSymlinkTraversal(stagingRoot, relative);
|
|
80226
82031
|
assertWritableDestination(stagingRoot, relative);
|
|
80227
|
-
const temporary = `${destination}.${process.pid}.${
|
|
82032
|
+
const temporary = `${destination}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.download`;
|
|
80228
82033
|
const controller = new AbortController;
|
|
80229
82034
|
const timer = setTimeout(() => controller.abort(), remainingMs);
|
|
80230
82035
|
let descriptor;
|
|
@@ -80256,7 +82061,7 @@ async function downloadInputReference(stagingRoot, input, context) {
|
|
|
80256
82061
|
let actual;
|
|
80257
82062
|
let size2 = 0;
|
|
80258
82063
|
try {
|
|
80259
|
-
const hash =
|
|
82064
|
+
const hash = crypto7.createHash("sha256");
|
|
80260
82065
|
while (true) {
|
|
80261
82066
|
const { done, value } = await reader.read();
|
|
80262
82067
|
if (done)
|
|
@@ -80441,9 +82246,9 @@ function findZipMembers(archivePath, requested, context) {
|
|
|
80441
82246
|
}
|
|
80442
82247
|
async function writeVerifiedArchiveMember(source, destination, material, context) {
|
|
80443
82248
|
fs81.mkdirSync(path89.dirname(destination), { recursive: true, mode: 448 });
|
|
80444
|
-
const temporary = `${destination}.${process.pid}.${
|
|
82249
|
+
const temporary = `${destination}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
|
|
80445
82250
|
const descriptor = fs81.openSync(temporary, "wx", 384);
|
|
80446
|
-
const hash =
|
|
82251
|
+
const hash = crypto7.createHash("sha256");
|
|
80447
82252
|
let size2 = 0;
|
|
80448
82253
|
try {
|
|
80449
82254
|
for await (const value of source) {
|
|
@@ -80632,7 +82437,7 @@ async function extractArchiveMembers(archivePath, outputRoot, materials, context
|
|
|
80632
82437
|
}
|
|
80633
82438
|
async function atomicCopy(source, destination, mode, sourceRoot) {
|
|
80634
82439
|
fs81.mkdirSync(path89.dirname(destination), { recursive: true });
|
|
80635
|
-
const temporary = `${destination}.${process.pid}.${
|
|
82440
|
+
const temporary = `${destination}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
|
|
80636
82441
|
const opened = openRegularFileNoFollow(source, `copy source ${source}`, sourceRoot);
|
|
80637
82442
|
try {
|
|
80638
82443
|
await pipeline2(fs81.createReadStream("", {
|
|
@@ -81040,7 +82845,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
81040
82845
|
const reachesPhaseDeadline = command.timeout_ms === undefined || command.timeout_ms >= remainingMs;
|
|
81041
82846
|
const timeoutMs2 = reachesPhaseDeadline ? remainingMs : command.timeout_ms;
|
|
81042
82847
|
const started = Date.now();
|
|
81043
|
-
const commandMarker =
|
|
82848
|
+
const commandMarker = crypto7.randomBytes(32).toString("hex");
|
|
81044
82849
|
return await new Promise((resolve, reject2) => {
|
|
81045
82850
|
const child = spawn4(command.argv[0], command.argv.slice(1), {
|
|
81046
82851
|
cwd: cwd2,
|
|
@@ -81077,7 +82882,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
81077
82882
|
return error2;
|
|
81078
82883
|
return new BenchmarkCommandExecutionError(error2.code, error2.message, sanitizedOutput(stdout), sanitizedOutput(stderr), error2.durationMs);
|
|
81079
82884
|
};
|
|
81080
|
-
const
|
|
82885
|
+
const fail2 = (error2) => {
|
|
81081
82886
|
if (settled)
|
|
81082
82887
|
return;
|
|
81083
82888
|
settled = true;
|
|
@@ -81096,7 +82901,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
81096
82901
|
captured += chunk2.length;
|
|
81097
82902
|
context.remainingOutputBytes -= chunk2.length;
|
|
81098
82903
|
if (captured > spec.budget.max_output_bytes || context.remainingOutputBytes < 0) {
|
|
81099
|
-
|
|
82904
|
+
fail2(new BenchmarkPhaseError("output_limit_exceeded", `command output exceeded budget: ${command.id}`));
|
|
81100
82905
|
return;
|
|
81101
82906
|
}
|
|
81102
82907
|
target.push(chunk2);
|
|
@@ -81119,14 +82924,14 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
81119
82924
|
child.stdout?.on("data", (chunk2) => capture(stdout, chunk2));
|
|
81120
82925
|
child.stderr?.on("data", (chunk2) => capture(stderr, chunk2));
|
|
81121
82926
|
child.on("error", (error2) => {
|
|
81122
|
-
|
|
82927
|
+
fail2(new BenchmarkCommandExecutionError("command_start_failed", `failed to start ${command.id}: ${error2.message}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
81123
82928
|
});
|
|
81124
82929
|
timer = setTimeout(() => {
|
|
81125
82930
|
if (reachesPhaseDeadline) {
|
|
81126
|
-
|
|
82931
|
+
fail2(new BenchmarkPhaseError("phase_timeout", "phase budget expired"));
|
|
81127
82932
|
return;
|
|
81128
82933
|
}
|
|
81129
|
-
|
|
82934
|
+
fail2(new BenchmarkCommandExecutionError("command_timeout", `command timed out: ${command.id}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
81130
82935
|
}, timeoutMs2);
|
|
81131
82936
|
child.on("exit", (code, signal) => {
|
|
81132
82937
|
if (settled)
|
|
@@ -81149,7 +82954,7 @@ async function runCommand(command, root, spec, context, options = {}) {
|
|
|
81149
82954
|
async function writeLog(root, name, data, spec) {
|
|
81150
82955
|
const destination = path89.join(root, name);
|
|
81151
82956
|
fs81.mkdirSync(path89.dirname(destination), { recursive: true });
|
|
81152
|
-
const temporary = `${destination}.${process.pid}.${
|
|
82957
|
+
const temporary = `${destination}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
|
|
81153
82958
|
try {
|
|
81154
82959
|
fs81.writeFileSync(temporary, redactCommandOutput(data, spec), {
|
|
81155
82960
|
flag: "wx",
|
|
@@ -81163,7 +82968,7 @@ async function writeLog(root, name, data, spec) {
|
|
|
81163
82968
|
}
|
|
81164
82969
|
function writeBufferAtomic(destination, data) {
|
|
81165
82970
|
fs81.mkdirSync(path89.dirname(destination), { recursive: true });
|
|
81166
|
-
const temporary = `${destination}.${process.pid}.${
|
|
82971
|
+
const temporary = `${destination}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
|
|
81167
82972
|
try {
|
|
81168
82973
|
fs81.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
|
|
81169
82974
|
fs81.renameSync(temporary, destination);
|
|
@@ -82006,7 +83811,7 @@ async function executeEvaluate(spec, context) {
|
|
|
82006
83811
|
if (spec.capture_workspace_archive) {
|
|
82007
83812
|
const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
|
|
82008
83813
|
const archive = path89.join(spec.logs_root, "candidate-workspace.tar.gz");
|
|
82009
|
-
const temporary = `${archive}.${process.pid}.${
|
|
83814
|
+
const temporary = `${archive}.${process.pid}.${crypto7.randomBytes(6).toString("hex")}.tmp`;
|
|
82010
83815
|
try {
|
|
82011
83816
|
await pack({ rootDir: spec.workspace_root, outFile: temporary, files: regularFiles });
|
|
82012
83817
|
fs81.renameSync(temporary, archive);
|
|
@@ -82459,7 +84264,7 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
82459
84264
|
}
|
|
82460
84265
|
|
|
82461
84266
|
// src/cli/benchmark-control.ts
|
|
82462
|
-
var
|
|
84267
|
+
var import_picocolors60 = __toESM(require_picocolors(), 1);
|
|
82463
84268
|
import fs85 from "node:fs";
|
|
82464
84269
|
import path93 from "node:path";
|
|
82465
84270
|
|
|
@@ -82957,10 +84762,10 @@ class BenchmarkApiClient {
|
|
|
82957
84762
|
}
|
|
82958
84763
|
});
|
|
82959
84764
|
}
|
|
82960
|
-
exportManifest(benchmarkId,
|
|
84765
|
+
exportManifest(benchmarkId, format2, revisionId) {
|
|
82961
84766
|
return this.request(`/${encodeURIComponent(benchmarkId)}/export`, {
|
|
82962
84767
|
mode: "binary",
|
|
82963
|
-
query: { format, revision_id: revisionId }
|
|
84768
|
+
query: { format: format2, revision_id: revisionId }
|
|
82964
84769
|
});
|
|
82965
84770
|
}
|
|
82966
84771
|
exportBundle(benchmarkId, revisionId) {
|
|
@@ -83158,7 +84963,7 @@ class BenchmarkApiClient {
|
|
|
83158
84963
|
|
|
83159
84964
|
// src/core/benchmark-authoring.ts
|
|
83160
84965
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
83161
|
-
import
|
|
84966
|
+
import crypto8 from "node:crypto";
|
|
83162
84967
|
import fs82 from "node:fs";
|
|
83163
84968
|
import path90 from "node:path";
|
|
83164
84969
|
|
|
@@ -83957,7 +85762,7 @@ function renderYaml(value) {
|
|
|
83957
85762
|
return import_yaml7.default.stringify(stableValue(value), { indent: 2, lineWidth: 0 });
|
|
83958
85763
|
}
|
|
83959
85764
|
function digest(data) {
|
|
83960
|
-
return
|
|
85765
|
+
return crypto8.createHash("sha256").update(data).digest("hex");
|
|
83961
85766
|
}
|
|
83962
85767
|
function assertRegularFile(filePath, label) {
|
|
83963
85768
|
let stat;
|
|
@@ -84327,7 +86132,7 @@ function sameDestinationObjectIdentity(target, identity2) {
|
|
|
84327
86132
|
}
|
|
84328
86133
|
}
|
|
84329
86134
|
function acquireDestinationWriteLock(root) {
|
|
84330
|
-
const digest2 =
|
|
86135
|
+
const digest2 = crypto8.createHash("sha256").update(root).digest("hex").slice(0, 20);
|
|
84331
86136
|
const lockPath = path90.join(path90.dirname(root), `.brainbase-benchmark-write-lock-${digest2}`);
|
|
84332
86137
|
let descriptor;
|
|
84333
86138
|
try {
|
|
@@ -84413,7 +86218,7 @@ function closeDestinationIdentity(identity2) {
|
|
|
84413
86218
|
throw cleanupError;
|
|
84414
86219
|
}
|
|
84415
86220
|
function createDirectoryClaim(target, identity2) {
|
|
84416
|
-
const claimPath = path90.join(target, `.brainbase-benchmark-write-${
|
|
86221
|
+
const claimPath = path90.join(target, `.brainbase-benchmark-write-${crypto8.randomUUID()}`);
|
|
84417
86222
|
try {
|
|
84418
86223
|
fs82.writeFileSync(claimPath, "", { flag: "wx", mode: 384 });
|
|
84419
86224
|
} catch (error2) {
|
|
@@ -84797,145 +86602,6 @@ function scaffoldBenchmarkDirectory(rootDir, options) {
|
|
|
84797
86602
|
return writeBenchmarkDirectory(rootDir, project);
|
|
84798
86603
|
}
|
|
84799
86604
|
|
|
84800
|
-
// src/core/argv.ts
|
|
84801
|
-
class ArgvParseError extends Error {
|
|
84802
|
-
code = "invalid_arguments";
|
|
84803
|
-
constructor(message) {
|
|
84804
|
-
super(message);
|
|
84805
|
-
this.name = "ArgvParseError";
|
|
84806
|
-
}
|
|
84807
|
-
}
|
|
84808
|
-
function parseBoolean(value, name) {
|
|
84809
|
-
switch (value.trim().toLowerCase()) {
|
|
84810
|
-
case "":
|
|
84811
|
-
case "0":
|
|
84812
|
-
case "false":
|
|
84813
|
-
case "no":
|
|
84814
|
-
case "off":
|
|
84815
|
-
return false;
|
|
84816
|
-
case "1":
|
|
84817
|
-
case "true":
|
|
84818
|
-
case "yes":
|
|
84819
|
-
case "on":
|
|
84820
|
-
return true;
|
|
84821
|
-
default:
|
|
84822
|
-
throw new ArgvParseError(`Unrecognised value for ${name}: ${value}`);
|
|
84823
|
-
}
|
|
84824
|
-
}
|
|
84825
|
-
function validateDefinitions(definitions) {
|
|
84826
|
-
const names = new Map;
|
|
84827
|
-
const keys2 = new Set;
|
|
84828
|
-
for (const definition of definitions) {
|
|
84829
|
-
if (!definition.key) {
|
|
84830
|
-
throw new Error("argv option keys must not be empty");
|
|
84831
|
-
}
|
|
84832
|
-
if (keys2.has(definition.key)) {
|
|
84833
|
-
throw new Error(`duplicate argv option key: ${definition.key}`);
|
|
84834
|
-
}
|
|
84835
|
-
keys2.add(definition.key);
|
|
84836
|
-
for (const name of definition.names) {
|
|
84837
|
-
if (!name.startsWith("-") || name === "-") {
|
|
84838
|
-
throw new Error(`invalid argv option name: ${name}`);
|
|
84839
|
-
}
|
|
84840
|
-
if (name.includes("=")) {
|
|
84841
|
-
throw new Error(`argv option names must not contain "=": ${name}`);
|
|
84842
|
-
}
|
|
84843
|
-
if (names.has(name)) {
|
|
84844
|
-
throw new Error(`duplicate argv option name: ${name}`);
|
|
84845
|
-
}
|
|
84846
|
-
names.set(name, definition);
|
|
84847
|
-
}
|
|
84848
|
-
}
|
|
84849
|
-
return names;
|
|
84850
|
-
}
|
|
84851
|
-
function findDefinition(token, definitions) {
|
|
84852
|
-
const exact = definitions.get(token);
|
|
84853
|
-
if (exact)
|
|
84854
|
-
return { definition: exact, name: token };
|
|
84855
|
-
const equals = token.indexOf("=");
|
|
84856
|
-
if (equals < 1)
|
|
84857
|
-
return null;
|
|
84858
|
-
const name = token.slice(0, equals);
|
|
84859
|
-
const definition = definitions.get(name);
|
|
84860
|
-
return definition ? { definition, name, joined: token.slice(equals + 1) } : null;
|
|
84861
|
-
}
|
|
84862
|
-
function assignOption(options, definition, value, name) {
|
|
84863
|
-
const current = options[definition.key];
|
|
84864
|
-
if (definition.multiple) {
|
|
84865
|
-
if (typeof value !== "string") {
|
|
84866
|
-
throw new Error(`boolean argv option cannot be repeated: ${name}`);
|
|
84867
|
-
}
|
|
84868
|
-
options[definition.key] = [
|
|
84869
|
-
...Array.isArray(current) ? current : [],
|
|
84870
|
-
value
|
|
84871
|
-
];
|
|
84872
|
-
return;
|
|
84873
|
-
}
|
|
84874
|
-
if (current !== undefined) {
|
|
84875
|
-
throw new ArgvParseError(`Option ${name} may only be provided once`);
|
|
84876
|
-
}
|
|
84877
|
-
options[definition.key] = value;
|
|
84878
|
-
}
|
|
84879
|
-
function parseArgv(argv, definitions) {
|
|
84880
|
-
const byName = validateDefinitions(definitions);
|
|
84881
|
-
const options = Object.create(null);
|
|
84882
|
-
const positionals = [];
|
|
84883
|
-
let optionsEnabled = true;
|
|
84884
|
-
for (let index = 0;index < argv.length; index += 1) {
|
|
84885
|
-
const token = argv[index];
|
|
84886
|
-
if (!optionsEnabled) {
|
|
84887
|
-
positionals.push(token);
|
|
84888
|
-
continue;
|
|
84889
|
-
}
|
|
84890
|
-
if (token === "--") {
|
|
84891
|
-
optionsEnabled = false;
|
|
84892
|
-
continue;
|
|
84893
|
-
}
|
|
84894
|
-
if (!token.startsWith("-") || token === "-") {
|
|
84895
|
-
positionals.push(token);
|
|
84896
|
-
continue;
|
|
84897
|
-
}
|
|
84898
|
-
const hit = findDefinition(token, byName);
|
|
84899
|
-
if (!hit) {
|
|
84900
|
-
throw new ArgvParseError(`Unknown option: ${token.split("=", 1)[0]}`);
|
|
84901
|
-
}
|
|
84902
|
-
if (hit.definition.kind === "boolean") {
|
|
84903
|
-
assignOption(options, hit.definition, hit.joined === undefined ? true : parseBoolean(hit.joined, hit.name), hit.name);
|
|
84904
|
-
continue;
|
|
84905
|
-
}
|
|
84906
|
-
let value = hit.joined;
|
|
84907
|
-
if (value === undefined) {
|
|
84908
|
-
const next = argv[index + 1];
|
|
84909
|
-
if (next === "--") {
|
|
84910
|
-
value = argv[index + 2];
|
|
84911
|
-
if (value === undefined) {
|
|
84912
|
-
throw new ArgvParseError(`Option ${hit.name} requires a value`);
|
|
84913
|
-
}
|
|
84914
|
-
index += 2;
|
|
84915
|
-
} else {
|
|
84916
|
-
if (next === undefined || next.startsWith("-")) {
|
|
84917
|
-
throw new ArgvParseError(`Option ${hit.name} requires a value; use ${hit.name}=<value> for values beginning with "-"`);
|
|
84918
|
-
}
|
|
84919
|
-
value = next;
|
|
84920
|
-
index += 1;
|
|
84921
|
-
}
|
|
84922
|
-
}
|
|
84923
|
-
assignOption(options, hit.definition, value, hit.name);
|
|
84924
|
-
}
|
|
84925
|
-
return { options, positionals };
|
|
84926
|
-
}
|
|
84927
|
-
function stringOption(parsed, key2) {
|
|
84928
|
-
const value = parsed.options[key2];
|
|
84929
|
-
return typeof value === "string" ? value : undefined;
|
|
84930
|
-
}
|
|
84931
|
-
function stringOptions(parsed, key2) {
|
|
84932
|
-
const value = parsed.options[key2];
|
|
84933
|
-
return Array.isArray(value) ? value : [];
|
|
84934
|
-
}
|
|
84935
|
-
function booleanOption(parsed, key2) {
|
|
84936
|
-
return parsed.options[key2] === true;
|
|
84937
|
-
}
|
|
84938
|
-
|
|
84939
86605
|
// src/cli/benchmark-control-options.ts
|
|
84940
86606
|
var DEFINITIONS = [
|
|
84941
86607
|
{ key: "agent", names: ["--agent", "-a"], kind: "value" },
|
|
@@ -85112,13 +86778,13 @@ function kebab(value) {
|
|
|
85112
86778
|
}
|
|
85113
86779
|
|
|
85114
86780
|
// src/cli/benchmark-control-io.ts
|
|
85115
|
-
import
|
|
86781
|
+
import crypto10 from "node:crypto";
|
|
85116
86782
|
import fs84 from "node:fs";
|
|
85117
86783
|
import os18 from "node:os";
|
|
85118
86784
|
import path92 from "node:path";
|
|
85119
86785
|
|
|
85120
86786
|
// src/core/benchmark-bundle.ts
|
|
85121
|
-
import
|
|
86787
|
+
import crypto9 from "node:crypto";
|
|
85122
86788
|
import fs83 from "node:fs";
|
|
85123
86789
|
import os17 from "node:os";
|
|
85124
86790
|
import path91 from "node:path";
|
|
@@ -85136,7 +86802,7 @@ var MANIFEST_NAMES = [
|
|
|
85136
86802
|
];
|
|
85137
86803
|
var MANIFEST_NAME_SET = new Set(MANIFEST_NAMES);
|
|
85138
86804
|
function sha2562(data) {
|
|
85139
|
-
return
|
|
86805
|
+
return crypto9.createHash("sha256").update(data).digest("hex");
|
|
85140
86806
|
}
|
|
85141
86807
|
function normalizeArchivePath(raw, directory) {
|
|
85142
86808
|
const candidate = directory ? raw.replace(/\/+$/, "") : raw;
|
|
@@ -85267,7 +86933,7 @@ async function writeBenchmarkBundle(outputPath, input) {
|
|
|
85267
86933
|
validateMemberTree(portableMembers);
|
|
85268
86934
|
const output = path91.resolve(outputPath);
|
|
85269
86935
|
const staging = fs83.mkdtempSync(path91.join(os17.tmpdir(), "brainbase-benchmark-bundle-"));
|
|
85270
|
-
const temporaryOutput = `${output}.${process.pid}.${
|
|
86936
|
+
const temporaryOutput = `${output}.${process.pid}.${crypto9.randomUUID()}.tmp`;
|
|
85271
86937
|
try {
|
|
85272
86938
|
const manifestData = Buffer.from(`${canonicalBenchmarkJson(project.manifest)}
|
|
85273
86939
|
`, "utf8");
|
|
@@ -85530,7 +87196,7 @@ function writeBinaryOutput(cwd2, output, bytes, fallbackName, force) {
|
|
|
85530
87196
|
const target = path92.resolve(cwd2, output ?? safeExportFilename(undefined, fallbackName));
|
|
85531
87197
|
fs84.mkdirSync(path92.dirname(target), { recursive: true });
|
|
85532
87198
|
assertSafeOutputDestination(target, force);
|
|
85533
|
-
const temporary = `${target}.${process.pid}.${
|
|
87199
|
+
const temporary = `${target}.${process.pid}.${crypto10.randomUUID()}.tmp`;
|
|
85534
87200
|
const descriptor = fs84.openSync(temporary, "wx", 384);
|
|
85535
87201
|
let closed = false;
|
|
85536
87202
|
try {
|
|
@@ -85804,20 +87470,20 @@ async function emitCursorPages(output, fetchPage, options) {
|
|
|
85804
87470
|
function commandHelp() {
|
|
85805
87471
|
return [
|
|
85806
87472
|
"",
|
|
85807
|
-
` ${
|
|
87473
|
+
` ${import_picocolors60.default.bold("brainbase benchmark")} ${import_picocolors60.default.dim("<command> [options]")}`,
|
|
85808
87474
|
"",
|
|
85809
|
-
` ${
|
|
85810
|
-
` ${
|
|
85811
|
-
` ${
|
|
85812
|
-
` ${
|
|
85813
|
-
` ${
|
|
87475
|
+
` ${import_picocolors60.default.cyan("init | list | show | create | validate | pull | push")}`,
|
|
87476
|
+
` ${import_picocolors60.default.cyan("publish | revisions | import | export | archive | restore")}`,
|
|
87477
|
+
` ${import_picocolors60.default.cyan("run plan|start|watch|list|show|cancel")}`,
|
|
87478
|
+
` ${import_picocolors60.default.cyan("results | diagnoses | attempt | artifacts | export-results")}`,
|
|
87479
|
+
` ${import_picocolors60.default.cyan("history | baseline show|set|clear")}`,
|
|
85814
87480
|
"",
|
|
85815
|
-
` ${
|
|
87481
|
+
` ${import_picocolors60.default.dim("Use --agent to override brainbase.agent.yaml, and --json or --jsonl for automation.")}`,
|
|
85816
87482
|
"",
|
|
85817
|
-
` ${
|
|
85818
|
-
` ${
|
|
85819
|
-
` ${
|
|
85820
|
-
` ${
|
|
87483
|
+
` ${import_picocolors60.default.bold("benchmark runtime (machine-only)")}`,
|
|
87484
|
+
` ${import_picocolors60.default.cyan("hydrate")} ${import_picocolors60.default.dim("--spec <path> --result <path> --json")}`,
|
|
87485
|
+
` ${import_picocolors60.default.cyan("evaluate")} ${import_picocolors60.default.dim("--spec <path> --result <path> --json")}`,
|
|
87486
|
+
` ${import_picocolors60.default.cyan("capabilities")} ${import_picocolors60.default.dim("--json")}`,
|
|
85821
87487
|
""
|
|
85822
87488
|
].join(`
|
|
85823
87489
|
`);
|
|
@@ -86149,19 +87815,19 @@ async function runExport(cwd2, argv, deps) {
|
|
|
86149
87815
|
]);
|
|
86150
87816
|
expectPositionals(options.positionals, 1, 1, "brainbase benchmark export <benchmark-id> --format <yaml|json|bundle>");
|
|
86151
87817
|
const benchmarkId = options.positionals[0];
|
|
86152
|
-
const
|
|
86153
|
-
if (!["yaml", "json", "bundle"].includes(
|
|
87818
|
+
const format2 = optionalNonblank(options.parsed, "format") ?? "yaml";
|
|
87819
|
+
if (!["yaml", "json", "bundle"].includes(format2)) {
|
|
86154
87820
|
throw usageError("--format must be yaml, json, or bundle");
|
|
86155
87821
|
}
|
|
86156
87822
|
const { client, output } = context(cwd2, "benchmark export", options, deps);
|
|
86157
87823
|
const revision = optionalNonblank(options.parsed, "revision");
|
|
86158
|
-
const response =
|
|
86159
|
-
const extension2 =
|
|
87824
|
+
const response = format2 === "bundle" ? await client.exportBundle(benchmarkId, revision) : await client.exportManifest(benchmarkId, format2, revision);
|
|
87825
|
+
const extension2 = format2 === "bundle" ? "tar.gz" : format2;
|
|
86160
87826
|
const fallback = safeExportFilename(response.filename, `benchmark-${benchmarkId}.${extension2}`);
|
|
86161
87827
|
const written = writeBinaryOutput(cwd2, optionalNonblank(options.parsed, "output"), response.bytes, fallback, bool(options.parsed, "force"));
|
|
86162
87828
|
output.result({
|
|
86163
87829
|
benchmark_id: benchmarkId,
|
|
86164
|
-
format,
|
|
87830
|
+
format: format2,
|
|
86165
87831
|
path: written,
|
|
86166
87832
|
size_bytes: response.bytes.byteLength
|
|
86167
87833
|
});
|
|
@@ -86971,7 +88637,7 @@ function terminatePhase(child) {
|
|
|
86971
88637
|
}
|
|
86972
88638
|
}
|
|
86973
88639
|
function createAnonymousSpecFd(bytes) {
|
|
86974
|
-
const temporary = path94.join(os19.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${
|
|
88640
|
+
const temporary = path94.join(os19.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto11.randomBytes(12).toString("hex")}`);
|
|
86975
88641
|
fs86.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
|
|
86976
88642
|
try {
|
|
86977
88643
|
const fd = fs86.openSync(temporary, "r");
|
|
@@ -87015,7 +88681,7 @@ async function runSupervisedPhase(phase, parsed, write) {
|
|
|
87015
88681
|
`);
|
|
87016
88682
|
return 1;
|
|
87017
88683
|
}
|
|
87018
|
-
const childToken =
|
|
88684
|
+
const childToken = crypto11.randomBytes(32).toString("hex");
|
|
87019
88685
|
let specFd;
|
|
87020
88686
|
try {
|
|
87021
88687
|
specFd = createAnonymousSpecFd(specBytes);
|
|
@@ -87200,148 +88866,161 @@ var SUBCOMMAND_OWNED_FLAGS = {
|
|
|
87200
88866
|
function help() {
|
|
87201
88867
|
const out = [];
|
|
87202
88868
|
out.push("");
|
|
87203
|
-
out.push(` ${brandTint("◆")} ${
|
|
87204
|
-
out.push(` ${
|
|
88869
|
+
out.push(` ${brandTint("◆")} ${import_picocolors61.default.bold("brainbase")} ${import_picocolors61.default.dim(`v${VERSION}`)}`);
|
|
88870
|
+
out.push(` ${import_picocolors61.default.dim("connect your local agent to the brainbase platform")}`);
|
|
87205
88871
|
out.push("");
|
|
87206
88872
|
out.push(divider("USAGE"));
|
|
87207
88873
|
out.push("");
|
|
87208
|
-
out.push(` ${
|
|
88874
|
+
out.push(` ${import_picocolors61.default.bold("brainbase")} ${import_picocolors61.default.dim("<command> [options]")}`);
|
|
87209
88875
|
out.push("");
|
|
87210
88876
|
out.push(divider("AUTH"));
|
|
87211
88877
|
out.push("");
|
|
87212
|
-
out.push(` ${
|
|
87213
|
-
out.push(` ${
|
|
87214
|
-
out.push(` ${
|
|
88878
|
+
out.push(` ${import_picocolors61.default.cyan("login")} ${import_picocolors61.default.dim(" open the web app and connect this device")}`);
|
|
88879
|
+
out.push(` ${import_picocolors61.default.cyan("logout")} ${import_picocolors61.default.dim(" clear the local session")}`);
|
|
88880
|
+
out.push(` ${import_picocolors61.default.cyan("whoami")} ${import_picocolors61.default.dim("[--json]")} ${import_picocolors61.default.dim(" show which credential is in use and what it covers")}`);
|
|
87215
88881
|
out.push("");
|
|
87216
88882
|
out.push(divider("DISCOVERY"));
|
|
87217
88883
|
out.push("");
|
|
87218
|
-
out.push(` ${
|
|
87219
|
-
out.push(` ${
|
|
88884
|
+
out.push(` ${import_picocolors61.default.cyan("team list")} ${import_picocolors61.default.dim("show the teams you can create agents in")}`);
|
|
88885
|
+
out.push(` ${import_picocolors61.default.cyan("agent list")} ${import_picocolors61.default.dim("show a team's agents and their ids")}`);
|
|
87220
88886
|
out.push("");
|
|
87221
88887
|
out.push(divider("LINKED AGENT"));
|
|
87222
88888
|
out.push("");
|
|
87223
|
-
out.push(` ${
|
|
87224
|
-
out.push(` ${
|
|
87225
|
-
out.push(` ${
|
|
87226
|
-
out.push(` ${
|
|
87227
|
-
out.push(` ${
|
|
87228
|
-
out.push(` ${
|
|
87229
|
-
out.push(` ${
|
|
87230
|
-
out.push(` ${
|
|
87231
|
-
out.push(` ${
|
|
87232
|
-
out.push(` ${
|
|
87233
|
-
out.push(` ${
|
|
87234
|
-
out.push(` ${
|
|
87235
|
-
out.push(` ${
|
|
87236
|
-
out.push(` ${
|
|
88889
|
+
out.push(` ${import_picocolors61.default.cyan("agent init")} ${import_picocolors61.default.dim("write a starter brainbase.agent.yaml here — offline, no login needed")}`);
|
|
88890
|
+
out.push(` ${import_picocolors61.default.cyan("agent create")} ${import_picocolors61.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
|
|
88891
|
+
out.push(` ${import_picocolors61.default.cyan("agent pull")} ${import_picocolors61.default.dim("[<id>]")} ${import_picocolors61.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
|
|
88892
|
+
out.push(` ${import_picocolors61.default.cyan("agent push")} ${import_picocolors61.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
|
|
88893
|
+
out.push(` ${import_picocolors61.default.cyan("agent unpack")} ${import_picocolors61.default.dim("install the claimed agent into a harness layout")}`);
|
|
88894
|
+
out.push(` ${import_picocolors61.default.cyan("link")} ${import_picocolors61.default.dim("attach this folder to an existing agent")}`);
|
|
88895
|
+
out.push(` ${import_picocolors61.default.cyan("agent status")} ${import_picocolors61.default.dim("show what would pull and what would push")}`);
|
|
88896
|
+
out.push(` ${import_picocolors61.default.cyan("agent connections")} ${import_picocolors61.default.dim("show which integrations this agent is wired to (--json for CI)")}`);
|
|
88897
|
+
out.push(` ${import_picocolors61.default.cyan("agent connect")} ${import_picocolors61.default.dim("<name>")} ${import_picocolors61.default.dim("connect slack or meeting from the terminal")}`);
|
|
88898
|
+
out.push(` ${import_picocolors61.default.cyan("agent disconnect")} ${import_picocolors61.default.dim("<name>")} ${import_picocolors61.default.dim("revoke a slack or meeting install")}`);
|
|
88899
|
+
out.push(` ${import_picocolors61.default.cyan("agent env")} ${import_picocolors61.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
|
|
88900
|
+
out.push(` ${import_picocolors61.default.cyan("run")} ${import_picocolors61.default.dim("<cmd> [args...]")} ${import_picocolors61.default.dim("run <cmd> with secrets.env loaded into env")}`);
|
|
88901
|
+
out.push(` ${import_picocolors61.default.cyan("status")} ${import_picocolors61.default.dim("show what this folder is linked to")}`);
|
|
88902
|
+
out.push(` ${import_picocolors61.default.cyan("unlink")} ${import_picocolors61.default.dim("disconnect this folder")}`);
|
|
87237
88903
|
out.push("");
|
|
87238
88904
|
out.push(divider("TASKS"));
|
|
87239
88905
|
out.push("");
|
|
87240
|
-
out.push(` ${
|
|
88906
|
+
out.push(` ${import_picocolors61.default.cyan("task create")} ${import_picocolors61.default.dim("--message <text>")} ${import_picocolors61.default.dim("create a managed task and start its first run (--wait to block on it)")}`);
|
|
88907
|
+
out.push(` ${import_picocolors61.default.cyan("task list")} ${import_picocolors61.default.dim("recent tasks you can reach")}`);
|
|
88908
|
+
out.push(` ${import_picocolors61.default.cyan("task get")} ${import_picocolors61.default.dim("<task-id>")} ${import_picocolors61.default.dim("one task: status, agent, machine, eval verdicts")}`);
|
|
88909
|
+
out.push(` ${import_picocolors61.default.cyan("task logs")} ${import_picocolors61.default.dim("<task-id> [--follow]")} ${import_picocolors61.default.dim("one line per event in the task's transcript, or tail it live")}`);
|
|
88910
|
+
out.push("");
|
|
88911
|
+
out.push(divider("SANDBOXES"));
|
|
88912
|
+
out.push("");
|
|
88913
|
+
out.push(` ${import_picocolors61.default.cyan("machine ls")} ${import_picocolors61.default.dim("[--all]")} ${import_picocolors61.default.dim("list your sandboxes — live ones only unless --all")}`);
|
|
88914
|
+
out.push(` ${import_picocolors61.default.cyan("machine rm")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("tear a sandbox down (it bills until you do)")}`);
|
|
87241
88915
|
out.push("");
|
|
87242
88916
|
out.push(divider("BENCHMARKS"));
|
|
87243
88917
|
out.push("");
|
|
87244
|
-
out.push(` ${
|
|
87245
|
-
out.push(` ${
|
|
87246
|
-
out.push(` ${
|
|
87247
|
-
out.push(` ${
|
|
87248
|
-
out.push(` ${
|
|
88918
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark list")} ${import_picocolors61.default.dim("list benchmarks for the linked agent")}`);
|
|
88919
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark init")} ${import_picocolors61.default.dim("[directory]")} ${import_picocolors61.default.dim("scaffold a local benchmark")}`);
|
|
88920
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark create")} ${import_picocolors61.default.dim("[path|-]")} ${import_picocolors61.default.dim("create a benchmark draft")}`);
|
|
88921
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark run")} ${import_picocolors61.default.dim("<benchmark> --yes")} ${import_picocolors61.default.dim("plan and start a benchmark run")}`);
|
|
88922
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark results")} ${import_picocolors61.default.dim("<run>")} ${import_picocolors61.default.dim("inspect normalized benchmark results")}`);
|
|
87249
88923
|
out.push("");
|
|
87250
88924
|
out.push(divider("BENCHMARK RUNTIME"));
|
|
87251
88925
|
out.push("");
|
|
87252
|
-
out.push(` ${
|
|
87253
|
-
out.push(` ${
|
|
87254
|
-
out.push(` ${
|
|
88926
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark hydrate")} ${import_picocolors61.default.dim("--spec <path> --result <path> --json")}`);
|
|
88927
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark evaluate")} ${import_picocolors61.default.dim("--spec <path> --result <path> --json")}`);
|
|
88928
|
+
out.push(` ${import_picocolors61.default.cyan("benchmark capabilities")} ${import_picocolors61.default.dim("--json")}`);
|
|
87255
88929
|
out.push("");
|
|
87256
88930
|
out.push(divider("ORCHESTRATIONS"));
|
|
87257
88931
|
out.push("");
|
|
87258
|
-
out.push(` ${
|
|
87259
|
-
out.push(` ${
|
|
87260
|
-
out.push(` ${
|
|
87261
|
-
out.push(` ${
|
|
87262
|
-
out.push(` ${
|
|
88932
|
+
out.push(` ${import_picocolors61.default.cyan("orchestration create")} ${import_picocolors61.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
|
|
88933
|
+
out.push(` ${import_picocolors61.default.cyan("orchestration list")} ${import_picocolors61.default.dim("list orchestrations under a team")}`);
|
|
88934
|
+
out.push(` ${import_picocolors61.default.cyan("orchestration pull")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("recursively fetch an orchestration + every member agent")}`);
|
|
88935
|
+
out.push(` ${import_picocolors61.default.cyan("orchestration push")} ${import_picocolors61.default.dim("recursively push each member, then update the graph")}`);
|
|
88936
|
+
out.push(` ${import_picocolors61.default.cyan("orchestration status")} ${import_picocolors61.default.dim("show what would push and what would pull")}`);
|
|
87263
88937
|
out.push("");
|
|
87264
88938
|
out.push(divider("TEMPLATES"));
|
|
87265
88939
|
out.push("");
|
|
87266
|
-
out.push(` ${
|
|
87267
|
-
out.push(` ${
|
|
87268
|
-
out.push(` ${
|
|
87269
|
-
out.push(` ${
|
|
87270
|
-
out.push(` ${
|
|
87271
|
-
out.push(` ${
|
|
87272
|
-
out.push(` ${
|
|
88940
|
+
out.push(` ${import_picocolors61.default.cyan("template pack")} ${import_picocolors61.default.dim("bundle the current agent into a template")}`);
|
|
88941
|
+
out.push(` ${import_picocolors61.default.cyan("template publish")} ${import_picocolors61.default.dim("upload a template to the registry")}`);
|
|
88942
|
+
out.push(` ${import_picocolors61.default.cyan("template search")} ${import_picocolors61.default.dim("[query]")} ${import_picocolors61.default.dim("search the registry")}`);
|
|
88943
|
+
out.push(` ${import_picocolors61.default.cyan("template info")} ${import_picocolors61.default.dim("<creator/slug>")} ${import_picocolors61.default.dim("show registry details for a template")}`);
|
|
88944
|
+
out.push(` ${import_picocolors61.default.cyan("template onboard")} ${import_picocolors61.default.dim("<creator/slug>")} ${import_picocolors61.default.dim("install (or refresh) a template")}`);
|
|
88945
|
+
out.push(` ${import_picocolors61.default.cyan("template list")} ${import_picocolors61.default.dim("show installed templates")}`);
|
|
88946
|
+
out.push(` ${import_picocolors61.default.cyan("template remove")} ${import_picocolors61.default.dim("<creator/slug>")} ${import_picocolors61.default.dim("uninstall a template")}`);
|
|
87273
88947
|
out.push("");
|
|
87274
88948
|
out.push(divider("SKILLS"));
|
|
87275
88949
|
out.push("");
|
|
87276
|
-
out.push(` ${
|
|
87277
|
-
out.push(` ${
|
|
87278
|
-
out.push(` ${
|
|
87279
|
-
out.push(` ${
|
|
87280
|
-
out.push(` ${
|
|
87281
|
-
out.push(` ${
|
|
87282
|
-
out.push(` ${
|
|
88950
|
+
out.push(` ${import_picocolors61.default.cyan("skill add")} ${import_picocolors61.default.dim("<source>")} ${import_picocolors61.default.dim("install a skill (github / git / brainbase)")}`);
|
|
88951
|
+
out.push(` ${import_picocolors61.default.cyan("skill list")} ${import_picocolors61.default.dim("show locally installed skills + their source")}`);
|
|
88952
|
+
out.push(` ${import_picocolors61.default.cyan("skill update")} ${import_picocolors61.default.dim("<slug>")} ${import_picocolors61.default.dim("re-fetch a skill from its recorded source")}`);
|
|
88953
|
+
out.push(` ${import_picocolors61.default.cyan("skill remove")} ${import_picocolors61.default.dim("<slug>")} ${import_picocolors61.default.dim("uninstall a skill")}`);
|
|
88954
|
+
out.push(` ${import_picocolors61.default.cyan("skill search")} ${import_picocolors61.default.dim("[query]")} ${import_picocolors61.default.dim("search the brainbase skill registry")}`);
|
|
88955
|
+
out.push(` ${import_picocolors61.default.cyan("skill info")} ${import_picocolors61.default.dim("<creator/slug>")} ${import_picocolors61.default.dim("show registry details for a skill")}`);
|
|
88956
|
+
out.push(` ${import_picocolors61.default.cyan("skill publish")} ${import_picocolors61.default.dim("[dir]")} ${import_picocolors61.default.dim("publish a SKILL.md folder (defaults to .)")}`);
|
|
87283
88957
|
out.push("");
|
|
87284
88958
|
out.push(divider("CLI TOKENS"));
|
|
87285
88959
|
out.push("");
|
|
87286
|
-
out.push(` ${
|
|
87287
|
-
out.push(` ${
|
|
87288
|
-
out.push(` ${
|
|
87289
|
-
out.push(` ${
|
|
88960
|
+
out.push(` ${import_picocolors61.default.cyan("token create")} ${import_picocolors61.default.dim("issue a long-lived CLI key for CI / scripts")}`);
|
|
88961
|
+
out.push(` ${import_picocolors61.default.cyan("token list")} ${import_picocolors61.default.dim("show your tokens")}`);
|
|
88962
|
+
out.push(` ${import_picocolors61.default.cyan("token rename")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("relabel a token")}`);
|
|
88963
|
+
out.push(` ${import_picocolors61.default.cyan("token revoke")} ${import_picocolors61.default.dim("<id>")} ${import_picocolors61.default.dim("revoke a token")}`);
|
|
87290
88964
|
out.push("");
|
|
87291
88965
|
out.push(divider("MCP"));
|
|
87292
88966
|
out.push("");
|
|
87293
|
-
out.push(` ${
|
|
87294
|
-
out.push(` ${
|
|
88967
|
+
out.push(` ${import_picocolors61.default.cyan("mcp check")} ${import_picocolors61.default.dim("[--json]")} ${import_picocolors61.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
|
|
88968
|
+
out.push(` ${import_picocolors61.default.cyan("mcp list")} ${import_picocolors61.default.dim("[--json]")} ${import_picocolors61.default.dim("show configured servers with OAuth state and expiry")}`);
|
|
87295
88969
|
out.push("");
|
|
87296
88970
|
out.push(divider("FLAGS"));
|
|
87297
88971
|
out.push("");
|
|
87298
|
-
out.push(` ${
|
|
87299
|
-
out.push(` ${
|
|
87300
|
-
out.push(` ${
|
|
87301
|
-
out.push(` ${
|
|
87302
|
-
out.push(` ${
|
|
87303
|
-
out.push(` ${
|
|
87304
|
-
out.push(` ${
|
|
87305
|
-
out.push(` ${
|
|
87306
|
-
out.push(` ${
|
|
87307
|
-
out.push(` ${
|
|
87308
|
-
out.push(` ${
|
|
87309
|
-
out.push(` ${
|
|
87310
|
-
out.push(` ${
|
|
87311
|
-
out.push(` ${
|
|
87312
|
-
out.push(` ${
|
|
87313
|
-
out.push(` ${
|
|
87314
|
-
out.push(` ${
|
|
87315
|
-
out.push(` ${
|
|
87316
|
-
out.push(` ${
|
|
87317
|
-
out.push(` ${
|
|
88972
|
+
out.push(` ${import_picocolors61.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
|
|
88973
|
+
out.push(` ${import_picocolors61.default.dim("--scope <s>")} force scope: global | project`);
|
|
88974
|
+
out.push(` ${import_picocolors61.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
|
|
88975
|
+
out.push(` ${" ".repeat("--yes, -y".length)} required for destructive commands with no terminal (pipes, CI)`);
|
|
88976
|
+
out.push(` ${import_picocolors61.default.dim("--agent <id>")} for link/task create: use this agent id explicitly (task list: filter to it)`);
|
|
88977
|
+
out.push(` ${import_picocolors61.default.dim("--message <text>")} for task create: required first user message`);
|
|
88978
|
+
out.push(` ${import_picocolors61.default.dim("--title <text>")} for task create: optional task title`);
|
|
88979
|
+
out.push(` ${import_picocolors61.default.dim("--model <id>")} for task create: optional model override`);
|
|
88980
|
+
out.push(` ${import_picocolors61.default.dim("--wait")} for task create: block until the task finishes; exit 1 unless it succeeded`);
|
|
88981
|
+
out.push(` ${import_picocolors61.default.dim("--timeout <secs>")} for task create --wait: give up after <secs> and exit 1`);
|
|
88982
|
+
out.push(` ${import_picocolors61.default.dim("--limit <n>")} for task list (1-200), task logs (events to print; with --follow, the first page size) and machine ls`);
|
|
88983
|
+
out.push(` ${import_picocolors61.default.dim("--follow, -f")} for task logs: stay attached and print events as they land`);
|
|
88984
|
+
out.push(` ${import_picocolors61.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
|
|
88985
|
+
out.push(` ${import_picocolors61.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
|
|
88986
|
+
out.push(` ${import_picocolors61.default.dim("--json")} machine-readable output for supported commands`);
|
|
88987
|
+
out.push(` ${import_picocolors61.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
|
|
88988
|
+
out.push(` ${import_picocolors61.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
|
|
88989
|
+
out.push(` ${import_picocolors61.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
|
|
88990
|
+
out.push(` ${import_picocolors61.default.dim("--bot-token <t>")} for agent connect slack (or BRAINBASE_SLACK_BOT_TOKEN, or stdin)`);
|
|
88991
|
+
out.push(` ${import_picocolors61.default.dim("--signing-secret <s>")} for agent connect slack (or BRAINBASE_SLACK_SIGNING_SECRET, or stdin)`);
|
|
88992
|
+
out.push(` ${import_picocolors61.default.dim("--bot-name <name>")} for agent connect meeting: the bot's display name`);
|
|
88993
|
+
out.push(` ${import_picocolors61.default.dim("--full")} for agent init: write a commented template covering every block`);
|
|
88994
|
+
out.push(` ${import_picocolors61.default.dim("--minimal")} for agent init: write the starter manifest (the default)`);
|
|
88995
|
+
out.push(` ${import_picocolors61.default.dim("--all")} for template list: include installs from other folders; for machine ls: include torn-down machines`);
|
|
88996
|
+
out.push(` ${import_picocolors61.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
|
|
87318
88997
|
out.push("");
|
|
87319
88998
|
out.push(divider("ENV"));
|
|
87320
88999
|
out.push("");
|
|
87321
|
-
out.push(` ${
|
|
87322
|
-
out.push(` ${
|
|
87323
|
-
out.push(` ${
|
|
87324
|
-
out.push(` ${
|
|
87325
|
-
out.push(` ${
|
|
87326
|
-
out.push(` ${
|
|
87327
|
-
out.push(` ${
|
|
87328
|
-
out.push(` ${
|
|
87329
|
-
out.push(` ${
|
|
87330
|
-
out.push(` ${
|
|
87331
|
-
out.push(` ${
|
|
89000
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
|
|
89001
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
|
|
89002
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
|
|
89003
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
|
|
89004
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
|
|
89005
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
|
|
89006
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
|
|
89007
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT; the only PAT control-plane commands accept (token.json is not read there)`);
|
|
89008
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
|
|
89009
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
|
|
89010
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
|
|
87332
89011
|
out.push("");
|
|
87333
|
-
out.push(` ${
|
|
87334
|
-
out.push(` ${
|
|
87335
|
-
out.push(` ${
|
|
87336
|
-
out.push(` ${
|
|
87337
|
-
out.push(` ${
|
|
87338
|
-
out.push(` ${
|
|
89012
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
|
|
89013
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
|
|
89014
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
|
|
89015
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
|
|
89016
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
|
|
89017
|
+
out.push(` ${import_picocolors61.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
|
|
87339
89018
|
out.push("");
|
|
87340
89019
|
out.push(divider("HARNESSES"));
|
|
87341
89020
|
out.push("");
|
|
87342
|
-
out.push(` ${
|
|
87343
|
-
out.push(` ${
|
|
87344
|
-
out.push(` ${
|
|
89021
|
+
out.push(` ${import_picocolors61.default.dim("•")} ${import_picocolors61.default.bold("claude-code")} ${import_picocolors61.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
|
|
89022
|
+
out.push(` ${import_picocolors61.default.dim("•")} ${import_picocolors61.default.bold("codex")} ${import_picocolors61.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
|
|
89023
|
+
out.push(` ${import_picocolors61.default.dim("•")} ${import_picocolors61.default.bold("kafka")} ${import_picocolors61.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
|
|
87345
89024
|
out.push("");
|
|
87346
89025
|
console.log(out.join(`
|
|
87347
89026
|
`));
|
|
@@ -87495,13 +89174,13 @@ async function requireAuth(cmd) {
|
|
|
87495
89174
|
if (STORED_PAT_COMMANDS.has(cmd) && readToken())
|
|
87496
89175
|
return;
|
|
87497
89176
|
console.error("");
|
|
87498
|
-
console.error(` ${brandTint("◆")} ${
|
|
89177
|
+
console.error(` ${brandTint("◆")} ${import_picocolors61.default.bold("brainbase")}`);
|
|
87499
89178
|
console.error("");
|
|
87500
|
-
console.error(` ${
|
|
89179
|
+
console.error(` ${import_picocolors61.default.red("✗")} You need to sign in to use ${import_picocolors61.default.bold("brainbase " + cmd)}.`);
|
|
87501
89180
|
if (status.reason)
|
|
87502
|
-
console.error(` ${
|
|
89181
|
+
console.error(` ${import_picocolors61.default.dim(status.reason)}`);
|
|
87503
89182
|
console.error("");
|
|
87504
|
-
console.error(` Run ${
|
|
89183
|
+
console.error(` Run ${import_picocolors61.default.cyan("brainbase login")} to connect this device.`);
|
|
87505
89184
|
console.error("");
|
|
87506
89185
|
process14.exit(1);
|
|
87507
89186
|
}
|
|
@@ -87682,6 +89361,17 @@ async function main() {
|
|
|
87682
89361
|
await runTask(cwd2, sub, argv);
|
|
87683
89362
|
break;
|
|
87684
89363
|
}
|
|
89364
|
+
case "machine":
|
|
89365
|
+
case "machines": {
|
|
89366
|
+
const sub = argv.shift();
|
|
89367
|
+
await runMachine(sub, argv, {
|
|
89368
|
+
all,
|
|
89369
|
+
limit: limitFlag,
|
|
89370
|
+
yes,
|
|
89371
|
+
json: jsonFlag
|
|
89372
|
+
});
|
|
89373
|
+
break;
|
|
89374
|
+
}
|
|
87685
89375
|
case "benchmark": {
|
|
87686
89376
|
const sub = argv.shift();
|
|
87687
89377
|
process14.exitCode = await runBenchmark(sub, argv, undefined, cwd2);
|
|
@@ -87696,6 +89386,7 @@ async function main() {
|
|
|
87696
89386
|
orgId: orgIdFlag,
|
|
87697
89387
|
teamId: teamIdFlag,
|
|
87698
89388
|
graphOnly: graphOnlyFlag,
|
|
89389
|
+
force: forceFlag,
|
|
87699
89390
|
name: nameFlag,
|
|
87700
89391
|
from: fromFlags,
|
|
87701
89392
|
to: toFlags,
|
|
@@ -87726,10 +89417,10 @@ async function main() {
|
|
|
87726
89417
|
process14.exit(1);
|
|
87727
89418
|
}
|
|
87728
89419
|
} catch (err) {
|
|
87729
|
-
console.error(
|
|
89420
|
+
console.error(import_picocolors61.default.red(`
|
|
87730
89421
|
${err.message}`));
|
|
87731
89422
|
if (err instanceof ApiError && err.status === 401) {
|
|
87732
|
-
console.error(` Run ${
|
|
89423
|
+
console.error(` Run ${import_picocolors61.default.cyan("brainbase login")} to connect this device.`);
|
|
87733
89424
|
}
|
|
87734
89425
|
if (process14.env.BRAINBASE_DEBUG)
|
|
87735
89426
|
console.error(err.stack);
|