@brainbase-labs/cli 0.21.0 → 0.21.2
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 +989 -323
- 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.21.
|
|
36011
|
+
version: "0.21.2",
|
|
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
|
|
@@ -53937,6 +53969,7 @@ class NetworkApiError extends ApiError {
|
|
|
53937
53969
|
|
|
53938
53970
|
class TaskRecoveryDeadlineError extends ApiError {
|
|
53939
53971
|
}
|
|
53972
|
+
var GET_NETWORK_RETRY_DELAYS_MS = [100, 250];
|
|
53940
53973
|
function normalizeControlPlaneUrl(url) {
|
|
53941
53974
|
const normalized = url?.trim().replace(/\/+$/, "");
|
|
53942
53975
|
return normalized || DEFAULT_CONTROL_PLANE_BASE;
|
|
@@ -54069,9 +54102,33 @@ async function sendWithAuthRetry(session, send) {
|
|
|
54069
54102
|
}
|
|
54070
54103
|
async function request(pathname, init = {}) {
|
|
54071
54104
|
const credential = await resolveCredential();
|
|
54072
|
-
|
|
54073
|
-
|
|
54074
|
-
const
|
|
54105
|
+
let currentSession = credential.session;
|
|
54106
|
+
let refreshSessionAvailable = credential.source === "session" && !new Headers(init.headers).has("Authorization");
|
|
54107
|
+
const method2 = (init.method ?? "GET").toUpperCase();
|
|
54108
|
+
let res;
|
|
54109
|
+
let text2;
|
|
54110
|
+
for (let attempt2 = 0;; attempt2 += 1) {
|
|
54111
|
+
try {
|
|
54112
|
+
res = await sendWithAuthRetry(refreshSessionAvailable ? currentSession : null, async (refreshed) => {
|
|
54113
|
+
if (refreshed) {
|
|
54114
|
+
currentSession = refreshed;
|
|
54115
|
+
refreshSessionAvailable = false;
|
|
54116
|
+
}
|
|
54117
|
+
return await sendRequest(`${apiBase(currentSession)}${pathname}`, init, currentSession?.access_token ?? credential.bearer);
|
|
54118
|
+
});
|
|
54119
|
+
try {
|
|
54120
|
+
text2 = await res.text();
|
|
54121
|
+
} catch (error) {
|
|
54122
|
+
throw new NetworkApiError(`Network error while reading response: ${error.message}`, false);
|
|
54123
|
+
}
|
|
54124
|
+
break;
|
|
54125
|
+
} catch (error) {
|
|
54126
|
+
if (method2 !== "GET" || !(error instanceof NetworkApiError) || attempt2 >= GET_NETWORK_RETRY_DELAYS_MS.length) {
|
|
54127
|
+
throw error;
|
|
54128
|
+
}
|
|
54129
|
+
await new Promise((resolve) => setTimeout(resolve, GET_NETWORK_RETRY_DELAYS_MS[attempt2]));
|
|
54130
|
+
}
|
|
54131
|
+
}
|
|
54075
54132
|
let body = text2;
|
|
54076
54133
|
try {
|
|
54077
54134
|
body = text2 ? JSON.parse(text2) : null;
|
|
@@ -54297,8 +54354,13 @@ var api = {
|
|
|
54297
54354
|
body: JSON.stringify(input)
|
|
54298
54355
|
});
|
|
54299
54356
|
},
|
|
54300
|
-
getAgentSecrets(agentId) {
|
|
54301
|
-
|
|
54357
|
+
async getAgentSecrets(agentId) {
|
|
54358
|
+
const body = await request(`/agents/${encodeURIComponent(agentId)}/secrets`);
|
|
54359
|
+
const secrets = body && typeof body === "object" ? body.secrets : undefined;
|
|
54360
|
+
if (!secrets || typeof secrets !== "object" || Array.isArray(secrets) || !Object.values(secrets).every((value) => typeof value === "string")) {
|
|
54361
|
+
throw new ApiError("The control plane returned an unreadable secrets response", undefined);
|
|
54362
|
+
}
|
|
54363
|
+
return { secrets };
|
|
54302
54364
|
},
|
|
54303
54365
|
putAgentSecrets(agentId, secrets) {
|
|
54304
54366
|
return request(`/agents/${encodeURIComponent(agentId)}/secrets`, {
|
|
@@ -54599,6 +54661,12 @@ var registryApi = {
|
|
|
54599
54661
|
body: JSON.stringify(input)
|
|
54600
54662
|
});
|
|
54601
54663
|
},
|
|
54664
|
+
renameCliToken(id, name) {
|
|
54665
|
+
return jsonRequest(`/v1/registry/cli-tokens/${encodeURIComponent(id)}`, {
|
|
54666
|
+
method: "PATCH",
|
|
54667
|
+
body: JSON.stringify({ name })
|
|
54668
|
+
});
|
|
54669
|
+
},
|
|
54602
54670
|
revokeCliToken(id) {
|
|
54603
54671
|
return jsonRequest(`/v1/registry/cli-tokens/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
54604
54672
|
}
|
|
@@ -61797,6 +61865,9 @@ var EvalSchema = exports_external.object({
|
|
|
61797
61865
|
path: ["classification_values"]
|
|
61798
61866
|
});
|
|
61799
61867
|
var MODEL_ID_RE = /^[A-Za-z0-9._:/-]{1,128}$/;
|
|
61868
|
+
var UNSYNCED_MANIFEST_KEYS = ["commands", "hooks", "files"];
|
|
61869
|
+
var UnsyncedBlockSchema = exports_external.array(exports_external.record(exports_external.unknown())).optional();
|
|
61870
|
+
var UnsyncedBlocksShape = Object.fromEntries(UNSYNCED_MANIFEST_KEYS.map((key2) => [key2, UnsyncedBlockSchema]));
|
|
61800
61871
|
var AgentManifestSchema = exports_external.object({
|
|
61801
61872
|
schema: exports_external.literal(1),
|
|
61802
61873
|
id: exports_external.string().min(1).optional(),
|
|
@@ -61823,9 +61894,7 @@ var AgentManifestSchema = exports_external.object({
|
|
|
61823
61894
|
});
|
|
61824
61895
|
}).default([]),
|
|
61825
61896
|
capabilities: CapabilitiesSchema.optional(),
|
|
61826
|
-
|
|
61827
|
-
hooks: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
|
|
61828
|
-
files: exports_external.array(exports_external.record(exports_external.unknown())).optional()
|
|
61897
|
+
...UnsyncedBlocksShape
|
|
61829
61898
|
});
|
|
61830
61899
|
function manifestPath(cwd2) {
|
|
61831
61900
|
return path73.join(cwd2, AGENT_MANIFEST_FILE);
|
|
@@ -63244,13 +63313,132 @@ var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
|
63244
63313
|
// src/cli/agent-pull.ts
|
|
63245
63314
|
import { spawn as spawn2 } from "node:child_process";
|
|
63246
63315
|
import path80 from "node:path";
|
|
63247
|
-
import
|
|
63316
|
+
import fs73 from "node:fs";
|
|
63248
63317
|
import os14 from "node:os";
|
|
63249
63318
|
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
63250
63319
|
|
|
63320
|
+
// src/core/manifest-unsynced.ts
|
|
63321
|
+
import fs69 from "node:fs";
|
|
63322
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
63323
|
+
function findUnsyncedBlocks(manifest) {
|
|
63324
|
+
const found = [];
|
|
63325
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63326
|
+
const block = manifest[key2];
|
|
63327
|
+
if (Array.isArray(block) && block.length > 0) {
|
|
63328
|
+
found.push({ key: key2, entries: block.length });
|
|
63329
|
+
}
|
|
63330
|
+
}
|
|
63331
|
+
return found;
|
|
63332
|
+
}
|
|
63333
|
+
function unsyncedBlockReason(block) {
|
|
63334
|
+
const entries = `${block.entries} ${block.entries === 1 ? "entry" : "entries"}`;
|
|
63335
|
+
return `\`${block.key}\` is declared in ${AGENT_MANIFEST_FILE} (${entries}) but this ` + `CLI does not sync ${block.key} yet — pushing would discard it.`;
|
|
63336
|
+
}
|
|
63337
|
+
function unsyncedBlockRemedy(blocks) {
|
|
63338
|
+
const keys2 = blocks.map((b4) => `\`${b4.key}\``).join(", ");
|
|
63339
|
+
const plural = blocks.length === 1 ? "" : "s";
|
|
63340
|
+
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.`;
|
|
63341
|
+
}
|
|
63342
|
+
function reportUnsyncedBlocks(manifest, opts = {}) {
|
|
63343
|
+
const blocks = findUnsyncedBlocks(manifest);
|
|
63344
|
+
if (blocks.length === 0)
|
|
63345
|
+
return false;
|
|
63346
|
+
const prefix = opts.label ? `${opts.label}: ` : "";
|
|
63347
|
+
for (const block of blocks) {
|
|
63348
|
+
f2.error(`${prefix}${unsyncedBlockReason(block)}`);
|
|
63349
|
+
}
|
|
63350
|
+
f2.info(unsyncedBlockRemedy(blocks));
|
|
63351
|
+
return true;
|
|
63352
|
+
}
|
|
63353
|
+
function carryForwardUnsyncedBlocks(prev) {
|
|
63354
|
+
const carried = {};
|
|
63355
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63356
|
+
const block = prev?.[key2];
|
|
63357
|
+
if (block !== undefined)
|
|
63358
|
+
carried[key2] = block;
|
|
63359
|
+
}
|
|
63360
|
+
return carried;
|
|
63361
|
+
}
|
|
63362
|
+
function salvageLocalOnlyContent(raw) {
|
|
63363
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
63364
|
+
return {};
|
|
63365
|
+
const doc = raw;
|
|
63366
|
+
const salvaged = {};
|
|
63367
|
+
for (const key2 of UNSYNCED_MANIFEST_KEYS) {
|
|
63368
|
+
if (doc[key2] === undefined)
|
|
63369
|
+
continue;
|
|
63370
|
+
const result2 = AgentManifestSchema.shape[key2].safeParse(doc[key2]);
|
|
63371
|
+
if (result2.success && result2.data !== undefined) {
|
|
63372
|
+
salvaged[key2] = result2.data;
|
|
63373
|
+
}
|
|
63374
|
+
}
|
|
63375
|
+
if (doc.evals !== undefined) {
|
|
63376
|
+
const evals = AgentManifestSchema.shape.evals.safeParse(doc.evals);
|
|
63377
|
+
if (evals.success)
|
|
63378
|
+
salvaged.evals = evals.data;
|
|
63379
|
+
}
|
|
63380
|
+
return salvaged;
|
|
63381
|
+
}
|
|
63382
|
+
function readLocalOnlyContent(cwd2) {
|
|
63383
|
+
if (!hasManifest(cwd2))
|
|
63384
|
+
return { content: {}, status: "absent" };
|
|
63385
|
+
try {
|
|
63386
|
+
const prev = readManifest(cwd2);
|
|
63387
|
+
return {
|
|
63388
|
+
content: {
|
|
63389
|
+
evals: prev?.evals ?? [],
|
|
63390
|
+
...carryForwardUnsyncedBlocks(prev)
|
|
63391
|
+
},
|
|
63392
|
+
status: "parsed"
|
|
63393
|
+
};
|
|
63394
|
+
} catch {}
|
|
63395
|
+
const file = existingManifestPath(cwd2);
|
|
63396
|
+
let raw = null;
|
|
63397
|
+
if (file) {
|
|
63398
|
+
try {
|
|
63399
|
+
raw = import_yaml3.default.parse(fs69.readFileSync(file, "utf8"));
|
|
63400
|
+
} catch {
|
|
63401
|
+
raw = null;
|
|
63402
|
+
}
|
|
63403
|
+
}
|
|
63404
|
+
const content = salvageLocalOnlyContent(raw);
|
|
63405
|
+
return {
|
|
63406
|
+
content,
|
|
63407
|
+
status: Object.keys(content).length > 0 ? "recovered" : "unreadable"
|
|
63408
|
+
};
|
|
63409
|
+
}
|
|
63410
|
+
function readManifestAgentId(cwd2) {
|
|
63411
|
+
if (!hasManifest(cwd2))
|
|
63412
|
+
return;
|
|
63413
|
+
const clean = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
63414
|
+
try {
|
|
63415
|
+
return clean(readManifest(cwd2)?.id);
|
|
63416
|
+
} catch {}
|
|
63417
|
+
const file = existingManifestPath(cwd2);
|
|
63418
|
+
if (!file)
|
|
63419
|
+
return;
|
|
63420
|
+
try {
|
|
63421
|
+
const raw = import_yaml3.default.parse(fs69.readFileSync(file, "utf8"));
|
|
63422
|
+
if (!raw || typeof raw !== "object")
|
|
63423
|
+
return;
|
|
63424
|
+
return clean(raw.id);
|
|
63425
|
+
} catch {
|
|
63426
|
+
return;
|
|
63427
|
+
}
|
|
63428
|
+
}
|
|
63429
|
+
function readLocalOnlyContentReporting(cwd2) {
|
|
63430
|
+
const { content, status } = readLocalOnlyContent(cwd2);
|
|
63431
|
+
if (status === "recovered") {
|
|
63432
|
+
f2.warn(`${AGENT_MANIFEST_FILE} could not be read; kept its ${Object.keys(content).join(", ")} and rebuilt the rest from the cloud.`);
|
|
63433
|
+
} else if (status === "unreadable") {
|
|
63434
|
+
f2.warn(`${AGENT_MANIFEST_FILE} could not be read and was replaced with cloud state.`);
|
|
63435
|
+
}
|
|
63436
|
+
return content;
|
|
63437
|
+
}
|
|
63438
|
+
|
|
63251
63439
|
// src/core/agent-diff.ts
|
|
63252
63440
|
import path77 from "node:path";
|
|
63253
|
-
import
|
|
63441
|
+
import fs70 from "node:fs";
|
|
63254
63442
|
import crypto4 from "node:crypto";
|
|
63255
63443
|
function compKey(type, slug) {
|
|
63256
63444
|
return `${type}/${slug}`;
|
|
@@ -63300,7 +63488,7 @@ function fileHash(p2) {
|
|
|
63300
63488
|
if (!exists(p2))
|
|
63301
63489
|
return null;
|
|
63302
63490
|
try {
|
|
63303
|
-
const buf =
|
|
63491
|
+
const buf = fs70.readFileSync(p2);
|
|
63304
63492
|
return crypto4.createHash("sha256").update(buf).digest("hex");
|
|
63305
63493
|
} catch {
|
|
63306
63494
|
return null;
|
|
@@ -63322,7 +63510,7 @@ function hashDirectoryAsComponent(dir) {
|
|
|
63322
63510
|
const walk = (sub) => {
|
|
63323
63511
|
let entries;
|
|
63324
63512
|
try {
|
|
63325
|
-
entries =
|
|
63513
|
+
entries = fs70.readdirSync(sub, { withFileTypes: true });
|
|
63326
63514
|
} catch {
|
|
63327
63515
|
return;
|
|
63328
63516
|
}
|
|
@@ -63590,7 +63778,7 @@ function diffAgentConfig(manifest, lock, cloud) {
|
|
|
63590
63778
|
|
|
63591
63779
|
// src/core/secrets-env.ts
|
|
63592
63780
|
import path78 from "node:path";
|
|
63593
|
-
import
|
|
63781
|
+
import fs71 from "node:fs";
|
|
63594
63782
|
var SECRETS_FILE = "secrets.env";
|
|
63595
63783
|
function secretsPath(cwd2) {
|
|
63596
63784
|
return path78.join(cwd2, LINK_DIR, SECRETS_FILE);
|
|
@@ -63638,18 +63826,18 @@ function readLocalSecrets(cwd2) {
|
|
|
63638
63826
|
const p2 = secretsPath(cwd2);
|
|
63639
63827
|
if (!exists(p2))
|
|
63640
63828
|
return {};
|
|
63641
|
-
return parseSecretsEnv(
|
|
63829
|
+
return parseSecretsEnv(fs71.readFileSync(p2, "utf8"));
|
|
63642
63830
|
}
|
|
63643
63831
|
function writeLocalSecrets(cwd2, secrets) {
|
|
63644
63832
|
ensureDir(path78.join(cwd2, LINK_DIR));
|
|
63645
|
-
|
|
63833
|
+
fs71.writeFileSync(secretsPath(cwd2), formatSecretsEnv(secrets), "utf8");
|
|
63646
63834
|
ensureSecretsGitignore(cwd2);
|
|
63647
63835
|
}
|
|
63648
63836
|
function ensureSecretsGitignore(cwd2) {
|
|
63649
63837
|
const ignorePath = path78.join(cwd2, LINK_DIR, ".gitignore");
|
|
63650
63838
|
const needed = [SYNC_STATE_FILE, SECRETS_FILE];
|
|
63651
63839
|
try {
|
|
63652
|
-
const current = exists(ignorePath) ?
|
|
63840
|
+
const current = exists(ignorePath) ? fs71.readFileSync(ignorePath, "utf8") : "";
|
|
63653
63841
|
const lines = new Set(current.split(/\r?\n/).map((l2) => l2.trim()).filter(Boolean));
|
|
63654
63842
|
let changed = false;
|
|
63655
63843
|
for (const n of needed) {
|
|
@@ -63659,7 +63847,7 @@ function ensureSecretsGitignore(cwd2) {
|
|
|
63659
63847
|
}
|
|
63660
63848
|
}
|
|
63661
63849
|
if (changed) {
|
|
63662
|
-
|
|
63850
|
+
fs71.writeFileSync(ignorePath, [...lines].join(`
|
|
63663
63851
|
`) + `
|
|
63664
63852
|
`);
|
|
63665
63853
|
}
|
|
@@ -63698,7 +63886,7 @@ function entrypointExecutionAllowed(opts) {
|
|
|
63698
63886
|
|
|
63699
63887
|
// src/cli/agent-unpack.ts
|
|
63700
63888
|
import path79 from "node:path";
|
|
63701
|
-
import
|
|
63889
|
+
import fs72 from "node:fs";
|
|
63702
63890
|
import os13 from "node:os";
|
|
63703
63891
|
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
63704
63892
|
function componentsForNativeInstall(components, acp) {
|
|
@@ -63747,14 +63935,14 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63747
63935
|
}
|
|
63748
63936
|
}
|
|
63749
63937
|
const scope = args.scope ?? "project";
|
|
63750
|
-
const stageRoot =
|
|
63938
|
+
const stageRoot = fs72.mkdtempSync(path79.join(os13.tmpdir(), "brainbase-unpack-"));
|
|
63751
63939
|
try {
|
|
63752
63940
|
const toInstall = [];
|
|
63753
63941
|
const instructionsBody = readInstructions(cwd2, manifest);
|
|
63754
63942
|
if (instructionsBody && instructionsBody.trim()) {
|
|
63755
63943
|
const compDir = path79.join(stageRoot, "instruction", "agent-instructions");
|
|
63756
63944
|
ensureDir(compDir);
|
|
63757
|
-
|
|
63945
|
+
fs72.writeFileSync(path79.join(compDir, "instructions.md"), instructionsBody, "utf8");
|
|
63758
63946
|
toInstall.push({
|
|
63759
63947
|
type: "instruction",
|
|
63760
63948
|
slug: "agent-instructions",
|
|
@@ -63833,7 +64021,7 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63833
64021
|
return;
|
|
63834
64022
|
} finally {
|
|
63835
64023
|
try {
|
|
63836
|
-
|
|
64024
|
+
fs72.rmSync(stageRoot, { recursive: true, force: true });
|
|
63837
64025
|
} catch {}
|
|
63838
64026
|
}
|
|
63839
64027
|
if (manifest.harness !== harness) {
|
|
@@ -63854,8 +64042,8 @@ async function runAgentUnpack(cwd2, args) {
|
|
|
63854
64042
|
function writeResolvedMcps(workdir, toInstall) {
|
|
63855
64043
|
const mcps = toInstall.filter((c2) => c2.type === "mcp").map((c2) => ({ name: c2.slug, ...c2.payload }));
|
|
63856
64044
|
const dir = path79.join(workdir, ".brainbase");
|
|
63857
|
-
|
|
63858
|
-
|
|
64045
|
+
fs72.mkdirSync(dir, { recursive: true });
|
|
64046
|
+
fs72.writeFileSync(path79.join(dir, "resolved-mcps.json"), JSON.stringify(mcps, null, 2));
|
|
63859
64047
|
}
|
|
63860
64048
|
function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
63861
64049
|
if (entry.content.text !== undefined && entry.content.file !== undefined) {
|
|
@@ -63869,7 +64057,7 @@ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
|
63869
64057
|
const compDir = path79.join(stageRoot, "playbook", slug);
|
|
63870
64058
|
ensureDir(compDir);
|
|
63871
64059
|
const wireBody = /^---\s*\n/.test(body) ? body : assembleFrontmatter(entry.title, entry.description) + body.replace(/^\n+/, "");
|
|
63872
|
-
|
|
64060
|
+
fs72.writeFileSync(path79.join(compDir, `${slug}.md`), wireBody, "utf8");
|
|
63873
64061
|
toInstall.push({
|
|
63874
64062
|
type: "playbook",
|
|
63875
64063
|
slug,
|
|
@@ -63883,7 +64071,7 @@ function stageLocalPlaybook(entry, cwd2, stageRoot, scope, toInstall) {
|
|
|
63883
64071
|
function stageLocalSkill(source, cwd2, stageRoot, scope, toInstall) {
|
|
63884
64072
|
if (source.startsWith("./") || source.startsWith("../") || source.startsWith("/")) {
|
|
63885
64073
|
const abs = path79.resolve(cwd2, source);
|
|
63886
|
-
if (!
|
|
64074
|
+
if (!fs72.existsSync(abs)) {
|
|
63887
64075
|
return `Skill ${source}: not found on disk — skipped.`;
|
|
63888
64076
|
}
|
|
63889
64077
|
const slug = path79.basename(abs);
|
|
@@ -63956,13 +64144,13 @@ function defaultSlugForSource(source) {
|
|
|
63956
64144
|
}
|
|
63957
64145
|
function copyDirRecursive(src, dest) {
|
|
63958
64146
|
ensureDir(dest);
|
|
63959
|
-
for (const entry of
|
|
64147
|
+
for (const entry of fs72.readdirSync(src, { withFileTypes: true })) {
|
|
63960
64148
|
const s3 = path79.join(src, entry.name);
|
|
63961
64149
|
const d3 = path79.join(dest, entry.name);
|
|
63962
64150
|
if (entry.isDirectory())
|
|
63963
64151
|
copyDirRecursive(s3, d3);
|
|
63964
64152
|
else if (entry.isFile())
|
|
63965
|
-
|
|
64153
|
+
fs72.copyFileSync(s3, d3);
|
|
63966
64154
|
}
|
|
63967
64155
|
}
|
|
63968
64156
|
function assembleFrontmatter(title, description) {
|
|
@@ -64214,14 +64402,14 @@ async function runAgentPull(cwd2, args) {
|
|
|
64214
64402
|
if (!prior)
|
|
64215
64403
|
continue;
|
|
64216
64404
|
for (const filePath of prior.installedPaths) {
|
|
64217
|
-
if (!
|
|
64405
|
+
if (!fs73.existsSync(filePath))
|
|
64218
64406
|
continue;
|
|
64219
64407
|
try {
|
|
64220
|
-
const stat =
|
|
64408
|
+
const stat = fs73.statSync(filePath);
|
|
64221
64409
|
if (stat.isDirectory())
|
|
64222
|
-
|
|
64410
|
+
fs73.rmSync(filePath, { recursive: true, force: true });
|
|
64223
64411
|
else
|
|
64224
|
-
|
|
64412
|
+
fs73.rmSync(filePath);
|
|
64225
64413
|
} catch (err) {
|
|
64226
64414
|
f2.warn(`Failed to remove ${filePath}: ${err.message}`);
|
|
64227
64415
|
}
|
|
@@ -64230,7 +64418,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
64230
64418
|
materializeInstructions(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
64231
64419
|
materializeEntrypoint(cwd2, cloudAgent.entrypoint ?? "", existingManifest);
|
|
64232
64420
|
materializePlaybooks(cwd2, cloud, toInstallKeys, keepLocalKeys, existingManifest);
|
|
64233
|
-
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness);
|
|
64421
|
+
const yaml = mergeManifest(cwd2, existingManifest, cloud, cloudAgent, harness, override ? {} : readLocalOnlyContentReporting(cwd2));
|
|
64234
64422
|
writeManifest(cwd2, yaml);
|
|
64235
64423
|
writeLink(cwd2, buildLinkFromAgent(cloudAgent, harness, readLink(cwd2)));
|
|
64236
64424
|
const lockComponents = buildLockComponents({
|
|
@@ -64260,7 +64448,7 @@ async function runAgentPull(cwd2, args) {
|
|
|
64260
64448
|
$e(`Pulled ${cloudAgent.name} at revision ${cloud.revision}.`);
|
|
64261
64449
|
} finally {
|
|
64262
64450
|
try {
|
|
64263
|
-
|
|
64451
|
+
fs73.rmSync(stageRoot, { recursive: true, force: true });
|
|
64264
64452
|
} catch {}
|
|
64265
64453
|
}
|
|
64266
64454
|
}
|
|
@@ -64316,14 +64504,14 @@ function skillSourceFromMeta(c2) {
|
|
|
64316
64504
|
}
|
|
64317
64505
|
}
|
|
64318
64506
|
function stageManifestComponents(components) {
|
|
64319
|
-
const root =
|
|
64507
|
+
const root = fs73.mkdtempSync(path80.join(os14.tmpdir(), "brainbase-pull-"));
|
|
64320
64508
|
for (const c2 of components) {
|
|
64321
64509
|
const compDir = path80.join(root, c2.type, c2.slug);
|
|
64322
64510
|
ensureDir(compDir);
|
|
64323
64511
|
for (const f4 of c2.files) {
|
|
64324
64512
|
const target = path80.join(compDir, f4.path);
|
|
64325
64513
|
ensureDir(path80.dirname(target));
|
|
64326
|
-
|
|
64514
|
+
fs73.writeFileSync(target, f4.content);
|
|
64327
64515
|
}
|
|
64328
64516
|
}
|
|
64329
64517
|
return root;
|
|
@@ -64366,7 +64554,7 @@ function materializeInstructions(cwd2, cloud, toInstall, keepLocal, existingMani
|
|
|
64366
64554
|
const targetRel = existingManifest?.instructions?.file ?? DEFAULT_INSTRUCTIONS_FILE;
|
|
64367
64555
|
const target = path80.resolve(cwd2, targetRel);
|
|
64368
64556
|
ensureDir(path80.dirname(target));
|
|
64369
|
-
|
|
64557
|
+
fs73.writeFileSync(target, normalizeInstructionBody(body), "utf8");
|
|
64370
64558
|
}
|
|
64371
64559
|
}
|
|
64372
64560
|
function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifest) {
|
|
@@ -64388,10 +64576,10 @@ function materializePlaybooks(cwd2, cloud, toInstall, keepLocal, existingManifes
|
|
|
64388
64576
|
const targetRel = existing?.content?.file ?? path80.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
|
|
64389
64577
|
const target = path80.resolve(cwd2, targetRel);
|
|
64390
64578
|
ensureDir(path80.dirname(target));
|
|
64391
|
-
|
|
64579
|
+
fs73.writeFileSync(target, body, "utf8");
|
|
64392
64580
|
}
|
|
64393
64581
|
}
|
|
64394
|
-
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
64582
|
+
function mergeManifest(cwd2, prev, cloud, cloudAgent, harness, localOnly = {}) {
|
|
64395
64583
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
64396
64584
|
const localDecl = prev?.skills.find((s3) => looseSkillComponentSlug(s3.source) === c2.slug);
|
|
64397
64585
|
if (localDecl)
|
|
@@ -64472,7 +64660,8 @@ function mergeManifest(cwd2, prev, cloud, cloudAgent, harness) {
|
|
|
64472
64660
|
playbooks,
|
|
64473
64661
|
skills,
|
|
64474
64662
|
mcp,
|
|
64475
|
-
evals:
|
|
64663
|
+
evals: [],
|
|
64664
|
+
...localOnly,
|
|
64476
64665
|
capabilities: {
|
|
64477
64666
|
memory: caps.memory,
|
|
64478
64667
|
browser: caps.browser,
|
|
@@ -64491,9 +64680,9 @@ function materializeEntrypoint(cwd2, cloudEntrypoint, prev) {
|
|
|
64491
64680
|
return;
|
|
64492
64681
|
const filename = prev?.entrypoint?.file ?? DEFAULT_ENTRYPOINT_FILE;
|
|
64493
64682
|
const target = path80.resolve(cwd2, filename);
|
|
64494
|
-
|
|
64683
|
+
fs73.writeFileSync(target, cloudEntrypoint, "utf8");
|
|
64495
64684
|
try {
|
|
64496
|
-
|
|
64685
|
+
fs73.chmodSync(target, 493);
|
|
64497
64686
|
} catch {}
|
|
64498
64687
|
}
|
|
64499
64688
|
function buildLockComponents(input) {
|
|
@@ -64572,9 +64761,9 @@ async function runEntrypointIfPresent(cwd2, manifest, execute) {
|
|
|
64572
64761
|
ensureDir(stateDir);
|
|
64573
64762
|
const scriptPath = path80.join(stateDir, "entrypoint.sh");
|
|
64574
64763
|
const logPath = path80.join(stateDir, "entrypoint.log");
|
|
64575
|
-
|
|
64764
|
+
fs73.writeFileSync(scriptPath, body, "utf8");
|
|
64576
64765
|
try {
|
|
64577
|
-
|
|
64766
|
+
fs73.chmodSync(scriptPath, 493);
|
|
64578
64767
|
} catch {}
|
|
64579
64768
|
if (!execute) {
|
|
64580
64769
|
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.`);
|
|
@@ -64583,7 +64772,7 @@ async function runEntrypointIfPresent(cwd2, manifest, execute) {
|
|
|
64583
64772
|
f2.info(`Running entrypoint ${import_picocolors26.default.dim(`(${path80.relative(cwd2, scriptPath)})`)}`);
|
|
64584
64773
|
const secrets = readLocalSecrets(cwd2);
|
|
64585
64774
|
const env3 = { ...process.env, ...secrets };
|
|
64586
|
-
const logStream =
|
|
64775
|
+
const logStream = fs73.createWriteStream(logPath, { flags: "w" });
|
|
64587
64776
|
const exitCode = await new Promise((resolve) => {
|
|
64588
64777
|
const child = spawn2("bash", [scriptPath], {
|
|
64589
64778
|
cwd: cwd2,
|
|
@@ -64618,7 +64807,7 @@ async function pullSecrets(cwd2, agentId) {
|
|
|
64618
64807
|
sp.start("Fetching secrets…");
|
|
64619
64808
|
try {
|
|
64620
64809
|
const res = await api.getAgentSecrets(agentId);
|
|
64621
|
-
cloudSecrets = res.secrets
|
|
64810
|
+
cloudSecrets = res.secrets;
|
|
64622
64811
|
sp.stop(Object.keys(cloudSecrets).length === 0 ? "No secrets on cloud." : `Got ${Object.keys(cloudSecrets).length} secret${Object.keys(cloudSecrets).length === 1 ? "" : "s"}.`);
|
|
64623
64812
|
} catch (err) {
|
|
64624
64813
|
sp.stop("Failed to fetch secrets.");
|
|
@@ -64859,6 +65048,10 @@ async function runAgentPush(cwd2, args) {
|
|
|
64859
65048
|
process.exitCode = 1;
|
|
64860
65049
|
return;
|
|
64861
65050
|
}
|
|
65051
|
+
if (reportUnsyncedBlocks(manifest)) {
|
|
65052
|
+
process.exitCode = 1;
|
|
65053
|
+
return;
|
|
65054
|
+
}
|
|
64862
65055
|
if (!manifest.id) {
|
|
64863
65056
|
f2.warn(`${import_picocolors28.default.bold(AGENT_MANIFEST_FILE)} is unclaimed (no ${import_picocolors28.default.cyan("id")}). Nothing to push to.`);
|
|
64864
65057
|
f2.info(`Run ${import_picocolors28.default.cyan("brainbase agent create")} first — that creates the cloud agent and stamps an id here.`);
|
|
@@ -64961,6 +65154,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64961
65154
|
const version = registryRefs.get(name)?.version ?? "0.1.0";
|
|
64962
65155
|
f2.info(` ${import_picocolors28.default.cyan(`brainbase skill publish ./path/to/skill --name ${name} --skill-version ${version} --yes`)}`);
|
|
64963
65156
|
}
|
|
65157
|
+
process.exitCode = 1;
|
|
64964
65158
|
return;
|
|
64965
65159
|
}
|
|
64966
65160
|
const skillUpdates = planRegistrySkillUpdates(manifest.skills, cloud.components, latestByName);
|
|
@@ -64981,6 +65175,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64981
65175
|
} else {
|
|
64982
65176
|
f2.error("Entrypoint block is empty.");
|
|
64983
65177
|
}
|
|
65178
|
+
process.exitCode = 1;
|
|
64984
65179
|
return;
|
|
64985
65180
|
}
|
|
64986
65181
|
resolvedEntrypoint = body;
|
|
@@ -64993,6 +65188,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
64993
65188
|
for (const r2 of rows) {
|
|
64994
65189
|
if (r2.type !== "instruction" && r2.type !== "skill" && r2.type !== "mcp" && r2.type !== "playbook") {
|
|
64995
65190
|
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.`);
|
|
65191
|
+
process.exitCode = 1;
|
|
64996
65192
|
return;
|
|
64997
65193
|
}
|
|
64998
65194
|
}
|
|
@@ -65005,6 +65201,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65005
65201
|
}
|
|
65006
65202
|
if (parsed.kind === "local") {
|
|
65007
65203
|
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\`).`);
|
|
65204
|
+
process.exitCode = 1;
|
|
65008
65205
|
return;
|
|
65009
65206
|
}
|
|
65010
65207
|
}
|
|
@@ -65017,6 +65214,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65017
65214
|
}).map((c2) => c2.slug);
|
|
65018
65215
|
if (preIdSchemaSlugs.length > 0) {
|
|
65019
65216
|
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.`);
|
|
65217
|
+
process.exitCode = 1;
|
|
65020
65218
|
return;
|
|
65021
65219
|
}
|
|
65022
65220
|
const { toSend, conflicts, upstreamOnly } = partitionPushRows(rows, !!args.force);
|
|
@@ -65027,6 +65225,7 @@ async function runAgentPush(cwd2, args) {
|
|
|
65027
65225
|
console.error(` ${import_picocolors28.default.red("!")} ${fmtType(r2.type)} ${import_picocolors28.default.bold(r2.slug)}`);
|
|
65028
65226
|
}
|
|
65029
65227
|
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.`);
|
|
65228
|
+
process.exitCode = 1;
|
|
65030
65229
|
return;
|
|
65031
65230
|
}
|
|
65032
65231
|
if (forcedOverrides.length > 0) {
|
|
@@ -65303,7 +65502,7 @@ async function planSecretPush(cwd2, agentId) {
|
|
|
65303
65502
|
if (Object.keys(localSecrets).length === 0)
|
|
65304
65503
|
return null;
|
|
65305
65504
|
const res = await api.getAgentSecrets(agentId);
|
|
65306
|
-
const cloudSecrets = res.secrets
|
|
65505
|
+
const cloudSecrets = res.secrets;
|
|
65307
65506
|
const diff2 = diffSecrets(localSecrets, cloudSecrets);
|
|
65308
65507
|
if (diff2.localOnly.length === 0 && diff2.changed.length === 0 && diff2.cloudOnly.length === 0) {
|
|
65309
65508
|
return null;
|
|
@@ -65340,37 +65539,64 @@ function handleApiError3(err) {
|
|
|
65340
65539
|
}
|
|
65341
65540
|
|
|
65342
65541
|
// src/cli/agent-status.ts
|
|
65542
|
+
import path81 from "node:path";
|
|
65343
65543
|
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
65344
|
-
async function runAgentStatus(cwd2) {
|
|
65345
|
-
|
|
65544
|
+
async function runAgentStatus(cwd2, args = {}) {
|
|
65545
|
+
const json = args.json === true;
|
|
65546
|
+
if (!json)
|
|
65547
|
+
banner("agent status — what changed locally, remotely, both");
|
|
65346
65548
|
const link2 = readLink(cwd2);
|
|
65347
65549
|
if (!link2) {
|
|
65550
|
+
if (json) {
|
|
65551
|
+
emitJson({ linked: false, ignored: [], unchecked: [] });
|
|
65552
|
+
return;
|
|
65553
|
+
}
|
|
65348
65554
|
f2.warn("This folder is not linked to any agent.");
|
|
65349
65555
|
f2.info(`Run ${import_picocolors29.default.cyan("brainbase link")} first.`);
|
|
65350
65556
|
return;
|
|
65351
65557
|
}
|
|
65352
65558
|
const manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
|
|
65353
65559
|
const lock = readSyncState(cwd2);
|
|
65560
|
+
const ignoredBlocks = manifest ? findUnsyncedBlocks(manifest) : [];
|
|
65561
|
+
const ignored = ignoredBlocks.map((block) => ({
|
|
65562
|
+
block: block.key,
|
|
65563
|
+
entries: block.entries,
|
|
65564
|
+
reason: unsyncedBlockReason(block)
|
|
65565
|
+
}));
|
|
65354
65566
|
let cloud = null;
|
|
65355
65567
|
let cloudAgent = null;
|
|
65356
|
-
const sp = de();
|
|
65357
|
-
sp
|
|
65568
|
+
const sp = json ? null : de();
|
|
65569
|
+
sp?.start(`Fetching ${link2.name}…`);
|
|
65358
65570
|
try {
|
|
65359
65571
|
[cloud, cloudAgent] = await Promise.all([
|
|
65360
65572
|
api.getAgentManifest(link2.agent_id),
|
|
65361
65573
|
api.getAgent(link2.agent_id)
|
|
65362
65574
|
]);
|
|
65363
|
-
sp
|
|
65575
|
+
sp?.stop(`Cloud revision ${cloud.revision}.`);
|
|
65364
65576
|
} catch (err) {
|
|
65365
|
-
|
|
65366
|
-
|
|
65367
|
-
|
|
65368
|
-
|
|
65369
|
-
|
|
65577
|
+
const unauthorized = err instanceof ApiError && err.status === 401;
|
|
65578
|
+
const message = unauthorized ? "Your session is invalid. Run `brainbase login` and try again." : err.message;
|
|
65579
|
+
if (json) {
|
|
65580
|
+
console.error(message);
|
|
65581
|
+
process.exitCode = 1;
|
|
65582
|
+
return;
|
|
65370
65583
|
}
|
|
65584
|
+
sp?.stop("Failed to reach brainbase.");
|
|
65585
|
+
f2.error(message);
|
|
65371
65586
|
return;
|
|
65372
65587
|
}
|
|
65373
65588
|
if (!manifest) {
|
|
65589
|
+
if (json) {
|
|
65590
|
+
emitJson({
|
|
65591
|
+
linked: true,
|
|
65592
|
+
manifest: false,
|
|
65593
|
+
agent: { id: link2.agent_id, name: link2.name, slug: link2.slug },
|
|
65594
|
+
revision: { cloud: cloud.revision, lock: lock?.revision ?? null },
|
|
65595
|
+
ignored,
|
|
65596
|
+
unchecked: []
|
|
65597
|
+
});
|
|
65598
|
+
return;
|
|
65599
|
+
}
|
|
65374
65600
|
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.`);
|
|
65375
65601
|
f2.info(`Cloud has ${import_picocolors29.default.bold(String(cloud.components.length))} component${cloud.components.length === 1 ? "" : "s"} at revision ${cloud.revision}.`);
|
|
65376
65602
|
return;
|
|
@@ -65415,21 +65641,68 @@ async function runAgentStatus(cwd2) {
|
|
|
65415
65641
|
cloudOnly: [],
|
|
65416
65642
|
changed: []
|
|
65417
65643
|
};
|
|
65644
|
+
let secretsChecked = true;
|
|
65645
|
+
let secretsUncheckedReason = "";
|
|
65418
65646
|
try {
|
|
65419
65647
|
const localSecrets = readLocalSecrets(cwd2);
|
|
65420
65648
|
const cloudRes = await api.getAgentSecrets(link2.agent_id);
|
|
65421
|
-
secretDrift = diffSecrets(localSecrets, cloudRes.secrets
|
|
65422
|
-
} catch {
|
|
65649
|
+
secretDrift = diffSecrets(localSecrets, cloudRes.secrets);
|
|
65650
|
+
} catch (err) {
|
|
65651
|
+
if (!(err instanceof ApiError && err.status === 404)) {
|
|
65652
|
+
secretsChecked = false;
|
|
65653
|
+
secretsUncheckedReason = describeSecretsFailure(err);
|
|
65654
|
+
}
|
|
65655
|
+
}
|
|
65423
65656
|
const componentsDrifted = conflicts.length > 0 || toPush.length > 0 || toPull.length > 0;
|
|
65424
65657
|
const metaDrifted = meta.localChanged || meta.cloudChanged;
|
|
65425
65658
|
const configDrifted = config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged;
|
|
65426
65659
|
const secretsDrifted = secretDrift.localOnly.length > 0 || secretDrift.cloudOnly.length > 0 || secretDrift.changed.length > 0;
|
|
65660
|
+
const everythingInSync = !componentsDrifted && !metaDrifted && !configDrifted && !secretsDrifted;
|
|
65661
|
+
const unchecked = secretsChecked ? [] : [{ signal: "secrets", reason: secretsUncheckedReason }];
|
|
65662
|
+
if (json) {
|
|
65663
|
+
emitJson({
|
|
65664
|
+
linked: true,
|
|
65665
|
+
manifest: true,
|
|
65666
|
+
agent: { id: link2.agent_id, name: link2.name, slug: link2.slug },
|
|
65667
|
+
revision: { cloud: cloud.revision, lock: lock?.revision ?? null },
|
|
65668
|
+
ignored,
|
|
65669
|
+
metadata: { push: meta.localChanged, pull: meta.cloudChanged },
|
|
65670
|
+
runtimeConfig: {
|
|
65671
|
+
unsupported: config.unsupported,
|
|
65672
|
+
machineMismatch: config.machineMismatch,
|
|
65673
|
+
machineCloudChanged: config.machineCloudChanged,
|
|
65674
|
+
defaultModelLocalChanged: config.defaultModelLocalChanged,
|
|
65675
|
+
defaultModelCloudChanged: config.defaultModelCloudChanged,
|
|
65676
|
+
defaultModelConflict: config.defaultModelConflict
|
|
65677
|
+
},
|
|
65678
|
+
secrets: secretsChecked ? {
|
|
65679
|
+
localOnly: secretDrift.localOnly,
|
|
65680
|
+
cloudOnly: secretDrift.cloudOnly,
|
|
65681
|
+
changed: secretDrift.changed
|
|
65682
|
+
} : null,
|
|
65683
|
+
components: {
|
|
65684
|
+
push: toPush.map(rowJson),
|
|
65685
|
+
pull: toPull.map(rowJson),
|
|
65686
|
+
conflicts: conflicts.map(rowJson)
|
|
65687
|
+
},
|
|
65688
|
+
inSync: everythingInSync,
|
|
65689
|
+
unchecked
|
|
65690
|
+
});
|
|
65691
|
+
return;
|
|
65692
|
+
}
|
|
65427
65693
|
const lines = [];
|
|
65428
65694
|
lines.push("");
|
|
65429
65695
|
lines.push(` ${import_picocolors29.default.bold(link2.name)} ${import_picocolors29.default.dim(`(${link2.slug})`)}`);
|
|
65430
65696
|
lines.push(` ${import_picocolors29.default.dim("agent_id")} ${link2.agent_id}`);
|
|
65431
65697
|
lines.push(` ${import_picocolors29.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
|
|
65432
65698
|
lines.push("");
|
|
65699
|
+
if (ignoredBlocks.length > 0) {
|
|
65700
|
+
lines.push(` ${import_picocolors29.default.bold("ignored manifest blocks")}`);
|
|
65701
|
+
for (const block of ignoredBlocks) {
|
|
65702
|
+
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`);
|
|
65703
|
+
}
|
|
65704
|
+
lines.push("");
|
|
65705
|
+
}
|
|
65433
65706
|
if (metaDrifted) {
|
|
65434
65707
|
lines.push(` ${import_picocolors29.default.bold("agent metadata")}`);
|
|
65435
65708
|
if (meta.localChanged) {
|
|
@@ -65463,8 +65736,11 @@ async function runAgentStatus(cwd2) {
|
|
|
65463
65736
|
}
|
|
65464
65737
|
lines.push("");
|
|
65465
65738
|
}
|
|
65466
|
-
if (secretsDrifted) {
|
|
65739
|
+
if (secretsDrifted || !secretsChecked) {
|
|
65467
65740
|
lines.push(` ${import_picocolors29.default.bold("secrets")}`);
|
|
65741
|
+
if (!secretsChecked) {
|
|
65742
|
+
lines.push(` ${import_picocolors29.default.dim("? unchecked")} ${secretsUncheckedReason}`);
|
|
65743
|
+
}
|
|
65468
65744
|
if (secretDrift.localOnly.length)
|
|
65469
65745
|
lines.push(` ${import_picocolors29.default.yellow("→ push")} new locally: ${secretDrift.localOnly.join(", ")}`);
|
|
65470
65746
|
if (secretDrift.changed.length)
|
|
@@ -65473,8 +65749,9 @@ async function runAgentStatus(cwd2) {
|
|
|
65473
65749
|
lines.push(` ${import_picocolors29.default.cyan("← pull")} new on cloud: ${secretDrift.cloudOnly.join(", ")}`);
|
|
65474
65750
|
lines.push("");
|
|
65475
65751
|
}
|
|
65476
|
-
if (
|
|
65477
|
-
|
|
65752
|
+
if (everythingInSync) {
|
|
65753
|
+
const qualifier = secretsChecked ? "" : ` ${import_picocolors29.default.dim("(secrets not checked)")}`;
|
|
65754
|
+
lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync${qualifier}`);
|
|
65478
65755
|
lines.push("");
|
|
65479
65756
|
console.log(lines.join(`
|
|
65480
65757
|
`));
|
|
@@ -65503,6 +65780,26 @@ async function runAgentStatus(cwd2) {
|
|
|
65503
65780
|
console.log(lines.join(`
|
|
65504
65781
|
`));
|
|
65505
65782
|
}
|
|
65783
|
+
function emitJson(report) {
|
|
65784
|
+
console.log(JSON.stringify(report, null, 2));
|
|
65785
|
+
}
|
|
65786
|
+
function rowJson(r2) {
|
|
65787
|
+
return { type: r2.type, slug: r2.slug, status: r2.status };
|
|
65788
|
+
}
|
|
65789
|
+
var MAX_REASON_LENGTH = 120;
|
|
65790
|
+
function oneLine(text2) {
|
|
65791
|
+
const collapsed = text2.replace(/\s+/g, " ").trim();
|
|
65792
|
+
return collapsed.length > MAX_REASON_LENGTH ? `${collapsed.slice(0, MAX_REASON_LENGTH - 1)}…` : collapsed;
|
|
65793
|
+
}
|
|
65794
|
+
function describeSecretsFailure(err) {
|
|
65795
|
+
const remote = err instanceof ApiError;
|
|
65796
|
+
if (remote && err.status === 401) {
|
|
65797
|
+
return "could not fetch secrets: your session is invalid — run `brainbase login`";
|
|
65798
|
+
}
|
|
65799
|
+
const where = remote ? "could not fetch secrets from the control plane" : `could not read ${path81.join(LINK_DIR, SECRETS_FILE)}`;
|
|
65800
|
+
const detail = oneLine(err instanceof Error ? err.message : typeof err === "string" ? err : "");
|
|
65801
|
+
return detail ? `${where}: ${detail}` : where;
|
|
65802
|
+
}
|
|
65506
65803
|
function fmtRow(r2) {
|
|
65507
65804
|
const head3 = `${fmtType(r2.type)} ${import_picocolors29.default.bold(r2.slug)}`;
|
|
65508
65805
|
switch (r2.status) {
|
|
@@ -65558,7 +65855,7 @@ function formatExport(shell, key2, value) {
|
|
|
65558
65855
|
}
|
|
65559
65856
|
|
|
65560
65857
|
// src/cli/agent-create.ts
|
|
65561
|
-
import
|
|
65858
|
+
import path82 from "node:path";
|
|
65562
65859
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
65563
65860
|
|
|
65564
65861
|
// src/ui/box.ts
|
|
@@ -65762,6 +66059,10 @@ async function runAgentCreate(cwd2, args) {
|
|
|
65762
66059
|
f2.info(`If you want to detach it, run ${import_picocolors32.default.cyan("brainbase unlink")} first; or move to a different directory.`);
|
|
65763
66060
|
return;
|
|
65764
66061
|
}
|
|
66062
|
+
if (reportUnsyncedBlocks(manifest)) {
|
|
66063
|
+
process.exitCode = 1;
|
|
66064
|
+
return;
|
|
66065
|
+
}
|
|
65765
66066
|
const { org, team } = await resolveOrgAndTeam({
|
|
65766
66067
|
orgId: args.orgId,
|
|
65767
66068
|
teamId: args.teamId,
|
|
@@ -66030,7 +66331,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
|
|
|
66030
66331
|
return null;
|
|
66031
66332
|
}
|
|
66032
66333
|
}
|
|
66033
|
-
const seedName = args.name?.trim() ??
|
|
66334
|
+
const seedName = args.name?.trim() ?? path82.basename(path82.resolve(cwd2)) ?? "My Agent";
|
|
66034
66335
|
const seedHarness = args.harness ? normalizeHarnessId(args.harness) : undefined;
|
|
66035
66336
|
const scaffold = {
|
|
66036
66337
|
schema: 1,
|
|
@@ -66168,7 +66469,7 @@ async function runAgent(cwd2, sub, args, opts) {
|
|
|
66168
66469
|
});
|
|
66169
66470
|
return;
|
|
66170
66471
|
case "status":
|
|
66171
|
-
await runAgentStatus(cwd2);
|
|
66472
|
+
await runAgentStatus(cwd2, { json: opts.json });
|
|
66172
66473
|
return;
|
|
66173
66474
|
case "env":
|
|
66174
66475
|
await runAgentEnv(cwd2, { shell: opts.shell });
|
|
@@ -66196,7 +66497,7 @@ function printHelp() {
|
|
|
66196
66497
|
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")}`);
|
|
66197
66498
|
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)")}`);
|
|
66198
66499
|
out.push(` ${import_picocolors34.default.cyan("unpack")} ${import_picocolors34.default.dim("install the claimed agent into a harness layout (--harness to override)")}`);
|
|
66199
|
-
out.push(` ${import_picocolors34.default.cyan("status")} ${import_picocolors34.default.dim("show what would push
|
|
66500
|
+
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)")}`);
|
|
66200
66501
|
out.push(` ${import_picocolors34.default.cyan("env")} ${import_picocolors34.default.dim('print export statements — use with `eval "$(brainbase agent env)"`')}`);
|
|
66201
66502
|
out.push("");
|
|
66202
66503
|
console.log(out.join(`
|
|
@@ -66291,14 +66592,14 @@ function printHelp2() {
|
|
|
66291
66592
|
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
66292
66593
|
|
|
66293
66594
|
// src/cli/orchestration-pull.ts
|
|
66294
|
-
import
|
|
66295
|
-
import
|
|
66595
|
+
import path86 from "node:path";
|
|
66596
|
+
import fs77 from "node:fs";
|
|
66296
66597
|
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
66297
66598
|
|
|
66298
66599
|
// src/core/orchestration-manifest.ts
|
|
66299
|
-
import
|
|
66300
|
-
import
|
|
66301
|
-
var
|
|
66600
|
+
import path83 from "node:path";
|
|
66601
|
+
import fs74 from "node:fs";
|
|
66602
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
66302
66603
|
var ORCH_MANIFEST_FILE = "brainbase-orchestration.yaml";
|
|
66303
66604
|
var ORCH_MEMBERS_DIR = "agents";
|
|
66304
66605
|
var OrchMetaSchema = exports_external.object({
|
|
@@ -66350,19 +66651,19 @@ var OrchestrationManifestSchema = exports_external.object({
|
|
|
66350
66651
|
triggers: exports_external.array(TriggerSchema).optional()
|
|
66351
66652
|
});
|
|
66352
66653
|
function orchManifestPath(cwd2) {
|
|
66353
|
-
return
|
|
66654
|
+
return path83.join(cwd2, ORCH_MANIFEST_FILE);
|
|
66354
66655
|
}
|
|
66355
66656
|
function hasOrchManifest(cwd2) {
|
|
66356
|
-
return
|
|
66657
|
+
return fs74.existsSync(orchManifestPath(cwd2));
|
|
66357
66658
|
}
|
|
66358
66659
|
function readOrchManifest(cwd2) {
|
|
66359
66660
|
const p2 = orchManifestPath(cwd2);
|
|
66360
|
-
if (!
|
|
66661
|
+
if (!fs74.existsSync(p2))
|
|
66361
66662
|
return null;
|
|
66362
|
-
const raw =
|
|
66663
|
+
const raw = fs74.readFileSync(p2, "utf8");
|
|
66363
66664
|
let parsed;
|
|
66364
66665
|
try {
|
|
66365
|
-
parsed =
|
|
66666
|
+
parsed = import_yaml4.default.parse(raw);
|
|
66366
66667
|
} catch (err) {
|
|
66367
66668
|
throw new Error(`${ORCH_MANIFEST_FILE} is not valid YAML: ${err.message}`);
|
|
66368
66669
|
}
|
|
@@ -66373,17 +66674,17 @@ function readOrchManifest(cwd2) {
|
|
|
66373
66674
|
return result2.data;
|
|
66374
66675
|
}
|
|
66375
66676
|
function writeOrchManifest(cwd2, manifest) {
|
|
66376
|
-
const doc = new
|
|
66677
|
+
const doc = new import_yaml4.default.Document;
|
|
66377
66678
|
doc.contents = manifest;
|
|
66378
66679
|
doc.commentBefore = ` brainbase-orchestration.yaml — declarative orchestration manifest.
|
|
66379
66680
|
` + ` Committed to source control. Edit by hand, then
|
|
66380
66681
|
` + " `brainbase orchestration push`. Member agents live under ./agents/." + `
|
|
66381
66682
|
Schedule triggers are writable. App/Pipedream triggers are preserved
|
|
66382
66683
|
` + " as read-only context and ignored by `orchestration push`.";
|
|
66383
|
-
|
|
66684
|
+
fs74.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
|
|
66384
66685
|
}
|
|
66385
66686
|
function memberDir(cwd2, slug) {
|
|
66386
|
-
return
|
|
66687
|
+
return path83.join(cwd2, ORCH_MEMBERS_DIR, slug);
|
|
66387
66688
|
}
|
|
66388
66689
|
var MEMBER_SLUG_MAX = 50;
|
|
66389
66690
|
function slugifyRaw(raw) {
|
|
@@ -66417,8 +66718,8 @@ function resolveMemberSlugs(members) {
|
|
|
66417
66718
|
}
|
|
66418
66719
|
|
|
66419
66720
|
// src/core/orchestration-link.ts
|
|
66420
|
-
import
|
|
66421
|
-
import
|
|
66721
|
+
import path84 from "node:path";
|
|
66722
|
+
import fs75 from "node:fs";
|
|
66422
66723
|
var ORCH_LINK_FILE = "orchestration-link.json";
|
|
66423
66724
|
var ORCH_SYNC_STATE_FILE = "orchestration-sync-state.json";
|
|
66424
66725
|
var OrchestrationLinkSchema = exports_external.object({
|
|
@@ -66452,10 +66753,10 @@ var OrchestrationSyncStateSchema = exports_external.object({
|
|
|
66452
66753
|
edges: exports_external.array(SyncedEdgeSchema)
|
|
66453
66754
|
});
|
|
66454
66755
|
function orchLinkPath(cwd2) {
|
|
66455
|
-
return
|
|
66756
|
+
return path84.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
|
|
66456
66757
|
}
|
|
66457
66758
|
function orchSyncStatePath(cwd2) {
|
|
66458
|
-
return
|
|
66759
|
+
return path84.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
|
|
66459
66760
|
}
|
|
66460
66761
|
function readOrchLink(cwd2) {
|
|
66461
66762
|
const p2 = orchLinkPath(cwd2);
|
|
@@ -66468,7 +66769,7 @@ function readOrchLink(cwd2) {
|
|
|
66468
66769
|
}
|
|
66469
66770
|
}
|
|
66470
66771
|
function writeOrchLink(cwd2, link2) {
|
|
66471
|
-
ensureDir(
|
|
66772
|
+
ensureDir(path84.join(cwd2, LINK_DIR));
|
|
66472
66773
|
const clean = {};
|
|
66473
66774
|
for (const [k3, v3] of Object.entries(link2)) {
|
|
66474
66775
|
if (v3 !== null && v3 !== undefined)
|
|
@@ -66488,22 +66789,22 @@ function readOrchSyncState(cwd2) {
|
|
|
66488
66789
|
}
|
|
66489
66790
|
}
|
|
66490
66791
|
function writeOrchSyncState(cwd2, state) {
|
|
66491
|
-
ensureDir(
|
|
66792
|
+
ensureDir(path84.join(cwd2, LINK_DIR));
|
|
66492
66793
|
writeJson(orchSyncStatePath(cwd2), state);
|
|
66493
66794
|
ensureGitignore2(cwd2);
|
|
66494
66795
|
}
|
|
66495
66796
|
function ensureGitignore2(cwd2) {
|
|
66496
|
-
const ignorePath =
|
|
66797
|
+
const ignorePath = path84.join(cwd2, LINK_DIR, ".gitignore");
|
|
66497
66798
|
const desired = `${ORCH_SYNC_STATE_FILE}
|
|
66498
66799
|
`;
|
|
66499
66800
|
try {
|
|
66500
66801
|
if (!exists(ignorePath)) {
|
|
66501
|
-
|
|
66802
|
+
fs75.writeFileSync(ignorePath, desired);
|
|
66502
66803
|
return;
|
|
66503
66804
|
}
|
|
66504
|
-
const current =
|
|
66805
|
+
const current = fs75.readFileSync(ignorePath, "utf8");
|
|
66505
66806
|
if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
|
|
66506
|
-
|
|
66807
|
+
fs75.writeFileSync(ignorePath, current.endsWith(`
|
|
66507
66808
|
`) ? current + desired : current + `
|
|
66508
66809
|
` + desired);
|
|
66509
66810
|
}
|
|
@@ -66511,8 +66812,8 @@ function ensureGitignore2(cwd2) {
|
|
|
66511
66812
|
}
|
|
66512
66813
|
|
|
66513
66814
|
// src/core/agent-fresh-install.ts
|
|
66514
|
-
import
|
|
66515
|
-
import
|
|
66815
|
+
import path85 from "node:path";
|
|
66816
|
+
import fs76 from "node:fs";
|
|
66516
66817
|
import os15 from "node:os";
|
|
66517
66818
|
async function installAgentFresh(input) {
|
|
66518
66819
|
const { cwd: cwd2, agent, cloud, harness } = input;
|
|
@@ -66534,7 +66835,7 @@ async function installAgentFresh(input) {
|
|
|
66534
66835
|
type: c2.type,
|
|
66535
66836
|
slug: c2.slug,
|
|
66536
66837
|
scope,
|
|
66537
|
-
rootDir:
|
|
66838
|
+
rootDir: path85.join(stageRoot, c2.type, c2.slug),
|
|
66538
66839
|
description: c2.description,
|
|
66539
66840
|
meta: c2.meta,
|
|
66540
66841
|
payload: proxifyMcpPayload(structuredClone(c2.meta?.mcp)),
|
|
@@ -66556,7 +66857,12 @@ async function installAgentFresh(input) {
|
|
|
66556
66857
|
}
|
|
66557
66858
|
materializeInstructions2(cwd2, cloud);
|
|
66558
66859
|
materializePlaybooks2(cwd2, cloud);
|
|
66559
|
-
const
|
|
66860
|
+
const claimedByOther = folderClaimedByOtherAgent(cwd2, agent.id);
|
|
66861
|
+
const localOnly = input.preserveManifest || claimedByOther ? {} : readLocalOnlyContentReporting(cwd2);
|
|
66862
|
+
if (claimedByOther) {
|
|
66863
|
+
f2.warn(`${path85.basename(cwd2)} was linked to a different agent; its local-only blocks were left out of the rebuilt manifest.`);
|
|
66864
|
+
}
|
|
66865
|
+
const manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent, localOnly);
|
|
66560
66866
|
if (manifest)
|
|
66561
66867
|
writeManifest(cwd2, manifest);
|
|
66562
66868
|
writeLink(cwd2, {
|
|
@@ -66590,7 +66896,7 @@ async function installAgentFresh(input) {
|
|
|
66590
66896
|
...Object.prototype.hasOwnProperty.call(agent, "default_model") ? { default_model: agent.default_model ?? null } : {}
|
|
66591
66897
|
}
|
|
66592
66898
|
});
|
|
66593
|
-
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent);
|
|
66899
|
+
const returnedManifest = manifest ?? buildManifestFromCloud(cloud, agent, localOnly);
|
|
66594
66900
|
return {
|
|
66595
66901
|
installedPaths: justInstalledPaths,
|
|
66596
66902
|
manifest: returnedManifest,
|
|
@@ -66598,19 +66904,19 @@ async function installAgentFresh(input) {
|
|
|
66598
66904
|
};
|
|
66599
66905
|
} finally {
|
|
66600
66906
|
try {
|
|
66601
|
-
|
|
66907
|
+
fs76.rmSync(stageRoot, { recursive: true, force: true });
|
|
66602
66908
|
} catch {}
|
|
66603
66909
|
}
|
|
66604
66910
|
}
|
|
66605
66911
|
function stageManifestComponents2(components) {
|
|
66606
|
-
const root =
|
|
66912
|
+
const root = fs76.mkdtempSync(path85.join(os15.tmpdir(), "brainbase-orch-pull-"));
|
|
66607
66913
|
for (const c2 of components) {
|
|
66608
|
-
const compDir =
|
|
66914
|
+
const compDir = path85.join(root, c2.type, c2.slug);
|
|
66609
66915
|
ensureDir(compDir);
|
|
66610
66916
|
for (const f4 of c2.files) {
|
|
66611
|
-
const target =
|
|
66612
|
-
ensureDir(
|
|
66613
|
-
|
|
66917
|
+
const target = path85.join(compDir, f4.path);
|
|
66918
|
+
ensureDir(path85.dirname(target));
|
|
66919
|
+
fs76.writeFileSync(target, f4.content);
|
|
66614
66920
|
}
|
|
66615
66921
|
}
|
|
66616
66922
|
return root;
|
|
@@ -66643,9 +66949,9 @@ function materializeInstructions2(cwd2, cloud) {
|
|
|
66643
66949
|
const body = c2.files[0]?.content ?? "";
|
|
66644
66950
|
if (!body.trim())
|
|
66645
66951
|
continue;
|
|
66646
|
-
const target =
|
|
66647
|
-
ensureDir(
|
|
66648
|
-
|
|
66952
|
+
const target = path85.join(cwd2, DEFAULT_INSTRUCTIONS_FILE);
|
|
66953
|
+
ensureDir(path85.dirname(target));
|
|
66954
|
+
fs76.writeFileSync(target, normalizeInstructionBody(body), "utf8");
|
|
66649
66955
|
return;
|
|
66650
66956
|
}
|
|
66651
66957
|
}
|
|
@@ -66657,12 +66963,12 @@ function materializePlaybooks2(cwd2, cloud) {
|
|
|
66657
66963
|
if (!raw.trim())
|
|
66658
66964
|
continue;
|
|
66659
66965
|
const { body } = stripPlaybookFrontmatter(raw);
|
|
66660
|
-
const target =
|
|
66661
|
-
ensureDir(
|
|
66662
|
-
|
|
66966
|
+
const target = path85.join(cwd2, DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
|
|
66967
|
+
ensureDir(path85.dirname(target));
|
|
66968
|
+
fs76.writeFileSync(target, body, "utf8");
|
|
66663
66969
|
}
|
|
66664
66970
|
}
|
|
66665
|
-
function buildManifestFromCloud(cloud, agent) {
|
|
66971
|
+
function buildManifestFromCloud(cloud, agent, localOnly = {}) {
|
|
66666
66972
|
const skills = cloud.components.filter((c2) => c2.type === "skill").map((c2) => {
|
|
66667
66973
|
const meta = c2.meta ?? {};
|
|
66668
66974
|
if (meta.name && meta.name.includes("/")) {
|
|
@@ -66701,7 +67007,7 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66701
67007
|
title,
|
|
66702
67008
|
...description ? { description } : {},
|
|
66703
67009
|
...typeof pbMeta.icon === "string" && pbMeta.icon ? { icon: pbMeta.icon } : {},
|
|
66704
|
-
content: { file:
|
|
67010
|
+
content: { file: path85.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`) }
|
|
66705
67011
|
};
|
|
66706
67012
|
});
|
|
66707
67013
|
const caps = capabilitiesFromAgent(agent);
|
|
@@ -66715,7 +67021,8 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66715
67021
|
},
|
|
66716
67022
|
...hasInstructions ? { instructions: { file: DEFAULT_INSTRUCTIONS_FILE } } : {},
|
|
66717
67023
|
playbooks,
|
|
66718
|
-
evals: [],
|
|
67024
|
+
evals: localOnly.evals ?? [],
|
|
67025
|
+
...localOnly,
|
|
66719
67026
|
skills,
|
|
66720
67027
|
mcp,
|
|
66721
67028
|
capabilities: {
|
|
@@ -66730,7 +67037,7 @@ function buildManifestFromCloud(cloud, agent) {
|
|
|
66730
67037
|
async function pullAgentSecrets(cwd2, agentId) {
|
|
66731
67038
|
try {
|
|
66732
67039
|
const res = await api.getAgentSecrets(agentId);
|
|
66733
|
-
const secrets = res.secrets
|
|
67040
|
+
const secrets = res.secrets;
|
|
66734
67041
|
if (Object.keys(secrets).length > 0) {
|
|
66735
67042
|
writeLocalSecrets(cwd2, secrets);
|
|
66736
67043
|
}
|
|
@@ -66742,6 +67049,17 @@ async function pullAgentSecrets(cwd2, agentId) {
|
|
|
66742
67049
|
return {};
|
|
66743
67050
|
}
|
|
66744
67051
|
}
|
|
67052
|
+
function folderClaimedByOtherAgent(cwd2, agentId) {
|
|
67053
|
+
const claimedBy = readManifestAgentId(cwd2) ?? safeRead(() => readLink(cwd2)?.agent_id) ?? safeRead(() => readSyncState(cwd2)?.agent_id);
|
|
67054
|
+
return claimedBy !== undefined && claimedBy !== agentId;
|
|
67055
|
+
}
|
|
67056
|
+
function safeRead(read) {
|
|
67057
|
+
try {
|
|
67058
|
+
return read();
|
|
67059
|
+
} catch {
|
|
67060
|
+
return;
|
|
67061
|
+
}
|
|
67062
|
+
}
|
|
66745
67063
|
|
|
66746
67064
|
// src/core/orchestration-trigger-config.ts
|
|
66747
67065
|
function normalizeScheduleTriggerConfig(config) {
|
|
@@ -66851,7 +67169,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
66851
67169
|
}
|
|
66852
67170
|
}
|
|
66853
67171
|
const fallbackHarness = args.harness ?? "claude-code";
|
|
66854
|
-
|
|
67172
|
+
fs77.mkdirSync(cwd2, { recursive: true });
|
|
66855
67173
|
if (hasOrchManifest(cwd2) && existingLink && existingLink.orchestration_id !== orchId) {
|
|
66856
67174
|
f2.error(`This folder is linked to orchestration ${existingLink.orchestration_id}, not ${orchId}. Move to a fresh directory or unlink first.`);
|
|
66857
67175
|
return;
|
|
@@ -66947,7 +67265,7 @@ async function runOrchestrationPull(cwd2, args) {
|
|
|
66947
67265
|
payload_schema: e2.payload_schema ?? {}
|
|
66948
67266
|
}))
|
|
66949
67267
|
});
|
|
66950
|
-
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${
|
|
67268
|
+
$e(`Pulled ${cloud.name} at revision ${cloud.revision} into ${path86.basename(cwd2)}/ ${import_picocolors37.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
|
|
66951
67269
|
}
|
|
66952
67270
|
function handleApiError5(err) {
|
|
66953
67271
|
if (err instanceof ApiError) {
|
|
@@ -67029,6 +67347,34 @@ function buildOrchestrationGraphPayload(manifest, slugToAgentId) {
|
|
|
67029
67347
|
}
|
|
67030
67348
|
|
|
67031
67349
|
// src/cli/orchestration-push.ts
|
|
67350
|
+
function findUnpushableMembers(cwd2, members) {
|
|
67351
|
+
const blocked = [];
|
|
67352
|
+
for (const m3 of members) {
|
|
67353
|
+
const dir = memberDir(cwd2, m3.slug);
|
|
67354
|
+
if (!hasManifest(dir)) {
|
|
67355
|
+
f2.error(`${m3.slug}: no ${AGENT_MANIFEST_FILE} in this member folder.`);
|
|
67356
|
+
blocked.push(m3.slug);
|
|
67357
|
+
continue;
|
|
67358
|
+
}
|
|
67359
|
+
let memberManifest;
|
|
67360
|
+
try {
|
|
67361
|
+
memberManifest = readManifest(dir);
|
|
67362
|
+
} catch (err) {
|
|
67363
|
+
f2.error(`${m3.slug}: ${err.message}`);
|
|
67364
|
+
blocked.push(m3.slug);
|
|
67365
|
+
continue;
|
|
67366
|
+
}
|
|
67367
|
+
if (!memberManifest.id) {
|
|
67368
|
+
f2.error(`${m3.slug}: ${AGENT_MANIFEST_FILE} is unclaimed (no ${import_picocolors38.default.cyan("id")}), so there is nothing to push to.`);
|
|
67369
|
+
blocked.push(m3.slug);
|
|
67370
|
+
continue;
|
|
67371
|
+
}
|
|
67372
|
+
if (reportUnsyncedBlocks(memberManifest, { label: m3.slug })) {
|
|
67373
|
+
blocked.push(m3.slug);
|
|
67374
|
+
}
|
|
67375
|
+
}
|
|
67376
|
+
return blocked;
|
|
67377
|
+
}
|
|
67032
67378
|
async function runOrchestrationPush(cwd2, args) {
|
|
67033
67379
|
banner("orchestration push — recursively push each member, then update the graph");
|
|
67034
67380
|
const link2 = readOrchLink(cwd2);
|
|
@@ -67064,6 +67410,7 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67064
67410
|
if (missing.length) {
|
|
67065
67411
|
f2.error(`Missing local checkouts for: ${missing.join(", ")}.`);
|
|
67066
67412
|
f2.info(`Run ${import_picocolors38.default.cyan("brainbase orchestration pull")} to materialise the missing folders.`);
|
|
67413
|
+
process.exitCode = 1;
|
|
67067
67414
|
return;
|
|
67068
67415
|
}
|
|
67069
67416
|
let graph;
|
|
@@ -67074,6 +67421,14 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67074
67421
|
process.exitCode = 1;
|
|
67075
67422
|
return;
|
|
67076
67423
|
}
|
|
67424
|
+
if (!args.graphOnly) {
|
|
67425
|
+
const blockedMembers = findUnpushableMembers(cwd2, manifest.members);
|
|
67426
|
+
if (blockedMembers.length > 0) {
|
|
67427
|
+
f2.error(`Aborted — ${blockedMembers.join(", ")} cannot be pushed, so no member was pushed and the graph is unchanged.`);
|
|
67428
|
+
process.exitCode = 1;
|
|
67429
|
+
return;
|
|
67430
|
+
}
|
|
67431
|
+
}
|
|
67077
67432
|
const plan = [""];
|
|
67078
67433
|
plan.push(` ${import_picocolors38.default.bold(link2.name)} ${import_picocolors38.default.dim(`(${link2.orchestration_id})`)}`);
|
|
67079
67434
|
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"}`)}`);
|
|
@@ -67102,6 +67457,7 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67102
67457
|
const dir = memberDir(cwd2, m3.slug);
|
|
67103
67458
|
console.log("");
|
|
67104
67459
|
console.log(`${import_picocolors38.default.dim("───")} ${import_picocolors38.default.bold(m3.slug)} ${import_picocolors38.default.dim("───")}`);
|
|
67460
|
+
const exitCodeBeforePush = process.exitCode;
|
|
67105
67461
|
try {
|
|
67106
67462
|
await runAgentPush(dir, { yes: true });
|
|
67107
67463
|
} catch (err) {
|
|
@@ -67109,6 +67465,11 @@ async function runOrchestrationPush(cwd2, args) {
|
|
|
67109
67465
|
process.exitCode = 1;
|
|
67110
67466
|
return;
|
|
67111
67467
|
}
|
|
67468
|
+
if (process.exitCode !== exitCodeBeforePush) {
|
|
67469
|
+
f2.error(`Aborted — ${m3.slug} was not pushed, so the graph is left unchanged.`);
|
|
67470
|
+
process.exitCode = 1;
|
|
67471
|
+
return;
|
|
67472
|
+
}
|
|
67112
67473
|
}
|
|
67113
67474
|
}
|
|
67114
67475
|
const sp = de();
|
|
@@ -67374,7 +67735,7 @@ async function runOrchestrationList(args) {
|
|
|
67374
67735
|
}
|
|
67375
67736
|
|
|
67376
67737
|
// src/cli/orchestration-add-agent.ts
|
|
67377
|
-
import
|
|
67738
|
+
import fs78 from "node:fs";
|
|
67378
67739
|
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
67379
67740
|
|
|
67380
67741
|
// src/core/orchestration-add.ts
|
|
@@ -67460,10 +67821,10 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67460
67821
|
})).trim();
|
|
67461
67822
|
}
|
|
67462
67823
|
let slug = slugifyMemberName(name);
|
|
67463
|
-
if (manifest.members.some((m3) => m3.slug === slug) ||
|
|
67824
|
+
if (manifest.members.some((m3) => m3.slug === slug) || fs78.existsSync(memberDir(cwd2, slug))) {
|
|
67464
67825
|
let n = 2;
|
|
67465
67826
|
let candidate = `${slug}-${n}`;
|
|
67466
|
-
while (manifest.members.some((m3) => m3.slug === candidate) ||
|
|
67827
|
+
while (manifest.members.some((m3) => m3.slug === candidate) || fs78.existsSync(memberDir(cwd2, candidate))) {
|
|
67467
67828
|
candidate = `${slug}-${++n}`;
|
|
67468
67829
|
}
|
|
67469
67830
|
f2.info(`Slug ${import_picocolors41.default.bold(slug)} is taken — using ${import_picocolors41.default.bold(candidate)}.`);
|
|
@@ -67535,7 +67896,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67535
67896
|
}
|
|
67536
67897
|
const dest = memberDir(cwd2, slug);
|
|
67537
67898
|
try {
|
|
67538
|
-
|
|
67899
|
+
fs78.mkdirSync(dest, { recursive: true });
|
|
67539
67900
|
await runAgentCreate(dest, {
|
|
67540
67901
|
name,
|
|
67541
67902
|
orgId,
|
|
@@ -67546,7 +67907,7 @@ async function runOrchestrationAddAgent(cwd2, args) {
|
|
|
67546
67907
|
});
|
|
67547
67908
|
} catch (err) {
|
|
67548
67909
|
try {
|
|
67549
|
-
|
|
67910
|
+
fs78.rmSync(dest, { recursive: true, force: true });
|
|
67550
67911
|
} catch {}
|
|
67551
67912
|
f2.error(`Failed to create ${slug}: ${err.message}`);
|
|
67552
67913
|
return;
|
|
@@ -68234,10 +68595,13 @@ function TokenListCard(props) {
|
|
|
68234
68595
|
]
|
|
68235
68596
|
}, undefined, true, undefined, this);
|
|
68236
68597
|
}
|
|
68598
|
+
const liveCount = props.active.filter((t) => !t.expired).length;
|
|
68599
|
+
const expiredCount = props.active.length - liveCount;
|
|
68600
|
+
const subtitle = expiredCount ? `${liveCount} active, ${expiredCount} expired` : `${liveCount} active`;
|
|
68237
68601
|
return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Card, {
|
|
68238
68602
|
title: "TOKENS",
|
|
68239
68603
|
tone: "info",
|
|
68240
|
-
subtitle
|
|
68604
|
+
subtitle,
|
|
68241
68605
|
children: [
|
|
68242
68606
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68243
68607
|
flexDirection: "column",
|
|
@@ -68249,8 +68613,17 @@ function TokenListCard(props) {
|
|
|
68249
68613
|
children: [
|
|
68250
68614
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68251
68615
|
bold: true,
|
|
68616
|
+
dimColor: t.expired,
|
|
68252
68617
|
children: t.name
|
|
68253
68618
|
}, undefined, false, undefined, this),
|
|
68619
|
+
t.expired && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68620
|
+
marginLeft: 1,
|
|
68621
|
+
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Badge, {
|
|
68622
|
+
tone: "warn",
|
|
68623
|
+
outline: true,
|
|
68624
|
+
children: "expired"
|
|
68625
|
+
}, undefined, false, undefined, this)
|
|
68626
|
+
}, undefined, false, undefined, this),
|
|
68254
68627
|
t.isThisCli && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68255
68628
|
marginLeft: 1,
|
|
68256
68629
|
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Badge, {
|
|
@@ -68335,11 +68708,18 @@ function TokenListCard(props) {
|
|
|
68335
68708
|
}, undefined, true, undefined, this),
|
|
68336
68709
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
68337
68710
|
marginTop: 1,
|
|
68338
|
-
|
|
68339
|
-
|
|
68340
|
-
|
|
68341
|
-
|
|
68342
|
-
|
|
68711
|
+
flexDirection: "column",
|
|
68712
|
+
children: [
|
|
68713
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68714
|
+
dimColor: true,
|
|
68715
|
+
children: "› brainbase token rename <id> --name <label>"
|
|
68716
|
+
}, undefined, false, undefined, this),
|
|
68717
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
|
|
68718
|
+
dimColor: true,
|
|
68719
|
+
children: "› brainbase token revoke <id>"
|
|
68720
|
+
}, undefined, false, undefined, this)
|
|
68721
|
+
]
|
|
68722
|
+
}, undefined, true, undefined, this)
|
|
68343
68723
|
]
|
|
68344
68724
|
}, undefined, true, undefined, this);
|
|
68345
68725
|
}
|
|
@@ -68351,6 +68731,20 @@ async function showTokenListCard(props) {
|
|
|
68351
68731
|
|
|
68352
68732
|
// src/cli/token.ts
|
|
68353
68733
|
var DEFAULT_SCOPES = ["read", "publish"];
|
|
68734
|
+
var MAX_NAME_LENGTH = 128;
|
|
68735
|
+
var ALLOWED_SCOPES = ["read", "publish", "admin"];
|
|
68736
|
+
function isAllowedScope(value) {
|
|
68737
|
+
return ALLOWED_SCOPES.includes(value);
|
|
68738
|
+
}
|
|
68739
|
+
function isExpired2(token) {
|
|
68740
|
+
return Boolean(token.expires_at && Date.parse(token.expires_at) <= Date.now());
|
|
68741
|
+
}
|
|
68742
|
+
function withLoginHint(error) {
|
|
68743
|
+
if (error instanceof ApiError && error.status === 403) {
|
|
68744
|
+
return new Error("Managing tokens needs a logged-in session; a PAT (BRAINBASE_TOKEN) cannot. " + "Run `brainbase login` and try again.");
|
|
68745
|
+
}
|
|
68746
|
+
return error;
|
|
68747
|
+
}
|
|
68354
68748
|
async function runTokenCreate(args) {
|
|
68355
68749
|
banner("token create — make a long-lived CLI key");
|
|
68356
68750
|
let name = args.name;
|
|
@@ -68362,7 +68756,14 @@ async function runTokenCreate(args) {
|
|
|
68362
68756
|
flagHint: "Pass --name <label>."
|
|
68363
68757
|
});
|
|
68364
68758
|
}
|
|
68365
|
-
|
|
68759
|
+
let scopes;
|
|
68760
|
+
if (args.scopes === undefined) {
|
|
68761
|
+
scopes = DEFAULT_SCOPES;
|
|
68762
|
+
} else if (args.scopes.length === 0) {
|
|
68763
|
+
throw new Error("Usage: brainbase token create --scopes <list> (allowed: read, publish, admin)");
|
|
68764
|
+
} else {
|
|
68765
|
+
scopes = args.scopes;
|
|
68766
|
+
}
|
|
68366
68767
|
const spinner = de();
|
|
68367
68768
|
spinner.start("Creating token…");
|
|
68368
68769
|
const created = await registryApi.createCliToken({
|
|
@@ -68370,7 +68771,15 @@ async function runTokenCreate(args) {
|
|
|
68370
68771
|
scopes
|
|
68371
68772
|
});
|
|
68372
68773
|
spinner.stop("Token created.");
|
|
68373
|
-
|
|
68774
|
+
try {
|
|
68775
|
+
writeToken(created.token, name);
|
|
68776
|
+
} catch (error) {
|
|
68777
|
+
throw new Error(`Created token ${created.id}, but could not save it locally: ${error.message}
|
|
68778
|
+
` + `This is the only time it is shown — copy it now:
|
|
68779
|
+
|
|
68780
|
+
${created.token}
|
|
68781
|
+
`);
|
|
68782
|
+
}
|
|
68374
68783
|
await showTokenCreatedCard({
|
|
68375
68784
|
token: created.token,
|
|
68376
68785
|
id: created.id,
|
|
@@ -68392,30 +68801,151 @@ async function runTokenList() {
|
|
|
68392
68801
|
prefix: t.prefix,
|
|
68393
68802
|
scopes: t.scopes,
|
|
68394
68803
|
lastUsed: t.last_used_at ?? null,
|
|
68395
|
-
isThisCli: !!(local && local.token.startsWith(t.prefix))
|
|
68804
|
+
isThisCli: !!(local && local.token.startsWith(t.prefix)),
|
|
68805
|
+
expired: isExpired2(t)
|
|
68396
68806
|
})),
|
|
68397
68807
|
revokedCount: revoked.length
|
|
68398
68808
|
});
|
|
68399
68809
|
}
|
|
68810
|
+
async function runTokenRename(args) {
|
|
68811
|
+
if (!args.id) {
|
|
68812
|
+
throw new Error("Usage: brainbase token rename <id> --name <label>");
|
|
68813
|
+
}
|
|
68814
|
+
banner("token rename — relabel a CLI key");
|
|
68815
|
+
let tokens;
|
|
68816
|
+
try {
|
|
68817
|
+
tokens = await registryApi.listCliTokens();
|
|
68818
|
+
} catch (error) {
|
|
68819
|
+
throw withLoginHint(error);
|
|
68820
|
+
}
|
|
68821
|
+
const target = tokens.find((t) => t.id === args.id);
|
|
68822
|
+
if (!target) {
|
|
68823
|
+
throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
|
|
68824
|
+
}
|
|
68825
|
+
if (target.revoked_at) {
|
|
68826
|
+
throw new Error(`Token ${args.id} is revoked, and revoked tokens cannot be renamed.`);
|
|
68827
|
+
}
|
|
68828
|
+
if (isExpired2(target)) {
|
|
68829
|
+
throw new Error(`Token ${args.id} expired on ${target.expires_at}, and expired tokens cannot be renamed.`);
|
|
68830
|
+
}
|
|
68831
|
+
const takenBy = new Map;
|
|
68832
|
+
for (const t of tokens) {
|
|
68833
|
+
if (t.revoked_at || isExpired2(t) || t.id === target.id)
|
|
68834
|
+
continue;
|
|
68835
|
+
takenBy.set(t.name.trim().toLowerCase(), t);
|
|
68836
|
+
}
|
|
68837
|
+
const validate2 = (value) => {
|
|
68838
|
+
const candidate = value.trim();
|
|
68839
|
+
if (!candidate)
|
|
68840
|
+
return "Required.";
|
|
68841
|
+
if (candidate.length > MAX_NAME_LENGTH) {
|
|
68842
|
+
return `Too long — keep the label to ${MAX_NAME_LENGTH} characters or fewer.`;
|
|
68843
|
+
}
|
|
68844
|
+
const clash = takenBy.get(candidate.toLowerCase());
|
|
68845
|
+
if (clash) {
|
|
68846
|
+
return `Token ${clash.id} already uses the label "${clash.name}". Labels are how \`token list\` tells keys apart, so pick a different one.`;
|
|
68847
|
+
}
|
|
68848
|
+
return;
|
|
68849
|
+
};
|
|
68850
|
+
let name;
|
|
68851
|
+
if (!args.name) {
|
|
68852
|
+
const answer = await text({
|
|
68853
|
+
message: "New label",
|
|
68854
|
+
placeholder: target.name,
|
|
68855
|
+
validate: validate2,
|
|
68856
|
+
flagHint: "Pass --name <label>."
|
|
68857
|
+
});
|
|
68858
|
+
name = answer.trim();
|
|
68859
|
+
} else {
|
|
68860
|
+
name = args.name.trim();
|
|
68861
|
+
const problem = validate2(name);
|
|
68862
|
+
if (problem) {
|
|
68863
|
+
throw new Error(name ? problem : "--name cannot be blank.");
|
|
68864
|
+
}
|
|
68865
|
+
}
|
|
68866
|
+
if (name === target.name.trim()) {
|
|
68867
|
+
console.log(`${sym.ok} ${import_picocolors45.default.bold(target.name.trim())} already has that label; nothing to do.`);
|
|
68868
|
+
return;
|
|
68869
|
+
}
|
|
68870
|
+
try {
|
|
68871
|
+
await registryApi.renameCliToken(target.id, name);
|
|
68872
|
+
} catch (error) {
|
|
68873
|
+
throw withLoginHint(error);
|
|
68874
|
+
}
|
|
68875
|
+
console.log(`${sym.ok} Renamed ${import_picocolors45.default.dim(target.name)} → ${import_picocolors45.default.bold(name)}`);
|
|
68876
|
+
}
|
|
68400
68877
|
async function runTokenRevoke(args) {
|
|
68401
68878
|
if (!args.id) {
|
|
68402
68879
|
console.error("Usage: brainbase token revoke <id>");
|
|
68403
68880
|
process.exit(1);
|
|
68404
68881
|
}
|
|
68882
|
+
let tokens;
|
|
68883
|
+
try {
|
|
68884
|
+
tokens = await registryApi.listCliTokens();
|
|
68885
|
+
} catch (error) {
|
|
68886
|
+
throw withLoginHint(error);
|
|
68887
|
+
}
|
|
68888
|
+
const target = tokens.find((t) => t.id === args.id);
|
|
68889
|
+
if (!target) {
|
|
68890
|
+
throw new Error(`No token with id ${args.id}. Run \`brainbase token list\` to see yours.`);
|
|
68891
|
+
}
|
|
68892
|
+
if (target.revoked_at) {
|
|
68893
|
+
reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} is already revoked.`);
|
|
68894
|
+
return;
|
|
68895
|
+
}
|
|
68896
|
+
const stored = readToken();
|
|
68897
|
+
const isLocalToken = Boolean(stored && stored.token.startsWith(target.prefix));
|
|
68405
68898
|
if (!autoProceed(args.yes)) {
|
|
68406
68899
|
const ok = await se({
|
|
68407
|
-
message: `Revoke token ${import_picocolors45.default.bold(args.id)
|
|
68900
|
+
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.`,
|
|
68408
68901
|
initialValue: false
|
|
68409
68902
|
});
|
|
68410
68903
|
if (!ensureNotCancelled(ok))
|
|
68411
68904
|
return;
|
|
68412
68905
|
}
|
|
68413
|
-
|
|
68414
|
-
|
|
68415
|
-
|
|
68416
|
-
|
|
68906
|
+
try {
|
|
68907
|
+
await registryApi.revokeCliToken(args.id);
|
|
68908
|
+
} catch (error) {
|
|
68909
|
+
if (error instanceof ApiError && error.status === 404) {
|
|
68910
|
+
if (isExpired2(target)) {
|
|
68911
|
+
reconcileDeadToken(target, `${import_picocolors45.default.bold(target.name)} had already expired.`);
|
|
68912
|
+
return;
|
|
68913
|
+
}
|
|
68914
|
+
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.");
|
|
68915
|
+
}
|
|
68916
|
+
throw error;
|
|
68917
|
+
}
|
|
68918
|
+
reconcileDeadToken(target, `Revoked ${import_picocolors45.default.bold(target.name)}.`);
|
|
68919
|
+
}
|
|
68920
|
+
function reconcileDeadToken(target, headline) {
|
|
68921
|
+
let outcome;
|
|
68922
|
+
try {
|
|
68923
|
+
outcome = clearTokenIfMatches(target.prefix);
|
|
68924
|
+
} catch (error) {
|
|
68925
|
+
throw new Error(`${headline} That key is dead server-side, but the local token could not be ` + `cleared: ${error.message}
|
|
68926
|
+
` + "Run `brainbase token clear` to remove it.");
|
|
68927
|
+
}
|
|
68928
|
+
reportLocalToken(headline, outcome);
|
|
68929
|
+
}
|
|
68930
|
+
function reportLocalToken(headline, outcome) {
|
|
68931
|
+
switch (outcome) {
|
|
68932
|
+
case "cleared":
|
|
68933
|
+
console.log(`${sym.ok} ${headline} Cleared the local token too.`);
|
|
68934
|
+
return;
|
|
68935
|
+
case "kept":
|
|
68936
|
+
console.log(`${sym.ok} ${headline} The local token is a different key and is untouched.`);
|
|
68937
|
+
return;
|
|
68938
|
+
case "absent":
|
|
68939
|
+
console.log(`${sym.ok} ${headline}`);
|
|
68940
|
+
return;
|
|
68941
|
+
case "unverifiable":
|
|
68942
|
+
console.log(`${sym.ok} ${headline} Left the local token alone.`);
|
|
68943
|
+
return;
|
|
68944
|
+
default: {
|
|
68945
|
+
const exhaustive = outcome;
|
|
68946
|
+
throw new Error(`unhandled outcome: ${String(exhaustive)}`);
|
|
68947
|
+
}
|
|
68417
68948
|
}
|
|
68418
|
-
console.log(`${sym.ok} Revoked.`);
|
|
68419
68949
|
}
|
|
68420
68950
|
async function runTokenClear() {
|
|
68421
68951
|
if (!readToken()) {
|
|
@@ -68425,30 +68955,79 @@ async function runTokenClear() {
|
|
|
68425
68955
|
clearToken();
|
|
68426
68956
|
console.log(`${sym.ok} Cleared local token. (Server-side token still active until revoked.)`);
|
|
68427
68957
|
}
|
|
68958
|
+
var TOKEN_VALUE_FLAGS = new Set(["--name", "-n", "--scope", "--scopes"]);
|
|
68959
|
+
function isValueOfPriorFlag(rest2, index) {
|
|
68960
|
+
return index > 0 && TOKEN_VALUE_FLAGS.has(rest2[index - 1]);
|
|
68961
|
+
}
|
|
68428
68962
|
function pickFlag(rest2, ...names) {
|
|
68429
68963
|
for (const n of names) {
|
|
68430
|
-
const
|
|
68431
|
-
|
|
68432
|
-
|
|
68964
|
+
const prefix = `${n}=`;
|
|
68965
|
+
for (let i = 0;i < rest2.length; i++) {
|
|
68966
|
+
if (isValueOfPriorFlag(rest2, i))
|
|
68967
|
+
continue;
|
|
68968
|
+
const a3 = rest2[i];
|
|
68969
|
+
if (a3 === n) {
|
|
68970
|
+
const v3 = rest2[i + 1];
|
|
68971
|
+
if (v3 === undefined)
|
|
68972
|
+
return "";
|
|
68973
|
+
const label = n === "--name" || n === "-n";
|
|
68974
|
+
if (!label && v3.startsWith("-"))
|
|
68975
|
+
return "";
|
|
68976
|
+
return v3;
|
|
68977
|
+
}
|
|
68978
|
+
if (a3.startsWith(prefix))
|
|
68979
|
+
return a3.slice(prefix.length);
|
|
68980
|
+
}
|
|
68981
|
+
}
|
|
68982
|
+
return;
|
|
68983
|
+
}
|
|
68984
|
+
function firstPositional(rest2, ...valueFlags) {
|
|
68985
|
+
const consumesValue = new Set(valueFlags);
|
|
68986
|
+
for (let i = 0;i < rest2.length; i++) {
|
|
68987
|
+
const arg = rest2[i];
|
|
68988
|
+
if (consumesValue.has(arg)) {
|
|
68989
|
+
i++;
|
|
68990
|
+
continue;
|
|
68991
|
+
}
|
|
68992
|
+
if (arg.startsWith("-"))
|
|
68993
|
+
continue;
|
|
68994
|
+
return arg;
|
|
68433
68995
|
}
|
|
68434
68996
|
return;
|
|
68435
68997
|
}
|
|
68436
68998
|
function parseScopes(raw) {
|
|
68437
|
-
if (
|
|
68999
|
+
if (raw === undefined)
|
|
68438
69000
|
return;
|
|
68439
|
-
|
|
69001
|
+
const scopes = raw.split(",").map((s3) => s3.trim().toLowerCase()).filter((s3) => s3.length > 0);
|
|
69002
|
+
if (scopes.length === 0) {
|
|
69003
|
+
throw new Error("Usage: brainbase token create --scopes <list> (allowed: read, publish, admin)");
|
|
69004
|
+
}
|
|
69005
|
+
const unknown = scopes.filter((s3) => !isAllowedScope(s3));
|
|
69006
|
+
if (unknown.length > 0) {
|
|
69007
|
+
throw new Error(`Unknown scope${unknown.length === 1 ? "" : "s"} ${unknown.join(", ")} — allowed: read, publish, admin`);
|
|
69008
|
+
}
|
|
69009
|
+
return scopes;
|
|
68440
69010
|
}
|
|
68441
69011
|
async function runToken(sub, rest2, args) {
|
|
69012
|
+
const nameFlag = args.name || pickFlag(rest2, "--name", "-n");
|
|
68442
69013
|
switch (sub) {
|
|
68443
69014
|
case "create":
|
|
68444
69015
|
case "new": {
|
|
68445
|
-
const name = pickFlag(rest2, "--name", "-n");
|
|
68446
69016
|
const scopes = parseScopes(pickFlag(rest2, "--scope", "--scopes"));
|
|
68447
|
-
return runTokenCreate({ name, scopes });
|
|
69017
|
+
return runTokenCreate({ name: nameFlag, scopes });
|
|
68448
69018
|
}
|
|
68449
69019
|
case "list":
|
|
68450
69020
|
case "ls":
|
|
68451
69021
|
return runTokenList();
|
|
69022
|
+
case "rename": {
|
|
69023
|
+
if (pickFlag(rest2, "--scope", "--scopes") !== undefined) {
|
|
69024
|
+
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>`.");
|
|
69025
|
+
}
|
|
69026
|
+
return runTokenRename({
|
|
69027
|
+
id: firstPositional(rest2, "--name", "-n") ?? "",
|
|
69028
|
+
name: nameFlag
|
|
69029
|
+
});
|
|
69030
|
+
}
|
|
68452
69031
|
case "revoke":
|
|
68453
69032
|
case "rm":
|
|
68454
69033
|
return runTokenRevoke({ id: rest2[0] ?? "", yes: args.yes });
|
|
@@ -68473,7 +69052,8 @@ function printTokenHelp() {
|
|
|
68473
69052
|
out.push(` ${import_picocolors45.default.bold("brainbase token")} ${import_picocolors45.default.dim("<command>")}`);
|
|
68474
69053
|
out.push("");
|
|
68475
69054
|
out.push(` ${import_picocolors45.default.cyan("create")} ${import_picocolors45.default.dim("issue a new long-lived CLI key (PAT)")}`);
|
|
68476
|
-
out.push(` ${import_picocolors45.default.cyan("list")} ${import_picocolors45.default.dim("show your
|
|
69055
|
+
out.push(` ${import_picocolors45.default.cyan("list")} ${import_picocolors45.default.dim("show your tokens")}`);
|
|
69056
|
+
out.push(` ${import_picocolors45.default.cyan("rename")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("relabel a token by id")}`);
|
|
68477
69057
|
out.push(` ${import_picocolors45.default.cyan("revoke")} ${import_picocolors45.default.dim("<id>")} ${import_picocolors45.default.dim("revoke a token by id")}`);
|
|
68478
69058
|
out.push(` ${import_picocolors45.default.cyan("clear")} ${import_picocolors45.default.dim("forget the local token (does not revoke)")}`);
|
|
68479
69059
|
out.push("");
|
|
@@ -68482,6 +69062,9 @@ function printTokenHelp() {
|
|
|
68482
69062
|
out.push(` ${import_picocolors45.default.cyan("--scopes")} ${import_picocolors45.default.dim("<list>")} ${import_picocolors45.default.dim("comma-separated; allowed: read, publish, admin")}`);
|
|
68483
69063
|
out.push(` ${import_picocolors45.default.dim("default: read,publish")}`);
|
|
68484
69064
|
out.push("");
|
|
69065
|
+
out.push(` ${import_picocolors45.default.bold("rename flags")}`);
|
|
69066
|
+
out.push(` ${import_picocolors45.default.cyan("--name, -n")} ${import_picocolors45.default.dim("<label>")} ${import_picocolors45.default.dim("new label (prompted if omitted)")}`);
|
|
69067
|
+
out.push("");
|
|
68485
69068
|
console.log(out.join(`
|
|
68486
69069
|
`));
|
|
68487
69070
|
}
|
|
@@ -68490,8 +69073,8 @@ function printTokenHelp() {
|
|
|
68490
69073
|
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
68491
69074
|
|
|
68492
69075
|
// src/core/mcp-check/collect-servers.ts
|
|
68493
|
-
import
|
|
68494
|
-
import
|
|
69076
|
+
import path87 from "node:path";
|
|
69077
|
+
import fs79 from "node:fs";
|
|
68495
69078
|
function collectServers(cwd2, env3 = process.env) {
|
|
68496
69079
|
const out = [];
|
|
68497
69080
|
const seen = new Set;
|
|
@@ -68542,10 +69125,10 @@ function pushResolved(out, seen, name, entry, env3) {
|
|
|
68542
69125
|
out.push({ name, url: finalUrl, headers });
|
|
68543
69126
|
}
|
|
68544
69127
|
function* readResolvedMcps(cwd2) {
|
|
68545
|
-
const p2 =
|
|
69128
|
+
const p2 = path87.join(cwd2, ".brainbase", "resolved-mcps.json");
|
|
68546
69129
|
let raw;
|
|
68547
69130
|
try {
|
|
68548
|
-
raw =
|
|
69131
|
+
raw = fs79.readFileSync(p2, "utf-8");
|
|
68549
69132
|
} catch {
|
|
68550
69133
|
return;
|
|
68551
69134
|
}
|
|
@@ -68569,12 +69152,12 @@ function* readResolvedMcps(cwd2) {
|
|
|
68569
69152
|
}
|
|
68570
69153
|
}
|
|
68571
69154
|
function readClaudeCode(cwd2) {
|
|
68572
|
-
const file =
|
|
69155
|
+
const file = path87.join(cwd2, ".mcp.json");
|
|
68573
69156
|
const map2 = listMcpServersFromMcpJson(file);
|
|
68574
69157
|
return Object.entries(map2);
|
|
68575
69158
|
}
|
|
68576
69159
|
function readCodex(cwd2) {
|
|
68577
|
-
const file =
|
|
69160
|
+
const file = path87.join(cwd2, ".codex", "config.toml");
|
|
68578
69161
|
try {
|
|
68579
69162
|
return Object.entries(listMcpServers2(file));
|
|
68580
69163
|
} catch {
|
|
@@ -68582,7 +69165,7 @@ function readCodex(cwd2) {
|
|
|
68582
69165
|
}
|
|
68583
69166
|
}
|
|
68584
69167
|
function readKafka(cwd2) {
|
|
68585
|
-
const file =
|
|
69168
|
+
const file = path87.join(cwd2, ".kafka", "kafka.json");
|
|
68586
69169
|
try {
|
|
68587
69170
|
return Object.entries(listMcpServers3(file));
|
|
68588
69171
|
} catch {
|
|
@@ -68861,10 +69444,10 @@ function assignProp(target, prop, value) {
|
|
|
68861
69444
|
configurable: true
|
|
68862
69445
|
});
|
|
68863
69446
|
}
|
|
68864
|
-
function getElementAtPath(obj,
|
|
68865
|
-
if (!
|
|
69447
|
+
function getElementAtPath(obj, path88) {
|
|
69448
|
+
if (!path88)
|
|
68866
69449
|
return obj;
|
|
68867
|
-
return
|
|
69450
|
+
return path88.reduce((acc, key2) => acc?.[key2], obj);
|
|
68868
69451
|
}
|
|
68869
69452
|
function promiseAllObject(promisesObj) {
|
|
68870
69453
|
const keys2 = Object.keys(promisesObj);
|
|
@@ -69180,11 +69763,11 @@ function aborted(x3, startIndex = 0) {
|
|
|
69180
69763
|
}
|
|
69181
69764
|
return false;
|
|
69182
69765
|
}
|
|
69183
|
-
function prefixIssues(
|
|
69766
|
+
function prefixIssues(path88, issues) {
|
|
69184
69767
|
return issues.map((iss) => {
|
|
69185
69768
|
var _a;
|
|
69186
69769
|
(_a = iss).path ?? (_a.path = []);
|
|
69187
|
-
iss.path.unshift(
|
|
69770
|
+
iss.path.unshift(path88);
|
|
69188
69771
|
return iss;
|
|
69189
69772
|
});
|
|
69190
69773
|
}
|
|
@@ -77078,9 +77661,9 @@ import {
|
|
|
77078
77661
|
spawn as spawn5
|
|
77079
77662
|
} from "node:child_process";
|
|
77080
77663
|
import crypto7 from "node:crypto";
|
|
77081
|
-
import
|
|
77664
|
+
import fs81 from "node:fs";
|
|
77082
77665
|
import os17 from "node:os";
|
|
77083
|
-
import
|
|
77666
|
+
import path89 from "node:path";
|
|
77084
77667
|
|
|
77085
77668
|
// src/core/benchmark-phase.ts
|
|
77086
77669
|
import {
|
|
@@ -77088,9 +77671,9 @@ import {
|
|
|
77088
77671
|
spawn as spawn4
|
|
77089
77672
|
} from "node:child_process";
|
|
77090
77673
|
import crypto6 from "node:crypto";
|
|
77091
|
-
import
|
|
77674
|
+
import fs80 from "node:fs";
|
|
77092
77675
|
import os16 from "node:os";
|
|
77093
|
-
import
|
|
77676
|
+
import path88 from "node:path";
|
|
77094
77677
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
77095
77678
|
var SCHEMA_VERSION = "1";
|
|
77096
77679
|
var SHA256_RE = /^[a-f0-9]{64}$/i;
|
|
@@ -77115,7 +77698,7 @@ var BASE_ENV_NAMES = [
|
|
|
77115
77698
|
"USER"
|
|
77116
77699
|
];
|
|
77117
77700
|
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;
|
|
77118
|
-
var AbsolutePathSchema = exports_external.string().min(1).refine(
|
|
77701
|
+
var AbsolutePathSchema = exports_external.string().min(1).refine(path88.isAbsolute, {
|
|
77119
77702
|
message: "must be an absolute path"
|
|
77120
77703
|
});
|
|
77121
77704
|
var Sha256Schema = exports_external.string().regex(SHA256_RE).transform((value) => value.toLowerCase());
|
|
@@ -77331,35 +77914,35 @@ function normalizedRootRelative(input) {
|
|
|
77331
77914
|
return safeRelPath(input);
|
|
77332
77915
|
}
|
|
77333
77916
|
function isWithin(root, candidate) {
|
|
77334
|
-
const relative =
|
|
77335
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
77917
|
+
const relative = path88.relative(path88.resolve(root), path88.resolve(candidate));
|
|
77918
|
+
return relative === "" || !relative.startsWith("..") && !path88.isAbsolute(relative);
|
|
77336
77919
|
}
|
|
77337
77920
|
function canonicalFuturePath(input) {
|
|
77338
|
-
const resolved =
|
|
77921
|
+
const resolved = path88.resolve(input);
|
|
77339
77922
|
const suffix = [];
|
|
77340
77923
|
let current = resolved;
|
|
77341
|
-
while (!
|
|
77342
|
-
const parent =
|
|
77924
|
+
while (!fs80.existsSync(current)) {
|
|
77925
|
+
const parent = path88.dirname(current);
|
|
77343
77926
|
if (parent === current)
|
|
77344
77927
|
break;
|
|
77345
|
-
suffix.unshift(
|
|
77928
|
+
suffix.unshift(path88.basename(current));
|
|
77346
77929
|
current = parent;
|
|
77347
77930
|
}
|
|
77348
|
-
const canonicalBase =
|
|
77349
|
-
return
|
|
77931
|
+
const canonicalBase = fs80.realpathSync(current);
|
|
77932
|
+
return path88.join(canonicalBase, ...suffix);
|
|
77350
77933
|
}
|
|
77351
77934
|
function validateRoots(spec) {
|
|
77352
|
-
const workspace =
|
|
77353
|
-
if (!
|
|
77935
|
+
const workspace = path88.resolve(spec.workspace_root);
|
|
77936
|
+
if (!fs80.existsSync(workspace) || fs80.lstatSync(workspace).isSymbolicLink() || !fs80.lstatSync(workspace).isDirectory()) {
|
|
77354
77937
|
throw new BenchmarkPhaseError("invalid_workspace_root", "workspace_root must be an existing real directory");
|
|
77355
77938
|
}
|
|
77356
77939
|
const canonicalWorkspace = canonicalFuturePath(workspace);
|
|
77357
|
-
const staging =
|
|
77358
|
-
const expectedStaging =
|
|
77940
|
+
const staging = path88.resolve(spec.staging_root);
|
|
77941
|
+
const expectedStaging = path88.join(workspace, ".brainbase", "benchmark", spec.attempt_id, "incoming");
|
|
77359
77942
|
if (staging !== expectedStaging) {
|
|
77360
77943
|
throw new BenchmarkPhaseError("invalid_staging_root", `staging_root must be ${expectedStaging}`);
|
|
77361
77944
|
}
|
|
77362
|
-
if (!
|
|
77945
|
+
if (!fs80.existsSync(staging) || fs80.lstatSync(staging).isSymbolicLink() || !fs80.lstatSync(staging).isDirectory() || fs80.realpathSync(staging) !== path88.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
|
|
77363
77946
|
throw new BenchmarkPhaseError("invalid_staging_root", "staging_root must be a real directory under workspace_root");
|
|
77364
77947
|
}
|
|
77365
77948
|
const canonicalLogs = validateExternalRoot("logs_root", spec.logs_root, canonicalWorkspace);
|
|
@@ -77371,11 +77954,11 @@ function validateRoots(spec) {
|
|
|
77371
77954
|
}
|
|
77372
77955
|
}
|
|
77373
77956
|
function validateExternalRoot(label, input, canonicalWorkspace) {
|
|
77374
|
-
const candidate =
|
|
77375
|
-
if (candidate ===
|
|
77957
|
+
const candidate = path88.resolve(input);
|
|
77958
|
+
if (candidate === path88.parse(candidate).root) {
|
|
77376
77959
|
throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a filesystem root`);
|
|
77377
77960
|
}
|
|
77378
|
-
if (
|
|
77961
|
+
if (fs80.existsSync(candidate) && fs80.lstatSync(candidate).isSymbolicLink()) {
|
|
77379
77962
|
throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a symlink`);
|
|
77380
77963
|
}
|
|
77381
77964
|
const canonicalCandidate = canonicalFuturePath(candidate);
|
|
@@ -77402,12 +77985,12 @@ function assertNoSymlinkTraversal(root, relative) {
|
|
|
77402
77985
|
const rel = normalizedRootRelative(relative);
|
|
77403
77986
|
if (rel === ".")
|
|
77404
77987
|
return;
|
|
77405
|
-
let current =
|
|
77988
|
+
let current = path88.resolve(root);
|
|
77406
77989
|
for (const segment of rel.split("/").slice(0, -1)) {
|
|
77407
|
-
current =
|
|
77408
|
-
if (!
|
|
77990
|
+
current = path88.join(current, segment);
|
|
77991
|
+
if (!fs80.existsSync(current))
|
|
77409
77992
|
continue;
|
|
77410
|
-
if (
|
|
77993
|
+
if (fs80.lstatSync(current).isSymbolicLink()) {
|
|
77411
77994
|
throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
|
|
77412
77995
|
}
|
|
77413
77996
|
}
|
|
@@ -77417,9 +78000,9 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
|
|
|
77417
78000
|
let canonicalFile;
|
|
77418
78001
|
let currentStat;
|
|
77419
78002
|
try {
|
|
77420
|
-
canonicalRoot =
|
|
77421
|
-
canonicalFile =
|
|
77422
|
-
currentStat =
|
|
78003
|
+
canonicalRoot = fs80.realpathSync(root);
|
|
78004
|
+
canonicalFile = fs80.realpathSync(filePath);
|
|
78005
|
+
currentStat = fs80.statSync(filePath);
|
|
77423
78006
|
} catch {
|
|
77424
78007
|
throw new BenchmarkPhaseError("unsafe_path", `${label} changed while it was opened`);
|
|
77425
78008
|
}
|
|
@@ -77428,10 +78011,10 @@ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
|
|
|
77428
78011
|
}
|
|
77429
78012
|
}
|
|
77430
78013
|
function openRegularFileNoFollow(filePath, label, root) {
|
|
77431
|
-
const noFollow = typeof
|
|
78014
|
+
const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
|
|
77432
78015
|
let fd;
|
|
77433
78016
|
try {
|
|
77434
|
-
fd =
|
|
78017
|
+
fd = fs80.openSync(filePath, fs80.constants.O_RDONLY | noFollow);
|
|
77435
78018
|
} catch (error2) {
|
|
77436
78019
|
const code = error2.code;
|
|
77437
78020
|
if (code === "ELOOP") {
|
|
@@ -77439,16 +78022,16 @@ function openRegularFileNoFollow(filePath, label, root) {
|
|
|
77439
78022
|
}
|
|
77440
78023
|
throw error2;
|
|
77441
78024
|
}
|
|
77442
|
-
const stat =
|
|
78025
|
+
const stat = fs80.fstatSync(fd);
|
|
77443
78026
|
if (!stat.isFile()) {
|
|
77444
|
-
|
|
78027
|
+
fs80.closeSync(fd);
|
|
77445
78028
|
throw new BenchmarkPhaseError("invalid_input", `${label} must be a regular file`);
|
|
77446
78029
|
}
|
|
77447
78030
|
if (root) {
|
|
77448
78031
|
try {
|
|
77449
78032
|
assertOpenedFileWithinRoot(root, filePath, stat, label);
|
|
77450
78033
|
} catch (error2) {
|
|
77451
|
-
|
|
78034
|
+
fs80.closeSync(fd);
|
|
77452
78035
|
throw error2;
|
|
77453
78036
|
}
|
|
77454
78037
|
}
|
|
@@ -77456,7 +78039,7 @@ function openRegularFileNoFollow(filePath, label, root) {
|
|
|
77456
78039
|
}
|
|
77457
78040
|
async function sha256OfDescriptor(fd) {
|
|
77458
78041
|
const hash = crypto6.createHash("sha256");
|
|
77459
|
-
const stream =
|
|
78042
|
+
const stream = fs80.createReadStream("", {
|
|
77460
78043
|
fd,
|
|
77461
78044
|
autoClose: false,
|
|
77462
78045
|
start: 0
|
|
@@ -77467,19 +78050,19 @@ async function sha256OfDescriptor(fd) {
|
|
|
77467
78050
|
return hash.digest("hex");
|
|
77468
78051
|
}
|
|
77469
78052
|
function readDescriptor(fd) {
|
|
77470
|
-
return
|
|
78053
|
+
return fs80.readFileSync(fd);
|
|
77471
78054
|
}
|
|
77472
78055
|
function assertWritableDestination(root, relative) {
|
|
77473
78056
|
const rel = normalizedRootRelative(relative);
|
|
77474
78057
|
if (rel === ".")
|
|
77475
78058
|
return;
|
|
77476
|
-
let current =
|
|
78059
|
+
let current = path88.resolve(root);
|
|
77477
78060
|
const segments = rel.split("/");
|
|
77478
78061
|
for (const segment of segments.slice(0, -1)) {
|
|
77479
|
-
current =
|
|
77480
|
-
if (!
|
|
78062
|
+
current = path88.join(current, segment);
|
|
78063
|
+
if (!fs80.existsSync(current))
|
|
77481
78064
|
continue;
|
|
77482
|
-
const stat =
|
|
78065
|
+
const stat = fs80.lstatSync(current);
|
|
77483
78066
|
if (stat.isSymbolicLink()) {
|
|
77484
78067
|
throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
|
|
77485
78068
|
}
|
|
@@ -77487,8 +78070,8 @@ function assertWritableDestination(root, relative) {
|
|
|
77487
78070
|
throw new BenchmarkPhaseError("destination_conflict", `destination parent is not a directory: ${relative}`);
|
|
77488
78071
|
}
|
|
77489
78072
|
}
|
|
77490
|
-
const destination =
|
|
77491
|
-
if (
|
|
78073
|
+
const destination = path88.resolve(root, rel);
|
|
78074
|
+
if (fs80.existsSync(destination) && fs80.lstatSync(destination).isDirectory()) {
|
|
77492
78075
|
throw new BenchmarkPhaseError("destination_conflict", `file destination is an existing directory: ${relative}`);
|
|
77493
78076
|
}
|
|
77494
78077
|
}
|
|
@@ -77513,14 +78096,14 @@ function validateDestinationGraph(paths) {
|
|
|
77513
78096
|
}
|
|
77514
78097
|
function sourcePath(stagingRoot, relative) {
|
|
77515
78098
|
const rel = safeRelPath(relative);
|
|
77516
|
-
const source =
|
|
78099
|
+
const source = path88.resolve(stagingRoot, rel);
|
|
77517
78100
|
if (!isWithin(stagingRoot, source)) {
|
|
77518
78101
|
throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${relative}`);
|
|
77519
78102
|
}
|
|
77520
78103
|
assertNoSymlinkTraversal(stagingRoot, rel);
|
|
77521
78104
|
let stat;
|
|
77522
78105
|
try {
|
|
77523
|
-
stat =
|
|
78106
|
+
stat = fs80.lstatSync(source);
|
|
77524
78107
|
} catch {
|
|
77525
78108
|
throw new BenchmarkPhaseError("missing_input", `staged input does not exist: ${relative}`);
|
|
77526
78109
|
}
|
|
@@ -77548,13 +78131,13 @@ async function verifyRecordsUnchanged(records, spec) {
|
|
|
77548
78131
|
}
|
|
77549
78132
|
const relative = safeRelPath(record3.path);
|
|
77550
78133
|
assertNoSymlinkTraversal(root, relative);
|
|
77551
|
-
const candidate =
|
|
77552
|
-
if (!isWithin(root, candidate) || !
|
|
78134
|
+
const candidate = path88.resolve(root, relative);
|
|
78135
|
+
if (!isWithin(root, candidate) || !fs80.existsSync(candidate)) {
|
|
77553
78136
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
|
|
77554
78137
|
}
|
|
77555
|
-
const stat =
|
|
78138
|
+
const stat = fs80.lstatSync(candidate);
|
|
77556
78139
|
if (record3.kind === "symlink") {
|
|
77557
|
-
const target = stat.isSymbolicLink() ?
|
|
78140
|
+
const target = stat.isSymbolicLink() ? fs80.readlinkSync(candidate) : null;
|
|
77558
78141
|
if (target === null || Buffer.byteLength(target) !== record3.size || sha256(target) !== record3.sha256) {
|
|
77559
78142
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
|
|
77560
78143
|
}
|
|
@@ -77569,7 +78152,7 @@ async function verifyRecordsUnchanged(records, spec) {
|
|
|
77569
78152
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
|
|
77570
78153
|
}
|
|
77571
78154
|
} finally {
|
|
77572
|
-
|
|
78155
|
+
fs80.closeSync(opened.fd);
|
|
77573
78156
|
}
|
|
77574
78157
|
}
|
|
77575
78158
|
}
|
|
@@ -77585,35 +78168,35 @@ async function verifyInput(stagingRoot, material) {
|
|
|
77585
78168
|
throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
|
|
77586
78169
|
}
|
|
77587
78170
|
} finally {
|
|
77588
|
-
|
|
78171
|
+
fs80.closeSync(opened.fd);
|
|
77589
78172
|
}
|
|
77590
78173
|
return source;
|
|
77591
78174
|
}
|
|
77592
78175
|
async function atomicCopy(source, destination, mode, sourceRoot) {
|
|
77593
|
-
|
|
78176
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77594
78177
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77595
78178
|
const opened = openRegularFileNoFollow(source, `copy source ${source}`, sourceRoot);
|
|
77596
78179
|
try {
|
|
77597
|
-
await pipeline2(
|
|
78180
|
+
await pipeline2(fs80.createReadStream("", {
|
|
77598
78181
|
fd: opened.fd,
|
|
77599
78182
|
autoClose: false,
|
|
77600
78183
|
start: 0
|
|
77601
|
-
}),
|
|
78184
|
+
}), fs80.createWriteStream(temporary, {
|
|
77602
78185
|
flags: "wx",
|
|
77603
78186
|
mode: 384
|
|
77604
78187
|
}));
|
|
77605
|
-
|
|
77606
|
-
|
|
78188
|
+
fs80.chmodSync(temporary, mode ?? opened.stat.mode & 511);
|
|
78189
|
+
fs80.renameSync(temporary, destination);
|
|
77607
78190
|
} finally {
|
|
77608
|
-
|
|
77609
|
-
|
|
78191
|
+
fs80.closeSync(opened.fd);
|
|
78192
|
+
fs80.rmSync(temporary, { force: true });
|
|
77610
78193
|
}
|
|
77611
78194
|
}
|
|
77612
78195
|
async function recordFile(root, filePath, rootName, kind = "file") {
|
|
77613
|
-
const relative =
|
|
78196
|
+
const relative = path88.relative(root, filePath).replace(/\\/g, "/");
|
|
77614
78197
|
if (kind === "symlink") {
|
|
77615
|
-
const stat =
|
|
77616
|
-
const target =
|
|
78198
|
+
const stat = fs80.lstatSync(filePath);
|
|
78199
|
+
const target = fs80.readlinkSync(filePath);
|
|
77617
78200
|
return {
|
|
77618
78201
|
root: rootName,
|
|
77619
78202
|
path: relative,
|
|
@@ -77633,7 +78216,7 @@ async function recordFile(root, filePath, rootName, kind = "file") {
|
|
|
77633
78216
|
mode: opened.stat.mode & 511
|
|
77634
78217
|
};
|
|
77635
78218
|
} finally {
|
|
77636
|
-
|
|
78219
|
+
fs80.closeSync(opened.fd);
|
|
77637
78220
|
}
|
|
77638
78221
|
}
|
|
77639
78222
|
async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
|
|
@@ -77647,7 +78230,7 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77647
78230
|
throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
|
|
77648
78231
|
}
|
|
77649
78232
|
assertWritableDestination(destinationRoot, destinationRel);
|
|
77650
|
-
const destination =
|
|
78233
|
+
const destination = path88.resolve(destinationRoot, destinationRel);
|
|
77651
78234
|
await atomicCopy(source, destination, material.mode, sourceRoot);
|
|
77652
78235
|
const record3 = await recordFile(destinationRoot, destination, destinationRootName);
|
|
77653
78236
|
if (record3.sha256 !== material.sha256 || record3.size !== material.size_bytes) {
|
|
@@ -77655,15 +78238,15 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77655
78238
|
}
|
|
77656
78239
|
return [record3];
|
|
77657
78240
|
}
|
|
77658
|
-
const temporary =
|
|
78241
|
+
const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-"));
|
|
77659
78242
|
try {
|
|
77660
|
-
const verifiedArchive =
|
|
78243
|
+
const verifiedArchive = path88.join(temporary, "material.tar.gz");
|
|
77661
78244
|
await atomicCopy(source, verifiedArchive, 384, sourceRoot);
|
|
77662
78245
|
const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
|
|
77663
78246
|
if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
|
|
77664
78247
|
throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
|
|
77665
78248
|
}
|
|
77666
|
-
const extractedRoot =
|
|
78249
|
+
const extractedRoot = path88.join(temporary, "extracted");
|
|
77667
78250
|
const extracted = await extract({
|
|
77668
78251
|
tarFile: verifiedArchive,
|
|
77669
78252
|
outDir: extractedRoot,
|
|
@@ -77672,23 +78255,23 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
|
|
|
77672
78255
|
});
|
|
77673
78256
|
const outputs = [];
|
|
77674
78257
|
for (const extractedRel of extracted.sort()) {
|
|
77675
|
-
const sourceFile =
|
|
77676
|
-
const stat =
|
|
78258
|
+
const sourceFile = path88.resolve(extractedRoot, safeRelPath(extractedRel));
|
|
78259
|
+
const stat = fs80.lstatSync(sourceFile);
|
|
77677
78260
|
if (!stat.isFile())
|
|
77678
78261
|
continue;
|
|
77679
|
-
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(
|
|
78262
|
+
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path88.posix.join(destinationRel, extractedRel));
|
|
77680
78263
|
const checked = protectWorkspace ? workspaceRel(combined) : combined;
|
|
77681
78264
|
if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
|
|
77682
78265
|
throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
|
|
77683
78266
|
}
|
|
77684
78267
|
assertWritableDestination(destinationRoot, checked);
|
|
77685
|
-
const destination =
|
|
78268
|
+
const destination = path88.resolve(destinationRoot, checked);
|
|
77686
78269
|
await atomicCopy(sourceFile, destination, material.mode, extractedRoot);
|
|
77687
78270
|
outputs.push(await recordFile(destinationRoot, destination, destinationRootName));
|
|
77688
78271
|
}
|
|
77689
78272
|
return outputs;
|
|
77690
78273
|
} finally {
|
|
77691
|
-
|
|
78274
|
+
fs80.rmSync(temporary, { recursive: true, force: true });
|
|
77692
78275
|
}
|
|
77693
78276
|
}
|
|
77694
78277
|
async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
|
|
@@ -77704,15 +78287,15 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77704
78287
|
assertWritableDestination(destinationRoot, destinationRel);
|
|
77705
78288
|
return [destinationRel];
|
|
77706
78289
|
}
|
|
77707
|
-
const temporary =
|
|
78290
|
+
const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
|
|
77708
78291
|
try {
|
|
77709
|
-
const verifiedArchive =
|
|
78292
|
+
const verifiedArchive = path88.join(temporary, "material.tar.gz");
|
|
77710
78293
|
await atomicCopy(source, verifiedArchive, 384, sourceRoot);
|
|
77711
78294
|
const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
|
|
77712
78295
|
if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
|
|
77713
78296
|
throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
|
|
77714
78297
|
}
|
|
77715
|
-
const extractedRoot =
|
|
78298
|
+
const extractedRoot = path88.join(temporary, "extracted");
|
|
77716
78299
|
const extracted = await extract({
|
|
77717
78300
|
tarFile: verifiedArchive,
|
|
77718
78301
|
outDir: extractedRoot,
|
|
@@ -77721,7 +78304,7 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77721
78304
|
});
|
|
77722
78305
|
const planned = [];
|
|
77723
78306
|
for (const extractedRel of extracted) {
|
|
77724
|
-
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(
|
|
78307
|
+
const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path88.posix.join(destinationRel, extractedRel));
|
|
77725
78308
|
const checked = protectWorkspace ? workspaceRel(combined) : combined;
|
|
77726
78309
|
if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
|
|
77727
78310
|
throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
|
|
@@ -77731,34 +78314,34 @@ async function preflightMaterial(material, sourceRoot, destinationRoot, protectW
|
|
|
77731
78314
|
}
|
|
77732
78315
|
return planned;
|
|
77733
78316
|
} finally {
|
|
77734
|
-
|
|
78317
|
+
fs80.rmSync(temporary, { recursive: true, force: true });
|
|
77735
78318
|
}
|
|
77736
78319
|
}
|
|
77737
78320
|
function ownerMarker(root) {
|
|
77738
|
-
return
|
|
78321
|
+
return path88.join(root, ".brainbase-benchmark-owner.json");
|
|
77739
78322
|
}
|
|
77740
78323
|
function verifyOwnedDirectory(root, role, spec) {
|
|
77741
|
-
if (!
|
|
78324
|
+
if (!fs80.existsSync(root) || fs80.lstatSync(root).isSymbolicLink())
|
|
77742
78325
|
return false;
|
|
77743
78326
|
try {
|
|
77744
|
-
const marker = JSON.parse(
|
|
78327
|
+
const marker = JSON.parse(fs80.readFileSync(ownerMarker(root), "utf8"));
|
|
77745
78328
|
return marker.attempt_id === spec.attempt_id && marker.phase === spec.phase && marker.phase_id === spec.phase_id && marker.role === role;
|
|
77746
78329
|
} catch {
|
|
77747
78330
|
return false;
|
|
77748
78331
|
}
|
|
77749
78332
|
}
|
|
77750
78333
|
function prepareOwnedDirectory(root, role, spec) {
|
|
77751
|
-
if (
|
|
78334
|
+
if (fs80.existsSync(root)) {
|
|
77752
78335
|
if (!verifyOwnedDirectory(root, role, spec)) {
|
|
77753
|
-
const stat =
|
|
77754
|
-
if (!stat.isDirectory() ||
|
|
78336
|
+
const stat = fs80.lstatSync(root);
|
|
78337
|
+
if (!stat.isDirectory() || fs80.readdirSync(root).length > 0) {
|
|
77755
78338
|
throw new BenchmarkPhaseError(`unowned_${role}_root`, `${role}_root exists without a matching attempt ownership marker`);
|
|
77756
78339
|
}
|
|
77757
78340
|
} else {
|
|
77758
|
-
|
|
78341
|
+
fs80.rmSync(root, { recursive: true, force: true });
|
|
77759
78342
|
}
|
|
77760
78343
|
}
|
|
77761
|
-
|
|
78344
|
+
fs80.mkdirSync(root, { recursive: true, mode: 448 });
|
|
77762
78345
|
writeJsonAtomic(ownerMarker(root), {
|
|
77763
78346
|
schema_version: SCHEMA_VERSION,
|
|
77764
78347
|
attempt_id: spec.attempt_id,
|
|
@@ -77847,10 +78430,10 @@ function terminate(child) {
|
|
|
77847
78430
|
async function runCommand(command, root, spec, context, additions = {}) {
|
|
77848
78431
|
const cwdRel = normalizedRootRelative(command.cwd);
|
|
77849
78432
|
assertNoSymlinkTraversal(root, cwdRel);
|
|
77850
|
-
const cwd2 =
|
|
78433
|
+
const cwd2 = path88.resolve(root, cwdRel);
|
|
77851
78434
|
let cwdStat;
|
|
77852
78435
|
try {
|
|
77853
|
-
cwdStat =
|
|
78436
|
+
cwdStat = fs80.lstatSync(cwd2);
|
|
77854
78437
|
} catch {
|
|
77855
78438
|
throw new BenchmarkPhaseError("invalid_command_cwd", `command cwd is invalid: ${command.cwd}`);
|
|
77856
78439
|
}
|
|
@@ -77921,28 +78504,28 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
77921
78504
|
});
|
|
77922
78505
|
}
|
|
77923
78506
|
async function writeLog(root, name, data, spec) {
|
|
77924
|
-
const destination =
|
|
77925
|
-
|
|
78507
|
+
const destination = path88.join(root, name);
|
|
78508
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77926
78509
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77927
78510
|
try {
|
|
77928
|
-
|
|
78511
|
+
fs80.writeFileSync(temporary, redactCommandOutput(data, spec), {
|
|
77929
78512
|
flag: "wx",
|
|
77930
78513
|
mode: 384
|
|
77931
78514
|
});
|
|
77932
|
-
|
|
78515
|
+
fs80.renameSync(temporary, destination);
|
|
77933
78516
|
} finally {
|
|
77934
|
-
|
|
78517
|
+
fs80.rmSync(temporary, { force: true });
|
|
77935
78518
|
}
|
|
77936
78519
|
return await recordFile(root, destination, "logs");
|
|
77937
78520
|
}
|
|
77938
78521
|
function writeBufferAtomic(destination, data) {
|
|
77939
|
-
|
|
78522
|
+
fs80.mkdirSync(path88.dirname(destination), { recursive: true });
|
|
77940
78523
|
const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
77941
78524
|
try {
|
|
77942
|
-
|
|
77943
|
-
|
|
78525
|
+
fs80.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
|
|
78526
|
+
fs80.renameSync(temporary, destination);
|
|
77944
78527
|
} finally {
|
|
77945
|
-
|
|
78528
|
+
fs80.rmSync(temporary, { force: true });
|
|
77946
78529
|
}
|
|
77947
78530
|
}
|
|
77948
78531
|
function assertBudget(context) {
|
|
@@ -77951,7 +78534,7 @@ function assertBudget(context) {
|
|
|
77951
78534
|
}
|
|
77952
78535
|
}
|
|
77953
78536
|
async function executeHydrate(spec, context) {
|
|
77954
|
-
|
|
78537
|
+
fs80.mkdirSync(spec.workspace_root, { recursive: true });
|
|
77955
78538
|
prepareOwnedDirectory(spec.logs_root, "logs", spec);
|
|
77956
78539
|
context.logsOwned = true;
|
|
77957
78540
|
const outputs = [];
|
|
@@ -78030,11 +78613,11 @@ async function executeHydrate(spec, context) {
|
|
|
78030
78613
|
finalOutputs.push(output);
|
|
78031
78614
|
continue;
|
|
78032
78615
|
}
|
|
78033
|
-
const candidate =
|
|
78616
|
+
const candidate = path88.resolve(spec.workspace_root, safeRelPath(output.path));
|
|
78034
78617
|
assertNoSymlinkTraversal(spec.workspace_root, output.path);
|
|
78035
|
-
if (!
|
|
78618
|
+
if (!fs80.existsSync(candidate))
|
|
78036
78619
|
continue;
|
|
78037
|
-
const stat =
|
|
78620
|
+
const stat = fs80.lstatSync(candidate);
|
|
78038
78621
|
if (!stat.isFile() && !stat.isSymbolicLink())
|
|
78039
78622
|
continue;
|
|
78040
78623
|
finalOutputs.push(await recordFile(spec.workspace_root, candidate, "workspace", stat.isSymbolicLink() ? "symlink" : "file"));
|
|
@@ -78061,27 +78644,27 @@ async function readEvidence(stagingRoot, evidence) {
|
|
|
78061
78644
|
buffer,
|
|
78062
78645
|
record: {
|
|
78063
78646
|
root: "staging",
|
|
78064
|
-
path:
|
|
78647
|
+
path: path88.relative(stagingRoot, filePath).replace(/\\/g, "/"),
|
|
78065
78648
|
sha256: evidence.sha256,
|
|
78066
78649
|
size: opened.stat.size,
|
|
78067
78650
|
mode: opened.stat.mode & 511
|
|
78068
78651
|
}
|
|
78069
78652
|
};
|
|
78070
78653
|
} finally {
|
|
78071
|
-
|
|
78654
|
+
fs80.closeSync(opened.fd);
|
|
78072
78655
|
}
|
|
78073
78656
|
}
|
|
78074
78657
|
async function workspaceManifest(spec, context) {
|
|
78075
78658
|
const records = [];
|
|
78076
78659
|
let totalBytes = 0;
|
|
78077
|
-
const stack = [
|
|
78660
|
+
const stack = [path88.resolve(spec.workspace_root)];
|
|
78078
78661
|
while (stack.length > 0) {
|
|
78079
78662
|
const directory = stack.pop();
|
|
78080
|
-
const entries =
|
|
78663
|
+
const entries = fs80.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
|
|
78081
78664
|
for (const entry of entries) {
|
|
78082
78665
|
assertBudget(context);
|
|
78083
|
-
const full =
|
|
78084
|
-
const relative =
|
|
78666
|
+
const full = path88.join(directory, entry.name);
|
|
78667
|
+
const relative = path88.relative(spec.workspace_root, full).replace(/\\/g, "/");
|
|
78085
78668
|
if (relative === ".brainbase" || relative.startsWith(".brainbase/"))
|
|
78086
78669
|
continue;
|
|
78087
78670
|
if (relative === ".git" || relative.startsWith(".git/"))
|
|
@@ -78183,10 +78766,10 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78183
78766
|
if (evaluator.type === "workspace_assertion") {
|
|
78184
78767
|
const relative = workspaceRel(evaluator.path);
|
|
78185
78768
|
assertNoSymlinkTraversal(spec.workspace_root, relative);
|
|
78186
|
-
const candidate =
|
|
78769
|
+
const candidate = path88.resolve(spec.workspace_root, relative);
|
|
78187
78770
|
let stat = null;
|
|
78188
78771
|
try {
|
|
78189
|
-
stat =
|
|
78772
|
+
stat = fs80.lstatSync(candidate);
|
|
78190
78773
|
} catch (error2) {
|
|
78191
78774
|
const code = error2.code;
|
|
78192
78775
|
if (code !== "ENOENT" && code !== "ENOTDIR")
|
|
@@ -78207,7 +78790,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78207
78790
|
try {
|
|
78208
78791
|
verdict2 = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
|
|
78209
78792
|
} finally {
|
|
78210
|
-
|
|
78793
|
+
fs80.closeSync(opened.fd);
|
|
78211
78794
|
}
|
|
78212
78795
|
}
|
|
78213
78796
|
}
|
|
@@ -78217,7 +78800,7 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
78217
78800
|
try {
|
|
78218
78801
|
verdict2 = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
|
|
78219
78802
|
} finally {
|
|
78220
|
-
|
|
78803
|
+
fs80.closeSync(opened.fd);
|
|
78221
78804
|
}
|
|
78222
78805
|
}
|
|
78223
78806
|
}
|
|
@@ -78271,8 +78854,8 @@ async function executeEvaluate(spec, context) {
|
|
|
78271
78854
|
context.logsOwned = true;
|
|
78272
78855
|
validateRoots(spec);
|
|
78273
78856
|
const outputs = [];
|
|
78274
|
-
const finalOutputPath =
|
|
78275
|
-
const trajectoryPath =
|
|
78857
|
+
const finalOutputPath = path88.join(spec.logs_root, "candidate-evidence", "final-output");
|
|
78858
|
+
const trajectoryPath = path88.join(spec.logs_root, "candidate-evidence", "trajectory.json");
|
|
78276
78859
|
writeBufferAtomic(finalOutputPath, finalOutput.buffer);
|
|
78277
78860
|
writeBufferAtomic(trajectoryPath, trajectoryEvidence.buffer);
|
|
78278
78861
|
const frozenEvidenceRecords = [
|
|
@@ -78283,7 +78866,7 @@ async function executeEvaluate(spec, context) {
|
|
|
78283
78866
|
context.outputs.push(...frozenEvidenceRecords);
|
|
78284
78867
|
assertBudget(context);
|
|
78285
78868
|
const manifest = await workspaceManifest(spec, context);
|
|
78286
|
-
const manifestPath2 =
|
|
78869
|
+
const manifestPath2 = path88.join(spec.logs_root, "candidate-workspace-manifest.json");
|
|
78287
78870
|
writeJsonAtomic(manifestPath2, {
|
|
78288
78871
|
schema_version: SCHEMA_VERSION,
|
|
78289
78872
|
attempt_id: spec.attempt_id,
|
|
@@ -78296,12 +78879,12 @@ async function executeEvaluate(spec, context) {
|
|
|
78296
78879
|
for (const artifactRelInput of spec.candidate_artifacts) {
|
|
78297
78880
|
const artifactRel = workspaceRel(artifactRelInput);
|
|
78298
78881
|
assertNoSymlinkTraversal(spec.workspace_root, artifactRel);
|
|
78299
|
-
const source =
|
|
78882
|
+
const source = path88.resolve(spec.workspace_root, artifactRel);
|
|
78300
78883
|
const frozenArtifact = manifest.find((entry) => entry.path === artifactRel && entry.kind !== "symlink");
|
|
78301
|
-
if (!frozenArtifact || !
|
|
78884
|
+
if (!frozenArtifact || !fs80.existsSync(source) || !fs80.lstatSync(source).isFile()) {
|
|
78302
78885
|
throw new BenchmarkPhaseError("missing_artifact", `candidate artifact is missing: ${artifactRel}`);
|
|
78303
78886
|
}
|
|
78304
|
-
const destination =
|
|
78887
|
+
const destination = path88.resolve(spec.logs_root, "candidate-artifacts", artifactRel);
|
|
78305
78888
|
await atomicCopy(source, destination, undefined, spec.workspace_root);
|
|
78306
78889
|
const artifact = await recordFile(spec.logs_root, destination, "logs");
|
|
78307
78890
|
if (artifact.sha256 !== frozenArtifact.sha256 || artifact.size !== frozenArtifact.size || artifact.mode !== frozenArtifact.mode) {
|
|
@@ -78312,13 +78895,13 @@ async function executeEvaluate(spec, context) {
|
|
|
78312
78895
|
}
|
|
78313
78896
|
if (spec.capture_workspace_archive) {
|
|
78314
78897
|
const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
|
|
78315
|
-
const archive =
|
|
78898
|
+
const archive = path88.join(spec.logs_root, "candidate-workspace.tar.gz");
|
|
78316
78899
|
const temporary = `${archive}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
|
|
78317
78900
|
try {
|
|
78318
78901
|
await pack({ rootDir: spec.workspace_root, outFile: temporary, files: regularFiles });
|
|
78319
|
-
|
|
78902
|
+
fs80.renameSync(temporary, archive);
|
|
78320
78903
|
} finally {
|
|
78321
|
-
|
|
78904
|
+
fs80.rmSync(temporary, { force: true });
|
|
78322
78905
|
}
|
|
78323
78906
|
const archiveRecord = await recordFile(spec.logs_root, archive, "logs");
|
|
78324
78907
|
outputs.push(archiveRecord);
|
|
@@ -78417,22 +79000,22 @@ function rawIdentity(value) {
|
|
|
78417
79000
|
};
|
|
78418
79001
|
}
|
|
78419
79002
|
function readSpecBytes(specPathInput) {
|
|
78420
|
-
const specPath =
|
|
78421
|
-
const noFollow = typeof
|
|
79003
|
+
const specPath = path88.resolve(specPathInput);
|
|
79004
|
+
const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
|
|
78422
79005
|
let fd;
|
|
78423
79006
|
try {
|
|
78424
|
-
fd =
|
|
79007
|
+
fd = fs80.openSync(specPath, fs80.constants.O_RDONLY | noFollow);
|
|
78425
79008
|
} catch {
|
|
78426
79009
|
throw new BenchmarkPhaseError("spec_read_failed", "spec file could not be read");
|
|
78427
79010
|
}
|
|
78428
79011
|
try {
|
|
78429
|
-
const stat =
|
|
79012
|
+
const stat = fs80.fstatSync(fd);
|
|
78430
79013
|
if (!stat.isFile() || stat.size > MAX_SPEC_BYTES) {
|
|
78431
79014
|
throw new BenchmarkPhaseError("invalid_spec_file", "spec must be a regular JSON file no larger than 20 MiB");
|
|
78432
79015
|
}
|
|
78433
79016
|
return readDescriptor(fd);
|
|
78434
79017
|
} finally {
|
|
78435
|
-
|
|
79018
|
+
fs80.closeSync(fd);
|
|
78436
79019
|
}
|
|
78437
79020
|
}
|
|
78438
79021
|
function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase) {
|
|
@@ -78448,8 +79031,8 @@ function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase)
|
|
|
78448
79031
|
throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
|
|
78449
79032
|
}
|
|
78450
79033
|
validateRoots(spec);
|
|
78451
|
-
const resultPath =
|
|
78452
|
-
const expectedResultPath =
|
|
79034
|
+
const resultPath = path88.resolve(resultPathInput);
|
|
79035
|
+
const expectedResultPath = path88.join(path88.resolve(spec.logs_root), "result.json");
|
|
78453
79036
|
if (resultPath !== expectedResultPath) {
|
|
78454
79037
|
throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
|
|
78455
79038
|
}
|
|
@@ -78476,9 +79059,9 @@ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expecte
|
|
|
78476
79059
|
spec_digest: digest,
|
|
78477
79060
|
timeout_ms: spec.budget.timeout_ms
|
|
78478
79061
|
};
|
|
78479
|
-
if (
|
|
79062
|
+
if (fs80.existsSync(resultPath)) {
|
|
78480
79063
|
try {
|
|
78481
|
-
const cached2 = JSON.parse(
|
|
79064
|
+
const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
|
|
78482
79065
|
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") {
|
|
78483
79066
|
return {
|
|
78484
79067
|
ok: true,
|
|
@@ -78546,7 +79129,7 @@ function writeBenchmarkPhaseTimeoutResult(specBytes, resultPathInput, expectedPh
|
|
|
78546
79129
|
async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase, immutableSpecBytes) {
|
|
78547
79130
|
const startedAt = nowIso();
|
|
78548
79131
|
const started = Date.now();
|
|
78549
|
-
const resultPath =
|
|
79132
|
+
const resultPath = path88.resolve(resultPathInput);
|
|
78550
79133
|
let raw = undefined;
|
|
78551
79134
|
let digest = null;
|
|
78552
79135
|
let identity2 = rawIdentity(raw);
|
|
@@ -78580,14 +79163,14 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
78580
79163
|
throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
|
|
78581
79164
|
}
|
|
78582
79165
|
validateRoots(spec);
|
|
78583
|
-
const expectedResultPath =
|
|
79166
|
+
const expectedResultPath = path88.join(path88.resolve(spec.logs_root), "result.json");
|
|
78584
79167
|
if (resultPath !== expectedResultPath) {
|
|
78585
79168
|
throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
|
|
78586
79169
|
}
|
|
78587
79170
|
resultPathValidated = true;
|
|
78588
|
-
if (
|
|
79171
|
+
if (fs80.existsSync(resultPath)) {
|
|
78589
79172
|
try {
|
|
78590
|
-
const cached2 = JSON.parse(
|
|
79173
|
+
const cached2 = JSON.parse(fs80.readFileSync(resultPath, "utf8"));
|
|
78591
79174
|
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") {
|
|
78592
79175
|
return { exitCode: 0, result: cached2 };
|
|
78593
79176
|
}
|
|
@@ -78783,14 +79366,14 @@ function terminatePhase(child) {
|
|
|
78783
79366
|
}
|
|
78784
79367
|
}
|
|
78785
79368
|
function createAnonymousSpecFd(bytes) {
|
|
78786
|
-
const temporary =
|
|
78787
|
-
|
|
79369
|
+
const temporary = path89.join(os17.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto7.randomBytes(12).toString("hex")}`);
|
|
79370
|
+
fs81.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
|
|
78788
79371
|
try {
|
|
78789
|
-
const fd =
|
|
78790
|
-
|
|
79372
|
+
const fd = fs81.openSync(temporary, "r");
|
|
79373
|
+
fs81.unlinkSync(temporary);
|
|
78791
79374
|
return fd;
|
|
78792
79375
|
} catch (error2) {
|
|
78793
|
-
|
|
79376
|
+
fs81.rmSync(temporary, { force: true });
|
|
78794
79377
|
throw error2;
|
|
78795
79378
|
}
|
|
78796
79379
|
}
|
|
@@ -78859,13 +79442,13 @@ async function runSupervisedPhase(phase, parsed, write) {
|
|
|
78859
79442
|
detached: process.platform !== "win32"
|
|
78860
79443
|
});
|
|
78861
79444
|
} catch {
|
|
78862
|
-
|
|
79445
|
+
fs81.closeSync(specFd);
|
|
78863
79446
|
const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child process could not be started");
|
|
78864
79447
|
write(`${JSON.stringify(failure)}
|
|
78865
79448
|
`);
|
|
78866
79449
|
return 1;
|
|
78867
79450
|
}
|
|
78868
|
-
|
|
79451
|
+
fs81.closeSync(specFd);
|
|
78869
79452
|
return await new Promise((resolve) => {
|
|
78870
79453
|
const stdout = [];
|
|
78871
79454
|
let settled = false;
|
|
@@ -78947,7 +79530,7 @@ async function runBenchmark(sub, args, write = (value) => process.stdout.write(v
|
|
|
78947
79530
|
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) {
|
|
78948
79531
|
throw new Error("Invalid internal benchmark phase invocation");
|
|
78949
79532
|
}
|
|
78950
|
-
const specBytes =
|
|
79533
|
+
const specBytes = fs81.readFileSync(specFd);
|
|
78951
79534
|
const { exitCode, result: result2 } = await runBenchmarkPhase("", resultPath, phase, specBytes);
|
|
78952
79535
|
write(`${JSON.stringify(result2)}
|
|
78953
79536
|
`);
|
|
@@ -79092,7 +79675,8 @@ function help() {
|
|
|
79092
79675
|
out.push(divider("CLI TOKENS"));
|
|
79093
79676
|
out.push("");
|
|
79094
79677
|
out.push(` ${import_picocolors49.default.cyan("token create")} ${import_picocolors49.default.dim("issue a long-lived CLI key for CI / scripts")}`);
|
|
79095
|
-
out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your
|
|
79678
|
+
out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your tokens")}`);
|
|
79679
|
+
out.push(` ${import_picocolors49.default.cyan("token rename")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("relabel a token")}`);
|
|
79096
79680
|
out.push(` ${import_picocolors49.default.cyan("token revoke")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("revoke a token")}`);
|
|
79097
79681
|
out.push("");
|
|
79098
79682
|
out.push(divider("MCP"));
|
|
@@ -79147,36 +79731,118 @@ function help() {
|
|
|
79147
79731
|
console.log(out.join(`
|
|
79148
79732
|
`));
|
|
79149
79733
|
}
|
|
79150
|
-
|
|
79734
|
+
var VALUE_TAKING_FLAGS = new Set([
|
|
79735
|
+
"--scope",
|
|
79736
|
+
"--name",
|
|
79737
|
+
"-n",
|
|
79738
|
+
"--harness",
|
|
79739
|
+
"--web",
|
|
79740
|
+
"--visibility",
|
|
79741
|
+
"--category",
|
|
79742
|
+
"--target",
|
|
79743
|
+
"--page",
|
|
79744
|
+
"--as",
|
|
79745
|
+
"--agent",
|
|
79746
|
+
"--shell",
|
|
79747
|
+
"--skill-version",
|
|
79748
|
+
"--tagline",
|
|
79749
|
+
"--org",
|
|
79750
|
+
"--team",
|
|
79751
|
+
"--description",
|
|
79752
|
+
"--schema",
|
|
79753
|
+
"--from",
|
|
79754
|
+
"--to"
|
|
79755
|
+
]);
|
|
79756
|
+
function isValueOfPriorFlag2(args, index) {
|
|
79757
|
+
return index > 0 && VALUE_TAKING_FLAGS.has(args[index - 1]);
|
|
79758
|
+
}
|
|
79759
|
+
function findFlag(args, name) {
|
|
79760
|
+
const prefix = `${name}=`;
|
|
79761
|
+
for (let i = 0;i < args.length; i++) {
|
|
79762
|
+
if (isValueOfPriorFlag2(args, i))
|
|
79763
|
+
continue;
|
|
79764
|
+
const a3 = args[i];
|
|
79765
|
+
if (a3 === name)
|
|
79766
|
+
return { index: i };
|
|
79767
|
+
if (a3.startsWith(prefix))
|
|
79768
|
+
return { index: i, joinedValue: a3.slice(prefix.length) };
|
|
79769
|
+
}
|
|
79770
|
+
return null;
|
|
79771
|
+
}
|
|
79772
|
+
function takeFlagOnce(args, names) {
|
|
79773
|
+
let best = null;
|
|
79151
79774
|
for (const n of names) {
|
|
79152
|
-
const
|
|
79153
|
-
if (
|
|
79154
|
-
|
|
79155
|
-
args.splice(i, v3 && !v3.startsWith("--") && !(n.startsWith("-") && v3.startsWith("-")) ? 2 : 1);
|
|
79156
|
-
return v3 && !v3.startsWith("--") ? v3 : "";
|
|
79157
|
-
}
|
|
79775
|
+
const hit = findFlag(args, n);
|
|
79776
|
+
if (hit && (!best || hit.index < best.index))
|
|
79777
|
+
best = hit;
|
|
79158
79778
|
}
|
|
79159
|
-
|
|
79779
|
+
if (!best)
|
|
79780
|
+
return;
|
|
79781
|
+
if (best.joinedValue !== undefined) {
|
|
79782
|
+
args.splice(best.index, 1);
|
|
79783
|
+
return best.joinedValue;
|
|
79784
|
+
}
|
|
79785
|
+
const v3 = args[best.index + 1];
|
|
79786
|
+
if (v3 && !v3.startsWith("-")) {
|
|
79787
|
+
args.splice(best.index, 2);
|
|
79788
|
+
return v3;
|
|
79789
|
+
}
|
|
79790
|
+
args.splice(best.index, 1);
|
|
79791
|
+
return "";
|
|
79792
|
+
}
|
|
79793
|
+
function getFlag(args, ...names) {
|
|
79794
|
+
const first = takeFlagOnce(args, names);
|
|
79795
|
+
if (first === undefined)
|
|
79796
|
+
return;
|
|
79797
|
+
while (takeFlagOnce(args, names) !== undefined) {}
|
|
79798
|
+
return first;
|
|
79160
79799
|
}
|
|
79161
79800
|
function getFlagAll(args, ...names) {
|
|
79162
79801
|
const out = [];
|
|
79163
|
-
let v3 =
|
|
79802
|
+
let v3 = takeFlagOnce(args, names);
|
|
79164
79803
|
while (v3 !== undefined) {
|
|
79165
79804
|
if (v3)
|
|
79166
79805
|
out.push(v3);
|
|
79167
|
-
v3 =
|
|
79806
|
+
v3 = takeFlagOnce(args, names);
|
|
79168
79807
|
}
|
|
79169
79808
|
return out;
|
|
79170
79809
|
}
|
|
79171
|
-
function
|
|
79172
|
-
|
|
79173
|
-
|
|
79174
|
-
|
|
79175
|
-
|
|
79810
|
+
function interpretJoinedBoolean(value, name) {
|
|
79811
|
+
const v3 = value.trim().toLowerCase();
|
|
79812
|
+
if (v3 === "")
|
|
79813
|
+
return false;
|
|
79814
|
+
switch (v3) {
|
|
79815
|
+
case "false":
|
|
79816
|
+
case "0":
|
|
79817
|
+
case "no":
|
|
79818
|
+
case "off":
|
|
79819
|
+
return false;
|
|
79820
|
+
case "true":
|
|
79821
|
+
case "1":
|
|
79822
|
+
case "yes":
|
|
79823
|
+
case "on":
|
|
79176
79824
|
return true;
|
|
79825
|
+
default:
|
|
79826
|
+
throw new Error(`Unrecognised value for ${name}: ${value}`);
|
|
79827
|
+
}
|
|
79828
|
+
}
|
|
79829
|
+
function hasFlag2(args, ...names) {
|
|
79830
|
+
let leftmost;
|
|
79831
|
+
while (true) {
|
|
79832
|
+
let best = null;
|
|
79833
|
+
for (const n of names) {
|
|
79834
|
+
const hit = findFlag(args, n);
|
|
79835
|
+
if (hit && (!best || hit.index < best.index))
|
|
79836
|
+
best = { ...hit, name: n };
|
|
79177
79837
|
}
|
|
79838
|
+
if (!best)
|
|
79839
|
+
break;
|
|
79840
|
+
args.splice(best.index, 1);
|
|
79841
|
+
const enabled = best.joinedValue === undefined ? true : interpretJoinedBoolean(best.joinedValue, best.name);
|
|
79842
|
+
if (leftmost === undefined)
|
|
79843
|
+
leftmost = enabled;
|
|
79178
79844
|
}
|
|
79179
|
-
return false;
|
|
79845
|
+
return leftmost ?? false;
|
|
79180
79846
|
}
|
|
79181
79847
|
async function requireAuth(cmd) {
|
|
79182
79848
|
if (!PROTECTED.has(cmd))
|
|
@@ -79222,7 +79888,7 @@ async function main() {
|
|
|
79222
79888
|
const rawCwd = process14.cwd();
|
|
79223
79889
|
const cwd2 = (() => {
|
|
79224
79890
|
try {
|
|
79225
|
-
return
|
|
79891
|
+
return fs82.realpathSync(rawCwd);
|
|
79226
79892
|
} catch {
|
|
79227
79893
|
return rawCwd;
|
|
79228
79894
|
}
|
|
@@ -79319,7 +79985,7 @@ async function main() {
|
|
|
79319
79985
|
}
|
|
79320
79986
|
case "token": {
|
|
79321
79987
|
const sub = argv.shift();
|
|
79322
|
-
await runToken(sub, argv, { yes });
|
|
79988
|
+
await runToken(sub, argv, { yes, name: nameFlag });
|
|
79323
79989
|
break;
|
|
79324
79990
|
}
|
|
79325
79991
|
case "link": {
|