lastlight-evals 0.2.1 → 0.3.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/README.md +37 -1
- package/dist/add-case.js +444 -0
- package/dist/add-case.js.map +1 -0
- package/dist/grade.js +46 -8
- package/dist/grade.js.map +1 -1
- package/dist/init.js +6 -2
- package/dist/init.js.map +1 -1
- package/dist/mechanism.test.js +64 -2
- package/dist/mechanism.test.js.map +1 -1
- package/dist/run-instance.js +14 -6
- package/dist/run-instance.js.map +1 -1
- package/dist/run.js +68 -5
- package/dist/run.js.map +1 -1
- package/dist/seed.js +98 -14
- package/dist/seed.js.map +1 -1
- package/package.json +2 -2
package/dist/seed.js
CHANGED
|
@@ -2,16 +2,25 @@
|
|
|
2
2
|
* Deterministic workspace seeding for the code-fix tier.
|
|
3
3
|
*
|
|
4
4
|
* Pre-populates the run's sandbox workspace (`<stateDir>/sandboxes/<taskId>`,
|
|
5
|
-
* the exact dir `setupTaskWorktree` would create) with a
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* the exact dir `setupTaskWorktree` would create) with a repo checked out at a
|
|
6
|
+
* base commit, and points its `origin` at a LOCAL bare repo — so the real
|
|
7
|
+
* workflow's `git push origin HEAD` succeeds fully offline with NO GitHub clone.
|
|
8
|
+
* Because the eval calls `runWorkflow` with no `ctx.prePopulateBranch`, the
|
|
9
|
+
* runner never triggers its own GitHub clone and the agent works directly in
|
|
10
|
+
* this seeded dir.
|
|
11
|
+
*
|
|
12
|
+
* Two provenances, same end state:
|
|
13
|
+
* - {@link seedWorkspace} — a vendored fixture dir (`repos/<id>/`).
|
|
14
|
+
* - {@link seedWorkspaceFromGit} — a real repo cloned into a repo-local cache
|
|
15
|
+
* and checked out at `base_commit`.
|
|
16
|
+
*
|
|
17
|
+
* The git-source clone is a HARNESS SETUP action, not the workflow cloning
|
|
18
|
+
* GitHub — it touches the network only on a cache miss; the workflow itself
|
|
19
|
+
* still operates on a pre-seeded dir with an offline `file://` origin.
|
|
11
20
|
*/
|
|
12
21
|
import { execFileSync } from "node:child_process";
|
|
13
|
-
import { mkdirSync, cpSync } from "node:fs";
|
|
14
|
-
import { resolve } from "node:path";
|
|
22
|
+
import { mkdirSync, cpSync, existsSync } from "node:fs";
|
|
23
|
+
import { resolve, dirname } from "node:path";
|
|
15
24
|
const FIXED = "2026-01-01T00:00:00 +0000";
|
|
16
25
|
const GIT_ENV = {
|
|
17
26
|
...process.env,
|
|
@@ -25,6 +34,30 @@ const GIT_ENV = {
|
|
|
25
34
|
function git(cwd, args) {
|
|
26
35
|
return execFileSync("git", args, { cwd, env: GIT_ENV, stdio: ["ignore", "pipe", "pipe"] }).toString();
|
|
27
36
|
}
|
|
37
|
+
/** Where git-source repos are mirrored. Repo-local (NOT `~`), gitignored —
|
|
38
|
+
* overridable with `LASTLIGHT_EVALS_CACHE`. */
|
|
39
|
+
export function resolveCacheDir(override) {
|
|
40
|
+
const root = override ?? process.env.LASTLIGHT_EVALS_CACHE ?? resolve(process.cwd(), ".eval-cache");
|
|
41
|
+
return resolve(root, "repos");
|
|
42
|
+
}
|
|
43
|
+
/** Point `workDir`'s `origin` at a fresh LOCAL bare repo and push the current
|
|
44
|
+
* HEAD as the default branch, so the workflow can `git push` fully offline. */
|
|
45
|
+
function setupOfflineOrigin(workDir, stateDir, taskId, def) {
|
|
46
|
+
const originsDir = resolve(stateDir, "origins");
|
|
47
|
+
mkdirSync(originsDir, { recursive: true });
|
|
48
|
+
const originDir = resolve(originsDir, `${taskId}.git`);
|
|
49
|
+
git(workDir, ["init", "--bare", "-q", originDir]);
|
|
50
|
+
// A git-source clone already has an `origin` (the cache) — replace it.
|
|
51
|
+
try {
|
|
52
|
+
git(workDir, ["remote", "remove", "origin"]);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* no existing origin (fixture path) — fine */
|
|
56
|
+
}
|
|
57
|
+
git(workDir, ["remote", "add", "origin", `file://${originDir}`]);
|
|
58
|
+
git(workDir, ["push", "-q", "origin", `HEAD:refs/heads/${def}`]);
|
|
59
|
+
return originDir;
|
|
60
|
+
}
|
|
28
61
|
export function seedWorkspace(opts) {
|
|
29
62
|
const def = opts.defaultBranch ?? "main";
|
|
30
63
|
const sandboxBase = resolve(opts.stateDir, "sandboxes");
|
|
@@ -35,15 +68,66 @@ export function seedWorkspace(opts) {
|
|
|
35
68
|
git(workDir, ["add", "-A"]);
|
|
36
69
|
git(workDir, ["commit", "-q", "-m", "base"]);
|
|
37
70
|
const baseCommit = git(workDir, ["rev-parse", "HEAD"]).trim();
|
|
38
|
-
const
|
|
39
|
-
mkdirSync(originsDir, { recursive: true });
|
|
40
|
-
const originDir = resolve(originsDir, `${opts.taskId}.git`);
|
|
41
|
-
git(workDir, ["init", "--bare", "-q", originDir]);
|
|
42
|
-
git(workDir, ["remote", "add", "origin", `file://${originDir}`]);
|
|
43
|
-
git(workDir, ["push", "-q", "origin", `HEAD:refs/heads/${def}`]);
|
|
71
|
+
const originDir = setupOfflineOrigin(workDir, opts.stateDir, opts.taskId, def);
|
|
44
72
|
const branch = opts.branch ?? def;
|
|
45
73
|
if (branch !== def)
|
|
46
74
|
git(workDir, ["checkout", "-q", "-b", branch]);
|
|
47
75
|
return { workDir, originDir, baseCommit, branch };
|
|
48
76
|
}
|
|
77
|
+
/** True if `sha` is a 40-hex non-zero commit id (a real git-source base). */
|
|
78
|
+
export function isRealSha(sha) {
|
|
79
|
+
return !!sha && /^[0-9a-f]{40}$/i.test(sha) && !/^0+$/.test(sha);
|
|
80
|
+
}
|
|
81
|
+
/** Ensure a repo-local bare mirror of `repo` exists and contains `baseCommit`
|
|
82
|
+
* (clone on miss, fetch if the commit is absent). Returns the cache dir. Run
|
|
83
|
+
* this SERIALLY per repo before a parallel batch — concurrent clones of the same
|
|
84
|
+
* repo race. Network is touched only here, only on a miss. */
|
|
85
|
+
export function ensureRepoCache(opts) {
|
|
86
|
+
const [owner, name] = opts.repo.split("/");
|
|
87
|
+
if (!owner || !name)
|
|
88
|
+
throw new Error(`seedWorkspaceFromGit: repo must be "owner/name", got "${opts.repo}"`);
|
|
89
|
+
const cacheDir = resolveCacheDir(opts.cacheDir);
|
|
90
|
+
const mirror = resolve(cacheDir, `${owner}__${name}.git`);
|
|
91
|
+
if (!existsSync(mirror)) {
|
|
92
|
+
mkdirSync(dirname(mirror), { recursive: true });
|
|
93
|
+
git(dirname(mirror), ["clone", "--bare", "--quiet", `https://github.com/${owner}/${name}.git`, mirror]);
|
|
94
|
+
}
|
|
95
|
+
// Fetch only if the wanted commit isn't already in the mirror.
|
|
96
|
+
if (opts.baseCommit) {
|
|
97
|
+
const present = (() => {
|
|
98
|
+
try {
|
|
99
|
+
git(mirror, ["cat-file", "-e", `${opts.baseCommit}^{commit}`]);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
if (!present)
|
|
107
|
+
git(mirror, ["fetch", "--quiet", "origin", "+refs/heads/*:refs/heads/*"]);
|
|
108
|
+
}
|
|
109
|
+
return mirror;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Seed the sandbox from a real GitHub repo at `baseCommit`, with the same offline
|
|
113
|
+
* end state as {@link seedWorkspace}: a checked-out base, a feature branch, and a
|
|
114
|
+
* local bare `origin` to push to. Uses the repo-local mirror from
|
|
115
|
+
* {@link ensureRepoCache} so per-run checkout is offline and parallel-safe.
|
|
116
|
+
*/
|
|
117
|
+
export function seedWorkspaceFromGit(opts) {
|
|
118
|
+
const def = opts.defaultBranch ?? "main";
|
|
119
|
+
const mirror = ensureRepoCache({ repo: opts.repo, baseCommit: opts.baseCommit, cacheDir: opts.cacheDir });
|
|
120
|
+
const sandboxBase = resolve(opts.stateDir, "sandboxes");
|
|
121
|
+
const workDir = resolve(sandboxBase, opts.taskId);
|
|
122
|
+
mkdirSync(sandboxBase, { recursive: true });
|
|
123
|
+
// Plain local clone (not --shared) so the sandbox owns its objects/refs and
|
|
124
|
+
// parallel runs never touch the cache's object store.
|
|
125
|
+
git(sandboxBase, ["clone", "--quiet", `file://${mirror}`, workDir]);
|
|
126
|
+
git(workDir, ["checkout", "--quiet", "--detach", opts.baseCommit]);
|
|
127
|
+
const originDir = setupOfflineOrigin(workDir, opts.stateDir, opts.taskId, def);
|
|
128
|
+
const branch = opts.branch ?? def;
|
|
129
|
+
if (branch !== def)
|
|
130
|
+
git(workDir, ["checkout", "-q", "-b", branch]);
|
|
131
|
+
return { workDir, originDir, baseCommit: opts.baseCommit, branch };
|
|
132
|
+
}
|
|
49
133
|
//# sourceMappingURL=seed.js.map
|
package/dist/seed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lastlight-evals",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Eval harness for Last Light workflows — drives the real production workflows against a mocked GitHub and grades deterministically (SWE-bench compatible).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@clack/prompts": "^1.2.0",
|
|
45
45
|
"chalk": "^5.6.2",
|
|
46
|
-
"lastlight": "^0.
|
|
46
|
+
"lastlight": "^0.7.2",
|
|
47
47
|
"yaml": "^2.5.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|