@garuda-agent/garuda 0.18.0 → 0.18.2

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 (58) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/README.md +3 -2
  3. package/dist/{acpCommand-IUZPLPLI.js → acpCommand-PUJHFWYU.js} +10 -8
  4. package/dist/advise-C777SZ5M.js +433 -0
  5. package/dist/brief-RWKESOPT.js +91 -0
  6. package/dist/buildCheck-HB46NWLX.js +19 -0
  7. package/dist/buildInfo-Z4P7QAQL.js +8 -0
  8. package/dist/chunk-2OYTNNUJ.js +216 -0
  9. package/dist/chunk-4BELTWP4.js +156 -0
  10. package/dist/chunk-4QRTTRVK.js +88 -0
  11. package/dist/chunk-6JQTPW3P.js +88 -0
  12. package/dist/chunk-A5DLAXB4.js +1780 -0
  13. package/dist/{chunk-FARS4R67.js → chunk-AX3A5KPH.js} +18 -1
  14. package/dist/chunk-CFDRP6XW.js +9 -0
  15. package/dist/chunk-E6YRCDSF.js +9 -0
  16. package/dist/{chunk-OQ26W5L4.js → chunk-HP6EGFHV.js} +132 -75
  17. package/dist/chunk-L55VUSX3.js +54 -0
  18. package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
  19. package/dist/{chunk-Q4P3W657.js → chunk-LWNMEGDF.js} +10 -1124
  20. package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
  21. package/dist/{chunk-UKIE4AAM.js → chunk-NLS7GMF7.js} +11 -105
  22. package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
  23. package/dist/{chunk-4BVCYCQT.js → chunk-R7RCW4BQ.js} +9 -7
  24. package/dist/{chunk-NHWHG3SW.js → chunk-STVFWSIL.js} +350 -57
  25. package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
  26. package/dist/chunk-ULAJPMY7.js +107 -0
  27. package/dist/chunk-VISKX36R.js +306 -0
  28. package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
  29. package/dist/chunk-Y62J7PTD.js +90 -0
  30. package/dist/chunk-YAQ6QLKB.js +40 -0
  31. package/dist/{chunk-FOPBOB7W.js → chunk-YEH2OONM.js} +6 -4
  32. package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
  33. package/dist/cli/index.js +242 -52
  34. package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
  35. package/dist/{evalCommand-SKJQ6CW2.js → evalCommand-MRO6ENCA.js} +77 -39
  36. package/dist/{evalTune-CZRCPSZ3.js → evalTune-VL5RHYOG.js} +24 -18
  37. package/dist/{export-SJ3DUP6W.js → export-ZPF3AMO6.js} +27 -4
  38. package/dist/exportHtml-ISISG5HG.js +21 -0
  39. package/dist/{inkChat-WYYAFZXD.js → inkChat-UDFX6GH6.js} +256 -41
  40. package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
  41. package/dist/{jobCommand-2ODQLHB3.js → jobCommand-ILOTYOX3.js} +8 -7
  42. package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
  43. package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
  44. package/dist/{manager-TCYTA5XU.js → manager-YH7722C2.js} +3 -3
  45. package/dist/{nightCommand-WJU6VZA6.js → nightCommand-XPWT6CQZ.js} +8 -7
  46. package/dist/receiptView-YFDHV253.js +19 -0
  47. package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
  48. package/dist/{run-PTMRQCIU.js → run-W4TK52WT.js} +5 -5
  49. package/dist/runner-EBF6EOYM.js +97 -0
  50. package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
  51. package/dist/tour-CEVMAC5S.js +18 -0
  52. package/dist/tune-KSNKBPNJ.js +51 -0
  53. package/dist/uiState-YFJQ43D7.js +16 -0
  54. package/package.json +1 -1
  55. package/dist/chunk-4JSUUDFQ.js +0 -118
  56. package/dist/chunk-C57GHLKP.js +0 -9
  57. package/dist/chunk-DOCDCQVM.js +0 -484
  58. package/dist/tune-YVI2KWQF.js +0 -31
@@ -1,1110 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- DEFAULT_SEED,
4
- consistency,
5
- costPerPass,
6
- mcpUse,
7
- mcpUseText,
8
- passInterval,
9
- roughNote,
10
- spread,
11
- stepsSd,
12
- unexpectedChanges
13
- } from "./chunk-DOCDCQVM.js";
14
- import {
15
- AutoApprover
16
- } from "./chunk-NXJ4XLB5.js";
17
- import {
18
- DEFAULT_MAX_STEPS,
19
- Runtime
20
- } from "./chunk-NHWHG3SW.js";
21
- import {
22
- FileSessionStore,
23
- isCostIncomplete
24
- } from "./chunk-UKIE4AAM.js";
25
- import {
26
- totalTokens
27
- } from "./chunk-7KBOIPUT.js";
28
- import {
29
- LINK_CANDIDATES,
30
- cleanArgs
31
- } from "./chunk-55CFEEIN.js";
32
- import {
33
- MANIFEST,
34
- TEST_PATH,
35
- tail
36
- } from "./chunk-AOGFYUKG.js";
37
- import {
38
- git,
39
- shellWord
40
- } from "./chunk-6XHON3Q6.js";
41
- import {
42
- DEFAULT_ENV_ALLOWLIST,
43
- HostExecutor,
44
- parseSettings
45
- } from "./chunk-B4SJY7KT.js";
46
- import {
47
- pathMatches
48
- } from "./chunk-3NJNVZTK.js";
49
-
50
- // src/evals/toolchains.ts
51
- import { mkdtemp, rm } from "fs/promises";
52
- import { tmpdir } from "os";
53
- import { join as join2 } from "path";
54
-
55
- // src/evals/files.ts
56
- import { mkdirSync } from "fs";
57
- import { writeFile } from "fs/promises";
58
- import { dirname, join } from "path";
59
- async function writeFiles(root, files) {
60
- for (const [path, content] of Object.entries(files)) {
61
- const full = join(root, path);
62
- mkdirSync(dirname(full), { recursive: true });
63
- await writeFile(full, content);
64
- }
65
- }
66
-
67
- // src/evals/projects.ts
68
- var MAVEN_POM = `<?xml version="1.0" encoding="UTF-8"?>
69
- <project xmlns="http://maven.apache.org/POM/4.0.0"
70
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
71
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
72
- <modelVersion>4.0.0</modelVersion>
73
- <groupId>dev.garuda.eval</groupId>
74
- <artifactId>eval</artifactId>
75
- <version>1.0.0</version>
76
-
77
- <properties>
78
- <maven.compiler.release>17</maven.compiler.release>
79
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
80
- </properties>
81
-
82
- <dependencies>
83
- <dependency>
84
- <groupId>org.junit.jupiter</groupId>
85
- <artifactId>junit-jupiter</artifactId>
86
- <version>5.11.4</version>
87
- <scope>test</scope>
88
- </dependency>
89
- </dependencies>
90
-
91
- <build>
92
- <plugins>
93
- <plugin>
94
- <groupId>org.apache.maven.plugins</groupId>
95
- <artifactId>maven-resources-plugin</artifactId>
96
- <version>3.3.1</version>
97
- </plugin>
98
- <plugin>
99
- <groupId>org.apache.maven.plugins</groupId>
100
- <artifactId>maven-compiler-plugin</artifactId>
101
- <version>3.13.0</version>
102
- </plugin>
103
- <plugin>
104
- <groupId>org.apache.maven.plugins</groupId>
105
- <artifactId>maven-surefire-plugin</artifactId>
106
- <version>3.5.2</version>
107
- </plugin>
108
- </plugins>
109
- </build>
110
- </project>
111
- `;
112
- var MAVEN_CHECK = "test ! -e .mvn && mvn -B -q -o test";
113
- var PYPROJECT = `[project]
114
- name = "evalpkg"
115
- version = "0.1.0"
116
- requires-python = ">=3.9"
117
-
118
- [tool.pytest.ini_options]
119
- pythonpath = ["src"]
120
- testpaths = ["tests"]
121
- `;
122
- var PYTEST_CHECK = "python3 -m pytest -q -c pyproject.toml --noconftest -p no:cacheprovider";
123
- function isProtectedPath(path) {
124
- return /^(test|tests|src\/test)\//.test(path) || path === "pom.xml" || path === "pyproject.toml";
125
- }
126
- var lines = (...l) => `${l.join("\n")}
127
- `;
128
-
129
- // src/evals/toolchains.ts
130
- var TOOLCHAIN_ENV = ["JAVA_HOME", "GRADLE_USER_HOME", "VIRTUAL_ENV"];
131
- var TOOLCHAINS = {
132
- maven: {
133
- id: "maven",
134
- title: "Maven with JUnit 5 in ~/.m2",
135
- files: {
136
- "pom.xml": MAVEN_POM,
137
- "src/main/java/probe/Probe.java": "package probe;\n\npublic final class Probe {\n public static int one() {\n return 1;\n }\n}\n",
138
- "src/test/java/probe/ProbeTest.java": "package probe;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport org.junit.jupiter.api.Test;\n\nclass ProbeTest {\n @Test\n void one() {\n assertEquals(1, Probe.one());\n }\n}\n"
139
- },
140
- probe: "mvn -B -q -o test",
141
- prepare: "mvn -B -q test",
142
- hint: "The Java tasks need a JDK (17 or later), Maven, and JUnit 5 in ~/.m2. Run `garuda eval --prepare java` once: it downloads the plugins and JUnit with Maven (network)."
143
- },
144
- pytest: {
145
- id: "pytest",
146
- title: "Python 3 with pytest",
147
- files: {
148
- "pyproject.toml": PYPROJECT,
149
- "src/probe/__init__.py": "def one():\n return 1\n",
150
- "tests/test_probe.py": "from probe import one\n\n\ndef test_one():\n assert one() == 1\n"
151
- },
152
- probe: "python3 -m pytest -q -p no:cacheprovider",
153
- hint: "The Python tasks need python3 with pytest 7 or later. Install it, for example with `python3 -m pip install --user pytest`."
154
- }
155
- };
156
- var PROBE_TIMEOUT_MS = 12e4;
157
- var PREPARE_TIMEOUT_MS = 10 * 6e4;
158
- async function checkToolchains(ids) {
159
- return Promise.all(
160
- [...new Set(ids)].map(async (id) => {
161
- const toolchain = TOOLCHAINS[id];
162
- const r = await inScratch(toolchain, toolchain.probe, PROBE_TIMEOUT_MS);
163
- return { id, ...r };
164
- })
165
- );
166
- }
167
- async function prepareToolchain(id) {
168
- const toolchain = TOOLCHAINS[id];
169
- if (toolchain.prepare === void 0) return { ok: false, output: toolchain.hint };
170
- return inScratch(toolchain, toolchain.prepare, PREPARE_TIMEOUT_MS);
171
- }
172
- function toolchainId(name) {
173
- const aliases = {
174
- java: "maven",
175
- maven: "maven",
176
- python: "pytest",
177
- pytest: "pytest"
178
- };
179
- return aliases[name.toLowerCase()];
180
- }
181
- async function inScratch(toolchain, command, timeoutMs) {
182
- const root = await mkdtemp(join2(tmpdir(), `garuda-toolchain-${toolchain.id}-`));
183
- try {
184
- await writeFiles(root, toolchain.files);
185
- const r = await new HostExecutor().run(command, {
186
- root,
187
- sandbox: false,
188
- writePaths: [root],
189
- denyWritePaths: [],
190
- denyReadPaths: [],
191
- network: true,
192
- envAllowlist: [...DEFAULT_ENV_ALLOWLIST, ...TOOLCHAIN_ENV],
193
- timeoutMs,
194
- maxOutputBytes: 4e3
195
- });
196
- const output = `${r.stdout.text}${r.stderr.text}`.trim();
197
- return { ok: r.exitCode === 0 && !r.timedOut, output };
198
- } catch (error) {
199
- return { ok: false, output: error.message };
200
- } finally {
201
- await rm(root, { recursive: true, force: true });
202
- }
203
- }
204
-
205
- // src/evals/repoTasks.ts
206
- import { mkdtempSync, realpathSync } from "fs";
207
- import { mkdir, readFile, rm as rm2, symlink, writeFile as writeFile2 } from "fs/promises";
208
- import { tmpdir as tmpdir2 } from "os";
209
- import { dirname as dirname2, join as join3 } from "path";
210
- import { z } from "zod";
211
- var REPO_SUITE_FILE = join3(".garuda", "evals", "repo-suite.json");
212
- var DEFAULT_COMMITS = 200;
213
- var DEFAULT_MAX_TASKS = 30;
214
- var MAX_TASK_FILES = 10;
215
- var BUILD_TEST_TIMEOUT_MS = 5 * 6e4;
216
- var testFile = z.object({ path: z.string(), content: z.string().nullable() });
217
- var taskSchema = z.object({
218
- id: z.string(),
219
- sha: z.string(),
220
- base: z.string(),
221
- subject: z.string(),
222
- prompt: z.string(),
223
- tests: z.array(testFile),
224
- /** The check: the test command for this task's test files. Absent: the suite's test command. */
225
- check: z.string().optional()
226
- });
227
- var suiteSchema = z.object({
228
- version: z.literal(1),
229
- root: z.string(),
230
- head: z.string(),
231
- createdAt: z.string(),
232
- testCommand: z.string(),
233
- tasks: z.array(taskSchema)
234
- });
235
- var DOC_PATH = /\.(md|mdx|rst|txt|adoc)$|(^|\/)docs?\//i;
236
- var PACKAGE_JSON = /(^|\/)package\.json$/;
237
- function skipReason(commit) {
238
- const { files } = commit;
239
- if (files.length === 0) return "no files";
240
- const code = files.filter((f) => !DOC_PATH.test(f.path));
241
- if (code.length > MAX_TASK_FILES) return `more than ${MAX_TASK_FILES} files`;
242
- if (files.some((f) => f.added === void 0)) return "a binary file";
243
- if (files.some((f) => MANIFEST.test(f.path) && !PACKAGE_JSON.test(f.path))) {
244
- return "dependencies changed";
245
- }
246
- const tests = code.filter((f) => TEST_PATH.test(f.path));
247
- if (tests.length === 0) return "no test change";
248
- if (tests.length === code.length) return "only tests changed";
249
- return void 0;
250
- }
251
- function dependencyChange(diff) {
252
- for (const line of diff.split("\n")) {
253
- if (!/^[+-]/.test(line) || /^(\+\+\+|---)/.test(line)) continue;
254
- if (/[dD]ependencies"/.test(line)) return true;
255
- const entry = /^[+-]\s*"([^"]+)":\s*"[~^<>=]*\d/.exec(line);
256
- if (entry !== null && entry[1] !== "version") return true;
257
- }
258
- return false;
259
- }
260
- function scopedTestCommand(command, files) {
261
- const list = files.map(shellWord).join(" ");
262
- if (command.includes("{files}")) return command.replaceAll("{files}", list);
263
- if (files.length === 0) return command;
264
- const c = command.trim();
265
- if (/^npm (run )?test$/.test(c)) return `${c} -- ${list}`;
266
- if (/^(pnpm|yarn)( run)? test$/.test(c) || /^node --test$/.test(c) || /^(npx |pnpm exec )?(vitest|jest)( run)?$/.test(c) || /-m pytest( -q)?$|^pytest( -q)?$/.test(c)) {
267
- return `${c} ${list}`;
268
- }
269
- return c;
270
- }
271
- function repoPrompt(commit, tests) {
272
- return [
273
- commit.subject.trim(),
274
- ...commit.body.trim() === "" ? [] : ["", commit.body.trim()],
275
- "",
276
- `The tests for this change are already in the project: ${tests.join(", ")}. Make the change so that they pass. Do not change these test files.`
277
- ].join("\n");
278
- }
279
- async function recentCommits(executor, root, options = {}) {
280
- const log = await git(executor, root, [
281
- "log",
282
- "--no-merges",
283
- "--format=%H%x00%s%x00%b%x1e",
284
- `-n${options.commits ?? DEFAULT_COMMITS}`,
285
- ...options.since === void 0 ? [] : [`--since=${options.since}`],
286
- "HEAD"
287
- ]);
288
- const out = [];
289
- for (const entry of log.stdout.split("")) {
290
- const [sha = "", subject = "", body = ""] = entry.replace(/^\n/, "").split("\0");
291
- if (!/^[0-9a-f]{40,64}$/.test(sha)) continue;
292
- const stat = await git(executor, root, ["show", "--no-renames", "--numstat", "--format=", sha]);
293
- const files = stat.stdout.split("\n").map((line) => /^(\d+|-)\t(\d+|-)\t(.+)$/.exec(line)).filter((m) => m !== null).map(
294
- (m) => m[1] === "-" ? { path: m[3] } : { path: m[3], added: Number(m[1]), removed: Number(m[2]) }
295
- );
296
- out.push({ sha, subject, body, files });
297
- }
298
- return out;
299
- }
300
- async function taskWorktree(executor, root, commit) {
301
- const dir = realpathSync(mkdtempSync(join3(tmpdir2(), "garuda-repo-task-")));
302
- await git(executor, root, ["worktree", "add", "--detach", "--quiet", dir, commit]);
303
- for (const name of LINK_CANDIDATES) {
304
- try {
305
- await symlink(join3(root, name), join3(dir, name), "dir");
306
- } catch {
307
- }
308
- }
309
- return dir;
310
- }
311
- async function removeTaskWorktree(executor, root, dir) {
312
- await git(executor, root, ["worktree", "remove", "--force", dir], { check: false });
313
- await rm2(dir, { recursive: true, force: true });
314
- await git(executor, root, ["worktree", "prune"], { check: false });
315
- }
316
- async function applyTests(dir, tests) {
317
- for (const t of tests) {
318
- const file = join3(dir, t.path);
319
- if (t.content === null) await rm2(file, { force: true });
320
- else {
321
- await mkdir(dirname2(file), { recursive: true });
322
- await writeFile2(file, t.content);
323
- }
324
- }
325
- }
326
- async function runTests(executor, dir, command) {
327
- const result = await executor.run(command, {
328
- root: dir,
329
- sandbox: false,
330
- writePaths: [dir],
331
- denyWritePaths: [],
332
- denyReadPaths: [],
333
- network: false,
334
- envAllowlist: [...DEFAULT_ENV_ALLOWLIST, ...TOOLCHAIN_ENV],
335
- timeoutMs: BUILD_TEST_TIMEOUT_MS,
336
- maxOutputBytes: 2e4
337
- });
338
- const output = `${result.stdout.text}${result.stderr.text}`;
339
- return {
340
- ok: result.exitCode === 0 && !result.timedOut,
341
- tail: result.timedOut ? "(stopped: too long)" : tail(output, 15)
342
- };
343
- }
344
- async function buildRepoSuite(executor, root, options) {
345
- const say = options.onProgress ?? (() => {
346
- });
347
- const head = (await git(executor, root, ["rev-parse", "HEAD"])).stdout.trim();
348
- const commits = await recentCommits(executor, root, {
349
- ...options.commits === void 0 ? {} : { commits: options.commits },
350
- ...options.since === void 0 ? {} : { since: options.since }
351
- });
352
- const skipped = {};
353
- const skip = (why) => {
354
- skipped[why] = (skipped[why] ?? 0) + 1;
355
- };
356
- const tasks = [];
357
- let checked = 0;
358
- let failure;
359
- const max = options.maxTasks ?? DEFAULT_MAX_TASKS;
360
- for (const commit of commits) {
361
- if (tasks.length >= max) break;
362
- const why = skipReason(commit);
363
- if (why !== void 0) {
364
- skip(why);
365
- continue;
366
- }
367
- const parent = await git(
368
- executor,
369
- root,
370
- ["rev-parse", "--verify", "--quiet", `${commit.sha}^`],
371
- {
372
- check: false
373
- }
374
- );
375
- if (parent.exitCode !== 0) {
376
- skip("the first commit (no parent)");
377
- continue;
378
- }
379
- if (commit.files.some((f) => PACKAGE_JSON.test(f.path))) {
380
- const diff = await git(
381
- executor,
382
- root,
383
- ["show", "--format=", commit.sha, "--", "package.json"],
384
- {
385
- check: false
386
- }
387
- );
388
- if (dependencyChange(diff.stdout)) {
389
- skip("dependencies changed");
390
- continue;
391
- }
392
- }
393
- const base2 = parent.stdout.trim();
394
- const testPaths = commit.files.filter((f) => TEST_PATH.test(f.path) && !DOC_PATH.test(f.path)).map((f) => f.path);
395
- const tests = [];
396
- for (const path of testPaths) {
397
- const shown = await git(executor, root, ["show", `${commit.sha}:${path}`], { check: false });
398
- tests.push({ path, content: shown.exitCode === 0 ? shown.stdout : null });
399
- }
400
- const runnable = tests.filter((t) => t.content !== null).map((t) => t.path);
401
- if (runnable.length === 0) {
402
- skip("only deletes tests");
403
- continue;
404
- }
405
- const check = scopedTestCommand(options.testCommand, runnable);
406
- checked++;
407
- say(`checking ${commit.sha.slice(0, 7)} ${commit.subject}`);
408
- const dir = await taskWorktree(executor, root, base2);
409
- try {
410
- await applyTests(dir, tests);
411
- if ((await runTests(executor, dir, check)).ok) {
412
- skip("the tests already pass at the parent");
413
- continue;
414
- }
415
- await git(executor, dir, ["checkout", "--quiet", "--", "."], { check: false });
416
- await git(executor, dir, cleanArgs(), { check: false });
417
- await git(executor, dir, ["checkout", "--quiet", "--detach", commit.sha]);
418
- const atCommit = await runTests(executor, dir, check);
419
- if (!atCommit.ok) {
420
- skip("the tests fail at the commit");
421
- failure ??= { sha: commit.sha, command: check, tail: atCommit.tail };
422
- continue;
423
- }
424
- } finally {
425
- await removeTaskWorktree(executor, root, dir);
426
- }
427
- tasks.push({
428
- id: `repo-${commit.sha.slice(0, 7)}`,
429
- sha: commit.sha,
430
- base: base2,
431
- subject: commit.subject,
432
- prompt: repoPrompt(commit, testPaths),
433
- tests,
434
- check
435
- });
436
- say(`kept ${commit.sha.slice(0, 7)} (${tasks.length}/${max})`);
437
- }
438
- return {
439
- suite: {
440
- version: 1,
441
- root,
442
- head,
443
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
444
- testCommand: options.testCommand,
445
- tasks
446
- },
447
- checked,
448
- skipped,
449
- ...failure === void 0 ? {} : { failure }
450
- };
451
- }
452
- async function saveRepoSuite(suite) {
453
- const file = join3(suite.root, REPO_SUITE_FILE);
454
- await mkdir(dirname2(file), { recursive: true });
455
- await writeFile2(file, `${JSON.stringify(suite, null, 2)}
456
- `, { mode: 384 });
457
- return file;
458
- }
459
- async function loadRepoSuite(root) {
460
- let text;
461
- try {
462
- text = await readFile(join3(root, REPO_SUITE_FILE), "utf8");
463
- } catch {
464
- return void 0;
465
- }
466
- const parsed = suiteSchema.safeParse(JSON.parse(text));
467
- if (!parsed.success) throw new Error(`${REPO_SUITE_FILE}: ${z.prettifyError(parsed.error)}`);
468
- return parsed.data;
469
- }
470
- function repoEvalTasks(suite) {
471
- return suite.tasks.map((t) => ({
472
- id: t.id,
473
- title: t.subject,
474
- prompt: t.prompt,
475
- files: {},
476
- check: t.check ?? suite.testCommand,
477
- protect: t.tests.filter((f) => f.content !== null).map((f) => f.path),
478
- solution: {},
479
- repo: { root: suite.root, base: t.base, sha: t.sha, tests: t.tests }
480
- }));
481
- }
482
-
483
- // src/evals/runner.ts
484
- import { constants as fsConstants, mkdirSync as mkdirSync2, realpathSync as realpathSync2 } from "fs";
485
- import { copyFile, mkdtemp as mkdtemp3, readFile as readFile3, rm as rm4, writeFile as writeFile4 } from "fs/promises";
486
- import { tmpdir as tmpdir4 } from "os";
487
- import { join as join6 } from "path";
488
-
489
- // src/evals/agents/claudeCode.ts
490
- import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile3 } from "fs/promises";
491
- import { tmpdir as tmpdir3 } from "os";
492
- import { join as join4 } from "path";
493
- var MAX_OUTPUT_BYTES = 5e6;
494
- function claudeCommand(agent, prompt, maxTurns) {
495
- return [
496
- quote(agent.command),
497
- "-p",
498
- quote(prompt),
499
- "--output-format",
500
- "json",
501
- "--model",
502
- quote(agent.model),
503
- "--max-turns",
504
- String(maxTurns),
505
- "--permission-mode",
506
- "bypassPermissions"
507
- ].join(" ");
508
- }
509
- function parseClaudeResult(stdout) {
510
- const line = stdout.trim().split("\n").reverse().find((l) => l.trim().startsWith("{"));
511
- let data;
512
- try {
513
- data = JSON.parse(line ?? "");
514
- } catch {
515
- return {
516
- stopReason: "error",
517
- steps: 0,
518
- tokens: 0,
519
- cacheReadTokens: 0,
520
- costUsd: void 0,
521
- reason: `Claude Code gave no JSON result: ${stdout.trim().slice(0, 300) || "no output"}`
522
- };
523
- }
524
- const usage = data.usage ?? {};
525
- const n = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
526
- const cacheRead = n(usage.cache_read_input_tokens);
527
- const tokens = n(usage.input_tokens) + n(usage.output_tokens) + cacheRead + n(usage.cache_creation_input_tokens);
528
- const costUsd = typeof data.total_cost_usd === "number" ? data.total_cost_usd : void 0;
529
- const steps = n(data.num_turns);
530
- const subtype = typeof data.subtype === "string" ? data.subtype : "";
531
- const base2 = { steps, tokens, cacheReadTokens: cacheRead, costUsd };
532
- if (subtype === "error_max_turns") return { ...base2, stopReason: "max_steps" };
533
- if (subtype === "success" && data.is_error !== true) return { ...base2, stopReason: "done" };
534
- const text = typeof data.result === "string" ? data.result : subtype || "unknown error";
535
- return { ...base2, stopReason: "error", reason: `Claude Code failed: ${text.slice(0, 300)}` };
536
- }
537
- async function runClaudeCode(executor, policy, agent, prompt, maxTurns, signal) {
538
- const config = await mkdtemp2(join4(tmpdir3(), "garuda-claude-config-"));
539
- try {
540
- await writeFile3(
541
- join4(config, ".claude.json"),
542
- `${JSON.stringify({ hasCompletedOnboarding: true })}
543
- `
544
- );
545
- const result = await executor.run(
546
- claudeCommand(agent, prompt, maxTurns),
547
- { ...policy, maxOutputBytes: MAX_OUTPUT_BYTES },
548
- {
549
- signal,
550
- env: {
551
- ...agent.env,
552
- CLAUDE_CONFIG_DIR: config,
553
- CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
554
- DISABLE_AUTOUPDATER: "1"
555
- }
556
- }
557
- );
558
- const outcome = result.timedOut || result.aborted ? {
559
- stopReason: "timeout",
560
- steps: 0,
561
- tokens: 0,
562
- cacheReadTokens: 0,
563
- costUsd: void 0,
564
- reason: "Claude Code took longer than the task's time limit."
565
- } : parseClaudeResult(result.stdout.text);
566
- if (outcome.stopReason === "error" && result.stderr.text.trim() !== "" && outcome.reason !== void 0) {
567
- outcome.reason += `
568
- ${result.stderr.text.trim().split("\n").slice(-3).join("\n")}`;
569
- }
570
- return { result, outcome };
571
- } finally {
572
- await rm3(config, { recursive: true, force: true });
573
- }
574
- }
575
- function quote(text) {
576
- return `'${text.replace(/'/g, "'\\''")}'`;
577
- }
578
-
579
- // src/evals/changes.ts
580
- import { createHash } from "crypto";
581
- import { lstat, readdir, readFile as readFile2, readlink } from "fs/promises";
582
- import { join as join5 } from "path";
583
- var IGNORED_DIRS = /* @__PURE__ */ new Set([
584
- ".git",
585
- ".garuda",
586
- // Claude Code's own project folder (the T11b baseline), as .garuda is Garuda's.
587
- ".claude",
588
- "node_modules",
589
- "target",
590
- "build",
591
- "dist",
592
- "__pycache__",
593
- ".pytest_cache"
594
- ]);
595
- var IGNORED_FILE = /\.(class|pyc)$/;
596
- var MAX_TRACKED_FILES = 5e4;
597
- async function treeState(root) {
598
- const out = /* @__PURE__ */ new Map();
599
- const walk = async (dir, prefix) => {
600
- let names;
601
- try {
602
- names = await readdir(dir);
603
- } catch {
604
- return;
605
- }
606
- for (const name of names.sort()) {
607
- if (out.size >= MAX_TRACKED_FILES) return;
608
- const path = prefix === "" ? name : `${prefix}/${name}`;
609
- const full = join5(dir, name);
610
- const info = await lstat(full).catch(() => void 0);
611
- if (info === void 0) continue;
612
- if (info.isDirectory()) {
613
- if (!IGNORED_DIRS.has(name)) await walk(full, path);
614
- } else if (info.isSymbolicLink()) {
615
- out.set(path, `link:${await readlink(full).catch(() => "")}`);
616
- } else if (info.isFile() && !IGNORED_FILE.test(name)) {
617
- const hash = createHash("sha256");
618
- hash.update(await readFile2(full).catch(() => Buffer.alloc(0)));
619
- out.set(path, hash.digest("hex"));
620
- }
621
- }
622
- };
623
- await walk(root, "");
624
- return out;
625
- }
626
- function changedPaths(before, after) {
627
- const out = /* @__PURE__ */ new Set();
628
- for (const [path, hash] of after) if (before.get(path) !== hash) out.add(path);
629
- for (const path of before.keys()) if (!after.has(path)) out.add(path);
630
- return [...out].sort();
631
- }
632
- function unexpectedPaths(changed, expected, allowChanges = []) {
633
- const known = new Set(expected);
634
- return changed.filter(
635
- (path) => !known.has(path) && !allowChanges.some((glob) => pathMatches(glob, path, false))
636
- );
637
- }
638
-
639
- // src/evals/runner.ts
640
- var EVAL_DENY_RULES = [
641
- "bash(rm -rf*)",
642
- "bash(sudo*)",
643
- "bash(git push*)",
644
- "bash(curl*)",
645
- "bash(wget*)"
646
- ];
647
- var REPO_CHECK_TIMEOUT_MS = 5 * 6e4;
648
- var EVAL_TASK_TIMEOUT_MS = 10 * 6e4;
649
- var MCP_PREPARE_TIMEOUT_MS = 12e4;
650
- async function runEvalTask(task4, options) {
651
- const started = Date.now();
652
- const host = new HostExecutor();
653
- let root;
654
- if (task4.repo === void 0) {
655
- root = realpathSync2(await mkdtemp3(join6(tmpdir4(), `garuda-eval-${task4.id}-`)));
656
- await writeFiles(root, task4.files);
657
- } else {
658
- root = await taskWorktree(host, task4.repo.root, task4.repo.base);
659
- await applyTests(root, task4.repo.tests);
660
- }
661
- if (options.format !== void 0) await formatProject(root, options.format.biome);
662
- const protect = task4.protect ?? Object.keys(task4.files).filter(isProtectedPath);
663
- const before = await snapshot(root, protect);
664
- const settings2 = parseSettings({
665
- // With an allowlist, a host outside it is denied: nobody answers questions in an eval.
666
- permissions: {
667
- deny: options.network === void 0 ? EVAL_DENY_RULES : [...EVAL_DENY_RULES, "network"]
668
- },
669
- ...options.network === void 0 ? {} : { network: { allow: options.network } },
670
- // Evals must not depend on the internet.
671
- web: { enabled: false },
672
- ...options.executor === void 0 ? {} : { executor: options.executor },
673
- ...options.codeIndex === void 0 ? {} : { codeIndex: options.codeIndex },
674
- ...options.maxSteps === void 0 ? {} : { limits: { maxSteps: options.maxSteps } },
675
- ...options.subagents === void 0 ? {} : { subagents: { enabled: options.subagents } },
676
- ...options.todo === void 0 ? {} : { todo: { enabled: options.todo } },
677
- ...options.format === void 0 ? {} : {
678
- formatters: {
679
- enabled: options.format.on,
680
- commands: {
681
- biome: {
682
- extensions: ["js", "jsx", "mjs", "cjs", "ts", "tsx", "json"],
683
- command: [options.format.biome, "format", "--write", "$FILE"]
684
- }
685
- }
686
- }
687
- },
688
- ...options.keepThinking === void 0 ? {} : { thinking: { keepBlocks: options.keepThinking } }
689
- });
690
- const store = new FileSessionStore(root);
691
- let mcpCalls = 0;
692
- const tools = [];
693
- const createRuntime = (prepare2) => Runtime.create({
694
- root,
695
- modelId: options.modelId,
696
- model: async () => options.model(),
697
- ...options.modelInfo === void 0 ? {} : { modelInfo: options.modelInfo },
698
- ...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },
699
- ...options.subagentModel === void 0 ? {} : { subagentModel: options.subagentModel },
700
- approver: new AutoApprover("once"),
701
- store,
702
- settings: settings2,
703
- // The user's own MCP servers must not change eval results; `--mcp` allows one by name.
704
- mcp: options.mcp === void 0 || prepare2 ? false : { home: options.mcp.home, only: options.mcp.server },
705
- hooks: false,
706
- ...options.addendum === void 0 ? {} : { addendum: options.addendum },
707
- ...options.policy === void 0 ? {} : { policy: options.policy },
708
- commands: false,
709
- // The list comes from the eval command line: the user typed it.
710
- ...options.network === void 0 ? {} : { network: { approved: true } },
711
- ...options.lsp === void 0 ? {} : { lsp: { enabled: options.lsp } },
712
- onEvent: (event) => {
713
- if (event.type === "tool_call") {
714
- tools.push(event.call.name);
715
- if (event.call.name.startsWith("mcp__")) mcpCalls++;
716
- }
717
- options.onEvent?.(task4.id, event);
718
- }
719
- });
720
- let prepareFailure;
721
- const prepare = options.mcp?.prepare;
722
- if (prepare !== void 0) {
723
- const prep = await createRuntime(true);
724
- try {
725
- const prepared = await runCheck(
726
- root,
727
- prepare,
728
- MCP_PREPARE_TIMEOUT_MS,
729
- prep.executor.isolation === "none" ? void 0 : { executor: prep.executor, policy: prep.execPolicy(MCP_PREPARE_TIMEOUT_MS) }
730
- );
731
- if (!prepared.ok) prepareFailure = `${MCP_PREPARE_FAILED}
732
- ${prepared.output}`;
733
- } finally {
734
- await prep.close();
735
- prep.executor.shutdown();
736
- }
737
- }
738
- const runtime = await createRuntime(false);
739
- const result = {
740
- id: task4.id,
741
- title: task4.title,
742
- passed: false,
743
- stopReason: "error",
744
- steps: 0,
745
- tokens: 0,
746
- costUsd: void 0,
747
- durationMs: 0
748
- };
749
- if (prepareFailure !== void 0) result.reason = prepareFailure;
750
- const start = await treeState(root);
751
- const limitMs = options.taskTimeoutMs ?? EVAL_TASK_TIMEOUT_MS;
752
- const timeout = AbortSignal.timeout(limitMs);
753
- try {
754
- if (result.reason !== void 0) {
755
- } else if (options.agent !== void 0) {
756
- await runtime.prepareCommands(timeout);
757
- const { result: exec, outcome } = await runClaudeCode(
758
- runtime.executor,
759
- runtime.execPolicy(limitMs),
760
- options.agent,
761
- task4.prompt,
762
- options.maxSteps ?? DEFAULT_MAX_STEPS,
763
- timeout
764
- );
765
- result.stopReason = outcome.stopReason;
766
- result.steps = outcome.steps;
767
- result.tokens = outcome.tokens;
768
- result.cacheReadTokens = outcome.cacheReadTokens;
769
- result.costUsd = outcome.costUsd;
770
- if (outcome.reason !== void 0) result.reason = outcome.reason;
771
- if (options.outDir !== void 0) {
772
- mkdirSync2(options.outDir, { recursive: true });
773
- result.sessionFile = await saveUnique(
774
- options.outDir,
775
- task4.id,
776
- ".claude.json",
777
- (path) => writeFile4(path, exec.stdout.text, { flag: "wx" })
778
- );
779
- }
780
- } else {
781
- const run = await runtime.runTurn(task4.prompt, timeout);
782
- result.stopReason = run.stopReason;
783
- result.steps = run.steps;
784
- }
785
- } catch (error) {
786
- runtime.recordStop("error");
787
- if (timeout.aborted) {
788
- result.stopReason = "timeout";
789
- result.reason = `The task took longer than ${limitMs / 6e4} minutes.`;
790
- } else {
791
- result.reason = `The run failed: ${error.message}`;
792
- }
793
- } finally {
794
- if (tools.length > 0) result.tools = tools;
795
- if (options.mcp !== void 0) {
796
- result.mcpCalls = mcpCalls;
797
- const status = runtime.mcpStatus().find((m) => m.name === options.mcp?.server);
798
- if (result.reason === void 0 && status !== void 0 && status.state === "failed") {
799
- result.stopReason = "error";
800
- result.reason = `${MCP_NOT_STARTED} "${options.mcp.server}": ${status.message ?? "no reason given"}`;
801
- }
802
- }
803
- await runtime.close();
804
- runtime.executor.shutdown();
805
- }
806
- const session = runtime.session;
807
- if (session !== void 0 && options.agent === void 0) {
808
- result.tokens = totalTokens(session.usage);
809
- if (session.unreportedTokens > 0) result.unreportedTokens = session.unreportedTokens;
810
- result.costUsd = session.costUsd;
811
- if (isCostIncomplete(session)) result.costIncomplete = true;
812
- result.cacheReadTokens = session.usage.cacheReadTokens;
813
- if (options.outDir !== void 0) {
814
- mkdirSync2(options.outDir, { recursive: true });
815
- const from = store.path(session.id);
816
- result.sessionFile = await saveUnique(
817
- options.outDir,
818
- task4.id,
819
- ".jsonl",
820
- (path) => copyFile(from, path, fsConstants.COPYFILE_EXCL)
821
- );
822
- }
823
- }
824
- result.changed = changedPaths(start, await treeState(root));
825
- const expected = await expectedFiles(task4, host);
826
- if (expected !== void 0) {
827
- result.unexpected = unexpectedPaths(result.changed, expected, task4.allowChanges);
828
- }
829
- if (result.reason === void 0) {
830
- const changed = await changedFiles(root, before);
831
- const checkMs = task4.repo === void 0 ? 12e4 : REPO_CHECK_TIMEOUT_MS;
832
- const check = await runCheck(
833
- root,
834
- task4.check,
835
- checkMs,
836
- runtime.executor.isolation === "none" ? void 0 : { executor: runtime.executor, policy: runtime.execPolicy(checkMs) }
837
- );
838
- if (changed.length > 0)
839
- result.reason = `The agent changed protected files: ${changed.join(", ")}.`;
840
- else if (!check.ok) result.reason = `The check failed:
841
- ${check.output}`;
842
- else result.passed = true;
843
- }
844
- result.durationMs = Date.now() - started;
845
- if (!options.keep) {
846
- if (task4.repo === void 0) await rm4(root, { recursive: true, force: true });
847
- else await removeTaskWorktree(host, task4.repo.root, root);
848
- }
849
- return result;
850
- }
851
- async function expectedFiles(task4, host) {
852
- if (task4.repo === void 0) return Object.keys(task4.solution);
853
- if (task4.repo.sha === void 0) return void 0;
854
- const r = await git(
855
- host,
856
- task4.repo.root,
857
- ["diff", "--name-only", task4.repo.base, task4.repo.sha],
858
- {
859
- check: false
860
- }
861
- );
862
- if (r.exitCode !== 0) return void 0;
863
- const tests = new Set(task4.repo.tests.map((t) => t.path));
864
- return r.stdout.split("\n").map((line) => line.trim()).filter((line) => line !== "" && !tests.has(line));
865
- }
866
- function isAuthFailure(result) {
867
- if (!isErrorRun(result) || result.reason === void 0) return false;
868
- return /\b40[13]\b|authentication_error|permission_error|invalid x-api-key|invalid api key/i.test(
869
- result.reason
870
- );
871
- }
872
- function isConnectionFailure(result) {
873
- if (!isErrorRun(result) || result.reason === void 0) return false;
874
- return /ECONNREFUSED|ENOTFOUND|EAI_AGAIN|connection refused|self[- ]signed certificate|unable to get local issuer certificate|certificate has expired/i.test(
875
- result.reason
876
- );
877
- }
878
- async function saveUnique(dir, id, ext, write) {
879
- for (let n = 1; ; n++) {
880
- const path = join6(dir, `${id}${n === 1 ? "" : `-${n}`}${ext}`);
881
- try {
882
- await write(path);
883
- return path;
884
- } catch (error) {
885
- if (error.code !== "EEXIST") throw error;
886
- }
887
- }
888
- }
889
- var MCP_PREPARE_FAILED = "The MCP prepare command failed:";
890
- var MCP_NOT_STARTED = "The MCP server did not start:";
891
- function isMcpFailure(result) {
892
- return result.reason !== void 0 && (result.reason.startsWith(MCP_PREPARE_FAILED) || result.reason.startsWith(MCP_NOT_STARTED));
893
- }
894
- function isSetupFailure(result) {
895
- return isAuthFailure(result) || isConnectionFailure(result) || isMcpFailure(result);
896
- }
897
- async function runEvals(tasks, options, onResult, stop) {
898
- const results = new Array(tasks.length);
899
- const seen = /* @__PURE__ */ new Map();
900
- const attempts = tasks.map((t) => {
901
- const n = (seen.get(t.id) ?? 0) + 1;
902
- seen.set(t.id, n);
903
- return n;
904
- });
905
- let next = 0;
906
- let stopped = false;
907
- const worker = async () => {
908
- for (let i = next++; i < tasks.length && !stopped; i = next++) {
909
- const result = await runEvalTask(tasks[i], options);
910
- result.attempt = attempts[i];
911
- results[i] = result;
912
- onResult?.(result);
913
- if (stop?.(result)) stopped = true;
914
- }
915
- };
916
- const width = Math.max(1, Math.min(options.parallel ?? 1, tasks.length));
917
- await Promise.all(Array.from({ length: width }, worker));
918
- return results.filter((r) => r !== void 0);
919
- }
920
- async function runCheck(root, command, timeoutMs = 12e4, sandboxed) {
921
- const envAllowlist = [...DEFAULT_ENV_ALLOWLIST, ...TOOLCHAIN_ENV];
922
- const r = sandboxed === void 0 ? await new HostExecutor().run(command, {
923
- root,
924
- sandbox: false,
925
- writePaths: [root],
926
- denyWritePaths: [],
927
- denyReadPaths: [],
928
- network: false,
929
- envAllowlist,
930
- timeoutMs,
931
- maxOutputBytes: 4e3
932
- }) : await sandboxed.executor.run(command, {
933
- ...sandboxed.policy,
934
- envAllowlist: [.../* @__PURE__ */ new Set([...sandboxed.policy.envAllowlist, ...TOOLCHAIN_ENV])],
935
- timeoutMs,
936
- maxOutputBytes: 4e3
937
- });
938
- const text = `${r.stdout.text}${r.stderr.text}`.trim();
939
- const output = text !== "" ? text : `(no output; ${r.timedOut ? "timed out" : `exit code ${r.exitCode}`})`;
940
- return { ok: r.exitCode === 0 && !r.timedOut, output };
941
- }
942
- async function snapshot(root, paths) {
943
- const out = /* @__PURE__ */ new Map();
944
- for (const path of paths) out.set(path, await readFile3(join6(root, path), "utf8").catch(() => ""));
945
- return out;
946
- }
947
- async function changedFiles(root, before) {
948
- const after = await snapshot(root, [...before.keys()]);
949
- return [...before.keys()].filter((path) => before.get(path) !== after.get(path));
950
- }
951
- function isErrorRun(result) {
952
- return result.stopReason === "error";
953
- }
954
- function summarize(results) {
955
- const attempted = results.length;
956
- const errors = results.filter(isErrorRun).length;
957
- const scored = attempted - errors;
958
- const passed = results.filter((r) => r.passed).length;
959
- return {
960
- attempted,
961
- errors,
962
- scored,
963
- passed,
964
- ...scored === 0 ? {} : { scoredRate: passed / scored },
965
- ...attempted === 0 ? {} : { attemptedRate: passed / attempted }
966
- };
967
- }
968
- var percent = (rate) => rate === void 0 ? "\u2013" : `${Math.round(rate * 100)}%`;
969
- function formatReport(results, options = {}) {
970
- const width = idWidth(results);
971
- const rows = results.map(
972
- (r) => [
973
- r.passed ? "PASS" : isErrorRun(r) ? "ERR " : "FAIL",
974
- r.id.padEnd(width),
975
- `${String(r.steps).padStart(3)} steps`,
976
- (r.unreportedTokens ?? 0) > 0 ? `tok ? (${r.unreportedTokens} reserved)` : `${(r.tokens / 1e3).toFixed(1).padStart(7)}k tok`,
977
- r.costUsd === void 0 ? " cost ?" : `${r.costIncomplete === true ? "\u2265" : ""}$${r.costUsd.toFixed(4).padStart(7)}`,
978
- `${(r.durationMs / 1e3).toFixed(0).padStart(4)} s`,
979
- r.stopReason
980
- ].join(" ")
981
- );
982
- const summary = summarize(results);
983
- const known = `$${results.reduce((s, r) => s + (r.costUsd ?? 0), 0).toFixed(4)}`;
984
- const cost = !results.every((r) => r.costUsd !== void 0) ? "unknown" : results.some((r) => r.costIncomplete === true) ? `\u2265 ${known} (incomplete)` : known;
985
- const steps = results.reduce((s, r) => s + r.steps, 0);
986
- const counted = `${summary.passed}/${summary.scored} scored runs passed (${percent(summary.scoredRate)}) \xB7 ${summary.passed}/${summary.attempted} of all attempted runs (${percent(summary.attemptedRate)})` + (summary.errors > 0 ? ` \xB7 ${summary.errors} error run(s)` : "");
987
- const tokens = results.reduce((s, r) => s + r.tokens, 0);
988
- const cached = results.reduce((s, r) => s + (r.cacheReadTokens ?? 0), 0);
989
- const share = results.some((r) => (r.unreportedTokens ?? 0) > 0) ? " \xB7 cache share unknown" : tokens === 0 ? "" : ` \xB7 ${Math.round(cached / tokens * 100)}% of tokens from the cache`;
990
- const lines4 = [
991
- ...rows,
992
- "",
993
- `${counted} \xB7 ${steps} steps \xB7 cost ${cost}${share}`,
994
- ...evidenceLines(results, options.seed ?? DEFAULT_SEED)
995
- ];
996
- const ids = [...new Set(results.map((r) => r.id))];
997
- if (ids.length < results.length) lines4.push("", "Mean per task:", ...meanRows(results, ids));
998
- return lines4.join("\n");
999
- }
1000
- function evidenceLines(results, seed) {
1001
- const out = [];
1002
- if (results.length > 0 && results.every(isErrorRun)) {
1003
- return [
1004
- "No scored run: every run failed with an error (the reasons are above), so this run gives no evidence about the agent."
1005
- ];
1006
- }
1007
- const interval = passInterval(results, { seed });
1008
- if (interval !== void 0 && interval.tasks >= 2) {
1009
- out.push(
1010
- `Pass rate over all attempts: ${percent(interval.rate)} (95% interval ${percent(interval.low)}\u2013${percent(interval.high)}; cluster bootstrap over ${interval.tasks} tasks, ${interval.draws} draws, seed ${interval.seed})`
1011
- );
1012
- if (interval.low === interval.high) {
1013
- out.push(
1014
- " Every draw gave the same rate, so the interval shows no uncertainty: more tasks are needed to measure it."
1015
- );
1016
- }
1017
- if (interval.tasks < 10) out.push(` ${roughNote(interval.tasks)}`);
1018
- }
1019
- const c = consistency(results);
1020
- if (c.repeated > 0) {
1021
- const none = c.nonePassed.length === 0 ? "" : ` (${c.nonePassed.join(", ")})`;
1022
- const errors = c.onlyErrors.length === 0 ? "" : `; ${c.onlyErrors.length} had only error runs (${c.onlyErrors.join(", ")})`;
1023
- out.push(
1024
- `Consistency: ${c.allPassed.length} of ${c.repeated} repeated tasks passed every run; ${c.nonePassed.length} passed none${none}${errors}`
1025
- );
1026
- }
1027
- const s = spread(results);
1028
- if (s !== void 0) {
1029
- const k = (n) => `${(n / 1e3).toFixed(1)}k`;
1030
- const sec = (ms) => `${Math.round(ms / 1e3)} s`;
1031
- out.push(
1032
- `Spread (${s.runs} scored runs): steps median ${s.steps.median.toFixed(1)}, p95 ${s.steps.p95.toFixed(1)} \xB7 tokens median ${k(s.tokens.median)}, p95 ${k(s.tokens.p95)} \xB7 time median ${sec(s.durationMs.median)}, p95 ${sec(s.durationMs.p95)}`
1033
- );
1034
- }
1035
- const cost = costPerPass(results);
1036
- out.push(
1037
- cost.kind === "unknown" ? "Cost per accepted change: unknown (a run's cost is unknown)" : cost.kind === "none" ? "Cost per accepted change: no passes" : `Cost per accepted change: ${cost.minimum ? "\u2265 " : ""}$${cost.usd.toFixed(4)} (all attempts ${cost.minimum ? "\u2265 " : ""}$${cost.totalUsd.toFixed(4)} / ${cost.passes} pass${cost.passes === 1 ? "" : "es"})`
1038
- );
1039
- const u = unexpectedChanges(results);
1040
- if (u.measured > 0) {
1041
- out.push(
1042
- `Unexpected changes: ${u.runs} of ${u.measured} runs, ${u.files} file${u.files === 1 ? "" : "s"}`
1043
- );
1044
- const shown = results.filter((r) => (r.unexpected?.length ?? 0) > 0).slice(0, 5);
1045
- for (const r of shown) {
1046
- out.push(
1047
- ` ${r.id}${r.attempt === void 0 ? "" : ` (run ${r.attempt})`}: ${(r.unexpected ?? []).join(", ")}`
1048
- );
1049
- }
1050
- if (u.runs > shown.length) out.push(` \u2026 ${u.runs - shown.length} more in report.json`);
1051
- }
1052
- const mcp = mcpUse(results);
1053
- if (mcp !== void 0) out.push(`MCP tool calls: ${mcpUseText(mcp)}`);
1054
- return out;
1055
- }
1056
- function idWidth(results) {
1057
- return Math.max(18, ...results.map((r) => r.id.length));
1058
- }
1059
- function meanRows(results, ids) {
1060
- const width = idWidth(results);
1061
- return ids.map((id) => {
1062
- const all = results.filter((r) => r.id === id);
1063
- const runs = all.filter((r) => !isErrorRun(r));
1064
- const errors = all.length - runs.length;
1065
- const passesAll = all.filter((r) => r.passed).length;
1066
- const note = errors > 0 ? ` (${passesAll}/${all.length} of all attempts; ${errors} error run(s))` : "";
1067
- if (runs.length === 0) return `${"0/0".padEnd(4)} ${id.padEnd(width)}${note}`;
1068
- const mean = (f) => runs.reduce((s, r) => s + f(r), 0) / runs.length;
1069
- const passes = runs.filter((r) => r.passed).length;
1070
- return [
1071
- `${passes}/${runs.length}`.padEnd(4),
1072
- id.padEnd(width),
1073
- `${mean((r) => r.steps).toFixed(1).padStart(5)} steps`,
1074
- runs.some((r) => (r.unreportedTokens ?? 0) > 0) ? " tok ?" : `${(mean((r) => r.tokens) / 1e3).toFixed(1).padStart(7)}k tok`,
1075
- runs.every((r) => r.costUsd !== void 0) ? `${runs.some((r) => r.costIncomplete === true) ? "\u2265" : ""}$${mean((r) => r.costUsd ?? 0).toFixed(4).padStart(7)}` : " cost ?",
1076
- ...stepsSd(runs) === void 0 ? [] : [`sd ${stepsSd(runs).toFixed(1)} steps`]
1077
- ].join(" ") + note;
1078
- });
1079
- }
1080
- var EVAL_BIOME_CONFIG = {
1081
- formatter: { indentStyle: "space", indentWidth: 2, lineWidth: 100 },
1082
- linter: { enabled: false },
1083
- assist: { enabled: false }
1084
- };
1085
- async function formatProject(root, biome) {
1086
- await writeFile4(join6(root, "biome.json"), `${JSON.stringify(EVAL_BIOME_CONFIG, null, 2)}
1087
- `);
1088
- const result = await new HostExecutor().run(`${shellWord2(biome)} format --write .`, {
1089
- root,
1090
- sandbox: false,
1091
- writePaths: [root],
1092
- denyWritePaths: [],
1093
- denyReadPaths: [],
1094
- network: false,
1095
- envAllowlist: [...DEFAULT_ENV_ALLOWLIST],
1096
- timeoutMs: 6e4,
1097
- maxOutputBytes: 2e4
1098
- });
1099
- if (result.exitCode !== 0) {
1100
- throw new Error(
1101
- `Biome could not format the eval project: ${result.stderr.text.trim().split("\n")[0] ?? ""}`
1102
- );
1103
- }
1104
- }
1105
- function shellWord2(text) {
1106
- return /^[A-Za-z0-9_./:@=+-]+$/.test(text) ? text : `'${text.replace(/'/g, "'\\''")}'`;
1107
- }
3
+ MAVEN_CHECK,
4
+ MAVEN_POM,
5
+ PYPROJECT,
6
+ PYTEST_CHECK,
7
+ lines
8
+ } from "./chunk-A5DLAXB4.js";
1108
9
 
1109
10
  // src/evals/taskKit.ts
1110
11
  var NODE_PKG = lines("{", ' "type": "module",', ' "private": true', "}");
@@ -1120,17 +21,17 @@ ${body}GARUDA_HIDDEN
1120
21
  `;
1121
22
  function mutationCheck(file, testCommand, mutants) {
1122
23
  const each = mutants.map(
1123
- (m) => `rm -rf "$d/p" && cp -R . "$d/p" && sed -i.orig ${shellWord3(m)} "$d/p/${file}" && ! cmp -s "${file}" "$d/p/${file}" && (cd "$d/p" && ! ${testCommand} >/dev/null 2>&1)`
24
+ (m) => `rm -rf "$d/p" && cp -R . "$d/p" && sed -i.orig ${shellWord(m)} "$d/p/${file}" && ! cmp -s "${file}" "$d/p/${file}" && (cd "$d/p" && ! ${testCommand} >/dev/null 2>&1)`
1124
25
  ).join(" && ");
1125
26
  return `${testCommand} && d=$(mktemp -d) && ${each}`;
1126
27
  }
1127
- function shellWord3(text) {
28
+ function shellWord(text) {
1128
29
  return `'${text.replace(/'/g, "'\\''")}'`;
1129
30
  }
1130
31
  var hiddenMaven = (path, body) => `mkdir -p "$(dirname ${path})" && cat > ${path} <<'GARUDA_HIDDEN'
1131
32
  ${body}GARUDA_HIDDEN
1132
33
  ${MAVEN_CHECK}`;
1133
- var guard = (test2, message) => `{ ${test2} || { echo ${shellWord3(`check: ${message}`)}; false; }; } && `;
34
+ var guard = (test2, message) => `{ ${test2} || { echo ${shellWord(`check: ${message}`)}; false; }; } && `;
1134
35
 
1135
36
  // src/evals/heldOutTasks.ts
1136
37
  var priceCache = {
@@ -6349,24 +5250,9 @@ function requiredToolchains(tasks) {
6349
5250
  }
6350
5251
 
6351
5252
  export {
6352
- TOOLCHAINS,
6353
- checkToolchains,
6354
- prepareToolchain,
6355
- toolchainId,
6356
- DEFAULT_COMMITS,
6357
- buildRepoSuite,
6358
- saveRepoSuite,
6359
- loadRepoSuite,
6360
- repoEvalTasks,
6361
- isAuthFailure,
6362
- isMcpFailure,
6363
- isSetupFailure,
6364
- runEvals,
6365
- summarize,
6366
- formatReport,
6367
5253
  HELD_OUT_TASKS,
6368
5254
  EVAL_SUITES,
6369
5255
  chooseTasks,
6370
5256
  requiredToolchains
6371
5257
  };
6372
- //# sourceMappingURL=chunk-Q4P3W657.js.map
5258
+ //# sourceMappingURL=chunk-LWNMEGDF.js.map