@brainbase-labs/cli 0.25.0-eng1209.7 → 0.25.0-eng1209.8
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 +178 -26
- 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.8",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -78492,6 +78492,9 @@ var MAX_CRITERION_EXPLANATION_LENGTH = 16384;
|
|
|
78492
78492
|
var MAX_CRITERION_EVIDENCE_IDS = 100;
|
|
78493
78493
|
var MAX_CRITERION_EVIDENCE_ID_LENGTH = 256;
|
|
78494
78494
|
var MAX_ALLOWED_EVIDENCE_IDS = 1e4;
|
|
78495
|
+
var COMMAND_PROCESS_MARKER_ENV = "BRAINBASE_BENCHMARK_COMMAND_MARKER";
|
|
78496
|
+
var COMMAND_PROCESS_POLL_MS = 10;
|
|
78497
|
+
var COMMAND_PROCESS_CLEANUP_MS = 500;
|
|
78495
78498
|
var RESERVED_WORKSPACE_PATHS = new Set([
|
|
78496
78499
|
".brainbase",
|
|
78497
78500
|
".git",
|
|
@@ -78712,6 +78715,20 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
|
|
|
78712
78715
|
HydrateSpecSchema,
|
|
78713
78716
|
EvaluateSpecSchema
|
|
78714
78717
|
]).superRefine((value, context) => {
|
|
78718
|
+
if (Object.hasOwn(value.environment, COMMAND_PROCESS_MARKER_ENV)) {
|
|
78719
|
+
context.addIssue({
|
|
78720
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78721
|
+
path: ["environment", COMMAND_PROCESS_MARKER_ENV],
|
|
78722
|
+
message: `${COMMAND_PROCESS_MARKER_ENV} is reserved for command supervision`
|
|
78723
|
+
});
|
|
78724
|
+
}
|
|
78725
|
+
if (value.secret_env.includes(COMMAND_PROCESS_MARKER_ENV)) {
|
|
78726
|
+
context.addIssue({
|
|
78727
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78728
|
+
path: ["secret_env"],
|
|
78729
|
+
message: `${COMMAND_PROCESS_MARKER_ENV} is reserved for command supervision`
|
|
78730
|
+
});
|
|
78731
|
+
}
|
|
78715
78732
|
for (const name of Object.keys(value.environment)) {
|
|
78716
78733
|
if (SENSITIVE_ENV_NAME_RE.test(name)) {
|
|
78717
78734
|
context.addIssue({
|
|
@@ -79920,7 +79937,7 @@ function buildEnvironment(spec, secretNames, additions = {}) {
|
|
|
79920
79937
|
Object.assign(env3, additions);
|
|
79921
79938
|
return env3;
|
|
79922
79939
|
}
|
|
79923
|
-
function redactCommandOutput(data, spec) {
|
|
79940
|
+
function redactCommandOutput(data, spec, additionalSecrets = []) {
|
|
79924
79941
|
let value = data.toString("utf8");
|
|
79925
79942
|
const sensitiveNames = new Set([
|
|
79926
79943
|
...spec.secret_env,
|
|
@@ -79931,6 +79948,10 @@ function redactCommandOutput(data, spec) {
|
|
|
79931
79948
|
if (secret)
|
|
79932
79949
|
value = value.split(secret).join("[REDACTED]");
|
|
79933
79950
|
}
|
|
79951
|
+
for (const secret of additionalSecrets) {
|
|
79952
|
+
if (secret)
|
|
79953
|
+
value = value.split(secret).join("[REDACTED]");
|
|
79954
|
+
}
|
|
79934
79955
|
return Buffer.from(value);
|
|
79935
79956
|
}
|
|
79936
79957
|
function descendantPids(parentPid) {
|
|
@@ -79982,6 +80003,86 @@ function terminate(child) {
|
|
|
79982
80003
|
child.kill("SIGKILL");
|
|
79983
80004
|
}
|
|
79984
80005
|
}
|
|
80006
|
+
function markedProcessPids(marker) {
|
|
80007
|
+
const assignment = `${COMMAND_PROCESS_MARKER_ENV}=${marker}`;
|
|
80008
|
+
if (process.platform === "linux") {
|
|
80009
|
+
const matches2 = [];
|
|
80010
|
+
let entries;
|
|
80011
|
+
try {
|
|
80012
|
+
entries = fs81.readdirSync("/proc");
|
|
80013
|
+
} catch {
|
|
80014
|
+
return matches2;
|
|
80015
|
+
}
|
|
80016
|
+
for (const entry of entries) {
|
|
80017
|
+
if (!/^\d+$/.test(entry))
|
|
80018
|
+
continue;
|
|
80019
|
+
const pid = Number(entry);
|
|
80020
|
+
if (pid === process.pid)
|
|
80021
|
+
continue;
|
|
80022
|
+
try {
|
|
80023
|
+
const environment = fs81.readFileSync(path88.join("/proc", entry, "environ"), "utf8");
|
|
80024
|
+
if (environment.split("\x00").includes(assignment))
|
|
80025
|
+
matches2.push(pid);
|
|
80026
|
+
} catch {}
|
|
80027
|
+
}
|
|
80028
|
+
return matches2;
|
|
80029
|
+
}
|
|
80030
|
+
if (process.platform === "darwin") {
|
|
80031
|
+
try {
|
|
80032
|
+
const output = execFileSync2("ps", ["eww", "-axo", "pid=,command="], {
|
|
80033
|
+
encoding: "utf8",
|
|
80034
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
80035
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
80036
|
+
});
|
|
80037
|
+
const matches2 = [];
|
|
80038
|
+
for (const line of output.split(`
|
|
80039
|
+
`)) {
|
|
80040
|
+
const match = line.match(/^\s*(\d+)\s+(.*)$/);
|
|
80041
|
+
if (!match || !match[2].includes(assignment))
|
|
80042
|
+
continue;
|
|
80043
|
+
const pid = Number(match[1]);
|
|
80044
|
+
if (Number.isInteger(pid) && pid !== process.pid)
|
|
80045
|
+
matches2.push(pid);
|
|
80046
|
+
}
|
|
80047
|
+
return matches2;
|
|
80048
|
+
} catch {
|
|
80049
|
+
return [];
|
|
80050
|
+
}
|
|
80051
|
+
}
|
|
80052
|
+
return [];
|
|
80053
|
+
}
|
|
80054
|
+
function processExists(pid) {
|
|
80055
|
+
try {
|
|
80056
|
+
process.kill(pid, 0);
|
|
80057
|
+
return true;
|
|
80058
|
+
} catch (error2) {
|
|
80059
|
+
return error2.code !== "ESRCH";
|
|
80060
|
+
}
|
|
80061
|
+
}
|
|
80062
|
+
async function terminateCommandProcesses(child, marker, observedDescendants) {
|
|
80063
|
+
if (child.pid !== undefined) {
|
|
80064
|
+
for (const pid of descendantPids(child.pid))
|
|
80065
|
+
observedDescendants.add(pid);
|
|
80066
|
+
}
|
|
80067
|
+
terminate(child);
|
|
80068
|
+
const deadline = Date.now() + COMMAND_PROCESS_CLEANUP_MS;
|
|
80069
|
+
while (true) {
|
|
80070
|
+
for (const pid of markedProcessPids(marker))
|
|
80071
|
+
observedDescendants.add(pid);
|
|
80072
|
+
const active = [...observedDescendants].filter(processExists);
|
|
80073
|
+
for (const pid of active) {
|
|
80074
|
+
try {
|
|
80075
|
+
process.kill(pid, "SIGKILL");
|
|
80076
|
+
} catch {}
|
|
80077
|
+
}
|
|
80078
|
+
if (active.length === 0)
|
|
80079
|
+
return;
|
|
80080
|
+
if (Date.now() >= deadline) {
|
|
80081
|
+
throw new BenchmarkPhaseError("command_cleanup_failed", "command descendants remained after bounded cleanup");
|
|
80082
|
+
}
|
|
80083
|
+
await new Promise((resolve) => setTimeout(resolve, COMMAND_PROCESS_POLL_MS));
|
|
80084
|
+
}
|
|
80085
|
+
}
|
|
79985
80086
|
async function runCommand(command, root, spec, context, additions = {}) {
|
|
79986
80087
|
const cwdRel = normalizedRootRelative(command.cwd);
|
|
79987
80088
|
assertNoSymlinkTraversal(root, cwdRel);
|
|
@@ -80001,27 +80102,56 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80001
80102
|
const reachesPhaseDeadline = command.timeout_ms === undefined || command.timeout_ms >= remainingMs;
|
|
80002
80103
|
const timeoutMs2 = reachesPhaseDeadline ? remainingMs : command.timeout_ms;
|
|
80003
80104
|
const started = Date.now();
|
|
80105
|
+
const commandMarker = crypto6.randomBytes(32).toString("hex");
|
|
80004
80106
|
return await new Promise((resolve, reject2) => {
|
|
80005
80107
|
const child = spawn4(command.argv[0], command.argv.slice(1), {
|
|
80006
80108
|
cwd: cwd2,
|
|
80007
|
-
env: buildEnvironment(spec, command.secret_env,
|
|
80109
|
+
env: buildEnvironment(spec, command.secret_env, {
|
|
80110
|
+
...additions,
|
|
80111
|
+
[COMMAND_PROCESS_MARKER_ENV]: commandMarker
|
|
80112
|
+
}),
|
|
80008
80113
|
stdio: ["ignore", "pipe", "pipe"],
|
|
80009
80114
|
detached: process.platform !== "win32"
|
|
80010
80115
|
});
|
|
80011
80116
|
const stdout = [];
|
|
80012
80117
|
const stderr = [];
|
|
80118
|
+
const observedDescendants = new Set;
|
|
80013
80119
|
let captured = 0;
|
|
80014
80120
|
let settled = false;
|
|
80015
80121
|
let timer;
|
|
80122
|
+
let observer;
|
|
80123
|
+
let cleanup;
|
|
80124
|
+
const observeDescendants = () => {
|
|
80125
|
+
if (child.pid === undefined)
|
|
80126
|
+
return;
|
|
80127
|
+
for (const pid of descendantPids(child.pid))
|
|
80128
|
+
observedDescendants.add(pid);
|
|
80129
|
+
};
|
|
80130
|
+
const cleanupProcesses = () => {
|
|
80131
|
+
if (observer)
|
|
80132
|
+
clearInterval(observer);
|
|
80133
|
+
cleanup ??= terminateCommandProcesses(child, commandMarker, observedDescendants);
|
|
80134
|
+
return cleanup;
|
|
80135
|
+
};
|
|
80136
|
+
const sanitizedOutput = (chunks) => redactCommandOutput(Buffer.concat(chunks), spec, [commandMarker]);
|
|
80137
|
+
const sanitizedError = (error2) => {
|
|
80138
|
+
if (!(error2 instanceof BenchmarkCommandExecutionError))
|
|
80139
|
+
return error2;
|
|
80140
|
+
return new BenchmarkCommandExecutionError(error2.code, error2.message, sanitizedOutput(stdout), sanitizedOutput(stderr), error2.durationMs);
|
|
80141
|
+
};
|
|
80016
80142
|
const fail = (error2) => {
|
|
80017
80143
|
if (settled)
|
|
80018
80144
|
return;
|
|
80019
80145
|
settled = true;
|
|
80020
80146
|
if (timer)
|
|
80021
80147
|
clearTimeout(timer);
|
|
80022
|
-
|
|
80023
|
-
reject2(error2);
|
|
80148
|
+
cleanupProcesses().then(() => reject2(sanitizedError(error2)), reject2);
|
|
80024
80149
|
};
|
|
80150
|
+
if (process.platform !== "linux") {
|
|
80151
|
+
observeDescendants();
|
|
80152
|
+
observer = setInterval(observeDescendants, COMMAND_PROCESS_POLL_MS);
|
|
80153
|
+
observer.unref();
|
|
80154
|
+
}
|
|
80025
80155
|
const capture = (target, chunk2) => {
|
|
80026
80156
|
if (settled)
|
|
80027
80157
|
return;
|
|
@@ -80036,7 +80166,9 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80036
80166
|
child.stdout?.on("data", (chunk2) => capture(stdout, chunk2));
|
|
80037
80167
|
child.stderr?.on("data", (chunk2) => capture(stderr, chunk2));
|
|
80038
80168
|
child.once("exit", () => {
|
|
80039
|
-
|
|
80169
|
+
if (timer)
|
|
80170
|
+
clearTimeout(timer);
|
|
80171
|
+
cleanupProcesses();
|
|
80040
80172
|
});
|
|
80041
80173
|
child.on("error", (error2) => {
|
|
80042
80174
|
fail(new BenchmarkCommandExecutionError("command_start_failed", `failed to start ${command.id}: ${error2.message}`, Buffer.concat(stdout), Buffer.concat(stderr), Date.now() - started));
|
|
@@ -80053,16 +80185,19 @@ async function runCommand(command, root, spec, context, additions = {}) {
|
|
|
80053
80185
|
return;
|
|
80054
80186
|
settled = true;
|
|
80055
80187
|
clearTimeout(timer);
|
|
80056
|
-
|
|
80057
|
-
|
|
80058
|
-
|
|
80059
|
-
|
|
80060
|
-
|
|
80061
|
-
|
|
80062
|
-
|
|
80063
|
-
|
|
80064
|
-
|
|
80065
|
-
|
|
80188
|
+
cleanupProcesses().then(() => {
|
|
80189
|
+
if (code === null) {
|
|
80190
|
+
reject2(new BenchmarkCommandExecutionError("command_terminated", `command was terminated by ${signal ?? "an unknown signal"}: ${command.id}`, sanitizedOutput(stdout), sanitizedOutput(stderr), Date.now() - started));
|
|
80191
|
+
return;
|
|
80192
|
+
}
|
|
80193
|
+
resolve({
|
|
80194
|
+
exitCode: code,
|
|
80195
|
+
stdout: sanitizedOutput(stdout),
|
|
80196
|
+
stderr: sanitizedOutput(stderr),
|
|
80197
|
+
durationMs: Date.now() - started,
|
|
80198
|
+
redactions: [commandMarker]
|
|
80199
|
+
});
|
|
80200
|
+
}, reject2);
|
|
80066
80201
|
});
|
|
80067
80202
|
});
|
|
80068
80203
|
}
|
|
@@ -80255,6 +80390,13 @@ async function workspaceManifest(spec, context) {
|
|
|
80255
80390
|
}
|
|
80256
80391
|
return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
|
|
80257
80392
|
}
|
|
80393
|
+
async function verifyWorkspaceManifestUnchanged(expected, spec, context) {
|
|
80394
|
+
await verifyRecordsUnchanged(expected, spec);
|
|
80395
|
+
const actual = await workspaceManifest(spec, context);
|
|
80396
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
80397
|
+
throw new BenchmarkPhaseError("evidence_tampered", "candidate workspace changed during read-only evaluation");
|
|
80398
|
+
}
|
|
80399
|
+
}
|
|
80258
80400
|
function treeBytes(root, context) {
|
|
80259
80401
|
let totalBytes = 0;
|
|
80260
80402
|
const stack = [path88.resolve(root)];
|
|
@@ -80516,7 +80658,7 @@ var CriterionResultSchema = exports_external.object({
|
|
|
80516
80658
|
var CriteriaResultFileSchema = exports_external.object({
|
|
80517
80659
|
criteria: exports_external.array(CriterionResultSchema).max(MAX_CRITERIA_PER_EVALUATOR)
|
|
80518
80660
|
}).strict();
|
|
80519
|
-
function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds, spec) {
|
|
80661
|
+
function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds, spec, additionalSecrets = []) {
|
|
80520
80662
|
let opened;
|
|
80521
80663
|
try {
|
|
80522
80664
|
opened = openRegularFileNoFollow(resultPath, "criterion result", path88.dirname(resultPath));
|
|
@@ -80564,7 +80706,7 @@ function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds, spe
|
|
|
80564
80706
|
const criterion = byKey.get(key2);
|
|
80565
80707
|
return {
|
|
80566
80708
|
...criterion,
|
|
80567
|
-
explanation: redactCommandOutput(Buffer.from(criterion.explanation), spec).toString("utf8")
|
|
80709
|
+
explanation: redactCommandOutput(Buffer.from(criterion.explanation), spec, additionalSecrets).toString("utf8")
|
|
80568
80710
|
};
|
|
80569
80711
|
});
|
|
80570
80712
|
} finally {
|
|
@@ -80723,9 +80865,13 @@ async function evaluateOne(evaluator, spec, manifest, frozenWorkspaceRoot, final
|
|
|
80723
80865
|
let isolatedWorkspace;
|
|
80724
80866
|
let isolatedTestsRoot;
|
|
80725
80867
|
let privateResultRoot;
|
|
80868
|
+
const usesLiveWorkspace = evaluator.workspace_mode === "read_only";
|
|
80726
80869
|
try {
|
|
80727
|
-
const evaluatorWorkspace = await copyFrozenWorkspace(manifest, spec, context, frozenWorkspaceRoot);
|
|
80728
|
-
|
|
80870
|
+
const evaluatorWorkspace = usesLiveWorkspace ? spec.workspace_root : await copyFrozenWorkspace(manifest, spec, context, frozenWorkspaceRoot);
|
|
80871
|
+
if (!usesLiveWorkspace)
|
|
80872
|
+
isolatedWorkspace = evaluatorWorkspace;
|
|
80873
|
+
else
|
|
80874
|
+
await verifyWorkspaceManifestUnchanged(manifest, spec, context);
|
|
80729
80875
|
isolatedTestsRoot = await copyEvaluatorTests(spec, context);
|
|
80730
80876
|
const testsPath = evaluatorTestsPath(evaluator, isolatedTestsRoot);
|
|
80731
80877
|
const commandRoot = evaluator.root === "workspace" ? evaluatorWorkspace : isolatedTestsRoot;
|
|
@@ -80750,7 +80896,7 @@ async function evaluateOne(evaluator, spec, manifest, frozenWorkspaceRoot, final
|
|
|
80750
80896
|
const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
|
|
80751
80897
|
let criterionResults;
|
|
80752
80898
|
try {
|
|
80753
|
-
criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? [], spec) : undefined;
|
|
80899
|
+
criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? [], spec, result2.redactions) : undefined;
|
|
80754
80900
|
} catch (error2) {
|
|
80755
80901
|
const normalized = stableError(error2);
|
|
80756
80902
|
return {
|
|
@@ -80779,11 +80925,17 @@ async function evaluateOne(evaluator, spec, manifest, frozenWorkspaceRoot, final
|
|
|
80779
80925
|
...criterionResults ? { criterion_results: criterionResults } : {}
|
|
80780
80926
|
};
|
|
80781
80927
|
} finally {
|
|
80782
|
-
|
|
80783
|
-
if (
|
|
80784
|
-
|
|
80785
|
-
|
|
80786
|
-
|
|
80928
|
+
try {
|
|
80929
|
+
if (usesLiveWorkspace) {
|
|
80930
|
+
await verifyWorkspaceManifestUnchanged(manifest, spec, context);
|
|
80931
|
+
}
|
|
80932
|
+
} finally {
|
|
80933
|
+
for (const temporary of [privateResultRoot, isolatedTestsRoot, isolatedWorkspace]) {
|
|
80934
|
+
if (!temporary)
|
|
80935
|
+
continue;
|
|
80936
|
+
fs81.rmSync(temporary, { recursive: true, force: true });
|
|
80937
|
+
context.temporaryRoots.delete(temporary);
|
|
80938
|
+
}
|
|
80787
80939
|
}
|
|
80788
80940
|
}
|
|
80789
80941
|
}
|