@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.
Files changed (2) hide show
  1. package/dist/index.js +989 -323
  2. 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(path87) {
31712
- let input = path87;
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 [path87, query] = wsComponent.resourceName.split("?");
31956
- wsComponent.path = path87 && path87 !== "/" ? path87 : undefined;
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, fs79, exportName) {
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, fs79[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 fs81 from "node:fs";
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.0",
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(BRAINBASE_HOME);
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
- writeJson(TOKEN_FILE, stored);
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
- if (exists(TOKEN_FILE))
53899
- fs47.rmSync(TOKEN_FILE);
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
- const retrySession = credential.source === "session" && !new Headers(init.headers).has("Authorization") ? credential.session : null;
54073
- const res = await sendWithAuthRetry(retrySession, (refreshed) => sendRequest(`${apiBase(refreshed ?? credential.session)}${pathname}`, init, refreshed?.access_token ?? credential.bearer));
54074
- const text2 = await res.text();
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
- return request(`/agents/${encodeURIComponent(agentId)}/secrets`);
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
- commands: exports_external.array(exports_external.record(exports_external.unknown())).optional(),
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 fs72 from "node:fs";
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 fs69 from "node:fs";
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 = fs69.readFileSync(p2);
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 = fs69.readdirSync(sub, { withFileTypes: true });
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 fs70 from "node:fs";
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(fs70.readFileSync(p2, "utf8"));
63829
+ return parseSecretsEnv(fs71.readFileSync(p2, "utf8"));
63642
63830
  }
63643
63831
  function writeLocalSecrets(cwd2, secrets) {
63644
63832
  ensureDir(path78.join(cwd2, LINK_DIR));
63645
- fs70.writeFileSync(secretsPath(cwd2), formatSecretsEnv(secrets), "utf8");
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) ? fs70.readFileSync(ignorePath, "utf8") : "";
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
- fs70.writeFileSync(ignorePath, [...lines].join(`
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 fs71 from "node:fs";
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 = fs71.mkdtempSync(path79.join(os13.tmpdir(), "brainbase-unpack-"));
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
- fs71.writeFileSync(path79.join(compDir, "instructions.md"), instructionsBody, "utf8");
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
- fs71.rmSync(stageRoot, { recursive: true, force: true });
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
- fs71.mkdirSync(dir, { recursive: true });
63858
- fs71.writeFileSync(path79.join(dir, "resolved-mcps.json"), JSON.stringify(mcps, null, 2));
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
- fs71.writeFileSync(path79.join(compDir, `${slug}.md`), wireBody, "utf8");
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 (!fs71.existsSync(abs)) {
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 fs71.readdirSync(src, { withFileTypes: true })) {
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
- fs71.copyFileSync(s3, d3);
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 (!fs72.existsSync(filePath))
64405
+ if (!fs73.existsSync(filePath))
64218
64406
  continue;
64219
64407
  try {
64220
- const stat = fs72.statSync(filePath);
64408
+ const stat = fs73.statSync(filePath);
64221
64409
  if (stat.isDirectory())
64222
- fs72.rmSync(filePath, { recursive: true, force: true });
64410
+ fs73.rmSync(filePath, { recursive: true, force: true });
64223
64411
  else
64224
- fs72.rmSync(filePath);
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
- fs72.rmSync(stageRoot, { recursive: true, force: true });
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 = fs72.mkdtempSync(path80.join(os14.tmpdir(), "brainbase-pull-"));
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
- fs72.writeFileSync(target, f4.content);
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
- fs72.writeFileSync(target, normalizeInstructionBody(body), "utf8");
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
- fs72.writeFileSync(target, body, "utf8");
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: prev?.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
- fs72.writeFileSync(target, cloudEntrypoint, "utf8");
64683
+ fs73.writeFileSync(target, cloudEntrypoint, "utf8");
64495
64684
  try {
64496
- fs72.chmodSync(target, 493);
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
- fs72.writeFileSync(scriptPath, body, "utf8");
64764
+ fs73.writeFileSync(scriptPath, body, "utf8");
64576
64765
  try {
64577
- fs72.chmodSync(scriptPath, 493);
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 = fs72.createWriteStream(logPath, { flags: "w" });
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
- banner("agent status what changed locally, remotely, both");
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.start(`Fetching ${link2.name}…`);
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.stop(`Cloud revision ${cloud.revision}.`);
65575
+ sp?.stop(`Cloud revision ${cloud.revision}.`);
65364
65576
  } catch (err) {
65365
- sp.stop("Failed to reach brainbase.");
65366
- if (err instanceof ApiError && err.status === 401) {
65367
- f2.error("Your session is invalid. Run `brainbase login` and try again.");
65368
- } else {
65369
- f2.error(err.message);
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 (!componentsDrifted && !metaDrifted && !configDrifted && !secretsDrifted) {
65477
- lines.push(` ${import_picocolors29.default.green("")} everything is in sync`);
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 path81 from "node:path";
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() ?? path81.basename(path81.resolve(cwd2)) ?? "My Agent";
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 and what would pull")}`);
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 path85 from "node:path";
66295
- import fs76 from "node:fs";
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 path82 from "node:path";
66300
- import fs73 from "node:fs";
66301
- var import_yaml3 = __toESM(require_dist(), 1);
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 path82.join(cwd2, ORCH_MANIFEST_FILE);
66654
+ return path83.join(cwd2, ORCH_MANIFEST_FILE);
66354
66655
  }
66355
66656
  function hasOrchManifest(cwd2) {
66356
- return fs73.existsSync(orchManifestPath(cwd2));
66657
+ return fs74.existsSync(orchManifestPath(cwd2));
66357
66658
  }
66358
66659
  function readOrchManifest(cwd2) {
66359
66660
  const p2 = orchManifestPath(cwd2);
66360
- if (!fs73.existsSync(p2))
66661
+ if (!fs74.existsSync(p2))
66361
66662
  return null;
66362
- const raw = fs73.readFileSync(p2, "utf8");
66663
+ const raw = fs74.readFileSync(p2, "utf8");
66363
66664
  let parsed;
66364
66665
  try {
66365
- parsed = import_yaml3.default.parse(raw);
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 import_yaml3.default.Document;
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
- fs73.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
66684
+ fs74.writeFileSync(orchManifestPath(cwd2), String(doc), "utf8");
66384
66685
  }
66385
66686
  function memberDir(cwd2, slug) {
66386
- return path82.join(cwd2, ORCH_MEMBERS_DIR, slug);
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 path83 from "node:path";
66421
- import fs74 from "node:fs";
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 path83.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
66756
+ return path84.join(cwd2, LINK_DIR, ORCH_LINK_FILE);
66456
66757
  }
66457
66758
  function orchSyncStatePath(cwd2) {
66458
- return path83.join(cwd2, LINK_DIR, ORCH_SYNC_STATE_FILE);
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(path83.join(cwd2, LINK_DIR));
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(path83.join(cwd2, LINK_DIR));
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 = path83.join(cwd2, LINK_DIR, ".gitignore");
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
- fs74.writeFileSync(ignorePath, desired);
66802
+ fs75.writeFileSync(ignorePath, desired);
66502
66803
  return;
66503
66804
  }
66504
- const current = fs74.readFileSync(ignorePath, "utf8");
66805
+ const current = fs75.readFileSync(ignorePath, "utf8");
66505
66806
  if (!current.split(/\r?\n/).some((l2) => l2.trim() === ORCH_SYNC_STATE_FILE)) {
66506
- fs74.writeFileSync(ignorePath, current.endsWith(`
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 path84 from "node:path";
66515
- import fs75 from "node:fs";
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: path84.join(stageRoot, c2.type, c2.slug),
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 manifest = input.preserveManifest ? null : buildManifestFromCloud(cloud, agent);
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
- fs75.rmSync(stageRoot, { recursive: true, force: true });
66907
+ fs76.rmSync(stageRoot, { recursive: true, force: true });
66602
66908
  } catch {}
66603
66909
  }
66604
66910
  }
66605
66911
  function stageManifestComponents2(components) {
66606
- const root = fs75.mkdtempSync(path84.join(os15.tmpdir(), "brainbase-orch-pull-"));
66912
+ const root = fs76.mkdtempSync(path85.join(os15.tmpdir(), "brainbase-orch-pull-"));
66607
66913
  for (const c2 of components) {
66608
- const compDir = path84.join(root, c2.type, c2.slug);
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 = path84.join(compDir, f4.path);
66612
- ensureDir(path84.dirname(target));
66613
- fs75.writeFileSync(target, f4.content);
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 = path84.join(cwd2, DEFAULT_INSTRUCTIONS_FILE);
66647
- ensureDir(path84.dirname(target));
66648
- fs75.writeFileSync(target, normalizeInstructionBody(body), "utf8");
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 = path84.join(cwd2, DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`);
66661
- ensureDir(path84.dirname(target));
66662
- fs75.writeFileSync(target, body, "utf8");
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: path84.join(DEFAULT_PLAYBOOKS_DIR, `${c2.slug}.md`) }
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
- fs76.mkdirSync(cwd2, { recursive: true });
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 ${path85.basename(cwd2)}/ ${import_picocolors37.default.dim(`(${installedMembers.length}/${cloud.members.length} members)`)}.`);
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 fs77 from "node:fs";
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) || fs77.existsSync(memberDir(cwd2, 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) || fs77.existsSync(memberDir(cwd2, 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
- fs77.mkdirSync(dest, { recursive: true });
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
- fs77.rmSync(dest, { recursive: true, force: true });
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: `${props.active.length} active`,
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
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68339
- dimColor: true,
68340
- children: "› brainbase token revoke <id>"
68341
- }, undefined, false, undefined, this)
68342
- }, undefined, false, undefined, this)
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
- const scopes = args.scopes && args.scopes.length > 0 ? args.scopes : DEFAULT_SCOPES;
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
- writeToken(created.token, name);
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)}? CIs and machines using it will stop working.`,
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
- await registryApi.revokeCliToken(args.id);
68414
- const local = readToken();
68415
- if (local) {
68416
- clearToken();
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 i = rest2.indexOf(n);
68431
- if (i !== -1 && i + 1 < rest2.length)
68432
- return rest2[i + 1];
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 (!raw)
68999
+ if (raw === undefined)
68438
69000
  return;
68439
- return raw.split(",").map((s3) => s3.trim()).filter((s3) => s3.length > 0);
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 active tokens")}`);
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 path86 from "node:path";
68494
- import fs78 from "node:fs";
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 = path86.join(cwd2, ".brainbase", "resolved-mcps.json");
69128
+ const p2 = path87.join(cwd2, ".brainbase", "resolved-mcps.json");
68546
69129
  let raw;
68547
69130
  try {
68548
- raw = fs78.readFileSync(p2, "utf-8");
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 = path86.join(cwd2, ".mcp.json");
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 = path86.join(cwd2, ".codex", "config.toml");
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 = path86.join(cwd2, ".kafka", "kafka.json");
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, path87) {
68865
- if (!path87)
69447
+ function getElementAtPath(obj, path88) {
69448
+ if (!path88)
68866
69449
  return obj;
68867
- return path87.reduce((acc, key2) => acc?.[key2], obj);
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(path87, issues) {
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(path87);
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 fs80 from "node:fs";
77664
+ import fs81 from "node:fs";
77082
77665
  import os17 from "node:os";
77083
- import path88 from "node:path";
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 fs79 from "node:fs";
77674
+ import fs80 from "node:fs";
77092
77675
  import os16 from "node:os";
77093
- import path87 from "node:path";
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(path87.isAbsolute, {
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 = path87.relative(path87.resolve(root), path87.resolve(candidate));
77335
- return relative === "" || !relative.startsWith("..") && !path87.isAbsolute(relative);
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 = path87.resolve(input);
77921
+ const resolved = path88.resolve(input);
77339
77922
  const suffix = [];
77340
77923
  let current = resolved;
77341
- while (!fs79.existsSync(current)) {
77342
- const parent = path87.dirname(current);
77924
+ while (!fs80.existsSync(current)) {
77925
+ const parent = path88.dirname(current);
77343
77926
  if (parent === current)
77344
77927
  break;
77345
- suffix.unshift(path87.basename(current));
77928
+ suffix.unshift(path88.basename(current));
77346
77929
  current = parent;
77347
77930
  }
77348
- const canonicalBase = fs79.realpathSync(current);
77349
- return path87.join(canonicalBase, ...suffix);
77931
+ const canonicalBase = fs80.realpathSync(current);
77932
+ return path88.join(canonicalBase, ...suffix);
77350
77933
  }
77351
77934
  function validateRoots(spec) {
77352
- const workspace = path87.resolve(spec.workspace_root);
77353
- if (!fs79.existsSync(workspace) || fs79.lstatSync(workspace).isSymbolicLink() || !fs79.lstatSync(workspace).isDirectory()) {
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 = path87.resolve(spec.staging_root);
77358
- const expectedStaging = path87.join(workspace, ".brainbase", "benchmark", spec.attempt_id, "incoming");
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 (!fs79.existsSync(staging) || fs79.lstatSync(staging).isSymbolicLink() || !fs79.lstatSync(staging).isDirectory() || fs79.realpathSync(staging) !== path87.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
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 = path87.resolve(input);
77375
- if (candidate === path87.parse(candidate).root) {
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 (fs79.existsSync(candidate) && fs79.lstatSync(candidate).isSymbolicLink()) {
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 = path87.resolve(root);
77988
+ let current = path88.resolve(root);
77406
77989
  for (const segment of rel.split("/").slice(0, -1)) {
77407
- current = path87.join(current, segment);
77408
- if (!fs79.existsSync(current))
77990
+ current = path88.join(current, segment);
77991
+ if (!fs80.existsSync(current))
77409
77992
  continue;
77410
- if (fs79.lstatSync(current).isSymbolicLink()) {
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 = fs79.realpathSync(root);
77421
- canonicalFile = fs79.realpathSync(filePath);
77422
- currentStat = fs79.statSync(filePath);
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 fs79.constants.O_NOFOLLOW === "number" ? fs79.constants.O_NOFOLLOW : 0;
78014
+ const noFollow = typeof fs80.constants.O_NOFOLLOW === "number" ? fs80.constants.O_NOFOLLOW : 0;
77432
78015
  let fd;
77433
78016
  try {
77434
- fd = fs79.openSync(filePath, fs79.constants.O_RDONLY | noFollow);
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 = fs79.fstatSync(fd);
78025
+ const stat = fs80.fstatSync(fd);
77443
78026
  if (!stat.isFile()) {
77444
- fs79.closeSync(fd);
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
- fs79.closeSync(fd);
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 = fs79.createReadStream("", {
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 fs79.readFileSync(fd);
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 = path87.resolve(root);
78059
+ let current = path88.resolve(root);
77477
78060
  const segments = rel.split("/");
77478
78061
  for (const segment of segments.slice(0, -1)) {
77479
- current = path87.join(current, segment);
77480
- if (!fs79.existsSync(current))
78062
+ current = path88.join(current, segment);
78063
+ if (!fs80.existsSync(current))
77481
78064
  continue;
77482
- const stat = fs79.lstatSync(current);
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 = path87.resolve(root, rel);
77491
- if (fs79.existsSync(destination) && fs79.lstatSync(destination).isDirectory()) {
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 = path87.resolve(stagingRoot, rel);
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 = fs79.lstatSync(source);
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 = path87.resolve(root, relative);
77552
- if (!isWithin(root, candidate) || !fs79.existsSync(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 = fs79.lstatSync(candidate);
78138
+ const stat = fs80.lstatSync(candidate);
77556
78139
  if (record3.kind === "symlink") {
77557
- const target = stat.isSymbolicLink() ? fs79.readlinkSync(candidate) : null;
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
- fs79.closeSync(opened.fd);
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
- fs79.closeSync(opened.fd);
78171
+ fs80.closeSync(opened.fd);
77589
78172
  }
77590
78173
  return source;
77591
78174
  }
77592
78175
  async function atomicCopy(source, destination, mode, sourceRoot) {
77593
- fs79.mkdirSync(path87.dirname(destination), { recursive: true });
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(fs79.createReadStream("", {
78180
+ await pipeline2(fs80.createReadStream("", {
77598
78181
  fd: opened.fd,
77599
78182
  autoClose: false,
77600
78183
  start: 0
77601
- }), fs79.createWriteStream(temporary, {
78184
+ }), fs80.createWriteStream(temporary, {
77602
78185
  flags: "wx",
77603
78186
  mode: 384
77604
78187
  }));
77605
- fs79.chmodSync(temporary, mode ?? opened.stat.mode & 511);
77606
- fs79.renameSync(temporary, destination);
78188
+ fs80.chmodSync(temporary, mode ?? opened.stat.mode & 511);
78189
+ fs80.renameSync(temporary, destination);
77607
78190
  } finally {
77608
- fs79.closeSync(opened.fd);
77609
- fs79.rmSync(temporary, { force: true });
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 = path87.relative(root, filePath).replace(/\\/g, "/");
78196
+ const relative = path88.relative(root, filePath).replace(/\\/g, "/");
77614
78197
  if (kind === "symlink") {
77615
- const stat = fs79.lstatSync(filePath);
77616
- const target = fs79.readlinkSync(filePath);
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
- fs79.closeSync(opened.fd);
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 = path87.resolve(destinationRoot, destinationRel);
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 = fs79.mkdtempSync(path87.join(os16.tmpdir(), "brainbase-benchmark-"));
78241
+ const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-"));
77659
78242
  try {
77660
- const verifiedArchive = path87.join(temporary, "material.tar.gz");
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 = path87.join(temporary, "extracted");
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 = path87.resolve(extractedRoot, safeRelPath(extractedRel));
77676
- const stat = fs79.lstatSync(sourceFile);
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(path87.posix.join(destinationRel, extractedRel));
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 = path87.resolve(destinationRoot, checked);
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
- fs79.rmSync(temporary, { recursive: true, force: true });
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 = fs79.mkdtempSync(path87.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
78290
+ const temporary = fs80.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
77708
78291
  try {
77709
- const verifiedArchive = path87.join(temporary, "material.tar.gz");
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 = path87.join(temporary, "extracted");
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(path87.posix.join(destinationRel, extractedRel));
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
- fs79.rmSync(temporary, { recursive: true, force: true });
78317
+ fs80.rmSync(temporary, { recursive: true, force: true });
77735
78318
  }
77736
78319
  }
77737
78320
  function ownerMarker(root) {
77738
- return path87.join(root, ".brainbase-benchmark-owner.json");
78321
+ return path88.join(root, ".brainbase-benchmark-owner.json");
77739
78322
  }
77740
78323
  function verifyOwnedDirectory(root, role, spec) {
77741
- if (!fs79.existsSync(root) || fs79.lstatSync(root).isSymbolicLink())
78324
+ if (!fs80.existsSync(root) || fs80.lstatSync(root).isSymbolicLink())
77742
78325
  return false;
77743
78326
  try {
77744
- const marker = JSON.parse(fs79.readFileSync(ownerMarker(root), "utf8"));
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 (fs79.existsSync(root)) {
78334
+ if (fs80.existsSync(root)) {
77752
78335
  if (!verifyOwnedDirectory(root, role, spec)) {
77753
- const stat = fs79.lstatSync(root);
77754
- if (!stat.isDirectory() || fs79.readdirSync(root).length > 0) {
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
- fs79.rmSync(root, { recursive: true, force: true });
78341
+ fs80.rmSync(root, { recursive: true, force: true });
77759
78342
  }
77760
78343
  }
77761
- fs79.mkdirSync(root, { recursive: true, mode: 448 });
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 = path87.resolve(root, cwdRel);
78433
+ const cwd2 = path88.resolve(root, cwdRel);
77851
78434
  let cwdStat;
77852
78435
  try {
77853
- cwdStat = fs79.lstatSync(cwd2);
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 = path87.join(root, name);
77925
- fs79.mkdirSync(path87.dirname(destination), { recursive: true });
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
- fs79.writeFileSync(temporary, redactCommandOutput(data, spec), {
78511
+ fs80.writeFileSync(temporary, redactCommandOutput(data, spec), {
77929
78512
  flag: "wx",
77930
78513
  mode: 384
77931
78514
  });
77932
- fs79.renameSync(temporary, destination);
78515
+ fs80.renameSync(temporary, destination);
77933
78516
  } finally {
77934
- fs79.rmSync(temporary, { force: true });
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
- fs79.mkdirSync(path87.dirname(destination), { recursive: true });
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
- fs79.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
77943
- fs79.renameSync(temporary, destination);
78525
+ fs80.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
78526
+ fs80.renameSync(temporary, destination);
77944
78527
  } finally {
77945
- fs79.rmSync(temporary, { force: true });
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
- fs79.mkdirSync(spec.workspace_root, { recursive: true });
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 = path87.resolve(spec.workspace_root, safeRelPath(output.path));
78616
+ const candidate = path88.resolve(spec.workspace_root, safeRelPath(output.path));
78034
78617
  assertNoSymlinkTraversal(spec.workspace_root, output.path);
78035
- if (!fs79.existsSync(candidate))
78618
+ if (!fs80.existsSync(candidate))
78036
78619
  continue;
78037
- const stat = fs79.lstatSync(candidate);
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: path87.relative(stagingRoot, filePath).replace(/\\/g, "/"),
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
- fs79.closeSync(opened.fd);
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 = [path87.resolve(spec.workspace_root)];
78660
+ const stack = [path88.resolve(spec.workspace_root)];
78078
78661
  while (stack.length > 0) {
78079
78662
  const directory = stack.pop();
78080
- const entries = fs79.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
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 = path87.join(directory, entry.name);
78084
- const relative = path87.relative(spec.workspace_root, full).replace(/\\/g, "/");
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 = path87.resolve(spec.workspace_root, relative);
78769
+ const candidate = path88.resolve(spec.workspace_root, relative);
78187
78770
  let stat = null;
78188
78771
  try {
78189
- stat = fs79.lstatSync(candidate);
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
- fs79.closeSync(opened.fd);
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
- fs79.closeSync(opened.fd);
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 = path87.join(spec.logs_root, "candidate-evidence", "final-output");
78275
- const trajectoryPath = path87.join(spec.logs_root, "candidate-evidence", "trajectory.json");
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 = path87.join(spec.logs_root, "candidate-workspace-manifest.json");
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 = path87.resolve(spec.workspace_root, artifactRel);
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 || !fs79.existsSync(source) || !fs79.lstatSync(source).isFile()) {
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 = path87.resolve(spec.logs_root, "candidate-artifacts", artifactRel);
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 = path87.join(spec.logs_root, "candidate-workspace.tar.gz");
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
- fs79.renameSync(temporary, archive);
78902
+ fs80.renameSync(temporary, archive);
78320
78903
  } finally {
78321
- fs79.rmSync(temporary, { force: true });
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 = path87.resolve(specPathInput);
78421
- const noFollow = typeof fs79.constants.O_NOFOLLOW === "number" ? fs79.constants.O_NOFOLLOW : 0;
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 = fs79.openSync(specPath, fs79.constants.O_RDONLY | noFollow);
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 = fs79.fstatSync(fd);
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
- fs79.closeSync(fd);
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 = path87.resolve(resultPathInput);
78452
- const expectedResultPath = path87.join(path87.resolve(spec.logs_root), "result.json");
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 (fs79.existsSync(resultPath)) {
79062
+ if (fs80.existsSync(resultPath)) {
78480
79063
  try {
78481
- const cached2 = JSON.parse(fs79.readFileSync(resultPath, "utf8"));
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 = path87.resolve(resultPathInput);
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 = path87.join(path87.resolve(spec.logs_root), "result.json");
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 (fs79.existsSync(resultPath)) {
79171
+ if (fs80.existsSync(resultPath)) {
78589
79172
  try {
78590
- const cached2 = JSON.parse(fs79.readFileSync(resultPath, "utf8"));
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 = path88.join(os17.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto7.randomBytes(12).toString("hex")}`);
78787
- fs80.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
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 = fs80.openSync(temporary, "r");
78790
- fs80.unlinkSync(temporary);
79372
+ const fd = fs81.openSync(temporary, "r");
79373
+ fs81.unlinkSync(temporary);
78791
79374
  return fd;
78792
79375
  } catch (error2) {
78793
- fs80.rmSync(temporary, { force: true });
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
- fs80.closeSync(specFd);
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
- fs80.closeSync(specFd);
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 = fs80.readFileSync(specFd);
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 active tokens")}`);
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
- function getFlag(args, ...names) {
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 i = args.indexOf(n);
79153
- if (i >= 0) {
79154
- const v3 = args[i + 1];
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
- return;
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 = getFlag(args, ...names);
79802
+ let v3 = takeFlagOnce(args, names);
79164
79803
  while (v3 !== undefined) {
79165
79804
  if (v3)
79166
79805
  out.push(v3);
79167
- v3 = getFlag(args, ...names);
79806
+ v3 = takeFlagOnce(args, names);
79168
79807
  }
79169
79808
  return out;
79170
79809
  }
79171
- function hasFlag2(args, ...names) {
79172
- for (const n of names) {
79173
- const i = args.indexOf(n);
79174
- if (i >= 0) {
79175
- args.splice(i, 1);
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 fs81.realpathSync(rawCwd);
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": {