@brainbase-labs/cli 0.20.0 → 0.21.1

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