@brainbase-labs/cli 0.22.0 → 0.24.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 +23 -5
  2. package/dist/index.js +958 -80
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -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.22.0",
36011
+ version: "0.24.0",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -53931,6 +53931,76 @@ function clearTokenIfMatches(prefix) {
53931
53931
  });
53932
53932
  }
53933
53933
 
53934
+ // src/core/credentials.ts
53935
+ var REGISTRY_COMMANDS = "template, skill, token";
53936
+ var CONTROL_PLANE_COMMANDS = "agent, orchestration, link, unlink, sync, status, team";
53937
+ var NOT_A_PAT = "(not a bbpat_… token)";
53938
+ function maskPat(token) {
53939
+ if (!isValidTokenFormat(token))
53940
+ return NOT_A_PAT;
53941
+ return token.slice(0, TOKEN_PREFIX_LEN);
53942
+ }
53943
+ function readEnvPat() {
53944
+ const value = process.env.BRAINBASE_TOKEN?.trim();
53945
+ if (!value)
53946
+ return null;
53947
+ return { prefix: maskPat(value), malformed: !isValidTokenFormat(value) };
53948
+ }
53949
+ function storedPatIgnoredHint(client) {
53950
+ const setEnv = `Set BRAINBASE_TOKEN to that token's value to authenticate with it here, ` + "or run `brainbase login` to refresh the session";
53951
+ switch (client) {
53952
+ case "control-plane":
53953
+ return `The PAT saved in ${TOKEN_FILE} is never used by control-plane ` + `commands (${CONTROL_PLANE_COMMANDS}). ${setEnv}.`;
53954
+ case "managed-task":
53955
+ return `The PAT saved in ${TOKEN_FILE} is not used while a login session is ` + `configured. ${setEnv} — or \`brainbase logout\`, which leaves the ` + "PAT as the only credential.";
53956
+ default: {
53957
+ const exhaustive = client;
53958
+ throw new Error(`unhandled credential client: ${String(exhaustive)}`);
53959
+ }
53960
+ }
53961
+ }
53962
+ function withStoredPatHint(reason, client) {
53963
+ if (!readToken())
53964
+ return reason;
53965
+ const trimmed = reason.trimEnd();
53966
+ const separator = /[.!?:]$/.test(trimmed) ? " " : ". ";
53967
+ return `${trimmed}${separator}${storedPatIgnoredHint(client)}`;
53968
+ }
53969
+ function withRejectedSessionHint(message, source, client) {
53970
+ if (source !== "session")
53971
+ return message;
53972
+ return withStoredPatHint(message, client);
53973
+ }
53974
+ function isRefreshable(session) {
53975
+ return Boolean(session.refresh_token && session.supabase_url && session.supabase_anon_key);
53976
+ }
53977
+ function describeCredentials() {
53978
+ const env3 = readEnvPat();
53979
+ const status = authStatus();
53980
+ const stored = readToken();
53981
+ const refreshable = Boolean(status.session && !status.ok && isRefreshable(status.session));
53982
+ const session = status.session ? {
53983
+ email: status.session.email ?? null,
53984
+ userId: status.session.user_id,
53985
+ expiresAt: status.session.expires_at ?? null,
53986
+ expired: !status.ok,
53987
+ refreshable
53988
+ } : null;
53989
+ let active = null;
53990
+ if (env3)
53991
+ active = "env_pat";
53992
+ else if (status.ok || refreshable)
53993
+ active = "session";
53994
+ else if (stored)
53995
+ active = "stored_pat";
53996
+ return {
53997
+ active,
53998
+ envPat: env3,
53999
+ session,
54000
+ storedPat: stored ? { name: stored.name ?? null, prefix: stored.prefix } : null
54001
+ };
54002
+ }
54003
+
53934
54004
  // src/core/api.ts
53935
54005
  var DEFAULT_CONTROL_PLANE_BASE = "https://api.brainbaselabs.com";
53936
54006
  var DEFAULT_PROXY_BASE = "https://api.v1.brainbaselabs.com";
@@ -54005,7 +54075,7 @@ function legacyScheduleError() {
54005
54075
  function legacyAgentConfigError() {
54006
54076
  return new ApiError("Declarative machine/model config requires the MAS control plane. Set BRAINBASE_CONTROL_PLANE_URL or unset the legacy BRAINBASE_API_URL override.", 400);
54007
54077
  }
54008
- async function resolveCredential() {
54078
+ async function resolveCredential(storedPatHint = "control-plane") {
54009
54079
  const envToken = process.env.BRAINBASE_TOKEN;
54010
54080
  if (envToken && envToken.trim()) {
54011
54081
  return {
@@ -54023,19 +54093,20 @@ async function resolveCredential() {
54023
54093
  };
54024
54094
  }
54025
54095
  const status = authStatus();
54026
- throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : status.reason ?? "not logged in", 401);
54096
+ const reason = status.reason ?? "not logged in";
54097
+ throw new ApiError(status.ok ? "CLI authentication changed while this command was starting; retry it" : storedPatHint ? withStoredPatHint(reason, storedPatHint) : reason, 401);
54027
54098
  }
54028
54099
  async function resolveMasCredential() {
54029
54100
  const configuredSession = readAuth();
54030
54101
  try {
54031
- return await resolveCredential();
54102
+ return await resolveCredential(null);
54032
54103
  } catch (error) {
54033
54104
  if (!(error instanceof ApiError && error.status === 401)) {
54034
54105
  throw error;
54035
54106
  }
54036
54107
  if (configuredSession || readAuth()) {
54037
54108
  if (readToken()) {
54038
- throw new ApiError(`${error.message}. A stored PAT is available but will not be used while a login session is configured. Run \`brainbase logout\` to use the stored PAT, or \`brainbase login\` to refresh the session.`, 401);
54109
+ throw new ApiError(`${error.message}. ${storedPatIgnoredHint("managed-task")}`, 401);
54039
54110
  }
54040
54111
  throw error;
54041
54112
  }
@@ -54134,7 +54205,8 @@ async function request(pathname, init = {}) {
54134
54205
  body = text2 ? JSON.parse(text2) : null;
54135
54206
  } catch {}
54136
54207
  if (!res.ok) {
54137
- throw new ApiError(apiErrorMessage(body, res.status), res.status, body);
54208
+ const message = apiErrorMessage(body, res.status);
54209
+ throw new ApiError(res.status === 401 ? withRejectedSessionHint(message, credential.source, "control-plane") : message, res.status, body);
54138
54210
  }
54139
54211
  return body;
54140
54212
  }
@@ -54277,7 +54349,7 @@ async function masRequest(pathname, init) {
54277
54349
  }
54278
54350
  if (!res.ok) {
54279
54351
  const message = masApiErrorMessage(body, res.status);
54280
- throw new ApiError(res.status >= 500 ? `${message} Task creation may still be processing; check your tasks before running this command again.` : message, res.status, body);
54352
+ throw new ApiError(res.status >= 500 ? `${message} Task creation may still be processing; check your tasks before running this command again.` : res.status === 401 ? withRejectedSessionHint(message, credential.source, "managed-task") : message, res.status, body);
54281
54353
  }
54282
54354
  return body;
54283
54355
  }
@@ -61658,12 +61730,13 @@ async function runLogin(_cwd, args) {
61658
61730
  // src/ui/ink/IdentityCard.tsx
61659
61731
  var jsx_dev_runtime15 = __toESM(require_jsx_dev_runtime(), 1);
61660
61732
  function IdentityCard(props) {
61733
+ const hasRows = Boolean(props.rows?.length || props.controlPlaneUrl || props.expiresAt);
61661
61734
  return /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Card, {
61662
61735
  title: props.title,
61663
61736
  tone: props.tone ?? "info",
61664
61737
  children: [
61665
61738
  props.email && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61666
- marginBottom: props.controlPlaneUrl || props.expiresAt ? 1 : 0,
61739
+ marginBottom: hasRows ? 1 : 0,
61667
61740
  children: /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61668
61741
  bold: true,
61669
61742
  children: props.email
@@ -61672,6 +61745,20 @@ function IdentityCard(props) {
61672
61745
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61673
61746
  flexDirection: "column",
61674
61747
  children: [
61748
+ props.rows?.map(([label, value]) => /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61749
+ children: [
61750
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61751
+ width: 15,
61752
+ children: /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61753
+ dimColor: true,
61754
+ children: label
61755
+ }, undefined, false, undefined, this)
61756
+ }, undefined, false, undefined, this),
61757
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
61758
+ children: value
61759
+ }, undefined, false, undefined, this)
61760
+ ]
61761
+ }, label, true, undefined, this)),
61675
61762
  props.controlPlaneUrl && /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
61676
61763
  children: [
61677
61764
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
@@ -61739,22 +61826,117 @@ async function runLogout() {
61739
61826
  }
61740
61827
 
61741
61828
  // src/cli/whoami.ts
61742
- async function runWhoami() {
61743
- const { ok, session, reason } = authStatus();
61744
- if (!ok || !session) {
61745
- await showIdentityCard({
61746
- title: "NOT SIGNED IN",
61747
- tone: "warn",
61748
- message: `${reason ?? "not logged in"}. Run \`brainbase login\` to connect this device.`
61749
- });
61750
- process.exit(1);
61829
+ function usableForControlPlane(report) {
61830
+ switch (report.active) {
61831
+ case "env_pat":
61832
+ return !report.envPat?.malformed;
61833
+ case "session":
61834
+ return true;
61835
+ case "stored_pat":
61836
+ case null:
61837
+ return false;
61838
+ default: {
61839
+ const exhaustive = report.active;
61840
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61841
+ }
61751
61842
  }
61843
+ }
61844
+ function exitCodeFor(report) {
61845
+ return usableForControlPlane(report) ? 0 : 1;
61846
+ }
61847
+ function reasonFor(report) {
61848
+ switch (report.active) {
61849
+ case "env_pat":
61850
+ return report.envPat?.malformed ? "BRAINBASE_TOKEN is set to something that is not a `bbpat_…` token, " + "and it outranks every other credential — so every request will fail " + "until it is corrected or unset. Mint one with `brainbase token create`." : null;
61851
+ case "session":
61852
+ return null;
61853
+ case "stored_pat":
61854
+ return `The stored PAT authenticates registry commands (${REGISTRY_COMMANDS}) only. ` + `Set BRAINBASE_TOKEN to its value for ${CONTROL_PLANE_COMMANDS}, ` + "or run `brainbase login`.";
61855
+ case null:
61856
+ return report.session?.expired ? "Session expired. Run `brainbase login` to connect this device." : "Not logged in. Run `brainbase login` to connect this device.";
61857
+ default: {
61858
+ const exhaustive = report.active;
61859
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61860
+ }
61861
+ }
61862
+ }
61863
+ function toJson(report, reason) {
61864
+ const usingSession = report.active === "session";
61865
+ return {
61866
+ credential: report.active,
61867
+ authenticated: report.active !== null && !report.envPat?.malformed,
61868
+ control_plane: usableForControlPlane(report),
61869
+ email: usingSession ? report.session?.email ?? null : null,
61870
+ user_id: usingSession ? report.session?.userId ?? null : null,
61871
+ expires_at: usingSession ? report.session?.expiresAt ?? null : null,
61872
+ token_prefix: report.active === "env_pat" ? report.envPat?.prefix ?? null : report.active === "stored_pat" ? report.storedPat?.prefix ?? null : null,
61873
+ control_plane_url: controlPlaneBaseUrl(usingSession ? readAuth() : null),
61874
+ session: report.session ? {
61875
+ present: true,
61876
+ expired: report.session.expired,
61877
+ refreshable: report.session.refreshable
61878
+ } : { present: false, expired: false, refreshable: false },
61879
+ stored_pat: report.storedPat ? { present: true, name: report.storedPat.name } : { present: false, name: null },
61880
+ reason
61881
+ };
61882
+ }
61883
+ function displayPrefix(prefix) {
61884
+ return prefix === NOT_A_PAT ? prefix : `${prefix}…`;
61885
+ }
61886
+ function cardRows(report) {
61887
+ const rows = [];
61888
+ switch (report.active) {
61889
+ case "env_pat":
61890
+ rows.push(["credential", "BRAINBASE_TOKEN (env PAT)"]);
61891
+ if (report.envPat) {
61892
+ rows.push(["token", displayPrefix(report.envPat.prefix)]);
61893
+ }
61894
+ break;
61895
+ case "session":
61896
+ rows.push([
61897
+ "credential",
61898
+ report.session?.refreshable ? "login session (auth.json) — expired, renews on next use" : "login session (auth.json)"
61899
+ ]);
61900
+ break;
61901
+ case "stored_pat":
61902
+ rows.push(["credential", "stored PAT (token.json)"]);
61903
+ rows.push([
61904
+ "token",
61905
+ report.storedPat?.name ? `${displayPrefix(report.storedPat.prefix)} (${report.storedPat.name})` : displayPrefix(report.storedPat?.prefix ?? "?")
61906
+ ]);
61907
+ break;
61908
+ case null:
61909
+ break;
61910
+ default: {
61911
+ const exhaustive = report.active;
61912
+ throw new Error(`unhandled credential: ${String(exhaustive)}`);
61913
+ }
61914
+ }
61915
+ if (report.session && report.active !== "session") {
61916
+ rows.push([
61917
+ "session",
61918
+ `${report.session.email ?? report.session.userId} (${report.session.expired ? "expired" : "not used — env PAT wins"})`
61919
+ ]);
61920
+ }
61921
+ return rows;
61922
+ }
61923
+ async function runWhoami(args = {}) {
61924
+ const report = describeCredentials();
61925
+ const reason = reasonFor(report);
61926
+ process.exitCode = exitCodeFor(report);
61927
+ if (args.json) {
61928
+ console.log(JSON.stringify(toJson(report, reason), null, 2));
61929
+ return;
61930
+ }
61931
+ const signedIn = report.active !== null;
61752
61932
  await showIdentityCard({
61753
- title: "WHOAMI",
61754
- tone: "ok",
61755
- email: session.email ?? session.user_id,
61756
- controlPlaneUrl: controlPlaneBaseUrl(session),
61757
- expiresAt: session.expires_at
61933
+ title: signedIn ? "WHOAMI" : "NOT SIGNED IN",
61934
+ tone: process.exitCode === 0 ? "ok" : "warn",
61935
+ email: report.active === "session" ? report.session?.email ?? report.session?.userId ?? null : null,
61936
+ controlPlaneUrl: signedIn ? controlPlaneBaseUrl(report.active === "session" ? readAuth() : null) : null,
61937
+ expiresAt: report.active === "session" ? report.session?.expiresAt : null,
61938
+ rows: cardRows(report),
61939
+ message: reason ?? undefined
61758
61940
  });
61759
61941
  }
61760
61942
 
@@ -68922,14 +69104,6 @@ function TokenCreatedCard(props) {
68922
69104
  tone: "warn",
68923
69105
  subtitle: "shown ONCE — copy it now",
68924
69106
  children: [
68925
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
68926
- marginBottom: 1,
68927
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68928
- bold: true,
68929
- color: "yellow",
68930
- children: props.token
68931
- }, undefined, false, undefined, this)
68932
- }, undefined, false, undefined, this),
68933
69107
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
68934
69108
  flexDirection: "column",
68935
69109
  marginBottom: 1,
@@ -68990,20 +69164,22 @@ function TokenCreatedCard(props) {
68990
69164
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68991
69165
  dimColor: true,
68992
69166
  children: [
68993
- "saved locally to ",
69167
+ "saved to ",
68994
69168
  props.storedAt,
68995
- " (mode 0600)"
69169
+ " (mode 0600) — covers ",
69170
+ REGISTRY_COMMANDS
68996
69171
  ]
68997
69172
  }, undefined, true, undefined, this),
68998
69173
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
68999
69174
  dimColor: true,
69000
69175
  children: [
69001
- "for CI: set ",
69176
+ CONTROL_PLANE_COMMANDS,
69177
+ " do ",
69002
69178
  /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
69003
69179
  bold: true,
69004
- children: "BRAINBASE_TOKEN"
69180
+ children: "not"
69005
69181
  }, undefined, false, undefined, this),
69006
- " instead of relying on token.json"
69182
+ " read that file export it instead:"
69007
69183
  ]
69008
69184
  }, undefined, true, undefined, this)
69009
69185
  ]
@@ -69012,9 +69188,12 @@ function TokenCreatedCard(props) {
69012
69188
  }, undefined, true, undefined, this);
69013
69189
  }
69014
69190
  async function showTokenCreatedCard(props) {
69191
+ const { token, ...card } = props;
69015
69192
  await renderStatic(/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(TokenCreatedCard, {
69016
- ...props
69193
+ ...card
69017
69194
  }, undefined, false, undefined, this));
69195
+ console.log(` export BRAINBASE_TOKEN=${token}`);
69196
+ console.log("");
69018
69197
  }
69019
69198
  function TokenListCard(props) {
69020
69199
  if (props.active.length === 0) {
@@ -69180,11 +69359,32 @@ function isAllowedScope(value) {
69180
69359
  function isExpired2(token) {
69181
69360
  return Boolean(token.expires_at && Date.parse(token.expires_at) <= Date.now());
69182
69361
  }
69362
+ function isJwtRequired(body) {
69363
+ if (!body || typeof body !== "object")
69364
+ return false;
69365
+ const detail = body.detail;
69366
+ if (!detail || typeof detail !== "object")
69367
+ return false;
69368
+ return detail.code === "jwt_required";
69369
+ }
69370
+ function sessionWouldBeUsed() {
69371
+ const { ok, session } = authStatus();
69372
+ if (ok)
69373
+ return true;
69374
+ return Boolean(session?.refresh_token && session.supabase_url && session.supabase_anon_key);
69375
+ }
69183
69376
  function withLoginHint(error) {
69184
- if (error instanceof ApiError && error.status === 403) {
69185
- return new Error("Managing tokens needs a logged-in session; a PAT (BRAINBASE_TOKEN) cannot. " + "Run `brainbase login` and try again.");
69186
- }
69187
- return error;
69377
+ if (!(error instanceof ApiError) || error.status !== 403)
69378
+ return error;
69379
+ if (!isJwtRequired(error.body))
69380
+ return error;
69381
+ if (!process.env.BRAINBASE_TOKEN?.trim()) {
69382
+ if (sessionWouldBeUsed() || !readToken())
69383
+ return error;
69384
+ return new Error("Managing tokens needs a logged-in session; the stored PAT cannot. " + "Run `brainbase login` and try again.");
69385
+ }
69386
+ const lead = "Managing tokens needs a logged-in session, and BRAINBASE_TOKEN is set — " + "that PAT is being used instead.";
69387
+ return new Error(sessionWouldBeUsed() ? `${lead} Run \`unset BRAINBASE_TOKEN\` and try again.` : `${lead} Run \`unset BRAINBASE_TOKEN\`, then \`brainbase login\`.`);
69188
69388
  }
69189
69389
  async function runTokenCreate(args) {
69190
69390
  banner("token create — make a long-lived CLI key");
@@ -69207,10 +69407,16 @@ async function runTokenCreate(args) {
69207
69407
  }
69208
69408
  const spinner = de();
69209
69409
  spinner.start("Creating token…");
69210
- const created = await registryApi.createCliToken({
69211
- name,
69212
- scopes
69213
- });
69410
+ let created;
69411
+ try {
69412
+ created = await registryApi.createCliToken({
69413
+ name,
69414
+ scopes
69415
+ });
69416
+ } catch (error) {
69417
+ spinner.stop("Could not create token.");
69418
+ throw withLoginHint(error);
69419
+ }
69214
69420
  spinner.stop("Token created.");
69215
69421
  try {
69216
69422
  writeToken(created.token, name);
@@ -69231,7 +69437,12 @@ async function runTokenCreate(args) {
69231
69437
  }
69232
69438
  async function runTokenList() {
69233
69439
  banner("tokens");
69234
- const tokens = await registryApi.listCliTokens();
69440
+ let tokens;
69441
+ try {
69442
+ tokens = await registryApi.listCliTokens();
69443
+ } catch (error) {
69444
+ throw withLoginHint(error);
69445
+ }
69235
69446
  const active = tokens.filter((t) => !t.revoked_at);
69236
69447
  const revoked = tokens.filter((t) => t.revoked_at);
69237
69448
  const local = readToken();
@@ -69354,7 +69565,7 @@ async function runTokenRevoke(args) {
69354
69565
  }
69355
69566
  throw new Error(`The server reported no active token with id ${args.id}, but it listed one a moment ago. ` + "The local token has been left alone, since that key may still work. " + "If this server predates `DELETE /v1/registry/cli-tokens/{id}`, revoke from the web app instead.");
69356
69567
  }
69357
- throw error;
69568
+ throw withLoginHint(error);
69358
69569
  }
69359
69570
  reconcileDeadToken(target, `Revoked ${import_picocolors48.default.bold(target.name)}.`);
69360
69571
  }
@@ -78261,7 +78472,9 @@ import crypto6 from "node:crypto";
78261
78472
  import fs81 from "node:fs";
78262
78473
  import os16 from "node:os";
78263
78474
  import path88 from "node:path";
78475
+ import { Readable, Transform as Transform2 } from "node:stream";
78264
78476
  import { pipeline as pipeline2 } from "node:stream/promises";
78477
+ import { createGunzip, createInflateRaw } from "node:zlib";
78265
78478
  var SCHEMA_VERSION = "1";
78266
78479
  var SHA256_RE = /^[a-f0-9]{64}$/i;
78267
78480
  var ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
@@ -78269,6 +78482,9 @@ var ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
78269
78482
  var MAX_SPEC_BYTES = 20 * 1024 * 1024;
78270
78483
  var MAX_FINAL_OUTPUT_BYTES = 10 * 1024 * 1024;
78271
78484
  var MAX_TRAJECTORY_BYTES = 100 * 1024 * 1024;
78485
+ var MAX_REMOTE_INPUT_BYTES = 2 * 1024 * 1024 * 1024;
78486
+ var MAX_ARCHIVE_EXTRACTED_BYTES = 2 * 1024 * 1024 * 1024;
78487
+ var MAX_ARCHIVE_SCAN_BYTES = 2 * 1024 * 1024 * 1024;
78272
78488
  var RESERVED_WORKSPACE_PATHS = new Set([
78273
78489
  ".brainbase",
78274
78490
  ".git",
@@ -78296,21 +78512,51 @@ var NonSecretEnvironmentValueSchema = exports_external.object({
78296
78512
  sensitive: exports_external.literal(false)
78297
78513
  }).strict();
78298
78514
  var RootRelativePathSchema = exports_external.string().min(1).max(1024);
78515
+ var ArchivePathSchema = RootRelativePathSchema.refine((value) => {
78516
+ try {
78517
+ return safeRelPath(value) === value;
78518
+ } catch {
78519
+ return false;
78520
+ }
78521
+ }, {
78522
+ message: "must be a normalized safe relative path"
78523
+ });
78299
78524
  var BudgetSchema = exports_external.object({
78300
78525
  timeout_ms: exports_external.number().int().min(100).max(3600000),
78301
78526
  max_output_bytes: exports_external.number().int().min(1024).max(100 * 1024 * 1024)
78302
78527
  }).strict();
78303
- var MaterialSchema = exports_external.object({
78528
+ var MaterialBaseSchema = {
78304
78529
  id: IdSchema,
78305
- kind: exports_external.enum(["file", "tar_gz"]),
78306
78530
  source: RootRelativePathSchema,
78531
+ download_url_env: EnvNameSchema.optional(),
78307
78532
  destination: RootRelativePathSchema,
78308
78533
  sha256: Sha256Schema,
78309
78534
  size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024),
78310
- mode: exports_external.number().int().min(0).max(511).optional(),
78535
+ mode: exports_external.number().int().min(0).max(511).optional()
78536
+ };
78537
+ var ExpandableMaterialSchema = {
78311
78538
  max_unpacked_bytes: exports_external.number().int().min(1).max(2 * 1024 * 1024 * 1024).optional(),
78312
78539
  max_file_count: exports_external.number().int().min(1).max(1e5).optional()
78313
- }).strict();
78540
+ };
78541
+ var MaterialSchema = exports_external.discriminatedUnion("kind", [
78542
+ exports_external.object({
78543
+ ...MaterialBaseSchema,
78544
+ ...ExpandableMaterialSchema,
78545
+ kind: exports_external.literal("file")
78546
+ }).strict(),
78547
+ exports_external.object({
78548
+ ...MaterialBaseSchema,
78549
+ ...ExpandableMaterialSchema,
78550
+ kind: exports_external.literal("tar_gz")
78551
+ }).strict(),
78552
+ exports_external.object({
78553
+ ...MaterialBaseSchema,
78554
+ kind: exports_external.literal("archive_file"),
78555
+ archive_path: ArchivePathSchema,
78556
+ file_sha256: Sha256Schema,
78557
+ file_size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
78558
+ }).strict()
78559
+ ]);
78314
78560
  var CommandSchema = exports_external.object({
78315
78561
  id: IdSchema,
78316
78562
  argv: exports_external.array(exports_external.string().min(1)).min(1).max(128),
@@ -78377,6 +78623,7 @@ var EvaluatorSchema = exports_external.discriminatedUnion("type", [
78377
78623
  ]);
78378
78624
  var EvidenceFileSchema = exports_external.object({
78379
78625
  source: RootRelativePathSchema,
78626
+ download_url_env: EnvNameSchema.optional(),
78380
78627
  sha256: Sha256Schema,
78381
78628
  size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
78382
78629
  }).strict();
@@ -78421,6 +78668,35 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78421
78668
  }
78422
78669
  }
78423
78670
  const declaredSecrets = new Set(value.secret_env);
78671
+ const remoteInputs = value.phase === "hydrate" ? value.materials : [
78672
+ value.evidence.final_output,
78673
+ value.evidence.trajectory,
78674
+ ...value.references
78675
+ ];
78676
+ const remoteUrlEnvNames = new Set(remoteInputs.flatMap((input) => input.download_url_env ? [input.download_url_env] : []));
78677
+ const uniqueRemoteInputs = new Map;
78678
+ for (const input of remoteInputs) {
78679
+ if (!input.download_url_env)
78680
+ continue;
78681
+ uniqueRemoteInputs.set([input.source, input.sha256, input.size_bytes].join("\x00"), input.size_bytes);
78682
+ }
78683
+ const remoteInputBytes = [...uniqueRemoteInputs.values()].reduce((total, size2) => total + size2, 0);
78684
+ if (remoteInputBytes > MAX_REMOTE_INPUT_BYTES) {
78685
+ context.addIssue({
78686
+ code: exports_external.ZodIssueCode.custom,
78687
+ path: [value.phase === "hydrate" ? "materials" : "references"],
78688
+ message: "remote inputs exceed the aggregate download byte limit"
78689
+ });
78690
+ }
78691
+ for (const name of remoteUrlEnvNames) {
78692
+ if (Object.hasOwn(value.environment, name)) {
78693
+ context.addIssue({
78694
+ code: exports_external.ZodIssueCode.custom,
78695
+ path: ["environment", name],
78696
+ message: "signed download URLs must be supplied through the process environment"
78697
+ });
78698
+ }
78699
+ }
78424
78700
  const commands = value.phase === "hydrate" ? value.setup_commands.map((command, index) => ({
78425
78701
  command,
78426
78702
  path: ["setup_commands", index, "secret_env"]
@@ -78430,6 +78706,13 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78430
78706
  }] : []);
78431
78707
  for (const { command, path: issuePath } of commands) {
78432
78708
  for (const name of command.secret_env) {
78709
+ if (remoteUrlEnvNames.has(name)) {
78710
+ context.addIssue({
78711
+ code: exports_external.ZodIssueCode.custom,
78712
+ path: issuePath,
78713
+ message: `signed download URL environment variables cannot be exposed to commands: ${name}`
78714
+ });
78715
+ }
78433
78716
  if (!declaredSecrets.has(name)) {
78434
78717
  context.addIssue({
78435
78718
  code: exports_external.ZodIssueCode.custom,
@@ -78456,6 +78739,15 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78456
78739
  });
78457
78740
  }
78458
78741
  }
78742
+ const materials = value.phase === "hydrate" ? value.materials : value.references;
78743
+ const archiveOutputBytes = materials.reduce((total, material) => total + (material.kind === "archive_file" ? material.file_size_bytes : 0), 0);
78744
+ if (archiveOutputBytes > MAX_ARCHIVE_EXTRACTED_BYTES) {
78745
+ context.addIssue({
78746
+ code: exports_external.ZodIssueCode.custom,
78747
+ path: [value.phase === "hydrate" ? "materials" : "references"],
78748
+ message: "archive-file materials exceed the aggregate extracted byte limit"
78749
+ });
78750
+ }
78459
78751
  if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length > 1) {
78460
78752
  context.addIssue({
78461
78753
  code: exports_external.ZodIssueCode.custom,
@@ -78469,6 +78761,10 @@ var BENCHMARK_CAPABILITIES = {
78469
78761
  cli_version: VERSION,
78470
78762
  schema_versions: [SCHEMA_VERSION],
78471
78763
  phases: ["hydrate", "evaluate"],
78764
+ features: [
78765
+ "remote_input_references_v1",
78766
+ "archive_file_materials_v1"
78767
+ ],
78472
78768
  evaluator_types: [
78473
78769
  "output_assertion",
78474
78770
  "trajectory_assertion",
@@ -78492,6 +78788,11 @@ class BenchmarkPhaseError extends Error {
78492
78788
  this.name = "BenchmarkPhaseError";
78493
78789
  }
78494
78790
  }
78791
+ var ZIP_EOCD_SIGNATURE = 101010256;
78792
+ var ZIP_CENTRAL_SIGNATURE = 33639248;
78793
+ var ZIP_LOCAL_SIGNATURE = 67324752;
78794
+ var MAX_ZIP_EOCD_BYTES = 65535 + 22;
78795
+ var MAX_ARCHIVE_MEMBERS = 1e5;
78495
78796
  function nowIso() {
78496
78797
  return new Date().toISOString();
78497
78798
  }
@@ -78754,10 +79055,516 @@ async function verifyInput(stagingRoot, material) {
78754
79055
  if (actual !== material.sha256) {
78755
79056
  throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
78756
79057
  }
79058
+ return {
79059
+ source,
79060
+ sha256: actual,
79061
+ size: opened.stat.size,
79062
+ mode: opened.stat.mode & 511
79063
+ };
78757
79064
  } finally {
78758
79065
  fs81.closeSync(opened.fd);
78759
79066
  }
78760
- return source;
79067
+ }
79068
+ function inputCacheKey(input) {
79069
+ return [
79070
+ input.source,
79071
+ input.sha256,
79072
+ input.size_bytes
79073
+ ].join(":");
79074
+ }
79075
+ async function cachedVerifiedInput(stagingRoot, input, context) {
79076
+ const cacheKey = inputCacheKey(input);
79077
+ const cached2 = context.verifiedInputs.get(cacheKey);
79078
+ if (cached2)
79079
+ return cached2;
79080
+ const verified = await verifyInput(stagingRoot, input);
79081
+ context.verifiedInputs.set(cacheKey, verified);
79082
+ return verified;
79083
+ }
79084
+ function stagedInputRecord(stagingRoot, verified) {
79085
+ return {
79086
+ root: "staging",
79087
+ path: path88.relative(stagingRoot, verified.source).replace(/\\/g, "/"),
79088
+ sha256: verified.sha256,
79089
+ size: verified.size,
79090
+ mode: verified.mode,
79091
+ kind: "file"
79092
+ };
79093
+ }
79094
+ function remoteUrlEnvironmentNames(spec) {
79095
+ const inputs = spec.phase === "hydrate" ? spec.materials : [
79096
+ spec.evidence.final_output,
79097
+ spec.evidence.trajectory,
79098
+ ...spec.references
79099
+ ];
79100
+ return new Set(inputs.flatMap((input) => input.download_url_env ? [input.download_url_env] : []));
79101
+ }
79102
+ function removeRemoteHydrationInputs(spec) {
79103
+ const removedSources = new Set;
79104
+ for (const material of spec.materials) {
79105
+ if (!material.download_url_env || removedSources.has(material.source))
79106
+ continue;
79107
+ const relative = safeRelPath(material.source);
79108
+ const source = path88.resolve(spec.staging_root, relative);
79109
+ if (!isWithin(spec.staging_root, source)) {
79110
+ throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${material.source}`);
79111
+ }
79112
+ assertNoSymlinkTraversal(spec.staging_root, relative);
79113
+ try {
79114
+ fs81.rmSync(source, { force: true });
79115
+ } catch {
79116
+ throw new BenchmarkPhaseError("staging_cleanup_failed", `downloaded benchmark input could not be removed: ${material.source}`);
79117
+ }
79118
+ removedSources.add(material.source);
79119
+ }
79120
+ }
79121
+ async function downloadInputReference(stagingRoot, input, context) {
79122
+ const cacheKey = inputCacheKey(input);
79123
+ const cached2 = context.verifiedInputs.get(cacheKey);
79124
+ if (cached2)
79125
+ return cached2;
79126
+ const envName = input.download_url_env;
79127
+ if (!envName) {
79128
+ return await cachedVerifiedInput(stagingRoot, input, context);
79129
+ }
79130
+ const relative = safeRelPath(input.source);
79131
+ const destination = path88.resolve(stagingRoot, relative);
79132
+ if (!isWithin(stagingRoot, destination)) {
79133
+ throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${input.source}`);
79134
+ }
79135
+ assertNoSymlinkTraversal(stagingRoot, relative);
79136
+ try {
79137
+ fs81.lstatSync(destination);
79138
+ return await cachedVerifiedInput(stagingRoot, input, context);
79139
+ } catch (error2) {
79140
+ if (error2.code !== "ENOENT")
79141
+ throw error2;
79142
+ }
79143
+ const rawUrl = process.env[envName];
79144
+ if (!rawUrl) {
79145
+ throw new BenchmarkPhaseError("missing_environment", `required signed download URL environment variable is missing: ${envName}`);
79146
+ }
79147
+ let url2;
79148
+ try {
79149
+ url2 = new URL(rawUrl);
79150
+ } catch {
79151
+ throw new BenchmarkPhaseError("invalid_download_url", `signed download URL environment variable is invalid: ${envName}`);
79152
+ }
79153
+ if (url2.protocol !== "https:" || url2.username || url2.password) {
79154
+ throw new BenchmarkPhaseError("invalid_download_url", `signed download URL environment variable must contain an HTTPS URL without credentials: ${envName}`);
79155
+ }
79156
+ const remainingMs = context.deadline - Date.now();
79157
+ if (remainingMs <= 0) {
79158
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79159
+ }
79160
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
79161
+ assertNoSymlinkTraversal(stagingRoot, relative);
79162
+ assertWritableDestination(stagingRoot, relative);
79163
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.download`;
79164
+ const controller = new AbortController;
79165
+ const timer = setTimeout(() => controller.abort(), remainingMs);
79166
+ let descriptor;
79167
+ try {
79168
+ let response;
79169
+ try {
79170
+ response = await fetch(url2, {
79171
+ redirect: "error",
79172
+ signal: controller.signal
79173
+ });
79174
+ } catch {
79175
+ if (controller.signal.aborted || Date.now() >= context.deadline) {
79176
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79177
+ }
79178
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`);
79179
+ }
79180
+ if (response.redirected || response.status >= 300 && response.status < 400) {
79181
+ throw new BenchmarkPhaseError("download_redirect_rejected", `signed input download redirected for ${input.source}`);
79182
+ }
79183
+ if (!response.ok || !response.body) {
79184
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`, { status: response.status });
79185
+ }
79186
+ const declaredLength = response.headers.get("content-length");
79187
+ if (declaredLength !== null && /^\d+$/.test(declaredLength) && Number(declaredLength) > input.size_bytes) {
79188
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: Number(declaredLength) });
79189
+ }
79190
+ descriptor = fs81.openSync(temporary, "wx", 384);
79191
+ const reader = response.body.getReader();
79192
+ let actual;
79193
+ let size2 = 0;
79194
+ try {
79195
+ const hash = crypto6.createHash("sha256");
79196
+ while (true) {
79197
+ const { done, value } = await reader.read();
79198
+ if (done)
79199
+ break;
79200
+ assertBudget(context);
79201
+ size2 += value.byteLength;
79202
+ if (size2 > input.size_bytes) {
79203
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: size2 });
79204
+ }
79205
+ hash.update(value);
79206
+ let offset = 0;
79207
+ while (offset < value.byteLength) {
79208
+ offset += fs81.writeSync(descriptor, value, offset, value.byteLength - offset);
79209
+ }
79210
+ }
79211
+ actual = hash.digest("hex");
79212
+ } finally {
79213
+ try {
79214
+ await reader.cancel();
79215
+ } catch {}
79216
+ }
79217
+ if (size2 !== input.size_bytes) {
79218
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: size2 });
79219
+ }
79220
+ if (actual !== input.sha256) {
79221
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${input.source}`, { expected: input.sha256, actual });
79222
+ }
79223
+ fs81.fsyncSync(descriptor);
79224
+ fs81.closeSync(descriptor);
79225
+ descriptor = undefined;
79226
+ assertNoSymlinkTraversal(stagingRoot, relative);
79227
+ if (fs81.existsSync(destination)) {
79228
+ return await cachedVerifiedInput(stagingRoot, input, context);
79229
+ }
79230
+ fs81.renameSync(temporary, destination);
79231
+ return await cachedVerifiedInput(stagingRoot, input, context);
79232
+ } catch (error2) {
79233
+ if (!(error2 instanceof BenchmarkPhaseError) && (controller.signal.aborted || Date.now() >= context.deadline)) {
79234
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79235
+ }
79236
+ if (error2 instanceof BenchmarkPhaseError)
79237
+ throw error2;
79238
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`);
79239
+ } finally {
79240
+ clearTimeout(timer);
79241
+ controller.abort();
79242
+ if (descriptor !== undefined)
79243
+ fs81.closeSync(descriptor);
79244
+ fs81.rmSync(temporary, { force: true });
79245
+ }
79246
+ }
79247
+ function readExactly(descriptor, length, position) {
79248
+ const buffer = Buffer.alloc(length);
79249
+ let offset = 0;
79250
+ while (offset < length) {
79251
+ const count = fs81.readSync(descriptor, buffer, offset, length - offset, position + offset);
79252
+ if (count === 0) {
79253
+ throw new BenchmarkPhaseError("invalid_archive", "archive ended unexpectedly");
79254
+ }
79255
+ offset += count;
79256
+ }
79257
+ return buffer;
79258
+ }
79259
+ function decodeZipPath(value, utf8) {
79260
+ if (!utf8 && value.some((byte) => byte >= 128)) {
79261
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP members with non-UTF-8 names are unsupported");
79262
+ }
79263
+ try {
79264
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
79265
+ } catch {
79266
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member name is not valid UTF-8");
79267
+ }
79268
+ }
79269
+ function findZipMembers(archivePath, requested, context) {
79270
+ const descriptor = fs81.openSync(archivePath, "r");
79271
+ try {
79272
+ assertBudget(context);
79273
+ const archiveSize = fs81.fstatSync(descriptor).size;
79274
+ const tailSize = Math.min(archiveSize, MAX_ZIP_EOCD_BYTES);
79275
+ const tailOffset = archiveSize - tailSize;
79276
+ const tail2 = readExactly(descriptor, tailSize, tailOffset);
79277
+ let eocdOffset = -1;
79278
+ for (let offset2 = tail2.length - 22;offset2 >= 0; offset2 -= 1) {
79279
+ assertBudget(context);
79280
+ if (tail2.readUInt32LE(offset2) === ZIP_EOCD_SIGNATURE) {
79281
+ const commentLength = tail2.readUInt16LE(offset2 + 20);
79282
+ if (offset2 + 22 + commentLength === tail2.length) {
79283
+ eocdOffset = offset2;
79284
+ break;
79285
+ }
79286
+ }
79287
+ }
79288
+ if (eocdOffset < 0) {
79289
+ throw new BenchmarkPhaseError("invalid_archive", "invalid ZIP archive");
79290
+ }
79291
+ const diskNumber = tail2.readUInt16LE(eocdOffset + 4);
79292
+ const directoryDisk = tail2.readUInt16LE(eocdOffset + 6);
79293
+ const diskEntries = tail2.readUInt16LE(eocdOffset + 8);
79294
+ const totalEntries = tail2.readUInt16LE(eocdOffset + 10);
79295
+ const directorySize = tail2.readUInt32LE(eocdOffset + 12);
79296
+ const directoryOffset = tail2.readUInt32LE(eocdOffset + 16);
79297
+ if (diskNumber !== 0 || directoryDisk !== 0 || diskEntries !== totalEntries) {
79298
+ throw new BenchmarkPhaseError("invalid_archive", "multi-disk ZIP archives are unsupported");
79299
+ }
79300
+ if (totalEntries === 65535 || directorySize === 4294967295 || directoryOffset === 4294967295) {
79301
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP64 archives are unsupported");
79302
+ }
79303
+ if (totalEntries > MAX_ARCHIVE_MEMBERS || directoryOffset + directorySize > tailOffset + eocdOffset) {
79304
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79305
+ }
79306
+ let offset = directoryOffset;
79307
+ const found = new Map;
79308
+ for (let index = 0;index < totalEntries; index += 1) {
79309
+ assertBudget(context);
79310
+ const header = readExactly(descriptor, 46, offset);
79311
+ if (header.readUInt32LE(0) !== ZIP_CENTRAL_SIGNATURE) {
79312
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79313
+ }
79314
+ const flags = header.readUInt16LE(8);
79315
+ const compressionMethod = header.readUInt16LE(10);
79316
+ const compressedSize = header.readUInt32LE(20);
79317
+ const uncompressedSize = header.readUInt32LE(24);
79318
+ const nameLength = header.readUInt16LE(28);
79319
+ const extraLength = header.readUInt16LE(30);
79320
+ const commentLength = header.readUInt16LE(32);
79321
+ const diskStart = header.readUInt16LE(34);
79322
+ const externalAttributes = header.readUInt32LE(38);
79323
+ const localHeaderOffset = header.readUInt32LE(42);
79324
+ const recordSize = 46 + nameLength + extraLength + commentLength;
79325
+ if (offset + recordSize > directoryOffset + directorySize || compressedSize === 4294967295 || uncompressedSize === 4294967295 || localHeaderOffset === 4294967295 || diskStart !== 0) {
79326
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member metadata is invalid");
79327
+ }
79328
+ const name = decodeZipPath(readExactly(descriptor, nameLength, offset + 46), (flags & 2048) !== 0);
79329
+ const material = requested.get(name);
79330
+ if (material) {
79331
+ if (found.has(name)) {
79332
+ throw new BenchmarkPhaseError("invalid_archive", `archive member is duplicated: ${name}`);
79333
+ }
79334
+ const madeBy = header.readUInt16LE(4) >> 8;
79335
+ const unixMode = externalAttributes >>> 16;
79336
+ const fileType = unixMode & 61440;
79337
+ if (name.endsWith("/") || (externalAttributes & 16) !== 0 || madeBy === 3 && fileType !== 0 && fileType !== 32768) {
79338
+ throw new BenchmarkPhaseError("invalid_archive", `archive member must be a regular file: ${name}`);
79339
+ }
79340
+ if ((flags & 1) !== 0 || compressionMethod !== 0 && compressionMethod !== 8) {
79341
+ throw new BenchmarkPhaseError("invalid_archive", `archive member uses unsupported ZIP features: ${name}`);
79342
+ }
79343
+ if (uncompressedSize !== material.file_size_bytes) {
79344
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${name}`, { expected: material.file_size_bytes, actual: uncompressedSize });
79345
+ }
79346
+ const localHeader = readExactly(descriptor, 30, localHeaderOffset);
79347
+ if (localHeader.readUInt32LE(0) !== ZIP_LOCAL_SIGNATURE || localHeader.readUInt16LE(6) !== flags || localHeader.readUInt16LE(8) !== compressionMethod) {
79348
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP local header is invalid");
79349
+ }
79350
+ const localNameLength = localHeader.readUInt16LE(26);
79351
+ const localExtraLength = localHeader.readUInt16LE(28);
79352
+ const localName = decodeZipPath(readExactly(descriptor, localNameLength, localHeaderOffset + 30), (flags & 2048) !== 0);
79353
+ const dataOffset = localHeaderOffset + 30 + localNameLength + localExtraLength;
79354
+ if (localName !== name || dataOffset + compressedSize > directoryOffset) {
79355
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member bounds are invalid");
79356
+ }
79357
+ found.set(name, {
79358
+ compressionMethod,
79359
+ compressedSize,
79360
+ dataOffset
79361
+ });
79362
+ }
79363
+ offset += recordSize;
79364
+ }
79365
+ if (offset !== directoryOffset + directorySize) {
79366
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79367
+ }
79368
+ for (const memberPath of requested.keys()) {
79369
+ if (!found.has(memberPath)) {
79370
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${memberPath}`);
79371
+ }
79372
+ }
79373
+ return found;
79374
+ } finally {
79375
+ fs81.closeSync(descriptor);
79376
+ }
79377
+ }
79378
+ async function writeVerifiedArchiveMember(source, destination, material, context) {
79379
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
79380
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
79381
+ const descriptor = fs81.openSync(temporary, "wx", 384);
79382
+ const hash = crypto6.createHash("sha256");
79383
+ let size2 = 0;
79384
+ try {
79385
+ for await (const value of source) {
79386
+ assertBudget(context);
79387
+ const chunk2 = Buffer.isBuffer(value) ? value : Buffer.from(value);
79388
+ size2 += chunk2.length;
79389
+ if (size2 > material.file_size_bytes) {
79390
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${material.archive_path}`, { expected: material.file_size_bytes, actual: size2 });
79391
+ }
79392
+ hash.update(chunk2);
79393
+ let offset = 0;
79394
+ while (offset < chunk2.length) {
79395
+ offset += fs81.writeSync(descriptor, chunk2, offset, chunk2.length - offset);
79396
+ }
79397
+ }
79398
+ if (size2 !== material.file_size_bytes) {
79399
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${material.archive_path}`, { expected: material.file_size_bytes, actual: size2 });
79400
+ }
79401
+ const actual = hash.digest("hex");
79402
+ if (actual !== material.file_sha256) {
79403
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for archive member ${material.archive_path}`, { expected: material.file_sha256, actual });
79404
+ }
79405
+ fs81.fsyncSync(descriptor);
79406
+ fs81.closeSync(descriptor);
79407
+ fs81.renameSync(temporary, destination);
79408
+ } catch (error2) {
79409
+ if (error2 instanceof BenchmarkPhaseError)
79410
+ throw error2;
79411
+ throw new BenchmarkPhaseError("invalid_archive", `archive member could not be extracted: ${material.archive_path}`);
79412
+ } finally {
79413
+ try {
79414
+ fs81.closeSync(descriptor);
79415
+ } catch {}
79416
+ fs81.rmSync(temporary, { force: true });
79417
+ }
79418
+ }
79419
+ function isZipArchive(archivePath) {
79420
+ const descriptor = fs81.openSync(archivePath, "r");
79421
+ try {
79422
+ const header = Buffer.alloc(4);
79423
+ return fs81.readSync(descriptor, header, 0, header.length, 0) === header.length && [
79424
+ ZIP_LOCAL_SIGNATURE,
79425
+ ZIP_EOCD_SIGNATURE,
79426
+ 134695760
79427
+ ].includes(header.readUInt32LE(0));
79428
+ } finally {
79429
+ fs81.closeSync(descriptor);
79430
+ }
79431
+ }
79432
+ function isGzipArchive(archivePath) {
79433
+ const descriptor = fs81.openSync(archivePath, "r");
79434
+ try {
79435
+ const header = Buffer.alloc(2);
79436
+ return fs81.readSync(descriptor, header, 0, header.length, 0) === header.length && header[0] === 31 && header[1] === 139;
79437
+ } finally {
79438
+ fs81.closeSync(descriptor);
79439
+ }
79440
+ }
79441
+ function archiveSourceCacheKey(material) {
79442
+ return [
79443
+ material.source,
79444
+ material.sha256,
79445
+ material.size_bytes,
79446
+ material.download_url_env ?? ""
79447
+ ].join("\x00");
79448
+ }
79449
+ function archiveMemberCacheKey(material) {
79450
+ return [
79451
+ archiveSourceCacheKey(material),
79452
+ material.archive_path,
79453
+ material.file_sha256,
79454
+ material.file_size_bytes
79455
+ ].join("\x00");
79456
+ }
79457
+ function archiveScanBudget(context) {
79458
+ let scanned = 0;
79459
+ return new Transform2({
79460
+ transform(chunk2, _encoding, callback) {
79461
+ try {
79462
+ assertBudget(context);
79463
+ scanned += chunk2.length;
79464
+ if (scanned > MAX_ARCHIVE_SCAN_BYTES) {
79465
+ throw new BenchmarkPhaseError("invalid_archive", "archive expands beyond the supported scan limit");
79466
+ }
79467
+ callback(null, chunk2);
79468
+ } catch (error2) {
79469
+ callback(error2);
79470
+ }
79471
+ }
79472
+ });
79473
+ }
79474
+ async function extractArchiveMembers(archivePath, outputRoot, materials, context) {
79475
+ const requested = new Map;
79476
+ for (const material of materials) {
79477
+ let memberPath;
79478
+ try {
79479
+ memberPath = safeRelPath(material.archive_path);
79480
+ } catch {
79481
+ throw new BenchmarkPhaseError("unsafe_path", "archive member path is unsafe");
79482
+ }
79483
+ const existing = requested.get(memberPath);
79484
+ if (existing && (existing.file_sha256 !== material.file_sha256 || existing.file_size_bytes !== material.file_size_bytes)) {
79485
+ throw new BenchmarkPhaseError("invalid_archive", `archive member has conflicting declarations: ${memberPath}`);
79486
+ }
79487
+ requested.set(memberPath, material);
79488
+ }
79489
+ const extracted = new Map;
79490
+ if (isZipArchive(archivePath)) {
79491
+ const indexed = findZipMembers(archivePath, requested, context);
79492
+ for (const [memberPath, material] of requested) {
79493
+ assertBudget(context);
79494
+ const destination = path88.resolve(outputRoot, memberPath);
79495
+ if (!isWithin(outputRoot, destination)) {
79496
+ throw new BenchmarkPhaseError("unsafe_path", `archive member escapes output root: ${memberPath}`);
79497
+ }
79498
+ const member = indexed.get(memberPath);
79499
+ const compressed = member.compressedSize === 0 ? Readable.from([]) : fs81.createReadStream(archivePath, {
79500
+ start: member.dataOffset,
79501
+ end: member.dataOffset + member.compressedSize - 1
79502
+ });
79503
+ const contents = member.compressionMethod === 8 ? compressed.pipe(createInflateRaw()) : compressed;
79504
+ await writeVerifiedArchiveMember(contents, destination, material, context);
79505
+ extracted.set(memberPath, destination);
79506
+ }
79507
+ return extracted;
79508
+ }
79509
+ const matches2 = new Map;
79510
+ let validationError;
79511
+ const unpack = co({
79512
+ cwd: outputRoot,
79513
+ strict: true,
79514
+ preserveOwner: false,
79515
+ filter: (entryPath, entryAny) => {
79516
+ assertBudget(context);
79517
+ const material = requested.get(entryPath);
79518
+ if (!material)
79519
+ return false;
79520
+ const count = (matches2.get(entryPath) ?? 0) + 1;
79521
+ matches2.set(entryPath, count);
79522
+ const entry = entryAny;
79523
+ if (count > 1) {
79524
+ validationError = new BenchmarkPhaseError("invalid_archive", `archive member is duplicated: ${entryPath}`);
79525
+ return false;
79526
+ }
79527
+ if (!["File", "OldFile", "ContiguousFile"].includes(entry.type)) {
79528
+ validationError = new BenchmarkPhaseError("invalid_archive", `archive member must be a regular file: ${entryPath}`);
79529
+ return false;
79530
+ }
79531
+ if (entry.size !== material.file_size_bytes) {
79532
+ validationError = new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${entryPath}`, { expected: material.file_size_bytes, actual: entry.size });
79533
+ return false;
79534
+ }
79535
+ return true;
79536
+ }
79537
+ });
79538
+ const archive = fs81.createReadStream(archivePath);
79539
+ const scanBudget = archiveScanBudget(context);
79540
+ try {
79541
+ if (isGzipArchive(archivePath)) {
79542
+ await pipeline2(archive, createGunzip(), scanBudget, unpack);
79543
+ } else {
79544
+ await pipeline2(archive, scanBudget, unpack);
79545
+ }
79546
+ } catch (error2) {
79547
+ if (validationError)
79548
+ throw validationError;
79549
+ if (error2 instanceof BenchmarkPhaseError)
79550
+ throw error2;
79551
+ throw new BenchmarkPhaseError("invalid_archive", "archive members could not be extracted");
79552
+ }
79553
+ if (validationError)
79554
+ throw validationError;
79555
+ for (const [memberPath, material] of requested) {
79556
+ if (!matches2.has(memberPath)) {
79557
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${memberPath}`);
79558
+ }
79559
+ const verified = await verifyInput(outputRoot, {
79560
+ source: memberPath,
79561
+ sha256: material.file_sha256,
79562
+ size_bytes: material.file_size_bytes
79563
+ });
79564
+ assertBudget(context);
79565
+ extracted.set(memberPath, verified.source);
79566
+ }
79567
+ return extracted;
78761
79568
  }
78762
79569
  async function atomicCopy(source, destination, mode, sourceRoot) {
78763
79570
  fs81.mkdirSync(path88.dirname(destination), { recursive: true });
@@ -78806,21 +79613,31 @@ async function recordFile(root, filePath, rootName, kind = "file") {
78806
79613
  fs81.closeSync(opened.fd);
78807
79614
  }
78808
79615
  }
78809
- async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
78810
- const source = await verifyInput(sourceRoot, material);
79616
+ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace, context) {
79617
+ const verifiedSource = material.kind === "archive_file" ? undefined : await cachedVerifiedInput(sourceRoot, material, context);
79618
+ const source = material.kind === "archive_file" ? context.preparedArchiveFiles.get(archiveMemberCacheKey(material)) : verifiedSource?.source;
79619
+ if (!source) {
79620
+ throw new BenchmarkPhaseError("invalid_archive", `archive member was not prepared: ${material.id}`);
79621
+ }
78811
79622
  const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
78812
79623
  if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
78813
79624
  throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
78814
79625
  }
78815
- if (material.kind === "file") {
79626
+ if (material.kind === "file" || material.kind === "archive_file") {
78816
79627
  if (destinationRel === ".") {
78817
79628
  throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
78818
79629
  }
78819
79630
  assertWritableDestination(destinationRoot, destinationRel);
78820
79631
  const destination = path88.resolve(destinationRoot, destinationRel);
78821
- await atomicCopy(source, destination, material.mode, sourceRoot);
79632
+ if (material.kind === "file") {
79633
+ await atomicCopy(source, destination, material.mode ?? verifiedSource?.mode, sourceRoot);
79634
+ } else {
79635
+ await atomicCopy(source, destination, material.mode, path88.dirname(source));
79636
+ }
78822
79637
  const record3 = await recordFile(destinationRoot, destination, destinationRootName);
78823
- if (record3.sha256 !== material.sha256 || record3.size !== material.size_bytes) {
79638
+ const expectedSha256 = material.kind === "archive_file" ? material.file_sha256 : material.sha256;
79639
+ const expectedSize = material.kind === "archive_file" ? material.file_size_bytes : material.size_bytes;
79640
+ if (record3.sha256 !== expectedSha256 || record3.size !== expectedSize) {
78824
79641
  throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
78825
79642
  }
78826
79643
  return [record3];
@@ -78861,17 +79678,39 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
78861
79678
  fs81.rmSync(temporary, { recursive: true, force: true });
78862
79679
  }
78863
79680
  }
78864
- async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
78865
- const source = await verifyInput(sourceRoot, material);
79681
+ async function preflightMaterial(material, materials, sourceRoot, destinationRoot, protectWorkspace, context) {
79682
+ const source = (await cachedVerifiedInput(sourceRoot, material, context)).source;
78866
79683
  const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
78867
79684
  if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
78868
79685
  throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
78869
79686
  }
78870
- if (material.kind === "file") {
79687
+ if (material.kind === "file" || material.kind === "archive_file") {
78871
79688
  if (destinationRel === ".") {
78872
79689
  throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
78873
79690
  }
78874
79691
  assertWritableDestination(destinationRoot, destinationRel);
79692
+ if (material.kind === "archive_file") {
79693
+ const cacheKey = archiveMemberCacheKey(material);
79694
+ let extracted = context.preparedArchiveFiles.get(cacheKey);
79695
+ if (!extracted) {
79696
+ const temporary2 = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-member-"));
79697
+ context.temporaryRoots.add(temporary2);
79698
+ const archiveKey = archiveSourceCacheKey(material);
79699
+ const related = materials.filter((candidate) => candidate.kind === "archive_file" && archiveSourceCacheKey(candidate) === archiveKey);
79700
+ const extractedMembers = await extractArchiveMembers(source, temporary2, related, context);
79701
+ for (const candidate of related) {
79702
+ const prepared = extractedMembers.get(safeRelPath(candidate.archive_path));
79703
+ if (!prepared) {
79704
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${candidate.archive_path}`);
79705
+ }
79706
+ context.preparedArchiveFiles.set(archiveMemberCacheKey(candidate), prepared);
79707
+ }
79708
+ extracted = context.preparedArchiveFiles.get(cacheKey);
79709
+ }
79710
+ if (!extracted) {
79711
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${material.archive_path}`);
79712
+ }
79713
+ }
78875
79714
  return [destinationRel];
78876
79715
  }
78877
79716
  const temporary = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
@@ -78939,14 +79778,18 @@ function prepareOwnedDirectory(root, role, spec) {
78939
79778
  }
78940
79779
  function buildEnvironment(spec, secretNames, additions = {}) {
78941
79780
  const env3 = {};
79781
+ const remoteUrlEnvNames = remoteUrlEnvironmentNames(spec);
78942
79782
  for (const name of BASE_ENV_NAMES) {
78943
- if (process.env[name] !== undefined)
79783
+ if (!remoteUrlEnvNames.has(name) && process.env[name] !== undefined) {
78944
79784
  env3[name] = process.env[name];
79785
+ }
78945
79786
  }
78946
79787
  for (const [name, declared] of Object.entries(spec.environment)) {
78947
79788
  env3[name] = declared.value;
78948
79789
  }
78949
79790
  for (const name of secretNames) {
79791
+ if (remoteUrlEnvNames.has(name))
79792
+ continue;
78950
79793
  const value = process.env[name];
78951
79794
  if (value === undefined) {
78952
79795
  throw new BenchmarkPhaseError("missing_environment", `required environment variable is missing: ${name}`);
@@ -78958,7 +79801,11 @@ function buildEnvironment(spec, secretNames, additions = {}) {
78958
79801
  }
78959
79802
  function redactCommandOutput(data, spec) {
78960
79803
  let value = data.toString("utf8");
78961
- for (const name of spec.secret_env) {
79804
+ const sensitiveNames = new Set([
79805
+ ...spec.secret_env,
79806
+ ...remoteUrlEnvironmentNames(spec)
79807
+ ]);
79808
+ for (const name of sensitiveNames) {
78962
79809
  const secret = process.env[name];
78963
79810
  if (secret)
78964
79811
  value = value.split(secret).join("[REDACTED]");
@@ -79128,16 +79975,19 @@ async function executeHydrate(spec, context) {
79128
79975
  const plannedDestinations = [];
79129
79976
  for (const material of spec.materials) {
79130
79977
  assertBudget(context);
79131
- plannedDestinations.push(...await preflightMaterial(material, spec.staging_root, spec.workspace_root, true));
79132
- const source = await verifyInput(spec.staging_root, material);
79133
- context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
79978
+ const verified = await downloadInputReference(spec.staging_root, material, context);
79979
+ plannedDestinations.push(...await preflightMaterial(material, spec.materials, spec.staging_root, spec.workspace_root, true, context));
79980
+ const record3 = stagedInputRecord(spec.staging_root, verified);
79981
+ if (!context.inputs.some((input) => input.path === record3.path && input.sha256 === record3.sha256 && input.size === record3.size)) {
79982
+ context.inputs.push(record3);
79983
+ }
79134
79984
  }
79135
79985
  validateDestinationGraph(plannedDestinations);
79136
79986
  for (const material of spec.materials) {
79137
79987
  assertBudget(context);
79138
79988
  const started = Date.now();
79139
79989
  try {
79140
- const records = await copyMaterial(material, spec.staging_root, spec.workspace_root, "workspace", true);
79990
+ const records = await copyMaterial(material, spec.staging_root, spec.workspace_root, "workspace", true, context);
79141
79991
  outputs.push(...records);
79142
79992
  context.outputs.push(...records);
79143
79993
  context.steps.push({
@@ -79211,6 +80061,7 @@ async function executeHydrate(spec, context) {
79211
80061
  }
79212
80062
  outputs.splice(0, outputs.length, ...finalOutputs);
79213
80063
  context.outputs.splice(0, context.outputs.length, ...finalOutputs);
80064
+ removeRemoteHydrationInputs(spec);
79214
80065
  assertBudget(context);
79215
80066
  return outputs;
79216
80067
  }
@@ -79416,6 +80267,8 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
79416
80267
  };
79417
80268
  }
79418
80269
  async function executeEvaluate(spec, context) {
80270
+ await downloadInputReference(spec.staging_root, spec.evidence.final_output, context);
80271
+ await downloadInputReference(spec.staging_root, spec.evidence.trajectory, context);
79419
80272
  const finalOutput = await readEvidence(spec.staging_root, spec.evidence.final_output);
79420
80273
  const trajectoryEvidence = await readEvidence(spec.staging_root, spec.evidence.trajectory);
79421
80274
  context.inputs.push(finalOutput.record, trajectoryEvidence.record);
@@ -79429,9 +80282,12 @@ async function executeEvaluate(spec, context) {
79429
80282
  const plannedReferences = [];
79430
80283
  for (const reference of spec.references) {
79431
80284
  assertBudget(context);
79432
- plannedReferences.push(...await preflightMaterial(reference, spec.staging_root, spec.tests_root, false));
79433
- const source = await verifyInput(spec.staging_root, reference);
79434
- context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
80285
+ const verified = await downloadInputReference(spec.staging_root, reference, context);
80286
+ plannedReferences.push(...await preflightMaterial(reference, spec.references, spec.staging_root, spec.tests_root, false, context));
80287
+ const record3 = stagedInputRecord(spec.staging_root, verified);
80288
+ if (!context.inputs.some((input) => input.path === record3.path && input.sha256 === record3.sha256 && input.size === record3.size)) {
80289
+ context.inputs.push(record3);
80290
+ }
79435
80291
  }
79436
80292
  validateDestinationGraph(plannedReferences);
79437
80293
  assertBudget(context);
@@ -79496,7 +80352,7 @@ async function executeEvaluate(spec, context) {
79496
80352
  }
79497
80353
  await verifyRecordsUnchanged(manifest, spec);
79498
80354
  for (const reference of spec.references) {
79499
- const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false);
80355
+ const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false, context);
79500
80356
  outputs.push(...referenceOutputs);
79501
80357
  context.outputs.push(...referenceOutputs);
79502
80358
  }
@@ -79646,19 +80502,26 @@ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expecte
79646
80502
  spec_digest: digest,
79647
80503
  timeout_ms: spec.budget.timeout_ms
79648
80504
  };
80505
+ let cachedResult;
79649
80506
  if (fs81.existsSync(resultPath)) {
79650
80507
  try {
79651
80508
  const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79652
80509
  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") {
79653
- return {
79654
- ok: true,
79655
- invocation,
79656
- spec_bytes: bytes,
79657
- cached_result: cached2
79658
- };
80510
+ cachedResult = cached2;
79659
80511
  }
79660
80512
  } catch {}
79661
80513
  }
80514
+ if (cachedResult) {
80515
+ if (spec.phase === "hydrate") {
80516
+ removeRemoteHydrationInputs(spec);
80517
+ }
80518
+ return {
80519
+ ok: true,
80520
+ invocation,
80521
+ spec_bytes: bytes,
80522
+ cached_result: cachedResult
80523
+ };
80524
+ }
79662
80525
  return { ok: true, invocation, spec_bytes: bytes };
79663
80526
  } catch (error2) {
79664
80527
  return {
@@ -79755,14 +80618,21 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79755
80618
  throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
79756
80619
  }
79757
80620
  resultPathValidated = true;
80621
+ let cachedResult;
79758
80622
  if (fs81.existsSync(resultPath)) {
79759
80623
  try {
79760
80624
  const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79761
80625
  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") {
79762
- return { exitCode: 0, result: cached2 };
80626
+ cachedResult = cached2;
79763
80627
  }
79764
80628
  } catch {}
79765
80629
  }
80630
+ if (cachedResult) {
80631
+ if (spec.phase === "hydrate") {
80632
+ removeRemoteHydrationInputs(spec);
80633
+ }
80634
+ return { exitCode: 0, result: cachedResult };
80635
+ }
79766
80636
  context = {
79767
80637
  deadline: started + spec.budget.timeout_ms,
79768
80638
  remainingOutputBytes: spec.budget.max_output_bytes,
@@ -79770,7 +80640,10 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79770
80640
  evaluators: [],
79771
80641
  inputs: [],
79772
80642
  outputs: [],
79773
- logsOwned: false
80643
+ logsOwned: false,
80644
+ verifiedInputs: new Map,
80645
+ preparedArchiveFiles: new Map,
80646
+ temporaryRoots: new Set
79774
80647
  };
79775
80648
  if (spec.phase === "hydrate") {
79776
80649
  outputs = await executeHydrate(spec, context);
@@ -79790,6 +80663,11 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79790
80663
  evaluators = context.evaluators;
79791
80664
  }
79792
80665
  }
80666
+ if (context) {
80667
+ for (const temporary of context.temporaryRoots) {
80668
+ fs81.rmSync(temporary, { recursive: true, force: true });
80669
+ }
80670
+ }
79793
80671
  const result2 = {
79794
80672
  schema_version: SCHEMA_VERSION,
79795
80673
  cli_version: VERSION,
@@ -80201,7 +81079,7 @@ function help() {
80201
81079
  out.push("");
80202
81080
  out.push(` ${import_picocolors52.default.cyan("login")} ${import_picocolors52.default.dim(" open the web app and connect this device")}`);
80203
81081
  out.push(` ${import_picocolors52.default.cyan("logout")} ${import_picocolors52.default.dim(" clear the local session")}`);
80204
- out.push(` ${import_picocolors52.default.cyan("whoami")} ${import_picocolors52.default.dim(" show the current user")}`);
81082
+ out.push(` ${import_picocolors52.default.cyan("whoami")} ${import_picocolors52.default.dim("[--json]")} ${import_picocolors52.default.dim(" show which credential is in use and what it covers")}`);
80205
81083
  out.push("");
80206
81084
  out.push(divider("DISCOVERY"));
80207
81085
  out.push("");
@@ -80304,7 +81182,7 @@ function help() {
80304
81182
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_API_URL")} legacy KLS host override (uses /api/cli; proxy/registry fallback)`);
80305
81183
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_PROXY_URL")} override the model-proxy URL used by harness traffic (default https://api.v1.brainbaselabs.com)`);
80306
81184
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_REGISTRY_URL")} override the registry API URL (default https://api.v1.brainbaselabs.com)`);
80307
- out.push(` ${import_picocolors52.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT (overrides token.json)`);
81185
+ out.push(` ${import_picocolors52.default.dim("BRAINBASE_TOKEN")} long-lived CLI PAT; the only PAT control-plane commands accept (token.json is not read there)`);
80308
81186
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_SKIP_AUTH")} bypass the auth gate for development`);
80309
81187
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_NON_INTERACTIVE")} force non-interactive mode — skip/auto-default prompts (CI & agents)`);
80310
81188
  out.push(` ${import_picocolors52.default.dim("BRAINBASE_RUN_ENTRYPOINT")} =1 → agent pull executes the agent entrypoint (sandbox boots; or pass --run-entrypoint)`);
@@ -80556,7 +81434,7 @@ async function main() {
80556
81434
  break;
80557
81435
  }
80558
81436
  case "whoami": {
80559
- await runWhoami();
81437
+ await runWhoami({ json: jsonFlag });
80560
81438
  break;
80561
81439
  }
80562
81440
  case "template": {