agentv 4.37.0-next.1 → 4.38.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.
- package/dist/{artifact-writer-GFNKYREE.js → artifact-writer-MK5X5MSO.js} +4 -4
- package/dist/{chunk-P4LSNFZR.js → chunk-3G4BK6Z5.js} +21 -20
- package/dist/{chunk-P4LSNFZR.js.map → chunk-3G4BK6Z5.js.map} +1 -1
- package/dist/{chunk-N6E5XFOM.js → chunk-DKUAETXE.js} +3 -3
- package/dist/{chunk-M7AMFWBZ.js → chunk-EKMMIULD.js} +42 -37
- package/dist/chunk-EKMMIULD.js.map +1 -0
- package/dist/{chunk-OYI35QFW.js → chunk-NLTIK3LV.js} +32 -250
- package/dist/chunk-NLTIK3LV.js.map +1 -0
- package/dist/{chunk-RL4S2FBZ.js → chunk-VBHHZQS6.js} +902 -488
- package/dist/chunk-VBHHZQS6.js.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/dashboard/assets/index-BpnllKET.css +1 -0
- package/dist/dashboard/assets/index-Cm9SUopp.js +118 -0
- package/dist/dashboard/assets/{index-BDRYJsGF.js → index-SIl6NbIJ.js} +1 -1
- package/dist/dashboard/index.html +2 -2
- package/dist/{dist-OY3JSP6Z.js → dist-HVLBDG5F.js} +17 -13
- package/dist/index.js +5 -5
- package/dist/{interactive-CQELHITQ.js → interactive-QFAAM4SI.js} +5 -5
- package/dist/skills/agentv-eval-writer/SKILL.md +28 -36
- package/dist/skills/agentv-eval-writer/references/eval-schema.json +57 -210
- package/dist/{ts-eval-loader-RBTB2HG2-H5TRXZLO.js → ts-eval-loader-TJT6BGFF-DI7XNSO4.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-M7AMFWBZ.js.map +0 -1
- package/dist/chunk-OYI35QFW.js.map +0 -1
- package/dist/chunk-RL4S2FBZ.js.map +0 -1
- package/dist/dashboard/assets/index-9tV-u4HJ.css +0 -1
- package/dist/dashboard/assets/index-DuESU7zZ.js +0 -118
- /package/dist/{artifact-writer-GFNKYREE.js.map → artifact-writer-MK5X5MSO.js.map} +0 -0
- /package/dist/{chunk-N6E5XFOM.js.map → chunk-DKUAETXE.js.map} +0 -0
- /package/dist/{dist-OY3JSP6Z.js.map → dist-HVLBDG5F.js.map} +0 -0
- /package/dist/{interactive-CQELHITQ.js.map → interactive-QFAAM4SI.js.map} +0 -0
- /package/dist/{ts-eval-loader-RBTB2HG2-H5TRXZLO.js.map → ts-eval-loader-TJT6BGFF-DI7XNSO4.js.map} +0 -0
|
@@ -493,8 +493,8 @@ function getErrorMap() {
|
|
|
493
493
|
|
|
494
494
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
495
495
|
var makeIssue = (params) => {
|
|
496
|
-
const { data, path:
|
|
497
|
-
const fullPath = [...
|
|
496
|
+
const { data, path: path49, errorMaps, issueData } = params;
|
|
497
|
+
const fullPath = [...path49, ...issueData.path || []];
|
|
498
498
|
const fullIssue = {
|
|
499
499
|
...issueData,
|
|
500
500
|
path: fullPath
|
|
@@ -610,11 +610,11 @@ var errorUtil;
|
|
|
610
610
|
|
|
611
611
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
612
612
|
var ParseInputLazyPath = class {
|
|
613
|
-
constructor(parent, value,
|
|
613
|
+
constructor(parent, value, path49, key) {
|
|
614
614
|
this._cachedPath = [];
|
|
615
615
|
this.parent = parent;
|
|
616
616
|
this.data = value;
|
|
617
|
-
this._path =
|
|
617
|
+
this._path = path49;
|
|
618
618
|
this._key = key;
|
|
619
619
|
}
|
|
620
620
|
get path() {
|
|
@@ -4056,7 +4056,7 @@ var coerce = {
|
|
|
4056
4056
|
};
|
|
4057
4057
|
var NEVER = INVALID;
|
|
4058
4058
|
|
|
4059
|
-
// ../../packages/core/dist/chunk-
|
|
4059
|
+
// ../../packages/core/dist/chunk-M54RBDXI.js
|
|
4060
4060
|
import { parse } from "yaml";
|
|
4061
4061
|
import os from "node:os";
|
|
4062
4062
|
import path from "node:path";
|
|
@@ -6184,21 +6184,21 @@ async function expandFileReferences(tests, evalFileDir) {
|
|
|
6184
6184
|
return expanded;
|
|
6185
6185
|
}
|
|
6186
6186
|
|
|
6187
|
-
// ../../packages/core/dist/chunk-
|
|
6188
|
-
import
|
|
6187
|
+
// ../../packages/core/dist/chunk-RH5LAMMU.js
|
|
6188
|
+
import path48 from "node:path";
|
|
6189
6189
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
6190
|
-
import { existsSync as
|
|
6191
|
-
import
|
|
6190
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
6191
|
+
import path47 from "node:path";
|
|
6192
6192
|
import micromatch4 from "micromatch";
|
|
6193
6193
|
import { mkdir, readFile as readFile3, writeFile } from "node:fs/promises";
|
|
6194
6194
|
import path5 from "node:path";
|
|
6195
|
-
import { execFile as
|
|
6196
|
-
import { createHash as
|
|
6197
|
-
import { existsSync as
|
|
6198
|
-
import { copyFile as copyFile2, mkdir as
|
|
6199
|
-
import
|
|
6195
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
6196
|
+
import { createHash as createHash5, randomUUID as randomUUID10 } from "node:crypto";
|
|
6197
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
6198
|
+
import { copyFile as copyFile2, mkdir as mkdir17, readdir as readdir8, stat as stat9 } from "node:fs/promises";
|
|
6199
|
+
import path46 from "node:path";
|
|
6200
6200
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
6201
|
-
import { promisify as
|
|
6201
|
+
import { promisify as promisify6 } from "node:util";
|
|
6202
6202
|
import micromatch3 from "micromatch";
|
|
6203
6203
|
import { mkdtemp, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
6204
6204
|
import { tmpdir } from "node:os";
|
|
@@ -6916,10 +6916,10 @@ function assignProp(target, prop, value) {
|
|
|
6916
6916
|
configurable: true
|
|
6917
6917
|
});
|
|
6918
6918
|
}
|
|
6919
|
-
function getElementAtPath(obj,
|
|
6920
|
-
if (!
|
|
6919
|
+
function getElementAtPath(obj, path49) {
|
|
6920
|
+
if (!path49)
|
|
6921
6921
|
return obj;
|
|
6922
|
-
return
|
|
6922
|
+
return path49.reduce((acc, key) => acc?.[key], obj);
|
|
6923
6923
|
}
|
|
6924
6924
|
function promiseAllObject(promisesObj) {
|
|
6925
6925
|
const keys = Object.keys(promisesObj);
|
|
@@ -7239,11 +7239,11 @@ function aborted(x, startIndex = 0) {
|
|
|
7239
7239
|
}
|
|
7240
7240
|
return false;
|
|
7241
7241
|
}
|
|
7242
|
-
function prefixIssues(
|
|
7242
|
+
function prefixIssues(path49, issues) {
|
|
7243
7243
|
return issues.map((iss) => {
|
|
7244
7244
|
var _a;
|
|
7245
7245
|
(_a = iss).path ?? (_a.path = []);
|
|
7246
|
-
iss.path.unshift(
|
|
7246
|
+
iss.path.unshift(path49);
|
|
7247
7247
|
return iss;
|
|
7248
7248
|
});
|
|
7249
7249
|
}
|
|
@@ -7380,7 +7380,7 @@ function treeifyError(error40, _mapper) {
|
|
|
7380
7380
|
return issue2.message;
|
|
7381
7381
|
};
|
|
7382
7382
|
const result = { errors: [] };
|
|
7383
|
-
const processError = (error41,
|
|
7383
|
+
const processError = (error41, path49 = []) => {
|
|
7384
7384
|
var _a, _b;
|
|
7385
7385
|
for (const issue2 of error41.issues) {
|
|
7386
7386
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -7390,7 +7390,7 @@ function treeifyError(error40, _mapper) {
|
|
|
7390
7390
|
} else if (issue2.code === "invalid_element") {
|
|
7391
7391
|
processError({ issues: issue2.issues }, issue2.path);
|
|
7392
7392
|
} else {
|
|
7393
|
-
const fullpath = [...
|
|
7393
|
+
const fullpath = [...path49, ...issue2.path];
|
|
7394
7394
|
if (fullpath.length === 0) {
|
|
7395
7395
|
result.errors.push(mapper(issue2));
|
|
7396
7396
|
continue;
|
|
@@ -7420,9 +7420,9 @@ function treeifyError(error40, _mapper) {
|
|
|
7420
7420
|
processError(error40);
|
|
7421
7421
|
return result;
|
|
7422
7422
|
}
|
|
7423
|
-
function toDotPath(
|
|
7423
|
+
function toDotPath(path49) {
|
|
7424
7424
|
const segs = [];
|
|
7425
|
-
for (const seg of
|
|
7425
|
+
for (const seg of path49) {
|
|
7426
7426
|
if (typeof seg === "number")
|
|
7427
7427
|
segs.push(`[${seg}]`);
|
|
7428
7428
|
else if (typeof seg === "symbol")
|
|
@@ -18852,7 +18852,7 @@ var RequestError = class _RequestError extends Error {
|
|
|
18852
18852
|
}
|
|
18853
18853
|
};
|
|
18854
18854
|
|
|
18855
|
-
// ../../packages/core/dist/chunk-
|
|
18855
|
+
// ../../packages/core/dist/chunk-RH5LAMMU.js
|
|
18856
18856
|
import { exec as execCallback } from "node:child_process";
|
|
18857
18857
|
import { readdirSync, statSync } from "node:fs";
|
|
18858
18858
|
import { readFile as readFile32, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
@@ -18927,38 +18927,41 @@ import path33 from "node:path";
|
|
|
18927
18927
|
import fg3 from "fast-glob";
|
|
18928
18928
|
import { cp, mkdir as mkdir14, readdir as readdir5, rm as rm4, stat as stat6 } from "node:fs/promises";
|
|
18929
18929
|
import path34 from "node:path";
|
|
18930
|
-
import { execFile } from "node:child_process";
|
|
18931
18930
|
import { createHash as createHash3 } from "node:crypto";
|
|
18932
18931
|
import { existsSync as existsSync3 } from "node:fs";
|
|
18933
18932
|
import { cp as cp2, mkdir as mkdir15, readFile as readFile11, readdir as readdir6, rm as rm5, unlink, writeFile as writeFile9 } from "node:fs/promises";
|
|
18934
18933
|
import path35 from "node:path";
|
|
18934
|
+
import { execFile, spawn as spawn5 } from "node:child_process";
|
|
18935
|
+
import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
|
|
18936
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
18937
|
+
import { mkdir as mkdir16, rename, rm as rm6 } from "node:fs/promises";
|
|
18938
|
+
import path37 from "node:path";
|
|
18935
18939
|
import { promisify as promisify5 } from "node:util";
|
|
18936
|
-
import {
|
|
18937
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
18940
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync22, readdirSync as readdirSync3, statSync as statSync2, writeFileSync } from "node:fs";
|
|
18938
18941
|
import path36 from "node:path";
|
|
18939
|
-
import {
|
|
18942
|
+
import { stringify as stringifyYaml } from "yaml";
|
|
18940
18943
|
import { readdir as readdir7, stat as stat7 } from "node:fs/promises";
|
|
18941
|
-
import
|
|
18944
|
+
import path38 from "node:path";
|
|
18942
18945
|
import { readFile as readFile18, stat as stat8 } from "node:fs/promises";
|
|
18943
|
-
import
|
|
18946
|
+
import path45 from "node:path";
|
|
18944
18947
|
import micromatch2 from "micromatch";
|
|
18945
|
-
import { stringify as
|
|
18948
|
+
import { stringify as stringifyYaml2 } from "yaml";
|
|
18946
18949
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
18947
|
-
import
|
|
18950
|
+
import path39 from "node:path";
|
|
18948
18951
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
18949
|
-
import
|
|
18952
|
+
import path41 from "node:path";
|
|
18950
18953
|
import { constants as constants4 } from "node:fs";
|
|
18951
18954
|
import { access as access4 } from "node:fs/promises";
|
|
18952
|
-
import
|
|
18955
|
+
import path40 from "node:path";
|
|
18953
18956
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
18954
18957
|
import { readFile as readFile15 } from "node:fs/promises";
|
|
18955
|
-
import
|
|
18958
|
+
import path422 from "node:path";
|
|
18956
18959
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
18957
18960
|
import { readFile as readFile17 } from "node:fs/promises";
|
|
18958
|
-
import
|
|
18961
|
+
import path44 from "node:path";
|
|
18959
18962
|
import micromatch from "micromatch";
|
|
18960
18963
|
import { readFile as readFile16 } from "node:fs/promises";
|
|
18961
|
-
import
|
|
18964
|
+
import path43 from "node:path";
|
|
18962
18965
|
var DEFAULT_CACHE_PATH = ".agentv/cache";
|
|
18963
18966
|
var ResponseCache = class {
|
|
18964
18967
|
cachePath;
|
|
@@ -19489,14 +19492,14 @@ function toCamelCaseDeep(obj) {
|
|
|
19489
19492
|
}
|
|
19490
19493
|
return obj;
|
|
19491
19494
|
}
|
|
19492
|
-
function getRepoCheckoutRef(
|
|
19493
|
-
return
|
|
19495
|
+
function getRepoCheckoutRef(repo) {
|
|
19496
|
+
return repo?.commit ?? repo?.base_commit ?? "HEAD";
|
|
19494
19497
|
}
|
|
19495
19498
|
function getRepoCheckoutTargets(repos) {
|
|
19496
19499
|
if (!repos) return [];
|
|
19497
|
-
return repos.filter((repo) => repo.
|
|
19500
|
+
return repos.filter((repo) => repo.commit || repo.base_commit).map((repo) => ({
|
|
19498
19501
|
path: repo.path,
|
|
19499
|
-
ref: getRepoCheckoutRef(repo
|
|
19502
|
+
ref: getRepoCheckoutRef(repo)
|
|
19500
19503
|
}));
|
|
19501
19504
|
}
|
|
19502
19505
|
var FILE_BACKED_OUTPUT_THRESHOLD = 5e4;
|
|
@@ -22529,115 +22532,115 @@ var FieldAccuracyGrader = class {
|
|
|
22529
22532
|
* Evaluate a single field against the expected value.
|
|
22530
22533
|
*/
|
|
22531
22534
|
evaluateField(fieldConfig, candidateData, expectedData) {
|
|
22532
|
-
const { path:
|
|
22533
|
-
const candidateValue = resolvePath(candidateData,
|
|
22534
|
-
const expectedValue = resolvePath(expectedData,
|
|
22535
|
+
const { path: path49, match, required: required2 = true, weight = 1 } = fieldConfig;
|
|
22536
|
+
const candidateValue = resolvePath(candidateData, path49);
|
|
22537
|
+
const expectedValue = resolvePath(expectedData, path49);
|
|
22535
22538
|
if (expectedValue === void 0) {
|
|
22536
22539
|
return {
|
|
22537
|
-
path:
|
|
22540
|
+
path: path49,
|
|
22538
22541
|
score: 1,
|
|
22539
22542
|
// No expected value means no comparison needed
|
|
22540
22543
|
weight,
|
|
22541
22544
|
hit: true,
|
|
22542
|
-
message: `${
|
|
22545
|
+
message: `${path49}: no expected value`
|
|
22543
22546
|
};
|
|
22544
22547
|
}
|
|
22545
22548
|
if (candidateValue === void 0) {
|
|
22546
22549
|
if (required2) {
|
|
22547
22550
|
return {
|
|
22548
|
-
path:
|
|
22551
|
+
path: path49,
|
|
22549
22552
|
score: 0,
|
|
22550
22553
|
weight,
|
|
22551
22554
|
hit: false,
|
|
22552
|
-
message: `${
|
|
22555
|
+
message: `${path49} (required, missing)`
|
|
22553
22556
|
};
|
|
22554
22557
|
}
|
|
22555
22558
|
return {
|
|
22556
|
-
path:
|
|
22559
|
+
path: path49,
|
|
22557
22560
|
score: 1,
|
|
22558
22561
|
// Don't penalize missing optional fields
|
|
22559
22562
|
weight: 0,
|
|
22560
22563
|
// Zero weight means it won't affect the score
|
|
22561
22564
|
hit: true,
|
|
22562
|
-
message: `${
|
|
22565
|
+
message: `${path49}: optional field missing`
|
|
22563
22566
|
};
|
|
22564
22567
|
}
|
|
22565
22568
|
switch (match) {
|
|
22566
22569
|
case "exact":
|
|
22567
|
-
return this.compareExact(
|
|
22570
|
+
return this.compareExact(path49, candidateValue, expectedValue, weight);
|
|
22568
22571
|
case "numeric_tolerance":
|
|
22569
22572
|
return this.compareNumericTolerance(
|
|
22570
|
-
|
|
22573
|
+
path49,
|
|
22571
22574
|
candidateValue,
|
|
22572
22575
|
expectedValue,
|
|
22573
22576
|
fieldConfig,
|
|
22574
22577
|
weight
|
|
22575
22578
|
);
|
|
22576
22579
|
case "date":
|
|
22577
|
-
return this.compareDate(
|
|
22580
|
+
return this.compareDate(path49, candidateValue, expectedValue, fieldConfig, weight);
|
|
22578
22581
|
default:
|
|
22579
22582
|
return {
|
|
22580
|
-
path:
|
|
22583
|
+
path: path49,
|
|
22581
22584
|
score: 0,
|
|
22582
22585
|
weight,
|
|
22583
22586
|
hit: false,
|
|
22584
|
-
message: `${
|
|
22587
|
+
message: `${path49}: unknown match type "${match}"`
|
|
22585
22588
|
};
|
|
22586
22589
|
}
|
|
22587
22590
|
}
|
|
22588
22591
|
/**
|
|
22589
22592
|
* Exact equality comparison.
|
|
22590
22593
|
*/
|
|
22591
|
-
compareExact(
|
|
22594
|
+
compareExact(path49, candidateValue, expectedValue, weight) {
|
|
22592
22595
|
if (deepEqual(candidateValue, expectedValue)) {
|
|
22593
22596
|
return {
|
|
22594
|
-
path:
|
|
22597
|
+
path: path49,
|
|
22595
22598
|
score: 1,
|
|
22596
22599
|
weight,
|
|
22597
22600
|
hit: true,
|
|
22598
|
-
message:
|
|
22601
|
+
message: path49
|
|
22599
22602
|
};
|
|
22600
22603
|
}
|
|
22601
22604
|
if (typeof candidateValue !== typeof expectedValue) {
|
|
22602
22605
|
return {
|
|
22603
|
-
path:
|
|
22606
|
+
path: path49,
|
|
22604
22607
|
score: 0,
|
|
22605
22608
|
weight,
|
|
22606
22609
|
hit: false,
|
|
22607
|
-
message: `${
|
|
22610
|
+
message: `${path49} (type mismatch: got ${typeof candidateValue}, expected ${typeof expectedValue})`
|
|
22608
22611
|
};
|
|
22609
22612
|
}
|
|
22610
22613
|
return {
|
|
22611
|
-
path:
|
|
22614
|
+
path: path49,
|
|
22612
22615
|
score: 0,
|
|
22613
22616
|
weight,
|
|
22614
22617
|
hit: false,
|
|
22615
|
-
message: `${
|
|
22618
|
+
message: `${path49} (value mismatch)`
|
|
22616
22619
|
};
|
|
22617
22620
|
}
|
|
22618
22621
|
/**
|
|
22619
22622
|
* Numeric comparison with absolute or relative tolerance.
|
|
22620
22623
|
*/
|
|
22621
|
-
compareNumericTolerance(
|
|
22624
|
+
compareNumericTolerance(path49, candidateValue, expectedValue, fieldConfig, weight) {
|
|
22622
22625
|
const { tolerance = 0, relative = false } = fieldConfig;
|
|
22623
22626
|
const candidateNum = toNumber(candidateValue);
|
|
22624
22627
|
const expectedNum = toNumber(expectedValue);
|
|
22625
22628
|
if (candidateNum === null || expectedNum === null) {
|
|
22626
22629
|
return {
|
|
22627
|
-
path:
|
|
22630
|
+
path: path49,
|
|
22628
22631
|
score: 0,
|
|
22629
22632
|
weight,
|
|
22630
22633
|
hit: false,
|
|
22631
|
-
message: `${
|
|
22634
|
+
message: `${path49} (non-numeric value)`
|
|
22632
22635
|
};
|
|
22633
22636
|
}
|
|
22634
22637
|
if (!Number.isFinite(candidateNum) || !Number.isFinite(expectedNum)) {
|
|
22635
22638
|
return {
|
|
22636
|
-
path:
|
|
22639
|
+
path: path49,
|
|
22637
22640
|
score: 0,
|
|
22638
22641
|
weight,
|
|
22639
22642
|
hit: false,
|
|
22640
|
-
message: `${
|
|
22643
|
+
message: `${path49} (invalid numeric value)`
|
|
22641
22644
|
};
|
|
22642
22645
|
}
|
|
22643
22646
|
const diff = Math.abs(candidateNum - expectedNum);
|
|
@@ -22650,61 +22653,61 @@ var FieldAccuracyGrader = class {
|
|
|
22650
22653
|
}
|
|
22651
22654
|
if (withinTolerance) {
|
|
22652
22655
|
return {
|
|
22653
|
-
path:
|
|
22656
|
+
path: path49,
|
|
22654
22657
|
score: 1,
|
|
22655
22658
|
weight,
|
|
22656
22659
|
hit: true,
|
|
22657
|
-
message: `${
|
|
22660
|
+
message: `${path49} (within tolerance: diff=${diff.toFixed(2)})`
|
|
22658
22661
|
};
|
|
22659
22662
|
}
|
|
22660
22663
|
return {
|
|
22661
|
-
path:
|
|
22664
|
+
path: path49,
|
|
22662
22665
|
score: 0,
|
|
22663
22666
|
weight,
|
|
22664
22667
|
hit: false,
|
|
22665
|
-
message: `${
|
|
22668
|
+
message: `${path49} (outside tolerance: diff=${diff.toFixed(2)}, tolerance=${tolerance})`
|
|
22666
22669
|
};
|
|
22667
22670
|
}
|
|
22668
22671
|
/**
|
|
22669
22672
|
* Date comparison with format normalization.
|
|
22670
22673
|
*/
|
|
22671
|
-
compareDate(
|
|
22674
|
+
compareDate(path49, candidateValue, expectedValue, fieldConfig, weight) {
|
|
22672
22675
|
const formats = fieldConfig.formats ?? DEFAULT_DATE_FORMATS;
|
|
22673
22676
|
const candidateDate = parseDate(String(candidateValue), formats);
|
|
22674
22677
|
const expectedDate = parseDate(String(expectedValue), formats);
|
|
22675
22678
|
if (candidateDate === null) {
|
|
22676
22679
|
return {
|
|
22677
|
-
path:
|
|
22680
|
+
path: path49,
|
|
22678
22681
|
score: 0,
|
|
22679
22682
|
weight,
|
|
22680
22683
|
hit: false,
|
|
22681
|
-
message: `${
|
|
22684
|
+
message: `${path49} (unparseable candidate date)`
|
|
22682
22685
|
};
|
|
22683
22686
|
}
|
|
22684
22687
|
if (expectedDate === null) {
|
|
22685
22688
|
return {
|
|
22686
|
-
path:
|
|
22689
|
+
path: path49,
|
|
22687
22690
|
score: 0,
|
|
22688
22691
|
weight,
|
|
22689
22692
|
hit: false,
|
|
22690
|
-
message: `${
|
|
22693
|
+
message: `${path49} (unparseable expected date)`
|
|
22691
22694
|
};
|
|
22692
22695
|
}
|
|
22693
22696
|
if (candidateDate.getFullYear() === expectedDate.getFullYear() && candidateDate.getMonth() === expectedDate.getMonth() && candidateDate.getDate() === expectedDate.getDate()) {
|
|
22694
22697
|
return {
|
|
22695
|
-
path:
|
|
22698
|
+
path: path49,
|
|
22696
22699
|
score: 1,
|
|
22697
22700
|
weight,
|
|
22698
22701
|
hit: true,
|
|
22699
|
-
message:
|
|
22702
|
+
message: path49
|
|
22700
22703
|
};
|
|
22701
22704
|
}
|
|
22702
22705
|
return {
|
|
22703
|
-
path:
|
|
22706
|
+
path: path49,
|
|
22704
22707
|
score: 0,
|
|
22705
22708
|
weight,
|
|
22706
22709
|
hit: false,
|
|
22707
|
-
message: `${
|
|
22710
|
+
message: `${path49} (date mismatch: got ${formatDateISO(candidateDate)}, expected ${formatDateISO(expectedDate)})`
|
|
22708
22711
|
};
|
|
22709
22712
|
}
|
|
22710
22713
|
/**
|
|
@@ -22737,11 +22740,11 @@ var FieldAccuracyGrader = class {
|
|
|
22737
22740
|
};
|
|
22738
22741
|
}
|
|
22739
22742
|
};
|
|
22740
|
-
function resolvePath(obj,
|
|
22741
|
-
if (!
|
|
22743
|
+
function resolvePath(obj, path49) {
|
|
22744
|
+
if (!path49 || !obj) {
|
|
22742
22745
|
return void 0;
|
|
22743
22746
|
}
|
|
22744
|
-
const parts =
|
|
22747
|
+
const parts = path49.split(/\.|\[|\]/).filter((p) => p.length > 0);
|
|
22745
22748
|
let current = obj;
|
|
22746
22749
|
for (const part of parts) {
|
|
22747
22750
|
if (current === null || current === void 0) {
|
|
@@ -23275,8 +23278,8 @@ var TokenUsageGrader = class {
|
|
|
23275
23278
|
};
|
|
23276
23279
|
}
|
|
23277
23280
|
};
|
|
23278
|
-
function getNestedValue(obj,
|
|
23279
|
-
const parts =
|
|
23281
|
+
function getNestedValue(obj, path49) {
|
|
23282
|
+
const parts = path49.split(".");
|
|
23280
23283
|
let current = obj;
|
|
23281
23284
|
for (const part of parts) {
|
|
23282
23285
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -32958,47 +32961,57 @@ async function cleanupEvalWorkspaces(evalRunId, workspaceRoot) {
|
|
|
32958
32961
|
await rm4(evalDir, { recursive: true, force: true });
|
|
32959
32962
|
}
|
|
32960
32963
|
}
|
|
32961
|
-
var
|
|
32962
|
-
function
|
|
32963
|
-
const
|
|
32964
|
-
|
|
32965
|
-
|
|
32966
|
-
|
|
32964
|
+
var GITHUB_SHORTHAND_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
32965
|
+
function resolveRepoCloneUrl(repo) {
|
|
32966
|
+
const trimmed = repo.trim();
|
|
32967
|
+
if (GITHUB_SHORTHAND_RE.test(trimmed)) {
|
|
32968
|
+
return `https://github.com/${trimmed}.git`;
|
|
32969
|
+
}
|
|
32970
|
+
return trimmed;
|
|
32971
|
+
}
|
|
32972
|
+
function normalizeRepoIdentity(repo) {
|
|
32973
|
+
const cloneUrl = resolveRepoCloneUrl(repo);
|
|
32974
|
+
const sshMatch = /^git@([^:]+):(.+)$/.exec(cloneUrl);
|
|
32975
|
+
if (sshMatch) {
|
|
32976
|
+
return normalizeHostPath(sshMatch[1], sshMatch[2]);
|
|
32977
|
+
}
|
|
32978
|
+
try {
|
|
32979
|
+
const parsed = new URL(cloneUrl);
|
|
32980
|
+
if (parsed.protocol === "ssh:" && parsed.username === "git") {
|
|
32981
|
+
return normalizeHostPath(parsed.hostname, parsed.pathname);
|
|
32982
|
+
}
|
|
32983
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
32984
|
+
return normalizeHostPath(parsed.hostname, parsed.pathname);
|
|
32967
32985
|
}
|
|
32986
|
+
if (parsed.protocol === "file:") {
|
|
32987
|
+
return `file://${stripGitSuffix(decodeURIComponent(parsed.pathname)).replace(/\/+$/, "")}`;
|
|
32988
|
+
}
|
|
32989
|
+
} catch {
|
|
32968
32990
|
}
|
|
32969
|
-
return
|
|
32970
|
-
...env,
|
|
32971
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
32972
|
-
GIT_ASKPASS: "",
|
|
32973
|
-
GIT_SSH_COMMAND: "ssh -o BatchMode=yes"
|
|
32974
|
-
};
|
|
32991
|
+
return stripGitSuffix(cloneUrl).replace(/\/+$/, "");
|
|
32975
32992
|
}
|
|
32976
|
-
|
|
32977
|
-
const
|
|
32978
|
-
|
|
32979
|
-
|
|
32980
|
-
|
|
32981
|
-
|
|
32982
|
-
|
|
32983
|
-
return stdout.trim();
|
|
32993
|
+
function normalizeHostPath(host, rawPath) {
|
|
32994
|
+
const normalizedPath = stripGitSuffix(rawPath.replace(/^\/+/, "").replace(/\/+$/, ""));
|
|
32995
|
+
const normalized = host.toLowerCase() === "github.com" ? normalizedPath.toLowerCase() : normalizedPath;
|
|
32996
|
+
return `${host.toLowerCase()}/${normalized}`;
|
|
32997
|
+
}
|
|
32998
|
+
function stripGitSuffix(value) {
|
|
32999
|
+
return value.replace(/\.git$/i, "");
|
|
32984
33000
|
}
|
|
32985
33001
|
function normalizeRepoForFingerprint(repo) {
|
|
32986
33002
|
const result = {};
|
|
32987
33003
|
if (repo.path) {
|
|
32988
33004
|
result.path = repo.path;
|
|
32989
33005
|
}
|
|
32990
|
-
if (repo.
|
|
32991
|
-
result.
|
|
32992
|
-
}
|
|
32993
|
-
result.ref = getRepoCheckoutRef(repo.checkout);
|
|
32994
|
-
if (repo.clone?.depth !== void 0) {
|
|
32995
|
-
result.depth = repo.clone.depth;
|
|
33006
|
+
if (repo.repo) {
|
|
33007
|
+
result.repo = normalizeRepoIdentity(repo.repo);
|
|
32996
33008
|
}
|
|
32997
|
-
|
|
32998
|
-
|
|
33009
|
+
result.ref = getRepoCheckoutRef(repo);
|
|
33010
|
+
if (repo.ancestor !== void 0) {
|
|
33011
|
+
result.ancestor = repo.ancestor;
|
|
32999
33012
|
}
|
|
33000
|
-
if (repo.
|
|
33001
|
-
result.sparse = [...repo.
|
|
33013
|
+
if (repo.sparse?.length) {
|
|
33014
|
+
result.sparse = [...repo.sparse].sort();
|
|
33002
33015
|
}
|
|
33003
33016
|
return result;
|
|
33004
33017
|
}
|
|
@@ -33064,7 +33077,7 @@ var WorkspacePoolManager = class {
|
|
|
33064
33077
|
}
|
|
33065
33078
|
const slotExists = existsSync3(slotPath);
|
|
33066
33079
|
if (slotExists) {
|
|
33067
|
-
await this.resetSlot(slotPath, templatePath, repos, poolReset);
|
|
33080
|
+
await this.resetSlot(slotPath, templatePath, repos, options.repoManager, poolReset);
|
|
33068
33081
|
return {
|
|
33069
33082
|
index: i,
|
|
33070
33083
|
path: slotPath,
|
|
@@ -33193,33 +33206,12 @@ var WorkspacePoolManager = class {
|
|
|
33193
33206
|
}
|
|
33194
33207
|
/**
|
|
33195
33208
|
* Reset an existing slot for reuse:
|
|
33196
|
-
* 1. Reset repos
|
|
33209
|
+
* 1. Reset repos to their declared checkout, then git clean per repo
|
|
33197
33210
|
* 2. Re-copy template files (skip repo directories)
|
|
33198
33211
|
*/
|
|
33199
|
-
async resetSlot(slotPath, templatePath, repos, poolReset = "fast") {
|
|
33200
|
-
|
|
33201
|
-
|
|
33202
|
-
const repoDir = path35.join(slotPath, repo.path);
|
|
33203
|
-
if (!existsSync3(repoDir)) {
|
|
33204
|
-
continue;
|
|
33205
|
-
}
|
|
33206
|
-
if (poolReset === "none") {
|
|
33207
|
-
continue;
|
|
33208
|
-
}
|
|
33209
|
-
const ref = getRepoCheckoutRef(repo.checkout);
|
|
33210
|
-
const resolve = repo.checkout?.resolve ?? "remote";
|
|
33211
|
-
if (resolve === "remote") {
|
|
33212
|
-
const fetchArgs = ["fetch", "origin", ref];
|
|
33213
|
-
if (repo.clone?.depth) {
|
|
33214
|
-
fetchArgs.splice(1, 0, "--depth", String(repo.clone.depth));
|
|
33215
|
-
}
|
|
33216
|
-
await git(fetchArgs, { cwd: repoDir });
|
|
33217
|
-
await git(["reset", "--hard", "FETCH_HEAD"], { cwd: repoDir });
|
|
33218
|
-
} else {
|
|
33219
|
-
await git(["reset", "--hard", ref], { cwd: repoDir });
|
|
33220
|
-
}
|
|
33221
|
-
const cleanFlag = poolReset === "strict" ? "-fdx" : "-fd";
|
|
33222
|
-
await git(["clean", cleanFlag], { cwd: repoDir });
|
|
33212
|
+
async resetSlot(slotPath, templatePath, repos, repoManager, poolReset = "fast") {
|
|
33213
|
+
if (poolReset !== "none") {
|
|
33214
|
+
await repoManager.reset(repos, slotPath, poolReset);
|
|
33223
33215
|
}
|
|
33224
33216
|
if (templatePath) {
|
|
33225
33217
|
const repoDirNames = new Set(
|
|
@@ -33232,9 +33224,201 @@ var WorkspacePoolManager = class {
|
|
|
33232
33224
|
}
|
|
33233
33225
|
}
|
|
33234
33226
|
};
|
|
33235
|
-
|
|
33227
|
+
function getProjectsRegistryPath() {
|
|
33228
|
+
return path36.join(getAgentvConfigDir(), "config.yaml");
|
|
33229
|
+
}
|
|
33230
|
+
function fromYaml(raw) {
|
|
33231
|
+
if (!raw || typeof raw !== "object") return null;
|
|
33232
|
+
const e = raw;
|
|
33233
|
+
if (typeof e.id !== "string" || typeof e.name !== "string" || typeof e.path !== "string") {
|
|
33234
|
+
return null;
|
|
33235
|
+
}
|
|
33236
|
+
const entry = {
|
|
33237
|
+
id: e.id,
|
|
33238
|
+
name: e.name,
|
|
33239
|
+
path: e.path,
|
|
33240
|
+
addedAt: typeof e.added_at === "string" ? e.added_at : "",
|
|
33241
|
+
lastOpenedAt: typeof e.last_opened_at === "string" ? e.last_opened_at : ""
|
|
33242
|
+
};
|
|
33243
|
+
if (typeof e.repo_url === "string" && e.repo_url.trim().length > 0) {
|
|
33244
|
+
entry.repoUrl = e.repo_url.trim();
|
|
33245
|
+
}
|
|
33246
|
+
if (typeof e.ref === "string" && e.ref.trim().length > 0) {
|
|
33247
|
+
entry.ref = e.ref.trim();
|
|
33248
|
+
}
|
|
33249
|
+
if (e.results && typeof e.results === "object") {
|
|
33250
|
+
const r = e.results;
|
|
33251
|
+
if (typeof r.repo_url === "string" && r.repo_url.trim().length > 0) {
|
|
33252
|
+
const sync = r.sync && typeof r.sync === "object" ? r.sync : void 0;
|
|
33253
|
+
entry.results = {
|
|
33254
|
+
repoUrl: r.repo_url.trim(),
|
|
33255
|
+
...typeof r.branch === "string" && r.branch.trim().length > 0 ? { branch: r.branch.trim() } : {},
|
|
33256
|
+
...typeof r.path === "string" && r.path.trim().length > 0 ? { path: r.path.trim() } : {},
|
|
33257
|
+
...sync && typeof sync.auto_push === "boolean" ? { sync: { autoPush: sync.auto_push } } : {},
|
|
33258
|
+
...typeof r.branch_prefix === "string" && r.branch_prefix.trim().length > 0 ? { branchPrefix: r.branch_prefix.trim() } : {}
|
|
33259
|
+
};
|
|
33260
|
+
}
|
|
33261
|
+
}
|
|
33262
|
+
return entry;
|
|
33263
|
+
}
|
|
33264
|
+
function toYaml(entry) {
|
|
33265
|
+
const yaml = {
|
|
33266
|
+
id: entry.id,
|
|
33267
|
+
name: entry.name,
|
|
33268
|
+
...entry.repoUrl !== void 0 && { repo_url: entry.repoUrl },
|
|
33269
|
+
path: entry.path,
|
|
33270
|
+
...entry.ref !== void 0 && { ref: entry.ref },
|
|
33271
|
+
added_at: entry.addedAt,
|
|
33272
|
+
last_opened_at: entry.lastOpenedAt
|
|
33273
|
+
};
|
|
33274
|
+
if (entry.results) {
|
|
33275
|
+
yaml.results = {
|
|
33276
|
+
repo_url: entry.results.repoUrl,
|
|
33277
|
+
...entry.results.branch !== void 0 && { branch: entry.results.branch },
|
|
33278
|
+
...entry.results.path !== void 0 && { path: entry.results.path },
|
|
33279
|
+
...entry.results.sync?.autoPush !== void 0 && {
|
|
33280
|
+
sync: { auto_push: entry.results.sync.autoPush }
|
|
33281
|
+
},
|
|
33282
|
+
...entry.results.branchPrefix !== void 0 && {
|
|
33283
|
+
branch_prefix: entry.results.branchPrefix
|
|
33284
|
+
}
|
|
33285
|
+
};
|
|
33286
|
+
}
|
|
33287
|
+
return yaml;
|
|
33288
|
+
}
|
|
33289
|
+
function loadProjectRegistry() {
|
|
33290
|
+
const registryPath = getProjectsRegistryPath();
|
|
33291
|
+
if (!existsSync4(registryPath)) {
|
|
33292
|
+
return { projects: [] };
|
|
33293
|
+
}
|
|
33294
|
+
try {
|
|
33295
|
+
const raw = readFileSync22(registryPath, "utf-8");
|
|
33296
|
+
const parsed = parseYamlValue(raw);
|
|
33297
|
+
if (!parsed || typeof parsed !== "object") {
|
|
33298
|
+
return { projects: [] };
|
|
33299
|
+
}
|
|
33300
|
+
const env = process.env;
|
|
33301
|
+
const projects = Array.isArray(parsed.projects) ? parsed.projects.map((e) => fromYaml(interpolateEnv(e, env))).filter((e) => e !== null) : [];
|
|
33302
|
+
return { projects };
|
|
33303
|
+
} catch {
|
|
33304
|
+
return { projects: [] };
|
|
33305
|
+
}
|
|
33306
|
+
}
|
|
33307
|
+
function saveProjectRegistry(registry2) {
|
|
33308
|
+
const registryPath = getProjectsRegistryPath();
|
|
33309
|
+
const dir = path36.dirname(registryPath);
|
|
33310
|
+
if (!existsSync4(dir)) {
|
|
33311
|
+
mkdirSync2(dir, { recursive: true });
|
|
33312
|
+
}
|
|
33313
|
+
const payload = { ...readHomeConfig(registryPath), projects: registry2.projects.map(toYaml) };
|
|
33314
|
+
writeFileSync(registryPath, stringifyYaml(payload), "utf-8");
|
|
33315
|
+
}
|
|
33316
|
+
function readHomeConfig(configPath2) {
|
|
33317
|
+
if (!existsSync4(configPath2)) return {};
|
|
33318
|
+
try {
|
|
33319
|
+
const parsed = parseYamlValue(readFileSync22(configPath2, "utf-8"));
|
|
33320
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
33321
|
+
} catch {
|
|
33322
|
+
return {};
|
|
33323
|
+
}
|
|
33324
|
+
}
|
|
33325
|
+
function deriveProjectId(dirPath, existingIds) {
|
|
33326
|
+
const base = path36.basename(dirPath).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
33327
|
+
let candidate = base || "project";
|
|
33328
|
+
let suffix = 2;
|
|
33329
|
+
while (existingIds.includes(candidate)) {
|
|
33330
|
+
candidate = `${base}-${suffix}`;
|
|
33331
|
+
suffix++;
|
|
33332
|
+
}
|
|
33333
|
+
return candidate;
|
|
33334
|
+
}
|
|
33335
|
+
function addProject(projectPath) {
|
|
33336
|
+
const absPath = path36.resolve(projectPath);
|
|
33337
|
+
if (!existsSync4(absPath)) {
|
|
33338
|
+
throw new Error(`Directory not found: ${absPath}`);
|
|
33339
|
+
}
|
|
33340
|
+
if (!existsSync4(path36.join(absPath, ".agentv"))) {
|
|
33341
|
+
throw new Error(`No .agentv/ directory found in ${absPath}. Run an evaluation first.`);
|
|
33342
|
+
}
|
|
33343
|
+
const registry2 = loadProjectRegistry();
|
|
33344
|
+
const existing = registry2.projects.find((p) => p.path === absPath);
|
|
33345
|
+
if (existing) {
|
|
33346
|
+
return existing;
|
|
33347
|
+
}
|
|
33348
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
33349
|
+
const entry = {
|
|
33350
|
+
id: deriveProjectId(
|
|
33351
|
+
absPath,
|
|
33352
|
+
registry2.projects.map((p) => p.id)
|
|
33353
|
+
),
|
|
33354
|
+
name: path36.basename(absPath),
|
|
33355
|
+
path: absPath,
|
|
33356
|
+
addedAt: now,
|
|
33357
|
+
lastOpenedAt: now
|
|
33358
|
+
};
|
|
33359
|
+
registry2.projects.push(entry);
|
|
33360
|
+
saveProjectRegistry(registry2);
|
|
33361
|
+
return entry;
|
|
33362
|
+
}
|
|
33363
|
+
function removeProject(projectId) {
|
|
33364
|
+
const registry2 = loadProjectRegistry();
|
|
33365
|
+
const idx = registry2.projects.findIndex((p) => p.id === projectId);
|
|
33366
|
+
if (idx < 0) return false;
|
|
33367
|
+
registry2.projects.splice(idx, 1);
|
|
33368
|
+
saveProjectRegistry(registry2);
|
|
33369
|
+
return true;
|
|
33370
|
+
}
|
|
33371
|
+
function getProject(projectId) {
|
|
33372
|
+
return loadProjectRegistry().projects.find((p) => p.id === projectId);
|
|
33373
|
+
}
|
|
33374
|
+
function getProjectForPath(fsPath) {
|
|
33375
|
+
const absPath = path36.resolve(fsPath);
|
|
33376
|
+
return loadProjectRegistry().projects.filter((p) => {
|
|
33377
|
+
const projectPath = path36.resolve(p.path);
|
|
33378
|
+
const relative = path36.relative(projectPath, absPath);
|
|
33379
|
+
return relative === "" || !relative.startsWith("..") && !path36.isAbsolute(relative);
|
|
33380
|
+
}).sort((a, b) => path36.resolve(b.path).length - path36.resolve(a.path).length)[0];
|
|
33381
|
+
}
|
|
33382
|
+
function touchProject(projectId) {
|
|
33383
|
+
const registry2 = loadProjectRegistry();
|
|
33384
|
+
const entry = registry2.projects.find((p) => p.id === projectId);
|
|
33385
|
+
if (entry) {
|
|
33386
|
+
entry.lastOpenedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
33387
|
+
saveProjectRegistry(registry2);
|
|
33388
|
+
}
|
|
33389
|
+
}
|
|
33390
|
+
function discoverProjects(rootDir, maxDepth = 2) {
|
|
33391
|
+
const absRoot = path36.resolve(rootDir);
|
|
33392
|
+
if (!existsSync4(absRoot) || !statSync2(absRoot).isDirectory()) {
|
|
33393
|
+
return [];
|
|
33394
|
+
}
|
|
33395
|
+
const results = [];
|
|
33396
|
+
function scan(dir, depth) {
|
|
33397
|
+
if (depth > maxDepth) return;
|
|
33398
|
+
if (existsSync4(path36.join(dir, ".agentv"))) {
|
|
33399
|
+
results.push(dir);
|
|
33400
|
+
return;
|
|
33401
|
+
}
|
|
33402
|
+
if (depth === maxDepth) return;
|
|
33403
|
+
try {
|
|
33404
|
+
const entries = readdirSync3(dir, { withFileTypes: true });
|
|
33405
|
+
for (const entry of entries) {
|
|
33406
|
+
if (!entry.isDirectory()) continue;
|
|
33407
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
33408
|
+
scan(path36.join(dir, entry.name), depth + 1);
|
|
33409
|
+
}
|
|
33410
|
+
} catch {
|
|
33411
|
+
}
|
|
33412
|
+
}
|
|
33413
|
+
scan(absRoot, 0);
|
|
33414
|
+
return results.sort();
|
|
33415
|
+
}
|
|
33416
|
+
var execFileAsync = promisify5(execFile);
|
|
33236
33417
|
var DEFAULT_TIMEOUT_MS2 = 3e5;
|
|
33237
|
-
|
|
33418
|
+
var DEFAULT_HEARTBEAT_MS = 3e4;
|
|
33419
|
+
var ERROR_OUTPUT_LIMIT = 1024 * 1024;
|
|
33420
|
+
var LOCK_POLL_MS = 100;
|
|
33421
|
+
function gitEnv() {
|
|
33238
33422
|
const env = { ...process.env };
|
|
33239
33423
|
for (const key of Object.keys(env)) {
|
|
33240
33424
|
if (key.startsWith("GIT_") && key !== "GIT_SSH_COMMAND") {
|
|
@@ -33248,64 +33432,62 @@ function gitEnv2() {
|
|
|
33248
33432
|
GIT_SSH_COMMAND: "ssh -o BatchMode=yes"
|
|
33249
33433
|
};
|
|
33250
33434
|
}
|
|
33251
|
-
function
|
|
33252
|
-
|
|
33435
|
+
function appendLimited(current, chunk) {
|
|
33436
|
+
if (current.length >= ERROR_OUTPUT_LIMIT) return current;
|
|
33437
|
+
const next = current + chunk.toString();
|
|
33438
|
+
return next.length > ERROR_OUTPUT_LIMIT ? next.slice(-ERROR_OUTPUT_LIMIT) : next;
|
|
33439
|
+
}
|
|
33440
|
+
function formatDuration(ms) {
|
|
33441
|
+
const seconds = Math.round(ms / 1e3);
|
|
33442
|
+
if (seconds < 60) return `${seconds}s`;
|
|
33443
|
+
const minutes = Math.floor(seconds / 60);
|
|
33444
|
+
const remainder = seconds % 60;
|
|
33445
|
+
return remainder === 0 ? `${minutes}m` : `${minutes}m ${remainder}s`;
|
|
33253
33446
|
}
|
|
33254
33447
|
function isFullCommitSha(ref) {
|
|
33255
33448
|
return typeof ref === "string" && /^[0-9a-f]{40}$/i.test(ref);
|
|
33256
33449
|
}
|
|
33257
|
-
|
|
33258
|
-
|
|
33450
|
+
function assertSafeGitOperand(value, label) {
|
|
33451
|
+
if (value.length === 0) {
|
|
33452
|
+
throw new Error(`${label} must not be empty.`);
|
|
33453
|
+
}
|
|
33454
|
+
if (value.includes("\0")) {
|
|
33455
|
+
throw new Error(`${label} must not contain NUL bytes.`);
|
|
33456
|
+
}
|
|
33457
|
+
if (value.startsWith("-")) {
|
|
33458
|
+
throw new Error(`${label} must not start with '-'.`);
|
|
33459
|
+
}
|
|
33460
|
+
}
|
|
33461
|
+
function sleep2(ms) {
|
|
33462
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
33463
|
+
}
|
|
33464
|
+
function configPath() {
|
|
33465
|
+
return path37.join(getAgentvConfigDir(), "config.yaml");
|
|
33466
|
+
}
|
|
33467
|
+
function expandHome(value) {
|
|
33468
|
+
if (value === "~") return process.env.HOME ?? value;
|
|
33469
|
+
if (value.startsWith("~/")) return path37.join(process.env.HOME ?? "~", value.slice(2));
|
|
33470
|
+
return value;
|
|
33471
|
+
}
|
|
33472
|
+
async function git(args, opts) {
|
|
33473
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
33259
33474
|
cwd: opts?.cwd,
|
|
33260
33475
|
timeout: opts?.timeout ?? DEFAULT_TIMEOUT_MS2,
|
|
33261
|
-
env:
|
|
33476
|
+
env: gitEnv(),
|
|
33262
33477
|
maxBuffer: 50 * 1024 * 1024
|
|
33263
|
-
// 50MB
|
|
33264
33478
|
});
|
|
33265
33479
|
return stdout.trim();
|
|
33266
33480
|
}
|
|
33267
33481
|
var RepoManager = class {
|
|
33268
33482
|
verbose;
|
|
33269
|
-
|
|
33483
|
+
progress;
|
|
33484
|
+
heartbeatMs;
|
|
33485
|
+
timeoutMs;
|
|
33486
|
+
constructor(verbose = false, options = {}) {
|
|
33270
33487
|
this.verbose = verbose;
|
|
33271
|
-
|
|
33272
|
-
|
|
33273
|
-
|
|
33274
|
-
* Returns an array of validation errors (empty if all paths are valid).
|
|
33275
|
-
*/
|
|
33276
|
-
static validateLocalPaths(repos) {
|
|
33277
|
-
const errors = [];
|
|
33278
|
-
for (const repo of repos) {
|
|
33279
|
-
if (!repo.source || repo.source.type !== "local") continue;
|
|
33280
|
-
const sourcePath = repo.source.path;
|
|
33281
|
-
if (!sourcePath || sourcePath.trim() === "") {
|
|
33282
|
-
errors.push({
|
|
33283
|
-
repoPath: repo.path ?? "(none)",
|
|
33284
|
-
resolvedSourcePath: sourcePath ?? "",
|
|
33285
|
-
reason: "empty_path"
|
|
33286
|
-
});
|
|
33287
|
-
} else if (!existsSync4(sourcePath)) {
|
|
33288
|
-
errors.push({
|
|
33289
|
-
repoPath: repo.path ?? "(none)",
|
|
33290
|
-
resolvedSourcePath: sourcePath,
|
|
33291
|
-
reason: "not_found"
|
|
33292
|
-
});
|
|
33293
|
-
}
|
|
33294
|
-
}
|
|
33295
|
-
return errors;
|
|
33296
|
-
}
|
|
33297
|
-
/**
|
|
33298
|
-
* Format validation errors into a human-readable warning message.
|
|
33299
|
-
*/
|
|
33300
|
-
static formatValidationErrors(errors) {
|
|
33301
|
-
const lines = errors.map((e) => {
|
|
33302
|
-
if (e.reason === "empty_path") {
|
|
33303
|
-
return ` - repo "${e.repoPath}": local source path is empty (check that the env var is set)`;
|
|
33304
|
-
}
|
|
33305
|
-
return ` - repo "${e.repoPath}": local source path not found: ${e.resolvedSourcePath}`;
|
|
33306
|
-
});
|
|
33307
|
-
return `Local repo path validation failed:
|
|
33308
|
-
${lines.join("\n")}`;
|
|
33488
|
+
this.progress = options.progress ?? true;
|
|
33489
|
+
this.heartbeatMs = options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;
|
|
33490
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
33309
33491
|
}
|
|
33310
33492
|
async runGit(args, opts) {
|
|
33311
33493
|
const startedAt = Date.now();
|
|
@@ -33313,7 +33495,7 @@ ${lines.join("\n")}`;
|
|
|
33313
33495
|
console.log(`[repo] git start cwd=${opts?.cwd ?? process.cwd()} args=${args.join(" ")}`);
|
|
33314
33496
|
}
|
|
33315
33497
|
try {
|
|
33316
|
-
const output = await
|
|
33498
|
+
const output = await git(args, { ...opts, timeout: opts?.timeout ?? this.timeoutMs });
|
|
33317
33499
|
if (this.verbose) {
|
|
33318
33500
|
console.log(`[repo] git ok durationMs=${Date.now() - startedAt} args=${args.join(" ")}`);
|
|
33319
33501
|
}
|
|
@@ -33328,100 +33510,370 @@ ${lines.join("\n")}`;
|
|
|
33328
33510
|
throw error40;
|
|
33329
33511
|
}
|
|
33330
33512
|
}
|
|
33513
|
+
runGitStreaming(args, opts) {
|
|
33514
|
+
const startedAt = Date.now();
|
|
33515
|
+
const timeout = opts.timeout ?? this.timeoutMs;
|
|
33516
|
+
if (this.verbose) {
|
|
33517
|
+
console.log(`[repo] git start cwd=${opts.cwd ?? process.cwd()} args=${args.join(" ")}`);
|
|
33518
|
+
}
|
|
33519
|
+
return new Promise((resolve, reject) => {
|
|
33520
|
+
let stdout = "";
|
|
33521
|
+
let stderr = "";
|
|
33522
|
+
let settled = false;
|
|
33523
|
+
let timedOut = false;
|
|
33524
|
+
const child = spawn5("git", args, {
|
|
33525
|
+
cwd: opts.cwd,
|
|
33526
|
+
env: gitEnv(),
|
|
33527
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
33528
|
+
});
|
|
33529
|
+
let timeoutHandle;
|
|
33530
|
+
const resetIdleTimeout = () => {
|
|
33531
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
33532
|
+
timeoutHandle = setTimeout(() => {
|
|
33533
|
+
timedOut = true;
|
|
33534
|
+
child.kill("SIGTERM");
|
|
33535
|
+
}, timeout);
|
|
33536
|
+
};
|
|
33537
|
+
resetIdleTimeout();
|
|
33538
|
+
const heartbeatHandle = this.progress && this.heartbeatMs > 0 ? setInterval(() => {
|
|
33539
|
+
const elapsed = formatDuration(Date.now() - startedAt);
|
|
33540
|
+
console.error(`[repo] ${opts.description} still running after ${elapsed}`);
|
|
33541
|
+
}, this.heartbeatMs) : void 0;
|
|
33542
|
+
const finish = (error40) => {
|
|
33543
|
+
if (settled) return;
|
|
33544
|
+
settled = true;
|
|
33545
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
33546
|
+
if (heartbeatHandle) clearInterval(heartbeatHandle);
|
|
33547
|
+
if (error40) {
|
|
33548
|
+
reject(error40);
|
|
33549
|
+
} else {
|
|
33550
|
+
resolve();
|
|
33551
|
+
}
|
|
33552
|
+
};
|
|
33553
|
+
child.stdout.on("data", (chunk) => {
|
|
33554
|
+
stdout = appendLimited(stdout, chunk);
|
|
33555
|
+
if (!timedOut) resetIdleTimeout();
|
|
33556
|
+
if (this.progress) process.stdout.write(chunk);
|
|
33557
|
+
});
|
|
33558
|
+
child.stderr.on("data", (chunk) => {
|
|
33559
|
+
stderr = appendLimited(stderr, chunk);
|
|
33560
|
+
if (!timedOut) resetIdleTimeout();
|
|
33561
|
+
if (this.progress) process.stderr.write(chunk);
|
|
33562
|
+
});
|
|
33563
|
+
child.on("error", (error40) => finish(error40));
|
|
33564
|
+
child.on("close", (code, signal) => {
|
|
33565
|
+
const durationMs = Date.now() - startedAt;
|
|
33566
|
+
if (this.verbose) {
|
|
33567
|
+
console.log(
|
|
33568
|
+
`[repo] git ${code === 0 ? "ok" : "fail"} durationMs=${durationMs} args=${args.join(" ")}`
|
|
33569
|
+
);
|
|
33570
|
+
}
|
|
33571
|
+
if (timedOut) {
|
|
33572
|
+
finish(
|
|
33573
|
+
new Error(
|
|
33574
|
+
`${opts.description} made no progress for ${formatDuration(timeout)}. Register a matching local checkout, configure git_cache.mirrors in ${configPath()}, or check network connectivity.`
|
|
33575
|
+
)
|
|
33576
|
+
);
|
|
33577
|
+
return;
|
|
33578
|
+
}
|
|
33579
|
+
if (code !== 0) {
|
|
33580
|
+
const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
|
|
33581
|
+
finish(
|
|
33582
|
+
new Error(
|
|
33583
|
+
`git ${args.join(" ")} failed with code ${code ?? "unknown"}${signal ? ` (signal ${signal})` : ""}${output ? `:
|
|
33584
|
+
${output}` : ""}`
|
|
33585
|
+
)
|
|
33586
|
+
);
|
|
33587
|
+
return;
|
|
33588
|
+
}
|
|
33589
|
+
finish();
|
|
33590
|
+
});
|
|
33591
|
+
});
|
|
33592
|
+
}
|
|
33593
|
+
loadConfiguredMirrors() {
|
|
33594
|
+
const filePath = configPath();
|
|
33595
|
+
if (!existsSync5(filePath)) return {};
|
|
33596
|
+
try {
|
|
33597
|
+
const parsed = parseYamlValue(readFileSync3(filePath, "utf-8"));
|
|
33598
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
33599
|
+
const config2 = parsed;
|
|
33600
|
+
const gitCache = config2.git_cache;
|
|
33601
|
+
if (!gitCache || typeof gitCache !== "object" || Array.isArray(gitCache)) return {};
|
|
33602
|
+
const mirrors = gitCache.mirrors;
|
|
33603
|
+
if (!mirrors || typeof mirrors !== "object" || Array.isArray(mirrors)) return {};
|
|
33604
|
+
const result = {};
|
|
33605
|
+
for (const [repo, localPath] of Object.entries(mirrors)) {
|
|
33606
|
+
if (typeof localPath === "string" && localPath.trim().length > 0) {
|
|
33607
|
+
result[repo] = expandHome(localPath.trim());
|
|
33608
|
+
}
|
|
33609
|
+
}
|
|
33610
|
+
return result;
|
|
33611
|
+
} catch {
|
|
33612
|
+
return {};
|
|
33613
|
+
}
|
|
33614
|
+
}
|
|
33615
|
+
findConfiguredMirror(repoIdentity) {
|
|
33616
|
+
const mirrors = this.loadConfiguredMirrors();
|
|
33617
|
+
for (const [repo, localPath] of Object.entries(mirrors)) {
|
|
33618
|
+
if (normalizeRepoIdentity(repo) !== repoIdentity) continue;
|
|
33619
|
+
if (!existsSync5(localPath)) {
|
|
33620
|
+
console.warn(`[repo] configured mirror not found, falling back: ${localPath}`);
|
|
33621
|
+
continue;
|
|
33622
|
+
}
|
|
33623
|
+
return localPath;
|
|
33624
|
+
}
|
|
33625
|
+
return void 0;
|
|
33626
|
+
}
|
|
33627
|
+
async findRegisteredProject(repoIdentity) {
|
|
33628
|
+
for (const project of loadProjectRegistry().projects) {
|
|
33629
|
+
if (!existsSync5(project.path)) continue;
|
|
33630
|
+
try {
|
|
33631
|
+
const origin = await this.runGit(["remote", "get-url", "origin"], {
|
|
33632
|
+
cwd: project.path,
|
|
33633
|
+
timeout: 1e4
|
|
33634
|
+
});
|
|
33635
|
+
if (normalizeRepoIdentity(origin) === repoIdentity) {
|
|
33636
|
+
return project.path;
|
|
33637
|
+
}
|
|
33638
|
+
} catch {
|
|
33639
|
+
if (project.repoUrl && normalizeRepoIdentity(project.repoUrl) === repoIdentity) {
|
|
33640
|
+
return project.path;
|
|
33641
|
+
}
|
|
33642
|
+
}
|
|
33643
|
+
}
|
|
33644
|
+
return void 0;
|
|
33645
|
+
}
|
|
33646
|
+
gitCachePath(repoIdentity) {
|
|
33647
|
+
const hash = createHash4("sha256").update(repoIdentity).digest("hex");
|
|
33648
|
+
return path37.join(getAgentvDataDir(), "git-cache", hash);
|
|
33649
|
+
}
|
|
33650
|
+
async withMirrorCacheLock(mirrorPath, action) {
|
|
33651
|
+
const lockPath = `${mirrorPath}.lock`;
|
|
33652
|
+
const startedAt = Date.now();
|
|
33653
|
+
while (true) {
|
|
33654
|
+
try {
|
|
33655
|
+
await mkdir16(lockPath);
|
|
33656
|
+
break;
|
|
33657
|
+
} catch (error40) {
|
|
33658
|
+
const code = error40.code;
|
|
33659
|
+
if (code !== "EEXIST") throw error40;
|
|
33660
|
+
if (Date.now() - startedAt > this.timeoutMs) {
|
|
33661
|
+
throw new Error(`Timed out waiting for git cache lock: ${lockPath}`);
|
|
33662
|
+
}
|
|
33663
|
+
await sleep2(LOCK_POLL_MS);
|
|
33664
|
+
}
|
|
33665
|
+
}
|
|
33666
|
+
try {
|
|
33667
|
+
return await action();
|
|
33668
|
+
} finally {
|
|
33669
|
+
await rm6(lockPath, { recursive: true, force: true });
|
|
33670
|
+
}
|
|
33671
|
+
}
|
|
33672
|
+
async isValidBareRepo(repoPath) {
|
|
33673
|
+
if (!existsSync5(path37.join(repoPath, "HEAD"))) return false;
|
|
33674
|
+
try {
|
|
33675
|
+
return await this.runGit(["rev-parse", "--is-bare-repository"], {
|
|
33676
|
+
cwd: repoPath,
|
|
33677
|
+
timeout: 1e4
|
|
33678
|
+
}) === "true";
|
|
33679
|
+
} catch {
|
|
33680
|
+
return false;
|
|
33681
|
+
}
|
|
33682
|
+
}
|
|
33683
|
+
async removeInvalidMirrorCache(mirrorPath) {
|
|
33684
|
+
if (!existsSync5(mirrorPath)) return;
|
|
33685
|
+
const quarantinePath = `${mirrorPath}.invalid-${process.pid}-${Date.now()}-${randomUUID9()}`;
|
|
33686
|
+
try {
|
|
33687
|
+
await rename(mirrorPath, quarantinePath);
|
|
33688
|
+
await rm6(quarantinePath, { recursive: true, force: true });
|
|
33689
|
+
} catch {
|
|
33690
|
+
await rm6(mirrorPath, { recursive: true, force: true });
|
|
33691
|
+
}
|
|
33692
|
+
}
|
|
33693
|
+
async prepareMirrorCache(seedSource, repoIdentity) {
|
|
33694
|
+
assertSafeGitOperand(seedSource, "repo clone source");
|
|
33695
|
+
const mirrorPath = this.gitCachePath(repoIdentity);
|
|
33696
|
+
try {
|
|
33697
|
+
await mkdir16(path37.dirname(mirrorPath), { recursive: true });
|
|
33698
|
+
return await this.withMirrorCacheLock(mirrorPath, async () => {
|
|
33699
|
+
if (await this.isValidBareRepo(mirrorPath)) {
|
|
33700
|
+
try {
|
|
33701
|
+
await this.runGit(["remote", "set-url", "origin", seedSource], {
|
|
33702
|
+
cwd: mirrorPath,
|
|
33703
|
+
timeout: 1e4
|
|
33704
|
+
});
|
|
33705
|
+
await this.runGitStreaming(["fetch", "--prune", "--progress", "origin"], {
|
|
33706
|
+
cwd: mirrorPath,
|
|
33707
|
+
description: `git fetch cache for ${seedSource}`
|
|
33708
|
+
});
|
|
33709
|
+
} catch (error40) {
|
|
33710
|
+
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
33711
|
+
console.warn(`[repo] mirror cache fetch failed; using existing cache: ${message}`);
|
|
33712
|
+
}
|
|
33713
|
+
return mirrorPath;
|
|
33714
|
+
}
|
|
33715
|
+
await this.removeInvalidMirrorCache(mirrorPath);
|
|
33716
|
+
const tempPath = path37.join(
|
|
33717
|
+
path37.dirname(mirrorPath),
|
|
33718
|
+
`${path37.basename(mirrorPath)}.tmp-${process.pid}-${Date.now()}-${randomUUID9()}`
|
|
33719
|
+
);
|
|
33720
|
+
try {
|
|
33721
|
+
await this.runGitStreaming(
|
|
33722
|
+
["clone", "--mirror", "--progress", "--", seedSource, tempPath],
|
|
33723
|
+
{
|
|
33724
|
+
description: `git mirror clone ${seedSource}`
|
|
33725
|
+
}
|
|
33726
|
+
);
|
|
33727
|
+
if (!await this.isValidBareRepo(tempPath)) {
|
|
33728
|
+
throw new Error(`git mirror clone did not create a valid bare repo at ${tempPath}`);
|
|
33729
|
+
}
|
|
33730
|
+
await rename(tempPath, mirrorPath);
|
|
33731
|
+
return mirrorPath;
|
|
33732
|
+
} finally {
|
|
33733
|
+
await rm6(tempPath, { recursive: true, force: true });
|
|
33734
|
+
}
|
|
33735
|
+
});
|
|
33736
|
+
} catch (error40) {
|
|
33737
|
+
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
33738
|
+
console.warn(`[repo] mirror cache unavailable; trying next acquisition source: ${message}`);
|
|
33739
|
+
return void 0;
|
|
33740
|
+
}
|
|
33741
|
+
}
|
|
33742
|
+
async resolveCommit(ref, cwd) {
|
|
33743
|
+
assertSafeGitOperand(ref, "repo checkout ref");
|
|
33744
|
+
const candidates = [ref];
|
|
33745
|
+
if (!ref.startsWith("refs/") && !ref.startsWith("origin/") && !isFullCommitSha(ref)) {
|
|
33746
|
+
candidates.push(`refs/remotes/origin/${ref}`);
|
|
33747
|
+
}
|
|
33748
|
+
for (const candidate of candidates) {
|
|
33749
|
+
try {
|
|
33750
|
+
return await this.runGit(
|
|
33751
|
+
["rev-parse", "--verify", "--end-of-options", `${candidate}^{commit}`],
|
|
33752
|
+
{ cwd }
|
|
33753
|
+
);
|
|
33754
|
+
} catch {
|
|
33755
|
+
}
|
|
33756
|
+
}
|
|
33757
|
+
throw new Error(`Cannot resolve ref '${ref}' to a commit.`);
|
|
33758
|
+
}
|
|
33759
|
+
async resolveCheckoutCommit(repo, targetDir) {
|
|
33760
|
+
const ref = getRepoCheckoutRef(repo);
|
|
33761
|
+
const checkoutSha = await this.resolveCommit(ref, targetDir);
|
|
33762
|
+
const ancestor = repo.ancestor ?? 0;
|
|
33763
|
+
if (ancestor === 0) {
|
|
33764
|
+
return checkoutSha;
|
|
33765
|
+
}
|
|
33766
|
+
try {
|
|
33767
|
+
return await this.resolveCommit(`${checkoutSha}~${ancestor}`, targetDir);
|
|
33768
|
+
} catch {
|
|
33769
|
+
const shallowHint = isFullCommitSha(ref) ? "" : " Ensure the declared commit has enough reachable history in the selected repo.";
|
|
33770
|
+
throw new Error(`Cannot resolve ancestor ${ancestor} of ref '${ref}'.${shallowHint}`);
|
|
33771
|
+
}
|
|
33772
|
+
}
|
|
33773
|
+
assertNoUserOwnedAlternates(targetDir, acquisition) {
|
|
33774
|
+
const alternatesPath = path37.join(targetDir, ".git", "objects", "info", "alternates");
|
|
33775
|
+
if (!existsSync5(alternatesPath)) return;
|
|
33776
|
+
const alternates = readFileSync3(alternatesPath, "utf-8").trim();
|
|
33777
|
+
if (alternates.length > 0) {
|
|
33778
|
+
throw new Error(
|
|
33779
|
+
`git clone for ${acquisition.kind} left an alternates dependency at ${alternatesPath}`
|
|
33780
|
+
);
|
|
33781
|
+
}
|
|
33782
|
+
}
|
|
33783
|
+
async resolveAcquisition(repo) {
|
|
33784
|
+
const declaredRepo = repo.repo;
|
|
33785
|
+
if (!declaredRepo) {
|
|
33786
|
+
throw new Error(`repo is required for workspace repo at path ${repo.path ?? "(none)"}`);
|
|
33787
|
+
}
|
|
33788
|
+
const originUrl = resolveRepoCloneUrl(declaredRepo);
|
|
33789
|
+
const repoIdentity = normalizeRepoIdentity(declaredRepo);
|
|
33790
|
+
const registeredProject = await this.findRegisteredProject(repoIdentity);
|
|
33791
|
+
if (registeredProject) {
|
|
33792
|
+
const mirrorCache2 = await this.prepareMirrorCache(registeredProject, repoIdentity);
|
|
33793
|
+
if (mirrorCache2) {
|
|
33794
|
+
return {
|
|
33795
|
+
kind: "registered-project",
|
|
33796
|
+
sourceUrl: mirrorCache2,
|
|
33797
|
+
originUrl
|
|
33798
|
+
};
|
|
33799
|
+
}
|
|
33800
|
+
}
|
|
33801
|
+
const configuredMirror = this.findConfiguredMirror(repoIdentity);
|
|
33802
|
+
if (configuredMirror) {
|
|
33803
|
+
const mirrorCache2 = await this.prepareMirrorCache(configuredMirror, repoIdentity);
|
|
33804
|
+
if (mirrorCache2) {
|
|
33805
|
+
return {
|
|
33806
|
+
kind: "configured-mirror",
|
|
33807
|
+
sourceUrl: mirrorCache2,
|
|
33808
|
+
originUrl
|
|
33809
|
+
};
|
|
33810
|
+
}
|
|
33811
|
+
}
|
|
33812
|
+
const mirrorCache = await this.prepareMirrorCache(originUrl, repoIdentity);
|
|
33813
|
+
if (mirrorCache) {
|
|
33814
|
+
return {
|
|
33815
|
+
kind: "mirror-cache",
|
|
33816
|
+
sourceUrl: mirrorCache,
|
|
33817
|
+
originUrl
|
|
33818
|
+
};
|
|
33819
|
+
}
|
|
33820
|
+
return { kind: "remote", sourceUrl: originUrl, originUrl };
|
|
33821
|
+
}
|
|
33331
33822
|
/**
|
|
33332
|
-
* Clone a repo
|
|
33333
|
-
* Handles
|
|
33823
|
+
* Clone a repo into the workspace at the configured path.
|
|
33824
|
+
* Handles acquisition resolution, sparse checkout, commit checkout, and ancestor walking.
|
|
33334
33825
|
*/
|
|
33335
33826
|
async materialize(repo, workspacePath) {
|
|
33336
|
-
if (!repo.
|
|
33827
|
+
if (!repo.repo || !repo.path) {
|
|
33337
33828
|
if (this.verbose) {
|
|
33338
|
-
console.log(`[repo] materialize skip path=${repo.path ?? "(none)"} (no
|
|
33829
|
+
console.log(`[repo] materialize skip path=${repo.path ?? "(none)"} (no repo or path)`);
|
|
33339
33830
|
}
|
|
33340
33831
|
return;
|
|
33341
33832
|
}
|
|
33342
|
-
const targetDir =
|
|
33343
|
-
const
|
|
33833
|
+
const targetDir = path37.join(workspacePath, repo.path);
|
|
33834
|
+
const acquisition = await this.resolveAcquisition(repo);
|
|
33344
33835
|
const startedAt = Date.now();
|
|
33345
33836
|
if (this.verbose) {
|
|
33346
33837
|
console.log(
|
|
33347
|
-
`[repo] materialize start path=${repo.path}
|
|
33838
|
+
`[repo] materialize start path=${repo.path} repo=${repo.repo} acquisition=${acquisition.kind} workspace=${workspacePath}`
|
|
33348
33839
|
);
|
|
33349
33840
|
}
|
|
33350
|
-
const cloneArgs = ["clone"];
|
|
33351
|
-
|
|
33352
|
-
|
|
33353
|
-
|
|
33354
|
-
|
|
33355
|
-
|
|
33841
|
+
const cloneArgs = ["clone", "--progress", "--no-checkout"];
|
|
33842
|
+
assertSafeGitOperand(acquisition.sourceUrl, "repo clone source");
|
|
33843
|
+
cloneArgs.push("--", acquisition.sourceUrl, targetDir);
|
|
33844
|
+
await this.runGitStreaming(cloneArgs, {
|
|
33845
|
+
description: `git clone ${repo.repo}`
|
|
33846
|
+
});
|
|
33847
|
+
this.assertNoUserOwnedAlternates(targetDir, acquisition);
|
|
33848
|
+
if (acquisition.sourceUrl !== acquisition.originUrl) {
|
|
33849
|
+
assertSafeGitOperand(acquisition.originUrl, "repo origin URL");
|
|
33850
|
+
await this.runGit(["remote", "set-url", "origin", acquisition.originUrl], { cwd: targetDir });
|
|
33356
33851
|
}
|
|
33357
|
-
|
|
33358
|
-
|
|
33359
|
-
|
|
33360
|
-
await this.runGit(cloneArgs);
|
|
33361
|
-
if (repo.clone?.sparse?.length) {
|
|
33362
|
-
await this.runGit(["sparse-checkout", "init", "--cone"], { cwd: targetDir });
|
|
33363
|
-
await this.runGit(["sparse-checkout", "set", ...repo.clone.sparse], { cwd: targetDir });
|
|
33364
|
-
}
|
|
33365
|
-
const ref = getRepoCheckoutRef(repo.checkout);
|
|
33366
|
-
const resolve = repo.checkout?.resolve ?? "remote";
|
|
33367
|
-
const baseCommit = repo.checkout?.base_commit;
|
|
33368
|
-
const shouldResolveLocally = resolve === "local" || repo.source.type === "git" && isFullCommitSha(baseCommit);
|
|
33369
|
-
let resolvedSha;
|
|
33370
|
-
if (!shouldResolveLocally && repo.source.type === "git") {
|
|
33371
|
-
const url2 = getSourceUrl(repo.source);
|
|
33372
|
-
try {
|
|
33373
|
-
const lsOutput = await this.runGit(["ls-remote", url2, ref]);
|
|
33374
|
-
const match = lsOutput.split(" ")[0];
|
|
33375
|
-
if (!match) {
|
|
33376
|
-
throw new Error(`Ref '${ref}' not found on remote ${url2}`);
|
|
33377
|
-
}
|
|
33378
|
-
resolvedSha = match;
|
|
33379
|
-
} catch (err) {
|
|
33380
|
-
if (err instanceof Error && err.message.includes("not found")) throw err;
|
|
33381
|
-
resolvedSha = ref;
|
|
33852
|
+
if (repo.sparse?.length) {
|
|
33853
|
+
for (const sparsePath of repo.sparse) {
|
|
33854
|
+
assertSafeGitOperand(sparsePath, "repo sparse path");
|
|
33382
33855
|
}
|
|
33383
|
-
|
|
33384
|
-
|
|
33856
|
+
await this.runGit(["sparse-checkout", "init", "--cone"], { cwd: targetDir });
|
|
33857
|
+
await this.runGit(["sparse-checkout", "set", "--", ...repo.sparse], { cwd: targetDir });
|
|
33385
33858
|
}
|
|
33859
|
+
const ref = getRepoCheckoutRef(repo);
|
|
33386
33860
|
if (this.verbose) {
|
|
33387
|
-
console.log(
|
|
33388
|
-
`[repo] checkout path=${repo.path} ref=${ref} resolved=${resolvedSha} resolve=${resolve}`
|
|
33389
|
-
);
|
|
33390
|
-
}
|
|
33391
|
-
await this.runGit(["checkout", resolvedSha], { cwd: targetDir });
|
|
33392
|
-
const ancestor = repo.checkout?.ancestor ?? 0;
|
|
33393
|
-
if (ancestor > 0) {
|
|
33394
|
-
try {
|
|
33395
|
-
const ancestorSha = await this.runGit(["rev-parse", `HEAD~${ancestor}`], {
|
|
33396
|
-
cwd: targetDir
|
|
33397
|
-
});
|
|
33398
|
-
await this.runGit(["checkout", ancestorSha], { cwd: targetDir });
|
|
33399
|
-
} catch {
|
|
33400
|
-
if (repo.clone?.depth) {
|
|
33401
|
-
await this.runGit(["fetch", "--deepen", String(ancestor)], { cwd: targetDir });
|
|
33402
|
-
const ancestorSha = await this.runGit(["rev-parse", `HEAD~${ancestor}`], {
|
|
33403
|
-
cwd: targetDir
|
|
33404
|
-
});
|
|
33405
|
-
await this.runGit(["checkout", ancestorSha], { cwd: targetDir });
|
|
33406
|
-
} else {
|
|
33407
|
-
throw new Error(
|
|
33408
|
-
`Cannot resolve ancestor ${ancestor} of ref '${ref}'. If using shallow clone, increase clone.depth to at least ${ancestor + 1}.`
|
|
33409
|
-
);
|
|
33410
|
-
}
|
|
33411
|
-
}
|
|
33861
|
+
console.log(`[repo] checkout path=${repo.path} ref=${ref}`);
|
|
33412
33862
|
}
|
|
33863
|
+
const checkoutSha = await this.resolveCheckoutCommit(repo, targetDir);
|
|
33864
|
+
await this.runGit(["checkout", "--detach", checkoutSha], { cwd: targetDir });
|
|
33413
33865
|
if (this.verbose) {
|
|
33414
33866
|
console.log(
|
|
33415
33867
|
`[repo] materialize done path=${repo.path} target=${targetDir} durationMs=${Date.now() - startedAt}`
|
|
33416
33868
|
);
|
|
33417
33869
|
}
|
|
33418
33870
|
}
|
|
33419
|
-
/** Materialize all repos into the workspace. Skips repos without
|
|
33871
|
+
/** Materialize all repos into the workspace. Skips repos without repo (Docker-only repos). */
|
|
33420
33872
|
async materializeAll(repos, workspacePath) {
|
|
33421
|
-
const materializableRepos = repos.filter((r) => r.
|
|
33873
|
+
const materializableRepos = repos.filter((r) => r.repo);
|
|
33422
33874
|
if (this.verbose) {
|
|
33423
33875
|
console.log(
|
|
33424
|
-
`[repo] materializeAll count=${materializableRepos.length} (${repos.length - materializableRepos.length} skipped, no
|
|
33876
|
+
`[repo] materializeAll count=${materializableRepos.length} (${repos.length - materializableRepos.length} skipped, no repo) workspace=${workspacePath}`
|
|
33425
33877
|
);
|
|
33426
33878
|
}
|
|
33427
33879
|
for (const repo of materializableRepos) {
|
|
@@ -33431,13 +33883,14 @@ ${lines.join("\n")}`;
|
|
|
33431
33883
|
console.log("[repo] materializeAll complete");
|
|
33432
33884
|
}
|
|
33433
33885
|
}
|
|
33434
|
-
/** Reset repos in workspace to their checkout state. Skips repos without path or
|
|
33886
|
+
/** Reset repos in workspace to their checkout state. Skips repos without path or repo. */
|
|
33435
33887
|
async reset(repos, workspacePath, reset) {
|
|
33436
33888
|
const cleanFlag = reset === "strict" ? "-fdx" : "-fd";
|
|
33437
33889
|
for (const repo of repos) {
|
|
33438
|
-
if (!repo.path || !repo.
|
|
33439
|
-
const targetDir =
|
|
33440
|
-
await this.
|
|
33890
|
+
if (!repo.path || !repo.repo) continue;
|
|
33891
|
+
const targetDir = path37.join(workspacePath, repo.path);
|
|
33892
|
+
const resetSha = await this.resolveCheckoutCommit(repo, targetDir);
|
|
33893
|
+
await this.runGit(["reset", "--hard", resetSha], { cwd: targetDir });
|
|
33441
33894
|
await this.runGit(["clean", cleanFlag], { cwd: targetDir });
|
|
33442
33895
|
}
|
|
33443
33896
|
}
|
|
@@ -33446,11 +33899,11 @@ async function resolveWorkspaceTemplate(templatePath) {
|
|
|
33446
33899
|
if (!templatePath) {
|
|
33447
33900
|
return void 0;
|
|
33448
33901
|
}
|
|
33449
|
-
const resolved =
|
|
33902
|
+
const resolved = path38.resolve(templatePath);
|
|
33450
33903
|
const stats = await stat7(resolved);
|
|
33451
33904
|
if (stats.isFile()) {
|
|
33452
33905
|
return {
|
|
33453
|
-
dir:
|
|
33906
|
+
dir: path38.dirname(resolved),
|
|
33454
33907
|
workspaceFile: resolved
|
|
33455
33908
|
};
|
|
33456
33909
|
}
|
|
@@ -33462,14 +33915,14 @@ async function resolveWorkspaceTemplate(templatePath) {
|
|
|
33462
33915
|
if (workspaceFiles.length === 1) {
|
|
33463
33916
|
return {
|
|
33464
33917
|
dir: resolved,
|
|
33465
|
-
workspaceFile:
|
|
33918
|
+
workspaceFile: path38.join(resolved, workspaceFiles[0])
|
|
33466
33919
|
};
|
|
33467
33920
|
}
|
|
33468
33921
|
if (workspaceFiles.length > 1) {
|
|
33469
33922
|
const conventionFile = workspaceFiles.find((f) => f === "template.code-workspace");
|
|
33470
33923
|
return {
|
|
33471
33924
|
dir: resolved,
|
|
33472
|
-
workspaceFile: conventionFile ?
|
|
33925
|
+
workspaceFile: conventionFile ? path38.join(resolved, conventionFile) : void 0
|
|
33473
33926
|
};
|
|
33474
33927
|
}
|
|
33475
33928
|
return { dir: resolved };
|
|
@@ -33595,7 +34048,7 @@ async function loadTestsFromAgentSkills(filePath) {
|
|
|
33595
34048
|
} catch {
|
|
33596
34049
|
throw new Error(`Invalid Agent Skills evals.json: failed to parse JSON in '${filePath}'`);
|
|
33597
34050
|
}
|
|
33598
|
-
return parseAgentSkillsEvals(parsed, filePath,
|
|
34051
|
+
return parseAgentSkillsEvals(parsed, filePath, path39.dirname(path39.resolve(filePath)));
|
|
33599
34052
|
}
|
|
33600
34053
|
function parseAgentSkillsEvals(parsed, source = "evals.json", baseDir) {
|
|
33601
34054
|
if (!isAgentSkillsFormat(parsed)) {
|
|
@@ -33633,7 +34086,7 @@ function parseAgentSkillsEvals(parsed, source = "evals.json", baseDir) {
|
|
|
33633
34086
|
if (baseDir) {
|
|
33634
34087
|
metadata.agent_skills_base_dir = baseDir;
|
|
33635
34088
|
for (const file2 of evalCase.files) {
|
|
33636
|
-
filePaths.push(
|
|
34089
|
+
filePaths.push(path39.resolve(baseDir, file2));
|
|
33637
34090
|
}
|
|
33638
34091
|
}
|
|
33639
34092
|
}
|
|
@@ -33669,15 +34122,15 @@ function resolveToAbsolutePath(candidate) {
|
|
|
33669
34122
|
if (candidate.startsWith("file:")) {
|
|
33670
34123
|
return fileURLToPath4(candidate);
|
|
33671
34124
|
}
|
|
33672
|
-
return
|
|
34125
|
+
return path40.resolve(candidate);
|
|
33673
34126
|
}
|
|
33674
34127
|
throw new TypeError("Unsupported repoRoot value. Expected string or URL.");
|
|
33675
34128
|
}
|
|
33676
34129
|
function buildDirectoryChain2(filePath, repoRoot) {
|
|
33677
34130
|
const directories = [];
|
|
33678
34131
|
const seen = /* @__PURE__ */ new Set();
|
|
33679
|
-
const boundary =
|
|
33680
|
-
let current =
|
|
34132
|
+
const boundary = path40.resolve(repoRoot);
|
|
34133
|
+
let current = path40.resolve(path40.dirname(filePath));
|
|
33681
34134
|
while (current !== void 0) {
|
|
33682
34135
|
if (!seen.has(current)) {
|
|
33683
34136
|
directories.push(current);
|
|
@@ -33686,7 +34139,7 @@ function buildDirectoryChain2(filePath, repoRoot) {
|
|
|
33686
34139
|
if (current === boundary) {
|
|
33687
34140
|
break;
|
|
33688
34141
|
}
|
|
33689
|
-
const parent =
|
|
34142
|
+
const parent = path40.dirname(current);
|
|
33690
34143
|
if (parent === current) {
|
|
33691
34144
|
break;
|
|
33692
34145
|
}
|
|
@@ -33700,16 +34153,16 @@ function buildDirectoryChain2(filePath, repoRoot) {
|
|
|
33700
34153
|
function buildSearchRoots2(evalPath, repoRoot) {
|
|
33701
34154
|
const uniqueRoots = [];
|
|
33702
34155
|
const addRoot = (root) => {
|
|
33703
|
-
const normalized =
|
|
34156
|
+
const normalized = path40.resolve(root);
|
|
33704
34157
|
if (!uniqueRoots.includes(normalized)) {
|
|
33705
34158
|
uniqueRoots.push(normalized);
|
|
33706
34159
|
}
|
|
33707
34160
|
};
|
|
33708
|
-
let currentDir =
|
|
34161
|
+
let currentDir = path40.dirname(evalPath);
|
|
33709
34162
|
let reachedBoundary = false;
|
|
33710
34163
|
while (!reachedBoundary) {
|
|
33711
34164
|
addRoot(currentDir);
|
|
33712
|
-
const parentDir =
|
|
34165
|
+
const parentDir = path40.dirname(currentDir);
|
|
33713
34166
|
if (currentDir === repoRoot || parentDir === currentDir) {
|
|
33714
34167
|
reachedBoundary = true;
|
|
33715
34168
|
} else {
|
|
@@ -33727,16 +34180,16 @@ function trimLeadingSeparators2(value) {
|
|
|
33727
34180
|
async function resolveFileReference3(rawValue, searchRoots) {
|
|
33728
34181
|
const displayPath = trimLeadingSeparators2(rawValue);
|
|
33729
34182
|
const potentialPaths = [];
|
|
33730
|
-
if (
|
|
33731
|
-
potentialPaths.push(
|
|
34183
|
+
if (path40.isAbsolute(rawValue)) {
|
|
34184
|
+
potentialPaths.push(path40.normalize(rawValue));
|
|
33732
34185
|
}
|
|
33733
34186
|
for (const base of searchRoots) {
|
|
33734
|
-
potentialPaths.push(
|
|
34187
|
+
potentialPaths.push(path40.resolve(base, displayPath));
|
|
33735
34188
|
}
|
|
33736
34189
|
const attempted = [];
|
|
33737
34190
|
const seen = /* @__PURE__ */ new Set();
|
|
33738
34191
|
for (const candidate of potentialPaths) {
|
|
33739
|
-
const absoluteCandidate =
|
|
34192
|
+
const absoluteCandidate = path40.resolve(candidate);
|
|
33740
34193
|
if (seen.has(absoluteCandidate)) {
|
|
33741
34194
|
continue;
|
|
33742
34195
|
}
|
|
@@ -33757,48 +34210,48 @@ var DEFAULT_EVAL_PATTERNS = [
|
|
|
33757
34210
|
];
|
|
33758
34211
|
async function loadConfig(evalFilePath, repoRoot) {
|
|
33759
34212
|
const directories = buildDirectoryChain2(evalFilePath, repoRoot);
|
|
33760
|
-
const globalConfigPath =
|
|
34213
|
+
const globalConfigPath = path41.join(getAgentvConfigDir(), "config.yaml");
|
|
33761
34214
|
for (const directory of directories) {
|
|
33762
|
-
const
|
|
33763
|
-
if (!await fileExists3(
|
|
34215
|
+
const configPath2 = path41.join(directory, ".agentv", "config.yaml");
|
|
34216
|
+
if (!await fileExists3(configPath2)) {
|
|
33764
34217
|
continue;
|
|
33765
34218
|
}
|
|
33766
|
-
const config2 = await readConfigFile(
|
|
34219
|
+
const config2 = await readConfigFile(configPath2);
|
|
33767
34220
|
if (config2) {
|
|
33768
34221
|
return config2;
|
|
33769
34222
|
}
|
|
33770
34223
|
}
|
|
33771
34224
|
return await fileExists3(globalConfigPath) ? readConfigFile(globalConfigPath) : null;
|
|
33772
34225
|
}
|
|
33773
|
-
async function readConfigFile(
|
|
34226
|
+
async function readConfigFile(configPath2) {
|
|
33774
34227
|
try {
|
|
33775
|
-
const rawConfig = await readFile13(
|
|
34228
|
+
const rawConfig = await readFile13(configPath2, "utf8");
|
|
33776
34229
|
const parsed = interpolateEnv(parseYamlValue(rawConfig), process.env);
|
|
33777
34230
|
if (!isJsonObject(parsed)) {
|
|
33778
|
-
logWarning(`Invalid config.yaml format at ${
|
|
34231
|
+
logWarning(`Invalid config.yaml format at ${configPath2}`);
|
|
33779
34232
|
return null;
|
|
33780
34233
|
}
|
|
33781
34234
|
const config2 = parsed;
|
|
33782
34235
|
const requiredVersion = parsed.required_version;
|
|
33783
34236
|
if (requiredVersion !== void 0 && typeof requiredVersion !== "string") {
|
|
33784
|
-
logWarning(`Invalid required_version in ${
|
|
34237
|
+
logWarning(`Invalid required_version in ${configPath2}, expected string`);
|
|
33785
34238
|
return null;
|
|
33786
34239
|
}
|
|
33787
34240
|
const evalPatterns = config2.eval_patterns;
|
|
33788
34241
|
if (evalPatterns !== void 0 && !Array.isArray(evalPatterns)) {
|
|
33789
|
-
logWarning(`Invalid eval_patterns in ${
|
|
34242
|
+
logWarning(`Invalid eval_patterns in ${configPath2}, expected array`);
|
|
33790
34243
|
return null;
|
|
33791
34244
|
}
|
|
33792
34245
|
if (Array.isArray(evalPatterns) && !evalPatterns.every((p) => typeof p === "string")) {
|
|
33793
|
-
logWarning(`Invalid eval_patterns in ${
|
|
34246
|
+
logWarning(`Invalid eval_patterns in ${configPath2}, all entries must be strings`);
|
|
33794
34247
|
return null;
|
|
33795
34248
|
}
|
|
33796
34249
|
const executionDefaults = parseExecutionDefaults(
|
|
33797
34250
|
parsed.execution,
|
|
33798
|
-
|
|
34251
|
+
configPath2
|
|
33799
34252
|
);
|
|
33800
|
-
const results = parseResultsConfig(parsed.results,
|
|
33801
|
-
const hooks = parseHooksConfig(parsed.hooks,
|
|
34253
|
+
const results = parseResultsConfig(parsed.results, configPath2);
|
|
34254
|
+
const hooks = parseHooksConfig(parsed.hooks, configPath2);
|
|
33802
34255
|
return {
|
|
33803
34256
|
required_version: requiredVersion,
|
|
33804
34257
|
eval_patterns: evalPatterns,
|
|
@@ -33807,7 +34260,7 @@ async function readConfigFile(configPath) {
|
|
|
33807
34260
|
...hooks && { hooks }
|
|
33808
34261
|
};
|
|
33809
34262
|
} catch (error40) {
|
|
33810
|
-
logWarning(`Could not read config.yaml at ${
|
|
34263
|
+
logWarning(`Could not read config.yaml at ${configPath2}: ${error40.message}`);
|
|
33811
34264
|
return null;
|
|
33812
34265
|
}
|
|
33813
34266
|
}
|
|
@@ -34045,7 +34498,7 @@ function extractThreshold(suite) {
|
|
|
34045
34498
|
logWarning(`Invalid execution.threshold: ${raw}. Must be a number between 0 and 1. Ignoring.`);
|
|
34046
34499
|
return void 0;
|
|
34047
34500
|
}
|
|
34048
|
-
function parseExecutionDefaults(raw,
|
|
34501
|
+
function parseExecutionDefaults(raw, configPath2) {
|
|
34049
34502
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
34050
34503
|
return void 0;
|
|
34051
34504
|
}
|
|
@@ -34054,78 +34507,78 @@ function parseExecutionDefaults(raw, configPath) {
|
|
|
34054
34507
|
if (typeof obj.verbose === "boolean") {
|
|
34055
34508
|
result.verbose = obj.verbose;
|
|
34056
34509
|
} else if (obj.verbose !== void 0) {
|
|
34057
|
-
logWarning(`Invalid execution.verbose in ${
|
|
34510
|
+
logWarning(`Invalid execution.verbose in ${configPath2}, expected boolean`);
|
|
34058
34511
|
}
|
|
34059
34512
|
if (typeof obj.keep_workspaces === "boolean") {
|
|
34060
34513
|
result.keep_workspaces = obj.keep_workspaces;
|
|
34061
34514
|
} else if (obj.keep_workspaces !== void 0) {
|
|
34062
|
-
logWarning(`Invalid execution.keep_workspaces in ${
|
|
34515
|
+
logWarning(`Invalid execution.keep_workspaces in ${configPath2}, expected boolean`);
|
|
34063
34516
|
}
|
|
34064
34517
|
const otelFile = obj.otel_file;
|
|
34065
34518
|
if (typeof otelFile === "string" && otelFile.trim().length > 0) {
|
|
34066
34519
|
result.otel_file = otelFile.trim();
|
|
34067
34520
|
} else if (otelFile !== void 0) {
|
|
34068
|
-
logWarning(`Invalid execution.otel_file in ${
|
|
34521
|
+
logWarning(`Invalid execution.otel_file in ${configPath2}, expected non-empty string`);
|
|
34069
34522
|
}
|
|
34070
34523
|
if (typeof obj.export_otel === "boolean") {
|
|
34071
34524
|
result.export_otel = obj.export_otel;
|
|
34072
34525
|
} else if (obj.export_otel !== void 0) {
|
|
34073
|
-
logWarning(`Invalid execution.export_otel in ${
|
|
34526
|
+
logWarning(`Invalid execution.export_otel in ${configPath2}, expected boolean`);
|
|
34074
34527
|
}
|
|
34075
34528
|
const otelBackend = obj.otel_backend;
|
|
34076
34529
|
if (typeof otelBackend === "string" && otelBackend.trim().length > 0) {
|
|
34077
34530
|
result.otel_backend = otelBackend.trim();
|
|
34078
34531
|
} else if (otelBackend !== void 0) {
|
|
34079
|
-
logWarning(`Invalid execution.otel_backend in ${
|
|
34532
|
+
logWarning(`Invalid execution.otel_backend in ${configPath2}, expected non-empty string`);
|
|
34080
34533
|
}
|
|
34081
34534
|
if (typeof obj.otel_capture_content === "boolean") {
|
|
34082
34535
|
result.otel_capture_content = obj.otel_capture_content;
|
|
34083
34536
|
} else if (obj.otel_capture_content !== void 0) {
|
|
34084
|
-
logWarning(`Invalid execution.otel_capture_content in ${
|
|
34537
|
+
logWarning(`Invalid execution.otel_capture_content in ${configPath2}, expected boolean`);
|
|
34085
34538
|
}
|
|
34086
34539
|
if (typeof obj.otel_group_turns === "boolean") {
|
|
34087
34540
|
result.otel_group_turns = obj.otel_group_turns;
|
|
34088
34541
|
} else if (obj.otel_group_turns !== void 0) {
|
|
34089
|
-
logWarning(`Invalid execution.otel_group_turns in ${
|
|
34542
|
+
logWarning(`Invalid execution.otel_group_turns in ${configPath2}, expected boolean`);
|
|
34090
34543
|
}
|
|
34091
34544
|
if (typeof obj.pool_workspaces === "boolean") {
|
|
34092
34545
|
result.pool_workspaces = obj.pool_workspaces;
|
|
34093
34546
|
} else if (obj.pool_workspaces !== void 0) {
|
|
34094
|
-
logWarning(`Invalid execution.pool_workspaces in ${
|
|
34547
|
+
logWarning(`Invalid execution.pool_workspaces in ${configPath2}, expected boolean`);
|
|
34095
34548
|
}
|
|
34096
34549
|
const poolSlots = obj.pool_slots;
|
|
34097
34550
|
if (typeof poolSlots === "number" && Number.isInteger(poolSlots) && poolSlots >= 1 && poolSlots <= 50) {
|
|
34098
34551
|
result.pool_slots = poolSlots;
|
|
34099
34552
|
} else if (poolSlots !== void 0) {
|
|
34100
|
-
logWarning(`Invalid execution.pool_slots in ${
|
|
34553
|
+
logWarning(`Invalid execution.pool_slots in ${configPath2}, expected integer 1-50`);
|
|
34101
34554
|
}
|
|
34102
34555
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
34103
34556
|
}
|
|
34104
34557
|
function isFilesystemPath(p) {
|
|
34105
34558
|
return p.startsWith("/") || p.startsWith("~/") || p.startsWith("~\\") || p === "~" || /^[A-Za-z]:[/\\]/.test(p);
|
|
34106
34559
|
}
|
|
34107
|
-
function parseResultsConfig(raw,
|
|
34560
|
+
function parseResultsConfig(raw, configPath2) {
|
|
34108
34561
|
if (raw === void 0 || raw === null) {
|
|
34109
34562
|
return void 0;
|
|
34110
34563
|
}
|
|
34111
34564
|
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
34112
|
-
logWarning(`Invalid results in ${
|
|
34565
|
+
logWarning(`Invalid results in ${configPath2}, expected object`);
|
|
34113
34566
|
return void 0;
|
|
34114
34567
|
}
|
|
34115
34568
|
const obj = raw;
|
|
34116
34569
|
if (obj.mode !== "github") {
|
|
34117
|
-
logWarning(`Invalid results.mode in ${
|
|
34570
|
+
logWarning(`Invalid results.mode in ${configPath2}, expected 'github'`);
|
|
34118
34571
|
return void 0;
|
|
34119
34572
|
}
|
|
34120
34573
|
const repo = typeof obj.repo === "string" ? obj.repo.trim() : "";
|
|
34121
34574
|
if (!repo) {
|
|
34122
|
-
logWarning(`Invalid results.repo in ${
|
|
34575
|
+
logWarning(`Invalid results.repo in ${configPath2}, expected non-empty string`);
|
|
34123
34576
|
return void 0;
|
|
34124
34577
|
}
|
|
34125
34578
|
let branch;
|
|
34126
34579
|
if (obj.branch !== void 0) {
|
|
34127
34580
|
if (typeof obj.branch !== "string" || obj.branch.trim().length === 0) {
|
|
34128
|
-
logWarning(`Invalid results.branch in ${
|
|
34581
|
+
logWarning(`Invalid results.branch in ${configPath2}, expected non-empty string`);
|
|
34129
34582
|
return void 0;
|
|
34130
34583
|
}
|
|
34131
34584
|
branch = obj.branch.trim();
|
|
@@ -34133,26 +34586,26 @@ function parseResultsConfig(raw, configPath) {
|
|
|
34133
34586
|
let resultsPath;
|
|
34134
34587
|
if (obj.path !== void 0) {
|
|
34135
34588
|
if (typeof obj.path !== "string" || obj.path.trim().length === 0) {
|
|
34136
|
-
logWarning(`Invalid results.path in ${
|
|
34589
|
+
logWarning(`Invalid results.path in ${configPath2}, expected non-empty string`);
|
|
34137
34590
|
return void 0;
|
|
34138
34591
|
}
|
|
34139
34592
|
const trimmedPath = obj.path.trim();
|
|
34140
34593
|
if (!isFilesystemPath(trimmedPath)) {
|
|
34141
34594
|
logWarning(
|
|
34142
|
-
`Invalid results.path in ${
|
|
34595
|
+
`Invalid results.path in ${configPath2}: '${trimmedPath}' looks like a repo subdirectory. results.path now specifies the local filesystem directory for the clone (e.g., ~/data/agentv-results). Remove 'path' to use the default or set an absolute/home-relative path.`
|
|
34143
34596
|
);
|
|
34144
34597
|
return void 0;
|
|
34145
34598
|
}
|
|
34146
34599
|
resultsPath = trimmedPath;
|
|
34147
34600
|
}
|
|
34148
34601
|
if (obj.auto_push !== void 0 && typeof obj.auto_push !== "boolean") {
|
|
34149
|
-
logWarning(`Invalid results.auto_push in ${
|
|
34602
|
+
logWarning(`Invalid results.auto_push in ${configPath2}, expected boolean`);
|
|
34150
34603
|
return void 0;
|
|
34151
34604
|
}
|
|
34152
34605
|
let branchPrefix;
|
|
34153
34606
|
if (obj.branch_prefix !== void 0) {
|
|
34154
34607
|
if (typeof obj.branch_prefix !== "string" || obj.branch_prefix.trim().length === 0) {
|
|
34155
|
-
logWarning(`Invalid results.branch_prefix in ${
|
|
34608
|
+
logWarning(`Invalid results.branch_prefix in ${configPath2}, expected non-empty string`);
|
|
34156
34609
|
return void 0;
|
|
34157
34610
|
}
|
|
34158
34611
|
branchPrefix = obj.branch_prefix.trim();
|
|
@@ -34172,19 +34625,19 @@ function resolveResultsConfigForProject(config2, _projectId) {
|
|
|
34172
34625
|
}
|
|
34173
34626
|
return config2.results;
|
|
34174
34627
|
}
|
|
34175
|
-
function parseHooksConfig(raw,
|
|
34628
|
+
function parseHooksConfig(raw, configPath2) {
|
|
34176
34629
|
if (raw === void 0 || raw === null) {
|
|
34177
34630
|
return void 0;
|
|
34178
34631
|
}
|
|
34179
34632
|
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
34180
|
-
logWarning(`Invalid hooks in ${
|
|
34633
|
+
logWarning(`Invalid hooks in ${configPath2}, expected object`);
|
|
34181
34634
|
return void 0;
|
|
34182
34635
|
}
|
|
34183
34636
|
const obj = raw;
|
|
34184
34637
|
const beforeSession = obj.before_session;
|
|
34185
34638
|
if (beforeSession !== void 0) {
|
|
34186
34639
|
if (typeof beforeSession !== "string" || beforeSession.trim().length === 0) {
|
|
34187
|
-
logWarning(`Invalid hooks.before_session in ${
|
|
34640
|
+
logWarning(`Invalid hooks.before_session in ${configPath2}, expected non-empty string`);
|
|
34188
34641
|
return void 0;
|
|
34189
34642
|
}
|
|
34190
34643
|
return { before_session: beforeSession.trim() };
|
|
@@ -34286,8 +34739,8 @@ function isTemplateReference(value) {
|
|
|
34286
34739
|
}
|
|
34287
34740
|
async function resolveAssertionTemplateReference(include, searchRoots) {
|
|
34288
34741
|
const templateCandidates = isTemplateReference(include) ? [
|
|
34289
|
-
|
|
34290
|
-
|
|
34742
|
+
path422.join(".agentv", "templates", `${include}.yaml`),
|
|
34743
|
+
path422.join(".agentv", "templates", `${include}.yml`)
|
|
34291
34744
|
] : [include];
|
|
34292
34745
|
const attempted = [];
|
|
34293
34746
|
for (const candidate of templateCandidates) {
|
|
@@ -34340,10 +34793,10 @@ ${resolved.attempted.map((attempt) => ` Tried: ${attempt}`).join("\n")}` : "";
|
|
|
34340
34793
|
`Invalid assertion template file in '${evalId}': ${resolved.resolvedPath} is missing a top-level assertions array`
|
|
34341
34794
|
);
|
|
34342
34795
|
}
|
|
34343
|
-
const templateDir =
|
|
34796
|
+
const templateDir = path422.dirname(resolved.resolvedPath);
|
|
34344
34797
|
const nestedSearchRoots = [
|
|
34345
34798
|
templateDir,
|
|
34346
|
-
...searchRoots.filter((root) =>
|
|
34799
|
+
...searchRoots.filter((root) => path422.resolve(root) !== templateDir)
|
|
34347
34800
|
];
|
|
34348
34801
|
return await expandGraderEntries(assertions, nestedSearchRoots, evalId, {
|
|
34349
34802
|
depth: nextDepth,
|
|
@@ -34404,7 +34857,7 @@ async function collectAssertionTemplateReferencesFromValue(value, searchRoots, e
|
|
|
34404
34857
|
references.push({
|
|
34405
34858
|
kind: "assertion_template",
|
|
34406
34859
|
displayPath: resolved.displayPath,
|
|
34407
|
-
...resolved.resolvedPath ? { resolvedPath:
|
|
34860
|
+
...resolved.resolvedPath ? { resolvedPath: path422.resolve(resolved.resolvedPath) } : {}
|
|
34408
34861
|
});
|
|
34409
34862
|
if (resolved.resolvedPath) {
|
|
34410
34863
|
if (includeContext.chain.includes(resolved.resolvedPath)) {
|
|
@@ -34414,10 +34867,10 @@ async function collectAssertionTemplateReferencesFromValue(value, searchRoots, e
|
|
|
34414
34867
|
const content = await readFile15(resolved.resolvedPath, "utf8");
|
|
34415
34868
|
const parsed = interpolateEnv(parseYamlValue(content), process.env);
|
|
34416
34869
|
if (isJsonObject2(parsed) && Array.isArray(parsed.assertions)) {
|
|
34417
|
-
const templateDir =
|
|
34870
|
+
const templateDir = path422.dirname(resolved.resolvedPath);
|
|
34418
34871
|
const nestedSearchRoots = [
|
|
34419
34872
|
templateDir,
|
|
34420
|
-
...searchRoots.filter((root) =>
|
|
34873
|
+
...searchRoots.filter((root) => path422.resolve(root) !== templateDir)
|
|
34421
34874
|
];
|
|
34422
34875
|
references.push(
|
|
34423
34876
|
...await collectAssertionTemplateReferencesFromValue(
|
|
@@ -34603,7 +35056,7 @@ async function parseGraderList(candidateEvaluators, searchRoots, evalId, default
|
|
|
34603
35056
|
if (cwd) {
|
|
34604
35057
|
const resolved = await resolveFileReference3(cwd, searchRoots);
|
|
34605
35058
|
if (resolved.resolvedPath) {
|
|
34606
|
-
resolvedCwd =
|
|
35059
|
+
resolvedCwd = path422.resolve(resolved.resolvedPath);
|
|
34607
35060
|
} else {
|
|
34608
35061
|
logWarning2(
|
|
34609
35062
|
`Code-grader evaluator '${name}' in '${evalId}': cwd not found (${resolved.displayPath})`,
|
|
@@ -34789,7 +35242,7 @@ async function parseGraderList(candidateEvaluators, searchRoots, evalId, default
|
|
|
34789
35242
|
aggregatorPrompt = fileRef;
|
|
34790
35243
|
const resolved = await resolveFileReference3(fileRef, searchRoots);
|
|
34791
35244
|
if (resolved.resolvedPath) {
|
|
34792
|
-
promptPath2 =
|
|
35245
|
+
promptPath2 = path422.resolve(resolved.resolvedPath);
|
|
34793
35246
|
} else {
|
|
34794
35247
|
throw new Error(
|
|
34795
35248
|
`Composite aggregator in '${evalId}': prompt file not found: ${resolved.displayPath}`
|
|
@@ -35469,7 +35922,7 @@ async function parseGraderList(candidateEvaluators, searchRoots, evalId, default
|
|
|
35469
35922
|
const commandPath = commandArray[commandArray.length - 1];
|
|
35470
35923
|
const resolved = await resolveFileReference3(commandPath, searchRoots);
|
|
35471
35924
|
if (resolved.resolvedPath) {
|
|
35472
|
-
resolvedPromptScript = [...commandArray.slice(0, -1),
|
|
35925
|
+
resolvedPromptScript = [...commandArray.slice(0, -1), path422.resolve(resolved.resolvedPath)];
|
|
35473
35926
|
} else {
|
|
35474
35927
|
throw new Error(
|
|
35475
35928
|
`Grader '${name}' in '${evalId}': prompt command file not found: ${resolved.displayPath}`
|
|
@@ -35484,7 +35937,7 @@ async function parseGraderList(candidateEvaluators, searchRoots, evalId, default
|
|
|
35484
35937
|
prompt = fileRef;
|
|
35485
35938
|
const resolved = await resolveFileReference3(fileRef, searchRoots);
|
|
35486
35939
|
if (resolved.resolvedPath) {
|
|
35487
|
-
promptPath =
|
|
35940
|
+
promptPath = path422.resolve(resolved.resolvedPath);
|
|
35488
35941
|
try {
|
|
35489
35942
|
await validateCustomPromptContent(promptPath);
|
|
35490
35943
|
} catch (error40) {
|
|
@@ -35642,7 +36095,7 @@ async function parsePreprocessors(rawValue, searchRoots, evaluatorName, evalId)
|
|
|
35642
36095
|
preprocessors.push({
|
|
35643
36096
|
type,
|
|
35644
36097
|
command,
|
|
35645
|
-
resolvedCommand: [...command.slice(0, -1),
|
|
36098
|
+
resolvedCommand: [...command.slice(0, -1), path422.resolve(resolved.resolvedPath)]
|
|
35646
36099
|
});
|
|
35647
36100
|
}
|
|
35648
36101
|
return preprocessors;
|
|
@@ -35737,10 +36190,10 @@ async function resolveOptionalCommandSource(command, searchRoots) {
|
|
|
35737
36190
|
return void 0;
|
|
35738
36191
|
}
|
|
35739
36192
|
const resolved = await resolveFileReference3(candidate, searchRoots);
|
|
35740
|
-
return resolved.resolvedPath ?
|
|
36193
|
+
return resolved.resolvedPath ? path422.resolve(resolved.resolvedPath) : void 0;
|
|
35741
36194
|
}
|
|
35742
36195
|
function looksLikeFilePath(value) {
|
|
35743
|
-
return
|
|
36196
|
+
return path422.isAbsolute(value) || value.startsWith(".") || value.includes("/") || value.includes("\\") || /\.[cm]?[jt]sx?$|\.py$|\.sh$|\.bash$|\.rb$|\.go$|\.rs$/i.test(value);
|
|
35744
36197
|
}
|
|
35745
36198
|
function parseCommandToArgv(command) {
|
|
35746
36199
|
if (process.platform === "win32") {
|
|
@@ -36128,7 +36581,7 @@ var IMAGE_MEDIA_TYPES = {
|
|
|
36128
36581
|
".bmp": "image/bmp"
|
|
36129
36582
|
};
|
|
36130
36583
|
function detectImageMediaType(filePath) {
|
|
36131
|
-
const ext =
|
|
36584
|
+
const ext = path43.extname(filePath).toLowerCase();
|
|
36132
36585
|
return IMAGE_MEDIA_TYPES[ext];
|
|
36133
36586
|
}
|
|
36134
36587
|
var ANSI_YELLOW5 = "\x1B[33m";
|
|
@@ -36192,7 +36645,7 @@ async function processMessages(options) {
|
|
|
36192
36645
|
...cloneJsonObject(rawSegment),
|
|
36193
36646
|
path: displayPath,
|
|
36194
36647
|
text: fileContent,
|
|
36195
|
-
resolvedPath:
|
|
36648
|
+
resolvedPath: path43.resolve(resolvedPath)
|
|
36196
36649
|
});
|
|
36197
36650
|
if (verbose) {
|
|
36198
36651
|
const label = messageType === "input" ? "[File]" : "[Expected Output File]";
|
|
@@ -36316,7 +36769,7 @@ async function processExpectedMessages(options) {
|
|
|
36316
36769
|
type: "file",
|
|
36317
36770
|
path: displayPath,
|
|
36318
36771
|
text: fileContent,
|
|
36319
|
-
resolvedPath:
|
|
36772
|
+
resolvedPath: path43.resolve(resolvedPath)
|
|
36320
36773
|
});
|
|
36321
36774
|
if (verbose) {
|
|
36322
36775
|
console.log(` [Expected Output File] Found: ${displayPath}`);
|
|
@@ -36462,7 +36915,7 @@ function matchesFilter(id, filter) {
|
|
|
36462
36915
|
return typeof filter === "string" ? micromatch.isMatch(id, filter) : filter.some((pattern) => micromatch.isMatch(id, pattern));
|
|
36463
36916
|
}
|
|
36464
36917
|
function detectFormat(filePath) {
|
|
36465
|
-
const ext =
|
|
36918
|
+
const ext = path44.extname(filePath).toLowerCase();
|
|
36466
36919
|
if (ext === ".jsonl") return "jsonl";
|
|
36467
36920
|
if (ext === ".yaml" || ext === ".yml") return "yaml";
|
|
36468
36921
|
if (ext === ".json") return "agent-skills-json";
|
|
@@ -36472,9 +36925,9 @@ function detectFormat(filePath) {
|
|
|
36472
36925
|
);
|
|
36473
36926
|
}
|
|
36474
36927
|
async function loadSidecarMetadata(jsonlPath, verbose) {
|
|
36475
|
-
const dir =
|
|
36476
|
-
const base =
|
|
36477
|
-
const sidecarPath =
|
|
36928
|
+
const dir = path44.dirname(jsonlPath);
|
|
36929
|
+
const base = path44.basename(jsonlPath, ".jsonl");
|
|
36930
|
+
const sidecarPath = path44.join(dir, `${base}.yaml`);
|
|
36478
36931
|
if (!await fileExists3(sidecarPath)) {
|
|
36479
36932
|
if (verbose) {
|
|
36480
36933
|
logWarning4(`Sidecar metadata file not found: ${sidecarPath} (using defaults)`);
|
|
@@ -36523,13 +36976,13 @@ function parseJsonlContent(content, filePath) {
|
|
|
36523
36976
|
async function loadTestsFromJsonl(evalFilePath, repoRoot, options) {
|
|
36524
36977
|
const verbose = options?.verbose ?? false;
|
|
36525
36978
|
const filterPattern = options?.filter;
|
|
36526
|
-
const absoluteTestPath =
|
|
36979
|
+
const absoluteTestPath = path44.resolve(evalFilePath);
|
|
36527
36980
|
const repoRootPath = resolveToAbsolutePath(repoRoot);
|
|
36528
36981
|
const searchRoots = buildSearchRoots2(absoluteTestPath, repoRootPath);
|
|
36529
36982
|
const sidecar = await loadSidecarMetadata(absoluteTestPath, verbose);
|
|
36530
36983
|
const rawFile = await readFile17(absoluteTestPath, "utf8");
|
|
36531
36984
|
const rawCases = parseJsonlContent(rawFile, evalFilePath);
|
|
36532
|
-
const fallbackSuiteName =
|
|
36985
|
+
const fallbackSuiteName = path44.basename(absoluteTestPath, ".jsonl") || "eval";
|
|
36533
36986
|
const suiteName = sidecar.name && sidecar.name.trim().length > 0 ? sidecar.name : fallbackSuiteName;
|
|
36534
36987
|
const globalEvaluator = coerceEvaluator(sidecar.evaluator, "sidecar") ?? "llm-grader";
|
|
36535
36988
|
const globalExecution = sidecar.execution;
|
|
@@ -36687,60 +37140,51 @@ function parseMetadata(suite) {
|
|
|
36687
37140
|
requires: suite.requires
|
|
36688
37141
|
});
|
|
36689
37142
|
}
|
|
36690
|
-
function
|
|
37143
|
+
function readString(obj, key) {
|
|
37144
|
+
const value = obj[key];
|
|
37145
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
37146
|
+
}
|
|
37147
|
+
function readStringArray(obj, key) {
|
|
37148
|
+
const value = obj[key];
|
|
37149
|
+
if (!Array.isArray(value)) return void 0;
|
|
37150
|
+
const strings = value.filter((item) => typeof item === "string");
|
|
37151
|
+
return strings.length > 0 ? strings : void 0;
|
|
37152
|
+
}
|
|
37153
|
+
function parseRepoConfig(raw) {
|
|
36691
37154
|
if (!isJsonObject(raw)) return void 0;
|
|
36692
37155
|
const obj = raw;
|
|
36693
|
-
if (
|
|
36694
|
-
|
|
37156
|
+
if ("source" in obj) {
|
|
37157
|
+
throw new Error("workspace.repos[].source has been removed. Use workspace.repos[].repo.");
|
|
37158
|
+
}
|
|
37159
|
+
if ("checkout" in obj) {
|
|
37160
|
+
throw new Error(
|
|
37161
|
+
"workspace.repos[].checkout has been removed. Use top-level commit, base_commit, and ancestor."
|
|
37162
|
+
);
|
|
36695
37163
|
}
|
|
36696
|
-
if (
|
|
36697
|
-
|
|
37164
|
+
if ("clone" in obj) {
|
|
37165
|
+
throw new Error("workspace.repos[].clone has been removed. Use top-level sparse if needed.");
|
|
36698
37166
|
}
|
|
36699
|
-
|
|
36700
|
-
|
|
36701
|
-
|
|
36702
|
-
|
|
36703
|
-
const obj = raw;
|
|
36704
|
-
const ref = typeof obj.ref === "string" ? obj.ref : void 0;
|
|
36705
|
-
const baseCommit = typeof obj.base_commit === "string" ? obj.base_commit : void 0;
|
|
36706
|
-
const resolve = obj.resolve === "remote" || obj.resolve === "local" ? obj.resolve : void 0;
|
|
37167
|
+
const repoPath = readString(obj, "path");
|
|
37168
|
+
const repo = readString(obj, "repo");
|
|
37169
|
+
const commit = readString(obj, "commit");
|
|
37170
|
+
const baseCommit = readString(obj, "base_commit");
|
|
36707
37171
|
const ancestor = typeof obj.ancestor === "number" ? obj.ancestor : void 0;
|
|
36708
|
-
|
|
37172
|
+
const sparse = readStringArray(obj, "sparse");
|
|
37173
|
+
if (commit !== void 0 && baseCommit !== void 0 && commit !== baseCommit) {
|
|
37174
|
+
throw new Error("workspace.repos[].commit and workspace.repos[].base_commit must match.");
|
|
37175
|
+
}
|
|
37176
|
+
if (!repoPath && !repo && !commit && !baseCommit && ancestor === void 0 && !sparse) {
|
|
37177
|
+
return void 0;
|
|
37178
|
+
}
|
|
36709
37179
|
return {
|
|
36710
|
-
...
|
|
37180
|
+
...repoPath !== void 0 && { path: repoPath },
|
|
37181
|
+
...repo !== void 0 && { repo },
|
|
37182
|
+
...commit !== void 0 && { commit },
|
|
36711
37183
|
...baseCommit !== void 0 && { base_commit: baseCommit },
|
|
36712
|
-
...
|
|
36713
|
-
...ancestor !== void 0 && { ancestor }
|
|
36714
|
-
};
|
|
36715
|
-
}
|
|
36716
|
-
function parseRepoClone(raw) {
|
|
36717
|
-
if (!isJsonObject(raw)) return void 0;
|
|
36718
|
-
const obj = raw;
|
|
36719
|
-
const depth = typeof obj.depth === "number" ? obj.depth : void 0;
|
|
36720
|
-
const filter = typeof obj.filter === "string" ? obj.filter : void 0;
|
|
36721
|
-
const sparse = Array.isArray(obj.sparse) ? obj.sparse.filter((s) => typeof s === "string") : void 0;
|
|
36722
|
-
if (depth === void 0 && !filter && !sparse) return void 0;
|
|
36723
|
-
return {
|
|
36724
|
-
...depth !== void 0 && { depth },
|
|
36725
|
-
...filter !== void 0 && { filter },
|
|
37184
|
+
...ancestor !== void 0 && { ancestor },
|
|
36726
37185
|
...sparse !== void 0 && { sparse }
|
|
36727
37186
|
};
|
|
36728
37187
|
}
|
|
36729
|
-
function parseRepoConfig(raw) {
|
|
36730
|
-
if (!isJsonObject(raw)) return void 0;
|
|
36731
|
-
const obj = raw;
|
|
36732
|
-
const repoPath = typeof obj.path === "string" ? obj.path : void 0;
|
|
36733
|
-
const source = parseRepoSource(obj.source);
|
|
36734
|
-
const checkout = parseRepoCheckout(obj.checkout);
|
|
36735
|
-
const clone2 = parseRepoClone(obj.clone);
|
|
36736
|
-
if (!repoPath && !source && !checkout && !clone2) return void 0;
|
|
36737
|
-
return {
|
|
36738
|
-
...repoPath !== void 0 && { path: repoPath },
|
|
36739
|
-
...source !== void 0 && { source },
|
|
36740
|
-
...checkout !== void 0 && { checkout },
|
|
36741
|
-
...clone2 !== void 0 && { clone: clone2 }
|
|
36742
|
-
};
|
|
36743
|
-
}
|
|
36744
37188
|
async function buildPromptInputs(testCase, mode = "lm") {
|
|
36745
37189
|
const segmentsByMessage = testCase.input.map(
|
|
36746
37190
|
(message) => extractContentSegments(message.content)
|
|
@@ -36935,7 +37379,7 @@ function interpolateRawEvalCase(raw, vars) {
|
|
|
36935
37379
|
}
|
|
36936
37380
|
async function readTestSuiteMetadata(testFilePath) {
|
|
36937
37381
|
try {
|
|
36938
|
-
const absolutePath =
|
|
37382
|
+
const absolutePath = path45.resolve(testFilePath);
|
|
36939
37383
|
const content = await readFile18(absolutePath, "utf8");
|
|
36940
37384
|
const parsed = interpolateEnv(parseYamlValue(content), process.env);
|
|
36941
37385
|
if (!isJsonObject(parsed)) {
|
|
@@ -36960,7 +37404,7 @@ async function loadTestSuite(evalFilePath, repoRoot, options) {
|
|
|
36960
37404
|
return { tests: await loadTestsFromAgentSkills(evalFilePath) };
|
|
36961
37405
|
}
|
|
36962
37406
|
if (format === "typescript") {
|
|
36963
|
-
const { loadTsEvalSuite: loadTsEvalSuite2 } = await import("./ts-eval-loader-
|
|
37407
|
+
const { loadTsEvalSuite: loadTsEvalSuite2 } = await import("./ts-eval-loader-TJT6BGFF-DI7XNSO4.js");
|
|
36964
37408
|
return loadTsEvalSuite2(evalFilePath, resolveToAbsolutePath(repoRoot), options);
|
|
36965
37409
|
}
|
|
36966
37410
|
const { tests, parsed, suiteWorkspacePath } = await loadTestsFromYaml(
|
|
@@ -36995,7 +37439,7 @@ async function loadTests(evalFilePath, repoRoot, options) {
|
|
|
36995
37439
|
return loadTestsFromAgentSkills(evalFilePath);
|
|
36996
37440
|
}
|
|
36997
37441
|
if (format === "typescript") {
|
|
36998
|
-
const { loadTsEvalSuite: loadTsEvalSuite2 } = await import("./ts-eval-loader-
|
|
37442
|
+
const { loadTsEvalSuite: loadTsEvalSuite2 } = await import("./ts-eval-loader-TJT6BGFF-DI7XNSO4.js");
|
|
36999
37443
|
const suite = await loadTsEvalSuite2(evalFilePath, resolveToAbsolutePath(repoRoot), options);
|
|
37000
37444
|
return suite.tests;
|
|
37001
37445
|
}
|
|
@@ -37006,7 +37450,7 @@ var loadEvalCases = loadTests;
|
|
|
37006
37450
|
async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
|
|
37007
37451
|
const verbose = options?.verbose ?? false;
|
|
37008
37452
|
const filterPattern = options?.filter;
|
|
37009
|
-
const absoluteTestPath =
|
|
37453
|
+
const absoluteTestPath = path45.resolve(evalFilePath);
|
|
37010
37454
|
const repoRootPath = resolveToAbsolutePath(repoRoot);
|
|
37011
37455
|
const searchRoots = buildSearchRoots2(absoluteTestPath, repoRootPath);
|
|
37012
37456
|
const config2 = await loadConfig(absoluteTestPath, repoRootPath);
|
|
@@ -37019,7 +37463,7 @@ async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
|
|
|
37019
37463
|
}
|
|
37020
37464
|
const suite = interpolated;
|
|
37021
37465
|
const suiteNameFromFile = asString5(suite.name)?.trim();
|
|
37022
|
-
const fallbackSuiteName =
|
|
37466
|
+
const fallbackSuiteName = path45.basename(absoluteTestPath).replace(/\.eval\.ya?ml$/i, "").replace(/\.ya?ml$/i, "") || "eval";
|
|
37023
37467
|
const suiteName = suiteNameFromFile && suiteNameFromFile.length > 0 ? suiteNameFromFile : fallbackSuiteName;
|
|
37024
37468
|
const rawTestCases = resolveTests(suite);
|
|
37025
37469
|
const globalEvaluator = coerceEvaluator(suite.evaluator, "global") ?? "llm-grader";
|
|
@@ -37029,10 +37473,10 @@ async function loadTestsFromYaml(evalFilePath, repoRoot, options) {
|
|
|
37029
37473
|
"<suite>",
|
|
37030
37474
|
absoluteTestPath
|
|
37031
37475
|
);
|
|
37032
|
-
const evalFileDir =
|
|
37476
|
+
const evalFileDir = path45.dirname(absoluteTestPath);
|
|
37033
37477
|
let expandedTestCases;
|
|
37034
37478
|
if (typeof rawTestCases === "string") {
|
|
37035
|
-
const externalPath =
|
|
37479
|
+
const externalPath = path45.resolve(evalFileDir, rawTestCases);
|
|
37036
37480
|
let isDir = false;
|
|
37037
37481
|
try {
|
|
37038
37482
|
const pathStat = await stat8(externalPath);
|
|
@@ -37266,7 +37710,7 @@ function buildEvalTestSource(params) {
|
|
|
37266
37710
|
};
|
|
37267
37711
|
}
|
|
37268
37712
|
function stringifySourceYaml(value) {
|
|
37269
|
-
return
|
|
37713
|
+
return stringifyYaml2(sanitizeSourceValue(value), { lineWidth: 0 }).trimEnd();
|
|
37270
37714
|
}
|
|
37271
37715
|
function sanitizeSourceValue(value, keyHint) {
|
|
37272
37716
|
if (keyHint && SOURCE_SECRET_KEY_PATTERN.test(keyHint)) {
|
|
@@ -37336,7 +37780,7 @@ function collectInputSourceReferences(inputMessages) {
|
|
|
37336
37780
|
references.push({
|
|
37337
37781
|
kind: "input_file",
|
|
37338
37782
|
displayPath,
|
|
37339
|
-
...typeof segment.resolvedPath === "string" ? { resolvedPath:
|
|
37783
|
+
...typeof segment.resolvedPath === "string" ? { resolvedPath: path45.resolve(segment.resolvedPath) } : {}
|
|
37340
37784
|
});
|
|
37341
37785
|
}
|
|
37342
37786
|
}
|
|
@@ -37409,7 +37853,7 @@ function collectSingleGraderSourceReferences(evaluator) {
|
|
|
37409
37853
|
references.push({
|
|
37410
37854
|
kind: "code_grader_command",
|
|
37411
37855
|
displayPath: evaluator.aggregator.path,
|
|
37412
|
-
resolvedPath:
|
|
37856
|
+
resolvedPath: path45.resolve(evaluator.aggregator.cwd ?? "", evaluator.aggregator.path),
|
|
37413
37857
|
graderName: evaluator.name
|
|
37414
37858
|
});
|
|
37415
37859
|
} else if (evaluator.aggregator.type === "llm-grader" && evaluator.aggregator.promptPath) {
|
|
@@ -37442,9 +37886,9 @@ function dedupeSourceReferences(references) {
|
|
|
37442
37886
|
return deduped;
|
|
37443
37887
|
}
|
|
37444
37888
|
function toPortableRelativePath(root, candidate) {
|
|
37445
|
-
const relative =
|
|
37446
|
-
if (relative && !relative.startsWith("..") && !
|
|
37447
|
-
return relative.split(
|
|
37889
|
+
const relative = path45.relative(root, candidate);
|
|
37890
|
+
if (relative && !relative.startsWith("..") && !path45.isAbsolute(relative)) {
|
|
37891
|
+
return relative.split(path45.sep).join("/");
|
|
37448
37892
|
}
|
|
37449
37893
|
return void 0;
|
|
37450
37894
|
}
|
|
@@ -37498,8 +37942,8 @@ function parseWorkspaceScriptConfig(raw, evalFileDir) {
|
|
|
37498
37942
|
if (!command) return void 0;
|
|
37499
37943
|
const timeoutMs = typeof obj.timeout_ms === "number" ? obj.timeout_ms : void 0;
|
|
37500
37944
|
let cwd = typeof obj.cwd === "string" ? obj.cwd : void 0;
|
|
37501
|
-
if (cwd && !
|
|
37502
|
-
cwd =
|
|
37945
|
+
if (cwd && !path45.isAbsolute(cwd)) {
|
|
37946
|
+
cwd = path45.resolve(evalFileDir, cwd);
|
|
37503
37947
|
}
|
|
37504
37948
|
const config2 = { command };
|
|
37505
37949
|
if (timeoutMs !== void 0) {
|
|
@@ -37537,7 +37981,7 @@ function parseWorkspaceHooksConfig(raw, evalFileDir) {
|
|
|
37537
37981
|
}
|
|
37538
37982
|
async function resolveWorkspaceConfig(raw, evalFileDir) {
|
|
37539
37983
|
if (typeof raw === "string") {
|
|
37540
|
-
const workspaceFilePath =
|
|
37984
|
+
const workspaceFilePath = path45.resolve(evalFileDir, raw);
|
|
37541
37985
|
let content;
|
|
37542
37986
|
try {
|
|
37543
37987
|
content = await readFile18(workspaceFilePath, "utf8");
|
|
@@ -37550,7 +37994,7 @@ async function resolveWorkspaceConfig(raw, evalFileDir) {
|
|
|
37550
37994
|
`Invalid workspace file format: ${workspaceFilePath} (expected a YAML object)`
|
|
37551
37995
|
);
|
|
37552
37996
|
}
|
|
37553
|
-
const workspaceFileDir =
|
|
37997
|
+
const workspaceFileDir = path45.dirname(workspaceFilePath);
|
|
37554
37998
|
const resolvedWorkspace = parseWorkspaceConfig(parsed, workspaceFileDir);
|
|
37555
37999
|
if (resolvedWorkspace) {
|
|
37556
38000
|
return { ...resolvedWorkspace, workspaceFileDir };
|
|
@@ -37584,8 +38028,8 @@ function parseWorkspaceConfig(raw, evalFileDir) {
|
|
|
37584
38028
|
throw new Error("workspace.static has been removed. Use workspace.mode='static'.");
|
|
37585
38029
|
}
|
|
37586
38030
|
let template = typeof obj.template === "string" ? obj.template : void 0;
|
|
37587
|
-
if (template && !
|
|
37588
|
-
template =
|
|
38031
|
+
if (template && !path45.isAbsolute(template)) {
|
|
38032
|
+
template = path45.resolve(evalFileDir, template);
|
|
37589
38033
|
}
|
|
37590
38034
|
const isolation = obj.isolation === "shared" || obj.isolation === "per_test" ? obj.isolation : void 0;
|
|
37591
38035
|
const repos = Array.isArray(obj.repos) ? obj.repos.map(parseRepoConfig).filter(Boolean) : void 0;
|
|
@@ -37722,7 +38166,7 @@ ${detailBlock}${ANSI_RESET8}`);
|
|
|
37722
38166
|
console.error(`${ANSI_RED3}Error: ${message}${ANSI_RESET8}`);
|
|
37723
38167
|
}
|
|
37724
38168
|
}
|
|
37725
|
-
var
|
|
38169
|
+
var execFileAsync2 = promisify6(execFile2);
|
|
37726
38170
|
var WORKSPACE_GIT_TIMEOUT_MS = 3e5;
|
|
37727
38171
|
function pathFromRoot(root) {
|
|
37728
38172
|
return root instanceof URL ? fileURLToPath5(root) : String(root);
|
|
@@ -37779,7 +38223,7 @@ function workspaceGitEnv() {
|
|
|
37779
38223
|
};
|
|
37780
38224
|
}
|
|
37781
38225
|
async function resetWorkspaceRoot(workspacePath, resetMode, baselineRef) {
|
|
37782
|
-
if (!
|
|
38226
|
+
if (!existsSync6(path46.join(workspacePath, ".git"))) {
|
|
37783
38227
|
return false;
|
|
37784
38228
|
}
|
|
37785
38229
|
const cleanFlag = resetMode === "strict" ? "-fdx" : "-fd";
|
|
@@ -37789,8 +38233,8 @@ async function resetWorkspaceRoot(workspacePath, resetMode, baselineRef) {
|
|
|
37789
38233
|
env: workspaceGitEnv(),
|
|
37790
38234
|
maxBuffer: 50 * 1024 * 1024
|
|
37791
38235
|
};
|
|
37792
|
-
await
|
|
37793
|
-
await
|
|
38236
|
+
await execFileAsync2("git", ["reset", "--hard", baselineRef ?? "HEAD"], opts);
|
|
38237
|
+
await execFileAsync2("git", ["clean", cleanFlag], opts);
|
|
37794
38238
|
return true;
|
|
37795
38239
|
}
|
|
37796
38240
|
function validateDependencyGraph(tests) {
|
|
@@ -37822,18 +38266,18 @@ function validateDependencyGraph(tests) {
|
|
|
37822
38266
|
}
|
|
37823
38267
|
const visited = /* @__PURE__ */ new Set();
|
|
37824
38268
|
const visiting = /* @__PURE__ */ new Set();
|
|
37825
|
-
function visit(id,
|
|
38269
|
+
function visit(id, path49) {
|
|
37826
38270
|
if (visiting.has(id)) {
|
|
37827
|
-
const cycle = [...
|
|
38271
|
+
const cycle = [...path49.slice(path49.indexOf(id)), id];
|
|
37828
38272
|
throw new Error(`Circular dependency detected: ${cycle.join(" \u2192 ")}`);
|
|
37829
38273
|
}
|
|
37830
38274
|
if (visited.has(id)) return;
|
|
37831
38275
|
visiting.add(id);
|
|
37832
|
-
|
|
38276
|
+
path49.push(id);
|
|
37833
38277
|
for (const dep of depMap.get(id) ?? []) {
|
|
37834
|
-
visit(dep,
|
|
38278
|
+
visit(dep, path49);
|
|
37835
38279
|
}
|
|
37836
|
-
|
|
38280
|
+
path49.pop();
|
|
37837
38281
|
visiting.delete(id);
|
|
37838
38282
|
visited.add(id);
|
|
37839
38283
|
}
|
|
@@ -37933,7 +38377,7 @@ async function runEvaluation(options) {
|
|
|
37933
38377
|
);
|
|
37934
38378
|
useCache = false;
|
|
37935
38379
|
}
|
|
37936
|
-
const evalRunId =
|
|
38380
|
+
const evalRunId = randomUUID10();
|
|
37937
38381
|
const evalCases = preloadedEvalCases ?? await loadTests(evalFilePath, repoRoot, { verbose, filter });
|
|
37938
38382
|
const filteredEvalCases = filterEvalCases(evalCases, filter);
|
|
37939
38383
|
if (filteredEvalCases.length === 0) {
|
|
@@ -38015,7 +38459,7 @@ async function runEvaluation(options) {
|
|
|
38015
38459
|
];
|
|
38016
38460
|
const evaluatorRegistry = buildEvaluatorRegistry(evaluators, resolveGraderProvider);
|
|
38017
38461
|
const typeRegistry = createBuiltinRegistry();
|
|
38018
|
-
const discoveryBaseDir = evalFilePath ?
|
|
38462
|
+
const discoveryBaseDir = evalFilePath ? path46.dirname(path46.resolve(evalFilePath)) : process.cwd();
|
|
38019
38463
|
const evalDir = discoveryBaseDir;
|
|
38020
38464
|
await discoverAssertions(typeRegistry, discoveryBaseDir);
|
|
38021
38465
|
await discoverGraders(typeRegistry, discoveryBaseDir);
|
|
@@ -38081,29 +38525,6 @@ async function runEvaluation(options) {
|
|
|
38081
38525
|
console.log(`[setup] ${message}`);
|
|
38082
38526
|
}
|
|
38083
38527
|
};
|
|
38084
|
-
const allRepos = /* @__PURE__ */ new Map();
|
|
38085
|
-
for (const ec of filteredEvalCases) {
|
|
38086
|
-
if (ec.workspace?.repos) {
|
|
38087
|
-
for (const repo of ec.workspace.repos) {
|
|
38088
|
-
if (!repo.source) continue;
|
|
38089
|
-
const key = `${repo.path ?? ""}::${repo.source.type === "local" ? repo.source.path : ""}`;
|
|
38090
|
-
if (!allRepos.has(key)) {
|
|
38091
|
-
allRepos.set(key, repo);
|
|
38092
|
-
}
|
|
38093
|
-
}
|
|
38094
|
-
}
|
|
38095
|
-
}
|
|
38096
|
-
if (allRepos.size > 0) {
|
|
38097
|
-
const localPathErrors = RepoManager.validateLocalPaths([...allRepos.values()]);
|
|
38098
|
-
if (localPathErrors.length > 0) {
|
|
38099
|
-
const message = RepoManager.formatValidationErrors(localPathErrors);
|
|
38100
|
-
console.warn(`Warning: ${message}`);
|
|
38101
|
-
const invalidLocalRepoPaths = new Set(localPathErrors.map((e) => e.repoPath));
|
|
38102
|
-
if (suiteWorkspace?.repos?.some((r) => r.path && invalidLocalRepoPaths.has(r.path))) {
|
|
38103
|
-
throw new Error(message);
|
|
38104
|
-
}
|
|
38105
|
-
}
|
|
38106
|
-
}
|
|
38107
38528
|
const isPerTestIsolation = suiteWorkspace?.isolation === "per_test";
|
|
38108
38529
|
const cliWorkspacePath = workspacePath ?? legacyWorkspacePath;
|
|
38109
38530
|
const yamlWorkspacePath = suiteWorkspace?.path;
|
|
@@ -38172,7 +38593,7 @@ async function runEvaluation(options) {
|
|
|
38172
38593
|
const isEmpty = dirExists ? (await readdir8(configuredStaticPath)).length === 0 : false;
|
|
38173
38594
|
if (isYamlConfiguredPath && (!dirExists || isEmpty)) {
|
|
38174
38595
|
if (!dirExists) {
|
|
38175
|
-
await
|
|
38596
|
+
await mkdir17(configuredStaticPath, { recursive: true });
|
|
38176
38597
|
}
|
|
38177
38598
|
if (workspaceTemplate) {
|
|
38178
38599
|
await copyDirectoryRecursive(workspaceTemplate, configuredStaticPath);
|
|
@@ -38217,7 +38638,7 @@ async function runEvaluation(options) {
|
|
|
38217
38638
|
}
|
|
38218
38639
|
} else if (!isPerTestIsolation && (suiteWorkspace?.hooks || suiteWorkspace?.repos?.length)) {
|
|
38219
38640
|
sharedWorkspacePath = getWorkspacePath(evalRunId, "shared");
|
|
38220
|
-
await
|
|
38641
|
+
await mkdir17(sharedWorkspacePath, { recursive: true });
|
|
38221
38642
|
setupLog(`created empty shared workspace at: ${sharedWorkspacePath}`);
|
|
38222
38643
|
}
|
|
38223
38644
|
try {
|
|
@@ -38258,7 +38679,7 @@ async function runEvaluation(options) {
|
|
|
38258
38679
|
};
|
|
38259
38680
|
var toDependencyResult = toDependencyResult2, checkDependencies = checkDependencies2, extractEvaluationCostUsd = extractEvaluationCostUsd2;
|
|
38260
38681
|
if (suiteWorkspaceFile && sharedWorkspacePath) {
|
|
38261
|
-
const copiedWorkspaceFile =
|
|
38682
|
+
const copiedWorkspaceFile = path46.join(sharedWorkspacePath, path46.basename(suiteWorkspaceFile));
|
|
38262
38683
|
try {
|
|
38263
38684
|
await stat9(copiedWorkspaceFile);
|
|
38264
38685
|
suiteWorkspaceFile = copiedWorkspaceFile;
|
|
@@ -38273,9 +38694,9 @@ async function runEvaluation(options) {
|
|
|
38273
38694
|
try {
|
|
38274
38695
|
if (needsPerRepoCheck) {
|
|
38275
38696
|
for (const repo of suiteWorkspace.repos) {
|
|
38276
|
-
if (!repo.path || !repo.
|
|
38277
|
-
const targetDir =
|
|
38278
|
-
if (
|
|
38697
|
+
if (!repo.path || !repo.repo) continue;
|
|
38698
|
+
const targetDir = path46.join(sharedWorkspacePath, repo.path);
|
|
38699
|
+
if (existsSync6(targetDir)) {
|
|
38279
38700
|
setupLog(`reusing existing repo at: ${targetDir}`);
|
|
38280
38701
|
continue;
|
|
38281
38702
|
}
|
|
@@ -39140,7 +39561,7 @@ async function runEvalCase(options) {
|
|
|
39140
39561
|
);
|
|
39141
39562
|
}
|
|
39142
39563
|
if (caseWorkspaceFile && workspacePath) {
|
|
39143
|
-
const copiedFile =
|
|
39564
|
+
const copiedFile = path46.join(workspacePath, path46.basename(caseWorkspaceFile));
|
|
39144
39565
|
try {
|
|
39145
39566
|
await stat9(copiedFile);
|
|
39146
39567
|
caseWorkspaceFile = copiedFile;
|
|
@@ -39150,25 +39571,7 @@ async function runEvalCase(options) {
|
|
|
39150
39571
|
}
|
|
39151
39572
|
if (!workspacePath && (evalCase.workspace?.hooks || evalCase.workspace?.repos?.length) && evalRunId) {
|
|
39152
39573
|
workspacePath = getWorkspacePath(evalRunId, evalCase.id);
|
|
39153
|
-
await
|
|
39154
|
-
}
|
|
39155
|
-
if (evalCase.workspace?.repos?.length && workspacePath) {
|
|
39156
|
-
const localPathErrors = RepoManager.validateLocalPaths(evalCase.workspace.repos);
|
|
39157
|
-
if (localPathErrors.length > 0) {
|
|
39158
|
-
const message = RepoManager.formatValidationErrors(localPathErrors);
|
|
39159
|
-
console.warn(`Warning: test=${evalCase.id} ${message}`);
|
|
39160
|
-
return buildErrorResult(
|
|
39161
|
-
evalCase,
|
|
39162
|
-
target.name,
|
|
39163
|
-
nowFn(),
|
|
39164
|
-
new Error(message),
|
|
39165
|
-
promptInputs,
|
|
39166
|
-
provider,
|
|
39167
|
-
"repo_setup",
|
|
39168
|
-
"local_path_not_found",
|
|
39169
|
-
verbose
|
|
39170
|
-
);
|
|
39171
|
-
}
|
|
39574
|
+
await mkdir17(workspacePath, { recursive: true });
|
|
39172
39575
|
}
|
|
39173
39576
|
if (evalCase.workspace?.repos?.length && workspacePath) {
|
|
39174
39577
|
const perCaseRepoManager = new RepoManager(setupDebug);
|
|
@@ -39202,10 +39605,10 @@ async function runEvalCase(options) {
|
|
|
39202
39605
|
const files = evalCase.metadata.agent_skills_files;
|
|
39203
39606
|
if (baseDir && files.length > 0) {
|
|
39204
39607
|
for (const relPath of files) {
|
|
39205
|
-
const srcPath =
|
|
39206
|
-
const destPath =
|
|
39608
|
+
const srcPath = path46.resolve(baseDir, relPath);
|
|
39609
|
+
const destPath = path46.resolve(workspacePath, relPath);
|
|
39207
39610
|
try {
|
|
39208
|
-
await
|
|
39611
|
+
await mkdir17(path46.dirname(destPath), { recursive: true });
|
|
39209
39612
|
await copyFile2(srcPath, destPath);
|
|
39210
39613
|
} catch (error40) {
|
|
39211
39614
|
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
@@ -39434,7 +39837,7 @@ async function runEvalCase(options) {
|
|
|
39434
39837
|
lastError = error40;
|
|
39435
39838
|
if (attempt + 1 < attemptBudget) {
|
|
39436
39839
|
const delayMs = retryBackoffMs(attempt);
|
|
39437
|
-
await
|
|
39840
|
+
await sleep3(delayMs, signal);
|
|
39438
39841
|
attempt += 1;
|
|
39439
39842
|
continue;
|
|
39440
39843
|
}
|
|
@@ -40085,7 +40488,7 @@ async function runEvaluatorList(options) {
|
|
|
40085
40488
|
dockerConfig,
|
|
40086
40489
|
dependencyResults
|
|
40087
40490
|
};
|
|
40088
|
-
const evalFileDir = evalCase.file_paths[0] ?
|
|
40491
|
+
const evalFileDir = evalCase.file_paths[0] ? path46.dirname(evalCase.file_paths[0]) : process.cwd();
|
|
40089
40492
|
const dispatchContext = {
|
|
40090
40493
|
graderProvider,
|
|
40091
40494
|
targetResolver,
|
|
@@ -40621,7 +41024,7 @@ function extractProviderError(response) {
|
|
|
40621
41024
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
40622
41025
|
}
|
|
40623
41026
|
function createCacheKey(provider, target, evalCase, promptInputs) {
|
|
40624
|
-
const hash =
|
|
41027
|
+
const hash = createHash5("sha256");
|
|
40625
41028
|
hash.update(provider.id);
|
|
40626
41029
|
hash.update(target.name);
|
|
40627
41030
|
hash.update(evalCase.id);
|
|
@@ -40706,7 +41109,7 @@ function extractErrorMessage(error40) {
|
|
|
40706
41109
|
function retryBackoffMs(attempt) {
|
|
40707
41110
|
return Math.min(2 ** attempt * 1e3, 3e4);
|
|
40708
41111
|
}
|
|
40709
|
-
function
|
|
41112
|
+
function sleep3(ms, signal) {
|
|
40710
41113
|
if (signal?.aborted) return Promise.resolve();
|
|
40711
41114
|
return new Promise((resolve) => {
|
|
40712
41115
|
const timer = setTimeout(resolve, ms);
|
|
@@ -40748,15 +41151,15 @@ function computeWeightedMean(entries) {
|
|
|
40748
41151
|
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
40749
41152
|
}
|
|
40750
41153
|
async function runPreflightChecks(env, cwd, log) {
|
|
40751
|
-
const
|
|
41154
|
+
const execFileAsync3 = promisify6(execFile2);
|
|
40752
41155
|
const missing = [];
|
|
40753
41156
|
for (const cmd of env.required_commands ?? []) {
|
|
40754
41157
|
log(`preflight: checking command "${cmd}"`);
|
|
40755
41158
|
try {
|
|
40756
41159
|
if (process.platform === "win32") {
|
|
40757
|
-
await
|
|
41160
|
+
await execFileAsync3("where", [cmd], { cwd });
|
|
40758
41161
|
} else {
|
|
40759
|
-
await
|
|
41162
|
+
await execFileAsync3("sh", ["-c", `command -v ${cmd}`], { cwd });
|
|
40760
41163
|
}
|
|
40761
41164
|
} catch {
|
|
40762
41165
|
missing.push(`command: ${cmd}`);
|
|
@@ -40765,7 +41168,7 @@ async function runPreflightChecks(env, cwd, log) {
|
|
|
40765
41168
|
for (const mod of env.required_python_modules ?? []) {
|
|
40766
41169
|
log(`preflight: checking Python module "${mod}"`);
|
|
40767
41170
|
try {
|
|
40768
|
-
await
|
|
41171
|
+
await execFileAsync3("python3", ["-c", `import ${mod}`], { cwd });
|
|
40769
41172
|
} catch {
|
|
40770
41173
|
missing.push(`python module: ${mod}`);
|
|
40771
41174
|
}
|
|
@@ -40843,7 +41246,7 @@ async function evaluate(config2) {
|
|
|
40843
41246
|
cliNoCache: false,
|
|
40844
41247
|
yamlCache: config2.cache === void 0 ? materialized.cache : void 0
|
|
40845
41248
|
});
|
|
40846
|
-
const cache = cacheEnabled ? new ResponseCache(materialized.cachePath ?
|
|
41249
|
+
const cache = cacheEnabled ? new ResponseCache(materialized.cachePath ? path47.resolve(materialized.cachePath) : void 0) : void 0;
|
|
40847
41250
|
const results = await runEvaluation({
|
|
40848
41251
|
testFilePath,
|
|
40849
41252
|
repoRoot,
|
|
@@ -40874,7 +41277,7 @@ async function evaluate(config2) {
|
|
|
40874
41277
|
async function materializeEvalConfig(config2, options) {
|
|
40875
41278
|
const baseDir = options?.baseDir ?? process.cwd();
|
|
40876
41279
|
const repoRoot = options?.repoRoot ?? await findGitRoot(baseDir) ?? baseDir;
|
|
40877
|
-
const testFilePath = config2.specFile ?
|
|
41280
|
+
const testFilePath = config2.specFile ? path47.resolve(baseDir, config2.specFile) : path47.join(baseDir, "__programmatic__.yaml");
|
|
40878
41281
|
const effectiveFilter = options?.filter ?? config2.filter;
|
|
40879
41282
|
if (config2.specFile) {
|
|
40880
41283
|
const suite = await loadTestSuite(testFilePath, repoRoot, {
|
|
@@ -40951,7 +41354,7 @@ function convertAssertions(entries) {
|
|
|
40951
41354
|
}
|
|
40952
41355
|
function buildInlineEvalTests(config2, options) {
|
|
40953
41356
|
const suiteWorkspace = config2.beforeAll ? { hooks: { before_all: toBeforeAllHook(config2.beforeAll) } } : void 0;
|
|
40954
|
-
const derivedSuiteName =
|
|
41357
|
+
const derivedSuiteName = path47.basename(options.testFilePath).replace(/\.eval\.[cm]?ts$/i, "").replace(/\.[cm]?ts$/i, "");
|
|
40955
41358
|
const suiteName = config2.metadata?.name ?? (derivedSuiteName || "eval");
|
|
40956
41359
|
return (config2.tests ?? []).filter((test) => !options.filter || matchesFilter4(test.id, options.filter)).map((test) => {
|
|
40957
41360
|
const isConversation = test.mode === "conversation" || test.turns && test.turns.length > 0;
|
|
@@ -41047,11 +41450,11 @@ function computeSummary(results, durationMs, threshold = DEFAULT_THRESHOLD) {
|
|
|
41047
41450
|
var TARGET_FILE_CANDIDATES = [".agentv/targets.yaml", ".agentv/targets.yml"];
|
|
41048
41451
|
async function discoverDefaultTarget(repoRoot) {
|
|
41049
41452
|
const cwd = process.cwd();
|
|
41050
|
-
const chain = buildDirectoryChain(
|
|
41453
|
+
const chain = buildDirectoryChain(path47.join(cwd, "_placeholder"), repoRoot);
|
|
41051
41454
|
for (const dir of chain) {
|
|
41052
41455
|
for (const candidate of TARGET_FILE_CANDIDATES) {
|
|
41053
|
-
const targetsPath =
|
|
41054
|
-
if (!
|
|
41456
|
+
const targetsPath = path47.join(dir, candidate);
|
|
41457
|
+
if (!existsSync7(targetsPath)) continue;
|
|
41055
41458
|
try {
|
|
41056
41459
|
const definitions = await readTargetDefinitions(targetsPath);
|
|
41057
41460
|
const defaultTarget = definitions.find((d) => d.name === "default");
|
|
@@ -41063,16 +41466,16 @@ async function discoverDefaultTarget(repoRoot) {
|
|
|
41063
41466
|
return null;
|
|
41064
41467
|
}
|
|
41065
41468
|
async function loadEnvHierarchy(repoRoot, startPath) {
|
|
41066
|
-
const { readFileSync:
|
|
41469
|
+
const { readFileSync: readFileSync4 } = await import("node:fs");
|
|
41067
41470
|
const chain = buildDirectoryChain(startPath, repoRoot);
|
|
41068
41471
|
const envFiles = [];
|
|
41069
41472
|
for (const dir of chain) {
|
|
41070
|
-
const envPath =
|
|
41071
|
-
if (
|
|
41473
|
+
const envPath = path47.join(dir, ".env");
|
|
41474
|
+
if (existsSync7(envPath)) envFiles.push(envPath);
|
|
41072
41475
|
}
|
|
41073
41476
|
for (let i = 0; i < envFiles.length; i++) {
|
|
41074
41477
|
try {
|
|
41075
|
-
const content =
|
|
41478
|
+
const content = readFileSync4(envFiles[i], "utf8");
|
|
41076
41479
|
for (const line of content.split("\n")) {
|
|
41077
41480
|
const trimmed = line.trim();
|
|
41078
41481
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -41093,7 +41496,7 @@ async function loadEnvHierarchy(repoRoot, startPath) {
|
|
|
41093
41496
|
}
|
|
41094
41497
|
var EXPORT_NAMES = ["default", "config", "evalConfig"];
|
|
41095
41498
|
async function loadTsEvalFile(filePath) {
|
|
41096
|
-
const absolutePath =
|
|
41499
|
+
const absolutePath = path48.resolve(filePath);
|
|
41097
41500
|
const moduleUrl = pathToFileURL2(absolutePath).href;
|
|
41098
41501
|
const module = await import(moduleUrl);
|
|
41099
41502
|
let config2;
|
|
@@ -41115,7 +41518,7 @@ async function loadTsEvalSuite(filePath, repoRoot, options) {
|
|
|
41115
41518
|
const { config: config2, filePath: absolutePath } = await loadTsEvalFile(filePath);
|
|
41116
41519
|
const materialized = await materializeEvalConfig(config2, {
|
|
41117
41520
|
repoRoot,
|
|
41118
|
-
baseDir:
|
|
41521
|
+
baseDir: path48.dirname(absolutePath),
|
|
41119
41522
|
filter: options?.filter,
|
|
41120
41523
|
category: options?.category
|
|
41121
41524
|
});
|
|
@@ -41203,6 +41606,7 @@ export {
|
|
|
41203
41606
|
negateScore,
|
|
41204
41607
|
toSnakeCaseDeep,
|
|
41205
41608
|
toCamelCaseDeep,
|
|
41609
|
+
getRepoCheckoutRef,
|
|
41206
41610
|
CodeGrader,
|
|
41207
41611
|
executeScript,
|
|
41208
41612
|
DEFAULT_GRADER_TEMPLATE,
|
|
@@ -41357,8 +41761,20 @@ export {
|
|
|
41357
41761
|
createTempWorkspace,
|
|
41358
41762
|
cleanupWorkspace,
|
|
41359
41763
|
cleanupEvalWorkspaces,
|
|
41764
|
+
resolveRepoCloneUrl,
|
|
41765
|
+
normalizeRepoIdentity,
|
|
41360
41766
|
computeWorkspaceFingerprint,
|
|
41361
41767
|
WorkspacePoolManager,
|
|
41768
|
+
getProjectsRegistryPath,
|
|
41769
|
+
loadProjectRegistry,
|
|
41770
|
+
saveProjectRegistry,
|
|
41771
|
+
deriveProjectId,
|
|
41772
|
+
addProject,
|
|
41773
|
+
removeProject,
|
|
41774
|
+
getProject,
|
|
41775
|
+
getProjectForPath,
|
|
41776
|
+
touchProject,
|
|
41777
|
+
discoverProjects,
|
|
41362
41778
|
RepoManager,
|
|
41363
41779
|
resolveWorkspaceTemplate,
|
|
41364
41780
|
executeWorkspaceScript,
|
|
@@ -41377,9 +41793,7 @@ export {
|
|
|
41377
41793
|
extractThreshold,
|
|
41378
41794
|
resolveResultsConfigForProject,
|
|
41379
41795
|
detectFormat,
|
|
41380
|
-
|
|
41381
|
-
parseRepoCheckout,
|
|
41382
|
-
parseRepoClone,
|
|
41796
|
+
parseRepoConfig,
|
|
41383
41797
|
buildPromptInputs,
|
|
41384
41798
|
readTestSuiteMetadata,
|
|
41385
41799
|
loadTestSuite,
|
|
@@ -41394,4 +41808,4 @@ export {
|
|
|
41394
41808
|
loadTsEvalFile,
|
|
41395
41809
|
loadTsEvalSuite
|
|
41396
41810
|
};
|
|
41397
|
-
//# sourceMappingURL=chunk-
|
|
41811
|
+
//# sourceMappingURL=chunk-VBHHZQS6.js.map
|