@uinaf/skillcheck 1.4.0 → 1.4.1

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/cli.js CHANGED
@@ -357,6 +357,17 @@ function readJson(file) {
357
357
  return;
358
358
  }
359
359
  }
360
+ function liveScenarios(root) {
361
+ const cli = path.join(root, "cli");
362
+ if (!(fs.existsSync(path.join(root, "skills")) || fs.existsSync(cli) && fs.readdirSync(cli).some((d) => fs.existsSync(path.join(cli, d, "skills"))))) return void 0;
363
+ return new Set(discoverScenarios(root).map((dir) => {
364
+ const parts = dir.split(path.sep);
365
+ return `${parts.at(-3)}\0${parts.at(-1)}`;
366
+ }));
367
+ }
368
+ function isLive(live, e) {
369
+ return live === void 0 || live.has(`${e.skill}\0${e.scenario}`);
370
+ }
360
371
  function discoverScenarios(root) {
361
372
  const roots = [path.join(root, "skills")];
362
373
  const cliDir = path.join(root, "cli");
@@ -464,15 +475,26 @@ function resultIdentity(file, dir) {
464
475
  variant
465
476
  };
466
477
  }
467
- function reduceResults(dir, allowMixed) {
478
+ function reduceResults(dir, allowMixed, live) {
468
479
  const entries = [];
469
480
  const skipped = [];
481
+ const retired = /* @__PURE__ */ new Set();
470
482
  const gradedAt = /* @__PURE__ */ new Map();
471
483
  const shas = /* @__PURE__ */ new Set();
472
484
  const files = fs.readdirSync(dir);
473
485
  const incomplete = new Set(files.filter((f) => f.endsWith(".json.attempt")).map((f) => f.replace(/\.attempt$/, "")));
474
486
  const results = files.filter((f) => f.endsWith(".json") && !f.endsWith(".meta.json"));
475
487
  for (const f of [.../* @__PURE__ */ new Set([...results, ...incomplete])].sort()) {
488
+ let identity;
489
+ try {
490
+ identity = resultIdentity(f, dir);
491
+ } catch {
492
+ identity = void 0;
493
+ }
494
+ if (identity !== void 0 && identity.scenario !== "" && !isLive(live, identity)) {
495
+ retired.add(entryKey(identity));
496
+ continue;
497
+ }
476
498
  if (f.endsWith("--cursor.json")) {
477
499
  console.error(`skipping ${f}: Cursor harness is retired`);
478
500
  skipped.push(f);
@@ -522,7 +544,8 @@ function reduceResults(dir, allowMixed) {
522
544
  treeSha: shas.size === 1 ? [...shas][0] : shas.size === 0 ? "none" : "mixed",
523
545
  entries,
524
546
  skipped,
525
- gradedAt
547
+ gradedAt,
548
+ retired
526
549
  };
527
550
  }
528
551
  function entryKey(e) {
@@ -565,12 +588,17 @@ function readExistingScorecard(out) {
565
588
  function cmdSummarize(argv) {
566
589
  const { positional, flags } = parseArgs(argv);
567
590
  if (positional.length > 0) fail("usage: skillcheck summarize [--root DIR] [--allow-mixed]");
568
- const dirs = stateDirs(resolveRoot(flags));
591
+ const root = resolveRoot(flags);
592
+ const dirs = stateDirs(root);
569
593
  if (!fs.existsSync(dirs.results)) fail(`no results directory at ${dirs.results}; run some evals first`);
570
- const { entries, skipped, gradedAt } = reduceResults(dirs.results, flags.get("--allow-mixed") === true);
594
+ const live = liveScenarios(root);
595
+ const { entries, skipped, gradedAt, retired: retiredResults } = reduceResults(dirs.results, flags.get("--allow-mixed") === true, live);
571
596
  fs.mkdirSync(dirs.scorecards, { recursive: true });
572
597
  const out = path.join(dirs.scorecards, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`);
573
- const existing = readExistingScorecard(out);
598
+ const previous = readExistingScorecard(out);
599
+ const existing = previous.filter((e) => isLive(live, e));
600
+ for (const e of previous) if (!isLive(live, e)) retiredResults.add(entryKey(e));
601
+ const retired = retiredResults.size;
574
602
  const skippedKeys = new Set(skipped.map((file) => ({
575
603
  key: entryKey(resultIdentity(file, dirs.results)),
576
604
  modifiedAt: fs.statSync(fs.existsSync(path.join(dirs.results, `${file}.attempt`)) ? path.join(dirs.results, `${file}.attempt`) : path.join(dirs.results, file)).mtimeMs
@@ -587,6 +615,7 @@ function cmdSummarize(argv) {
587
615
  scenarios: merged.entries
588
616
  };
589
617
  fs.writeFileSync(out, JSON.stringify(scorecard, null, 2) + "\n");
618
+ if (retired > 0) console.log(`dropped ${retired} row(s) for scenarios no longer in the tree`);
590
619
  const scenarios = merged.entries.filter((e) => e.variant !== "control");
591
620
  console.log(`${out}: ${scenarios.length} scenario(s), ${scenarios.filter((e) => e.pass).length} passing, ${merged.entries.length - scenarios.length} control(s), ${skipped.length} skipped file(s)`);
592
621
  if (existing.length > 0) console.log(`merged into today's scorecard: ${entries.length} from this run, ${merged.carried} carried over`);
@@ -688,4 +717,4 @@ if (isMainModule()) {
688
717
  }
689
718
  }
690
719
  //#endregion
691
- export { NOISY_SPREAD, aggregateTrials, assertUniformConfig, classifyResult, ensurePrivateDir, formatStats, mergeScorecard, parseArgs, parsePositiveInt, reduceResults, resolveRoot, resultRunConfig, runConfigOf, runOptions, stateDirs, summarizeSkills, toolVersion, treeShaOf };
720
+ export { NOISY_SPREAD, aggregateTrials, assertUniformConfig, classifyResult, ensurePrivateDir, formatStats, liveScenarios, mergeScorecard, parseArgs, parsePositiveInt, reduceResults, resolveRoot, resultRunConfig, runConfigOf, runOptions, stateDirs, summarizeSkills, toolVersion, treeShaOf };
package/docs/usage.md CHANGED
@@ -179,6 +179,11 @@ six of twenty-nine scenarios therefore leaves twenty-nine rows in the file, not
179
179
  six. A same-date file that cannot be parsed stops the write instead of being
180
180
  overwritten.
181
181
 
182
+ Rows for scenarios that no longer exist in the tree, whether carried from
183
+ today's scorecard or left in `results/`, are dropped and counted on stdout.
184
+ A root with no skills tree (`skills/` or `cli/*/skills/`) holds results only
185
+ and keeps every row.
186
+
182
187
  Files that are not promptfoo results and ungraded transport errors are skipped
183
188
  with a warning rather than failing the reduction. Graded assertion failures
184
189
  remain scored results. If a skipped file matches an existing scorecard row,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uinaf/skillcheck",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "Lint and eval harness for agent skills",
5
5
  "homepage": "https://github.com/uinaf/skillcheck#readme",
6
6
  "bugs": {