@brainbase-labs/cli 0.20.0 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +887 -328
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31708,8 +31708,8 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
31708
31708
|
}
|
|
31709
31709
|
return ind;
|
|
31710
31710
|
}
|
|
31711
|
-
function removeDotSegments(
|
|
31712
|
-
let input =
|
|
31711
|
+
function removeDotSegments(path88) {
|
|
31712
|
+
let input = path88;
|
|
31713
31713
|
const output = [];
|
|
31714
31714
|
let nextSlash = -1;
|
|
31715
31715
|
let len = 0;
|
|
@@ -31952,8 +31952,8 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
31952
31952
|
wsComponent.secure = undefined;
|
|
31953
31953
|
}
|
|
31954
31954
|
if (wsComponent.resourceName) {
|
|
31955
|
-
const [
|
|
31956
|
-
wsComponent.path =
|
|
31955
|
+
const [path88, query] = wsComponent.resourceName.split("?");
|
|
31956
|
+
wsComponent.path = path88 && path88 !== "/" ? path88 : undefined;
|
|
31957
31957
|
wsComponent.query = query;
|
|
31958
31958
|
wsComponent.resourceName = undefined;
|
|
31959
31959
|
}
|
|
@@ -35128,12 +35128,12 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
35128
35128
|
throw new Error(`Unknown format "${name}"`);
|
|
35129
35129
|
return f4;
|
|
35130
35130
|
};
|
|
35131
|
-
function addFormats(ajv, list,
|
|
35131
|
+
function addFormats(ajv, list, fs80, exportName) {
|
|
35132
35132
|
var _a;
|
|
35133
35133
|
var _b;
|
|
35134
35134
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== undefined || (_b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`);
|
|
35135
35135
|
for (const f4 of list)
|
|
35136
|
-
ajv.addFormat(f4,
|
|
35136
|
+
ajv.addFormat(f4, fs80[f4]);
|
|
35137
35137
|
}
|
|
35138
35138
|
module.exports = exports = formatsPlugin;
|
|
35139
35139
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -35143,7 +35143,7 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
35143
35143
|
// src/index.ts
|
|
35144
35144
|
var import_picocolors49 = __toESM(require_picocolors(), 1);
|
|
35145
35145
|
import process14 from "node:process";
|
|
35146
|
-
import
|
|
35146
|
+
import fs82 from "node:fs";
|
|
35147
35147
|
|
|
35148
35148
|
// src/cli/template.ts
|
|
35149
35149
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
|
|
|
36008
36008
|
// package.json
|
|
36009
36009
|
var package_default = {
|
|
36010
36010
|
name: "@brainbase-labs/cli",
|
|
36011
|
-
version: "0.
|
|
36011
|
+
version: "0.21.1",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -40917,7 +40917,7 @@ function readAuth() {
|
|
|
40917
40917
|
}
|
|
40918
40918
|
}
|
|
40919
40919
|
function acquireLock(lockFile, timeoutMs) {
|
|
40920
|
-
ensureDir(
|
|
40920
|
+
ensureDir(path8.dirname(lockFile));
|
|
40921
40921
|
const deadline = Date.now() + timeoutMs;
|
|
40922
40922
|
const lockId = randomUUID();
|
|
40923
40923
|
const owner = `${process.pid}:${lockId}`;
|
|
@@ -53845,6 +53845,8 @@ function apiErrorMessage(body, status) {
|
|
|
53845
53845
|
import path57 from "node:path";
|
|
53846
53846
|
import fs47 from "node:fs";
|
|
53847
53847
|
var TOKEN_FILE = path57.join(BRAINBASE_HOME, "token.json");
|
|
53848
|
+
var TOKEN_LOCK_FILE = `${TOKEN_FILE}.lock`;
|
|
53849
|
+
var TOKEN_LOCK_TIMEOUT_MS = 5000;
|
|
53848
53850
|
var TOKEN_PREFIX = "bbpat_";
|
|
53849
53851
|
var TOKEN_PREFIX_LEN = 14;
|
|
53850
53852
|
function tokenPrefix(token) {
|
|
@@ -53867,6 +53869,17 @@ var StoredTokenSchema = exports_external.object({
|
|
|
53867
53869
|
name: exports_external.string().optional(),
|
|
53868
53870
|
createdAt: exports_external.string()
|
|
53869
53871
|
});
|
|
53872
|
+
function withTokenLock(operation) {
|
|
53873
|
+
const release = acquireLock(TOKEN_LOCK_FILE, TOKEN_LOCK_TIMEOUT_MS);
|
|
53874
|
+
if (!release) {
|
|
53875
|
+
throw new Error(`Timed out waiting to update the local CLI token; if no other brainbase process is running, remove ${TOKEN_LOCK_FILE}`);
|
|
53876
|
+
}
|
|
53877
|
+
try {
|
|
53878
|
+
return operation();
|
|
53879
|
+
} finally {
|
|
53880
|
+
release();
|
|
53881
|
+
}
|
|
53882
|
+
}
|
|
53870
53883
|
function readToken() {
|
|
53871
53884
|
if (!exists(TOKEN_FILE))
|
|
53872
53885
|
return null;
|
|
@@ -53880,7 +53893,6 @@ function writeToken(token, name) {
|
|
|
53880
53893
|
if (!isValidTokenFormat(token)) {
|
|
53881
53894
|
throw new Error("refusing to store token: invalid format");
|
|
53882
53895
|
}
|
|
53883
|
-
ensureDir(BRAINBASE_HOME);
|
|
53884
53896
|
const stored = {
|
|
53885
53897
|
schemaVersion: 1,
|
|
53886
53898
|
token,
|
|
@@ -53888,15 +53900,35 @@ function writeToken(token, name) {
|
|
|
53888
53900
|
name,
|
|
53889
53901
|
createdAt: new Date().toISOString()
|
|
53890
53902
|
};
|
|
53891
|
-
|
|
53892
|
-
try {
|
|
53893
|
-
fs47.chmodSync(TOKEN_FILE, 384);
|
|
53894
|
-
} catch {}
|
|
53903
|
+
withTokenLock(() => writeJsonAtomic(TOKEN_FILE, stored));
|
|
53895
53904
|
return stored;
|
|
53896
53905
|
}
|
|
53897
53906
|
function clearToken() {
|
|
53898
|
-
|
|
53899
|
-
|
|
53907
|
+
withTokenLock(() => {
|
|
53908
|
+
if (exists(TOKEN_FILE))
|
|
53909
|
+
fs47.rmSync(TOKEN_FILE);
|
|
53910
|
+
});
|
|
53911
|
+
}
|
|
53912
|
+
function clearTokenIfMatches(prefix) {
|
|
53913
|
+
if (!prefix.startsWith(TOKEN_PREFIX))
|
|
53914
|
+
return "unverifiable";
|
|
53915
|
+
if (prefix.length < TOKEN_PREFIX_LEN)
|
|
53916
|
+
return "unverifiable";
|
|
53917
|
+
const before2 = readToken();
|
|
53918
|
+
if (!before2)
|
|
53919
|
+
return "absent";
|
|
53920
|
+
if (!before2.token.startsWith(prefix))
|
|
53921
|
+
return "kept";
|
|
53922
|
+
return withTokenLock(() => {
|
|
53923
|
+
const stored = readToken();
|
|
53924
|
+
if (!stored)
|
|
53925
|
+
return "absent";
|
|
53926
|
+
if (!stored.token.startsWith(prefix))
|
|
53927
|
+
return "kept";
|
|
53928
|
+
if (exists(TOKEN_FILE))
|
|
53929
|
+
fs47.rmSync(TOKEN_FILE);
|
|
53930
|
+
return "cleared";
|
|
53931
|
+
});
|
|
53900
53932
|
}
|
|
53901
53933
|
|
|
53902
53934
|
// src/core/api.ts
|
|
@@ -54297,8 +54329,13 @@ var api = {
|
|
|
54297
54329
|
body: JSON.stringify(input)
|
|
54298
54330
|
});
|
|
54299
54331
|
},
|
|
54300
|
-
getAgentSecrets(agentId) {
|
|
54301
|
-
|
|
54332
|
+
async getAgentSecrets(agentId) {
|
|
54333
|
+
const body = await request(`/agents/${encodeURIComponent(agentId)}/secrets`);
|
|
54334
|
+
const secrets = body && typeof body === "object" ? body.secrets : undefined;
|
|
54335
|
+
if (!secrets || typeof secrets !== "object" || Array.isArray(secrets) || !Object.values(secrets).every((value) => typeof value === "string")) {
|
|
54336
|
+
throw new ApiError("The control plane returned an unreadable secrets response", undefined);
|
|
54337
|
+
}
|
|
54338
|
+
return { secrets };
|
|
54302
54339
|
},
|
|
54303
54340
|
putAgentSecrets(agentId, secrets) {
|
|
54304
54341
|
return request(`/agents/${encodeURIComponent(agentId)}/secrets`, {
|
|
@@ -54599,6 +54636,12 @@ var registryApi = {
|
|
|
54599
54636
|
body: JSON.stringify(input)
|
|
54600
54637
|
});
|
|
54601
54638
|
},
|
|
54639
|
+
renameCliToken(id, name) {
|
|
54640
|
+
return jsonRequest(`/v1/registry/cli-tokens/${encodeURIComponent(id)}`, {
|
|
54641
|
+
method: "PATCH",
|
|
54642
|
+
body: JSON.stringify({ name })
|
|
54643
|
+
});
|
|
54644
|
+
},
|
|
54602
54645
|
revokeCliToken(id) {
|
|
54603
54646
|
return jsonRequest(`/v1/registry/cli-tokens/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
54604
54647
|
}
|
|
@@ -61679,6 +61722,20 @@ var DEFAULT_INSTRUCTIONS_FILE = ".brainbase/instructions.md";
|
|
|
61679
61722
|
var DEFAULT_ENTRYPOINT_FILE = ".brainbase/entrypoint.sh";
|
|
61680
61723
|
var DEFAULT_PLAYBOOKS_DIR = ".brainbase/playbooks";
|
|
61681
61724
|
var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
|
|
61725
|
+
var EXACT_VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
61726
|
+
function skillSourceVersionError(raw) {
|
|
61727
|
+
const m3 = raw.match(REGISTRY_SOURCE_RE);
|
|
61728
|
+
if (!m3) {
|
|
61729
|
+
if (!/^registry:/i.test(raw))
|
|
61730
|
+
return null;
|
|
61731
|
+
return `"${raw}" is not a valid registry source — expected ` + `"registry:creator/slug" or "registry:creator/slug@1.0.0".`;
|
|
61732
|
+
}
|
|
61733
|
+
const version = m3[3];
|
|
61734
|
+
if (!version || EXACT_VERSION_RE.test(version))
|
|
61735
|
+
return null;
|
|
61736
|
+
const head3 = m3[1] ? `${m3[1]}/${m3[2]}` : m3[2];
|
|
61737
|
+
return `"@${version}" is not supported — pin an exact version, e.g. ` + `"registry:${head3}@1.0.0", or drop the version to track the latest.`;
|
|
61738
|
+
}
|
|
61682
61739
|
function parseSkillSource2(raw) {
|
|
61683
61740
|
if (!raw || typeof raw !== "string") {
|
|
61684
61741
|
throw new Error("Skill source must be a non-empty string");
|
|
@@ -61734,7 +61791,11 @@ var PlaybookSchema = exports_external.object({
|
|
|
61734
61791
|
content: PlaybookContentSchema
|
|
61735
61792
|
});
|
|
61736
61793
|
var SkillEntrySchema = exports_external.object({
|
|
61737
|
-
source: exports_external.string().min(1)
|
|
61794
|
+
source: exports_external.string().min(1).superRefine((raw, ctx) => {
|
|
61795
|
+
const message = skillSourceVersionError(raw);
|
|
61796
|
+
if (message)
|
|
61797
|
+
ctx.addIssue({ code: exports_external.ZodIssueCode.custom, message });
|
|
61798
|
+
})
|
|
61738
61799
|
});
|
|
61739
61800
|
var McpEntrySchema = exports_external.object({
|
|
61740
61801
|
name: exports_external.string().min(1),
|
|
@@ -61779,6 +61840,9 @@ var EvalSchema = exports_external.object({
|
|
|
61779
61840
|
path: ["classification_values"]
|
|
61780
61841
|
});
|
|
61781
61842
|
var MODEL_ID_RE = /^[A-Za-z0-9._:/-]{1,128}$/;
|
|
61843
|
+
var UNSYNCED_MANIFEST_KEYS = ["commands", "hooks", "files"];
|
|
61844
|
+
var UnsyncedBlockSchema = exports_external.array(exports_external.record(exports_external.unknown())).optional();
|
|
61845
|
+
var UnsyncedBlocksShape = Object.fromEntries(UNSYNCED_MANIFEST_KEYS.map((key2) => [key2, UnsyncedBlockSchema]));
|
|
61782
61846
|
var AgentManifestSchema = exports_external.object({
|
|
61783
61847
|
schema: exports_external.literal(1),
|
|
61784
61848
|
id: exports_external.string().min(1).optional(),
|
|
@@ -61805,9 +61869,7 @@ var AgentManifestSchema = exports_external.object({
|
|
|
61805
61869
|
});
|
|
61806
61870
|
}).default([]),
|
|
61807
61871
|
capabilities: CapabilitiesSchema.optional(),
|
|
61808
|
-
|
|
61809
|
-
hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
|
|
61810
|
-
files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
|
|
61872
|
+
...UnsyncedBlocksShape
|
|
61811
61873
|
});
|
|
61812
61874
|
function manifestPath(cwd2) {
|
|
61813
61875
|
return path73.join(cwd2, AGENT_MANIFEST_FILE);
|
|
@@ -62938,6 +63000,7 @@ async function runSync(cwd2, args) {
|
|
|
62938
63000
|
caps = capabilitiesFromManifest(readManifest(cwd2));
|
|
62939
63001
|
} catch (err) {
|
|
62940
63002
|
f2.error(err.message);
|
|
63003
|
+
process.exitCode = 1;
|
|
62941
63004
|
return;
|
|
62942
63005
|
}
|
|
62943
63006
|
const declaredMcpSlugs = new Set(manifest.components.filter((c2) => c2.type === "mcp").map((c2) => c2.slug));
|
|
@@ -63225,13 +63288,132 @@ var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
|
63225
63288
|
// src/cli/agent-pull.ts
|
|
63226
63289
|
import { spawn as spawn2 } from "node:child_process";
|
|
63227
63290
|
import path80 from "node:path";
|
|
63228
|
-
import
|
|
63291
|
+
import fs73 from "node:fs";
|
|
63229
63292
|
import os14 from "node:os";
|
|
63230
63293
|
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
63231
63294
|
|
|
63295
|
+
// src/core/manifest-unsynced.ts
|
|
63296
|
+
import fs69 from "node:fs";
|
|
63297
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
63298
|
+
function findUnsyncedBlocks(manifest) {
|
|
63299
|
+
const found = [];
|
|
63300
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63301
|
+
const block = manifest[key2];
|
|
63302
|
+
if (Array.isArray(block) && block.length > 0) {
|
|
63303
|
+
found.push({ key: key2, entries: block.length });
|
|
63304
|
+
}
|
|
63305
|
+
}
|
|
63306
|
+
return found;
|
|
63307
|
+
}
|
|
63308
|
+
function unsyncedBlockReason(block) {
|
|
63309
|
+
const entries = `${block.entries} ${block.entries === 1 ? "entry" : "entries"}`;
|
|
63310
|
+
return `\`${block.key}\` is declared in ${AGENT_MANIFEST_FILE} (${entries}) but this ` + `CLI does not sync ${block.key} yet — pushing would discard it.`;
|
|
63311
|
+
}
|
|
63312
|
+
function unsyncedBlockRemedy(blocks) {
|
|
63313
|
+
const keys2 = blocks.map((b4) => `\`${b4.key}\``).join(", ");
|
|
63314
|
+
const plural = blocks.length === 1 ? "" : "s";
|
|
63315
|
+
return `Remove the ${keys2} block${plural} from ${AGENT_MANIFEST_FILE} to continue. ` + `These blocks are unsupported with no target release — see "Reserved ` + `fields" in the agent manifest reference.`;
|
|
63316
|
+
}
|
|
63317
|
+
function reportUnsyncedBlocks(manifest, opts = {}) {
|
|
63318
|
+
const blocks = findUnsyncedBlocks(manifest);
|
|
63319
|
+
if (blocks.length === 0)
|
|
63320
|
+
return false;
|
|
63321
|
+
const prefix = opts.label ? `${opts.label}: ` : "";
|
|
63322
|
+
for (const block of blocks) {
|
|
63323
|
+
f2.error(`${prefix}${unsyncedBlockReason(block)}`);
|
|
63324
|
+
}
|
|
63325
|
+
f2.info(unsyncedBlockRemedy(blocks));
|
|
63326
|
+
return true;
|
|
63327
|
+
}
|
|
63328
|
+
function carryForwardUnsyncedBlocks(prev) {
|
|
63329
|
+
const carried = {};
|
|
63330
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63331
|
+
const block = prev?.[key2];
|
|
63332
|
+
if (block !== undefined)
|
|
63333
|
+
carried[key2] = block;
|
|
63334
|
+
}
|
|
63335
|
+
return carried;
|
|
63336
|
+
}
|
|
63337
|
+
function salvageLocalOnlyContent(raw) {
|
|
63338
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
63339
|
+
return {};
|
|
63340
|
+
const doc = raw;
|
|
63341
|
+
const salvaged = {};
|
|
63342
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63343
|
+
if (doc[key2] === undefined)
|
|
63344
|
+
continue;
|
|
63345
|
+
const result2 = AgentManifestSchema.shape[key2].safeParse(doc[key2]);
|
|
63346
|
+
if (result2.success && result2.data !== undefined) {
|
|
63347
|
+
salvaged[key2] = result2.data;
|
|
63348
|
+
}
|
|
63349
|
+
}
|
|
63350
|
+
if (doc.evals !== undefined) {
|
|
63351
|
+
const evals = AgentManifestSchema.shape.evals.safeParse(doc.evals);
|
|
63352
|
+
if (evals.success)
|
|
63353
|
+
salvaged.evals = evals.data;
|
|
63354
|
+
}
|
|
63355
|
+
return salvaged;
|
|
63356
|
+
}
|
|
63357
|
+
function readLocalOnlyContent(cwd2) {
|
|
63358
|
+
if (!hasManifest(cwd2))
|
|
63359
|
+
return { content: {}, status: "absent" };
|
|
63360
|
+
try {
|
|
63361
|
+
const prev = readManifest(cwd2);
|
|
63362
|
+
return {
|
|
63363
|
+
content: {
|
|
63364
|
+
evals: prev?.evals ?? [],
|
|
63365
|
+
...carryForwardUnsyncedBlocks(prev)
|
|
63366
|
+
},
|
|
63367
|
+
status: "parsed"
|
|
63368
|
+
};
|
|
63369
|
+
} catch {}
|
|
63370
|
+
const file = existingManifestPath(cwd2);
|
|
63371
|
+
let raw = null;
|
|
63372
|
+
if (file) {
|
|
63373
|
+
try {
|
|
63374
|
+
raw = import_yaml3.default.parse(fs69.readFileSync(file, "utf8"));
|
|
63375
|
+
} catch {
|
|
63376
|
+
raw = null;
|
|
63377
|
+
}
|
|
63378
|
+
}
|
|
63379
|
+
const content = salvageLocalOnlyContent(raw);
|
|
63380
|
+
return {
|
|
63381
|
+
content,
|
|
63382
|
+
status: Object.keys(content).length > 0 ? "recovered" : "unreadable"
|
|
63383
|
+
};
|
|
63384
|
+
}
|
|
63385
|
+
function readManifestAgentId(cwd2) {
|
|
63386
|
+
if (!hasManifest(cwd2))
|
|
63387
|
+
return;
|
|
63388
|
+
const clean = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
63389
|
+
try {
|
|
63390
|
+
return clean(readManifest(cwd2)?.id);
|
|
63391
|
+
} catch {}
|
|
63392
|
+
const file = existingManifestPath(cwd2);
|
|
63393
|
+
if (!file)
|
|
63394
|
+
return;
|
|
63395
|
+
try {
|
|
63396
|
+
const raw = import_yaml3.default.parse(fs69.readFileSync(file, "utf8"));
|
|
63397
|
+
if (!raw || typeof raw !== "object")
|
|
63398
|
+
return;
|
|
63399
|
+
return clean(raw.id);
|
|
63400
|
+
} catch {
|
|
63401
|
+
return;
|
|
63402
|
+
}
|
|
63403
|
+
}
|
|
63404
|
+
function readLocalOnlyContentReporting(cwd2) {
|
|
63405
|
+
const { content, status } = readLocalOnlyContent(cwd2);
|
|
63406
|
+
if (status === "recovered") {
|
|
63407
|
+
f2.warn(`${AGENT_MANIFEST_FILE} could not be read; kept its ${Object.keys(content).join(", ")} and rebuilt the rest from the cloud.`);
|
|
63408
|
+
} else if (status === "unreadable") {
|
|
63409
|
+
f2.warn(`${AGENT_MANIFEST_FILE} could not be read and was replaced with cloud state.`);
|
|
63410
|
+
}
|
|
63411
|
+
return content;
|
|
63412
|
+
}
|
|
63413
|
+
|
|
63232
63414
|
// src/core/agent-diff.ts
|
|
63233
63415
|
import path77 from "node:path";
|
|
63234
|
-
import
|
|
63416
|
+
import fs70 from "node:fs";
|
|
63235
63417
|
import crypto4 from "node:crypto";
|
|
63236
63418
|
function compKey(type, slug) {
|
|
63237
63419
|
return `${type}/${slug}`;
|
|
@@ -63281,7 +63463,7 @@ function fileHash(p2) {
|
|
|
63281
63463
|
if (!exists(p2))
|
|
63282
63464
|
return null;
|
|
63283
63465
|
try {
|
|
63284
|
-
const buf =
|
|
63466
|
+
const buf = fs70.readFileSync(p2);
|
|
63285
63467
|
return crypto4.createHash("sha256").update(buf).digest("hex");
|
|
63286
63468
|
} catch {
|
|
63287
63469
|
return null;
|
|
@@ -63303,7 +63485,7 @@ function hashDirectoryAsComponent(dir) {
|
|
|
63303
63485
|
const walk = (sub) => {
|
|
63304
63486
|
let entries;
|
|
63305
63487
|
try {
|
|
63306
|
-
entries =
|
|
63488
|
+
entries = fs70.readdirSync(sub, { withFileTypes: true });
|
|
63307
63489
|
} catch {
|
|
63308
63490
|
return;
|
|
63309
63491
|
}
|
|
@@ -63571,7 +63753,7 @@ function diffAgentConfig(manifest, lock, cloud) {
|
|
|
63571
63753
|
|
|
63572
63754
|
// src/core/secrets-env.ts
|
|
63573
63755
|
import path78 from "node:path";
|
|
63574
|
-
import
|
|
63756
|
+
import fs71 from "node:fs";
|
|
63575
63757
|
var SECRETS_FILE = "secrets.env";
|
|
63576
63758
|
function secretsPath(cwd2) {
|
|
63577
63759
|
return path78.join(cwd2, LINK_DIR, SECRETS_FILE);
|
|
@@ -63619,18 +63801,18 @@ function readLocalSecrets(cwd2) {
|
|
|
63619
63801
|
const p2 = secretsPath(cwd2);
|
|
63620
63802
|
if (!exists(p2))
|
|
63621
63803
|
return {};
|
|
63622
|
-
return parseSecretsEnv(
|
|
63804
|
+
return parseSecretsEnv(fs71.readFileSync(p2, "utf8"));
|
|
63623
63805
|
}
|
|
63624
63806
|
function writeLocalSecrets(cwd2, secrets) {
|
|
63625
63807
|
ensureDir(path78.join(cwd2, LINK_DIR));
|
|
63626
|
-
|
|
63808
|
+
fs71.writeFileSync(secretsPath(cwd2), formatSecretsEnv(secrets), "utf8");
|
|
63627
63809
|
ensureSecretsGitignore(cwd2);
|
|
63628
63810
|
}
|
|
63629
63811
|
function ensureSecretsGitignore(cwd2) {
|
|
63630
63812
|
const ignorePath = path78.join(cwd2, LINK_DIR, ".gitignore");
|
|
63631
63813
|
const needed = [SYNC_STATE_FILE, SECRETS_FILE];
|
|
63632
63814
|
try {
|
|
63633
|
-
const current = exists(ignorePath) ?
|
|
63815
|
+
const current = exists(ignorePath) ? fs71.readFileSync(ignorePath, "utf8") : "";
|
|
63634
63816
|
const lines = new Set(current.split(/\r?\n/).map((l2) => l2.trim()).filter(Boolean));
|
|
63635
63817
|
let changed = false;
|
|
63636
63818
|
for (const n of needed) {
|
|
@@ -63640,7 +63822,7 @@ function ensureSecretsGitignore(cwd2) {
|
|
|
63640
63822
|
}
|
|
63641
63823
|
}
|
|
63642
63824
|
if (changed) {
|
|
63643
|
-
|
|
63825
|
+
fs71.writeFileSync(ignorePath, [...lines].join(`
|
|
63644
63826
|
`) + `
|
|
63645
63827
|
`);
|
|
63646
63828
|
}
|
|
@@ -63679,7 +63861,7 @@ function entrypointExecutionAllowed(opts) {
|
|
|
63679
63861
|
|
|
63680
63862
|
// src/cli/agent-unpack.ts
|
|
63681
63863
|
import path79 from "node:path";
|
|
63682
|
-
import
|
|
63864
|
+
import fs72 from "node:fs";
|
|
63683
63865
|
import os13 from "node:os";
|
|
63684
63866
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
63685
63867
|
function componentsForNativeInstall(components, acp) {
|
|
@@ -63697,6 +63879,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63697
63879
|
manifest = readManifest(cwd2);
|
|
63698
63880
|
} catch (err) {
|
|
63699
63881
|
f2.error(err.message);
|
|
63882
|
+
process.exitCode = 1;
|
|
63700
63883
|
return;
|
|
63701
63884
|
}
|
|
63702
63885
|
if (!manifest.id) {
|
|
@@ -63727,14 +63910,14 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63727
63910
|
}
|
|
63728
63911
|
}
|
|
63729
63912
|
const scope = args.scope ?? "project";
|
|
63730
|
-
const stageRoot =
|
|
63913
|
+
const stageRoot = fs72.mkdtempSync(path79.join(os13.tmpdir(), "brainbase-unpack-"));
|
|
63731
63914
|
try {
|
|
63732
63915
|
const toInstall = [];
|
|
63733
63916
|
const instructionsBody = readInstructions(cwd2, manifest);
|
|
63734
63917
|
if (instructionsBody && instructionsBody.trim()) {
|
|
63735
63918
|
const compDir = path79.join(stageRoot, "instruction", "agent-instructions");
|
|
63736
63919
|
ensureDir(compDir);
|
|
63737
|
-
|
|
63920
|
+
fs72.writeFileSync(path79.join(compDir, "instructions.md"), instructionsBody, "utf8");
|
|
63738
63921
|
toInstall.push({
|
|
63739
63922
|
type: "instruction",
|
|
63740
63923
|
slug: "agent-instructions",
|
|
@@ -63813,7 +63996,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63813
63996
|
return;
|
|
63814
63997
|
} finally {
|
|
63815
63998
|
try {
|
|
63816
|
-
|
|
63999
|
+
fs72.rmSync(stageRoot, { recursive: true, force: true });
|
|
63817
64000
|
} catch {}
|
|
63818
64001
|
}
|
|
63819
64002
|
if (manifest.harness !== harness) {
|
|
@@ -63834,8 +64017,8 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63834
64017
|
function writeResolvedMcps(workdir, toInstall) {
|
|
63835
64018
|
const mcps = toInstall.filter((c2) => c2.type === "mcp").map((c2) => ({ name: c2.slug, ...c2.payload }));
|
|
63836
64019
|
const dir = path79.join(workdir, ".brainbase");
|
|
63837
|
-
|
|
63838
|
-
|
|
64020
|
+
fs72.mkdirSync(dir, { recursive: true });
|
|
64021
|
+
fs72.writeFileSync(path79.join(dir, "resolved-mcps.json"), JSON.stringify(mcps, null, 2));
|
|
63839
64022
|
}
|
|
63840
64023
|
function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
63841
64024
|
if (entry.content.text !== undefined && entry.content.file !== undefined) {
|
|
@@ -63849,7 +64032,7 @@ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
|
63849
64032
|
const compDir = path79.join(stageRoot, "playbook", slug);
|
|
63850
64033
|
ensureDir(compDir);
|
|
63851
64034
|
const wireBody = /^---\s*\n/.test(body) ? body : assembleFrontmatter(entry.title, entry.description) + body.replace(/^\n+/, "");
|
|
63852
|
-
|
|
64035
|
+
fs72.writeFileSync(path79.join(compDir, `${slug}.md`), wireBody, "utf8");
|
|
63853
64036
|
toInstall.push({
|
|
63854
64037
|
type: "playbook",
|
|
63855
64038
|
slug,
|
|
@@ -63863,7 +64046,7 @@ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
|
63863
64046
|
function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
|
|
63864
64047
|
if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/")) {
|
|
63865
64048
|
const abs = path79.resolve(cwd2, source);
|
|
63866
|
-
if (!
|
|
64049
|
+
if (!fs72.existsSync(abs)) {
|
|
63867
64050
|
return `Skill ${source}: not found on disk — skipped.`;
|
|
63868
64051
|
}
|
|
63869
64052
|
const slug = path79.basename(abs);
|
|
@@ -63936,13 +64119,13 @@ function defaultSlugForSource(source) {
|
|
|
63936
64119
|
}
|
|
63937
64120
|
function copyDirRecursive(src, dest) {
|
|
63938
64121
|
ensureDir(dest);
|
|
63939
|
-
for (const entry of
|
|
64122
|
+
for (const entry of fs72.readdirSync(src, { withFileTypes: true })) {
|
|
63940
64123
|
const s3 = path79.join(src, entry.name);
|
|
63941
64124
|
const d3 = path79.join(dest, entry.name);
|
|
63942
64125
|
if (entry.isDirectory())
|
|
63943
64126
|
copyDirRecursive(s3, d3);
|
|
63944
64127
|
else if (entry.isFile())
|
|
63945
|
-
|
|
64128
|
+
fs72.copyFileSync(s3, d3);
|
|
63946
64129
|
}
|
|
63947
64130
|
}
|
|
63948
64131
|
function assembleFrontmatter(title, description) {
|
|
@@ -64194,14 +64377,14 @@ async function runAgentPull(cwd2, args) {
|
|
|
64194
64377
|
if (!prior)
|
|
64195
64378
|
continue;
|
|
64196
64379
|
for (const filePath of prior.installedPaths) {
|
|
64197
|
-
if (!
|
|
64380
|
+
if (!fs73.existsSync(filePath))
|
|
64198
64381
|
continue;
|
|
64199
64382
|
try {
|
|
64200
|
-
const stat =
|
|
64383
|
+
const stat = fs73.statSync(filePath);
|
|
64201
64384
|
if (stat.isDirectory())
|
|
64202
|
-
|
|
64385
|
+
fs73.rmSync(filePath, { recursive: true, force: true });
|
|
64203
64386
|
else
|
|
64204
|
-
|
|
64387
|
+
fs73.rmSync(filePath);
|
|
64205
64388
|
} catch (err) {
|
|
64206
64389
|
f2.warn(`Failed to remove ${filePath}: ${err.message}`);
|
|
64207
64390
|
}
|
|
@@ -64210,7 +64393,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
64210
64393
|
materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
64211
64394
|
materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
|
|
64212
64395
|
materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
64213
|
-
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
|
|
64396
|
+
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness, override ? {} : readLocalOnlyContentReporting(cwd2));
|
|
64214
64397
|
writeManifest(cwd2, yaml);
|
|
64215
64398
|
writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
|
|
64216
64399
|
const lockComponents = buildLockComponents({
|
|
@@ -64240,7 +64423,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
64240
64423
|
$e(`Pulled ${cloudAgent.name} at revision ${cloud.revision}.`);
|
|
64241
64424
|
} finally {
|
|
64242
64425
|
try {
|
|
64243
|
-
|
|
64426
|
+
fs73.rmSync(stageRoot, { recursive: true, force: true });
|
|
64244
64427
|
} catch {}
|
|
64245
64428
|
}
|
|
64246
64429
|
}
|
|
@@ -64251,6 +64434,7 @@ function resolveTargetAgentId(cwd2, args) {
|
|
|
64251
64434
|
manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
|
|
64252
64435
|
} catch (err) {
|
|
64253
64436
|
f2.error(err.message);
|
|
64437
|
+
process.exitCode = 1;
|
|
64254
64438
|
return null;
|
|
64255
64439
|
}
|
|
64256
64440
|
const manifestId = manifest?.id;
|
|
@@ -64295,14 +64479,14 @@ function skillSourceFromMeta(c2) {
|
|
|
64295
64479
|
}
|
|
64296
64480
|
}
|
|
64297
64481
|
function stageManifestComponents(components) {
|
|
64298
|
-
const root =
|
|
64482
|
+
const root = fs73.mkdtempSync(path80.join(os14.tmpdir(), "brainbase-pull-"));
|
|
64299
64483
|
for (const c2 of components) {
|
|
64300
64484
|
const compDir = path80.join(root, c2.type, c2.slug);
|
|
64301
64485
|
ensureDir(compDir);
|
|
64302
64486
|
for (const f4 of c2.files) {
|
|
64303
64487
|
const target = path80.join(compDir, f4.path);
|
|
64304
64488
|
ensureDir(path80.dirname(target));
|
|
64305
|
-
|
|
64489
|
+
fs73.writeFileSync(target, f4.content);
|
|
64306
64490
|
}
|
|
64307
64491
|
}
|
|
64308
64492
|
return root;
|
|
@@ -64345,7 +64529,7 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingMani
|
|
|
64345
64529
|
const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
|
|
64346
64530
|
const target = path80.resolve(cwd2, targetRel);
|
|
64347
64531
|
ensureDir(path80.dirname(target));
|
|
64348
|
-
|
|
64532
|
+
fs73.writeFileSync(target, normalizeInstructionBody(body), "utf8");
|
|
64349
64533
|
}
|
|
64350
64534
|
}
|
|
64351
64535
|
function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
|
|
@@ -64367,10 +64551,10 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
|
|
|
64367
64551
|
const targetRel = existing?.content?.file ?? path80.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
|
|
64368
64552
|
const target = path80.resolve(cwd2, targetRel);
|
|
64369
64553
|
ensureDir(path80.dirname(target));
|
|
64370
|
-
|
|
64554
|
+
fs73.writeFileSync(target, body, "utf8");
|
|
64371
64555
|
}
|
|
64372
64556
|
}
|
|
64373
|
-
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
64557
|
+
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness, localOnly = {}) {
|
|
64374
64558
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
64375
64559
|
const localDecl = prev?.skills.find((s3) => looseSkillComponentSlug(s3.source) === c2.slug);
|
|
64376
64560
|
if (localDecl)
|
|
@@ -64451,7 +64635,8 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
|
64451
64635
|
playbooks,
|
|
64452
64636
|
skills,
|
|
64453
64637
|
mcp,
|
|
64454
|
-
evals:
|
|
64638
|
+
evals: [],
|
|
64639
|
+
...localOnly,
|
|
64455
64640
|
capabilities: {
|
|
64456
64641
|
memory: caps.memory,
|
|
64457
64642
|
browser: caps.browser,
|
|
@@ -64470,9 +64655,9 @@ function materializeEntrypoint(cwd2, cloudEntrypoint, prev) {
|
|
|
64470
64655
|
return;
|
|
64471
64656
|
const filename = prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE;
|
|
64472
64657
|
const target = path80.resolve(cwd2, filename);
|
|
64473
|
-
|
|
64658
|
+
fs73.writeFileSync(target, cloudEntrypoint, "utf8");
|
|
64474
64659
|
try {
|
|
64475
|
-
|
|
64660
|
+
fs73.chmodSync(target, 493);
|
|
64476
64661
|
} catch {}
|
|
64477
64662
|
}
|
|
64478
64663
|
function buildLockComponents(input) {
|
|
@@ -64551,9 +64736,9 @@ async function runEntrypointIfPresent(cwd2, manifest, execute) {
|
|
|
64551
64736
|
ensureDir(stateDir);
|
|
64552
64737
|
const scriptPath = path80.join(stateDir, "entrypoint.sh");
|
|
64553
64738
|
const logPath = path80.join(stateDir, "entrypoint.log");
|
|
64554
|
-
|
|
64739
|
+
fs73.writeFileSync(scriptPath, body, "utf8");
|
|
64555
64740
|
try {
|
|
64556
|
-
|
|
64741
|
+
fs73.chmodSync(scriptPath, 493);
|
|
64557
64742
|
} catch {}
|
|
64558
64743
|
if (!execute) {
|
|
64559
64744
|
f2.info(`Agent has an entrypoint — written to ${import_picocolors26.default.dim(path80.relative(cwd2, scriptPath))}, not executed. ` + `Run it with ${import_picocolors26.default.cyan("brainbase run bash .brainbase/entrypoint.sh")} or re-pull with ${import_picocolors26.default.cyan("--run-entrypoint")}. Sandboxes run it automatically.`);
|
|
@@ -64562,7 +64747,7 @@ async function runEntrypointIfPresent(cwd2, manifest, execute) {
|
|
|
64562
64747
|
f2.info(`Running entrypoint ${import_picocolors26.default.dim(`(${path80.relative(cwd2, scriptPath)})`)}`);
|
|
64563
64748
|
const secrets = readLocalSecrets(cwd2);
|
|
64564
64749
|
const env3 = { ...process.env, ...secrets };
|
|
64565
|
-
const logStream =
|
|
64750
|
+
const logStream = fs73.createWriteStream(logPath, { flags: "w" });
|
|
64566
64751
|
const exitCode = await new Promise((resolve) => {
|
|
64567
64752
|
const child = spawn2("bash", [scriptPath], {
|
|
64568
64753
|
cwd: cwd2,
|
|
@@ -64597,7 +64782,7 @@ async function pullSecrets(cwd2, agentId) {
|
|
|
64597
64782
|
sp.start("Fetching secrets…");
|
|
64598
64783
|
try {
|
|
64599
64784
|
const res = await api.getAgentSecrets(agentId);
|
|
64600
|
-
cloudSecrets = res.secrets
|
|
64785
|
+
cloudSecrets = res.secrets;
|
|
64601
64786
|
sp.stop(Object.keys(cloudSecrets).length === 0 ? "No secrets on cloud." : `Got ${Object.keys(cloudSecrets).length} secret${Object.keys(cloudSecrets).length === 1 ? "" : "s"}.`);
|
|
64602
64787
|
} catch (err) {
|
|
64603
64788
|
sp.stop("Failed to fetch secrets.");
|
|
@@ -64835,6 +65020,11 @@ async function runAgentPush(cwd2, args) {
|
|
|
64835
65020
|
manifest = readManifest(cwd2);
|
|
64836
65021
|
} catch (err) {
|
|
64837
65022
|
f2.error(err.message);
|
|
65023
|
+
process.exitCode = 1;
|
|
65024
|
+
return;
|
|
65025
|
+
}
|
|
65026
|
+
if (reportUnsyncedBlocks(manifest)) {
|
|
65027
|
+
process.exitCode = 1;
|
|
64838
65028
|
return;
|
|
64839
65029
|
}
|
|
64840
65030
|
if (!manifest.id) {
|
|
@@ -64939,6 +65129,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64939
65129
|
const version = registryRefs.get(name)?.version ?? "0.1.0";
|
|
64940
65130
|
f2.info(` ${import_picocolors28.default.cyan(`brainbase skill publish ./path/to/skill --name ${name} --skill-version ${version} --yes`)}`);
|
|
64941
65131
|
}
|
|
65132
|
+
process.exitCode = 1;
|
|
64942
65133
|
return;
|
|
64943
65134
|
}
|
|
64944
65135
|
const skillUpdates = planRegistrySkillUpdates(manifest.skills, cloud.components, latestByName);
|
|
@@ -64959,6 +65150,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64959
65150
|
} else {
|
|
64960
65151
|
f2.error("Entrypoint block is empty.");
|
|
64961
65152
|
}
|
|
65153
|
+
process.exitCode = 1;
|
|
64962
65154
|
return;
|
|
64963
65155
|
}
|
|
64964
65156
|
resolvedEntrypoint = body;
|
|
@@ -64971,6 +65163,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64971
65163
|
for (const r2 of rows) {
|
|
64972
65164
|
if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp" && r2.type !== "playbook") {
|
|
64973
65165
|
f2.error(`Component ${fmtType(r2.type)} ${import_picocolors28.default.bold(r2.slug)} can't be pushed yet — the server accepts instructions, skills, and mcps in this version.`);
|
|
65166
|
+
process.exitCode = 1;
|
|
64974
65167
|
return;
|
|
64975
65168
|
}
|
|
64976
65169
|
}
|
|
@@ -64983,6 +65176,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64983
65176
|
}
|
|
64984
65177
|
if (parsed.kind === "local") {
|
|
64985
65178
|
f2.error(`Skill ${import_picocolors28.default.bold(entry.source)} is a local-authored skill. Local skill push isn't supported yet — publish it to the registry first (\`brainbase skill publish\`).`);
|
|
65179
|
+
process.exitCode = 1;
|
|
64986
65180
|
return;
|
|
64987
65181
|
}
|
|
64988
65182
|
}
|
|
@@ -64995,6 +65189,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64995
65189
|
}).map((c2) => c2.slug);
|
|
64996
65190
|
if (preIdSchemaSlugs.length > 0) {
|
|
64997
65191
|
f2.error(`Playbook ${preIdSchemaSlugs.length === 1 ? "entry" : "entries"} ${preIdSchemaSlugs.map((s3) => import_picocolors28.default.bold(s3)).join(", ")} in ${import_picocolors28.default.bold("brainbase.agent.yaml")} ${preIdSchemaSlugs.length === 1 ? "is" : "are"} missing ${import_picocolors28.default.cyan("id:")}. Run ${import_picocolors28.default.bold("brainbase agent pull")} first to sync playbook ids, then push.`);
|
|
65192
|
+
process.exitCode = 1;
|
|
64998
65193
|
return;
|
|
64999
65194
|
}
|
|
65000
65195
|
const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
|
|
@@ -65005,6 +65200,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65005
65200
|
console.error(` ${import_picocolors28.default.red("!")} ${fmtType(r2.type)} ${import_picocolors28.default.bold(r2.slug)}`);
|
|
65006
65201
|
}
|
|
65007
65202
|
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent pull")} first to reconcile, then push again — or ${import_picocolors28.default.cyan("brainbase agent push --force")} to overwrite the cloud with your local version.`);
|
|
65203
|
+
process.exitCode = 1;
|
|
65008
65204
|
return;
|
|
65009
65205
|
}
|
|
65010
65206
|
if (forcedOverrides.length > 0) {
|
|
@@ -65281,7 +65477,7 @@ async function planSecretPush(cwd2, agentId) {
|
|
|
65281
65477
|
if (Object.keys(localSecrets).length === 0)
|
|
65282
65478
|
return null;
|
|
65283
65479
|
const res = await api.getAgentSecrets(agentId);
|
|
65284
|
-
const cloudSecrets = res.secrets
|
|
65480
|
+
const cloudSecrets = res.secrets;
|
|
65285
65481
|
const diff2 = diffSecrets(localSecrets, cloudSecrets);
|
|
65286
65482
|
if (diff2.localOnly.length === 0 && diff2.changed.length === 0 && diff2.cloudOnly.length === 0) {
|
|
65287
65483
|
return null;
|
|
@@ -65318,37 +65514,64 @@ function handleApiError3(err) {
|
|
|
65318
65514
|
}
|
|
65319
65515
|
|
|
65320
65516
|
// src/cli/agent-status.ts
|
|
65517
|
+
import path81 from "node:path";
|
|
65321
65518
|
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
65322
|
-
async function runAgentStatus(cwd2) {
|
|
65323
|
-
|
|
65519
|
+
async function runAgentStatus(cwd2, args = {}) {
|
|
65520
|
+
const json = args.json === true;
|
|
65521
|
+
if (!json)
|
|
65522
|
+
banner("agent status — what changed locally, remotely, both");
|
|
65324
65523
|
const link2 = readLink(cwd2);
|
|
65325
65524
|
if (!link2) {
|
|
65525
|
+
if (json) {
|
|
65526
|
+
emitJson({ linked: false, ignored: [], unchecked: [] });
|
|
65527
|
+
return;
|
|
65528
|
+
}
|
|
65326
65529
|
f2.warn("This folder is not linked to any agent.");
|
|
65327
65530
|
f2.info(`Run ${import_picocolors29.default.cyan("brainbase link")} first.`);
|
|
65328
65531
|
return;
|
|
65329
65532
|
}
|
|
65330
65533
|
const manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
|
|
65331
65534
|
const lock = readSyncState(cwd2);
|
|
65535
|
+
const ignoredBlocks = manifest ? findUnsyncedBlocks(manifest) : [];
|
|
65536
|
+
const ignored = ignoredBlocks.map((block) => ({
|
|
65537
|
+
block: block.key,
|
|
65538
|
+
entries: block.entries,
|
|
65539
|
+
reason: unsyncedBlockReason(block)
|
|
65540
|
+
}));
|
|
65332
65541
|
let cloud = null;
|
|
65333
65542
|
let cloudAgent = null;
|
|
65334
|
-
const sp = de();
|
|
65335
|
-
sp
|
|
65543
|
+
const sp = json ? null : de();
|
|
65544
|
+
sp?.start(`Fetching ${link2.name}…`);
|
|
65336
65545
|
try {
|
|
65337
65546
|
[cloud, cloudAgent] = await Promise.all([
|
|
65338
65547
|
api.getAgentManifest(link2.agent_id),
|
|
65339
65548
|
api.getAgent(link2.agent_id)
|
|
65340
65549
|
]);
|
|
65341
|
-
sp
|
|
65550
|
+
sp?.stop(`Cloud revision ${cloud.revision}.`);
|
|
65342
65551
|
} catch (err) {
|
|
65343
|
-
|
|
65344
|
-
|
|
65345
|
-
|
|
65346
|
-
|
|
65347
|
-
|
|
65552
|
+
const unauthorized = err instanceof ApiError && err.status === 401;
|
|
65553
|
+
const message = unauthorized ? "Your session is invalid. Run `brainbase login` and try again." : err.message;
|
|
65554
|
+
if (json) {
|
|
65555
|
+
console.error(message);
|
|
65556
|
+
process.exitCode = 1;
|
|
65557
|
+
return;
|
|
65348
65558
|
}
|
|
65559
|
+
sp?.stop("Failed to reach brainbase.");
|
|
65560
|
+
f2.error(message);
|
|
65349
65561
|
return;
|
|
65350
65562
|
}
|
|
65351
65563
|
if (!manifest) {
|
|
65564
|
+
if (json) {
|
|
65565
|
+
emitJson({
|
|
65566
|
+
linked: true,
|
|
65567
|
+
manifest: false,
|
|
65568
|
+
agent: { id: link2.agent_id, name: link2.name, slug: link2.slug },
|
|
65569
|
+
revision: { cloud: cloud.revision, lock: lock?.revision ?? null },
|
|
65570
|
+
ignored,
|
|
65571
|
+
unchecked: []
|
|
65572
|
+
});
|
|
65573
|
+
return;
|
|
65574
|
+
}
|
|
65352
65575
|
f2.info(`${import_picocolors29.default.dim("No")} ${import_picocolors29.default.bold("brainbase.agent.yaml")} ${import_picocolors29.default.dim("here yet.")} Run ${import_picocolors29.default.cyan("brainbase agent pull")} to populate this folder.`);
|
|
65353
65576
|
f2.info(`Cloud has ${import_picocolors29.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
|
|
65354
65577
|
return;
|
|
@@ -65388,13 +65611,74 @@ async function runAgentStatus(cwd2) {
|
|
|
65388
65611
|
break;
|
|
65389
65612
|
}
|
|
65390
65613
|
}
|
|
65614
|
+
let secretDrift = {
|
|
65615
|
+
localOnly: [],
|
|
65616
|
+
cloudOnly: [],
|
|
65617
|
+
changed: []
|
|
65618
|
+
};
|
|
65619
|
+
let secretsChecked = true;
|
|
65620
|
+
let secretsUncheckedReason = "";
|
|
65621
|
+
try {
|
|
65622
|
+
const localSecrets = readLocalSecrets(cwd2);
|
|
65623
|
+
const cloudRes = await api.getAgentSecrets(link2.agent_id);
|
|
65624
|
+
secretDrift = diffSecrets(localSecrets, cloudRes.secrets);
|
|
65625
|
+
} catch (err) {
|
|
65626
|
+
if (!(err instanceof ApiError && err.status === 404)) {
|
|
65627
|
+
secretsChecked = false;
|
|
65628
|
+
secretsUncheckedReason = describeSecretsFailure(err);
|
|
65629
|
+
}
|
|
65630
|
+
}
|
|
65631
|
+
const componentsDrifted = conflicts.length > 0 || toPush.length > 0 || toPull.length > 0;
|
|
65632
|
+
const metaDrifted = meta.localChanged || meta.cloudChanged;
|
|
65633
|
+
const configDrifted = config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged;
|
|
65634
|
+
const secretsDrifted = secretDrift.localOnly.length > 0 || secretDrift.cloudOnly.length > 0 || secretDrift.changed.length > 0;
|
|
65635
|
+
const everythingInSync = !componentsDrifted && !metaDrifted && !configDrifted && !secretsDrifted;
|
|
65636
|
+
const unchecked = secretsChecked ? [] : [{ signal: "secrets", reason: secretsUncheckedReason }];
|
|
65637
|
+
if (json) {
|
|
65638
|
+
emitJson({
|
|
65639
|
+
linked: true,
|
|
65640
|
+
manifest: true,
|
|
65641
|
+
agent: { id: link2.agent_id, name: link2.name, slug: link2.slug },
|
|
65642
|
+
revision: { cloud: cloud.revision, lock: lock?.revision ?? null },
|
|
65643
|
+
ignored,
|
|
65644
|
+
metadata: { push: meta.localChanged, pull: meta.cloudChanged },
|
|
65645
|
+
runtimeConfig: {
|
|
65646
|
+
unsupported: config.unsupported,
|
|
65647
|
+
machineMismatch: config.machineMismatch,
|
|
65648
|
+
machineCloudChanged: config.machineCloudChanged,
|
|
65649
|
+
defaultModelLocalChanged: config.defaultModelLocalChanged,
|
|
65650
|
+
defaultModelCloudChanged: config.defaultModelCloudChanged,
|
|
65651
|
+
defaultModelConflict: config.defaultModelConflict
|
|
65652
|
+
},
|
|
65653
|
+
secrets: secretsChecked ? {
|
|
65654
|
+
localOnly: secretDrift.localOnly,
|
|
65655
|
+
cloudOnly: secretDrift.cloudOnly,
|
|
65656
|
+
changed: secretDrift.changed
|
|
65657
|
+
} : null,
|
|
65658
|
+
components: {
|
|
65659
|
+
push: toPush.map(rowJson),
|
|
65660
|
+
pull: toPull.map(rowJson),
|
|
65661
|
+
conflicts: conflicts.map(rowJson)
|
|
65662
|
+
},
|
|
65663
|
+
inSync: everythingInSync,
|
|
65664
|
+
unchecked
|
|
65665
|
+
});
|
|
65666
|
+
return;
|
|
65667
|
+
}
|
|
65391
65668
|
const lines = [];
|
|
65392
65669
|
lines.push("");
|
|
65393
65670
|
lines.push(` ${import_picocolors29.default.bold(link2.name)} ${import_picocolors29.default.dim(`(${link2.slug})`)}`);
|
|
65394
65671
|
lines.push(` ${import_picocolors29.default.dim("agent_id")} ${link2.agent_id}`);
|
|
65395
65672
|
lines.push(` ${import_picocolors29.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
|
|
65396
65673
|
lines.push("");
|
|
65397
|
-
if (
|
|
65674
|
+
if (ignoredBlocks.length > 0) {
|
|
65675
|
+
lines.push(` ${import_picocolors29.default.bold("ignored manifest blocks")}`);
|
|
65676
|
+
for (const block of ignoredBlocks) {
|
|
65677
|
+
lines.push(` ${import_picocolors29.default.red("! ignored")} ${import_picocolors29.default.bold(block.key)} (${block.entries}) — not synced by this CLI; ${import_picocolors29.default.cyan("agent push")} will refuse it`);
|
|
65678
|
+
}
|
|
65679
|
+
lines.push("");
|
|
65680
|
+
}
|
|
65681
|
+
if (metaDrifted) {
|
|
65398
65682
|
lines.push(` ${import_picocolors29.default.bold("agent metadata")}`);
|
|
65399
65683
|
if (meta.localChanged) {
|
|
65400
65684
|
lines.push(` ${import_picocolors29.default.yellow("→ push")} name/tagline edited in brainbase.agent.yaml`);
|
|
@@ -65404,7 +65688,7 @@ async function runAgentStatus(cwd2) {
|
|
|
65404
65688
|
}
|
|
65405
65689
|
lines.push("");
|
|
65406
65690
|
}
|
|
65407
|
-
if (
|
|
65691
|
+
if (configDrifted) {
|
|
65408
65692
|
lines.push(` ${import_picocolors29.default.bold("runtime config")}`);
|
|
65409
65693
|
if (config.unsupported.length > 0) {
|
|
65410
65694
|
lines.push(` ${import_picocolors29.default.red("! unsupported")} ${config.unsupported.join(", ")} not exposed by this control plane`);
|
|
@@ -65427,24 +65711,22 @@ async function runAgentStatus(cwd2) {
|
|
|
65427
65711
|
}
|
|
65428
65712
|
lines.push("");
|
|
65429
65713
|
}
|
|
65430
|
-
|
|
65431
|
-
|
|
65432
|
-
|
|
65433
|
-
|
|
65434
|
-
|
|
65435
|
-
if (
|
|
65436
|
-
lines.push(`
|
|
65437
|
-
|
|
65438
|
-
|
|
65439
|
-
|
|
65440
|
-
|
|
65441
|
-
|
|
65442
|
-
|
|
65443
|
-
|
|
65444
|
-
}
|
|
65445
|
-
}
|
|
65446
|
-
if (conflicts.length === 0 && toPush.length === 0 && toPull.length === 0 && !meta.localChanged && !meta.cloudChanged && config.unsupported.length === 0 && !config.machineMismatch && !config.machineCloudChanged && !config.defaultModelLocalChanged && !config.defaultModelCloudChanged) {
|
|
65447
|
-
lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync`);
|
|
65714
|
+
if (secretsDrifted || !secretsChecked) {
|
|
65715
|
+
lines.push(` ${import_picocolors29.default.bold("secrets")}`);
|
|
65716
|
+
if (!secretsChecked) {
|
|
65717
|
+
lines.push(` ${import_picocolors29.default.dim("? unchecked")} ${secretsUncheckedReason}`);
|
|
65718
|
+
}
|
|
65719
|
+
if (secretDrift.localOnly.length)
|
|
65720
|
+
lines.push(` ${import_picocolors29.default.yellow("→ push")} new locally: ${secretDrift.localOnly.join(", ")}`);
|
|
65721
|
+
if (secretDrift.changed.length)
|
|
65722
|
+
lines.push(` ${import_picocolors29.default.yellow("→ push")} values changed: ${secretDrift.changed.join(", ")}`);
|
|
65723
|
+
if (secretDrift.cloudOnly.length)
|
|
65724
|
+
lines.push(` ${import_picocolors29.default.cyan("← pull")} new on cloud: ${secretDrift.cloudOnly.join(", ")}`);
|
|
65725
|
+
lines.push("");
|
|
65726
|
+
}
|
|
65727
|
+
if (everythingInSync) {
|
|
65728
|
+
const qualifier = secretsChecked ? "" : ` ${import_picocolors29.default.dim("(secrets not checked)")}`;
|
|
65729
|
+
lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync${qualifier}`);
|
|
65448
65730
|
lines.push("");
|
|
65449
65731
|
console.log(lines.join(`
|
|
65450
65732
|
`));
|
|
@@ -65473,6 +65755,26 @@ async function runAgentStatus(cwd2) {
|
|
|
65473
65755
|
console.log(lines.join(`
|
|
65474
65756
|
`));
|
|
65475
65757
|
}
|
|
65758
|
+
function emitJson(report) {
|
|
65759
|
+
console.log(JSON.stringify(report, null, 2));
|
|
65760
|
+
}
|
|
65761
|
+
function rowJson(r2) {
|
|
65762
|
+
return { type: r2.type, slug: r2.slug, status: r2.status };
|
|
65763
|
+
}
|
|
65764
|
+
var MAX_REASON_LENGTH = 120;
|
|
65765
|
+
function oneLine(text2) {
|
|
65766
|
+
const collapsed = text2.replace(/\s+/g, " ").trim();
|
|
65767
|
+
return collapsed.length > MAX_REASON_LENGTH ? `${collapsed.slice(0, MAX_REASON_LENGTH - 1)}…` : collapsed;
|
|
65768
|
+
}
|
|
65769
|
+
function describeSecretsFailure(err) {
|
|
65770
|
+
const remote = err instanceof ApiError;
|
|
65771
|
+
if (remote && err.status === 401) {
|
|
65772
|
+
return "could not fetch secrets: your session is invalid — run `brainbase login`";
|
|
65773
|
+
}
|
|
65774
|
+
const where = remote ? "could not fetch secrets from the control plane" : `could not read ${path81.join(LINK_DIR, SECRETS_FILE)}`;
|
|
65775
|
+
const detail = oneLine(err instanceof Error ? err.message : typeof err === "string" ? err : "");
|
|
65776
|
+
return detail ? `${where}: ${detail}` : where;
|
|
65777
|
+
}
|
|
65476
65778
|
function fmtRow(r2) {
|
|
65477
65779
|
const head3 = `${fmtType(r2.type)} ${import_picocolors29.default.bold(r2.slug)}`;
|
|
65478
65780
|
switch (r2.status) {
|
|
@@ -65528,7 +65830,7 @@ function formatExport(shell, key2, value) {
|
|
|
65528
65830
|
}
|
|
65529
65831
|
|
|
65530
65832
|
// src/cli/agent-create.ts
|
|
65531
|
-
import
|
|
65833
|
+
import path82 from "node:path";
|
|
65532
65834
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
65533
65835
|
|
|
65534
65836
|
// src/ui/box.ts
|
|
@@ -65732,6 +66034,10 @@ async function runAgentCreate(cwd2, args) {
|
|
|
65732
66034
|
f2.info(`If you want to detach it, run ${import_picocolors32.default.cyan("brainbase unlink")} first; or move to a different directory.`);
|
|
65733
66035
|
return;
|
|
65734
66036
|
}
|
|
66037
|
+
if (reportUnsyncedBlocks(manifest)) {
|
|
66038
|
+
process.exitCode = 1;
|
|
66039
|
+
return;
|
|
66040
|
+
}
|
|
65735
66041
|
const { org, team } = await resolveOrgAndTeam({
|
|
65736
66042
|
orgId: args.orgId,
|
|
65737
66043
|
teamId: args.teamId,
|
|
@@ -65982,6 +66288,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
|
|
|
65982
66288
|
return readManifest(cwd2);
|
|
65983
66289
|
} catch (err) {
|
|
65984
66290
|
f2.error(err.message);
|
|
66291
|
+
process.exitCode = 1;
|
|
65985
66292
|
return null;
|
|
65986
66293
|
}
|
|
65987
66294
|
}
|
|
@@ -65999,7 +66306,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
|
|
|
65999
66306
|
return null;
|
|
66000
66307
|
}
|
|
66001
66308
|
}
|
|
66002
|
-
const seedName = args.name?.trim() ??
|
|
66309
|
+
const seedName = args.name?.trim() ?? path82.basename(path82.resolve(cwd2)) ?? "My Agent";
|
|
66003
66310
|
const seedHarness = args.harness ? normalizeHarnessId(args.harness) : undefined;
|
|
66004
66311
|
const scaffold = {
|
|
66005
66312
|
schema: 1,
|
|
@@ -66137,7 +66444,7 @@ async function runAgent(cwd2, sub, args, opts) {
|
|
|
66137
66444
|
});
|
|
66138
66445
|
return;
|
|
66139
66446
|
case "status":
|
|
66140
|
-
await runAgentStatus(cwd2);
|
|
66447
|
+
await runAgentStatus(cwd2, { json: opts.json });
|
|
66141
66448
|
return;
|
|
66142
66449
|
case "env":
|
|
66143
66450
|
await runAgentEnv(cwd2, { shell: opts.shell });
|
|
@@ -66165,7 +66472,7 @@ function printHelp() {
|
|
|
66165
66472
|
out.push(` ${import_picocolors34.default.cyan("pull")} ${import_picocolors34.default.dim("[<id>]")} ${import_picocolors34.default.dim("apply cloud changes into this folder — pass <id> to switch (--force to override); --run-entrypoint to also execute the agent entrypoint")}`);
|
|
66166
66473
|
out.push(` ${import_picocolors34.default.cyan("push")} ${import_picocolors34.default.dim("send local changes to the cloud — instructions, playbooks, skills, MCPs, entrypoint (--force to overwrite cloud-side conflicts with local)")}`);
|
|
66167
66474
|
out.push(` ${import_picocolors34.default.cyan("unpack")} ${import_picocolors34.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
|
|
66168
|
-
out.push(` ${import_picocolors34.default.cyan("status")} ${import_picocolors34.default.dim("show what would push
|
|
66475
|
+
out.push(` ${import_picocolors34.default.cyan("status")} ${import_picocolors34.default.dim("show what would push, what would pull, and which manifest blocks are ignored (--json for scripts)")}`);
|
|
66169
66476
|
out.push(` ${import_picocolors34.default.cyan("env")} ${import_picocolors34.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
|
|
66170
66477
|
out.push("");
|
|
66171
66478
|
console.log(out.join(`
|
|
@@ -66260,14 +66567,14 @@ function printHelp2() {
|
|
|
66260
66567
|
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
66261
66568
|
|
|
66262
66569
|
// src/cli/orchestration-pull.ts
|
|
66263
|
-
import
|
|
66264
|
-
import
|
|
66570
|
+
import path86 from "node:path";
|
|
66571
|
+
import fs77 from "node:fs";
|
|
66265
66572
|
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
66266
66573
|
|
|
66267
66574
|
// src/core/orchestration-manifest.ts
|
|
66268
|
-
import
|
|
66269
|
-
import
|
|
66270
|
-
var
|
|
66575
|
+
import path83 from "node:path";
|
|
66576
|
+
import fs74 from "node:fs";
|
|
66577
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
66271
66578
|
var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
|
|
66272
66579
|
var ORCH_MEMBERS_DIR = "agents";
|
|
66273
66580
|
var OrchMetaSchema = exports_external.object({
|
|
@@ -66319,19 +66626,19 @@ var OrchestrationManifestSchema = exports_external.object({
|
|
|
66319
66626
|
triggers: exports_external.array(TriggerSchema).optional()
|
|
66320
66627
|
});
|
|
66321
66628
|
function orchManifestPath(cwd2) {
|
|
66322
|
-
return
|
|
66629
|
+
return path83.join(cwd2, ORCH_MANIFEST_FILE);
|
|
66323
66630
|
}
|
|
66324
66631
|
function hasOrchManifest(cwd2) {
|
|
66325
|
-
return
|
|
66632
|
+
return fs74.existsSync(orchManifestPath(cwd2));
|
|
66326
66633
|
}
|
|
66327
66634
|
function readOrchManifest(cwd2) {
|
|
66328
66635
|
const p2 = orchManifestPath(cwd2);
|
|
66329
|
-
if (!
|
|
66636
|
+
if (!fs74.existsSync(p2))
|
|
66330
66637
|
return null;
|
|
66331
|
-
const raw =
|
|
66638
|
+
const raw = fs74.readFileSync(p2, "utf8");
|
|
66332
66639
|
let parsed;
|
|
66333
66640
|
try {
|
|
66334
|
-
parsed =
|
|
66641
|
+
parsed = import_yaml4.default.parse(raw);
|
|
66335
66642
|
} catch (err) {
|
|
66336
66643
|
throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
|
|
66337
66644
|
}
|
|
@@ -66342,17 +66649,17 @@ function readOrchManifest(cwd2) {
|
|
|
66342
66649
|
return result2.data;
|
|
66343
66650
|
}
|
|
66344
66651
|
function writeOrchManifest(cwd2, manifest) {
|
|
66345
|
-
const doc = new
|
|
66652
|
+
const doc = new import_yaml4.default.Document;
|
|
66346
66653
|
doc.contents = manifest;
|
|
66347
66654
|
doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
|
|
66348
66655
|
` + ` Committed to source control. Edit by hand, then
|
|
66349
66656
|
` + " `brainbase orchestration push`. Member agents live under ./agents/." + `
|
|
66350
66657
|
Schedule triggers are writable. App/Pipedream triggers are preserved
|
|
66351
66658
|
` + " as read-only context and ignored by `orchestration push`.";
|
|
66352
|
-
|
|
66659
|
+
fs74.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
|
|
66353
66660
|
}
|
|
66354
66661
|
function memberDir(cwd2, slug) {
|
|
66355
|
-
return
|
|
66662
|
+
return path83.join(cwd2, ORCH_MEMBERS_DIR, slug);
|
|
66356
66663
|
}
|
|
66357
66664
|
var MEMBER_SLUG_MAX = 50;
|
|
66358
66665
|
function slugifyRaw(raw) {
|
|
@@ -66386,8 +66693,8 @@ function resolveMemberSlugs(members) {
|
|
|
66386
66693
|
}
|
|
66387
66694
|
|
|
66388
66695
|
// src/core/orchestration-link.ts
|
|
66389
|
-
import
|
|
66390
|
-
import
|
|
66696
|
+
import path84 from "node:path";
|
|
66697
|
+
import fs75 from "node:fs";
|
|
66391
66698
|
var ORCH_LINK_FILE = "orchestration-link.json";
|
|
66392
66699
|
var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
|
|
66393
66700
|
var OrchestrationLinkSchema = exports_external.object({
|
|
@@ -66421,10 +66728,10 @@ var OrchestrationSyncStateSchema = exports_external.object({
|
|
|
66421
66728
|
edges: exports_external.array(SyncedEdgeSchema)
|
|
66422
66729
|
});
|
|
66423
66730
|
function orchLinkPath(cwd2) {
|
|
66424
|
-
return
|
|
66731
|
+
return path84.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
|
|
66425
66732
|
}
|
|
66426
66733
|
function orchSyncStatePath(cwd2) {
|
|
66427
|
-
return
|
|
66734
|
+
return path84.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
|
|
66428
66735
|
}
|
|
66429
66736
|
function readOrchLink(cwd2) {
|
|
66430
66737
|
const p2 = orchLinkPath(cwd2);
|
|
@@ -66437,7 +66744,7 @@ function readOrchLink(cwd2) {
|
|
|
66437
66744
|
}
|
|
66438
66745
|
}
|
|
66439
66746
|
function writeOrchLink(cwd2, link2) {
|
|
66440
|
-
ensureDir(
|
|
66747
|
+
ensureDir(path84.join(cwd2, LINK_DIR));
|
|
66441
66748
|
const clean = {};
|
|
66442
66749
|
for (const [k3, v3] of Object.entries(link2)) {
|
|
66443
66750
|
if (v3 !== null && v3 !== undefined)
|
|
@@ -66457,22 +66764,22 @@ function readOrchSyncState(cwd2) {
|
|
|
66457
66764
|
}
|
|
66458
66765
|
}
|
|
66459
66766
|
function writeOrchSyncState(cwd2, state) {
|
|
66460
|
-
ensureDir(
|
|
66767
|
+
ensureDir(path84.join(cwd2, LINK_DIR));
|
|
66461
66768
|
writeJson(orchSyncStatePath(cwd2), state);
|
|
66462
66769
|
ensureGitignore2(cwd2);
|
|
66463
66770
|
}
|
|
66464
66771
|
function ensureGitignore2(cwd2) {
|
|
66465
|
-
const ignorePath =
|
|
66772
|
+
const ignorePath = path84.join(cwd2, LINK_DIR, ".gitignore");
|
|
66466
66773
|
const desired = `${ORCH_SYNC_STATE_FILE}
|
|
66467
66774
|
`;
|
|
66468
66775
|
try {
|
|
66469
66776
|
if (!exists(ignorePath)) {
|
|
66470
|
-
|
|
66777
|
+
fs75.writeFileSync(ignorePath, desired);
|
|
66471
66778
|
return;
|
|
66472
66779
|
}
|
|
66473
|
-
const current =
|
|
66780
|
+
const current = fs75.readFileSync(ignorePath, "utf8");
|
|
66474
66781
|
if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
|
|
66475
|
-
|
|
66782
|
+
fs75.writeFileSync(ignorePath, current.endsWith(`
|
|
66476
66783
|
`) ? current + desired : current + `
|
|
66477
66784
|
` + desired);
|
|
66478
66785
|
}
|
|
@@ -66480,8 +66787,8 @@ function ensureGitignore2(cwd2) {
|
|
|
66480
66787
|
}
|
|
66481
66788
|
|
|
66482
66789
|
// src/core/agent-fresh-install.ts
|
|
66483
|
-
import
|
|
66484
|
-
import
|
|
66790
|
+
import path85 from "node:path";
|
|
66791
|
+
import fs76 from "node:fs";
|
|
66485
66792
|
import os15 from "node:os";
|
|
66486
66793
|
async function installAgentFresh(input) {
|
|
66487
66794
|
const { cwd: cwd2, agent, cloud, harness } = input;
|
|
@@ -66503,7 +66810,7 @@ async function installAgentFresh(input) {
|
|
|
66503
66810
|
type: c2.type,
|
|
66504
66811
|
slug: c2.slug,
|
|
66505
66812
|
scope,
|
|
66506
|
-
rootDir:
|
|
66813
|
+
rootDir: path85.join(stageRoot, c2.type, c2.slug),
|
|
66507
66814
|
description: c2.description,
|
|
66508
66815
|
meta: c2.meta,
|
|
66509
66816
|
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
|
|
@@ -66525,7 +66832,12 @@ async function installAgentFresh(input) {
|
|
|
66525
66832
|
}
|
|
66526
66833
|
materializeInstructions2(cwd2, cloud);
|
|
66527
66834
|
materializePlaybooks2(cwd2, cloud);
|
|
66528
|
-
const
|
|
66835
|
+
const claimedByOther = folderClaimedByOtherAgent(cwd2, agent.id);
|
|
66836
|
+
const localOnly = input.preserveManifest || claimedByOther ? {} : readLocalOnlyContentReporting(cwd2);
|
|
66837
|
+
if (claimedByOther) {
|
|
66838
|
+
f2.warn(`${path85.basename(cwd2)} was linked to a different agent; its local-only blocks were left out of the rebuilt manifest.`);
|
|
66839
|
+
}
|
|
66840
|
+
const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent, localOnly);
|
|
66529
66841
|
if (manifest)
|
|
66530
66842
|
writeManifest(cwd2, manifest);
|
|
66531
66843
|
writeLink(cwd2, {
|
|
@@ -66559,7 +66871,7 @@ async function installAgentFresh(input) {
|
|
|
66559
66871
|
...Object.prototype.hasOwnProperty.call(agent, "default_model") ? { default_model: agent.default_model ?? null } : {}
|
|
66560
66872
|
}
|
|
66561
66873
|
});
|
|
66562
|
-
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
|
|
66874
|
+
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent, localOnly);
|
|
66563
66875
|
return {
|
|
66564
66876
|
installedPaths: justInstalledPaths,
|
|
66565
66877
|
manifest: returnedManifest,
|
|
@@ -66567,19 +66879,19 @@ async function installAgentFresh(input) {
|
|
|
66567
66879
|
};
|
|
66568
66880
|
} finally {
|
|
66569
66881
|
try {
|
|
66570
|
-
|
|
66882
|
+
fs76.rmSync(stageRoot, { recursive: true, force: true });
|
|
66571
66883
|
} catch {}
|
|
66572
66884
|
}
|
|
66573
66885
|
}
|
|
66574
66886
|
function stageManifestComponents2(components) {
|
|
66575
|
-
const root =
|
|
66887
|
+
const root = fs76.mkdtempSync(path85.join(os15.tmpdir(), "brainbase-orch-pull-"));
|
|
66576
66888
|
for (const c2 of components) {
|
|
66577
|
-
const compDir =
|
|
66889
|
+
const compDir = path85.join(root, c2.type, c2.slug);
|
|
66578
66890
|
ensureDir(compDir);
|
|
66579
66891
|
for (const f4 of c2.files) {
|
|
66580
|
-
const target =
|
|
66581
|
-
ensureDir(
|
|
66582
|
-
|
|
66892
|
+
const target = path85.join(compDir, f4.path);
|
|
66893
|
+
ensureDir(path85.dirname(target));
|
|
66894
|
+
fs76.writeFileSync(target, f4.content);
|
|
66583
66895
|
}
|
|
66584
66896
|
}
|
|
66585
66897
|
return root;
|
|
@@ -66612,9 +66924,9 @@ function materializeInstructions2(cwd2, cloud) {
|
|
|
66612
66924
|
const body = c2.files[0]?.content ?? "";
|
|
66613
66925
|
if (!body.trim())
|
|
66614
66926
|
continue;
|
|
66615
|
-
const target =
|
|
66616
|
-
ensureDir(
|
|
66617
|
-
|
|
66927
|
+
const target = path85.join(cwd2, DEFAULT_INSTRUCTIONS_FILE);
|
|
66928
|
+
ensureDir(path85.dirname(target));
|
|
66929
|
+
fs76.writeFileSync(target, normalizeInstructionBody(body), "utf8");
|
|
66618
66930
|
return;
|
|
66619
66931
|
}
|
|
66620
66932
|
}
|
|
@@ -66626,12 +66938,12 @@ function materializePlaybooks2(cwd2, cloud) {
|
|
|
66626
66938
|
if (!raw.trim())
|
|
66627
66939
|
continue;
|
|
66628
66940
|
const { body } = stripPlaybookFrontmatter(raw);
|
|
66629
|
-
const target =
|
|
66630
|
-
ensureDir(
|
|
66631
|
-
|
|
66941
|
+
const target = path85.join(cwd2, DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
|
|
66942
|
+
ensureDir(path85.dirname(target));
|
|
66943
|
+
fs76.writeFileSync(target, body, "utf8");
|
|
66632
66944
|
}
|
|
66633
66945
|
}
|
|
66634
|
-
function buildManifestFromCloud(cloud, agent) {
|
|
66946
|
+
function buildManifestFromCloud(cloud, agent, localOnly = {}) {
|
|
66635
66947
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
66636
66948
|
const meta = c2.meta ?? {};
|
|
66637
66949
|
if (meta.name && meta.name.includes("/")) {
|
|
@@ -66670,7 +66982,7 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66670
66982
|
title,
|
|
66671
66983
|
...description ? { description } : {},
|
|
66672
66984
|
...typeof pbMeta.icon === "string" && pbMeta.icon ? { icon: pbMeta.icon } : {},
|
|
66673
|
-
content: { file:
|
|
66985
|
+
content: { file: path85.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`) }
|
|
66674
66986
|
};
|
|
66675
66987
|
});
|
|
66676
66988
|
const caps = capabilitiesFromAgent(agent);
|
|
@@ -66684,7 +66996,8 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66684
66996
|
},
|
|
66685
66997
|
...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
|
|
66686
66998
|
playbooks,
|
|
66687
|
-
evals: [],
|
|
66999
|
+
evals: localOnly.evals ?? [],
|
|
67000
|
+
...localOnly,
|
|
66688
67001
|
skills,
|
|
66689
67002
|
mcp,
|
|
66690
67003
|
capabilities: {
|
|
@@ -66699,7 +67012,7 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66699
67012
|
async function pullAgentSecrets(cwd2, agentId) {
|
|
66700
67013
|
try {
|
|
66701
67014
|
const res = await api.getAgentSecrets(agentId);
|
|
66702
|
-
const secrets = res.secrets
|
|
67015
|
+
const secrets = res.secrets;
|
|
66703
67016
|
if (Object.keys(secrets).length > 0) {
|
|
66704
67017
|
writeLocalSecrets(cwd2, secrets);
|
|
66705
67018
|
}
|
|
@@ -66711,6 +67024,17 @@ async function pullAgentSecrets(cwd2, agentId) {
|
|
|
66711
67024
|
return {};
|
|
66712
67025
|
}
|
|
66713
67026
|
}
|
|
67027
|
+
function folderClaimedByOtherAgent(cwd2, agentId) {
|
|
67028
|
+
const claimedBy = readManifestAgentId(cwd2) ?? safeRead(() => readLink(cwd2)?.agent_id) ?? safeRead(() => readSyncState(cwd2)?.agent_id);
|
|
67029
|
+
return claimedBy !== undefined && claimedBy !== agentId;
|
|
67030
|
+
}
|
|
67031
|
+
function safeRead(read) {
|
|
67032
|
+
try {
|
|
67033
|
+
return read();
|
|
67034
|
+
} catch {
|
|
67035
|
+
return;
|
|
67036
|
+
}
|
|
67037
|
+
}
|
|
66714
67038
|
|
|
66715
67039
|
// src/core/orchestration-trigger-config.ts
|
|
66716
67040
|
function normalizeScheduleTriggerConfig(config) {
|
|
@@ -66820,7 +67144,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
66820
67144
|
}
|
|
66821
67145
|
}
|
|
66822
67146
|
const fallbackHarness = args.harness ?? "claude-code";
|
|
66823
|
-
|
|
67147
|
+
fs77.mkdirSync(cwd2, { recursive: true });
|
|
66824
67148
|
if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
|
|
66825
67149
|
f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
|
|
66826
67150
|
return;
|
|
@@ -66916,7 +67240,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
66916
67240
|
payload_schema: e2.payload_schema ?? {}
|
|
66917
67241
|
}))
|
|
66918
67242
|
});
|
|
66919
|
-
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${
|
|
67243
|
+
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path86.basename(cwd2)}/ ${import_picocolors37.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
|
|
66920
67244
|
}
|
|
66921
67245
|
function handleApiError5(err) {
|
|
66922
67246
|
if (err instanceof ApiError) {
|
|
@@ -66998,6 +67322,34 @@ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
|
66998
67322
|
}
|
|
66999
67323
|
|
|
67000
67324
|
// src/cli/orchestration-push.ts
|
|
67325
|
+
function findUnpushableMembers(cwd2, members) {
|
|
67326
|
+
const blocked = [];
|
|
67327
|
+
for (const m3 of members) {
|
|
67328
|
+
const dir = memberDir(cwd2, m3.slug);
|
|
67329
|
+
if (!hasManifest(dir)) {
|
|
67330
|
+
f2.error(`${m3.slug}: no ${AGENT_MANIFEST_FILE} in this member folder.`);
|
|
67331
|
+
blocked.push(m3.slug);
|
|
67332
|
+
continue;
|
|
67333
|
+
}
|
|
67334
|
+
let memberManifest;
|
|
67335
|
+
try {
|
|
67336
|
+
memberManifest = readManifest(dir);
|
|
67337
|
+
} catch (err) {
|
|
67338
|
+
f2.error(`${m3.slug}: ${err.message}`);
|
|
67339
|
+
blocked.push(m3.slug);
|
|
67340
|
+
continue;
|
|
67341
|
+
}
|
|
67342
|
+
if (!memberManifest.id) {
|
|
67343
|
+
f2.error(`${m3.slug}: ${AGENT_MANIFEST_FILE} is unclaimed (no ${import_picocolors38.default.cyan("id")}), so there is nothing to push to.`);
|
|
67344
|
+
blocked.push(m3.slug);
|
|
67345
|
+
continue;
|
|
67346
|
+
}
|
|
67347
|
+
if (reportUnsyncedBlocks(memberManifest, { label: m3.slug })) {
|
|
67348
|
+
blocked.push(m3.slug);
|
|
67349
|
+
}
|
|
67350
|
+
}
|
|
67351
|
+
return blocked;
|
|
67352
|
+
}
|
|
67001
67353
|
async function runOrchestrationPush(cwd2, args) {
|
|
67002
67354
|
banner("orchestration push — recursively push each member, then update the graph");
|
|
67003
67355
|
const link2 = readOrchLink(cwd2);
|
|
@@ -67033,6 +67385,7 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67033
67385
|
if (missing.length) {
|
|
67034
67386
|
f2.error(`Missing local checkouts for: ${missing.join(", ")}.`);
|
|
67035
67387
|
f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
|
|
67388
|
+
process.exitCode = 1;
|
|
67036
67389
|
return;
|
|
67037
67390
|
}
|
|
67038
67391
|
let graph;
|
|
@@ -67043,6 +67396,14 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67043
67396
|
process.exitCode = 1;
|
|
67044
67397
|
return;
|
|
67045
67398
|
}
|
|
67399
|
+
if (!args.graphOnly) {
|
|
67400
|
+
const blockedMembers = findUnpushableMembers(cwd2, manifest.members);
|
|
67401
|
+
if (blockedMembers.length > 0) {
|
|
67402
|
+
f2.error(`Aborted — ${blockedMembers.join(", ")} cannot be pushed, so no member was pushed and the graph is unchanged.`);
|
|
67403
|
+
process.exitCode = 1;
|
|
67404
|
+
return;
|
|
67405
|
+
}
|
|
67406
|
+
}
|
|
67046
67407
|
const plan = [""];
|
|
67047
67408
|
plan.push(` ${import_picocolors38.default.bold(link2.name)} ${import_picocolors38.default.dim(`(${link2.orchestration_id})`)}`);
|
|
67048
67409
|
plan.push(` ${import_picocolors38.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"}`)}`);
|
|
@@ -67071,6 +67432,7 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67071
67432
|
const dir = memberDir(cwd2, m3.slug);
|
|
67072
67433
|
console.log("");
|
|
67073
67434
|
console.log(`${import_picocolors38.default.dim("───")} ${import_picocolors38.default.bold(m3.slug)} ${import_picocolors38.default.dim("───")}`);
|
|
67435
|
+
const exitCodeBeforePush = process.exitCode;
|
|
67074
67436
|
try {
|
|
67075
67437
|
await runAgentPush(dir, { yes: true });
|
|
67076
67438
|
} catch (err) {
|
|
@@ -67078,6 +67440,11 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67078
67440
|
process.exitCode = 1;
|
|
67079
67441
|
return;
|
|
67080
67442
|
}
|
|
67443
|
+
if (process.exitCode !== exitCodeBeforePush) {
|
|
67444
|
+
f2.error(`Aborted — ${m3.slug} was not pushed, so the graph is left unchanged.`);
|
|
67445
|
+
process.exitCode = 1;
|
|
67446
|
+
return;
|
|
67447
|
+
}
|
|
67081
67448
|
}
|
|
67082
67449
|
}
|
|
67083
67450
|
const sp = de();
|
|
@@ -67343,7 +67710,7 @@ async function runOrchestrationList(args) {
|
|
|
67343
67710
|
}
|
|
67344
67711
|
|
|
67345
67712
|
// src/cli/orchestration-add-agent.ts
|
|
67346
|
-
import
|
|
67713
|
+
import fs78 from "node:fs";
|
|
67347
67714
|
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
67348
67715
|
|
|
67349
67716
|
// src/core/orchestration-add.ts
|
|
@@ -67429,10 +67796,10 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67429
67796
|
})).trim();
|
|
67430
67797
|
}
|
|
67431
67798
|
let slug = slugifyMemberName(name);
|
|
67432
|
-
if (manifest.members.some((m3) => m3.slug === slug) ||
|
|
67799
|
+
if (manifest.members.some((m3) => m3.slug === slug) || fs78.existsSync(memberDir(cwd2, slug))) {
|
|
67433
67800
|
let n = 2;
|
|
67434
67801
|
let candidate = `${slug}-${n}`;
|
|
67435
|
-
while (manifest.members.some((m3) => m3.slug === candidate) ||
|
|
67802
|
+
while (manifest.members.some((m3) => m3.slug === candidate) || fs78.existsSync(memberDir(cwd2, candidate))) {
|
|
67436
67803
|
candidate = `${slug}-${++n}`;
|
|
67437
67804
|
}
|
|
67438
67805
|
f2.info(`Slug ${import_picocolors41.default.bold(slug)} is taken — using ${import_picocolors41.default.bold(candidate)}.`);
|
|
@@ -67504,7 +67871,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67504
67871
|
}
|
|
67505
67872
|
const dest = memberDir(cwd2, slug);
|
|
67506
67873
|
try {
|
|
67507
|
-
|
|
67874
|
+
fs78.mkdirSync(dest, { recursive: true });
|
|
67508
67875
|
await runAgentCreate(dest, {
|
|
67509
67876
|
name,
|
|
67510
67877
|
orgId,
|
|
@@ -67515,7 +67882,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67515
67882
|
});
|
|
67516
67883
|
} catch (err) {
|
|
67517
67884
|
try {
|
|
67518
|
-
|
|
67885
|
+
fs78.rmSync(dest, { recursive: true, force: true });
|
|
67519
67886
|
} catch {}
|
|
67520
67887
|
f2.error(`Failed to create ${slug}: ${err.message}`);
|
|
67521
67888
|
return;
|
|
@@ -67777,15 +68144,11 @@ async function runRun(cwd2, args) {
|
|
|
67777
68144
|
|
|
67778
68145
|
// src/cli/publish.ts
|
|
67779
68146
|
var import_picocolors44 = __toESM(require_picocolors(), 1);
|
|
67780
|
-
|
|
67781
|
-
banner("publish —
|
|
67782
|
-
|
|
67783
|
-
|
|
67784
|
-
|
|
67785
|
-
f2.info(`Run ${import_picocolors44.default.cyan("brainbase link")} first.`);
|
|
67786
|
-
return;
|
|
67787
|
-
}
|
|
67788
|
-
f2.info(`${import_picocolors44.default.bold("publish")} is coming soon — for now, edit the agent on the web app and run ${import_picocolors44.default.cyan("brainbase sync")} to bring changes here.`);
|
|
68147
|
+
function runPublish() {
|
|
68148
|
+
banner("publish — moved");
|
|
68149
|
+
f2.error(`${import_picocolors44.default.bold("brainbase publish")} does not exist.`);
|
|
68150
|
+
f2.info(`Use ${import_picocolors44.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
|
|
68151
|
+
process.exit(1);
|
|
67789
68152
|
}
|
|
67790
68153
|
|
|
67791
68154
|
// src/ui/ink/StatusCard.tsx
|
|
@@ -68207,10 +68570,13 @@ function TokenListCard(props) {
|
|
|
68207
68570
|
]
|
|
68208
68571
|
}, undefined, true, undefined, this);
|
|
68209
68572
|
}
|
|
68573
|
+
const liveCount = props.active.filter((t) => !t.expired).length;
|
|
68574
|
+
const expiredCount = props.active.length - liveCount;
|
|
68575
|
+
const subtitle = expiredCount ? `${liveCount} active, ${expiredCount} expired` : `${liveCount} active`;
|
|
68210
68576
|
return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Card, {
|
|
68211
68577
|
title: "TOKENS",
|
|
68212
68578
|
tone: "info",
|
|
68213
|
-
subtitle
|
|
68579
|
+
subtitle,
|
|
68214
68580
|
children: [
|
|
68215
68581
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68216
68582
|
flexDirection: "column",
|
|
@@ -68222,8 +68588,17 @@ function TokenListCard(props) {
|
|
|
68222
68588
|
children: [
|
|
68223
68589
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68224
68590
|
bold: true,
|
|
68591
|
+
dimColor: t.expired,
|
|
68225
68592
|
children: t.name
|
|
68226
68593
|
}, undefined, false, undefined, this),
|
|
68594
|
+
t.expired && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68595
|
+
marginLeft: 1,
|
|
68596
|
+
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Badge, {
|
|
68597
|
+
tone: "warn",
|
|
68598
|
+
outline: true,
|
|
68599
|
+
children: "expired"
|
|
68600
|
+
}, undefined, false, undefined, this)
|
|
68601
|
+
}, undefined, false, undefined, this),
|
|
68227
68602
|
t.isThisCli && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68228
68603
|
marginLeft: 1,
|
|
68229
68604
|
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Badge, {
|
|
@@ -68308,11 +68683,18 @@ function TokenListCard(props) {
|
|
|
68308
68683
|
}, undefined, true, undefined, this),
|
|
68309
68684
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68310
68685
|
marginTop: 1,
|
|
68311
|
-
|
|
68312
|
-
|
|
68313
|
-
|
|
68314
|
-
|
|
68315
|
-
|
|
68686
|
+
flexDirection: "column",
|
|
68687
|
+
children: [
|
|
68688
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68689
|
+
dimColor: true,
|
|
68690
|
+
children: "› brainbase token rename <id> --name <label>"
|
|
68691
|
+
}, undefined, false, undefined, this),
|
|
68692
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68693
|
+
dimColor: true,
|
|
68694
|
+
children: "› brainbase token revoke <id>"
|
|
68695
|
+
}, undefined, false, undefined, this)
|
|
68696
|
+
]
|
|
68697
|
+
}, undefined, true, undefined, this)
|
|
68316
68698
|
]
|
|
68317
68699
|
}, undefined, true, undefined, this);
|
|
68318
68700
|
}
|
|
@@ -68324,6 +68706,16 @@ async function showTokenListCard(props) {
|
|
|
68324
68706
|
|
|
68325
68707
|
// src/cli/token.ts
|
|
68326
68708
|
var DEFAULT_SCOPES = ["read", "publish"];
|
|
68709
|
+
var MAX_NAME_LENGTH = 128;
|
|
68710
|
+
function isExpired2(token) {
|
|
68711
|
+
return Boolean(token.expires_at && Date.parse(token.expires_at) <= Date.now());
|
|
68712
|
+
}
|
|
68713
|
+
function withLoginHint(error) {
|
|
68714
|
+
if (error instanceof ApiError && error.status === 403) {
|
|
68715
|
+
return new Error("Managing tokens needs a logged-in session; a PAT (BRAINBASE_TOKEN) cannot. " + "Run `brainbase login` and try again.");
|
|
68716
|
+
}
|
|
68717
|
+
return error;
|
|
68718
|
+
}
|
|
68327
68719
|
async function runTokenCreate(args) {
|
|
68328
68720
|
banner("token create — make a long-lived CLI key");
|
|
68329
68721
|
let name = args.name;
|
|
@@ -68343,7 +68735,15 @@ async function runTokenCreate(args) {
|
|
|
68343
68735
|
scopes
|
|
68344
68736
|
});
|
|
68345
68737
|
spinner.stop("Token created.");
|
|
68346
|
-
|
|
68738
|
+
try {
|
|
68739
|
+
writeToken(created.token, name);
|
|
68740
|
+
} catch (error) {
|
|
68741
|
+
throw new Error(`Created token ${created.id}, but could not save it locally: ${error.message}
|
|
68742
|
+
` + `This is the only time it is shown — copy it now:
|
|
68743
|
+
|
|
68744
|
+
${created.token}
|
|
68745
|
+
`);
|
|
68746
|
+
}
|
|
68347
68747
|
await showTokenCreatedCard({
|
|
68348
68748
|
token: created.token,
|
|
68349
68749
|
id: created.id,
|
|
@@ -68365,30 +68765,147 @@ async function runTokenList() {
|
|
|
68365
68765
|
prefix: t.prefix,
|
|
68366
68766
|
scopes: t.scopes,
|
|
68367
68767
|
lastUsed: t.last_used_at ?? null,
|
|
68368
|
-
isThisCli: !!(local && local.token.startsWith(t.prefix))
|
|
68768
|
+
isThisCli: !!(local && local.token.startsWith(t.prefix)),
|
|
68769
|
+
expired: isExpired2(t)
|
|
68369
68770
|
})),
|
|
68370
68771
|
revokedCount: revoked.length
|
|
68371
68772
|
});
|
|
68372
68773
|
}
|
|
68774
|
+
async function runTokenRename(args) {
|
|
68775
|
+
if (!args.id) {
|
|
68776
|
+
throw new Error("Usage: brainbase token rename <id> --name <label>");
|
|
68777
|
+
}
|
|
68778
|
+
banner("token rename — relabel a CLI key");
|
|
68779
|
+
let tokens;
|
|
68780
|
+
try {
|
|
68781
|
+
tokens = await registryApi.listCliTokens();
|
|
68782
|
+
} catch (error) {
|
|
68783
|
+
throw withLoginHint(error);
|
|
68784
|
+
}
|
|
68785
|
+
const target = tokens.find((t) => t.id === args.id);
|
|
68786
|
+
if (!target) {
|
|
68787
|
+
throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
|
|
68788
|
+
}
|
|
68789
|
+
if (target.revoked_at) {
|
|
68790
|
+
throw new Error(`Token ${args.id} is revoked, and revoked tokens cannot be renamed.`);
|
|
68791
|
+
}
|
|
68792
|
+
if (isExpired2(target)) {
|
|
68793
|
+
throw new Error(`Token ${args.id} expired on ${target.expires_at}, and expired tokens cannot be renamed.`);
|
|
68794
|
+
}
|
|
68795
|
+
const takenBy = new Map;
|
|
68796
|
+
for (const t of tokens) {
|
|
68797
|
+
if (t.revoked_at || isExpired2(t) || t.id === target.id)
|
|
68798
|
+
continue;
|
|
68799
|
+
takenBy.set(t.name.trim().toLowerCase(), t);
|
|
68800
|
+
}
|
|
68801
|
+
const validate2 = (value) => {
|
|
68802
|
+
const candidate = value.trim();
|
|
68803
|
+
if (!candidate)
|
|
68804
|
+
return "Required.";
|
|
68805
|
+
if (candidate.length > MAX_NAME_LENGTH) {
|
|
68806
|
+
return `Too long — keep the label to ${MAX_NAME_LENGTH} characters or fewer.`;
|
|
68807
|
+
}
|
|
68808
|
+
const clash = takenBy.get(candidate.toLowerCase());
|
|
68809
|
+
if (clash) {
|
|
68810
|
+
return `Token ${clash.id} already uses the label "${clash.name}". Labels are how \`token list\` tells keys apart, so pick a different one.`;
|
|
68811
|
+
}
|
|
68812
|
+
return;
|
|
68813
|
+
};
|
|
68814
|
+
let name;
|
|
68815
|
+
if (args.name === undefined) {
|
|
68816
|
+
const answer = await text({
|
|
68817
|
+
message: "New label",
|
|
68818
|
+
placeholder: target.name,
|
|
68819
|
+
validate: validate2,
|
|
68820
|
+
flagHint: "Pass --name <label>."
|
|
68821
|
+
});
|
|
68822
|
+
name = answer.trim();
|
|
68823
|
+
} else {
|
|
68824
|
+
name = args.name.trim();
|
|
68825
|
+
const problem = validate2(name);
|
|
68826
|
+
if (problem) {
|
|
68827
|
+
throw new Error(name ? problem : "--name cannot be blank.");
|
|
68828
|
+
}
|
|
68829
|
+
}
|
|
68830
|
+
if (name === target.name.trim()) {
|
|
68831
|
+
console.log(`${sym.ok} ${import_picocolors45.default.bold(target.name.trim())} already has that label; nothing to do.`);
|
|
68832
|
+
return;
|
|
68833
|
+
}
|
|
68834
|
+
try {
|
|
68835
|
+
await registryApi.renameCliToken(target.id, name);
|
|
68836
|
+
} catch (error) {
|
|
68837
|
+
throw withLoginHint(error);
|
|
68838
|
+
}
|
|
68839
|
+
console.log(`${sym.ok} Renamed ${import_picocolors45.default.dim(target.name)} → ${import_picocolors45.default.bold(name)}`);
|
|
68840
|
+
}
|
|
68373
68841
|
async function runTokenRevoke(args) {
|
|
68374
68842
|
if (!args.id) {
|
|
68375
68843
|
console.error("Usage: brainbase token revoke <id>");
|
|
68376
68844
|
process.exit(1);
|
|
68377
68845
|
}
|
|
68846
|
+
const tokens = await registryApi.listCliTokens();
|
|
68847
|
+
const target = tokens.find((t) => t.id === args.id);
|
|
68848
|
+
if (!target) {
|
|
68849
|
+
throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
|
|
68850
|
+
}
|
|
68851
|
+
if (target.revoked_at) {
|
|
68852
|
+
reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} is already revoked.`);
|
|
68853
|
+
return;
|
|
68854
|
+
}
|
|
68855
|
+
const stored = readToken();
|
|
68856
|
+
const isLocalToken = Boolean(stored && stored.token.startsWith(target.prefix));
|
|
68378
68857
|
if (!autoProceed(args.yes)) {
|
|
68379
68858
|
const ok = await se({
|
|
68380
|
-
message: `Revoke token ${import_picocolors45.default.bold(args.id)
|
|
68859
|
+
message: isLocalToken ? `Revoke ${import_picocolors45.default.bold(target.name)} (${args.id})? This is the token this CLI is using, so it will stop working here too.` : `Revoke ${import_picocolors45.default.bold(target.name)} (${args.id})? CIs and machines using it will stop working.`,
|
|
68381
68860
|
initialValue: false
|
|
68382
68861
|
});
|
|
68383
68862
|
if (!ensureNotCancelled(ok))
|
|
68384
68863
|
return;
|
|
68385
68864
|
}
|
|
68386
|
-
|
|
68387
|
-
|
|
68388
|
-
|
|
68389
|
-
|
|
68865
|
+
try {
|
|
68866
|
+
await registryApi.revokeCliToken(args.id);
|
|
68867
|
+
} catch (error) {
|
|
68868
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
68869
|
+
const expiryPassed = Boolean(target.expires_at && Date.parse(target.expires_at) <= Date.now());
|
|
68870
|
+
if (expiryPassed) {
|
|
68871
|
+
reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} had already expired.`);
|
|
68872
|
+
return;
|
|
68873
|
+
}
|
|
68874
|
+
throw new Error(`The server reported no active token with id ${args.id}, but it listed one a moment ago. ` + "The local token has been left alone, since that key may still work. " + "If this server predates `DELETE /v1/registry/cli-tokens/{id}`, revoke from the web app instead.");
|
|
68875
|
+
}
|
|
68876
|
+
throw error;
|
|
68877
|
+
}
|
|
68878
|
+
reconcileDeadToken(target, `Revoked ${import_picocolors45.default.bold(target.name)}.`);
|
|
68879
|
+
}
|
|
68880
|
+
function reconcileDeadToken(target, headline) {
|
|
68881
|
+
let outcome;
|
|
68882
|
+
try {
|
|
68883
|
+
outcome = clearTokenIfMatches(target.prefix);
|
|
68884
|
+
} catch (error) {
|
|
68885
|
+
throw new Error(`${headline} That key is dead server-side, but the local token could not be ` + `cleared: ${error.message}
|
|
68886
|
+
` + "Run `brainbase token clear` to remove it.");
|
|
68887
|
+
}
|
|
68888
|
+
reportLocalToken(headline, outcome);
|
|
68889
|
+
}
|
|
68890
|
+
function reportLocalToken(headline, outcome) {
|
|
68891
|
+
switch (outcome) {
|
|
68892
|
+
case "cleared":
|
|
68893
|
+
console.log(`${sym.ok} ${headline} Cleared the local token too.`);
|
|
68894
|
+
return;
|
|
68895
|
+
case "kept":
|
|
68896
|
+
console.log(`${sym.ok} ${headline} The local token is a different key and is untouched.`);
|
|
68897
|
+
return;
|
|
68898
|
+
case "absent":
|
|
68899
|
+
console.log(`${sym.ok} ${headline}`);
|
|
68900
|
+
return;
|
|
68901
|
+
case "unverifiable":
|
|
68902
|
+
console.log(`${sym.ok} ${headline} Left the local token alone.`);
|
|
68903
|
+
return;
|
|
68904
|
+
default: {
|
|
68905
|
+
const exhaustive = outcome;
|
|
68906
|
+
throw new Error(`unhandled outcome: ${String(exhaustive)}`);
|
|
68907
|
+
}
|
|
68390
68908
|
}
|
|
68391
|
-
console.log(`${sym.ok} Revoked.`);
|
|
68392
68909
|
}
|
|
68393
68910
|
async function runTokenClear() {
|
|
68394
68911
|
if (!readToken()) {
|
|
@@ -68406,22 +68923,45 @@ function pickFlag(rest2, ...names) {
|
|
|
68406
68923
|
}
|
|
68407
68924
|
return;
|
|
68408
68925
|
}
|
|
68926
|
+
function firstPositional(rest2, ...valueFlags) {
|
|
68927
|
+
const consumesValue = new Set(valueFlags);
|
|
68928
|
+
for (let i = 0;i < rest2.length; i++) {
|
|
68929
|
+
const arg = rest2[i];
|
|
68930
|
+
if (consumesValue.has(arg)) {
|
|
68931
|
+
i++;
|
|
68932
|
+
continue;
|
|
68933
|
+
}
|
|
68934
|
+
if (arg.startsWith("-"))
|
|
68935
|
+
continue;
|
|
68936
|
+
return arg;
|
|
68937
|
+
}
|
|
68938
|
+
return;
|
|
68939
|
+
}
|
|
68409
68940
|
function parseScopes(raw) {
|
|
68410
68941
|
if (!raw)
|
|
68411
68942
|
return;
|
|
68412
68943
|
return raw.split(",").map((s3) => s3.trim()).filter((s3) => s3.length > 0);
|
|
68413
68944
|
}
|
|
68414
68945
|
async function runToken(sub, rest2, args) {
|
|
68946
|
+
const nameFlag = args.name || pickFlag(rest2, "--name", "-n");
|
|
68415
68947
|
switch (sub) {
|
|
68416
68948
|
case "create":
|
|
68417
68949
|
case "new": {
|
|
68418
|
-
const name = pickFlag(rest2, "--name", "-n");
|
|
68419
68950
|
const scopes = parseScopes(pickFlag(rest2, "--scope", "--scopes"));
|
|
68420
|
-
return runTokenCreate({ name, scopes });
|
|
68951
|
+
return runTokenCreate({ name: nameFlag, scopes });
|
|
68421
68952
|
}
|
|
68422
68953
|
case "list":
|
|
68423
68954
|
case "ls":
|
|
68424
68955
|
return runTokenList();
|
|
68956
|
+
case "rename": {
|
|
68957
|
+
if (pickFlag(rest2, "--scope", "--scopes") !== undefined) {
|
|
68958
|
+
throw new Error("token rename only changes the label; a token's scopes are fixed when it is created. " + "Mint a replacement with `brainbase token create --scopes <list>`.");
|
|
68959
|
+
}
|
|
68960
|
+
return runTokenRename({
|
|
68961
|
+
id: firstPositional(rest2, "--name", "-n") ?? "",
|
|
68962
|
+
name: nameFlag
|
|
68963
|
+
});
|
|
68964
|
+
}
|
|
68425
68965
|
case "revoke":
|
|
68426
68966
|
case "rm":
|
|
68427
68967
|
return runTokenRevoke({ id: rest2[0] ?? "", yes: args.yes });
|
|
@@ -68446,7 +68986,8 @@ function printTokenHelp() {
|
|
|
68446
68986
|
out.push(` ${import_picocolors45.default.bold("brainbase token")} ${import_picocolors45.default.dim("<command>")}`);
|
|
68447
68987
|
out.push("");
|
|
68448
68988
|
out.push(` ${import_picocolors45.default.cyan("create")} ${import_picocolors45.default.dim("issue a new long-lived CLI key (PAT)")}`);
|
|
68449
|
-
out.push(` ${import_picocolors45.default.cyan("list")} ${import_picocolors45.default.dim("show your
|
|
68989
|
+
out.push(` ${import_picocolors45.default.cyan("list")} ${import_picocolors45.default.dim("show your tokens")}`);
|
|
68990
|
+
out.push(` ${import_picocolors45.default.cyan("rename")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("relabel a token by id")}`);
|
|
68450
68991
|
out.push(` ${import_picocolors45.default.cyan("revoke")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("revoke a token by id")}`);
|
|
68451
68992
|
out.push(` ${import_picocolors45.default.cyan("clear")} ${import_picocolors45.default.dim("forget the local token (does not revoke)")}`);
|
|
68452
68993
|
out.push("");
|
|
@@ -68455,6 +68996,9 @@ function printTokenHelp() {
|
|
|
68455
68996
|
out.push(` ${import_picocolors45.default.cyan("--scopes")} ${import_picocolors45.default.dim("<list>")} ${import_picocolors45.default.dim("comma-separated; allowed: read, publish, admin")}`);
|
|
68456
68997
|
out.push(` ${import_picocolors45.default.dim("default: read,publish")}`);
|
|
68457
68998
|
out.push("");
|
|
68999
|
+
out.push(` ${import_picocolors45.default.bold("rename flags")}`);
|
|
69000
|
+
out.push(` ${import_picocolors45.default.cyan("--name, -n")} ${import_picocolors45.default.dim("<label>")} ${import_picocolors45.default.dim("new label (prompted if omitted)")}`);
|
|
69001
|
+
out.push("");
|
|
68458
69002
|
console.log(out.join(`
|
|
68459
69003
|
`));
|
|
68460
69004
|
}
|
|
@@ -68463,8 +69007,8 @@ function printTokenHelp() {
|
|
|
68463
69007
|
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
68464
69008
|
|
|
68465
69009
|
// src/core/mcp-check/collect-servers.ts
|
|
68466
|
-
import
|
|
68467
|
-
import
|
|
69010
|
+
import path87 from "node:path";
|
|
69011
|
+
import fs79 from "node:fs";
|
|
68468
69012
|
function collectServers(cwd2, env3 = process.env) {
|
|
68469
69013
|
const out = [];
|
|
68470
69014
|
const seen = new Set;
|
|
@@ -68515,10 +69059,10 @@ function pushResolved(out, seen, name, entry, env3) {
|
|
|
68515
69059
|
out.push({ name, url: finalUrl, headers });
|
|
68516
69060
|
}
|
|
68517
69061
|
function* readResolvedMcps(cwd2) {
|
|
68518
|
-
const p2 =
|
|
69062
|
+
const p2 = path87.join(cwd2, ".brainbase", "resolved-mcps.json");
|
|
68519
69063
|
let raw;
|
|
68520
69064
|
try {
|
|
68521
|
-
raw =
|
|
69065
|
+
raw = fs79.readFileSync(p2, "utf-8");
|
|
68522
69066
|
} catch {
|
|
68523
69067
|
return;
|
|
68524
69068
|
}
|
|
@@ -68542,12 +69086,12 @@ function* readResolvedMcps(cwd2) {
|
|
|
68542
69086
|
}
|
|
68543
69087
|
}
|
|
68544
69088
|
function readClaudeCode(cwd2) {
|
|
68545
|
-
const file =
|
|
69089
|
+
const file = path87.join(cwd2, ".mcp.json");
|
|
68546
69090
|
const map2 = listMcpServersFromMcpJson(file);
|
|
68547
69091
|
return Object.entries(map2);
|
|
68548
69092
|
}
|
|
68549
69093
|
function readCodex(cwd2) {
|
|
68550
|
-
const file =
|
|
69094
|
+
const file = path87.join(cwd2, ".codex", "config.toml");
|
|
68551
69095
|
try {
|
|
68552
69096
|
return Object.entries(listMcpServers2(file));
|
|
68553
69097
|
} catch {
|
|
@@ -68555,7 +69099,7 @@ function readCodex(cwd2) {
|
|
|
68555
69099
|
}
|
|
68556
69100
|
}
|
|
68557
69101
|
function readKafka(cwd2) {
|
|
68558
|
-
const file =
|
|
69102
|
+
const file = path87.join(cwd2, ".kafka", "kafka.json");
|
|
68559
69103
|
try {
|
|
68560
69104
|
return Object.entries(listMcpServers3(file));
|
|
68561
69105
|
} catch {
|
|
@@ -68834,10 +69378,10 @@ function assignProp(target, prop, value) {
|
|
|
68834
69378
|
configurable: true
|
|
68835
69379
|
});
|
|
68836
69380
|
}
|
|
68837
|
-
function getElementAtPath(obj,
|
|
68838
|
-
if (!
|
|
69381
|
+
function getElementAtPath(obj, path88) {
|
|
69382
|
+
if (!path88)
|
|
68839
69383
|
return obj;
|
|
68840
|
-
return
|
|
69384
|
+
return path88.reduce((acc, key2) => acc?.[key2], obj);
|
|
68841
69385
|
}
|
|
68842
69386
|
function promiseAllObject(promisesObj) {
|
|
68843
69387
|
const keys2 = Object.keys(promisesObj);
|
|
@@ -69153,11 +69697,11 @@ function aborted(x3, startIndex = 0) {
|
|
|
69153
69697
|
}
|
|
69154
69698
|
return false;
|
|
69155
69699
|
}
|
|
69156
|
-
function prefixIssues(
|
|
69700
|
+
function prefixIssues(path88, issues) {
|
|
69157
69701
|
return issues.map((iss) => {
|
|
69158
69702
|
var _a;
|
|
69159
69703
|
(_a = iss).path ?? (_a.path = []);
|
|
69160
|
-
iss.path.unshift(
|
|
69704
|
+
iss.path.unshift(path88);
|
|
69161
69705
|
return iss;
|
|
69162
69706
|
});
|
|
69163
69707
|
}
|
|
@@ -77051,9 +77595,9 @@ import {
|
|
|
77051
77595
|
spawn as spawn5
|
|
77052
77596
|
} from "node:child_process";
|
|
77053
77597
|
import crypto7 from "node:crypto";
|
|
77054
|
-
import
|
|
77598
|
+
import fs81 from "node:fs";
|
|
77055
77599
|
import os17 from "node:os";
|
|
77056
|
-
import
|
|
77600
|
+
import path89 from "node:path";
|
|
77057
77601
|
|
|
77058
77602
|
// src/core/benchmark-phase.ts
|
|
77059
77603
|
import {
|
|
@@ -77061,9 +77605,9 @@ import {
|
|
|
77061
77605
|
spawn as spawn4
|
|
77062
77606
|
} from "node:child_process";
|
|
77063
77607
|
import crypto6 from "node:crypto";
|
|
77064
|
-
import
|
|
77608
|
+
import fs80 from "node:fs";
|
|
77065
77609
|
import os16 from "node:os";
|
|
77066
|
-
import
|
|
77610
|
+
import path88 from "node:path";
|
|
77067
77611
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
77068
77612
|
var SCHEMA_VERSION = "1";
|
|
77069
77613
|
var SHA256_RE = /^[a-f0-9]{64}$/i;
|
|
@@ -77088,7 +77632,7 @@ var BASE_ENV_NAMES = [
|
|
|
77088
77632
|
"USER"
|
|
77089
77633
|
];
|
|
77090
77634
|
var SENSITIVE_ENV_NAME_RE = /(?:^|_)(?:TOKEN|SECRET|PASSWORD|PASSWD|API_KEY|PRIVATE_KEY|ACCESS_KEY|PAT|CREDENTIAL)(?:$|_)|^(?:PGPASSWORD|DATABASE_URL|REDIS_URL|MONGODB_URI)$/i;
|
|
77091
|
-
var AbsolutePathSchema = exports_external.string().min(1).refine(
|
|
77635
|
+
var AbsolutePathSchema = exports_external.string().min(1).refine(path88.isAbsolute, {
|
|
77092
77636
|
message: "must be an absolute path"
|
|
77093
77637
|
});
|
|
77094
77638
|
var Sha256Schema = exports_external.string().regex(SHA256_RE).transform((value) => value.toLowerCase());
|
|
@@ -77304,35 +77848,35 @@ function normalizedRootRelative(input) {
|
|
|
77304
77848
|
return safeRelPath(input);
|
|
77305
77849
|
}
|
|
77306
77850
|
function isWithin(root, candidate) {
|
|
77307
|
-
const relative =
|
|
77308
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
77851
|
+
const relative = path88.relative(path88.resolve(root), path88.resolve(candidate));
|
|
77852
|
+
return relative === "" || !relative.startsWith("..") && !path88.isAbsolute(relative);
|
|
77309
77853
|
}
|
|
77310
77854
|
function canonicalFuturePath(input) {
|
|
77311
|
-
const resolved =
|
|
77855
|
+
const resolved = path88.resolve(input);
|
|
77312
77856
|
const suffix = [];
|
|
77313
77857
|
let current = resolved;
|
|
77314
|
-
while (!
|
|
77315
|
-
const parent =
|
|
77858
|
+
while (!fs80.existsSync(current)) {
|
|
77859
|
+
const parent = path88.dirname(current);
|
|
77316
77860
|
if (parent === current)
|
|
77317
77861
|
break;
|
|
77318
|
-
suffix.unshift(
|
|
77862
|
+
suffix.unshift(path88.basename(current));
|
|
77319
77863
|
current = parent;
|
|
77320
77864
|
}
|
|
77321
|
-
const canonicalBase =
|
|
77322
|
-
return
|
|
77865
|
+
const canonicalBase = fs80.realpathSync(current);
|
|
77866
|
+
return path88.join(canonicalBase, ...suffix);
|
|
77323
77867
|
}
|
|
77324
77868
|
function validateRoots(spec) {
|
|
77325
|
-
const workspace =
|
|
77326
|
-
if (!
|
|
77869
|
+
const workspace = path88.resolve(spec.workspace_root);
|
|
77870
|
+
if (!fs80.existsSync(workspace) || fs80.lstatSync(workspace).isSymbolicLink() || !fs80.lstatSync(workspace).isDirectory()) {
|
|
77327
77871
|
throw new BenchmarkPhaseError("invalid_workspace_root", "workspace_root must be an existing real directory");
|
|
77328
77872
|
}
|
|
77329
77873
|
const canonicalWorkspace = canonicalFuturePath(workspace);
|
|
77330
|
-
const staging =
|
|
77331
|
-
const expectedStaging =
|
|
77874
|
+
const staging = path88.resolve(spec.staging_root);
|
|
77875
|
+
const expectedStaging = path88.join(workspace, ".brainbase", "benchmark", spec.attempt_id, "incoming");
|
|
77332
77876
|
if (staging !== expectedStaging) {
|
|
77333
77877
|
throw new BenchmarkPhaseError("invalid_staging_root", `staging_root must be ${expectedStaging}`);
|
|
77334
77878
|
}
|
|
77335
|
-
if (!
|
|
77879
|
+
if (!fs80.existsSync(staging) || fs80.lstatSync(staging).isSymbolicLink() || !fs80.lstatSync(staging).isDirectory() || fs80.realpathSync(staging) !== path88.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
|
|
77336
77880
|
throw new BenchmarkPhaseError("invalid_staging_root", "staging_root must be a real directory under workspace_root");
|
|
77337
77881
|
}
|
|
77338
77882
|
const canonicalLogs = validateExternalRoot("logs_root", spec.logs_root, canonicalWorkspace);
|
|
@@ -77344,11 +77888,11 @@ function validateRoots(spec) {
|
|
|
77344
77888
|
}
|
|
77345
77889
|
}
|
|
77346
77890
|
function validateExternalRoot(label, input, canonicalWorkspace) {
|
|
77347
|
-
const candidate =
|
|
77348
|
-
if (candidate ===
|
|
77891
|
+
const candidate = path88.resolve(input);
|
|
77892
|
+
if (candidate === path88.parse(candidate).root) {
|
|
77349
77893
|
throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a filesystem root`);
|
|
77350
77894
|
}
|
|
77351
|
-
if (
|
|
77895
|
+
if (fs80.existsSync(candidate) && fs80.lstatSync(candidate).isSymbolicLink()) {
|
|
77352
77896
|
throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a symlink`);
|
|
77353
77897
|
}
|
|
77354
77898
|
const canonicalCandidate = canonicalFuturePath(candidate);
|
|
@@ -77375,12 +77919,12 @@ function assertNoSymlinkTraversal(root, relative) {
|
|
|
77375
77919
|
const rel = normalizedRootRelative(relative);
|
|
77376
77920
|
if (rel === ".")
|
|
77377
77921
|
return;
|
|
77378
|
-
let current =
|
|
77922
|
+
let current = path88.resolve(root);
|
|
77379
77923
|
for (const segment of rel.split("/").slice(0, -1)) {
|
|
77380
|
-
current =
|
|
77381
|
-
if (!
|
|
77924
|
+
current = path88.join(current, segment);
|
|
77925
|
+
if (!fs80.existsSync(current))
|
|
77382
77926
|
continue;
|
|
77383
|
-
if (
|
|
77927
|
+
if (fs80.lstatSync(current).isSymbolicLink()) {
|
|
77384
77928
|
throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
|
|
77385
77929
|
}
|
|
77386
77930
|
}
|
|
@@ -77390,9 +77934,9 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
|
|
|
77390
77934
|
let canonicalFile;
|
|
77391
77935
|
let currentStat;
|
|
77392
77936
|
try {
|
|
77393
|
-
canonicalRoot =
|
|
77394
|
-
canonicalFile =
|
|
77395
|
-
currentStat =
|
|
77937
|
+
canonicalRoot = fs80.realpathSync(root);
|
|
77938
|
+
canonicalFile = fs80.realpathSync(filePath);
|
|
77939
|
+
currentStat = fs80.statSync(filePath);
|
|
77396
77940
|
} catch {
|
|
77397
77941
|
throw new BenchmarkPhaseError("unsafe_path", `${label} changed while it was opened`);
|
|
77398
77942
|
}
|
|
@@ -77401,10 +77945,10 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
|
|
|
77401
77945
|
}
|
|
77402
77946
|
}
|
|
77403
77947
|
function openRegularFileNoFollow(filePath, label, root) {
|
|
77404
|
-
const noFollow = typeof
|
|
77948
|
+
const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
|
|
77405
77949
|
let fd;
|
|
77406
77950
|
try {
|
|
77407
|
-
fd =
|
|
77951
|
+
fd = fs80.openSync(filePath, fs80.constants.O_RDONLY | noFollow);
|
|
77408
77952
|
} catch (error2) {
|
|
77409
77953
|
const code = error2.code;
|
|
77410
77954
|
if (code === "ELOOP") {
|
|
@@ -77412,16 +77956,16 @@ function openRegularFileNoFollow(filePath, label, root) {
|
|
|
77412
77956
|
}
|
|
77413
77957
|
throw error2;
|
|
77414
77958
|
}
|
|
77415
|
-
const stat =
|
|
77959
|
+
const stat = fs80.fstatSync(fd);
|
|
77416
77960
|
if (!stat.isFile()) {
|
|
77417
|
-
|
|
77961
|
+
fs80.closeSync(fd);
|
|
77418
77962
|
throw new BenchmarkPhaseError("invalid_input", `${label} must be a regular file`);
|
|
77419
77963
|
}
|
|
77420
77964
|
if (root) {
|
|
77421
77965
|
try {
|
|
77422
77966
|
assertOpenedFileWithinRoot(root, filePath, stat, label);
|
|
77423
77967
|
} catch (error2) {
|
|
77424
|
-
|
|
77968
|
+
fs80.closeSync(fd);
|
|
77425
77969
|
throw error2;
|
|
77426
77970
|
}
|
|
77427
77971
|
}
|
|
@@ -77429,7 +77973,7 @@ function openRegularFileNoFollow(filePath, label, root) {
|
|
|
77429
77973
|
}
|
|
77430
77974
|
async function sha256OfDescriptor(fd) {
|
|
77431
77975
|
const hash = crypto6.createHash("sha256");
|
|
77432
|
-
const stream =
|
|
77976
|
+
const stream = fs80.createReadStream("", {
|
|
77433
77977
|
fd,
|
|
77434
77978
|
autoClose: false,
|
|
77435
77979
|
start: 0
|
|
@@ -77440,19 +77984,19 @@ async function sha256OfDescriptor(fd) {
|
|
|
77440
77984
|
return hash.digest("hex");
|
|
77441
77985
|
}
|
|
77442
77986
|
function readDescriptor(fd) {
|
|
77443
|
-
return
|
|
77987
|
+
return fs80.readFileSync(fd);
|
|
77444
77988
|
}
|
|
77445
77989
|
function assertWritableDestination(root, relative) {
|
|
77446
77990
|
const rel = normalizedRootRelative(relative);
|
|
77447
77991
|
if (rel === ".")
|
|
77448
77992
|
return;
|
|
77449
|
-
let current =
|
|
77993
|
+
let current = path88.resolve(root);
|
|
77450
77994
|
const segments = rel.split("/");
|
|
77451
77995
|
for (const segment of segments.slice(0, -1)) {
|
|
77452
|
-
current =
|
|
77453
|
-
if (!
|
|
77996
|
+
current = path88.join(current, segment);
|
|
77997
|
+
if (!fs80.existsSync(current))
|
|
77454
77998
|
continue;
|
|
77455
|
-
const stat =
|
|
77999
|
+
const stat = fs80.lstatSync(current);
|
|
77456
78000
|
if (stat.isSymbolicLink()) {
|
|
77457
78001
|
throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
|
|
77458
78002
|
}
|
|
@@ -77460,8 +78004,8 @@ function assertWritableDestination(root, relative) {
|
|
|
77460
78004
|
throw new BenchmarkPhaseError("destination_conflict", `destination parent is not a directory: ${relative}`);
|
|
77461
78005
|
}
|
|
77462
78006
|
}
|
|
77463
|
-
const destination =
|
|
77464
|
-
if (
|
|
78007
|
+
const destination = path88.resolve(root, rel);
|
|
78008
|
+
if (fs80.existsSync(destination) && fs80.lstatSync(destination).isDirectory()) {
|
|
77465
78009
|
throw new BenchmarkPhaseError("destination_conflict", `file destination is an existing directory: ${relative}`);
|
|
77466
78010
|
}
|
|
77467
78011
|
}
|
|
@@ -77486,14 +78030,14 @@ function validateDestinationGraph(paths) {
|
|
|
77486
78030
|
}
|
|
77487
78031
|
function sourcePath(stagingRoot, relative) {
|
|
77488
78032
|
const rel = safeRelPath(relative);
|
|
77489
|
-
const source =
|
|
78033
|
+
const source = path88.resolve(stagingRoot, rel);
|
|
77490
78034
|
if (!isWithin(stagingRoot, source)) {
|
|
77491
78035
|
throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${relative}`);
|
|
77492
78036
|
}
|
|
77493
78037
|
assertNoSymlinkTraversal(stagingRoot, rel);
|
|
77494
78038
|
let stat;
|
|
77495
78039
|
try {
|
|
77496
|
-
stat =
|
|
78040
|
+
stat = fs80.lstatSync(source);
|
|
77497
78041
|
} catch {
|
|
77498
78042
|
throw new BenchmarkPhaseError("missing_input", `staged input does not exist: ${relative}`);
|
|
77499
78043
|
}
|
|
@@ -77521,13 +78065,13 @@ async function verifyRecordsUnchanged(records, spec) {
|
|
|
77521
78065
|
}
|
|
77522
78066
|
const relative = safeRelPath(record3.path);
|
|
77523
78067
|
assertNoSymlinkTraversal(root, relative);
|
|
77524
|
-
const candidate =
|
|
77525
|
-
if (!isWithin(root, candidate) || !
|
|
78068
|
+
const candidate = path88.resolve(root, relative);
|
|
78069
|
+
if (!isWithin(root, candidate) || !fs80.existsSync(candidate)) {
|
|
77526
78070
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
|
|
77527
78071
|
}
|
|
77528
|
-
const stat =
|
|
78072
|
+
const stat = fs80.lstatSync(candidate);
|
|
77529
78073
|
if (record3.kind === "symlink") {
|
|
77530
|
-
const target = stat.isSymbolicLink() ?
|
|
78074
|
+
const target = stat.isSymbolicLink() ? fs80.readlinkSync(candidate) : null;
|
|
77531
78075
|
if (target === null || Buffer.byteLength(target) !== record3.size || sha256(target) !== record3.sha256) {
|
|
77532
78076
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
|
|
77533
78077
|
}
|
|
@@ -77542,7 +78086,7 @@ async function verifyRecordsUnchanged(records, spec) {
|
|
|
77542
78086
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
|
|
77543
78087
|
}
|
|
77544
78088
|
} finally {
|
|
77545
|
-
|
|
78089
|
+
fs80.closeSync(opened.fd);
|
|
77546
78090
|
}
|
|
77547
78091
|
}
|
|
77548
78092
|
}
|
|
@@ -77558,35 +78102,35 @@ async function verifyInput(stagingRoot, material) {
|
|
|
77558
78102
|
throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
|
|
77559
78103
|
}
|
|
77560
78104
|
} finally {
|
|
77561
|
-
|
|
78105
|
+
fs80.closeSync(opened.fd);
|
|
77562
78106
|
}
|
|
77563
78107
|
return source;
|
|
77564
78108
|
}
|
|
77565
78109
|
async function atomicCopy(source, destination, mode, sourceRoot) {
|
|
77566
|
-
|
|
78110
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77567
78111
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77568
78112
|
const opened = openRegularFileNoFollow(source, `copy source ${source}`, sourceRoot);
|
|
77569
78113
|
try {
|
|
77570
|
-
await pipeline2(
|
|
78114
|
+
await pipeline2(fs80.createReadStream("", {
|
|
77571
78115
|
fd: opened.fd,
|
|
77572
78116
|
autoClose: false,
|
|
77573
78117
|
start: 0
|
|
77574
|
-
}),
|
|
78118
|
+
}), fs80.createWriteStream(temporary, {
|
|
77575
78119
|
flags: "wx",
|
|
77576
78120
|
mode: 384
|
|
77577
78121
|
}));
|
|
77578
|
-
|
|
77579
|
-
|
|
78122
|
+
fs80.chmodSync(temporary, mode ?? opened.stat.mode & 511);
|
|
78123
|
+
fs80.renameSync(temporary, destination);
|
|
77580
78124
|
} finally {
|
|
77581
|
-
|
|
77582
|
-
|
|
78125
|
+
fs80.closeSync(opened.fd);
|
|
78126
|
+
fs80.rmSync(temporary, { force: true });
|
|
77583
78127
|
}
|
|
77584
78128
|
}
|
|
77585
78129
|
async function recordFile(root, filePath, rootName, kind = "file") {
|
|
77586
|
-
const relative =
|
|
78130
|
+
const relative = path88.relative(root, filePath).replace(/\\/g, "/");
|
|
77587
78131
|
if (kind === "symlink") {
|
|
77588
|
-
const stat =
|
|
77589
|
-
const target =
|
|
78132
|
+
const stat = fs80.lstatSync(filePath);
|
|
78133
|
+
const target = fs80.readlinkSync(filePath);
|
|
77590
78134
|
return {
|
|
77591
78135
|
root: rootName,
|
|
77592
78136
|
path: relative,
|
|
@@ -77606,7 +78150,7 @@ async function recordFile(root, filePath, rootName, kind = "file") {
|
|
|
77606
78150
|
mode: opened.stat.mode & 511
|
|
77607
78151
|
};
|
|
77608
78152
|
} finally {
|
|
77609
|
-
|
|
78153
|
+
fs80.closeSync(opened.fd);
|
|
77610
78154
|
}
|
|
77611
78155
|
}
|
|
77612
78156
|
async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
|
|
@@ -77620,7 +78164,7 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77620
78164
|
throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
|
|
77621
78165
|
}
|
|
77622
78166
|
assertWritableDestination(destinationRoot, destinationRel);
|
|
77623
|
-
const destination =
|
|
78167
|
+
const destination = path88.resolve(destinationRoot, destinationRel);
|
|
77624
78168
|
await atomicCopy(source, destination, material.mode, sourceRoot);
|
|
77625
78169
|
const record3 = await recordFile(destinationRoot, destination, destinationRootName);
|
|
77626
78170
|
if (record3.sha256 !== material.sha256 || record3.size !== material.size_bytes) {
|
|
@@ -77628,15 +78172,15 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77628
78172
|
}
|
|
77629
78173
|
return [record3];
|
|
77630
78174
|
}
|
|
77631
|
-
const temporary =
|
|
78175
|
+
const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-"));
|
|
77632
78176
|
try {
|
|
77633
|
-
const verifiedArchive =
|
|
78177
|
+
const verifiedArchive = path88.join(temporary, "material.tar.gz");
|
|
77634
78178
|
await atomicCopy(source, verifiedArchive, 384, sourceRoot);
|
|
77635
78179
|
const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
|
|
77636
78180
|
if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
|
|
77637
78181
|
throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
|
|
77638
78182
|
}
|
|
77639
|
-
const extractedRoot =
|
|
78183
|
+
const extractedRoot = path88.join(temporary, "extracted");
|
|
77640
78184
|
const extracted = await extract({
|
|
77641
78185
|
tarFile: verifiedArchive,
|
|
77642
78186
|
outDir: extractedRoot,
|
|
@@ -77645,23 +78189,23 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77645
78189
|
});
|
|
77646
78190
|
const outputs = [];
|
|
77647
78191
|
for (const extractedRel of extracted.sort()) {
|
|
77648
|
-
const sourceFile =
|
|
77649
|
-
const stat =
|
|
78192
|
+
const sourceFile = path88.resolve(extractedRoot, safeRelPath(extractedRel));
|
|
78193
|
+
const stat = fs80.lstatSync(sourceFile);
|
|
77650
78194
|
if (!stat.isFile())
|
|
77651
78195
|
continue;
|
|
77652
|
-
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(
|
|
78196
|
+
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path88.posix.join(destinationRel, extractedRel));
|
|
77653
78197
|
const checked = protectWorkspace ? workspaceRel(combined) : combined;
|
|
77654
78198
|
if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
|
|
77655
78199
|
throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
|
|
77656
78200
|
}
|
|
77657
78201
|
assertWritableDestination(destinationRoot, checked);
|
|
77658
|
-
const destination =
|
|
78202
|
+
const destination = path88.resolve(destinationRoot, checked);
|
|
77659
78203
|
await atomicCopy(sourceFile, destination, material.mode, extractedRoot);
|
|
77660
78204
|
outputs.push(await recordFile(destinationRoot, destination, destinationRootName));
|
|
77661
78205
|
}
|
|
77662
78206
|
return outputs;
|
|
77663
78207
|
} finally {
|
|
77664
|
-
|
|
78208
|
+
fs80.rmSync(temporary, { recursive: true, force: true });
|
|
77665
78209
|
}
|
|
77666
78210
|
}
|
|
77667
78211
|
async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
|
|
@@ -77677,15 +78221,15 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77677
78221
|
assertWritableDestination(destinationRoot, destinationRel);
|
|
77678
78222
|
return [destinationRel];
|
|
77679
78223
|
}
|
|
77680
|
-
const temporary =
|
|
78224
|
+
const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
|
|
77681
78225
|
try {
|
|
77682
|
-
const verifiedArchive =
|
|
78226
|
+
const verifiedArchive = path88.join(temporary, "material.tar.gz");
|
|
77683
78227
|
await atomicCopy(source, verifiedArchive, 384, sourceRoot);
|
|
77684
78228
|
const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
|
|
77685
78229
|
if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
|
|
77686
78230
|
throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
|
|
77687
78231
|
}
|
|
77688
|
-
const extractedRoot =
|
|
78232
|
+
const extractedRoot = path88.join(temporary, "extracted");
|
|
77689
78233
|
const extracted = await extract({
|
|
77690
78234
|
tarFile: verifiedArchive,
|
|
77691
78235
|
outDir: extractedRoot,
|
|
@@ -77694,7 +78238,7 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77694
78238
|
});
|
|
77695
78239
|
const planned = [];
|
|
77696
78240
|
for (const extractedRel of extracted) {
|
|
77697
|
-
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(
|
|
78241
|
+
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path88.posix.join(destinationRel, extractedRel));
|
|
77698
78242
|
const checked = protectWorkspace ? workspaceRel(combined) : combined;
|
|
77699
78243
|
if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
|
|
77700
78244
|
throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
|
|
@@ -77704,34 +78248,34 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77704
78248
|
}
|
|
77705
78249
|
return planned;
|
|
77706
78250
|
} finally {
|
|
77707
|
-
|
|
78251
|
+
fs80.rmSync(temporary, { recursive: true, force: true });
|
|
77708
78252
|
}
|
|
77709
78253
|
}
|
|
77710
78254
|
function ownerMarker(root) {
|
|
77711
|
-
return
|
|
78255
|
+
return path88.join(root, ".brainbase-benchmark-owner.json");
|
|
77712
78256
|
}
|
|
77713
78257
|
function verifyOwnedDirectory(root, role, spec) {
|
|
77714
|
-
if (!
|
|
78258
|
+
if (!fs80.existsSync(root) || fs80.lstatSync(root).isSymbolicLink())
|
|
77715
78259
|
return false;
|
|
77716
78260
|
try {
|
|
77717
|
-
const marker = JSON.parse(
|
|
78261
|
+
const marker = JSON.parse(fs80.readFileSync(ownerMarker(root), "utf8"));
|
|
77718
78262
|
return marker.attempt_id === spec.attempt_id && marker.phase === spec.phase && marker.phase_id === spec.phase_id && marker.role === role;
|
|
77719
78263
|
} catch {
|
|
77720
78264
|
return false;
|
|
77721
78265
|
}
|
|
77722
78266
|
}
|
|
77723
78267
|
function prepareOwnedDirectory(root, role, spec) {
|
|
77724
|
-
if (
|
|
78268
|
+
if (fs80.existsSync(root)) {
|
|
77725
78269
|
if (!verifyOwnedDirectory(root, role, spec)) {
|
|
77726
|
-
const stat =
|
|
77727
|
-
if (!stat.isDirectory() ||
|
|
78270
|
+
const stat = fs80.lstatSync(root);
|
|
78271
|
+
if (!stat.isDirectory() || fs80.readdirSync(root).length > 0) {
|
|
77728
78272
|
throw new BenchmarkPhaseError(`unowned_${role}_root`, `${role}_root exists without a matching attempt ownership marker`);
|
|
77729
78273
|
}
|
|
77730
78274
|
} else {
|
|
77731
|
-
|
|
78275
|
+
fs80.rmSync(root, { recursive: true, force: true });
|
|
77732
78276
|
}
|
|
77733
78277
|
}
|
|
77734
|
-
|
|
78278
|
+
fs80.mkdirSync(root, { recursive: true, mode: 448 });
|
|
77735
78279
|
writeJsonAtomic(ownerMarker(root), {
|
|
77736
78280
|
schema_version: SCHEMA_VERSION,
|
|
77737
78281
|
attempt_id: spec.attempt_id,
|
|
@@ -77820,10 +78364,10 @@ function terminate(child) {
|
|
|
77820
78364
|
async function runCommand(command, root, spec, context, additions = {}) {
|
|
77821
78365
|
const cwdRel = normalizedRootRelative(command.cwd);
|
|
77822
78366
|
assertNoSymlinkTraversal(root, cwdRel);
|
|
77823
|
-
const cwd2 =
|
|
78367
|
+
const cwd2 = path88.resolve(root, cwdRel);
|
|
77824
78368
|
let cwdStat;
|
|
77825
78369
|
try {
|
|
77826
|
-
cwdStat =
|
|
78370
|
+
cwdStat = fs80.lstatSync(cwd2);
|
|
77827
78371
|
} catch {
|
|
77828
78372
|
throw new BenchmarkPhaseError("invalid_command_cwd", `command cwd is invalid: ${command.cwd}`);
|
|
77829
78373
|
}
|
|
@@ -77894,28 +78438,28 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
77894
78438
|
});
|
|
77895
78439
|
}
|
|
77896
78440
|
async function writeLog(root, name, data, spec) {
|
|
77897
|
-
const destination =
|
|
77898
|
-
|
|
78441
|
+
const destination = path88.join(root, name);
|
|
78442
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77899
78443
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77900
78444
|
try {
|
|
77901
|
-
|
|
78445
|
+
fs80.writeFileSync(temporary, redactCommandOutput(data, spec), {
|
|
77902
78446
|
flag: "wx",
|
|
77903
78447
|
mode: 384
|
|
77904
78448
|
});
|
|
77905
|
-
|
|
78449
|
+
fs80.renameSync(temporary, destination);
|
|
77906
78450
|
} finally {
|
|
77907
|
-
|
|
78451
|
+
fs80.rmSync(temporary, { force: true });
|
|
77908
78452
|
}
|
|
77909
78453
|
return await recordFile(root, destination, "logs");
|
|
77910
78454
|
}
|
|
77911
78455
|
function writeBufferAtomic(destination, data) {
|
|
77912
|
-
|
|
78456
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77913
78457
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77914
78458
|
try {
|
|
77915
|
-
|
|
77916
|
-
|
|
78459
|
+
fs80.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
|
|
78460
|
+
fs80.renameSync(temporary, destination);
|
|
77917
78461
|
} finally {
|
|
77918
|
-
|
|
78462
|
+
fs80.rmSync(temporary, { force: true });
|
|
77919
78463
|
}
|
|
77920
78464
|
}
|
|
77921
78465
|
function assertBudget(context) {
|
|
@@ -77924,7 +78468,7 @@ function assertBudget(context) {
|
|
|
77924
78468
|
}
|
|
77925
78469
|
}
|
|
77926
78470
|
async function executeHydrate(spec, context) {
|
|
77927
|
-
|
|
78471
|
+
fs80.mkdirSync(spec.workspace_root, { recursive: true });
|
|
77928
78472
|
prepareOwnedDirectory(spec.logs_root, "logs", spec);
|
|
77929
78473
|
context.logsOwned = true;
|
|
77930
78474
|
const outputs = [];
|
|
@@ -78003,11 +78547,11 @@ async function executeHydrate(spec, context) {
|
|
|
78003
78547
|
finalOutputs.push(output);
|
|
78004
78548
|
continue;
|
|
78005
78549
|
}
|
|
78006
|
-
const candidate =
|
|
78550
|
+
const candidate = path88.resolve(spec.workspace_root, safeRelPath(output.path));
|
|
78007
78551
|
assertNoSymlinkTraversal(spec.workspace_root, output.path);
|
|
78008
|
-
if (!
|
|
78552
|
+
if (!fs80.existsSync(candidate))
|
|
78009
78553
|
continue;
|
|
78010
|
-
const stat =
|
|
78554
|
+
const stat = fs80.lstatSync(candidate);
|
|
78011
78555
|
if (!stat.isFile() && !stat.isSymbolicLink())
|
|
78012
78556
|
continue;
|
|
78013
78557
|
finalOutputs.push(await recordFile(spec.workspace_root, candidate, "workspace", stat.isSymbolicLink() ? "symlink" : "file"));
|
|
@@ -78034,27 +78578,27 @@ async function readEvidence(stagingRoot, evidence) {
|
|
|
78034
78578
|
buffer,
|
|
78035
78579
|
record: {
|
|
78036
78580
|
root: "staging",
|
|
78037
|
-
path:
|
|
78581
|
+
path: path88.relative(stagingRoot, filePath).replace(/\\/g, "/"),
|
|
78038
78582
|
sha256: evidence.sha256,
|
|
78039
78583
|
size: opened.stat.size,
|
|
78040
78584
|
mode: opened.stat.mode & 511
|
|
78041
78585
|
}
|
|
78042
78586
|
};
|
|
78043
78587
|
} finally {
|
|
78044
|
-
|
|
78588
|
+
fs80.closeSync(opened.fd);
|
|
78045
78589
|
}
|
|
78046
78590
|
}
|
|
78047
78591
|
async function workspaceManifest(spec, context) {
|
|
78048
78592
|
const records = [];
|
|
78049
78593
|
let totalBytes = 0;
|
|
78050
|
-
const stack = [
|
|
78594
|
+
const stack = [path88.resolve(spec.workspace_root)];
|
|
78051
78595
|
while (stack.length > 0) {
|
|
78052
78596
|
const directory = stack.pop();
|
|
78053
|
-
const entries =
|
|
78597
|
+
const entries = fs80.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
|
|
78054
78598
|
for (const entry of entries) {
|
|
78055
78599
|
assertBudget(context);
|
|
78056
|
-
const full =
|
|
78057
|
-
const relative =
|
|
78600
|
+
const full = path88.join(directory, entry.name);
|
|
78601
|
+
const relative = path88.relative(spec.workspace_root, full).replace(/\\/g, "/");
|
|
78058
78602
|
if (relative === ".brainbase" || relative.startsWith(".brainbase/"))
|
|
78059
78603
|
continue;
|
|
78060
78604
|
if (relative === ".git" || relative.startsWith(".git/"))
|
|
@@ -78156,10 +78700,10 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78156
78700
|
if (evaluator.type === "workspace_assertion") {
|
|
78157
78701
|
const relative = workspaceRel(evaluator.path);
|
|
78158
78702
|
assertNoSymlinkTraversal(spec.workspace_root, relative);
|
|
78159
|
-
const candidate =
|
|
78703
|
+
const candidate = path88.resolve(spec.workspace_root, relative);
|
|
78160
78704
|
let stat = null;
|
|
78161
78705
|
try {
|
|
78162
|
-
stat =
|
|
78706
|
+
stat = fs80.lstatSync(candidate);
|
|
78163
78707
|
} catch (error2) {
|
|
78164
78708
|
const code = error2.code;
|
|
78165
78709
|
if (code !== "ENOENT" && code !== "ENOTDIR")
|
|
@@ -78180,7 +78724,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78180
78724
|
try {
|
|
78181
78725
|
verdict2 = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
|
|
78182
78726
|
} finally {
|
|
78183
|
-
|
|
78727
|
+
fs80.closeSync(opened.fd);
|
|
78184
78728
|
}
|
|
78185
78729
|
}
|
|
78186
78730
|
}
|
|
@@ -78190,7 +78734,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78190
78734
|
try {
|
|
78191
78735
|
verdict2 = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
|
|
78192
78736
|
} finally {
|
|
78193
|
-
|
|
78737
|
+
fs80.closeSync(opened.fd);
|
|
78194
78738
|
}
|
|
78195
78739
|
}
|
|
78196
78740
|
}
|
|
@@ -78244,8 +78788,8 @@ async function executeEvaluate(spec, context) {
|
|
|
78244
78788
|
context.logsOwned = true;
|
|
78245
78789
|
validateRoots(spec);
|
|
78246
78790
|
const outputs = [];
|
|
78247
|
-
const finalOutputPath =
|
|
78248
|
-
const trajectoryPath =
|
|
78791
|
+
const finalOutputPath = path88.join(spec.logs_root, "candidate-evidence", "final-output");
|
|
78792
|
+
const trajectoryPath = path88.join(spec.logs_root, "candidate-evidence", "trajectory.json");
|
|
78249
78793
|
writeBufferAtomic(finalOutputPath, finalOutput.buffer);
|
|
78250
78794
|
writeBufferAtomic(trajectoryPath, trajectoryEvidence.buffer);
|
|
78251
78795
|
const frozenEvidenceRecords = [
|
|
@@ -78256,7 +78800,7 @@ async function executeEvaluate(spec, context) {
|
|
|
78256
78800
|
context.outputs.push(...frozenEvidenceRecords);
|
|
78257
78801
|
assertBudget(context);
|
|
78258
78802
|
const manifest = await workspaceManifest(spec, context);
|
|
78259
|
-
const manifestPath2 =
|
|
78803
|
+
const manifestPath2 = path88.join(spec.logs_root, "candidate-workspace-manifest.json");
|
|
78260
78804
|
writeJsonAtomic(manifestPath2, {
|
|
78261
78805
|
schema_version: SCHEMA_VERSION,
|
|
78262
78806
|
attempt_id: spec.attempt_id,
|
|
@@ -78269,12 +78813,12 @@ async function executeEvaluate(spec, context) {
|
|
|
78269
78813
|
for (const artifactRelInput of spec.candidate_artifacts) {
|
|
78270
78814
|
const artifactRel = workspaceRel(artifactRelInput);
|
|
78271
78815
|
assertNoSymlinkTraversal(spec.workspace_root, artifactRel);
|
|
78272
|
-
const source =
|
|
78816
|
+
const source = path88.resolve(spec.workspace_root, artifactRel);
|
|
78273
78817
|
const frozenArtifact = manifest.find((entry) => entry.path === artifactRel && entry.kind !== "symlink");
|
|
78274
|
-
if (!frozenArtifact || !
|
|
78818
|
+
if (!frozenArtifact || !fs80.existsSync(source) || !fs80.lstatSync(source).isFile()) {
|
|
78275
78819
|
throw new BenchmarkPhaseError("missing_artifact", `candidate artifact is missing: ${artifactRel}`);
|
|
78276
78820
|
}
|
|
78277
|
-
const destination =
|
|
78821
|
+
const destination = path88.resolve(spec.logs_root, "candidate-artifacts", artifactRel);
|
|
78278
78822
|
await atomicCopy(source, destination, undefined, spec.workspace_root);
|
|
78279
78823
|
const artifact = await recordFile(spec.logs_root, destination, "logs");
|
|
78280
78824
|
if (artifact.sha256 !== frozenArtifact.sha256 || artifact.size !== frozenArtifact.size || artifact.mode !== frozenArtifact.mode) {
|
|
@@ -78285,13 +78829,13 @@ async function executeEvaluate(spec, context) {
|
|
|
78285
78829
|
}
|
|
78286
78830
|
if (spec.capture_workspace_archive) {
|
|
78287
78831
|
const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
|
|
78288
|
-
const archive =
|
|
78832
|
+
const archive = path88.join(spec.logs_root, "candidate-workspace.tar.gz");
|
|
78289
78833
|
const temporary = `${archive}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
78290
78834
|
try {
|
|
78291
78835
|
await pack({ rootDir: spec.workspace_root, outFile: temporary, files: regularFiles });
|
|
78292
|
-
|
|
78836
|
+
fs80.renameSync(temporary, archive);
|
|
78293
78837
|
} finally {
|
|
78294
|
-
|
|
78838
|
+
fs80.rmSync(temporary, { force: true });
|
|
78295
78839
|
}
|
|
78296
78840
|
const archiveRecord = await recordFile(spec.logs_root, archive, "logs");
|
|
78297
78841
|
outputs.push(archiveRecord);
|
|
@@ -78390,22 +78934,22 @@ function rawIdentity(value) {
|
|
|
78390
78934
|
};
|
|
78391
78935
|
}
|
|
78392
78936
|
function readSpecBytes(specPathInput) {
|
|
78393
|
-
const specPath =
|
|
78394
|
-
const noFollow = typeof
|
|
78937
|
+
const specPath = path88.resolve(specPathInput);
|
|
78938
|
+
const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
|
|
78395
78939
|
let fd;
|
|
78396
78940
|
try {
|
|
78397
|
-
fd =
|
|
78941
|
+
fd = fs80.openSync(specPath, fs80.constants.O_RDONLY | noFollow);
|
|
78398
78942
|
} catch {
|
|
78399
78943
|
throw new BenchmarkPhaseError("spec_read_failed", "spec file could not be read");
|
|
78400
78944
|
}
|
|
78401
78945
|
try {
|
|
78402
|
-
const stat =
|
|
78946
|
+
const stat = fs80.fstatSync(fd);
|
|
78403
78947
|
if (!stat.isFile() || stat.size > MAX_SPEC_BYTES) {
|
|
78404
78948
|
throw new BenchmarkPhaseError("invalid_spec_file", "spec must be a regular JSON file no larger than 20 MiB");
|
|
78405
78949
|
}
|
|
78406
78950
|
return readDescriptor(fd);
|
|
78407
78951
|
} finally {
|
|
78408
|
-
|
|
78952
|
+
fs80.closeSync(fd);
|
|
78409
78953
|
}
|
|
78410
78954
|
}
|
|
78411
78955
|
function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase) {
|
|
@@ -78421,8 +78965,8 @@ function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase)
|
|
|
78421
78965
|
throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
|
|
78422
78966
|
}
|
|
78423
78967
|
validateRoots(spec);
|
|
78424
|
-
const resultPath =
|
|
78425
|
-
const expectedResultPath =
|
|
78968
|
+
const resultPath = path88.resolve(resultPathInput);
|
|
78969
|
+
const expectedResultPath = path88.join(path88.resolve(spec.logs_root), "result.json");
|
|
78426
78970
|
if (resultPath !== expectedResultPath) {
|
|
78427
78971
|
throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
|
|
78428
78972
|
}
|
|
@@ -78449,9 +78993,9 @@ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expecte
|
|
|
78449
78993
|
spec_digest: digest,
|
|
78450
78994
|
timeout_ms: spec.budget.timeout_ms
|
|
78451
78995
|
};
|
|
78452
|
-
if (
|
|
78996
|
+
if (fs80.existsSync(resultPath)) {
|
|
78453
78997
|
try {
|
|
78454
|
-
const cached2 = JSON.parse(
|
|
78998
|
+
const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
|
|
78455
78999
|
if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
|
|
78456
79000
|
return {
|
|
78457
79001
|
ok: true,
|
|
@@ -78519,7 +79063,7 @@ function writeBenchmarkPhaseTimeoutResult(specBytes, resultPathInput, expectedPh
|
|
|
78519
79063
|
async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase, immutableSpecBytes) {
|
|
78520
79064
|
const startedAt = nowIso();
|
|
78521
79065
|
const started = Date.now();
|
|
78522
|
-
const resultPath =
|
|
79066
|
+
const resultPath = path88.resolve(resultPathInput);
|
|
78523
79067
|
let raw = undefined;
|
|
78524
79068
|
let digest = null;
|
|
78525
79069
|
let identity2 = rawIdentity(raw);
|
|
@@ -78553,14 +79097,14 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
78553
79097
|
throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
|
|
78554
79098
|
}
|
|
78555
79099
|
validateRoots(spec);
|
|
78556
|
-
const expectedResultPath =
|
|
79100
|
+
const expectedResultPath = path88.join(path88.resolve(spec.logs_root), "result.json");
|
|
78557
79101
|
if (resultPath !== expectedResultPath) {
|
|
78558
79102
|
throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
|
|
78559
79103
|
}
|
|
78560
79104
|
resultPathValidated = true;
|
|
78561
|
-
if (
|
|
79105
|
+
if (fs80.existsSync(resultPath)) {
|
|
78562
79106
|
try {
|
|
78563
|
-
const cached2 = JSON.parse(
|
|
79107
|
+
const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
|
|
78564
79108
|
if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
|
|
78565
79109
|
return { exitCode: 0, result: cached2 };
|
|
78566
79110
|
}
|
|
@@ -78756,14 +79300,14 @@ function terminatePhase(child) {
|
|
|
78756
79300
|
}
|
|
78757
79301
|
}
|
|
78758
79302
|
function createAnonymousSpecFd(bytes) {
|
|
78759
|
-
const temporary =
|
|
78760
|
-
|
|
79303
|
+
const temporary = path89.join(os17.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto7.randomBytes(12).toString("hex")}`);
|
|
79304
|
+
fs81.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
|
|
78761
79305
|
try {
|
|
78762
|
-
const fd =
|
|
78763
|
-
|
|
79306
|
+
const fd = fs81.openSync(temporary, "r");
|
|
79307
|
+
fs81.unlinkSync(temporary);
|
|
78764
79308
|
return fd;
|
|
78765
79309
|
} catch (error2) {
|
|
78766
|
-
|
|
79310
|
+
fs81.rmSync(temporary, { force: true });
|
|
78767
79311
|
throw error2;
|
|
78768
79312
|
}
|
|
78769
79313
|
}
|
|
@@ -78832,13 +79376,13 @@ async function runSupervisedPhase(phase, parsed, write) {
|
|
|
78832
79376
|
detached: process.platform !== "win32"
|
|
78833
79377
|
});
|
|
78834
79378
|
} catch {
|
|
78835
|
-
|
|
79379
|
+
fs81.closeSync(specFd);
|
|
78836
79380
|
const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child process could not be started");
|
|
78837
79381
|
write(`${JSON.stringify(failure)}
|
|
78838
79382
|
`);
|
|
78839
79383
|
return 1;
|
|
78840
79384
|
}
|
|
78841
|
-
|
|
79385
|
+
fs81.closeSync(specFd);
|
|
78842
79386
|
return await new Promise((resolve) => {
|
|
78843
79387
|
const stdout = [];
|
|
78844
79388
|
let settled = false;
|
|
@@ -78920,7 +79464,7 @@ async function runBenchmark(sub, args, write = (value) => process.stdout.write(v
|
|
|
78920
79464
|
if (phase !== "hydrate" && phase !== "evaluate" || resultFlag !== "--result" || !resultPath || specFdFlag !== "--spec-fd" || !Number.isInteger(specFd) || specFd < 3 || tokenFlag !== "--token" || !token || token !== process.env.BRAINBASE_BENCHMARK_PHASE_CHILD_TOKEN) {
|
|
78921
79465
|
throw new Error("Invalid internal benchmark phase invocation");
|
|
78922
79466
|
}
|
|
78923
|
-
const specBytes =
|
|
79467
|
+
const specBytes = fs81.readFileSync(specFd);
|
|
78924
79468
|
const { exitCode, result: result2 } = await runBenchmarkPhase("", resultPath, phase, specBytes);
|
|
78925
79469
|
write(`${JSON.stringify(result2)}
|
|
78926
79470
|
`);
|
|
@@ -78979,16 +79523,17 @@ var PROTECTED = new Set([
|
|
|
78979
79523
|
"link",
|
|
78980
79524
|
"unlink",
|
|
78981
79525
|
"sync",
|
|
78982
|
-
"publish",
|
|
78983
79526
|
"status",
|
|
78984
79527
|
"token"
|
|
78985
79528
|
]);
|
|
78986
79529
|
var STORED_PAT_COMMANDS = new Set([
|
|
78987
79530
|
"template",
|
|
78988
79531
|
"skill",
|
|
78989
|
-
"publish",
|
|
78990
79532
|
"token"
|
|
78991
79533
|
]);
|
|
79534
|
+
var SUBCOMMAND_OWNED_FLAGS = {
|
|
79535
|
+
token: ["--scope", "--name"]
|
|
79536
|
+
};
|
|
78992
79537
|
function help() {
|
|
78993
79538
|
const out = [];
|
|
78994
79539
|
out.push("");
|
|
@@ -79064,7 +79609,8 @@ function help() {
|
|
|
79064
79609
|
out.push(divider("CLI TOKENS"));
|
|
79065
79610
|
out.push("");
|
|
79066
79611
|
out.push(` ${import_picocolors49.default.cyan("token create")} ${import_picocolors49.default.dim("issue a long-lived CLI key for CI / scripts")}`);
|
|
79067
|
-
out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your
|
|
79612
|
+
out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your tokens")}`);
|
|
79613
|
+
out.push(` ${import_picocolors49.default.cyan("token rename")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("relabel a token")}`);
|
|
79068
79614
|
out.push(` ${import_picocolors49.default.cyan("token revoke")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("revoke a token")}`);
|
|
79069
79615
|
out.push("");
|
|
79070
79616
|
out.push(divider("MCP"));
|
|
@@ -79092,6 +79638,7 @@ function help() {
|
|
|
79092
79638
|
out.push(divider("ENV"));
|
|
79093
79639
|
out.push("");
|
|
79094
79640
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
|
|
79641
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
|
|
79095
79642
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
|
|
79096
79643
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
|
|
79097
79644
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
|
|
@@ -79102,6 +79649,13 @@ function help() {
|
|
|
79102
79649
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
|
|
79103
79650
|
out.push(` ${import_picocolors49.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
|
|
79104
79651
|
out.push("");
|
|
79652
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
|
|
79653
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
|
|
79654
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
|
|
79655
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
|
|
79656
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
|
|
79657
|
+
out.push(` ${import_picocolors49.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
|
|
79658
|
+
out.push("");
|
|
79105
79659
|
out.push(divider("HARNESSES"));
|
|
79106
79660
|
out.push("");
|
|
79107
79661
|
out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("claude-code")} ${import_picocolors49.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
|
|
@@ -79186,7 +79740,7 @@ async function main() {
|
|
|
79186
79740
|
const rawCwd = process14.cwd();
|
|
79187
79741
|
const cwd2 = (() => {
|
|
79188
79742
|
try {
|
|
79189
|
-
return
|
|
79743
|
+
return fs82.realpathSync(rawCwd);
|
|
79190
79744
|
} catch {
|
|
79191
79745
|
return rawCwd;
|
|
79192
79746
|
}
|
|
@@ -79200,10 +79754,15 @@ async function main() {
|
|
|
79200
79754
|
return;
|
|
79201
79755
|
}
|
|
79202
79756
|
const sharedArgs = cmd === "task" || cmd === "benchmark" ? [] : argv;
|
|
79757
|
+
const ownedFlags = new Set(SUBCOMMAND_OWNED_FLAGS[cmd] ?? []);
|
|
79758
|
+
const takeFlag = (...names) => {
|
|
79759
|
+
const consumable = names.filter((n) => !ownedFlags.has(n));
|
|
79760
|
+
return consumable.length > 0 ? getFlag(sharedArgs, ...consumable) : undefined;
|
|
79761
|
+
};
|
|
79203
79762
|
const yes = hasFlag2(sharedArgs, "--yes", "-y");
|
|
79204
79763
|
const all = hasFlag2(sharedArgs, "--all");
|
|
79205
79764
|
const harness = getFlag(sharedArgs, "--harness");
|
|
79206
|
-
const scopeFlag =
|
|
79765
|
+
const scopeFlag = takeFlag("--scope");
|
|
79207
79766
|
const web = getFlag(sharedArgs, "--web");
|
|
79208
79767
|
const visibility = getFlag(sharedArgs, "--visibility");
|
|
79209
79768
|
const category = getFlag(sharedArgs, "--category");
|
|
@@ -79218,7 +79777,7 @@ async function main() {
|
|
|
79218
79777
|
const forceFlag = hasFlag2(sharedArgs, "--force");
|
|
79219
79778
|
const runEntrypointFlag = hasFlag2(sharedArgs, "--run-entrypoint");
|
|
79220
79779
|
const graphOnlyFlag = hasFlag2(sharedArgs, "--graph-only");
|
|
79221
|
-
const nameFlag =
|
|
79780
|
+
const nameFlag = takeFlag("--name");
|
|
79222
79781
|
const skillVersionFlag = getFlag(sharedArgs, "--skill-version");
|
|
79223
79782
|
const taglineFlag = getFlag(sharedArgs, "--tagline");
|
|
79224
79783
|
const orgIdFlag = getFlag(sharedArgs, "--org");
|
|
@@ -79278,7 +79837,7 @@ async function main() {
|
|
|
79278
79837
|
}
|
|
79279
79838
|
case "token": {
|
|
79280
79839
|
const sub = argv.shift();
|
|
79281
|
-
await runToken(sub, argv, { yes });
|
|
79840
|
+
await runToken(sub, argv, { yes, name: nameFlag });
|
|
79282
79841
|
break;
|
|
79283
79842
|
}
|
|
79284
79843
|
case "link": {
|
|
@@ -79352,7 +79911,7 @@ async function main() {
|
|
|
79352
79911
|
break;
|
|
79353
79912
|
}
|
|
79354
79913
|
case "publish": {
|
|
79355
|
-
|
|
79914
|
+
runPublish();
|
|
79356
79915
|
break;
|
|
79357
79916
|
}
|
|
79358
79917
|
case "status": {
|