@brainbase-labs/cli 0.25.0-eng1209.3 → 0.25.0-eng1209.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +172 -21
- 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.25.0-eng1209.
|
|
36011
|
+
version: "0.25.0-eng1209.5",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -79114,10 +79114,15 @@ async function verifyRecordsUnchanged(records, spec) {
|
|
|
79114
79114
|
const relative = safeRelPath(record3.path);
|
|
79115
79115
|
assertNoSymlinkTraversal(root, relative);
|
|
79116
79116
|
const candidate = path88.resolve(root, relative);
|
|
79117
|
-
if (!isWithin(root, candidate)
|
|
79117
|
+
if (!isWithin(root, candidate)) {
|
|
79118
|
+
throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
|
|
79119
|
+
}
|
|
79120
|
+
let stat;
|
|
79121
|
+
try {
|
|
79122
|
+
stat = fs81.lstatSync(candidate);
|
|
79123
|
+
} catch {
|
|
79118
79124
|
throw new BenchmarkPhaseError("evidence_tampered", `evidence was removed during evaluation: ${record3.root}:${record3.path}`);
|
|
79119
79125
|
}
|
|
79120
|
-
const stat = fs81.lstatSync(candidate);
|
|
79121
79126
|
if (record3.kind === "symlink") {
|
|
79122
79127
|
const target = stat.isSymbolicLink() ? fs81.readlinkSync(candidate) : null;
|
|
79123
79128
|
if (target === null || Buffer.byteLength(target) !== record3.size || sha256(target) !== record3.sha256) {
|
|
@@ -79212,6 +79217,15 @@ function removeRemoteHydrationInputs(spec) {
|
|
|
79212
79217
|
removedSources.add(material.source);
|
|
79213
79218
|
}
|
|
79214
79219
|
}
|
|
79220
|
+
function removePrivateHydrationSourcesBeforeSetup(spec, context) {
|
|
79221
|
+
removeRemoteHydrationInputs(spec);
|
|
79222
|
+
for (const temporary of context.temporaryRoots) {
|
|
79223
|
+
fs81.rmSync(temporary, { recursive: true, force: true });
|
|
79224
|
+
}
|
|
79225
|
+
context.temporaryRoots.clear();
|
|
79226
|
+
context.verifiedInputs.clear();
|
|
79227
|
+
context.preparedArchiveFiles.clear();
|
|
79228
|
+
}
|
|
79215
79229
|
async function downloadInputReference(stagingRoot, input, context) {
|
|
79216
79230
|
const cacheKey = inputCacheKey(input);
|
|
79217
79231
|
const cached2 = context.verifiedInputs.get(cacheKey);
|
|
@@ -80100,6 +80114,7 @@ async function executeHydrate(spec, context) {
|
|
|
80100
80114
|
throw error2;
|
|
80101
80115
|
}
|
|
80102
80116
|
}
|
|
80117
|
+
removePrivateHydrationSourcesBeforeSetup(spec, context);
|
|
80103
80118
|
for (const command of spec.setup_commands) {
|
|
80104
80119
|
assertBudget(context);
|
|
80105
80120
|
let result2;
|
|
@@ -80155,7 +80170,6 @@ async function executeHydrate(spec, context) {
|
|
|
80155
80170
|
}
|
|
80156
80171
|
outputs.splice(0, outputs.length, ...finalOutputs);
|
|
80157
80172
|
context.outputs.splice(0, context.outputs.length, ...finalOutputs);
|
|
80158
|
-
removeRemoteHydrationInputs(spec);
|
|
80159
80173
|
assertBudget(context);
|
|
80160
80174
|
return outputs;
|
|
80161
80175
|
}
|
|
@@ -80220,6 +80234,42 @@ async function workspaceManifest(spec, context) {
|
|
|
80220
80234
|
}
|
|
80221
80235
|
return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
|
|
80222
80236
|
}
|
|
80237
|
+
function treeBytes(root, context) {
|
|
80238
|
+
let totalBytes = 0;
|
|
80239
|
+
const stack = [path88.resolve(root)];
|
|
80240
|
+
while (stack.length > 0) {
|
|
80241
|
+
const directory = stack.pop();
|
|
80242
|
+
const entries = fs81.readdirSync(directory, { withFileTypes: true });
|
|
80243
|
+
for (const entry of entries) {
|
|
80244
|
+
assertBudget(context);
|
|
80245
|
+
const candidate = path88.join(directory, entry.name);
|
|
80246
|
+
const stat = fs81.lstatSync(candidate);
|
|
80247
|
+
if (stat.isDirectory()) {
|
|
80248
|
+
stack.push(candidate);
|
|
80249
|
+
continue;
|
|
80250
|
+
}
|
|
80251
|
+
if (stat.isFile()) {
|
|
80252
|
+
totalBytes += stat.size;
|
|
80253
|
+
continue;
|
|
80254
|
+
}
|
|
80255
|
+
if (stat.isSymbolicLink()) {
|
|
80256
|
+
totalBytes += Buffer.byteLength(fs81.readlinkSync(candidate));
|
|
80257
|
+
continue;
|
|
80258
|
+
}
|
|
80259
|
+
throw new BenchmarkPhaseError("unsafe_path", `evaluate output contains an unsupported filesystem entry: ${path88.relative(root, candidate)}`);
|
|
80260
|
+
}
|
|
80261
|
+
}
|
|
80262
|
+
return totalBytes;
|
|
80263
|
+
}
|
|
80264
|
+
function assertEvaluateOutputBudget(spec, context, additionalBytes = 0) {
|
|
80265
|
+
const actual = treeBytes(spec.logs_root, context) + additionalBytes;
|
|
80266
|
+
if (actual > spec.workspace_limits.max_total_bytes) {
|
|
80267
|
+
throw new BenchmarkPhaseError("workspace_limit_exceeded", "evaluate output bytes exceed the workspace byte limit", {
|
|
80268
|
+
actual,
|
|
80269
|
+
max_total_bytes: spec.workspace_limits.max_total_bytes
|
|
80270
|
+
});
|
|
80271
|
+
}
|
|
80272
|
+
}
|
|
80223
80273
|
function candidateGlob(pattern) {
|
|
80224
80274
|
let source = "^";
|
|
80225
80275
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
@@ -80346,12 +80396,6 @@ async function copyCandidateOutput(output, manifest, spec, context) {
|
|
|
80346
80396
|
return copied;
|
|
80347
80397
|
}
|
|
80348
80398
|
async function copyFrozenWorkspace(manifest, spec, context) {
|
|
80349
|
-
for (const entry of manifest) {
|
|
80350
|
-
assertBudget(context);
|
|
80351
|
-
if (entry.kind === "symlink") {
|
|
80352
|
-
throw new BenchmarkPhaseError("unsupported_workspace_symlink", `sandbox evaluator workspace cannot safely reproduce symlink: ${entry.path}`);
|
|
80353
|
-
}
|
|
80354
|
-
}
|
|
80355
80399
|
const destinationRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-workspace-"));
|
|
80356
80400
|
fs81.chmodSync(destinationRoot, 448);
|
|
80357
80401
|
context.temporaryRoots.add(destinationRoot);
|
|
@@ -80359,6 +80403,23 @@ async function copyFrozenWorkspace(manifest, spec, context) {
|
|
|
80359
80403
|
assertBudget(context);
|
|
80360
80404
|
const source = path88.resolve(spec.workspace_root, safeRelPath(frozenFile.path));
|
|
80361
80405
|
const destination = path88.resolve(destinationRoot, safeRelPath(frozenFile.path));
|
|
80406
|
+
if (frozenFile.kind === "symlink") {
|
|
80407
|
+
const stat = fs81.lstatSync(source);
|
|
80408
|
+
const target = stat.isSymbolicLink() ? fs81.readlinkSync(source) : null;
|
|
80409
|
+
if (target === null || Buffer.byteLength(target) !== frozenFile.size || sha256(target) !== frozenFile.sha256) {
|
|
80410
|
+
throw new BenchmarkPhaseError("evidence_tampered", `workspace changed after it was frozen: ${frozenFile.path}`);
|
|
80411
|
+
}
|
|
80412
|
+
if (path88.isAbsolute(target)) {
|
|
80413
|
+
throw new BenchmarkPhaseError("unsafe_workspace_symlink", `sandbox evaluator workspace cannot reproduce an absolute symlink: ${frozenFile.path}`);
|
|
80414
|
+
}
|
|
80415
|
+
const resolvedTarget = path88.resolve(path88.dirname(source), target);
|
|
80416
|
+
if (!isWithin(spec.workspace_root, resolvedTarget)) {
|
|
80417
|
+
throw new BenchmarkPhaseError("unsafe_workspace_symlink", `sandbox evaluator workspace symlink escapes the workspace: ${frozenFile.path}`);
|
|
80418
|
+
}
|
|
80419
|
+
fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
|
|
80420
|
+
fs81.symlinkSync(target, destination);
|
|
80421
|
+
continue;
|
|
80422
|
+
}
|
|
80362
80423
|
await atomicCopy(source, destination, frozenFile.mode, spec.workspace_root);
|
|
80363
80424
|
const copied = await recordFile(destinationRoot, destination, "workspace");
|
|
80364
80425
|
if (copied.sha256 !== frozenFile.sha256 || copied.size !== frozenFile.size || copied.mode !== frozenFile.mode) {
|
|
@@ -80367,13 +80428,48 @@ async function copyFrozenWorkspace(manifest, spec, context) {
|
|
|
80367
80428
|
}
|
|
80368
80429
|
return destinationRoot;
|
|
80369
80430
|
}
|
|
80370
|
-
function
|
|
80431
|
+
async function copyEvaluatorTests(spec, context) {
|
|
80432
|
+
const destinationRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-tests-"));
|
|
80433
|
+
fs81.chmodSync(destinationRoot, 448);
|
|
80434
|
+
context.temporaryRoots.add(destinationRoot);
|
|
80435
|
+
const stack = [{ source: spec.tests_root, destination: destinationRoot }];
|
|
80436
|
+
while (stack.length > 0) {
|
|
80437
|
+
assertBudget(context);
|
|
80438
|
+
const current = stack.pop();
|
|
80439
|
+
const entries = fs81.readdirSync(current.source, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
80440
|
+
for (const entry of entries) {
|
|
80441
|
+
assertBudget(context);
|
|
80442
|
+
const source = path88.join(current.source, entry.name);
|
|
80443
|
+
const destination = path88.join(current.destination, entry.name);
|
|
80444
|
+
const stat = fs81.lstatSync(source);
|
|
80445
|
+
if (stat.isSymbolicLink()) {
|
|
80446
|
+
throw new BenchmarkPhaseError("unsafe_path", `evaluator reference tree contains a symlink: ${path88.relative(spec.tests_root, source)}`);
|
|
80447
|
+
}
|
|
80448
|
+
if (stat.isDirectory()) {
|
|
80449
|
+
fs81.mkdirSync(destination, { recursive: true, mode: stat.mode & 511 });
|
|
80450
|
+
stack.push({ source, destination });
|
|
80451
|
+
continue;
|
|
80452
|
+
}
|
|
80453
|
+
if (!stat.isFile()) {
|
|
80454
|
+
throw new BenchmarkPhaseError("unsafe_path", `evaluator reference tree contains an unsupported filesystem entry: ${path88.relative(spec.tests_root, source)}`);
|
|
80455
|
+
}
|
|
80456
|
+
await atomicCopy(source, destination, stat.mode & 511, spec.tests_root);
|
|
80457
|
+
const sourceRecord = await recordFile(spec.tests_root, source, "tests");
|
|
80458
|
+
const copiedRecord = await recordFile(destinationRoot, destination, "tests");
|
|
80459
|
+
if (copiedRecord.path !== sourceRecord.path || copiedRecord.sha256 !== sourceRecord.sha256 || copiedRecord.size !== sourceRecord.size || copiedRecord.mode !== sourceRecord.mode) {
|
|
80460
|
+
throw new BenchmarkPhaseError("evidence_tampered", `evaluator reference changed while it was copied: ${sourceRecord.path}`);
|
|
80461
|
+
}
|
|
80462
|
+
}
|
|
80463
|
+
}
|
|
80464
|
+
return destinationRoot;
|
|
80465
|
+
}
|
|
80466
|
+
function evaluatorTestsPath(evaluator, testsRoot) {
|
|
80371
80467
|
if (!evaluator.tests_path)
|
|
80372
|
-
return
|
|
80468
|
+
return testsRoot;
|
|
80373
80469
|
const relative = normalizedRootRelative(evaluator.tests_path);
|
|
80374
|
-
assertNoSymlinkTraversal(
|
|
80375
|
-
const candidate = path88.resolve(
|
|
80376
|
-
if (!isWithin(
|
|
80470
|
+
assertNoSymlinkTraversal(testsRoot, relative);
|
|
80471
|
+
const candidate = path88.resolve(testsRoot, relative);
|
|
80472
|
+
if (!isWithin(testsRoot, candidate) || !fs81.existsSync(candidate)) {
|
|
80377
80473
|
throw new BenchmarkPhaseError("invalid_tests_path", `evaluator tests_path does not exist: ${evaluator.tests_path}`);
|
|
80378
80474
|
}
|
|
80379
80475
|
const stat = fs81.lstatSync(candidate);
|
|
@@ -80510,7 +80606,21 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80510
80606
|
}
|
|
80511
80607
|
verdict = regexResult.exitCode === 0;
|
|
80512
80608
|
}
|
|
80513
|
-
return {
|
|
80609
|
+
return {
|
|
80610
|
+
...base2,
|
|
80611
|
+
status: verdict ? "passed" : "failed",
|
|
80612
|
+
verdict,
|
|
80613
|
+
duration_ms: Date.now() - started,
|
|
80614
|
+
details: {
|
|
80615
|
+
operator: assertion.operator,
|
|
80616
|
+
actual_size_bytes: Buffer.byteLength(finalOutput),
|
|
80617
|
+
...assertion.operator === "exact" ? {
|
|
80618
|
+
expected_size_bytes: Buffer.byteLength(assertion.expected),
|
|
80619
|
+
actual_sha256: sha256(finalOutput),
|
|
80620
|
+
expected_sha256: sha256(assertion.expected)
|
|
80621
|
+
} : {}
|
|
80622
|
+
}
|
|
80623
|
+
};
|
|
80514
80624
|
}
|
|
80515
80625
|
if (evaluator.type === "trajectory_assertion") {
|
|
80516
80626
|
const count = trajectory.filter((event) => eventType(event) === evaluator.event_type).length;
|
|
@@ -80540,6 +80650,7 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80540
80650
|
}
|
|
80541
80651
|
const exists2 = stat !== null;
|
|
80542
80652
|
let verdict = false;
|
|
80653
|
+
let actualSha256;
|
|
80543
80654
|
if (evaluator.assertion.operator === "exists")
|
|
80544
80655
|
verdict = exists2;
|
|
80545
80656
|
if (evaluator.assertion.operator === "not_exists")
|
|
@@ -80548,7 +80659,8 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80548
80659
|
if (stat?.isFile()) {
|
|
80549
80660
|
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
|
|
80550
80661
|
try {
|
|
80551
|
-
|
|
80662
|
+
actualSha256 = await sha256OfDescriptor(opened.fd);
|
|
80663
|
+
verdict = actualSha256 === evaluator.assertion.expected;
|
|
80552
80664
|
} finally {
|
|
80553
80665
|
fs81.closeSync(opened.fd);
|
|
80554
80666
|
}
|
|
@@ -80564,15 +80676,32 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80564
80676
|
}
|
|
80565
80677
|
}
|
|
80566
80678
|
}
|
|
80567
|
-
return {
|
|
80679
|
+
return {
|
|
80680
|
+
...base2,
|
|
80681
|
+
status: verdict ? "passed" : "failed",
|
|
80682
|
+
verdict,
|
|
80683
|
+
duration_ms: Date.now() - started,
|
|
80684
|
+
details: {
|
|
80685
|
+
operator: evaluator.assertion.operator,
|
|
80686
|
+
path: relative,
|
|
80687
|
+
exists: exists2,
|
|
80688
|
+
...stat ? {
|
|
80689
|
+
actual_kind: stat.isFile() ? "file" : stat.isDirectory() ? "directory" : "other",
|
|
80690
|
+
actual_size_bytes: stat.size
|
|
80691
|
+
} : {},
|
|
80692
|
+
...actualSha256 ? { actual_sha256: actualSha256 } : {}
|
|
80693
|
+
}
|
|
80694
|
+
};
|
|
80568
80695
|
}
|
|
80569
80696
|
let isolatedWorkspace;
|
|
80697
|
+
let isolatedTestsRoot;
|
|
80570
80698
|
let privateResultRoot;
|
|
80571
80699
|
try {
|
|
80572
80700
|
const evaluatorWorkspace = await copyFrozenWorkspace(manifest, spec, context);
|
|
80573
80701
|
isolatedWorkspace = evaluatorWorkspace;
|
|
80574
|
-
|
|
80575
|
-
const
|
|
80702
|
+
isolatedTestsRoot = await copyEvaluatorTests(spec, context);
|
|
80703
|
+
const testsPath = evaluatorTestsPath(evaluator, isolatedTestsRoot);
|
|
80704
|
+
const commandRoot = evaluator.root === "workspace" ? evaluatorWorkspace : isolatedTestsRoot;
|
|
80576
80705
|
const command = { id: evaluator.id, ...evaluator.command };
|
|
80577
80706
|
const environment = {
|
|
80578
80707
|
BRAINBASE_BENCHMARK_WORKSPACE: evaluatorWorkspace,
|
|
@@ -80623,7 +80752,7 @@ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, f
|
|
|
80623
80752
|
...criterionResults ? { criterion_results: criterionResults } : {}
|
|
80624
80753
|
};
|
|
80625
80754
|
} finally {
|
|
80626
|
-
for (const temporary of [privateResultRoot, isolatedWorkspace]) {
|
|
80755
|
+
for (const temporary of [privateResultRoot, isolatedTestsRoot, isolatedWorkspace]) {
|
|
80627
80756
|
if (!temporary)
|
|
80628
80757
|
continue;
|
|
80629
80758
|
fs81.rmSync(temporary, { recursive: true, force: true });
|
|
@@ -80672,6 +80801,7 @@ async function executeEvaluate(spec, context) {
|
|
|
80672
80801
|
];
|
|
80673
80802
|
outputs.push(...frozenEvidenceRecords);
|
|
80674
80803
|
context.outputs.push(...frozenEvidenceRecords);
|
|
80804
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80675
80805
|
assertBudget(context);
|
|
80676
80806
|
const manifest = await workspaceManifest(spec, context);
|
|
80677
80807
|
const manifestPath2 = path88.join(spec.logs_root, "candidate-workspace-manifest.json");
|
|
@@ -80684,6 +80814,7 @@ async function executeEvaluate(spec, context) {
|
|
|
80684
80814
|
const manifestRecord = await recordFile(spec.logs_root, manifestPath2, "logs");
|
|
80685
80815
|
outputs.push(manifestRecord);
|
|
80686
80816
|
context.outputs.push(manifestRecord);
|
|
80817
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80687
80818
|
for (const artifactRelInput of spec.candidate_artifacts) {
|
|
80688
80819
|
const artifactRel = workspaceRel(artifactRelInput);
|
|
80689
80820
|
assertNoSymlinkTraversal(spec.workspace_root, artifactRel);
|
|
@@ -80701,11 +80832,13 @@ async function executeEvaluate(spec, context) {
|
|
|
80701
80832
|
outputs.push(artifact);
|
|
80702
80833
|
context.outputs.push(artifact);
|
|
80703
80834
|
}
|
|
80835
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80704
80836
|
for (const candidateOutput of spec.candidate_outputs) {
|
|
80705
80837
|
const copied = await copyCandidateOutput(candidateOutput, manifest, spec, context);
|
|
80706
80838
|
outputs.push(...copied);
|
|
80707
80839
|
context.outputs.push(...copied);
|
|
80708
80840
|
}
|
|
80841
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80709
80842
|
if (spec.capture_workspace_archive) {
|
|
80710
80843
|
const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
|
|
80711
80844
|
const archive = path88.join(spec.logs_root, "candidate-workspace.tar.gz");
|
|
@@ -80719,6 +80852,7 @@ async function executeEvaluate(spec, context) {
|
|
|
80719
80852
|
const archiveRecord = await recordFile(spec.logs_root, archive, "logs");
|
|
80720
80853
|
outputs.push(archiveRecord);
|
|
80721
80854
|
context.outputs.push(archiveRecord);
|
|
80855
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80722
80856
|
}
|
|
80723
80857
|
await verifyRecordsUnchanged(manifest, spec);
|
|
80724
80858
|
for (const reference of spec.references) {
|
|
@@ -80777,12 +80911,16 @@ async function executeEvaluate(spec, context) {
|
|
|
80777
80911
|
}
|
|
80778
80912
|
if (requiredResultError)
|
|
80779
80913
|
throw requiredResultError;
|
|
80914
|
+
if (evaluator.type === "sandbox_command") {
|
|
80915
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80916
|
+
}
|
|
80780
80917
|
}
|
|
80781
80918
|
await verifyRecordsUnchanged([...context.inputs, ...context.outputs.slice(0, frozenOutputCount)], spec);
|
|
80782
80919
|
if (!verifyOwnedDirectory(spec.tests_root, "tests", spec) || !verifyOwnedDirectory(spec.logs_root, "logs", spec)) {
|
|
80783
80920
|
throw new BenchmarkPhaseError("evidence_tampered", "benchmark evaluator changed an owned phase directory marker");
|
|
80784
80921
|
}
|
|
80785
80922
|
assertBudget(context);
|
|
80923
|
+
assertEvaluateOutputBudget(spec, context);
|
|
80786
80924
|
evaluators.sort((left, right) => evaluatorOrder.get(left.id) - evaluatorOrder.get(right.id));
|
|
80787
80925
|
return { outputs, evaluators };
|
|
80788
80926
|
}
|
|
@@ -80968,6 +81106,7 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
80968
81106
|
let status = "failed";
|
|
80969
81107
|
let error2;
|
|
80970
81108
|
let context;
|
|
81109
|
+
let validatedSpec;
|
|
80971
81110
|
let resultPathValidated = false;
|
|
80972
81111
|
try {
|
|
80973
81112
|
let bytes;
|
|
@@ -80987,6 +81126,7 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
80987
81126
|
}
|
|
80988
81127
|
identity2 = rawIdentity(raw);
|
|
80989
81128
|
const spec = BenchmarkSpecSchema.parse(raw);
|
|
81129
|
+
validatedSpec = spec;
|
|
80990
81130
|
if (expectedPhase && spec.phase !== expectedPhase) {
|
|
80991
81131
|
throw new BenchmarkPhaseError("phase_mismatch", `the ${expectedPhase} command cannot execute a ${spec.phase} spec`);
|
|
80992
81132
|
}
|
|
@@ -81066,6 +81206,17 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
|
|
|
81066
81206
|
if (!resultPathValidated || !context?.logsOwned) {
|
|
81067
81207
|
return { exitCode: status === "succeeded" ? 0 : 1, result: result2 };
|
|
81068
81208
|
}
|
|
81209
|
+
if (status === "succeeded" && validatedSpec?.phase === "evaluate") {
|
|
81210
|
+
try {
|
|
81211
|
+
const resultBytes = Buffer.byteLength(`${JSON.stringify(result2, null, 2)}
|
|
81212
|
+
`);
|
|
81213
|
+
assertEvaluateOutputBudget(validatedSpec, context, resultBytes);
|
|
81214
|
+
} catch (budgetError) {
|
|
81215
|
+
status = "failed";
|
|
81216
|
+
result2.status = "failed";
|
|
81217
|
+
result2.error = stableError(budgetError);
|
|
81218
|
+
}
|
|
81219
|
+
}
|
|
81069
81220
|
try {
|
|
81070
81221
|
writeJsonAtomic(resultPath, result2);
|
|
81071
81222
|
} catch (writeError) {
|