@brainbase-labs/cli 0.19.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +62 -0
  2. package/dist/index.js +2136 -142
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -35141,9 +35141,9 @@ var require_dist2 = __commonJS((exports, module) => {
35141
35141
  });
35142
35142
 
35143
35143
  // src/index.ts
35144
- var import_picocolors48 = __toESM(require_picocolors(), 1);
35144
+ var import_picocolors49 = __toESM(require_picocolors(), 1);
35145
35145
  import process14 from "node:process";
35146
- import fs79 from "node:fs";
35146
+ import fs81 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.19.1",
36011
+ version: "0.21.0",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -58081,45 +58081,59 @@ async function extract(opts) {
58081
58081
  const maxCount = opts.maxFileCount ?? MAX_FILE_COUNT;
58082
58082
  const maxRatio = opts.maxRatio ?? 100;
58083
58083
  let totalBytes = 0;
58084
- let fileCount = 0;
58084
+ let entryCount = 0;
58085
58085
  const written = [];
58086
+ let filterError;
58086
58087
  await co({
58087
58088
  file: opts.tarFile,
58088
58089
  cwd: out,
58089
58090
  strict: true,
58090
58091
  filter: (entryPath, entryAny) => {
58091
- const entry = entryAny;
58092
- const t = entry.type;
58093
- if (t !== "File" && t !== "OldFile" && t !== "ContiguousFile" && t !== "Directory" && t !== "GNUDumpDir") {
58094
- throw new TarballError(`refusing entry type "${t}" for ${entryPath}`);
58095
- }
58096
58092
  try {
58097
- safeRelPath(entryPath);
58098
- } catch (err) {
58099
- throw new TarballError(err.message);
58100
- }
58101
- const size2 = entry.size ?? 0;
58102
- if (size2 > maxBytes) {
58103
- throw new TarballError(`entry ${entryPath} size ${size2} exceeds cap ${maxBytes}`);
58104
- }
58105
- if (t === "Directory" || t === "GNUDumpDir")
58093
+ if (filterError)
58094
+ return false;
58095
+ const entry = entryAny;
58096
+ const t = entry.type;
58097
+ if (t !== "File" && t !== "OldFile" && t !== "ContiguousFile" && t !== "Directory" && t !== "GNUDumpDir") {
58098
+ throw new TarballError(`refusing entry type "${t}" for ${entryPath}`);
58099
+ }
58100
+ let normalizedPath;
58101
+ try {
58102
+ normalizedPath = safeRelPath(entryPath);
58103
+ } catch (err) {
58104
+ throw new TarballError(err.message);
58105
+ }
58106
+ if (normalizedPath.split("/").length > 64) {
58107
+ throw new TarballError(`entry path exceeds 64 segments: ${entryPath}`);
58108
+ }
58109
+ const size2 = entry.size ?? 0;
58110
+ if (size2 > maxBytes) {
58111
+ throw new TarballError(`entry ${entryPath} size ${size2} exceeds cap ${maxBytes}`);
58112
+ }
58113
+ entryCount++;
58114
+ if (entryCount > maxCount) {
58115
+ throw new TarballError(`too many entries (>${maxCount})`);
58116
+ }
58117
+ if (t === "Directory" || t === "GNUDumpDir")
58118
+ return true;
58119
+ totalBytes += size2;
58120
+ if (totalBytes > maxBytes) {
58121
+ throw new TarballError(`total uncompressed bytes ${totalBytes} exceeds cap ${maxBytes}`);
58122
+ }
58123
+ if (totalBytes > compressed * maxRatio) {
58124
+ throw new TarballError(`decompression ratio exceeds ${maxRatio}× (${totalBytes}B from ${compressed}B)`);
58125
+ }
58126
+ written.push(entryPath);
58106
58127
  return true;
58107
- fileCount++;
58108
- if (fileCount > maxCount) {
58109
- throw new TarballError(`too many entries (>${maxCount})`);
58110
- }
58111
- totalBytes += size2;
58112
- if (totalBytes > maxBytes) {
58113
- throw new TarballError(`total uncompressed bytes ${totalBytes} exceeds cap ${maxBytes}`);
58114
- }
58115
- if (totalBytes > compressed * maxRatio) {
58116
- throw new TarballError(`decompression ratio exceeds ${maxRatio}× (${totalBytes}B from ${compressed}B)`);
58128
+ } catch (error) {
58129
+ filterError = error instanceof TarballError ? error : new TarballError(error instanceof Error ? error.message : "invalid archive entry");
58130
+ return false;
58117
58131
  }
58118
- written.push(entryPath);
58119
- return true;
58120
58132
  },
58121
58133
  preserveOwner: false
58122
58134
  });
58135
+ if (filterError)
58136
+ throw filterError;
58123
58137
  return written;
58124
58138
  }
58125
58139
  async function sha256OfFile(filePath) {
@@ -61665,6 +61679,20 @@ var DEFAULT_INSTRUCTIONS_FILE = ".brainbase/instructions.md";
61665
61679
  var DEFAULT_ENTRYPOINT_FILE = ".brainbase/entrypoint.sh";
61666
61680
  var DEFAULT_PLAYBOOKS_DIR = ".brainbase/playbooks";
61667
61681
  var REGISTRY_SOURCE_RE = /^registry:(?:([a-z0-9_-]+)\/)?([a-z0-9_-]+)(?:@(.+))?$/i;
61682
+ var EXACT_VERSION_RE = /^\d+\.\d+\.\d+$/;
61683
+ function skillSourceVersionError(raw) {
61684
+ const m3 = raw.match(REGISTRY_SOURCE_RE);
61685
+ if (!m3) {
61686
+ if (!/^registry:/i.test(raw))
61687
+ return null;
61688
+ return `"${raw}" is not a valid registry source — expected ` + `"registry:creator/slug" or "registry:creator/slug@1.0.0".`;
61689
+ }
61690
+ const version = m3[3];
61691
+ if (!version || EXACT_VERSION_RE.test(version))
61692
+ return null;
61693
+ const head3 = m3[1] ? `${m3[1]}/${m3[2]}` : m3[2];
61694
+ return `"@${version}" is not supported — pin an exact version, e.g. ` + `"registry:${head3}@1.0.0", or drop the version to track the latest.`;
61695
+ }
61668
61696
  function parseSkillSource2(raw) {
61669
61697
  if (!raw || typeof raw !== "string") {
61670
61698
  throw new Error("Skill source must be a non-empty string");
@@ -61720,7 +61748,11 @@ var PlaybookSchema = exports_external.object({
61720
61748
  content: PlaybookContentSchema
61721
61749
  });
61722
61750
  var SkillEntrySchema = exports_external.object({
61723
- source: exports_external.string().min(1)
61751
+ source: exports_external.string().min(1).superRefine((raw, ctx) => {
61752
+ const message = skillSourceVersionError(raw);
61753
+ if (message)
61754
+ ctx.addIssue({ code: exports_external.ZodIssueCode.custom, message });
61755
+ })
61724
61756
  });
61725
61757
  var McpEntrySchema = exports_external.object({
61726
61758
  name: exports_external.string().min(1),
@@ -62924,6 +62956,7 @@ async function runSync(cwd2, args) {
62924
62956
  caps = capabilitiesFromManifest(readManifest(cwd2));
62925
62957
  } catch (err) {
62926
62958
  f2.error(err.message);
62959
+ process.exitCode = 1;
62927
62960
  return;
62928
62961
  }
62929
62962
  const declaredMcpSlugs = new Set(manifest.components.filter((c2) => c2.type === "mcp").map((c2) => c2.slug));
@@ -63683,6 +63716,7 @@ async function runAgentUnpack(cwd2, args) {
63683
63716
  manifest = readManifest(cwd2);
63684
63717
  } catch (err) {
63685
63718
  f2.error(err.message);
63719
+ process.exitCode = 1;
63686
63720
  return;
63687
63721
  }
63688
63722
  if (!manifest.id) {
@@ -64237,6 +64271,7 @@ function resolveTargetAgentId(cwd2, args) {
64237
64271
  manifest = hasManifest(cwd2) ? readManifest(cwd2) : null;
64238
64272
  } catch (err) {
64239
64273
  f2.error(err.message);
64274
+ process.exitCode = 1;
64240
64275
  return null;
64241
64276
  }
64242
64277
  const manifestId = manifest?.id;
@@ -64821,6 +64856,7 @@ async function runAgentPush(cwd2, args) {
64821
64856
  manifest = readManifest(cwd2);
64822
64857
  } catch (err) {
64823
64858
  f2.error(err.message);
64859
+ process.exitCode = 1;
64824
64860
  return;
64825
64861
  }
64826
64862
  if (!manifest.id) {
@@ -65374,13 +65410,27 @@ async function runAgentStatus(cwd2) {
65374
65410
  break;
65375
65411
  }
65376
65412
  }
65413
+ let secretDrift = {
65414
+ localOnly: [],
65415
+ cloudOnly: [],
65416
+ changed: []
65417
+ };
65418
+ try {
65419
+ const localSecrets = readLocalSecrets(cwd2);
65420
+ const cloudRes = await api.getAgentSecrets(link2.agent_id);
65421
+ secretDrift = diffSecrets(localSecrets, cloudRes.secrets ?? {});
65422
+ } catch {}
65423
+ const componentsDrifted = conflicts.length > 0 || toPush.length > 0 || toPull.length > 0;
65424
+ const metaDrifted = meta.localChanged || meta.cloudChanged;
65425
+ const configDrifted = config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged;
65426
+ const secretsDrifted = secretDrift.localOnly.length > 0 || secretDrift.cloudOnly.length > 0 || secretDrift.changed.length > 0;
65377
65427
  const lines = [];
65378
65428
  lines.push("");
65379
65429
  lines.push(` ${import_picocolors29.default.bold(link2.name)} ${import_picocolors29.default.dim(`(${link2.slug})`)}`);
65380
65430
  lines.push(` ${import_picocolors29.default.dim("agent_id")} ${link2.agent_id}`);
65381
65431
  lines.push(` ${import_picocolors29.default.dim("revision")} cloud ${cloud.revision}${lock ? ` · lock ${lock.revision}` : " · never pulled"}`);
65382
65432
  lines.push("");
65383
- if (meta.localChanged || meta.cloudChanged) {
65433
+ if (metaDrifted) {
65384
65434
  lines.push(` ${import_picocolors29.default.bold("agent metadata")}`);
65385
65435
  if (meta.localChanged) {
65386
65436
  lines.push(` ${import_picocolors29.default.yellow("→ push")} name/tagline edited in brainbase.agent.yaml`);
@@ -65390,7 +65440,7 @@ async function runAgentStatus(cwd2) {
65390
65440
  }
65391
65441
  lines.push("");
65392
65442
  }
65393
- if (config.unsupported.length > 0 || config.machineMismatch || config.machineCloudChanged || config.defaultModelLocalChanged || config.defaultModelCloudChanged) {
65443
+ if (configDrifted) {
65394
65444
  lines.push(` ${import_picocolors29.default.bold("runtime config")}`);
65395
65445
  if (config.unsupported.length > 0) {
65396
65446
  lines.push(` ${import_picocolors29.default.red("! unsupported")} ${config.unsupported.join(", ")} not exposed by this control plane`);
@@ -65413,23 +65463,17 @@ async function runAgentStatus(cwd2) {
65413
65463
  }
65414
65464
  lines.push("");
65415
65465
  }
65416
- try {
65417
- const localSecrets = readLocalSecrets(cwd2);
65418
- const cloudRes = await api.getAgentSecrets(link2.agent_id);
65419
- const cloudSecrets = cloudRes.secrets ?? {};
65420
- const sd = diffSecrets(localSecrets, cloudSecrets);
65421
- if (sd.localOnly.length || sd.cloudOnly.length || sd.changed.length) {
65422
- lines.push(` ${import_picocolors29.default.bold("secrets")}`);
65423
- if (sd.localOnly.length)
65424
- lines.push(` ${import_picocolors29.default.yellow("→ push")} new locally: ${sd.localOnly.join(", ")}`);
65425
- if (sd.changed.length)
65426
- lines.push(` ${import_picocolors29.default.yellow("→ push")} values changed: ${sd.changed.join(", ")}`);
65427
- if (sd.cloudOnly.length)
65428
- lines.push(` ${import_picocolors29.default.cyan("← pull")} new on cloud: ${sd.cloudOnly.join(", ")}`);
65429
- lines.push("");
65430
- }
65431
- } catch {}
65432
- 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) {
65466
+ if (secretsDrifted) {
65467
+ lines.push(` ${import_picocolors29.default.bold("secrets")}`);
65468
+ if (secretDrift.localOnly.length)
65469
+ lines.push(` ${import_picocolors29.default.yellow("→ push")} new locally: ${secretDrift.localOnly.join(", ")}`);
65470
+ if (secretDrift.changed.length)
65471
+ lines.push(` ${import_picocolors29.default.yellow("→ push")} values changed: ${secretDrift.changed.join(", ")}`);
65472
+ if (secretDrift.cloudOnly.length)
65473
+ lines.push(` ${import_picocolors29.default.cyan("← pull")} new on cloud: ${secretDrift.cloudOnly.join(", ")}`);
65474
+ lines.push("");
65475
+ }
65476
+ if (!componentsDrifted && !metaDrifted && !configDrifted && !secretsDrifted) {
65433
65477
  lines.push(` ${import_picocolors29.default.green("✓")} everything is in sync`);
65434
65478
  lines.push("");
65435
65479
  console.log(lines.join(`
@@ -65968,6 +66012,7 @@ async function loadOrScaffoldManifest(cwd2, args) {
65968
66012
  return readManifest(cwd2);
65969
66013
  } catch (err) {
65970
66014
  f2.error(err.message);
66015
+ process.exitCode = 1;
65971
66016
  return null;
65972
66017
  }
65973
66018
  }
@@ -67763,15 +67808,11 @@ async function runRun(cwd2, args) {
67763
67808
 
67764
67809
  // src/cli/publish.ts
67765
67810
  var import_picocolors44 = __toESM(require_picocolors(), 1);
67766
- async function runPublish(cwd2, _args) {
67767
- banner("publish — send your changes to the team");
67768
- const link2 = readLink(cwd2);
67769
- if (!link2) {
67770
- f2.warn("This folder is not linked to any agent.");
67771
- f2.info(`Run ${import_picocolors44.default.cyan("brainbase link")} first.`);
67772
- return;
67773
- }
67774
- 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.`);
67811
+ function runPublish() {
67812
+ banner("publish — moved");
67813
+ f2.error(`${import_picocolors44.default.bold("brainbase publish")} does not exist.`);
67814
+ f2.info(`Use ${import_picocolors44.default.cyan("brainbase agent push")} to send your local changes to the cloud.`);
67815
+ process.exit(1);
67775
67816
  }
67776
67817
 
67777
67818
  // src/ui/ink/StatusCard.tsx
@@ -77030,6 +77071,1934 @@ function printHelp4() {
77030
77071
  `));
77031
77072
  }
77032
77073
 
77074
+ // src/cli/benchmark.ts
77075
+ var import_picocolors48 = __toESM(require_picocolors(), 1);
77076
+ import {
77077
+ execFileSync as execFileSync3,
77078
+ spawn as spawn5
77079
+ } from "node:child_process";
77080
+ import crypto7 from "node:crypto";
77081
+ import fs80 from "node:fs";
77082
+ import os17 from "node:os";
77083
+ import path88 from "node:path";
77084
+
77085
+ // src/core/benchmark-phase.ts
77086
+ import {
77087
+ execFileSync as execFileSync2,
77088
+ spawn as spawn4
77089
+ } from "node:child_process";
77090
+ import crypto6 from "node:crypto";
77091
+ import fs79 from "node:fs";
77092
+ import os16 from "node:os";
77093
+ import path87 from "node:path";
77094
+ import { pipeline as pipeline2 } from "node:stream/promises";
77095
+ var SCHEMA_VERSION = "1";
77096
+ var SHA256_RE = /^[a-f0-9]{64}$/i;
77097
+ var ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
77098
+ var ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
77099
+ var MAX_SPEC_BYTES = 20 * 1024 * 1024;
77100
+ var MAX_FINAL_OUTPUT_BYTES = 10 * 1024 * 1024;
77101
+ var MAX_TRAJECTORY_BYTES = 100 * 1024 * 1024;
77102
+ var RESERVED_WORKSPACE_PATHS = new Set([
77103
+ ".brainbase",
77104
+ ".git",
77105
+ "brainbase.agent.yaml"
77106
+ ]);
77107
+ var BASE_ENV_NAMES = [
77108
+ "HOME",
77109
+ "LANG",
77110
+ "LC_ALL",
77111
+ "LOGNAME",
77112
+ "PATH",
77113
+ "SHELL",
77114
+ "TMPDIR",
77115
+ "USER"
77116
+ ];
77117
+ var SENSITIVE_ENV_NAME_RE = /(?:^|_)(?:TOKEN|SECRET|PASSWORD|PASSWD|API_KEY|PRIVATE_KEY|ACCESS_KEY|PAT|CREDENTIAL)(?:$|_)|^(?:PGPASSWORD|DATABASE_URL|REDIS_URL|MONGODB_URI)$/i;
77118
+ var AbsolutePathSchema = exports_external.string().min(1).refine(path87.isAbsolute, {
77119
+ message: "must be an absolute path"
77120
+ });
77121
+ var Sha256Schema = exports_external.string().regex(SHA256_RE).transform((value) => value.toLowerCase());
77122
+ var IdSchema = exports_external.string().regex(ID_RE);
77123
+ var EnvNameSchema = exports_external.string().regex(ENV_NAME_RE);
77124
+ var NonSecretEnvironmentValueSchema = exports_external.object({
77125
+ value: exports_external.string(),
77126
+ sensitive: exports_external.literal(false)
77127
+ }).strict();
77128
+ var RootRelativePathSchema = exports_external.string().min(1).max(1024);
77129
+ var BudgetSchema = exports_external.object({
77130
+ timeout_ms: exports_external.number().int().min(100).max(3600000),
77131
+ max_output_bytes: exports_external.number().int().min(1024).max(100 * 1024 * 1024)
77132
+ }).strict();
77133
+ var MaterialSchema = exports_external.object({
77134
+ id: IdSchema,
77135
+ kind: exports_external.enum(["file", "tar_gz"]),
77136
+ source: RootRelativePathSchema,
77137
+ destination: RootRelativePathSchema,
77138
+ sha256: Sha256Schema,
77139
+ size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024),
77140
+ mode: exports_external.number().int().min(0).max(511).optional(),
77141
+ max_unpacked_bytes: exports_external.number().int().min(1).max(2 * 1024 * 1024 * 1024).optional(),
77142
+ max_file_count: exports_external.number().int().min(1).max(1e5).optional()
77143
+ }).strict();
77144
+ var CommandSchema = exports_external.object({
77145
+ id: IdSchema,
77146
+ argv: exports_external.array(exports_external.string().min(1)).min(1).max(128),
77147
+ cwd: RootRelativePathSchema.default("."),
77148
+ timeout_ms: exports_external.number().int().min(100).max(3600000).optional(),
77149
+ secret_env: exports_external.array(EnvNameSchema).max(100).default([])
77150
+ }).strict();
77151
+ var BaseSpecSchema = exports_external.object({
77152
+ schema_version: exports_external.literal(SCHEMA_VERSION),
77153
+ attempt_id: exports_external.string().uuid(),
77154
+ phase_id: IdSchema,
77155
+ workspace_root: AbsolutePathSchema,
77156
+ staging_root: AbsolutePathSchema,
77157
+ logs_root: AbsolutePathSchema,
77158
+ budget: BudgetSchema,
77159
+ environment: exports_external.record(EnvNameSchema, NonSecretEnvironmentValueSchema).default({}),
77160
+ secret_env: exports_external.array(EnvNameSchema).max(100).default([])
77161
+ }).strict();
77162
+ var OutputAssertionSchema = exports_external.discriminatedUnion("operator", [
77163
+ exports_external.object({ operator: exports_external.literal("exact"), expected: exports_external.string() }).strict(),
77164
+ exports_external.object({ operator: exports_external.literal("contains"), expected: exports_external.string() }).strict(),
77165
+ exports_external.object({
77166
+ operator: exports_external.literal("regex"),
77167
+ pattern: exports_external.string().max(4096),
77168
+ flags: exports_external.string().regex(/^[imsu]*$/).default("")
77169
+ }).strict()
77170
+ ]);
77171
+ var WorkspaceAssertionSchema = exports_external.discriminatedUnion("operator", [
77172
+ exports_external.object({ operator: exports_external.literal("exists") }).strict(),
77173
+ exports_external.object({ operator: exports_external.literal("not_exists") }).strict(),
77174
+ exports_external.object({ operator: exports_external.literal("sha256"), expected: Sha256Schema }).strict(),
77175
+ exports_external.object({ operator: exports_external.literal("contains"), expected: exports_external.string() }).strict()
77176
+ ]);
77177
+ var EvaluatorBase = {
77178
+ id: IdSchema,
77179
+ required: exports_external.boolean().default(true),
77180
+ primary: exports_external.boolean().default(false)
77181
+ };
77182
+ var EvaluatorSchema = exports_external.discriminatedUnion("type", [
77183
+ exports_external.object({
77184
+ ...EvaluatorBase,
77185
+ type: exports_external.literal("output_assertion"),
77186
+ assertion: OutputAssertionSchema
77187
+ }).strict(),
77188
+ exports_external.object({
77189
+ ...EvaluatorBase,
77190
+ type: exports_external.literal("trajectory_assertion"),
77191
+ event_type: exports_external.string().min(1).max(256),
77192
+ min_count: exports_external.number().int().min(0).default(1),
77193
+ max_count: exports_external.number().int().min(0).optional()
77194
+ }).strict(),
77195
+ exports_external.object({
77196
+ ...EvaluatorBase,
77197
+ type: exports_external.literal("workspace_assertion"),
77198
+ path: RootRelativePathSchema,
77199
+ assertion: WorkspaceAssertionSchema
77200
+ }).strict(),
77201
+ exports_external.object({
77202
+ ...EvaluatorBase,
77203
+ type: exports_external.literal("sandbox_command"),
77204
+ command: CommandSchema.omit({ id: true }),
77205
+ root: exports_external.enum(["workspace", "tests"]).default("tests")
77206
+ }).strict()
77207
+ ]);
77208
+ var EvidenceFileSchema = exports_external.object({
77209
+ source: RootRelativePathSchema,
77210
+ sha256: Sha256Schema,
77211
+ size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
77212
+ }).strict();
77213
+ var FinalOutputEvidenceSchema = EvidenceFileSchema.extend({
77214
+ size_bytes: exports_external.number().int().min(0).max(MAX_FINAL_OUTPUT_BYTES)
77215
+ }).strict();
77216
+ var TrajectoryEvidenceSchema = EvidenceFileSchema.extend({
77217
+ size_bytes: exports_external.number().int().min(0).max(MAX_TRAJECTORY_BYTES)
77218
+ }).strict();
77219
+ var HydrateSpecSchema = BaseSpecSchema.extend({
77220
+ phase: exports_external.literal("hydrate"),
77221
+ materials: exports_external.array(MaterialSchema).max(1e4).default([]),
77222
+ setup_commands: exports_external.array(CommandSchema).max(128).default([])
77223
+ }).strict();
77224
+ var EvaluateSpecSchema = BaseSpecSchema.extend({
77225
+ phase: exports_external.literal("evaluate"),
77226
+ tests_root: AbsolutePathSchema,
77227
+ evidence: exports_external.object({
77228
+ final_output: FinalOutputEvidenceSchema,
77229
+ trajectory: TrajectoryEvidenceSchema
77230
+ }).strict(),
77231
+ references: exports_external.array(MaterialSchema).max(1e4).default([]),
77232
+ evaluators: exports_external.array(EvaluatorSchema).min(1).max(1000),
77233
+ candidate_artifacts: exports_external.array(RootRelativePathSchema).max(1000).default([]),
77234
+ capture_workspace_archive: exports_external.boolean().default(false),
77235
+ workspace_limits: exports_external.object({
77236
+ max_file_count: exports_external.number().int().min(1).max(1e6).default(1e5),
77237
+ max_total_bytes: exports_external.number().int().min(1).max(20 * 1024 * 1024 * 1024).default(2 * 1024 * 1024 * 1024)
77238
+ }).strict().default({})
77239
+ }).strict();
77240
+ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
77241
+ HydrateSpecSchema,
77242
+ EvaluateSpecSchema
77243
+ ]).superRefine((value, context) => {
77244
+ for (const name of Object.keys(value.environment)) {
77245
+ if (SENSITIVE_ENV_NAME_RE.test(name)) {
77246
+ context.addIssue({
77247
+ code: exports_external.ZodIssueCode.custom,
77248
+ path: ["environment", name],
77249
+ message: "credential-like values must be supplied through secret_env"
77250
+ });
77251
+ }
77252
+ }
77253
+ const declaredSecrets = new Set(value.secret_env);
77254
+ const commands = value.phase === "hydrate" ? value.setup_commands.map((command, index) => ({
77255
+ command,
77256
+ path: ["setup_commands", index, "secret_env"]
77257
+ })) : value.evaluators.flatMap((evaluator, index) => evaluator.type === "sandbox_command" ? [{
77258
+ command: evaluator.command,
77259
+ path: ["evaluators", index, "command", "secret_env"]
77260
+ }] : []);
77261
+ for (const { command, path: issuePath } of commands) {
77262
+ for (const name of command.secret_env) {
77263
+ if (!declaredSecrets.has(name)) {
77264
+ context.addIssue({
77265
+ code: exports_external.ZodIssueCode.custom,
77266
+ path: issuePath,
77267
+ message: `command secret_env references undeclared binding: ${name}`
77268
+ });
77269
+ }
77270
+ }
77271
+ }
77272
+ const uniqueLists = value.phase === "hydrate" ? [
77273
+ { items: value.materials, path: "materials" },
77274
+ { items: value.setup_commands, path: "setup_commands" }
77275
+ ] : [
77276
+ { items: value.references, path: "references" },
77277
+ { items: value.evaluators, path: "evaluators" }
77278
+ ];
77279
+ for (const { items, path: issuePath } of uniqueLists) {
77280
+ const ids = items.map((item) => item.id);
77281
+ if (new Set(ids).size !== ids.length) {
77282
+ context.addIssue({
77283
+ code: exports_external.ZodIssueCode.custom,
77284
+ path: [issuePath],
77285
+ message: `${issuePath} ids must be unique`
77286
+ });
77287
+ }
77288
+ }
77289
+ if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length > 1) {
77290
+ context.addIssue({
77291
+ code: exports_external.ZodIssueCode.custom,
77292
+ path: ["evaluators"],
77293
+ message: "schema version 1 supports at most one sandbox_command evaluator"
77294
+ });
77295
+ }
77296
+ });
77297
+ var BENCHMARK_CAPABILITIES = {
77298
+ contract: "brainbase.benchmark.phase",
77299
+ cli_version: VERSION,
77300
+ schema_versions: [SCHEMA_VERSION],
77301
+ phases: ["hydrate", "evaluate"],
77302
+ evaluator_types: [
77303
+ "output_assertion",
77304
+ "trajectory_assertion",
77305
+ "workspace_assertion",
77306
+ "sandbox_command"
77307
+ ],
77308
+ limits: {
77309
+ max_secret_bindings: 100,
77310
+ max_evaluators: 1000,
77311
+ max_sandbox_commands: 1
77312
+ }
77313
+ };
77314
+
77315
+ class BenchmarkPhaseError extends Error {
77316
+ code;
77317
+ details;
77318
+ constructor(code, message, details) {
77319
+ super(message);
77320
+ this.code = code;
77321
+ this.details = details;
77322
+ this.name = "BenchmarkPhaseError";
77323
+ }
77324
+ }
77325
+ function nowIso() {
77326
+ return new Date().toISOString();
77327
+ }
77328
+ function normalizedRootRelative(input) {
77329
+ if (input === ".")
77330
+ return ".";
77331
+ return safeRelPath(input);
77332
+ }
77333
+ function isWithin(root, candidate) {
77334
+ const relative = path87.relative(path87.resolve(root), path87.resolve(candidate));
77335
+ return relative === "" || !relative.startsWith("..") && !path87.isAbsolute(relative);
77336
+ }
77337
+ function canonicalFuturePath(input) {
77338
+ const resolved = path87.resolve(input);
77339
+ const suffix = [];
77340
+ let current = resolved;
77341
+ while (!fs79.existsSync(current)) {
77342
+ const parent = path87.dirname(current);
77343
+ if (parent === current)
77344
+ break;
77345
+ suffix.unshift(path87.basename(current));
77346
+ current = parent;
77347
+ }
77348
+ const canonicalBase = fs79.realpathSync(current);
77349
+ return path87.join(canonicalBase, ...suffix);
77350
+ }
77351
+ function validateRoots(spec) {
77352
+ const workspace = path87.resolve(spec.workspace_root);
77353
+ if (!fs79.existsSync(workspace) || fs79.lstatSync(workspace).isSymbolicLink() || !fs79.lstatSync(workspace).isDirectory()) {
77354
+ throw new BenchmarkPhaseError("invalid_workspace_root", "workspace_root must be an existing real directory");
77355
+ }
77356
+ const canonicalWorkspace = canonicalFuturePath(workspace);
77357
+ const staging = path87.resolve(spec.staging_root);
77358
+ const expectedStaging = path87.join(workspace, ".brainbase", "benchmark", spec.attempt_id, "incoming");
77359
+ if (staging !== expectedStaging) {
77360
+ throw new BenchmarkPhaseError("invalid_staging_root", `staging_root must be ${expectedStaging}`);
77361
+ }
77362
+ if (!fs79.existsSync(staging) || fs79.lstatSync(staging).isSymbolicLink() || !fs79.lstatSync(staging).isDirectory() || fs79.realpathSync(staging) !== path87.join(canonicalWorkspace, ".brainbase", "benchmark", spec.attempt_id, "incoming")) {
77363
+ throw new BenchmarkPhaseError("invalid_staging_root", "staging_root must be a real directory under workspace_root");
77364
+ }
77365
+ const canonicalLogs = validateExternalRoot("logs_root", spec.logs_root, canonicalWorkspace);
77366
+ if (spec.phase === "evaluate") {
77367
+ const canonicalTests = validateExternalRoot("tests_root", spec.tests_root, canonicalWorkspace);
77368
+ if (isWithin(canonicalTests, canonicalLogs) || isWithin(canonicalLogs, canonicalTests)) {
77369
+ throw new BenchmarkPhaseError("invalid_tests_root", "tests_root and logs_root must be disjoint");
77370
+ }
77371
+ }
77372
+ }
77373
+ function validateExternalRoot(label, input, canonicalWorkspace) {
77374
+ const candidate = path87.resolve(input);
77375
+ if (candidate === path87.parse(candidate).root) {
77376
+ throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a filesystem root`);
77377
+ }
77378
+ if (fs79.existsSync(candidate) && fs79.lstatSync(candidate).isSymbolicLink()) {
77379
+ throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot be a symlink`);
77380
+ }
77381
+ const canonicalCandidate = canonicalFuturePath(candidate);
77382
+ if (isWithin(canonicalWorkspace, canonicalCandidate)) {
77383
+ throw new BenchmarkPhaseError(`invalid_${label}`, `${label} must be outside workspace_root`);
77384
+ }
77385
+ if (isWithin(canonicalCandidate, canonicalWorkspace)) {
77386
+ throw new BenchmarkPhaseError(`invalid_${label}`, `${label} cannot contain workspace_root`);
77387
+ }
77388
+ return canonicalCandidate;
77389
+ }
77390
+ function workspaceRel(input, allowRoot = false) {
77391
+ const rel = normalizedRootRelative(input);
77392
+ if (rel === "." && !allowRoot) {
77393
+ throw new BenchmarkPhaseError("unsafe_path", "destination cannot be the workspace root");
77394
+ }
77395
+ const first = rel.split("/")[0].toLowerCase();
77396
+ if (RESERVED_WORKSPACE_PATHS.has(first)) {
77397
+ throw new BenchmarkPhaseError("reserved_path", `benchmark input cannot replace ${first}`);
77398
+ }
77399
+ return rel;
77400
+ }
77401
+ function assertNoSymlinkTraversal(root, relative) {
77402
+ const rel = normalizedRootRelative(relative);
77403
+ if (rel === ".")
77404
+ return;
77405
+ let current = path87.resolve(root);
77406
+ for (const segment of rel.split("/").slice(0, -1)) {
77407
+ current = path87.join(current, segment);
77408
+ if (!fs79.existsSync(current))
77409
+ continue;
77410
+ if (fs79.lstatSync(current).isSymbolicLink()) {
77411
+ throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
77412
+ }
77413
+ }
77414
+ }
77415
+ function assertOpenedFileWithinRoot(root, filePath, openedStat, label) {
77416
+ let canonicalRoot;
77417
+ let canonicalFile;
77418
+ let currentStat;
77419
+ try {
77420
+ canonicalRoot = fs79.realpathSync(root);
77421
+ canonicalFile = fs79.realpathSync(filePath);
77422
+ currentStat = fs79.statSync(filePath);
77423
+ } catch {
77424
+ throw new BenchmarkPhaseError("unsafe_path", `${label} changed while it was opened`);
77425
+ }
77426
+ if (!isWithin(canonicalRoot, canonicalFile) || currentStat.dev !== openedStat.dev || currentStat.ino !== openedStat.ino) {
77427
+ throw new BenchmarkPhaseError("unsafe_path", `${label} escapes its declared root`);
77428
+ }
77429
+ }
77430
+ function openRegularFileNoFollow(filePath, label, root) {
77431
+ const noFollow = typeof fs79.constants.O_NOFOLLOW === "number" ? fs79.constants.O_NOFOLLOW : 0;
77432
+ let fd;
77433
+ try {
77434
+ fd = fs79.openSync(filePath, fs79.constants.O_RDONLY | noFollow);
77435
+ } catch (error2) {
77436
+ const code = error2.code;
77437
+ if (code === "ELOOP") {
77438
+ throw new BenchmarkPhaseError("unsafe_path", `${label} cannot be a symlink`);
77439
+ }
77440
+ throw error2;
77441
+ }
77442
+ const stat = fs79.fstatSync(fd);
77443
+ if (!stat.isFile()) {
77444
+ fs79.closeSync(fd);
77445
+ throw new BenchmarkPhaseError("invalid_input", `${label} must be a regular file`);
77446
+ }
77447
+ if (root) {
77448
+ try {
77449
+ assertOpenedFileWithinRoot(root, filePath, stat, label);
77450
+ } catch (error2) {
77451
+ fs79.closeSync(fd);
77452
+ throw error2;
77453
+ }
77454
+ }
77455
+ return { fd, stat };
77456
+ }
77457
+ async function sha256OfDescriptor(fd) {
77458
+ const hash = crypto6.createHash("sha256");
77459
+ const stream = fs79.createReadStream("", {
77460
+ fd,
77461
+ autoClose: false,
77462
+ start: 0
77463
+ });
77464
+ for await (const chunk2 of stream) {
77465
+ hash.update(chunk2);
77466
+ }
77467
+ return hash.digest("hex");
77468
+ }
77469
+ function readDescriptor(fd) {
77470
+ return fs79.readFileSync(fd);
77471
+ }
77472
+ function assertWritableDestination(root, relative) {
77473
+ const rel = normalizedRootRelative(relative);
77474
+ if (rel === ".")
77475
+ return;
77476
+ let current = path87.resolve(root);
77477
+ const segments = rel.split("/");
77478
+ for (const segment of segments.slice(0, -1)) {
77479
+ current = path87.join(current, segment);
77480
+ if (!fs79.existsSync(current))
77481
+ continue;
77482
+ const stat = fs79.lstatSync(current);
77483
+ if (stat.isSymbolicLink()) {
77484
+ throw new BenchmarkPhaseError("unsafe_path", `path traverses symlink: ${relative}`);
77485
+ }
77486
+ if (!stat.isDirectory()) {
77487
+ throw new BenchmarkPhaseError("destination_conflict", `destination parent is not a directory: ${relative}`);
77488
+ }
77489
+ }
77490
+ const destination = path87.resolve(root, rel);
77491
+ if (fs79.existsSync(destination) && fs79.lstatSync(destination).isDirectory()) {
77492
+ throw new BenchmarkPhaseError("destination_conflict", `file destination is an existing directory: ${relative}`);
77493
+ }
77494
+ }
77495
+ function validateDestinationGraph(paths) {
77496
+ const portablePaths = new Map;
77497
+ for (const candidate of paths) {
77498
+ const key2 = candidate.toLowerCase();
77499
+ const existing = portablePaths.get(key2);
77500
+ if (existing && existing !== candidate) {
77501
+ throw new BenchmarkPhaseError("destination_conflict", `destination ${candidate} conflicts by case with ${existing}`);
77502
+ }
77503
+ portablePaths.set(key2, candidate);
77504
+ }
77505
+ const sorted = [...portablePaths.keys()].sort();
77506
+ for (let index = 0;index < sorted.length - 1; index += 1) {
77507
+ const current = sorted[index];
77508
+ const next = sorted[index + 1];
77509
+ if (next.startsWith(`${current}/`)) {
77510
+ throw new BenchmarkPhaseError("destination_conflict", `destination ${current} conflicts with descendant ${next}`);
77511
+ }
77512
+ }
77513
+ }
77514
+ function sourcePath(stagingRoot, relative) {
77515
+ const rel = safeRelPath(relative);
77516
+ const source = path87.resolve(stagingRoot, rel);
77517
+ if (!isWithin(stagingRoot, source)) {
77518
+ throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${relative}`);
77519
+ }
77520
+ assertNoSymlinkTraversal(stagingRoot, rel);
77521
+ let stat;
77522
+ try {
77523
+ stat = fs79.lstatSync(source);
77524
+ } catch {
77525
+ throw new BenchmarkPhaseError("missing_input", `staged input does not exist: ${relative}`);
77526
+ }
77527
+ if (!stat.isFile()) {
77528
+ throw new BenchmarkPhaseError("invalid_input", `staged input must be a regular file: ${relative}`);
77529
+ }
77530
+ return source;
77531
+ }
77532
+ function rootForRecord(spec, rootName) {
77533
+ if (rootName === "workspace")
77534
+ return spec.workspace_root;
77535
+ if (rootName === "staging")
77536
+ return spec.staging_root;
77537
+ if (rootName === "logs")
77538
+ return spec.logs_root;
77539
+ if (rootName === "tests" && spec.phase === "evaluate")
77540
+ return spec.tests_root;
77541
+ return null;
77542
+ }
77543
+ async function verifyRecordsUnchanged(records, spec) {
77544
+ for (const record3 of records) {
77545
+ const root = rootForRecord(spec, record3.root);
77546
+ if (!root) {
77547
+ throw new BenchmarkPhaseError("evidence_tampered", `unknown evidence root: ${record3.root}`);
77548
+ }
77549
+ const relative = safeRelPath(record3.path);
77550
+ assertNoSymlinkTraversal(root, relative);
77551
+ const candidate = path87.resolve(root, relative);
77552
+ if (!isWithin(root, candidate) || !fs79.existsSync(candidate)) {
77553
+ throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
77554
+ }
77555
+ const stat = fs79.lstatSync(candidate);
77556
+ if (record3.kind === "symlink") {
77557
+ const target = stat.isSymbolicLink() ? fs79.readlinkSync(candidate) : null;
77558
+ if (target === null || Buffer.byteLength(target) !== record3.size || sha256(target) !== record3.sha256) {
77559
+ throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
77560
+ }
77561
+ continue;
77562
+ }
77563
+ if (!stat.isFile()) {
77564
+ throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
77565
+ }
77566
+ const opened = openRegularFileNoFollow(candidate, `evidence ${record3.root}:${record3.path}`, root);
77567
+ try {
77568
+ if (opened.stat.size !== record3.size || await sha256OfDescriptor(opened.fd) !== record3.sha256) {
77569
+ throw new BenchmarkPhaseError("evidence_tampered", `evidence changed during evaluation: ${record3.root}:${record3.path}`);
77570
+ }
77571
+ } finally {
77572
+ fs79.closeSync(opened.fd);
77573
+ }
77574
+ }
77575
+ }
77576
+ async function verifyInput(stagingRoot, material) {
77577
+ const source = sourcePath(stagingRoot, material.source);
77578
+ const opened = openRegularFileNoFollow(source, `staged input ${material.source}`, stagingRoot);
77579
+ try {
77580
+ if (opened.stat.size !== material.size_bytes) {
77581
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${material.source}`, { expected: material.size_bytes, actual: opened.stat.size });
77582
+ }
77583
+ const actual = await sha256OfDescriptor(opened.fd);
77584
+ if (actual !== material.sha256) {
77585
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
77586
+ }
77587
+ } finally {
77588
+ fs79.closeSync(opened.fd);
77589
+ }
77590
+ return source;
77591
+ }
77592
+ async function atomicCopy(source, destination, mode, sourceRoot) {
77593
+ fs79.mkdirSync(path87.dirname(destination), { recursive: true });
77594
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
77595
+ const opened = openRegularFileNoFollow(source, `copy source ${source}`, sourceRoot);
77596
+ try {
77597
+ await pipeline2(fs79.createReadStream("", {
77598
+ fd: opened.fd,
77599
+ autoClose: false,
77600
+ start: 0
77601
+ }), fs79.createWriteStream(temporary, {
77602
+ flags: "wx",
77603
+ mode: 384
77604
+ }));
77605
+ fs79.chmodSync(temporary, mode ?? opened.stat.mode & 511);
77606
+ fs79.renameSync(temporary, destination);
77607
+ } finally {
77608
+ fs79.closeSync(opened.fd);
77609
+ fs79.rmSync(temporary, { force: true });
77610
+ }
77611
+ }
77612
+ async function recordFile(root, filePath, rootName, kind = "file") {
77613
+ const relative = path87.relative(root, filePath).replace(/\\/g, "/");
77614
+ if (kind === "symlink") {
77615
+ const stat = fs79.lstatSync(filePath);
77616
+ const target = fs79.readlinkSync(filePath);
77617
+ return {
77618
+ root: rootName,
77619
+ path: relative,
77620
+ sha256: sha256(target),
77621
+ size: Buffer.byteLength(target),
77622
+ mode: stat.mode & 511,
77623
+ kind
77624
+ };
77625
+ }
77626
+ const opened = openRegularFileNoFollow(filePath, `${rootName} file ${relative}`, root);
77627
+ try {
77628
+ return {
77629
+ root: rootName,
77630
+ path: relative,
77631
+ sha256: await sha256OfDescriptor(opened.fd),
77632
+ size: opened.stat.size,
77633
+ mode: opened.stat.mode & 511
77634
+ };
77635
+ } finally {
77636
+ fs79.closeSync(opened.fd);
77637
+ }
77638
+ }
77639
+ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
77640
+ const source = await verifyInput(sourceRoot, material);
77641
+ const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
77642
+ if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
77643
+ throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
77644
+ }
77645
+ if (material.kind === "file") {
77646
+ if (destinationRel === ".") {
77647
+ throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
77648
+ }
77649
+ assertWritableDestination(destinationRoot, destinationRel);
77650
+ const destination = path87.resolve(destinationRoot, destinationRel);
77651
+ await atomicCopy(source, destination, material.mode, sourceRoot);
77652
+ const record3 = await recordFile(destinationRoot, destination, destinationRootName);
77653
+ if (record3.sha256 !== material.sha256 || record3.size !== material.size_bytes) {
77654
+ throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
77655
+ }
77656
+ return [record3];
77657
+ }
77658
+ const temporary = fs79.mkdtempSync(path87.join(os16.tmpdir(), "brainbase-benchmark-"));
77659
+ try {
77660
+ const verifiedArchive = path87.join(temporary, "material.tar.gz");
77661
+ await atomicCopy(source, verifiedArchive, 384, sourceRoot);
77662
+ const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
77663
+ if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
77664
+ throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
77665
+ }
77666
+ const extractedRoot = path87.join(temporary, "extracted");
77667
+ const extracted = await extract({
77668
+ tarFile: verifiedArchive,
77669
+ outDir: extractedRoot,
77670
+ maxTotalBytes: material.max_unpacked_bytes,
77671
+ maxFileCount: material.max_file_count
77672
+ });
77673
+ const outputs = [];
77674
+ for (const extractedRel of extracted.sort()) {
77675
+ const sourceFile = path87.resolve(extractedRoot, safeRelPath(extractedRel));
77676
+ const stat = fs79.lstatSync(sourceFile);
77677
+ if (!stat.isFile())
77678
+ continue;
77679
+ const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path87.posix.join(destinationRel, extractedRel));
77680
+ const checked = protectWorkspace ? workspaceRel(combined) : combined;
77681
+ if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
77682
+ throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
77683
+ }
77684
+ assertWritableDestination(destinationRoot, checked);
77685
+ const destination = path87.resolve(destinationRoot, checked);
77686
+ await atomicCopy(sourceFile, destination, material.mode, extractedRoot);
77687
+ outputs.push(await recordFile(destinationRoot, destination, destinationRootName));
77688
+ }
77689
+ return outputs;
77690
+ } finally {
77691
+ fs79.rmSync(temporary, { recursive: true, force: true });
77692
+ }
77693
+ }
77694
+ async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
77695
+ const source = await verifyInput(sourceRoot, material);
77696
+ const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
77697
+ if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
77698
+ throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
77699
+ }
77700
+ if (material.kind === "file") {
77701
+ if (destinationRel === ".") {
77702
+ throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
77703
+ }
77704
+ assertWritableDestination(destinationRoot, destinationRel);
77705
+ return [destinationRel];
77706
+ }
77707
+ const temporary = fs79.mkdtempSync(path87.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
77708
+ try {
77709
+ const verifiedArchive = path87.join(temporary, "material.tar.gz");
77710
+ await atomicCopy(source, verifiedArchive, 384, sourceRoot);
77711
+ const archiveRecord = await recordFile(temporary, verifiedArchive, "staging");
77712
+ if (archiveRecord.sha256 !== material.sha256 || archiveRecord.size !== material.size_bytes) {
77713
+ throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
77714
+ }
77715
+ const extractedRoot = path87.join(temporary, "extracted");
77716
+ const extracted = await extract({
77717
+ tarFile: verifiedArchive,
77718
+ outDir: extractedRoot,
77719
+ maxTotalBytes: material.max_unpacked_bytes,
77720
+ maxFileCount: material.max_file_count
77721
+ });
77722
+ const planned = [];
77723
+ for (const extractedRel of extracted) {
77724
+ const combined = destinationRel === "." ? safeRelPath(extractedRel) : safeRelPath(path87.posix.join(destinationRel, extractedRel));
77725
+ const checked = protectWorkspace ? workspaceRel(combined) : combined;
77726
+ if (!protectWorkspace && checked.toLowerCase() === ".brainbase-benchmark-owner.json") {
77727
+ throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
77728
+ }
77729
+ assertWritableDestination(destinationRoot, checked);
77730
+ planned.push(checked);
77731
+ }
77732
+ return planned;
77733
+ } finally {
77734
+ fs79.rmSync(temporary, { recursive: true, force: true });
77735
+ }
77736
+ }
77737
+ function ownerMarker(root) {
77738
+ return path87.join(root, ".brainbase-benchmark-owner.json");
77739
+ }
77740
+ function verifyOwnedDirectory(root, role, spec) {
77741
+ if (!fs79.existsSync(root) || fs79.lstatSync(root).isSymbolicLink())
77742
+ return false;
77743
+ try {
77744
+ const marker = JSON.parse(fs79.readFileSync(ownerMarker(root), "utf8"));
77745
+ return marker.attempt_id === spec.attempt_id && marker.phase === spec.phase && marker.phase_id === spec.phase_id && marker.role === role;
77746
+ } catch {
77747
+ return false;
77748
+ }
77749
+ }
77750
+ function prepareOwnedDirectory(root, role, spec) {
77751
+ if (fs79.existsSync(root)) {
77752
+ if (!verifyOwnedDirectory(root, role, spec)) {
77753
+ const stat = fs79.lstatSync(root);
77754
+ if (!stat.isDirectory() || fs79.readdirSync(root).length > 0) {
77755
+ throw new BenchmarkPhaseError(`unowned_${role}_root`, `${role}_root exists without a matching attempt ownership marker`);
77756
+ }
77757
+ } else {
77758
+ fs79.rmSync(root, { recursive: true, force: true });
77759
+ }
77760
+ }
77761
+ fs79.mkdirSync(root, { recursive: true, mode: 448 });
77762
+ writeJsonAtomic(ownerMarker(root), {
77763
+ schema_version: SCHEMA_VERSION,
77764
+ attempt_id: spec.attempt_id,
77765
+ phase: spec.phase,
77766
+ phase_id: spec.phase_id,
77767
+ role
77768
+ });
77769
+ }
77770
+ function buildEnvironment(spec, secretNames, additions = {}) {
77771
+ const env3 = {};
77772
+ for (const name of BASE_ENV_NAMES) {
77773
+ if (process.env[name] !== undefined)
77774
+ env3[name] = process.env[name];
77775
+ }
77776
+ for (const [name, declared] of Object.entries(spec.environment)) {
77777
+ env3[name] = declared.value;
77778
+ }
77779
+ for (const name of secretNames) {
77780
+ const value = process.env[name];
77781
+ if (value === undefined) {
77782
+ throw new BenchmarkPhaseError("missing_environment", `required environment variable is missing: ${name}`);
77783
+ }
77784
+ env3[name] = value;
77785
+ }
77786
+ Object.assign(env3, additions);
77787
+ return env3;
77788
+ }
77789
+ function redactCommandOutput(data, spec) {
77790
+ let value = data.toString("utf8");
77791
+ for (const name of spec.secret_env) {
77792
+ const secret = process.env[name];
77793
+ if (secret)
77794
+ value = value.split(secret).join("[REDACTED]");
77795
+ }
77796
+ return Buffer.from(value);
77797
+ }
77798
+ function descendantPids(parentPid) {
77799
+ if (process.platform === "win32")
77800
+ return [];
77801
+ try {
77802
+ const output = execFileSync2("ps", ["-eo", "pid=,ppid="], {
77803
+ encoding: "utf8",
77804
+ stdio: ["ignore", "pipe", "ignore"]
77805
+ });
77806
+ const children = new Map;
77807
+ for (const line of output.split(`
77808
+ `)) {
77809
+ const [pidRaw, parentRaw] = line.trim().split(/\s+/);
77810
+ const pid = Number(pidRaw);
77811
+ const parent = Number(parentRaw);
77812
+ if (!Number.isInteger(pid) || !Number.isInteger(parent))
77813
+ continue;
77814
+ const current = children.get(parent) ?? [];
77815
+ current.push(pid);
77816
+ children.set(parent, current);
77817
+ }
77818
+ const descendants = [];
77819
+ const stack = [...children.get(parentPid) ?? []];
77820
+ while (stack.length > 0) {
77821
+ const pid = stack.pop();
77822
+ descendants.push(pid);
77823
+ stack.push(...children.get(pid) ?? []);
77824
+ }
77825
+ return descendants;
77826
+ } catch {
77827
+ return [];
77828
+ }
77829
+ }
77830
+ function terminate(child) {
77831
+ if (child.pid === undefined)
77832
+ return;
77833
+ for (const pid of descendantPids(child.pid).reverse()) {
77834
+ try {
77835
+ process.kill(pid, "SIGKILL");
77836
+ } catch {}
77837
+ }
77838
+ try {
77839
+ if (process.platform !== "win32")
77840
+ process.kill(-child.pid, "SIGKILL");
77841
+ else
77842
+ child.kill("SIGKILL");
77843
+ } catch {
77844
+ child.kill("SIGKILL");
77845
+ }
77846
+ }
77847
+ async function runCommand(command, root, spec, context, additions = {}) {
77848
+ const cwdRel = normalizedRootRelative(command.cwd);
77849
+ assertNoSymlinkTraversal(root, cwdRel);
77850
+ const cwd2 = path87.resolve(root, cwdRel);
77851
+ let cwdStat;
77852
+ try {
77853
+ cwdStat = fs79.lstatSync(cwd2);
77854
+ } catch {
77855
+ throw new BenchmarkPhaseError("invalid_command_cwd", `command cwd is invalid: ${command.cwd}`);
77856
+ }
77857
+ if (!isWithin(root, cwd2) || cwdStat.isSymbolicLink() || !cwdStat.isDirectory()) {
77858
+ throw new BenchmarkPhaseError("invalid_command_cwd", `command cwd is invalid: ${command.cwd}`);
77859
+ }
77860
+ const remainingMs = context.deadline - Date.now();
77861
+ if (remainingMs <= 0)
77862
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
77863
+ const timeoutMs2 = Math.min(command.timeout_ms ?? remainingMs, remainingMs);
77864
+ const started = Date.now();
77865
+ return await new Promise((resolve, reject2) => {
77866
+ const child = spawn4(command.argv[0], command.argv.slice(1), {
77867
+ cwd: cwd2,
77868
+ env: buildEnvironment(spec, command.secret_env, additions),
77869
+ stdio: ["ignore", "pipe", "pipe"],
77870
+ detached: process.platform !== "win32"
77871
+ });
77872
+ const stdout = [];
77873
+ const stderr = [];
77874
+ let captured = 0;
77875
+ let settled = false;
77876
+ let timer;
77877
+ const fail = (error2) => {
77878
+ if (settled)
77879
+ return;
77880
+ settled = true;
77881
+ if (timer)
77882
+ clearTimeout(timer);
77883
+ terminate(child);
77884
+ reject2(error2);
77885
+ };
77886
+ const capture = (target, chunk2) => {
77887
+ if (settled)
77888
+ return;
77889
+ captured += chunk2.length;
77890
+ context.remainingOutputBytes -= chunk2.length;
77891
+ if (captured > spec.budget.max_output_bytes || context.remainingOutputBytes < 0) {
77892
+ fail(new BenchmarkPhaseError("output_limit_exceeded", `command output exceeded budget: ${command.id}`));
77893
+ return;
77894
+ }
77895
+ target.push(chunk2);
77896
+ };
77897
+ child.stdout?.on("data", (chunk2) => capture(stdout, chunk2));
77898
+ child.stderr?.on("data", (chunk2) => capture(stderr, chunk2));
77899
+ child.on("error", (error2) => {
77900
+ fail(new BenchmarkPhaseError("command_start_failed", `failed to start ${command.id}: ${error2.message}`));
77901
+ });
77902
+ timer = setTimeout(() => {
77903
+ fail(new BenchmarkPhaseError("command_timeout", `command timed out: ${command.id}`));
77904
+ }, timeoutMs2);
77905
+ child.on("close", (code, signal) => {
77906
+ if (settled)
77907
+ return;
77908
+ settled = true;
77909
+ clearTimeout(timer);
77910
+ if (code === null) {
77911
+ reject2(new BenchmarkPhaseError("command_terminated", `command was terminated by ${signal ?? "an unknown signal"}: ${command.id}`));
77912
+ return;
77913
+ }
77914
+ resolve({
77915
+ exitCode: code,
77916
+ stdout: Buffer.concat(stdout),
77917
+ stderr: Buffer.concat(stderr),
77918
+ durationMs: Date.now() - started
77919
+ });
77920
+ });
77921
+ });
77922
+ }
77923
+ async function writeLog(root, name, data, spec) {
77924
+ const destination = path87.join(root, name);
77925
+ fs79.mkdirSync(path87.dirname(destination), { recursive: true });
77926
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
77927
+ try {
77928
+ fs79.writeFileSync(temporary, redactCommandOutput(data, spec), {
77929
+ flag: "wx",
77930
+ mode: 384
77931
+ });
77932
+ fs79.renameSync(temporary, destination);
77933
+ } finally {
77934
+ fs79.rmSync(temporary, { force: true });
77935
+ }
77936
+ return await recordFile(root, destination, "logs");
77937
+ }
77938
+ function writeBufferAtomic(destination, data) {
77939
+ fs79.mkdirSync(path87.dirname(destination), { recursive: true });
77940
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
77941
+ try {
77942
+ fs79.writeFileSync(temporary, data, { flag: "wx", mode: 384 });
77943
+ fs79.renameSync(temporary, destination);
77944
+ } finally {
77945
+ fs79.rmSync(temporary, { force: true });
77946
+ }
77947
+ }
77948
+ function assertBudget(context) {
77949
+ if (Date.now() > context.deadline) {
77950
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
77951
+ }
77952
+ }
77953
+ async function executeHydrate(spec, context) {
77954
+ fs79.mkdirSync(spec.workspace_root, { recursive: true });
77955
+ prepareOwnedDirectory(spec.logs_root, "logs", spec);
77956
+ context.logsOwned = true;
77957
+ const outputs = [];
77958
+ const plannedDestinations = [];
77959
+ for (const material of spec.materials) {
77960
+ assertBudget(context);
77961
+ plannedDestinations.push(...await preflightMaterial(material, spec.staging_root, spec.workspace_root, true));
77962
+ const source = await verifyInput(spec.staging_root, material);
77963
+ context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
77964
+ }
77965
+ validateDestinationGraph(plannedDestinations);
77966
+ for (const material of spec.materials) {
77967
+ assertBudget(context);
77968
+ const started = Date.now();
77969
+ try {
77970
+ const records = await copyMaterial(material, spec.staging_root, spec.workspace_root, "workspace", true);
77971
+ outputs.push(...records);
77972
+ context.outputs.push(...records);
77973
+ context.steps.push({
77974
+ id: material.id,
77975
+ type: `material:${material.kind}`,
77976
+ status: "passed",
77977
+ duration_ms: Date.now() - started
77978
+ });
77979
+ } catch (error2) {
77980
+ context.steps.push({
77981
+ id: material.id,
77982
+ type: `material:${material.kind}`,
77983
+ status: "failed",
77984
+ duration_ms: Date.now() - started
77985
+ });
77986
+ throw error2;
77987
+ }
77988
+ }
77989
+ for (const command of spec.setup_commands) {
77990
+ assertBudget(context);
77991
+ let result2;
77992
+ try {
77993
+ result2 = await runCommand(command, spec.workspace_root, spec, context);
77994
+ } catch (error2) {
77995
+ context.steps.push({
77996
+ id: command.id,
77997
+ type: "setup_command",
77998
+ status: "failed",
77999
+ duration_ms: 0
78000
+ });
78001
+ throw error2;
78002
+ }
78003
+ const stdout = await writeLog(spec.logs_root, `${command.id}.stdout.log`, result2.stdout, spec);
78004
+ const stderr = await writeLog(spec.logs_root, `${command.id}.stderr.log`, result2.stderr, spec);
78005
+ context.steps.push({
78006
+ id: command.id,
78007
+ type: "setup_command",
78008
+ status: result2.exitCode === 0 ? "passed" : "failed",
78009
+ duration_ms: result2.durationMs,
78010
+ exit_code: result2.exitCode,
78011
+ stdout,
78012
+ stderr
78013
+ });
78014
+ outputs.push(stdout, stderr);
78015
+ context.outputs.push(stdout, stderr);
78016
+ if (result2.exitCode !== 0) {
78017
+ throw new BenchmarkPhaseError("setup_failed", `setup command failed: ${command.id}`, {
78018
+ exit_code: result2.exitCode
78019
+ });
78020
+ }
78021
+ }
78022
+ const finalOutputs = [];
78023
+ const seenOutputs = new Set;
78024
+ for (const output of outputs) {
78025
+ const key2 = `${output.root}:${output.path}`;
78026
+ if (seenOutputs.has(key2))
78027
+ continue;
78028
+ seenOutputs.add(key2);
78029
+ if (output.root !== "workspace") {
78030
+ finalOutputs.push(output);
78031
+ continue;
78032
+ }
78033
+ const candidate = path87.resolve(spec.workspace_root, safeRelPath(output.path));
78034
+ assertNoSymlinkTraversal(spec.workspace_root, output.path);
78035
+ if (!fs79.existsSync(candidate))
78036
+ continue;
78037
+ const stat = fs79.lstatSync(candidate);
78038
+ if (!stat.isFile() && !stat.isSymbolicLink())
78039
+ continue;
78040
+ finalOutputs.push(await recordFile(spec.workspace_root, candidate, "workspace", stat.isSymbolicLink() ? "symlink" : "file"));
78041
+ }
78042
+ outputs.splice(0, outputs.length, ...finalOutputs);
78043
+ context.outputs.splice(0, context.outputs.length, ...finalOutputs);
78044
+ assertBudget(context);
78045
+ return outputs;
78046
+ }
78047
+ async function readEvidence(stagingRoot, evidence) {
78048
+ const filePath = sourcePath(stagingRoot, evidence.source);
78049
+ const opened = openRegularFileNoFollow(filePath, `evidence ${evidence.source}`, stagingRoot);
78050
+ try {
78051
+ const buffer = readDescriptor(opened.fd);
78052
+ if (opened.stat.size !== evidence.size_bytes) {
78053
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${evidence.source}`, { expected: evidence.size_bytes, actual: opened.stat.size });
78054
+ }
78055
+ const actual = sha256(buffer);
78056
+ if (actual !== evidence.sha256) {
78057
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${evidence.source}`, { expected: evidence.sha256, actual });
78058
+ }
78059
+ return {
78060
+ path: filePath,
78061
+ buffer,
78062
+ record: {
78063
+ root: "staging",
78064
+ path: path87.relative(stagingRoot, filePath).replace(/\\/g, "/"),
78065
+ sha256: evidence.sha256,
78066
+ size: opened.stat.size,
78067
+ mode: opened.stat.mode & 511
78068
+ }
78069
+ };
78070
+ } finally {
78071
+ fs79.closeSync(opened.fd);
78072
+ }
78073
+ }
78074
+ async function workspaceManifest(spec, context) {
78075
+ const records = [];
78076
+ let totalBytes = 0;
78077
+ const stack = [path87.resolve(spec.workspace_root)];
78078
+ while (stack.length > 0) {
78079
+ const directory = stack.pop();
78080
+ const entries = fs79.readdirSync(directory, { withFileTypes: true }).sort((a3, b4) => a3.name.localeCompare(b4.name));
78081
+ for (const entry of entries) {
78082
+ assertBudget(context);
78083
+ const full = path87.join(directory, entry.name);
78084
+ const relative = path87.relative(spec.workspace_root, full).replace(/\\/g, "/");
78085
+ if (relative === ".brainbase" || relative.startsWith(".brainbase/"))
78086
+ continue;
78087
+ if (relative === ".git" || relative.startsWith(".git/"))
78088
+ continue;
78089
+ if (entry.isDirectory()) {
78090
+ stack.push(full);
78091
+ continue;
78092
+ }
78093
+ if (!entry.isFile() && !entry.isSymbolicLink())
78094
+ continue;
78095
+ const record3 = await recordFile(spec.workspace_root, full, "workspace", entry.isSymbolicLink() ? "symlink" : "file");
78096
+ records.push(record3);
78097
+ totalBytes += record3.size;
78098
+ if (records.length > spec.workspace_limits.max_file_count) {
78099
+ throw new BenchmarkPhaseError("workspace_limit_exceeded", "workspace file count exceeds budget");
78100
+ }
78101
+ if (totalBytes > spec.workspace_limits.max_total_bytes) {
78102
+ throw new BenchmarkPhaseError("workspace_limit_exceeded", "workspace bytes exceed budget");
78103
+ }
78104
+ }
78105
+ }
78106
+ return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
78107
+ }
78108
+ function trajectoryEvents(value) {
78109
+ if (Array.isArray(value))
78110
+ return value;
78111
+ if (value && typeof value === "object" && Array.isArray(value.events)) {
78112
+ return value.events;
78113
+ }
78114
+ throw new BenchmarkPhaseError("invalid_trajectory", "trajectory evidence must be an array or an object with events");
78115
+ }
78116
+ function eventType(event) {
78117
+ if (!event || typeof event !== "object")
78118
+ return;
78119
+ const record3 = event;
78120
+ for (const key2 of ["event_type", "type", "kind"]) {
78121
+ if (typeof record3[key2] === "string")
78122
+ return record3[key2];
78123
+ }
78124
+ return;
78125
+ }
78126
+ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvidence, context) {
78127
+ const started = Date.now();
78128
+ const base2 = {
78129
+ id: evaluator.id,
78130
+ type: evaluator.type,
78131
+ required: evaluator.required,
78132
+ primary: evaluator.primary,
78133
+ engine: "brainbase-cli",
78134
+ engine_version: VERSION
78135
+ };
78136
+ if (evaluator.type === "output_assertion") {
78137
+ const assertion = evaluator.assertion;
78138
+ let verdict2 = false;
78139
+ if (assertion.operator === "exact")
78140
+ verdict2 = finalOutput === assertion.expected;
78141
+ if (assertion.operator === "contains")
78142
+ verdict2 = finalOutput.includes(assertion.expected);
78143
+ if (assertion.operator === "regex") {
78144
+ const regexResult = await runCommand({
78145
+ id: `${evaluator.id}.regex`,
78146
+ argv: [
78147
+ process.execPath,
78148
+ "-e",
78149
+ [
78150
+ 'const fs=require("node:fs");',
78151
+ "try {",
78152
+ 'const pattern=Buffer.from(process.env.BB_REGEX_PATTERN_B64,"base64").toString("utf8");',
78153
+ 'const value=fs.readFileSync(process.env.BB_REGEX_INPUT,"utf8");',
78154
+ "process.exit(new RegExp(pattern,process.env.BB_REGEX_FLAGS).test(value)?0:1);",
78155
+ "} catch { process.exit(2); }"
78156
+ ].join("")
78157
+ ],
78158
+ cwd: ".",
78159
+ secret_env: []
78160
+ }, spec.tests_root, spec, context, {
78161
+ BB_REGEX_INPUT: frozenEvidence.finalOutputPath,
78162
+ BB_REGEX_PATTERN_B64: Buffer.from(assertion.pattern).toString("base64"),
78163
+ BB_REGEX_FLAGS: assertion.flags
78164
+ });
78165
+ if (regexResult.exitCode === 2) {
78166
+ throw new BenchmarkPhaseError("invalid_evaluator", `invalid regex in evaluator: ${evaluator.id}`);
78167
+ }
78168
+ verdict2 = regexResult.exitCode === 0;
78169
+ }
78170
+ return { ...base2, status: verdict2 ? "passed" : "failed", verdict: verdict2, duration_ms: Date.now() - started };
78171
+ }
78172
+ if (evaluator.type === "trajectory_assertion") {
78173
+ const count = trajectory.filter((event) => eventType(event) === evaluator.event_type).length;
78174
+ const verdict2 = count >= evaluator.min_count && (evaluator.max_count === undefined || count <= evaluator.max_count);
78175
+ return {
78176
+ ...base2,
78177
+ status: verdict2 ? "passed" : "failed",
78178
+ verdict: verdict2,
78179
+ duration_ms: Date.now() - started,
78180
+ details: { count, min_count: evaluator.min_count, max_count: evaluator.max_count }
78181
+ };
78182
+ }
78183
+ if (evaluator.type === "workspace_assertion") {
78184
+ const relative = workspaceRel(evaluator.path);
78185
+ assertNoSymlinkTraversal(spec.workspace_root, relative);
78186
+ const candidate = path87.resolve(spec.workspace_root, relative);
78187
+ let stat = null;
78188
+ try {
78189
+ stat = fs79.lstatSync(candidate);
78190
+ } catch (error2) {
78191
+ const code = error2.code;
78192
+ if (code !== "ENOENT" && code !== "ENOTDIR")
78193
+ throw error2;
78194
+ }
78195
+ if (stat?.isSymbolicLink()) {
78196
+ throw new BenchmarkPhaseError("unsafe_path", `workspace assertion cannot target a symlink: ${relative}`);
78197
+ }
78198
+ const exists2 = stat !== null;
78199
+ let verdict2 = false;
78200
+ if (evaluator.assertion.operator === "exists")
78201
+ verdict2 = exists2;
78202
+ if (evaluator.assertion.operator === "not_exists")
78203
+ verdict2 = !exists2;
78204
+ if (evaluator.assertion.operator === "sha256") {
78205
+ if (stat?.isFile()) {
78206
+ const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
78207
+ try {
78208
+ verdict2 = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
78209
+ } finally {
78210
+ fs79.closeSync(opened.fd);
78211
+ }
78212
+ }
78213
+ }
78214
+ if (evaluator.assertion.operator === "contains") {
78215
+ if (stat?.isFile()) {
78216
+ const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
78217
+ try {
78218
+ verdict2 = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
78219
+ } finally {
78220
+ fs79.closeSync(opened.fd);
78221
+ }
78222
+ }
78223
+ }
78224
+ return { ...base2, status: verdict2 ? "passed" : "failed", verdict: verdict2, duration_ms: Date.now() - started };
78225
+ }
78226
+ const commandRoot = evaluator.root === "workspace" ? spec.workspace_root : spec.tests_root;
78227
+ const command = { id: evaluator.id, ...evaluator.command };
78228
+ const result2 = await runCommand(command, commandRoot, spec, context, {
78229
+ BRAINBASE_BENCHMARK_WORKSPACE: spec.workspace_root,
78230
+ BRAINBASE_BENCHMARK_TESTS: spec.tests_root,
78231
+ BRAINBASE_BENCHMARK_LOGS: spec.logs_root,
78232
+ BRAINBASE_BENCHMARK_FINAL_OUTPUT: frozenEvidence.finalOutputPath,
78233
+ BRAINBASE_BENCHMARK_TRAJECTORY: frozenEvidence.trajectoryPath
78234
+ });
78235
+ const stdout = await writeLog(spec.logs_root, `${evaluator.id}.stdout.log`, result2.stdout, spec);
78236
+ const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
78237
+ const verdict = result2.exitCode === 0;
78238
+ return {
78239
+ ...base2,
78240
+ status: verdict ? "passed" : "failed",
78241
+ verdict,
78242
+ duration_ms: result2.durationMs,
78243
+ details: { exit_code: result2.exitCode },
78244
+ stdout,
78245
+ stderr
78246
+ };
78247
+ }
78248
+ async function executeEvaluate(spec, context) {
78249
+ const finalOutput = await readEvidence(spec.staging_root, spec.evidence.final_output);
78250
+ const trajectoryEvidence = await readEvidence(spec.staging_root, spec.evidence.trajectory);
78251
+ context.inputs.push(finalOutput.record, trajectoryEvidence.record);
78252
+ let parsedTrajectory;
78253
+ try {
78254
+ parsedTrajectory = JSON.parse(trajectoryEvidence.buffer.toString("utf8"));
78255
+ } catch {
78256
+ throw new BenchmarkPhaseError("invalid_trajectory", "trajectory evidence is not valid JSON");
78257
+ }
78258
+ const trajectory = trajectoryEvents(parsedTrajectory);
78259
+ const plannedReferences = [];
78260
+ for (const reference of spec.references) {
78261
+ assertBudget(context);
78262
+ plannedReferences.push(...await preflightMaterial(reference, spec.staging_root, spec.tests_root, false));
78263
+ const source = await verifyInput(spec.staging_root, reference);
78264
+ context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
78265
+ }
78266
+ validateDestinationGraph(plannedReferences);
78267
+ assertBudget(context);
78268
+ validateRoots(spec);
78269
+ prepareOwnedDirectory(spec.tests_root, "tests", spec);
78270
+ prepareOwnedDirectory(spec.logs_root, "logs", spec);
78271
+ context.logsOwned = true;
78272
+ validateRoots(spec);
78273
+ const outputs = [];
78274
+ const finalOutputPath = path87.join(spec.logs_root, "candidate-evidence", "final-output");
78275
+ const trajectoryPath = path87.join(spec.logs_root, "candidate-evidence", "trajectory.json");
78276
+ writeBufferAtomic(finalOutputPath, finalOutput.buffer);
78277
+ writeBufferAtomic(trajectoryPath, trajectoryEvidence.buffer);
78278
+ const frozenEvidenceRecords = [
78279
+ await recordFile(spec.logs_root, finalOutputPath, "logs"),
78280
+ await recordFile(spec.logs_root, trajectoryPath, "logs")
78281
+ ];
78282
+ outputs.push(...frozenEvidenceRecords);
78283
+ context.outputs.push(...frozenEvidenceRecords);
78284
+ assertBudget(context);
78285
+ const manifest = await workspaceManifest(spec, context);
78286
+ const manifestPath2 = path87.join(spec.logs_root, "candidate-workspace-manifest.json");
78287
+ writeJsonAtomic(manifestPath2, {
78288
+ schema_version: SCHEMA_VERSION,
78289
+ attempt_id: spec.attempt_id,
78290
+ phase_id: spec.phase_id,
78291
+ files: manifest
78292
+ });
78293
+ const manifestRecord = await recordFile(spec.logs_root, manifestPath2, "logs");
78294
+ outputs.push(manifestRecord);
78295
+ context.outputs.push(manifestRecord);
78296
+ for (const artifactRelInput of spec.candidate_artifacts) {
78297
+ const artifactRel = workspaceRel(artifactRelInput);
78298
+ assertNoSymlinkTraversal(spec.workspace_root, artifactRel);
78299
+ const source = path87.resolve(spec.workspace_root, artifactRel);
78300
+ const frozenArtifact = manifest.find((entry) => entry.path === artifactRel && entry.kind !== "symlink");
78301
+ if (!frozenArtifact || !fs79.existsSync(source) || !fs79.lstatSync(source).isFile()) {
78302
+ throw new BenchmarkPhaseError("missing_artifact", `candidate artifact is missing: ${artifactRel}`);
78303
+ }
78304
+ const destination = path87.resolve(spec.logs_root, "candidate-artifacts", artifactRel);
78305
+ await atomicCopy(source, destination, undefined, spec.workspace_root);
78306
+ const artifact = await recordFile(spec.logs_root, destination, "logs");
78307
+ if (artifact.sha256 !== frozenArtifact.sha256 || artifact.size !== frozenArtifact.size || artifact.mode !== frozenArtifact.mode) {
78308
+ throw new BenchmarkPhaseError("evidence_tampered", `candidate artifact changed after the workspace freeze: ${artifactRel}`);
78309
+ }
78310
+ outputs.push(artifact);
78311
+ context.outputs.push(artifact);
78312
+ }
78313
+ if (spec.capture_workspace_archive) {
78314
+ const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
78315
+ const archive = path87.join(spec.logs_root, "candidate-workspace.tar.gz");
78316
+ const temporary = `${archive}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
78317
+ try {
78318
+ await pack({ rootDir: spec.workspace_root, outFile: temporary, files: regularFiles });
78319
+ fs79.renameSync(temporary, archive);
78320
+ } finally {
78321
+ fs79.rmSync(temporary, { force: true });
78322
+ }
78323
+ const archiveRecord = await recordFile(spec.logs_root, archive, "logs");
78324
+ outputs.push(archiveRecord);
78325
+ context.outputs.push(archiveRecord);
78326
+ }
78327
+ await verifyRecordsUnchanged(manifest, spec);
78328
+ for (const reference of spec.references) {
78329
+ const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false);
78330
+ outputs.push(...referenceOutputs);
78331
+ context.outputs.push(...referenceOutputs);
78332
+ }
78333
+ const frozenOutputCount = context.outputs.length;
78334
+ const evaluators = [];
78335
+ const evaluatorOrder = new Map(spec.evaluators.map((evaluator, index) => [evaluator.id, index]));
78336
+ const executionOrder = [...spec.evaluators].sort((left, right) => Number(left.type === "sandbox_command") - Number(right.type === "sandbox_command"));
78337
+ for (const evaluator of executionOrder) {
78338
+ assertBudget(context);
78339
+ const started = Date.now();
78340
+ try {
78341
+ const evaluated = await evaluateOne(evaluator, spec, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
78342
+ assertBudget(context);
78343
+ evaluators.push(evaluated);
78344
+ context.evaluators.push(evaluated);
78345
+ if (evaluated.stdout) {
78346
+ outputs.push(evaluated.stdout);
78347
+ context.outputs.push(evaluated.stdout);
78348
+ }
78349
+ if (evaluated.stderr) {
78350
+ outputs.push(evaluated.stderr);
78351
+ context.outputs.push(evaluated.stderr);
78352
+ }
78353
+ } catch (error2) {
78354
+ const normalized = stableError(error2);
78355
+ const errored = {
78356
+ id: evaluator.id,
78357
+ type: evaluator.type,
78358
+ required: evaluator.required,
78359
+ primary: evaluator.primary,
78360
+ status: "errored",
78361
+ verdict: null,
78362
+ engine: "brainbase-cli",
78363
+ engine_version: VERSION,
78364
+ duration_ms: Date.now() - started,
78365
+ details: {
78366
+ error_code: normalized?.code ?? "phase_failed",
78367
+ error_message: normalized?.message ?? "evaluator execution failed"
78368
+ }
78369
+ };
78370
+ evaluators.push(errored);
78371
+ context.evaluators.push(errored);
78372
+ if (evaluator.required)
78373
+ throw error2;
78374
+ assertBudget(context);
78375
+ }
78376
+ }
78377
+ await verifyRecordsUnchanged([...context.inputs, ...context.outputs.slice(0, frozenOutputCount)], spec);
78378
+ if (!verifyOwnedDirectory(spec.tests_root, "tests", spec) || !verifyOwnedDirectory(spec.logs_root, "logs", spec)) {
78379
+ throw new BenchmarkPhaseError("evidence_tampered", "benchmark evaluator changed an owned phase directory marker");
78380
+ }
78381
+ assertBudget(context);
78382
+ evaluators.sort((left, right) => evaluatorOrder.get(left.id) - evaluatorOrder.get(right.id));
78383
+ return { outputs, evaluators };
78384
+ }
78385
+ function stableError(error2) {
78386
+ if (error2 instanceof BenchmarkPhaseError) {
78387
+ return { code: error2.code, message: error2.message, details: error2.details };
78388
+ }
78389
+ if (error2 instanceof TarballError) {
78390
+ return { code: "invalid_archive", message: error2.message };
78391
+ }
78392
+ if (error2 instanceof exports_external.ZodError) {
78393
+ return {
78394
+ code: "invalid_spec",
78395
+ message: "benchmark phase spec is invalid",
78396
+ details: error2.issues.map((issue2) => ({
78397
+ path: issue2.path.join("."),
78398
+ code: issue2.code,
78399
+ message: issue2.message
78400
+ }))
78401
+ };
78402
+ }
78403
+ return {
78404
+ code: "phase_failed",
78405
+ message: error2 instanceof Error ? error2.message : "unknown benchmark phase failure"
78406
+ };
78407
+ }
78408
+ function rawIdentity(value) {
78409
+ if (!value || typeof value !== "object") {
78410
+ return { phase: "unknown", attemptId: null, phaseId: null };
78411
+ }
78412
+ const record3 = value;
78413
+ return {
78414
+ phase: record3.phase === "hydrate" || record3.phase === "evaluate" ? record3.phase : "unknown",
78415
+ attemptId: typeof record3.attempt_id === "string" ? record3.attempt_id : null,
78416
+ phaseId: typeof record3.phase_id === "string" ? record3.phase_id : null
78417
+ };
78418
+ }
78419
+ function readSpecBytes(specPathInput) {
78420
+ const specPath = path87.resolve(specPathInput);
78421
+ const noFollow = typeof fs79.constants.O_NOFOLLOW === "number" ? fs79.constants.O_NOFOLLOW : 0;
78422
+ let fd;
78423
+ try {
78424
+ fd = fs79.openSync(specPath, fs79.constants.O_RDONLY | noFollow);
78425
+ } catch {
78426
+ throw new BenchmarkPhaseError("spec_read_failed", "spec file could not be read");
78427
+ }
78428
+ try {
78429
+ const stat = fs79.fstatSync(fd);
78430
+ if (!stat.isFile() || stat.size > MAX_SPEC_BYTES) {
78431
+ throw new BenchmarkPhaseError("invalid_spec_file", "spec must be a regular JSON file no larger than 20 MiB");
78432
+ }
78433
+ return readDescriptor(fd);
78434
+ } finally {
78435
+ fs79.closeSync(fd);
78436
+ }
78437
+ }
78438
+ function validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase) {
78439
+ const digest = sha256(bytes);
78440
+ let raw;
78441
+ try {
78442
+ raw = JSON.parse(bytes.toString("utf8"));
78443
+ } catch {
78444
+ throw new BenchmarkPhaseError("invalid_spec_json", "spec is not valid JSON");
78445
+ }
78446
+ const spec = BenchmarkSpecSchema.parse(raw);
78447
+ if (spec.phase !== expectedPhase) {
78448
+ throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
78449
+ }
78450
+ validateRoots(spec);
78451
+ const resultPath = path87.resolve(resultPathInput);
78452
+ const expectedResultPath = path87.join(path87.resolve(spec.logs_root), "result.json");
78453
+ if (resultPath !== expectedResultPath) {
78454
+ throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
78455
+ }
78456
+ return { spec, digest, resultPath };
78457
+ }
78458
+ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expectedPhase, startedAt, started) {
78459
+ let raw = undefined;
78460
+ let digest = null;
78461
+ let identity2 = rawIdentity(raw);
78462
+ try {
78463
+ const bytes = readSpecBytes(specPathInput);
78464
+ digest = sha256(bytes);
78465
+ try {
78466
+ raw = JSON.parse(bytes.toString("utf8"));
78467
+ } catch {
78468
+ throw new BenchmarkPhaseError("invalid_spec_json", "spec is not valid JSON");
78469
+ }
78470
+ identity2 = rawIdentity(raw);
78471
+ const { spec, resultPath } = validateBenchmarkInvocationBytes(bytes, resultPathInput, expectedPhase);
78472
+ const invocation = {
78473
+ phase: spec.phase,
78474
+ attempt_id: spec.attempt_id,
78475
+ phase_id: spec.phase_id,
78476
+ spec_digest: digest,
78477
+ timeout_ms: spec.budget.timeout_ms
78478
+ };
78479
+ if (fs79.existsSync(resultPath)) {
78480
+ try {
78481
+ const cached2 = JSON.parse(fs79.readFileSync(resultPath, "utf8"));
78482
+ if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
78483
+ return {
78484
+ ok: true,
78485
+ invocation,
78486
+ spec_bytes: bytes,
78487
+ cached_result: cached2
78488
+ };
78489
+ }
78490
+ } catch {}
78491
+ }
78492
+ return { ok: true, invocation, spec_bytes: bytes };
78493
+ } catch (error2) {
78494
+ return {
78495
+ ok: false,
78496
+ result: {
78497
+ schema_version: SCHEMA_VERSION,
78498
+ cli_version: VERSION,
78499
+ phase: identity2.phase === "unknown" ? expectedPhase : identity2.phase,
78500
+ attempt_id: identity2.attemptId,
78501
+ phase_id: identity2.phaseId,
78502
+ spec_digest: digest,
78503
+ status: "failed",
78504
+ started_at: startedAt,
78505
+ completed_at: nowIso(),
78506
+ duration_ms: Date.now() - started,
78507
+ steps: [],
78508
+ inputs: [],
78509
+ outputs: [],
78510
+ error: stableError(error2)
78511
+ }
78512
+ };
78513
+ }
78514
+ }
78515
+ function writeBenchmarkPhaseTimeoutResult(specBytes, resultPathInput, expectedPhase, startedAt, started) {
78516
+ const { spec, digest, resultPath } = validateBenchmarkInvocationBytes(specBytes, resultPathInput, expectedPhase);
78517
+ const result2 = {
78518
+ schema_version: SCHEMA_VERSION,
78519
+ cli_version: VERSION,
78520
+ phase: spec.phase,
78521
+ attempt_id: spec.attempt_id,
78522
+ phase_id: spec.phase_id,
78523
+ spec_digest: digest,
78524
+ status: "failed",
78525
+ started_at: startedAt,
78526
+ completed_at: nowIso(),
78527
+ duration_ms: Date.now() - started,
78528
+ steps: [],
78529
+ inputs: [],
78530
+ outputs: [],
78531
+ error: {
78532
+ code: "phase_timeout",
78533
+ message: "phase budget expired"
78534
+ }
78535
+ };
78536
+ try {
78537
+ prepareOwnedDirectory(spec.logs_root, "logs", spec);
78538
+ writeJsonAtomic(resultPath, result2);
78539
+ } catch (error2) {
78540
+ result2.error.details = {
78541
+ result_write_error: error2 instanceof Error ? error2.message : "failed to write timeout result"
78542
+ };
78543
+ }
78544
+ return result2;
78545
+ }
78546
+ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase, immutableSpecBytes) {
78547
+ const startedAt = nowIso();
78548
+ const started = Date.now();
78549
+ const resultPath = path87.resolve(resultPathInput);
78550
+ let raw = undefined;
78551
+ let digest = null;
78552
+ let identity2 = rawIdentity(raw);
78553
+ const steps = [];
78554
+ let inputs = [];
78555
+ let outputs = [];
78556
+ let evaluators;
78557
+ let status = "failed";
78558
+ let error2;
78559
+ let context;
78560
+ let resultPathValidated = false;
78561
+ try {
78562
+ let bytes;
78563
+ if (immutableSpecBytes) {
78564
+ bytes = immutableSpecBytes;
78565
+ if (bytes.length > MAX_SPEC_BYTES) {
78566
+ throw new BenchmarkPhaseError("invalid_spec_file", "spec must be a regular JSON file no larger than 20 MiB");
78567
+ }
78568
+ } else {
78569
+ bytes = readSpecBytes(specPathInput);
78570
+ }
78571
+ digest = sha256(bytes);
78572
+ try {
78573
+ raw = JSON.parse(bytes.toString("utf8"));
78574
+ } catch {
78575
+ throw new BenchmarkPhaseError("invalid_spec_json", "spec is not valid JSON");
78576
+ }
78577
+ identity2 = rawIdentity(raw);
78578
+ const spec = BenchmarkSpecSchema.parse(raw);
78579
+ if (expectedPhase && spec.phase !== expectedPhase) {
78580
+ throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
78581
+ }
78582
+ validateRoots(spec);
78583
+ const expectedResultPath = path87.join(path87.resolve(spec.logs_root), "result.json");
78584
+ if (resultPath !== expectedResultPath) {
78585
+ throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
78586
+ }
78587
+ resultPathValidated = true;
78588
+ if (fs79.existsSync(resultPath)) {
78589
+ try {
78590
+ const cached2 = JSON.parse(fs79.readFileSync(resultPath, "utf8"));
78591
+ if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
78592
+ return { exitCode: 0, result: cached2 };
78593
+ }
78594
+ } catch {}
78595
+ }
78596
+ context = {
78597
+ deadline: started + spec.budget.timeout_ms,
78598
+ remainingOutputBytes: spec.budget.max_output_bytes,
78599
+ steps,
78600
+ evaluators: [],
78601
+ inputs: [],
78602
+ outputs: [],
78603
+ logsOwned: false
78604
+ };
78605
+ if (spec.phase === "hydrate") {
78606
+ outputs = await executeHydrate(spec, context);
78607
+ } else {
78608
+ const evaluated = await executeEvaluate(spec, context);
78609
+ outputs = evaluated.outputs;
78610
+ evaluators = evaluated.evaluators;
78611
+ }
78612
+ inputs = context.inputs;
78613
+ status = "succeeded";
78614
+ } catch (caught) {
78615
+ error2 = stableError(caught);
78616
+ if (context) {
78617
+ inputs = context.inputs;
78618
+ outputs = context.outputs;
78619
+ if (context.evaluators.length)
78620
+ evaluators = context.evaluators;
78621
+ }
78622
+ }
78623
+ const result2 = {
78624
+ schema_version: SCHEMA_VERSION,
78625
+ cli_version: VERSION,
78626
+ phase: identity2.phase === "unknown" && expectedPhase ? expectedPhase : identity2.phase,
78627
+ attempt_id: identity2.attemptId,
78628
+ phase_id: identity2.phaseId,
78629
+ spec_digest: digest,
78630
+ status,
78631
+ started_at: startedAt,
78632
+ completed_at: nowIso(),
78633
+ duration_ms: Date.now() - started,
78634
+ steps,
78635
+ inputs,
78636
+ outputs,
78637
+ ...evaluators ? { evaluators } : {},
78638
+ ...error2 ? { error: error2 } : {}
78639
+ };
78640
+ if (!resultPathValidated || !context?.logsOwned) {
78641
+ return { exitCode: status === "succeeded" ? 0 : 1, result: result2 };
78642
+ }
78643
+ try {
78644
+ writeJsonAtomic(resultPath, result2);
78645
+ } catch (writeError) {
78646
+ result2.status = "failed";
78647
+ result2.error = {
78648
+ code: "result_write_failed",
78649
+ message: writeError instanceof Error ? writeError.message : "failed to write result"
78650
+ };
78651
+ return { exitCode: 1, result: result2 };
78652
+ }
78653
+ return { exitCode: status === "succeeded" ? 0 : 1, result: result2 };
78654
+ }
78655
+
78656
+ // src/cli/benchmark.ts
78657
+ function parsePhaseArgs(args) {
78658
+ let spec;
78659
+ let result2;
78660
+ let json = false;
78661
+ const seen = new Set;
78662
+ for (let index = 0;index < args.length; index += 1) {
78663
+ const arg = args[index];
78664
+ if (arg === "--json") {
78665
+ if (seen.has(arg))
78666
+ throw new Error(`Duplicate benchmark option: ${arg}`);
78667
+ seen.add(arg);
78668
+ json = true;
78669
+ continue;
78670
+ }
78671
+ if (arg === "--spec" || arg === "--result") {
78672
+ if (seen.has(arg))
78673
+ throw new Error(`Duplicate benchmark option: ${arg}`);
78674
+ seen.add(arg);
78675
+ const value = args[index + 1];
78676
+ if (!value || value.startsWith("--")) {
78677
+ throw new Error(`${arg} requires a path`);
78678
+ }
78679
+ if (arg === "--spec")
78680
+ spec = value;
78681
+ else
78682
+ result2 = value;
78683
+ index += 1;
78684
+ continue;
78685
+ }
78686
+ throw new Error(`Unknown benchmark argument: ${arg}`);
78687
+ }
78688
+ if (!spec)
78689
+ throw new Error("--spec is required");
78690
+ if (!result2)
78691
+ throw new Error("--result is required");
78692
+ if (!json)
78693
+ throw new Error("--json is required for benchmark phase commands");
78694
+ return { spec, result: result2, json: true };
78695
+ }
78696
+ function argumentFailure(phase, message) {
78697
+ const timestamp = new Date().toISOString();
78698
+ return {
78699
+ schema_version: "1",
78700
+ cli_version: VERSION,
78701
+ phase,
78702
+ attempt_id: null,
78703
+ phase_id: null,
78704
+ spec_digest: null,
78705
+ status: "failed",
78706
+ started_at: timestamp,
78707
+ completed_at: timestamp,
78708
+ duration_ms: 0,
78709
+ steps: [],
78710
+ inputs: [],
78711
+ outputs: [],
78712
+ error: {
78713
+ code: "invalid_arguments",
78714
+ message
78715
+ }
78716
+ };
78717
+ }
78718
+ function phaseFailure(invocation, startedAt, started, code, message) {
78719
+ return {
78720
+ schema_version: "1",
78721
+ cli_version: VERSION,
78722
+ phase: invocation.phase,
78723
+ attempt_id: invocation.attempt_id,
78724
+ phase_id: invocation.phase_id,
78725
+ spec_digest: invocation.spec_digest,
78726
+ status: "failed",
78727
+ started_at: startedAt,
78728
+ completed_at: new Date().toISOString(),
78729
+ duration_ms: Date.now() - started,
78730
+ steps: [],
78731
+ inputs: [],
78732
+ outputs: [],
78733
+ error: { code, message }
78734
+ };
78735
+ }
78736
+ function descendantPids2(parentPid) {
78737
+ if (process.platform === "win32")
78738
+ return [];
78739
+ try {
78740
+ const output = execFileSync3("ps", ["-eo", "pid=,ppid="], {
78741
+ encoding: "utf8",
78742
+ stdio: ["ignore", "pipe", "ignore"]
78743
+ });
78744
+ const children = new Map;
78745
+ for (const line of output.split(`
78746
+ `)) {
78747
+ const [pidRaw, parentRaw] = line.trim().split(/\s+/);
78748
+ const pid = Number(pidRaw);
78749
+ const parent = Number(parentRaw);
78750
+ if (!Number.isInteger(pid) || !Number.isInteger(parent))
78751
+ continue;
78752
+ const current = children.get(parent) ?? [];
78753
+ current.push(pid);
78754
+ children.set(parent, current);
78755
+ }
78756
+ const descendants = [];
78757
+ const stack = [...children.get(parentPid) ?? []];
78758
+ while (stack.length > 0) {
78759
+ const pid = stack.pop();
78760
+ descendants.push(pid);
78761
+ stack.push(...children.get(pid) ?? []);
78762
+ }
78763
+ return descendants;
78764
+ } catch {
78765
+ return [];
78766
+ }
78767
+ }
78768
+ function terminatePhase(child) {
78769
+ if (child.pid === undefined)
78770
+ return;
78771
+ for (const pid of descendantPids2(child.pid).reverse()) {
78772
+ try {
78773
+ process.kill(pid, "SIGKILL");
78774
+ } catch {}
78775
+ }
78776
+ try {
78777
+ if (process.platform !== "win32")
78778
+ process.kill(-child.pid, "SIGKILL");
78779
+ else
78780
+ child.kill("SIGKILL");
78781
+ } catch {
78782
+ child.kill("SIGKILL");
78783
+ }
78784
+ }
78785
+ function createAnonymousSpecFd(bytes) {
78786
+ const temporary = path88.join(os17.tmpdir(), `brainbase-benchmark-spec-${process.pid}-${crypto7.randomBytes(12).toString("hex")}`);
78787
+ fs80.writeFileSync(temporary, bytes, { flag: "wx", mode: 384 });
78788
+ try {
78789
+ const fd = fs80.openSync(temporary, "r");
78790
+ fs80.unlinkSync(temporary);
78791
+ return fd;
78792
+ } catch (error2) {
78793
+ fs80.rmSync(temporary, { force: true });
78794
+ throw error2;
78795
+ }
78796
+ }
78797
+ async function runSupervisedPhase(phase, parsed, write) {
78798
+ const startedAt = new Date().toISOString();
78799
+ const started = Date.now();
78800
+ const prepared = prepareBenchmarkPhaseInvocation(parsed.spec, parsed.result, phase, startedAt, started);
78801
+ if (!prepared.ok) {
78802
+ write(`${JSON.stringify(prepared.result)}
78803
+ `);
78804
+ return 1;
78805
+ }
78806
+ if (prepared.cached_result) {
78807
+ write(`${JSON.stringify(prepared.cached_result)}
78808
+ `);
78809
+ return 0;
78810
+ }
78811
+ const { invocation, spec_bytes: specBytes } = prepared;
78812
+ const deadline = started + invocation.timeout_ms;
78813
+ const entrypoint = process.argv[1];
78814
+ if (!entrypoint) {
78815
+ const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase supervisor could not resolve the CLI entrypoint");
78816
+ write(`${JSON.stringify(failure)}
78817
+ `);
78818
+ return 1;
78819
+ }
78820
+ const remainingMs = deadline - Date.now();
78821
+ if (remainingMs <= 0) {
78822
+ let failure = phaseFailure(invocation, startedAt, started, "phase_timeout", "phase budget expired");
78823
+ try {
78824
+ failure = writeBenchmarkPhaseTimeoutResult(specBytes, parsed.result, phase, startedAt, started);
78825
+ } catch {}
78826
+ write(`${JSON.stringify(failure)}
78827
+ `);
78828
+ return 1;
78829
+ }
78830
+ const childToken = crypto7.randomBytes(32).toString("hex");
78831
+ let specFd;
78832
+ try {
78833
+ specFd = createAnonymousSpecFd(specBytes);
78834
+ } catch {
78835
+ const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase supervisor could not snapshot the validated spec");
78836
+ write(`${JSON.stringify(failure)}
78837
+ `);
78838
+ return 1;
78839
+ }
78840
+ let child;
78841
+ try {
78842
+ child = spawn5(process.execPath, [
78843
+ entrypoint,
78844
+ "benchmark",
78845
+ "__phase-child",
78846
+ phase,
78847
+ "--result",
78848
+ parsed.result,
78849
+ "--spec-fd",
78850
+ "3",
78851
+ "--token",
78852
+ childToken
78853
+ ], {
78854
+ env: {
78855
+ ...process.env,
78856
+ BRAINBASE_BENCHMARK_PHASE_CHILD_TOKEN: childToken
78857
+ },
78858
+ stdio: ["ignore", "pipe", "pipe", specFd],
78859
+ detached: process.platform !== "win32"
78860
+ });
78861
+ } catch {
78862
+ fs80.closeSync(specFd);
78863
+ const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child process could not be started");
78864
+ write(`${JSON.stringify(failure)}
78865
+ `);
78866
+ return 1;
78867
+ }
78868
+ fs80.closeSync(specFd);
78869
+ return await new Promise((resolve) => {
78870
+ const stdout = [];
78871
+ let settled = false;
78872
+ let timedOut = false;
78873
+ let timer;
78874
+ const expire = () => {
78875
+ if (settled || timedOut)
78876
+ return;
78877
+ timedOut = true;
78878
+ terminatePhase(child);
78879
+ };
78880
+ const remainingAfterSpawn = deadline - Date.now();
78881
+ if (remainingAfterSpawn <= 0)
78882
+ queueMicrotask(expire);
78883
+ else
78884
+ timer = setTimeout(expire, remainingAfterSpawn);
78885
+ child.stdout?.on("data", (chunk2) => {
78886
+ if (!timedOut)
78887
+ stdout.push(chunk2);
78888
+ });
78889
+ child.stderr?.resume();
78890
+ child.on("error", () => {
78891
+ if (settled)
78892
+ return;
78893
+ settled = true;
78894
+ if (timer)
78895
+ clearTimeout(timer);
78896
+ const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child process could not be started");
78897
+ write(`${JSON.stringify(failure)}
78898
+ `);
78899
+ resolve(1);
78900
+ });
78901
+ child.on("close", (code) => {
78902
+ if (settled)
78903
+ return;
78904
+ settled = true;
78905
+ if (timer)
78906
+ clearTimeout(timer);
78907
+ if (Date.now() >= deadline)
78908
+ timedOut = true;
78909
+ if (timedOut) {
78910
+ let failure = phaseFailure(invocation, startedAt, started, "phase_timeout", "phase budget expired");
78911
+ try {
78912
+ failure = writeBenchmarkPhaseTimeoutResult(specBytes, parsed.result, phase, startedAt, started);
78913
+ } catch {}
78914
+ write(`${JSON.stringify(failure)}
78915
+ `);
78916
+ resolve(1);
78917
+ return;
78918
+ }
78919
+ const output = Buffer.concat(stdout).toString("utf8");
78920
+ if (!output) {
78921
+ const failure = phaseFailure(invocation, startedAt, started, "phase_supervisor_failed", "benchmark phase child exited without a result");
78922
+ write(`${JSON.stringify(failure)}
78923
+ `);
78924
+ resolve(1);
78925
+ return;
78926
+ }
78927
+ write(output.endsWith(`
78928
+ `) ? output : `${output}
78929
+ `);
78930
+ resolve(code === 0 ? 0 : 1);
78931
+ });
78932
+ });
78933
+ }
78934
+ async function runBenchmark(sub, args, write = (value) => process.stdout.write(value)) {
78935
+ switch (sub) {
78936
+ case "__phase-child": {
78937
+ const [
78938
+ phase,
78939
+ resultFlag,
78940
+ resultPath,
78941
+ specFdFlag,
78942
+ specFdRaw,
78943
+ tokenFlag,
78944
+ token
78945
+ ] = args;
78946
+ const specFd = Number(specFdRaw);
78947
+ if (phase !== "hydrate" && phase !== "evaluate" || resultFlag !== "--result" || !resultPath || specFdFlag !== "--spec-fd" || !Number.isInteger(specFd) || specFd < 3 || tokenFlag !== "--token" || !token || token !== process.env.BRAINBASE_BENCHMARK_PHASE_CHILD_TOKEN) {
78948
+ throw new Error("Invalid internal benchmark phase invocation");
78949
+ }
78950
+ const specBytes = fs80.readFileSync(specFd);
78951
+ const { exitCode, result: result2 } = await runBenchmarkPhase("", resultPath, phase, specBytes);
78952
+ write(`${JSON.stringify(result2)}
78953
+ `);
78954
+ return exitCode;
78955
+ }
78956
+ case "hydrate":
78957
+ case "evaluate": {
78958
+ let parsed;
78959
+ try {
78960
+ parsed = parsePhaseArgs(args);
78961
+ } catch (error2) {
78962
+ const failure = argumentFailure(sub, error2 instanceof Error ? error2.message : "invalid benchmark arguments");
78963
+ write(`${JSON.stringify(failure)}
78964
+ `);
78965
+ return 1;
78966
+ }
78967
+ return await runSupervisedPhase(sub, parsed, write);
78968
+ }
78969
+ case "capabilities": {
78970
+ if (args.length !== 1 || args[0] !== "--json") {
78971
+ throw new Error("Usage: brainbase benchmark capabilities --json");
78972
+ }
78973
+ write(`${JSON.stringify(BENCHMARK_CAPABILITIES)}
78974
+ `);
78975
+ return 0;
78976
+ }
78977
+ case undefined:
78978
+ case "help":
78979
+ case "-h":
78980
+ case "--help":
78981
+ printHelp5();
78982
+ return 0;
78983
+ default:
78984
+ throw new Error(`Unknown benchmark subcommand: ${sub}`);
78985
+ }
78986
+ }
78987
+ function printHelp5() {
78988
+ const out = [];
78989
+ out.push("");
78990
+ out.push(` ${import_picocolors48.default.bold("brainbase benchmark")} ${import_picocolors48.default.dim("<sub> [options]")}`);
78991
+ out.push("");
78992
+ out.push(` ${import_picocolors48.default.cyan("hydrate")} ${import_picocolors48.default.dim("--spec <path> --result <path> --json")}`);
78993
+ out.push(` ${import_picocolors48.default.cyan("evaluate")} ${import_picocolors48.default.dim("--spec <path> --result <path> --json")}`);
78994
+ out.push(` ${import_picocolors48.default.cyan("capabilities")} ${import_picocolors48.default.dim("--json")}`);
78995
+ out.push("");
78996
+ out.push(` ${import_picocolors48.default.dim("These machine-only commands execute versioned benchmark phase specs inside a task sandbox.")}`);
78997
+ out.push("");
78998
+ console.log(out.join(`
78999
+ `));
79000
+ }
79001
+
77033
79002
  // src/index.ts
77034
79003
  var PROTECTED = new Set([
77035
79004
  "template",
@@ -77037,128 +79006,143 @@ var PROTECTED = new Set([
77037
79006
  "link",
77038
79007
  "unlink",
77039
79008
  "sync",
77040
- "publish",
77041
79009
  "status",
77042
79010
  "token"
77043
79011
  ]);
77044
79012
  var STORED_PAT_COMMANDS = new Set([
77045
79013
  "template",
77046
79014
  "skill",
77047
- "publish",
77048
79015
  "token"
77049
79016
  ]);
79017
+ var SUBCOMMAND_OWNED_FLAGS = {
79018
+ token: ["--scope", "--name"]
79019
+ };
77050
79020
  function help() {
77051
79021
  const out = [];
77052
79022
  out.push("");
77053
- out.push(` ${brandTint("◆")} ${import_picocolors48.default.bold("brainbase")} ${import_picocolors48.default.dim(`v${VERSION}`)}`);
77054
- out.push(` ${import_picocolors48.default.dim("connect your local agent to the brainbase platform")}`);
79023
+ out.push(` ${brandTint("◆")} ${import_picocolors49.default.bold("brainbase")} ${import_picocolors49.default.dim(`v${VERSION}`)}`);
79024
+ out.push(` ${import_picocolors49.default.dim("connect your local agent to the brainbase platform")}`);
77055
79025
  out.push("");
77056
79026
  out.push(divider("USAGE"));
77057
79027
  out.push("");
77058
- out.push(` ${import_picocolors48.default.bold("brainbase")} ${import_picocolors48.default.dim("<command> [options]")}`);
79028
+ out.push(` ${import_picocolors49.default.bold("brainbase")} ${import_picocolors49.default.dim("<command> [options]")}`);
77059
79029
  out.push("");
77060
79030
  out.push(divider("AUTH"));
77061
79031
  out.push("");
77062
- out.push(` ${import_picocolors48.default.cyan("login")} ${import_picocolors48.default.dim(" open the web app and connect this device")}`);
77063
- out.push(` ${import_picocolors48.default.cyan("logout")} ${import_picocolors48.default.dim(" clear the local session")}`);
77064
- out.push(` ${import_picocolors48.default.cyan("whoami")} ${import_picocolors48.default.dim(" show the current user")}`);
79032
+ out.push(` ${import_picocolors49.default.cyan("login")} ${import_picocolors49.default.dim(" open the web app and connect this device")}`);
79033
+ out.push(` ${import_picocolors49.default.cyan("logout")} ${import_picocolors49.default.dim(" clear the local session")}`);
79034
+ out.push(` ${import_picocolors49.default.cyan("whoami")} ${import_picocolors49.default.dim(" show the current user")}`);
77065
79035
  out.push("");
77066
79036
  out.push(divider("DISCOVERY"));
77067
79037
  out.push("");
77068
- out.push(` ${import_picocolors48.default.cyan("team list")} ${import_picocolors48.default.dim("show the teams you can create agents in")}`);
77069
- out.push(` ${import_picocolors48.default.cyan("agent list")} ${import_picocolors48.default.dim("show a team's agents and their ids")}`);
79038
+ out.push(` ${import_picocolors49.default.cyan("team list")} ${import_picocolors49.default.dim("show the teams you can create agents in")}`);
79039
+ out.push(` ${import_picocolors49.default.cyan("agent list")} ${import_picocolors49.default.dim("show a team's agents and their ids")}`);
77070
79040
  out.push("");
77071
79041
  out.push(divider("LINKED AGENT"));
77072
79042
  out.push("");
77073
- out.push(` ${import_picocolors48.default.cyan("agent create")} ${import_picocolors48.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
77074
- out.push(` ${import_picocolors48.default.cyan("agent pull")} ${import_picocolors48.default.dim("[<id>]")} ${import_picocolors48.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
77075
- out.push(` ${import_picocolors48.default.cyan("agent push")} ${import_picocolors48.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
77076
- out.push(` ${import_picocolors48.default.cyan("agent unpack")} ${import_picocolors48.default.dim("install the claimed agent into a harness layout")}`);
77077
- out.push(` ${import_picocolors48.default.cyan("link")} ${import_picocolors48.default.dim("attach this folder to an existing agent")}`);
77078
- out.push(` ${import_picocolors48.default.cyan("agent status")} ${import_picocolors48.default.dim("show what would pull and what would push")}`);
77079
- out.push(` ${import_picocolors48.default.cyan("agent env")} ${import_picocolors48.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
77080
- out.push(` ${import_picocolors48.default.cyan("run")} ${import_picocolors48.default.dim("<cmd> [args...]")} ${import_picocolors48.default.dim("run <cmd> with secrets.env loaded into env")}`);
77081
- out.push(` ${import_picocolors48.default.cyan("status")} ${import_picocolors48.default.dim("show what this folder is linked to")}`);
77082
- out.push(` ${import_picocolors48.default.cyan("unlink")} ${import_picocolors48.default.dim("disconnect this folder")}`);
79043
+ out.push(` ${import_picocolors49.default.cyan("agent create")} ${import_picocolors49.default.dim("claim an unclaimed brainbase.agent.yaml and create the cloud agent")}`);
79044
+ out.push(` ${import_picocolors49.default.cyan("agent pull")} ${import_picocolors49.default.dim("[<id>]")} ${import_picocolors49.default.dim("bring cloud changes into this folder (--force to override; --run-entrypoint to also execute the agent entrypoint)")}`);
79045
+ out.push(` ${import_picocolors49.default.cyan("agent push")} ${import_picocolors49.default.dim("send local changes to the cloud (--force to overwrite cloud-side conflicts with local)")}`);
79046
+ out.push(` ${import_picocolors49.default.cyan("agent unpack")} ${import_picocolors49.default.dim("install the claimed agent into a harness layout")}`);
79047
+ out.push(` ${import_picocolors49.default.cyan("link")} ${import_picocolors49.default.dim("attach this folder to an existing agent")}`);
79048
+ out.push(` ${import_picocolors49.default.cyan("agent status")} ${import_picocolors49.default.dim("show what would pull and what would push")}`);
79049
+ out.push(` ${import_picocolors49.default.cyan("agent env")} ${import_picocolors49.default.dim("print export lines for `eval $(brainbase agent env)`")}`);
79050
+ out.push(` ${import_picocolors49.default.cyan("run")} ${import_picocolors49.default.dim("<cmd> [args...]")} ${import_picocolors49.default.dim("run <cmd> with secrets.env loaded into env")}`);
79051
+ out.push(` ${import_picocolors49.default.cyan("status")} ${import_picocolors49.default.dim("show what this folder is linked to")}`);
79052
+ out.push(` ${import_picocolors49.default.cyan("unlink")} ${import_picocolors49.default.dim("disconnect this folder")}`);
77083
79053
  out.push("");
77084
79054
  out.push(divider("TASKS"));
77085
79055
  out.push("");
77086
- out.push(` ${import_picocolors48.default.cyan("task create")} ${import_picocolors48.default.dim("--message <text>")} ${import_picocolors48.default.dim("create a managed task and start its first run")}`);
79056
+ out.push(` ${import_picocolors49.default.cyan("task create")} ${import_picocolors49.default.dim("--message <text>")} ${import_picocolors49.default.dim("create a managed task and start its first run")}`);
79057
+ out.push("");
79058
+ out.push(divider("BENCHMARK RUNTIME"));
79059
+ out.push("");
79060
+ out.push(` ${import_picocolors49.default.cyan("benchmark hydrate")} ${import_picocolors49.default.dim("--spec <path> --result <path> --json")}`);
79061
+ out.push(` ${import_picocolors49.default.cyan("benchmark evaluate")} ${import_picocolors49.default.dim("--spec <path> --result <path> --json")}`);
79062
+ out.push(` ${import_picocolors49.default.cyan("benchmark capabilities")} ${import_picocolors49.default.dim("--json")}`);
77087
79063
  out.push("");
77088
79064
  out.push(divider("ORCHESTRATIONS"));
77089
79065
  out.push("");
77090
- out.push(` ${import_picocolors48.default.cyan("orchestration create")} ${import_picocolors48.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
77091
- out.push(` ${import_picocolors48.default.cyan("orchestration list")} ${import_picocolors48.default.dim("list orchestrations under a team")}`);
77092
- out.push(` ${import_picocolors48.default.cyan("orchestration pull")} ${import_picocolors48.default.dim("<id>")} ${import_picocolors48.default.dim("recursively fetch an orchestration + every member agent")}`);
77093
- out.push(` ${import_picocolors48.default.cyan("orchestration push")} ${import_picocolors48.default.dim("recursively push each member, then update the graph")}`);
77094
- out.push(` ${import_picocolors48.default.cyan("orchestration status")} ${import_picocolors48.default.dim("show what would push and what would pull")}`);
79066
+ out.push(` ${import_picocolors49.default.cyan("orchestration create")} ${import_picocolors49.default.dim("claim a local orchestration manifest and create it in the cloud")}`);
79067
+ out.push(` ${import_picocolors49.default.cyan("orchestration list")} ${import_picocolors49.default.dim("list orchestrations under a team")}`);
79068
+ out.push(` ${import_picocolors49.default.cyan("orchestration pull")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("recursively fetch an orchestration + every member agent")}`);
79069
+ out.push(` ${import_picocolors49.default.cyan("orchestration push")} ${import_picocolors49.default.dim("recursively push each member, then update the graph")}`);
79070
+ out.push(` ${import_picocolors49.default.cyan("orchestration status")} ${import_picocolors49.default.dim("show what would push and what would pull")}`);
77095
79071
  out.push("");
77096
79072
  out.push(divider("TEMPLATES"));
77097
79073
  out.push("");
77098
- out.push(` ${import_picocolors48.default.cyan("template pack")} ${import_picocolors48.default.dim("bundle the current agent into a template")}`);
77099
- out.push(` ${import_picocolors48.default.cyan("template publish")} ${import_picocolors48.default.dim("upload a template to the registry")}`);
77100
- out.push(` ${import_picocolors48.default.cyan("template search")} ${import_picocolors48.default.dim("[query]")} ${import_picocolors48.default.dim("search the registry")}`);
77101
- out.push(` ${import_picocolors48.default.cyan("template info")} ${import_picocolors48.default.dim("<creator/slug>")} ${import_picocolors48.default.dim("show registry details for a template")}`);
77102
- out.push(` ${import_picocolors48.default.cyan("template onboard")} ${import_picocolors48.default.dim("<creator/slug>")} ${import_picocolors48.default.dim("install (or refresh) a template")}`);
77103
- out.push(` ${import_picocolors48.default.cyan("template list")} ${import_picocolors48.default.dim("show installed templates")}`);
77104
- out.push(` ${import_picocolors48.default.cyan("template remove")} ${import_picocolors48.default.dim("<creator/slug>")} ${import_picocolors48.default.dim("uninstall a template")}`);
79074
+ out.push(` ${import_picocolors49.default.cyan("template pack")} ${import_picocolors49.default.dim("bundle the current agent into a template")}`);
79075
+ out.push(` ${import_picocolors49.default.cyan("template publish")} ${import_picocolors49.default.dim("upload a template to the registry")}`);
79076
+ out.push(` ${import_picocolors49.default.cyan("template search")} ${import_picocolors49.default.dim("[query]")} ${import_picocolors49.default.dim("search the registry")}`);
79077
+ out.push(` ${import_picocolors49.default.cyan("template info")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("show registry details for a template")}`);
79078
+ out.push(` ${import_picocolors49.default.cyan("template onboard")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("install (or refresh) a template")}`);
79079
+ out.push(` ${import_picocolors49.default.cyan("template list")} ${import_picocolors49.default.dim("show installed templates")}`);
79080
+ out.push(` ${import_picocolors49.default.cyan("template remove")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("uninstall a template")}`);
77105
79081
  out.push("");
77106
79082
  out.push(divider("SKILLS"));
77107
79083
  out.push("");
77108
- out.push(` ${import_picocolors48.default.cyan("skill add")} ${import_picocolors48.default.dim("<source>")} ${import_picocolors48.default.dim("install a skill (github / git / brainbase)")}`);
77109
- out.push(` ${import_picocolors48.default.cyan("skill list")} ${import_picocolors48.default.dim("show locally installed skills + their source")}`);
77110
- out.push(` ${import_picocolors48.default.cyan("skill update")} ${import_picocolors48.default.dim("<slug>")} ${import_picocolors48.default.dim("re-fetch a skill from its recorded source")}`);
77111
- out.push(` ${import_picocolors48.default.cyan("skill remove")} ${import_picocolors48.default.dim("<slug>")} ${import_picocolors48.default.dim("uninstall a skill")}`);
77112
- out.push(` ${import_picocolors48.default.cyan("skill search")} ${import_picocolors48.default.dim("[query]")} ${import_picocolors48.default.dim("search the brainbase skill registry")}`);
77113
- out.push(` ${import_picocolors48.default.cyan("skill info")} ${import_picocolors48.default.dim("<creator/slug>")} ${import_picocolors48.default.dim("show registry details for a skill")}`);
77114
- out.push(` ${import_picocolors48.default.cyan("skill publish")} ${import_picocolors48.default.dim("[dir]")} ${import_picocolors48.default.dim("publish a SKILL.md folder (defaults to .)")}`);
79084
+ out.push(` ${import_picocolors49.default.cyan("skill add")} ${import_picocolors49.default.dim("<source>")} ${import_picocolors49.default.dim("install a skill (github / git / brainbase)")}`);
79085
+ out.push(` ${import_picocolors49.default.cyan("skill list")} ${import_picocolors49.default.dim("show locally installed skills + their source")}`);
79086
+ out.push(` ${import_picocolors49.default.cyan("skill update")} ${import_picocolors49.default.dim("<slug>")} ${import_picocolors49.default.dim("re-fetch a skill from its recorded source")}`);
79087
+ out.push(` ${import_picocolors49.default.cyan("skill remove")} ${import_picocolors49.default.dim("<slug>")} ${import_picocolors49.default.dim("uninstall a skill")}`);
79088
+ out.push(` ${import_picocolors49.default.cyan("skill search")} ${import_picocolors49.default.dim("[query]")} ${import_picocolors49.default.dim("search the brainbase skill registry")}`);
79089
+ out.push(` ${import_picocolors49.default.cyan("skill info")} ${import_picocolors49.default.dim("<creator/slug>")} ${import_picocolors49.default.dim("show registry details for a skill")}`);
79090
+ out.push(` ${import_picocolors49.default.cyan("skill publish")} ${import_picocolors49.default.dim("[dir]")} ${import_picocolors49.default.dim("publish a SKILL.md folder (defaults to .)")}`);
77115
79091
  out.push("");
77116
79092
  out.push(divider("CLI TOKENS"));
77117
79093
  out.push("");
77118
- out.push(` ${import_picocolors48.default.cyan("token create")} ${import_picocolors48.default.dim("issue a long-lived CLI key for CI / scripts")}`);
77119
- out.push(` ${import_picocolors48.default.cyan("token list")} ${import_picocolors48.default.dim("show your active tokens")}`);
77120
- out.push(` ${import_picocolors48.default.cyan("token revoke")} ${import_picocolors48.default.dim("<id>")} ${import_picocolors48.default.dim("revoke a token")}`);
79094
+ out.push(` ${import_picocolors49.default.cyan("token create")} ${import_picocolors49.default.dim("issue a long-lived CLI key for CI / scripts")}`);
79095
+ out.push(` ${import_picocolors49.default.cyan("token list")} ${import_picocolors49.default.dim("show your active tokens")}`);
79096
+ out.push(` ${import_picocolors49.default.cyan("token revoke")} ${import_picocolors49.default.dim("<id>")} ${import_picocolors49.default.dim("revoke a token")}`);
77121
79097
  out.push("");
77122
79098
  out.push(divider("MCP"));
77123
79099
  out.push("");
77124
- out.push(` ${import_picocolors48.default.cyan("mcp check")} ${import_picocolors48.default.dim("[--json]")} ${import_picocolors48.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
79100
+ out.push(` ${import_picocolors49.default.cyan("mcp check")} ${import_picocolors49.default.dim("[--json]")} ${import_picocolors49.default.dim("verify MCP server connectivity through the brainbase proxy (runs at sandbox bootstrap)")}`);
77125
79101
  out.push("");
77126
79102
  out.push(divider("FLAGS"));
77127
79103
  out.push("");
77128
- out.push(` ${import_picocolors48.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
77129
- out.push(` ${import_picocolors48.default.dim("--scope <s>")} force scope: global | project`);
77130
- out.push(` ${import_picocolors48.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
77131
- out.push(` ${import_picocolors48.default.dim("--agent <id>")} for link/task create: use this agent id explicitly`);
77132
- out.push(` ${import_picocolors48.default.dim("--message <text>")} for task create: required first user message`);
77133
- out.push(` ${import_picocolors48.default.dim("--title <text>")} for task create: optional task title`);
77134
- out.push(` ${import_picocolors48.default.dim("--model <id>")} for task create: optional model override`);
77135
- out.push(` ${import_picocolors48.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
77136
- out.push(` ${import_picocolors48.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
77137
- out.push(` ${import_picocolors48.default.dim("--json")} for team/agent list, task create, mcp check: machine-readable output`);
77138
- out.push(` ${import_picocolors48.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
77139
- out.push(` ${import_picocolors48.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
77140
- out.push(` ${import_picocolors48.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
77141
- out.push(` ${import_picocolors48.default.dim("--all")} for template list: include installs from other folders`);
77142
- out.push(` ${import_picocolors48.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
79104
+ out.push(` ${import_picocolors49.default.dim("--harness <id>")} force harness for onboard / sync (e.g. claude-code)`);
79105
+ out.push(` ${import_picocolors49.default.dim("--scope <s>")} force scope: global | project`);
79106
+ out.push(` ${import_picocolors49.default.dim("--yes, -y")} skip confirmations / auto-overwrite`);
79107
+ out.push(` ${import_picocolors49.default.dim("--agent <id>")} for link/task create: use this agent id explicitly`);
79108
+ out.push(` ${import_picocolors49.default.dim("--message <text>")} for task create: required first user message`);
79109
+ out.push(` ${import_picocolors49.default.dim("--title <text>")} for task create: optional task title`);
79110
+ out.push(` ${import_picocolors49.default.dim("--model <id>")} for task create: optional model override`);
79111
+ out.push(` ${import_picocolors49.default.dim("--org <id-or-slug>")} pick the organization (team/agent list, agent create, orchestration create/list)`);
79112
+ out.push(` ${import_picocolors49.default.dim("--team <id>")} pick the team, same commands (works without --org)`);
79113
+ out.push(` ${import_picocolors49.default.dim("--json")} machine-readable output for supported commands`);
79114
+ out.push(` ${import_picocolors49.default.dim("--no-tracking")} for link: skip routing LLM traffic through brainbase`);
79115
+ out.push(` ${import_picocolors49.default.dim("--track")} for agent create: enable tracking non-interactively (off without a TTY)`);
79116
+ out.push(` ${import_picocolors49.default.dim("--shell <sh|fish>")} for agent env: pick output format (auto-detected from $SHELL)`);
79117
+ out.push(` ${import_picocolors49.default.dim("--all")} for template list: include installs from other folders`);
79118
+ out.push(` ${import_picocolors49.default.dim("--web <url>")} for login: web app URL (default https://app.brainbaselabs.com)`);
77143
79119
  out.push("");
77144
79120
  out.push(divider("ENV"));
77145
79121
  out.push("");
77146
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
77147
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
77148
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
77149
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
77150
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
77151
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
77152
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
77153
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
77154
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode skip/auto-default prompts (CI & agents)`);
77155
- out.push(` ${import_picocolors48.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
79122
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_HOME")} override the local config dir (default ~/.brainbase)`);
79123
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_DEBUG")} print full stack traces on error (any value; unset to disable)`);
79124
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_WEB_URL")} override the web app URL used by login`);
79125
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_CONTROL_PLANE_URL")} override the MAS host (/v2/cli; task create uses /v2/tasks)`);
79126
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
79127
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
79128
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
79129
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
79130
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
79131
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode skip/auto-default prompts (CI & agents)`);
79132
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
79133
+ out.push("");
79134
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEMORY_MCP_URL")} override the built-in memory MCP host`);
79135
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_BROWSER_MCP_URL")} override the built-in browser MCP host`);
79136
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_SLACK_MCP_URL")} override the built-in Slack MCP host`);
79137
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_MEETING_MCP_URL")} override the built-in meeting MCP host`);
79138
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_GITHUB_MCP_URL")} override the built-in GitHub MCP host`);
79139
+ out.push(` ${import_picocolors49.default.dim("BRAINBASE_ORCHESTRATION_MCP_URL")} override the built-in orchestration MCP host`);
77156
79140
  out.push("");
77157
79141
  out.push(divider("HARNESSES"));
77158
79142
  out.push("");
77159
- out.push(` ${import_picocolors48.default.dim("•")} ${import_picocolors48.default.bold("claude-code")} ${import_picocolors48.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
77160
- out.push(` ${import_picocolors48.default.dim("•")} ${import_picocolors48.default.bold("codex")} ${import_picocolors48.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
77161
- out.push(` ${import_picocolors48.default.dim("•")} ${import_picocolors48.default.bold("kafka")} ${import_picocolors48.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
79143
+ out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("claude-code")} ${import_picocolors49.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
79144
+ out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("codex")} ${import_picocolors49.default.dim("skills, mcps, commands, playbooks, instructions, files")}`);
79145
+ out.push(` ${import_picocolors49.default.dim("•")} ${import_picocolors49.default.bold("kafka")} ${import_picocolors49.default.dim("skills, mcps, agents, commands, playbooks, instructions, files")}`);
77162
79146
  out.push("");
77163
79147
  console.log(out.join(`
77164
79148
  `));
@@ -77222,13 +79206,13 @@ async function requireAuth(cmd) {
77222
79206
  if (STORED_PAT_COMMANDS.has(cmd) && readToken())
77223
79207
  return;
77224
79208
  console.error("");
77225
- console.error(` ${brandTint("◆")} ${import_picocolors48.default.bold("brainbase")}`);
79209
+ console.error(` ${brandTint("◆")} ${import_picocolors49.default.bold("brainbase")}`);
77226
79210
  console.error("");
77227
- console.error(` ${import_picocolors48.default.red("✗")} You need to sign in to use ${import_picocolors48.default.bold("brainbase " + cmd)}.`);
79211
+ console.error(` ${import_picocolors49.default.red("✗")} You need to sign in to use ${import_picocolors49.default.bold("brainbase " + cmd)}.`);
77228
79212
  if (status.reason)
77229
- console.error(` ${import_picocolors48.default.dim(status.reason)}`);
79213
+ console.error(` ${import_picocolors49.default.dim(status.reason)}`);
77230
79214
  console.error("");
77231
- console.error(` Run ${import_picocolors48.default.cyan("brainbase login")} to connect this device.`);
79215
+ console.error(` Run ${import_picocolors49.default.cyan("brainbase login")} to connect this device.`);
77232
79216
  console.error("");
77233
79217
  process14.exit(1);
77234
79218
  }
@@ -77238,7 +79222,7 @@ async function main() {
77238
79222
  const rawCwd = process14.cwd();
77239
79223
  const cwd2 = (() => {
77240
79224
  try {
77241
- return fs79.realpathSync(rawCwd);
79225
+ return fs81.realpathSync(rawCwd);
77242
79226
  } catch {
77243
79227
  return rawCwd;
77244
79228
  }
@@ -77251,11 +79235,16 @@ async function main() {
77251
79235
  await runRun(cwd2, argv);
77252
79236
  return;
77253
79237
  }
77254
- const sharedArgs = cmd === "task" ? [] : argv;
79238
+ const sharedArgs = cmd === "task" || cmd === "benchmark" ? [] : argv;
79239
+ const ownedFlags = new Set(SUBCOMMAND_OWNED_FLAGS[cmd] ?? []);
79240
+ const takeFlag = (...names) => {
79241
+ const consumable = names.filter((n) => !ownedFlags.has(n));
79242
+ return consumable.length > 0 ? getFlag(sharedArgs, ...consumable) : undefined;
79243
+ };
77255
79244
  const yes = hasFlag2(sharedArgs, "--yes", "-y");
77256
79245
  const all = hasFlag2(sharedArgs, "--all");
77257
79246
  const harness = getFlag(sharedArgs, "--harness");
77258
- const scopeFlag = getFlag(sharedArgs, "--scope");
79247
+ const scopeFlag = takeFlag("--scope");
77259
79248
  const web = getFlag(sharedArgs, "--web");
77260
79249
  const visibility = getFlag(sharedArgs, "--visibility");
77261
79250
  const category = getFlag(sharedArgs, "--category");
@@ -77270,7 +79259,7 @@ async function main() {
77270
79259
  const forceFlag = hasFlag2(sharedArgs, "--force");
77271
79260
  const runEntrypointFlag = hasFlag2(sharedArgs, "--run-entrypoint");
77272
79261
  const graphOnlyFlag = hasFlag2(sharedArgs, "--graph-only");
77273
- const nameFlag = getFlag(sharedArgs, "--name");
79262
+ const nameFlag = takeFlag("--name");
77274
79263
  const skillVersionFlag = getFlag(sharedArgs, "--skill-version");
77275
79264
  const taglineFlag = getFlag(sharedArgs, "--tagline");
77276
79265
  const orgIdFlag = getFlag(sharedArgs, "--org");
@@ -77380,6 +79369,11 @@ async function main() {
77380
79369
  await runTask(cwd2, sub, argv);
77381
79370
  break;
77382
79371
  }
79372
+ case "benchmark": {
79373
+ const sub = argv.shift();
79374
+ process14.exitCode = await runBenchmark(sub, argv);
79375
+ break;
79376
+ }
77383
79377
  case "orchestration":
77384
79378
  case "orch": {
77385
79379
  const sub = argv.shift();
@@ -77399,7 +79393,7 @@ async function main() {
77399
79393
  break;
77400
79394
  }
77401
79395
  case "publish": {
77402
- await runPublish(cwd2, { yes });
79396
+ runPublish();
77403
79397
  break;
77404
79398
  }
77405
79399
  case "status": {
@@ -77419,10 +79413,10 @@ async function main() {
77419
79413
  process14.exit(1);
77420
79414
  }
77421
79415
  } catch (err) {
77422
- console.error(import_picocolors48.default.red(`
79416
+ console.error(import_picocolors49.default.red(`
77423
79417
  ${err.message}`));
77424
79418
  if (err instanceof ApiError && err.status === 401) {
77425
- console.error(` Run ${import_picocolors48.default.cyan("brainbase login")} to connect this device.`);
79419
+ console.error(` Run ${import_picocolors49.default.cyan("brainbase login")} to connect this device.`);
77426
79420
  }
77427
79421
  if (process14.env.BRAINBASE_DEBUG)
77428
79422
  console.error(err.stack);