lastlight-evals 0.1.1 → 0.2.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.
Files changed (36) hide show
  1. package/README.md +198 -39
  2. package/dashboard/dist/assets/index-YwScAAxm.js +238 -0
  3. package/dashboard/dist/assets/index-uU9Sj3M4.css +1 -0
  4. package/dashboard/dist/index.html +19 -0
  5. package/dashboard/dist/logo.png +0 -0
  6. package/datasets/code-fix/repos/codefix__date-range-off-by-one/.github/workflows/ci.yml +16 -0
  7. package/datasets/code-fix/repos/codefix__date-range-off-by-one/README.md +7 -1
  8. package/datasets/code-fix/repos/codefix__date-range-off-by-one/package.json +3 -1
  9. package/datasets/code-fix/repos/codefix__date-range-off-by-one/scripts/lint.mjs +25 -0
  10. package/datasets/code-fix/repos/codefix__date-range-off-by-one/test/date-range.test.ts +14 -0
  11. package/datasets/code-fix/repos/codefix__date-range-off-by-one/tsconfig.json +13 -0
  12. package/datasets/code-fix/tests/codefix__date-range-off-by-one/date-range.test.ts +5 -5
  13. package/dist/config.js +100 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/init.js +229 -32
  16. package/dist/init.js.map +1 -1
  17. package/dist/mechanism.test.js +41 -0
  18. package/dist/mechanism.test.js.map +1 -1
  19. package/dist/metrics.js +91 -3
  20. package/dist/metrics.js.map +1 -1
  21. package/dist/paths.js +51 -1
  22. package/dist/paths.js.map +1 -1
  23. package/dist/report.js +128 -6
  24. package/dist/report.js.map +1 -1
  25. package/dist/run-instance.js +143 -14
  26. package/dist/run-instance.js.map +1 -1
  27. package/dist/run.js +401 -89
  28. package/dist/run.js.map +1 -1
  29. package/dist/serve.js +136 -0
  30. package/dist/serve.js.map +1 -0
  31. package/examples/overlay/README.md +30 -0
  32. package/examples/overlay/config.yaml +36 -0
  33. package/examples/overlay-anthropic/config.yaml +27 -0
  34. package/package.json +16 -6
  35. package/dist/html-report.js +0 -325
  36. package/dist/html-report.js.map +0 -1
package/dist/init.js CHANGED
@@ -1,24 +1,32 @@
1
1
  /**
2
- * `lastlight-evals init [dir]` — scaffold a fresh overlay + evals repo, seeded
3
- * from the shipped defaults, then optionally version it as a private GitHub repo.
2
+ * `lastlight-evals init [dir]` — scaffold an eval workspace, in one of two shapes.
4
3
  *
5
- * The result is a self-contained deployment overlay: it carries its own
6
- * `workflows/` / `skills/` / `agent-context/` (which shadow the built-ins by
7
- * logical name) AND its own `evals/datasets/` + `evals/models.json`. Point the
8
- * runner at it with `lastlight-evals run --overlay <dir>` (or run from inside
9
- * it with `--overlay .`). It's pure data/config — no node deps; the globally
10
- * installed CLI supplies the runtime.
4
+ * 1. **Plain** (`init [dir]`) — a self-contained overlay+evals repo: it carries
5
+ * its own `workflows/` / `skills/` / `agent-context/` (which shadow the
6
+ * built-ins by logical name) AND its own `evals/datasets/` + `evals/models.json`.
7
+ * Run it with `--overlay .`. Offered git/GitHub bootstrap via core's
8
+ * `detectGh` + `bootstrapOverlayRepo`.
11
9
  *
12
- * Git/GitHub bootstrap reuses core's `detectGh` + `bootstrapOverlayRepo` (the
13
- * same flow behind `lastlight server setup`) via the `lastlight/evals` barrel —
14
- * git init + initial commit + an offered `gh repo create --private`.
10
+ * 2. **Separate** (`init [dir] --clone <owner/repo>`) — the recommended shape
11
+ * when you already have a deployment overlay repo (e.g. `lastlight-instance`).
12
+ * The overlay is cloned into `<dir>/instance/` (its own git checkout, which
13
+ * the workspace `.gitignore`s) and the evals live at the workspace root
14
+ * (`evals/datasets/`, `evals/models.json`). The runner auto-detects `./instance`
15
+ * as the overlay and the local `./evals/datasets`, so a bare
16
+ * `lastlight-evals run` from the workspace "just works" — no flags. Evals stay
17
+ * out of your deployment repo; you `git pull` the overlay in `instance/`.
18
+ *
19
+ * It's pure data/config — no node deps; the globally installed CLI supplies the runtime.
15
20
  */
16
- import { existsSync, mkdirSync, writeFileSync, cpSync } from "node:fs";
21
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, cpSync, readdirSync, renameSync, rmSync } from "node:fs";
17
22
  import { join, resolve, basename } from "node:path";
23
+ import { execFile } from "node:child_process";
24
+ import { promisify } from "node:util";
18
25
  import * as p from "@clack/prompts";
19
26
  import chalk from "chalk";
20
27
  import { detectGh, bootstrapOverlayRepo } from "lastlight/evals";
21
28
  import { builtinDatasetsRoot, builtinModelsPath } from "./paths.js";
29
+ const exec = promisify(execFile);
22
30
  const CONFIG_YAML = `# Last Light — eval/overlay config (merged over the core config/default.yaml).
23
31
  # Arrays replace, maps deep-merge, env vars override. See the lastlight docs.
24
32
  #
@@ -37,7 +45,37 @@ secrets/*
37
45
  !secrets/.env.example
38
46
  *.pem
39
47
  `;
40
- function readmeFor(name) {
48
+ // Entries every eval workspace MUST ignore. `eval-results/` is always required;
49
+ // the Separate layout adds `instance/` (a nested overlay checkout). These are
50
+ // enforced even when a `.gitignore` already exists (plain init writes the full
51
+ // template; clone-into-subdir adds these to whatever the dir already has).
52
+ const EVAL_OUTPUT_IGNORE = "eval-results/";
53
+ const INSTANCE_IGNORE = "instance/";
54
+ /**
55
+ * Guarantee `.gitignore` exists and ignores `required` entries. Writes the full
56
+ * template when absent; otherwise appends only the lines it's missing
57
+ * (idempotent) so an existing `.gitignore` is preserved but the eval output (and,
58
+ * in the Separate layout, the `instance/` overlay checkout) is never committed.
59
+ */
60
+ function ensureGitignore(dir, created, required) {
61
+ const abs = join(dir, ".gitignore");
62
+ if (!existsSync(abs)) {
63
+ const extra = required.filter((l) => !GITIGNORE.includes(l));
64
+ writeFileSync(abs, extra.length ? `${GITIGNORE}\n${extra.join("\n")}\n` : GITIGNORE, "utf8");
65
+ created.push(".gitignore");
66
+ return;
67
+ }
68
+ const existing = readFileSync(abs, "utf8");
69
+ const have = new Set(existing.split("\n").map((l) => l.trim()));
70
+ const missing = required.filter((l) => !have.has(l));
71
+ if (!missing.length)
72
+ return;
73
+ const sep = existing.endsWith("\n") ? "" : "\n";
74
+ writeFileSync(abs, `${existing}${sep}\n# Last Light eval workspace — regenerated/checkout artifacts, never commit.\n${missing.join("\n")}\n`, "utf8");
75
+ created.push(`.gitignore (added ${missing.join(", ")})`);
76
+ }
77
+ /** README for the plain (self-overlay) workspace. */
78
+ function readmePlain(name) {
41
79
  return `# ${name}
42
80
 
43
81
  A Last Light **eval + overlay** workspace, created by \`lastlight-evals init\`.
@@ -64,8 +102,81 @@ lastlight-evals run code-fix --overlay .
64
102
  Override which core build the evals test with \`LASTLIGHT_CORE_DIR=/path/to/lastlight\`.
65
103
  `;
66
104
  }
67
- /** Write the default files/dirs into `dir`, never overwriting what exists. */
68
- function scaffoldEvalRepo(dir) {
105
+ /** README for the Separate layout — overlay checked out in `instance/`. */
106
+ function readmeSeparate(name, repo) {
107
+ return `# ${name}
108
+
109
+ A Last Light **eval workspace** created by \`lastlight-evals init --clone ${repo}\`.
110
+
111
+ The deployment overlay [\`${repo}\`](https://github.com/${repo}) is checked out in
112
+ \`instance/\` (its own git repo, \`.gitignore\`d here) and the evals live at the
113
+ workspace root. The runner auto-detects \`./instance\` as the overlay and your
114
+ local \`./evals/datasets\`, so a bare run "just works".
115
+
116
+ ## Layout
117
+
118
+ - \`instance/\` — your deployment overlay (config, workflows, skills, persona).
119
+ A separate git checkout — \`cd instance && git pull\` to update it.
120
+ - \`evals/datasets/<tier>/\` — eval datasets, seeded with the shipped
121
+ \`triage\` / \`code-fix\` samples. Edit or add tiers here.
122
+ - \`evals/models.json\` — the model registry these evals run against.
123
+ - \`.env\` — your provider key(s). GitHub is mocked, so no GitHub token is needed.
124
+
125
+ ## Run
126
+
127
+ \`\`\`bash
128
+ lastlight-evals run # auto: overlay ./instance + local datasets
129
+ lastlight-evals run code-fix # one tier
130
+ lastlight-evals run --compare # cross-vendor set (key-gated)
131
+ \`\`\`
132
+
133
+ Override which core build the evals test with \`LASTLIGHT_CORE_DIR=/path/to/lastlight\`.
134
+ `;
135
+ }
136
+ /** Turn a `--clone` value into a clone URL. Accepts a full URL/scp ref as-is,
137
+ * else treats `owner/repo` as a GitHub slug. */
138
+ function cloneUrl(repo) {
139
+ return /^(https?:\/\/|git@|ssh:\/\/)/.test(repo) ? repo : `https://github.com/${repo}.git`;
140
+ }
141
+ /**
142
+ * Clone an existing overlay repo (e.g. a deployment's `lastlight-instance`) into
143
+ * `target` as its own git checkout. Idempotent — if `target` is already a repo it
144
+ * leaves it untouched (so re-running `init` doesn't reclone). Clones to a temp
145
+ * sibling first and moves the contents in, so a pre-populated `target` keeps its
146
+ * files. Prefers `gh` (handles private-repo auth) and falls back to plain `git`.
147
+ */
148
+ async function cloneOverlayInto(target, repo) {
149
+ if (existsSync(join(target, ".git"))) {
150
+ p.log.info(`${chalk.cyan(target)} is already a checkout — skipping clone of ${chalk.bold(repo)} (\`cd instance && git pull\` to update).`);
151
+ return false;
152
+ }
153
+ mkdirSync(target, { recursive: true });
154
+ const tmp = `${target}.clone-tmp`;
155
+ rmSync(tmp, { recursive: true, force: true });
156
+ p.log.step(`Cloning ${chalk.bold(repo)} → ${chalk.cyan(target)}`);
157
+ try {
158
+ await exec("gh", ["repo", "clone", repo, tmp]);
159
+ }
160
+ catch {
161
+ await exec("git", ["clone", "--quiet", cloneUrl(repo), tmp]);
162
+ }
163
+ // Move cloned entries (including .git) into target, never clobbering what's there.
164
+ for (const entry of readdirSync(tmp)) {
165
+ const dst = join(target, entry);
166
+ if (!existsSync(dst))
167
+ renameSync(join(tmp, entry), dst);
168
+ }
169
+ rmSync(tmp, { recursive: true, force: true });
170
+ return true;
171
+ }
172
+ /**
173
+ * Write the default files/dirs into `dir`, never overwriting what exists.
174
+ * `overlayRepo` set ⇒ Separate layout: the overlay is a cloned `instance/`, so we
175
+ * skip the root `config.yaml` + `workflows/skills/agent-context` placeholders
176
+ * (those belong to — and are read from — `instance/`) and `.gitignore` the
177
+ * checkout. Either way we always seed `evals/datasets/` + `evals/models.json`.
178
+ */
179
+ function scaffoldEvalRepo(dir, overlayRepo) {
69
180
  const created = [];
70
181
  const writeIfMissing = (rel, content) => {
71
182
  const abs = join(dir, rel);
@@ -75,12 +186,9 @@ function scaffoldEvalRepo(dir) {
75
186
  writeFileSync(abs, content, "utf8");
76
187
  created.push(rel);
77
188
  };
78
- // Overlay asset dirs (empty placeholders the user fills in).
79
- for (const d of ["workflows", "skills", "agent-context"]) {
80
- const keep = join(d, ".gitkeep");
81
- writeIfMissing(keep, "");
82
- }
83
189
  // Seed datasets + models from the shipped defaults (a starting point to edit).
190
+ // Always created — the workspace's own `evals/datasets/` is what the runner
191
+ // auto-discovers, so it must exist even when the overlay lives in `instance/`.
84
192
  const datasetsDst = join(dir, "evals", "datasets");
85
193
  if (!existsSync(datasetsDst)) {
86
194
  mkdirSync(datasetsDst, { recursive: true });
@@ -92,31 +200,120 @@ function scaffoldEvalRepo(dir) {
92
200
  cpSync(builtinModelsPath(), modelsDst);
93
201
  created.push("evals/models.json");
94
202
  }
95
- writeIfMissing("config.yaml", CONFIG_YAML);
96
- writeIfMissing(".gitignore", GITIGNORE);
97
- writeIfMissing("README.md", readmeFor(basename(dir)));
203
+ if (overlayRepo) {
204
+ // Separate layout — overlay assets + config come from the `instance/` checkout.
205
+ ensureGitignore(dir, created, [EVAL_OUTPUT_IGNORE, INSTANCE_IGNORE]);
206
+ writeIfMissing("README.md", readmeSeparate(basename(dir), overlayRepo));
207
+ }
208
+ else {
209
+ // Plain layout — this repo is its own overlay.
210
+ for (const d of ["workflows", "skills", "agent-context"]) {
211
+ writeIfMissing(join(d, ".gitkeep"), "");
212
+ }
213
+ writeIfMissing("config.yaml", CONFIG_YAML);
214
+ ensureGitignore(dir, created, [EVAL_OUTPUT_IGNORE]);
215
+ writeIfMissing("README.md", readmePlain(basename(dir)));
216
+ }
98
217
  return created;
99
218
  }
100
- export async function runInit(dirArg) {
219
+ const INIT_USAGE = `lastlight-evals init [dir] [options]
220
+
221
+ Scaffold a fresh overlay + evals workspace (seeded triage + code-fix datasets).
222
+
223
+ Arguments:
224
+ dir Target directory (default: lastlight-evals-workspace; "." = here)
225
+
226
+ Options:
227
+ --clone <repo> Separate layout: clone an existing overlay repo (owner/repo or
228
+ URL) into <dir>/instance/ (its own checkout, git-ignored) and
229
+ scaffold evals/ at the root. The runner auto-detects ./instance
230
+ + ./evals/datasets, so a bare \`lastlight-evals run\` just works.
231
+ --yes, -y Non-interactive: scaffold without prompting; print the manual
232
+ git/GitHub commands instead of running them.
233
+ --no-git Scaffold files only; skip the git/GitHub bootstrap entirely.
234
+ --help, -h Show this help.
235
+
236
+ With no TTY (piped/automation), behaves as --yes so it never blocks on a prompt.
237
+
238
+ Example — point an eval workspace at your deployment overlay:
239
+ lastlight-evals init . --clone your-org/lastlight-instance
240
+ lastlight-evals run`;
241
+ /**
242
+ * `init [dir] [flags]`. Parses its own argv slice so it's safe to drive
243
+ * head-less: a leading `--flag` is never mistaken for the target dir, and the
244
+ * interactive git/GitHub bootstrap is skipped when there's no TTY (or when
245
+ * `--yes`/`--no-git` is passed) so an agent or CI run can't hang on a prompt.
246
+ */
247
+ export async function runInit(args = []) {
248
+ if (args.includes("--help") || args.includes("-h")) {
249
+ console.log(INIT_USAGE);
250
+ return 0;
251
+ }
252
+ const noGit = args.includes("--no-git");
253
+ // Non-interactive when asked (--yes/-y) or whenever stdin isn't a TTY, so
254
+ // automation never blocks on the version-as-repo confirm prompt.
255
+ const yes = args.includes("--yes") || args.includes("-y") || !process.stdin.isTTY;
256
+ // `--clone <repo>` / `--from <repo>` — its value isn't the target dir.
257
+ const valFlag = (...names) => {
258
+ for (let i = 0; i < args.length; i++) {
259
+ const eq = names.find((n) => args[i].startsWith(`${n}=`));
260
+ if (eq)
261
+ return args[i].slice(eq.length + 1);
262
+ if (names.includes(args[i]))
263
+ return args[i + 1];
264
+ }
265
+ return undefined;
266
+ };
267
+ const cloneRepo = valFlag("--clone", "--from");
268
+ const dirArg = args.find((a, i) => !a.startsWith("-") && args[i - 1] !== "--clone" && args[i - 1] !== "--from");
101
269
  p.intro(chalk.bold(`Last Light ${chalk.yellow("·")} eval init`));
102
270
  const dir = resolve(dirArg ?? "lastlight-evals-workspace");
271
+ // Separate layout: clone the overlay into `<dir>/instance/` (its own checkout),
272
+ // then scaffold the evals at the root with `instance/` git-ignored. The runner
273
+ // auto-detects `./instance` + `./evals/datasets`.
274
+ if (cloneRepo) {
275
+ try {
276
+ await cloneOverlayInto(join(dir, "instance"), cloneRepo);
277
+ }
278
+ catch (err) {
279
+ p.log.error(`Clone of ${cloneRepo} failed: ${err.message}`);
280
+ p.outro(chalk.red("aborted"));
281
+ return 1;
282
+ }
283
+ }
103
284
  p.log.step(`Scaffolding ${chalk.cyan(dir)}`);
104
- const created = scaffoldEvalRepo(dir);
285
+ const created = scaffoldEvalRepo(dir, cloneRepo);
105
286
  if (created.length) {
106
287
  p.log.success(`Created:\n ${created.join("\n ")}`);
107
288
  }
108
289
  else {
109
290
  p.log.info("Nothing to scaffold — every default file already existed.");
110
291
  }
111
- // Offer to version it + create a private GitHub repo (reuses core's flow).
112
- try {
113
- const gh = await detectGh();
114
- await bootstrapOverlayRepo(dir, { gh });
292
+ // Git/GitHub bootstrap (plain layout only — the overlay carries its own repo).
293
+ // `--no-git` skips it; otherwise `yes` forwards core's non-interactive path
294
+ // (scaffolds + prints the manual git/gh commands rather than prompting).
295
+ if (cloneRepo) {
296
+ p.log.info(`Overlay checked out in ${chalk.cyan("instance/")} — ${chalk.dim("cd instance && git pull")} to update it.`);
297
+ }
298
+ else if (noGit) {
299
+ p.log.info(`Skipped git/GitHub bootstrap (--no-git). Version it yourself with ${chalk.dim("git init")}.`);
115
300
  }
116
- catch (err) {
117
- p.log.warn(`Skipped git/GitHub bootstrap: ${err.message}`);
301
+ else {
302
+ try {
303
+ const gh = await detectGh();
304
+ await bootstrapOverlayRepo(dir, { gh, yes });
305
+ }
306
+ catch (err) {
307
+ p.log.warn(`Skipped git/GitHub bootstrap: ${err.message}`);
308
+ }
118
309
  }
119
- p.outro(chalk.green(`done — run it with: ${chalk.bold(`lastlight-evals run --overlay ${dir === process.cwd() ? "." : dir}`)}`));
310
+ const here = dir === process.cwd();
311
+ const runCmd = cloneRepo
312
+ ? here
313
+ ? "lastlight-evals run"
314
+ : `cd ${dir} && lastlight-evals run`
315
+ : `lastlight-evals run --overlay ${here ? "." : dir}`;
316
+ p.outro(chalk.green(`done — run it with: ${chalk.bold(runCmd)}`));
120
317
  return 0;
121
318
  }
122
319
  //# sourceMappingURL=init.js.map
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ import { tmpdir } from "node:os";
15
15
  import { startFakeGitHub } from "./fake-github.js";
16
16
  import { seedWorkspace } from "./seed.js";
17
17
  import { gradeExecution, gradeBehavioral, gradeTriage } from "./grade.js";
18
+ import { loadMergedConfig, resolvePhaseModel } from "./config.js";
18
19
  const staticAuth = { getToken: async () => "fake-token", expiresAt: null };
19
20
  describe("fake GitHub + agentic-pi github tools (baseUrl seam)", () => {
20
21
  it("serves seeded issues and records mutations made through the real GitHubClient", async () => {
@@ -61,6 +62,46 @@ describe("fake GitHub + agentic-pi github tools (baseUrl seam)", () => {
61
62
  }
62
63
  });
63
64
  });
65
+ describe("config run type — per-step model resolution (config.ts)", () => {
66
+ it("deep-merges overlay config.yaml over core default.yaml (overlay wins per key)", () => {
67
+ const root = mkdtempSync(join(tmpdir(), "ll-eval-cfg-"));
68
+ try {
69
+ // A stand-in core root: just the one file loadMergedConfig reads.
70
+ mkdirSync(join(root, "config"), { recursive: true });
71
+ writeFileSync(join(root, "config", "default.yaml"), "models:\n default: anthropic/claude-sonnet-4-6\nvariants: {}\n");
72
+ // An overlay that retargets some phases + sets a variant.
73
+ const overlay = join(root, "overlay");
74
+ mkdirSync(overlay, { recursive: true });
75
+ writeFileSync(join(overlay, "config.yaml"), "models:\n default: openai/gpt-5.4-mini\n architect: openai/gpt-5.5\nvariants:\n guardrails: low\n");
76
+ const { models, variants } = loadMergedConfig(root, overlay);
77
+ expect(models.default).toBe("openai/gpt-5.4-mini"); // overlay wins
78
+ expect(models.architect).toBe("openai/gpt-5.5"); // overlay-only key kept
79
+ expect(variants.guardrails).toBe("low");
80
+ // No overlay ⇒ just the core defaults.
81
+ const core = loadMergedConfig(root);
82
+ expect(core.models.default).toBe("anthropic/claude-sonnet-4-6");
83
+ expect(core.models.architect).toBeUndefined();
84
+ }
85
+ finally {
86
+ rmSync(root, { recursive: true, force: true });
87
+ }
88
+ });
89
+ it("resolvePhaseModel mirrors core precedence: {{models.X}} template → models[phase] → default", () => {
90
+ const models = { default: "m-default", guardrails: "m-guard", explore: "m-explore" };
91
+ // 1. A phase whose YAML names `{{models.guardrails}}` → that template wins.
92
+ expect(resolvePhaseModel("{{models.guardrails}}", "guardrails", models)).toBe("m-guard");
93
+ // 2. A template keyed differently from the phase name (explore.yaml's
94
+ // `read_context` phase uses `{{models.explore}}`) → the TEMPLATE key wins,
95
+ // NOT the phase-name lookup. This is the case the `ctx.models` wiring guards.
96
+ expect(resolvePhaseModel("{{models.explore}}", "read_context", models)).toBe("m-explore");
97
+ // 3. No template, phase name present in the map → that entry.
98
+ expect(resolvePhaseModel(undefined, "guardrails", models)).toBe("m-guard");
99
+ // 4. No template, unmapped phase → the default.
100
+ expect(resolvePhaseModel(undefined, "executor", models)).toBe("m-default");
101
+ // 5. Template referencing an unset key → falls through to phase/default.
102
+ expect(resolvePhaseModel("{{models.missing}}", "executor", models)).toBe("m-default");
103
+ });
104
+ });
64
105
  describe("workspace seed + execution grade (SWE-bench resolved)", () => {
65
106
  it("flips red→green when the bug is fixed, and detects PASS_TO_PASS regressions", () => {
66
107
  const stateDir = mkdtempSync(join(tmpdir(), "ll-eval-mech-"));
@@ -1 +1 @@
1
- {"version":3,"file":"mechanism.test.js","sourceRoot":"","sources":["../src/mechanism.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mechanism.test.js","sourceRoot":"","sources":["../src/mechanism.test.ts"],"names":[],"mappings":"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"}
package/dist/metrics.js CHANGED
@@ -2,8 +2,11 @@
2
2
  * Pull per-run token/cost/turn metrics out of the session jsonl the event
3
3
  * shim writes (`src/engine/event-shim.ts`). Each phase emits one `result`
4
4
  * envelope carrying `total_cost_usd` / `total_input_tokens` /
5
- * `total_output_tokens`. We sum them across every jsonl under the run's
6
- * sessions dir. Best-effort: missing files / lines just contribute zero.
5
+ * `total_output_tokens` (plus `total_cache_read_input_tokens` /
6
+ * `total_cache_creation_input_tokens`, which we sum into `cachedTokens` —
7
+ * Anthropic bills most of its prompt as cached, so omitting it made input
8
+ * collapse to ~zero). We sum them across every jsonl under the run's sessions
9
+ * dir. Best-effort: missing files / lines just contribute zero.
7
10
  */
8
11
  import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
9
12
  import { join } from "node:path";
@@ -43,6 +46,89 @@ export async function drainSessions(sessionsDir, maxMs = 4000, quietMs = 250) {
43
46
  await new Promise((r) => setTimeout(r, 80));
44
47
  }
45
48
  }
49
+ /** Enumerate the run's session jsonl files (one per sessionId / phase / sub-agent
50
+ * run), each with its first-line timestamp, sorted chronologically. The harness
51
+ * maps these to workflow phases by start-time window (see run-instance). */
52
+ export function listSessionFiles(sessionsDir) {
53
+ const files = [];
54
+ walkJsonl(join(sessionsDir, "projects"), files);
55
+ walkJsonl(sessionsDir, files);
56
+ const seen = new Set();
57
+ const out = [];
58
+ for (const file of files) {
59
+ if (seen.has(file))
60
+ continue;
61
+ seen.add(file);
62
+ let firstTs = 0;
63
+ try {
64
+ for (const line of readFileSync(file, "utf8").split("\n")) {
65
+ const t = line.trim();
66
+ if (!t)
67
+ continue;
68
+ try {
69
+ const o = JSON.parse(t);
70
+ if (o.timestamp != null) {
71
+ firstTs = typeof o.timestamp === "number" ? o.timestamp * 1000 : Date.parse(o.timestamp);
72
+ break;
73
+ }
74
+ }
75
+ catch {
76
+ /* keep scanning */
77
+ }
78
+ }
79
+ }
80
+ catch {
81
+ /* unreadable — leave firstTs 0 */
82
+ }
83
+ out.push({ file, firstTs });
84
+ }
85
+ return out.sort((a, b) => a.firstTs - b.firstTs);
86
+ }
87
+ /** Concatenate the given jsonl files (already in order) into one raw jsonl
88
+ * string. Best-effort: an unreadable file contributes nothing. */
89
+ export function concatJsonl(files) {
90
+ const chunks = [];
91
+ for (const f of files) {
92
+ try {
93
+ const text = readFileSync(f, "utf8").trim();
94
+ if (text)
95
+ chunks.push(text);
96
+ }
97
+ catch {
98
+ /* skip */
99
+ }
100
+ }
101
+ return chunks.length ? chunks.join("\n") + "\n" : "";
102
+ }
103
+ /**
104
+ * Concatenate every session jsonl under a run's sessions dir into one raw jsonl
105
+ * string (stable phase order by path, de-duplicated), for archiving alongside
106
+ * the run + later rendering in the dashboard. Each run uses a fresh temp
107
+ * `stateDir`, so all jsonl under it belong to that one instance — no slug
108
+ * matching needed (the same set `collectMetrics` reads). Best-effort: an
109
+ * unreadable file just contributes nothing.
110
+ */
111
+ export function readSessionLog(sessionsDir) {
112
+ const files = [];
113
+ walkJsonl(join(sessionsDir, "projects"), files);
114
+ walkJsonl(sessionsDir, files);
115
+ const seen = new Set();
116
+ const chunks = [];
117
+ for (const file of [...files].sort()) {
118
+ if (seen.has(file))
119
+ continue;
120
+ seen.add(file);
121
+ try {
122
+ const text = readFileSync(file, "utf8").trim();
123
+ if (text)
124
+ chunks.push(text);
125
+ }
126
+ catch {
127
+ /* best-effort */
128
+ }
129
+ }
130
+ return chunks.length ? chunks.join("\n") + "\n" : "";
131
+ }
46
132
  function walkJsonl(dir, out) {
47
133
  if (!existsSync(dir))
48
134
  return;
@@ -60,7 +146,7 @@ export function collectMetrics(sessionsDir) {
60
146
  // Fallback: some shim configs write directly under sessionsDir.
61
147
  walkJsonl(sessionsDir, files);
62
148
  const seen = new Set();
63
- const metrics = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
149
+ const metrics = { inputTokens: 0, cachedTokens: 0, outputTokens: 0, costUsd: 0 };
64
150
  for (const file of files) {
65
151
  if (seen.has(file))
66
152
  continue;
@@ -73,6 +159,8 @@ export function collectMetrics(sessionsDir) {
73
159
  if (env.type !== "result")
74
160
  continue;
75
161
  metrics.inputTokens += env.total_input_tokens ?? 0;
162
+ metrics.cachedTokens +=
163
+ (env.total_cache_read_input_tokens ?? 0) + (env.total_cache_creation_input_tokens ?? 0);
76
164
  metrics.outputTokens += env.total_output_tokens ?? 0;
77
165
  metrics.costUsd += env.total_cost_usd ?? 0;
78
166
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
package/dist/paths.js CHANGED
@@ -10,8 +10,10 @@
10
10
  * Run OUTPUT, by contrast, is written under the caller's cwd (an installed
11
11
  * package dir is read-only), overridable via `LASTLIGHT_EVALS_OUT`.
12
12
  */
13
- import { dirname, resolve } from "node:path";
13
+ import { existsSync } from "node:fs";
14
+ import { dirname, join, resolve } from "node:path";
14
15
  import { fileURLToPath } from "node:url";
16
+ import { spawnSync } from "node:child_process";
15
17
  /** Package root: the dir holding `datasets/`, `models.json`, `package.json`. */
16
18
  export function packageRoot() {
17
19
  return resolve(dirname(fileURLToPath(import.meta.url)), "..");
@@ -24,10 +26,58 @@ export function builtinDatasetsRoot() {
24
26
  export function builtinModelsPath() {
25
27
  return resolve(packageRoot(), "models.json");
26
28
  }
29
+ /**
30
+ * Built dashboard SPA assets (`<pkg>/dashboard/dist`) served by `serve`. Shipped
31
+ * prebuilt in the npm package so an installed CLI needs no Vite at runtime; in
32
+ * this repo it's produced by `npm run build` (which also builds the harness).
33
+ * Overridable via `LASTLIGHT_EVALS_DASHBOARD` for development.
34
+ */
35
+ export function dashboardDistRoot() {
36
+ return process.env.LASTLIGHT_EVALS_DASHBOARD
37
+ ? resolve(process.env.LASTLIGHT_EVALS_DASHBOARD)
38
+ : resolve(packageRoot(), "dashboard", "dist");
39
+ }
27
40
  /** Where scorecards/artifacts are written (cwd-relative, NOT the package dir). */
28
41
  export function resultsRoot() {
29
42
  return process.env.LASTLIGHT_EVALS_OUT
30
43
  ? resolve(process.env.LASTLIGHT_EVALS_OUT)
31
44
  : resolve(process.cwd(), "eval-results");
32
45
  }
46
+ /**
47
+ * The tier-combo directory — `<resultsRoot>/<tiersKey>`. It holds the
48
+ * overview/history `index.html` plus one timestamped subdir per run, so runs
49
+ * accumulate instead of overwriting each other.
50
+ */
51
+ export function tierResultsDir(tiersKey) {
52
+ return join(resultsRoot(), tiersKey);
53
+ }
54
+ /** Short git SHA of HEAD, or `undefined` outside a repo / on any failure. */
55
+ export function gitShortSha() {
56
+ try {
57
+ const r = spawnSync("git", ["rev-parse", "--short", "HEAD"], { encoding: "utf8" });
58
+ const sha = r.status === 0 ? r.stdout.trim() : "";
59
+ return sha || undefined;
60
+ }
61
+ catch {
62
+ return undefined;
63
+ }
64
+ }
65
+ /**
66
+ * A sortable, filesystem-safe run id: `YYYY-MM-DD_HHMMSS` (UTC, matching the
67
+ * `toISOString()` timestamps used elsewhere) optionally suffixed with the short
68
+ * git SHA of the code under test (e.g. `2026-06-28_143052-a0229c5`). If
69
+ * `parentDir` already holds that id, a numeric `-2`/`-3` suffix is appended so
70
+ * two runs in the same second never collide.
71
+ */
72
+ export function makeRunId(date, gitSha, parentDir) {
73
+ // 2026-06-28T14:30:52.123Z → 2026-06-28_143052
74
+ const stamp = date.toISOString().replace(/\.\d+Z$/, "").replace(/:/g, "").replace("T", "_");
75
+ const base = gitSha ? `${stamp}-${gitSha}` : stamp;
76
+ if (!parentDir)
77
+ return base;
78
+ let id = base;
79
+ for (let n = 2; existsSync(join(parentDir, id)); n++)
80
+ id = `${base}-${n}`;
81
+ return id;
82
+ }
33
83
  //# sourceMappingURL=paths.js.map