@hasna/evals 0.1.6 → 0.1.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,wBAAgB,aAAa,IAAI,OAAO,CAoDvC"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqCpC,wBAAgB,aAAa,IAAI,OAAO,CA4EvC"}
package/dist/cli/index.js CHANGED
@@ -8413,17 +8413,17 @@ __export(exports_store, {
8413
8413
  });
8414
8414
  import { Database } from "bun:sqlite";
8415
8415
  import { mkdirSync } from "fs";
8416
- import { homedir } from "os";
8417
- import { join } from "path";
8416
+ import { homedir as homedir2 } from "os";
8417
+ import { join as join2 } from "path";
8418
8418
  function getDbPath() {
8419
- return process.env["EVALS_DB_PATH"] ?? join(homedir(), ".hasna", "evals", "evals.db");
8419
+ return process.env["EVALS_DB_PATH"] ?? join2(homedir2(), ".hasna", "evals", "evals.db");
8420
8420
  }
8421
8421
  function getDatabase() {
8422
8422
  if (_db)
8423
8423
  return _db;
8424
8424
  const path2 = getDbPath();
8425
8425
  if (path2 !== ":memory:") {
8426
- mkdirSync(join(path2, ".."), { recursive: true });
8426
+ mkdirSync(join2(path2, ".."), { recursive: true });
8427
8427
  }
8428
8428
  _db = new Database(path2);
8429
8429
  _db.exec("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;");
@@ -8571,28 +8571,28 @@ __export(exports_dist, {
8571
8571
  import { createRequire } from "module";
8572
8572
  import { Database as Database2 } from "bun:sqlite";
8573
8573
  import {
8574
- existsSync as existsSync2,
8574
+ existsSync as existsSync4,
8575
8575
  mkdirSync as mkdirSync2,
8576
8576
  readdirSync,
8577
8577
  copyFileSync
8578
8578
  } from "fs";
8579
- import { homedir as homedir3 } from "os";
8580
- import { join as join3, relative } from "path";
8581
- import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
8579
+ import { homedir as homedir5 } from "os";
8580
+ import { join as join5, relative } from "path";
8581
+ import { existsSync as existsSync22, mkdirSync as mkdirSync22, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
8582
8582
  import { homedir as homedir22 } from "os";
8583
8583
  import { join as join22 } from "path";
8584
- import { readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
8584
+ import { readdirSync as readdirSync2, existsSync as existsSync32 } from "fs";
8585
8585
  import { join as join32 } from "path";
8586
8586
  import { homedir as homedir32 } from "os";
8587
8587
  import { hostname } from "os";
8588
- import { existsSync as existsSync4, readFileSync as readFileSync22 } from "fs";
8589
- import { homedir as homedir4 } from "os";
8590
- import { join as join4 } from "path";
8588
+ import { existsSync as existsSync42, readFileSync as readFileSync22 } from "fs";
8589
+ import { homedir as homedir42 } from "os";
8590
+ import { join as join42 } from "path";
8591
8591
  import { existsSync as existsSync5, readdirSync as readdirSync3 } from "fs";
8592
- import { join as join5 } from "path";
8592
+ import { join as join52 } from "path";
8593
8593
  import { join as join6, dirname } from "path";
8594
8594
  import { existsSync as existsSync6, writeFileSync as writeFileSync22, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
8595
- import { homedir as homedir5, platform } from "os";
8595
+ import { homedir as homedir52, platform } from "os";
8596
8596
  function __accessProp2(key) {
8597
8597
  return this[key];
8598
8598
  }
@@ -9474,20 +9474,20 @@ function custom(check, _params = {}, fatal) {
9474
9474
  return ZodAny.create();
9475
9475
  }
9476
9476
  function getDataDir(serviceName) {
9477
- const dir = join3(HASNA_DIR, serviceName);
9477
+ const dir = join5(HASNA_DIR, serviceName);
9478
9478
  mkdirSync2(dir, { recursive: true });
9479
9479
  return dir;
9480
9480
  }
9481
9481
  function getDbPath2(serviceName) {
9482
9482
  const dir = getDataDir(serviceName);
9483
- return join3(dir, `${serviceName}.db`);
9483
+ return join5(dir, `${serviceName}.db`);
9484
9484
  }
9485
9485
  function migrateDotfile(serviceName) {
9486
- const legacyDir = join3(homedir3(), `.${serviceName}`);
9487
- const newDir = join3(HASNA_DIR, serviceName);
9488
- if (!existsSync2(legacyDir))
9486
+ const legacyDir = join5(homedir5(), `.${serviceName}`);
9487
+ const newDir = join5(HASNA_DIR, serviceName);
9488
+ if (!existsSync4(legacyDir))
9489
9489
  return [];
9490
- if (existsSync2(newDir))
9490
+ if (existsSync4(newDir))
9491
9491
  return [];
9492
9492
  mkdirSync2(newDir, { recursive: true });
9493
9493
  const migrated = [];
@@ -9497,8 +9497,8 @@ function migrateDotfile(serviceName) {
9497
9497
  function copyDirRecursive(src, dest, root, migrated) {
9498
9498
  const entries = readdirSync(src, { withFileTypes: true });
9499
9499
  for (const entry of entries) {
9500
- const srcPath = join3(src, entry.name);
9501
- const destPath = join3(dest, entry.name);
9500
+ const srcPath = join5(src, entry.name);
9501
+ const destPath = join5(dest, entry.name);
9502
9502
  if (entry.isDirectory()) {
9503
9503
  mkdirSync2(destPath, { recursive: true });
9504
9504
  copyDirRecursive(srcPath, destPath, root, migrated);
@@ -9509,7 +9509,7 @@ function copyDirRecursive(src, dest, root, migrated) {
9509
9509
  }
9510
9510
  }
9511
9511
  function hasLegacyDotfile(serviceName) {
9512
- return existsSync2(join3(homedir3(), `.${serviceName}`));
9512
+ return existsSync4(join5(homedir5(), `.${serviceName}`));
9513
9513
  }
9514
9514
  function getHasnaDir() {
9515
9515
  mkdirSync2(HASNA_DIR, { recursive: true });
@@ -9526,7 +9526,7 @@ function getCloudConfig() {
9526
9526
  return CloudConfigSchema.parse({});
9527
9527
  }
9528
9528
  try {
9529
- const raw = readFileSync2(CONFIG_PATH, "utf-8");
9529
+ const raw = readFileSync4(CONFIG_PATH, "utf-8");
9530
9530
  return CloudConfigSchema.parse(JSON.parse(raw));
9531
9531
  } catch {
9532
9532
  return CloudConfigSchema.parse({});
@@ -9565,7 +9565,7 @@ function isSyncExcludedTable(table) {
9565
9565
  }
9566
9566
  function discoverServices() {
9567
9567
  const dataDir = join32(homedir32(), ".hasna");
9568
- if (!existsSync3(dataDir))
9568
+ if (!existsSync32(dataDir))
9569
9569
  return [];
9570
9570
  try {
9571
9571
  const entries = readdirSync2(dataDir, { withFileTypes: true });
@@ -9587,7 +9587,7 @@ function discoverSyncableServices() {
9587
9587
  }
9588
9588
  function getServiceDbPath(service) {
9589
9589
  const dataDir = join32(homedir32(), ".hasna", service);
9590
- if (!existsSync3(dataDir))
9590
+ if (!existsSync32(dataDir))
9591
9591
  return null;
9592
9592
  const candidates = [
9593
9593
  join32(dataDir, `${service}.db`),
@@ -9603,7 +9603,7 @@ function getServiceDbPath(service) {
9603
9603
  }
9604
9604
  } catch {}
9605
9605
  for (const p of candidates) {
9606
- if (existsSync3(p))
9606
+ if (existsSync32(p))
9607
9607
  return p;
9608
9608
  }
9609
9609
  return null;
@@ -10524,7 +10524,7 @@ function resetAllSyncMeta(db) {
10524
10524
  }
10525
10525
  function getAutoSyncConfig() {
10526
10526
  try {
10527
- if (!existsSync4(AUTO_SYNC_CONFIG_PATH)) {
10527
+ if (!existsSync42(AUTO_SYNC_CONFIG_PATH)) {
10528
10528
  return { ...DEFAULT_AUTO_SYNC_CONFIG };
10529
10529
  }
10530
10530
  const raw = JSON.parse(readFileSync22(AUTO_SYNC_CONFIG_PATH, "utf-8"));
@@ -10646,7 +10646,7 @@ function discoverSyncableServices2() {
10646
10646
  for (const entry of entries) {
10647
10647
  if (!entry.isDirectory())
10648
10648
  continue;
10649
- const dbPath = join5(hasnaDir, entry.name, `${entry.name}.db`);
10649
+ const dbPath = join52(hasnaDir, entry.name, `${entry.name}.db`);
10650
10650
  if (existsSync5(dbPath)) {
10651
10651
  services.push(entry.name);
10652
10652
  }
@@ -10669,7 +10669,7 @@ async function runScheduledSync() {
10669
10669
  errors: []
10670
10670
  };
10671
10671
  try {
10672
- const dbPath = join5(getDataDir(service), `${service}.db`);
10672
+ const dbPath = join52(getDataDir(service), `${service}.db`);
10673
10673
  if (!existsSync5(dbPath)) {
10674
10674
  continue;
10675
10675
  }
@@ -10761,7 +10761,7 @@ function getWorkerPath() {
10761
10761
  }
10762
10762
  function getBunPath() {
10763
10763
  const candidates = [
10764
- join6(homedir5(), ".bun", "bin", "bun"),
10764
+ join6(homedir52(), ".bun", "bin", "bun"),
10765
10765
  "/usr/local/bin/bun",
10766
10766
  "/usr/bin/bun"
10767
10767
  ];
@@ -10772,7 +10772,7 @@ function getBunPath() {
10772
10772
  return "bun";
10773
10773
  }
10774
10774
  function getLaunchdPlistPath() {
10775
- return join6(homedir5(), "Library", "LaunchAgents", `com.hasna.cloud-sync.plist`);
10775
+ return join6(homedir52(), "Library", "LaunchAgents", `com.hasna.cloud-sync.plist`);
10776
10776
  }
10777
10777
  function createLaunchdPlist(intervalMinutes) {
10778
10778
  const workerPath = getWorkerPath();
@@ -10804,7 +10804,7 @@ function createLaunchdPlist(intervalMinutes) {
10804
10804
  <key>PATH</key>
10805
10805
  <string>${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}</string>
10806
10806
  <key>HOME</key>
10807
- <string>${homedir5()}</string>
10807
+ <string>${homedir52()}</string>
10808
10808
  </dict>
10809
10809
  </dict>
10810
10810
  </plist>`;
@@ -10829,7 +10829,7 @@ async function removeLaunchd() {
10829
10829
  } catch {}
10830
10830
  }
10831
10831
  function getSystemdDir() {
10832
- return join6(homedir5(), ".config", "systemd", "user");
10832
+ return join6(homedir52(), ".config", "systemd", "user");
10833
10833
  }
10834
10834
  function createSystemdService() {
10835
10835
  const workerPath = getWorkerPath();
@@ -10841,7 +10841,7 @@ After=network.target
10841
10841
  [Service]
10842
10842
  Type=oneshot
10843
10843
  ExecStart=${bunPath} run ${workerPath}
10844
- Environment=HOME=${homedir5()}
10844
+ Environment=HOME=${homedir52()}
10845
10845
  Environment=PATH=${process.env.PATH || "/usr/local/bin:/usr/bin:/bin"}
10846
10846
 
10847
10847
  [Install]
@@ -19467,7 +19467,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
19467
19467
  init_external();
19468
19468
  });
19469
19469
  init_dotfile = __esm2(() => {
19470
- HASNA_DIR = join3(homedir3(), ".hasna");
19470
+ HASNA_DIR = join5(homedir5(), ".hasna");
19471
19471
  });
19472
19472
  exports_config = {};
19473
19473
  __export2(exports_config, {
@@ -19563,7 +19563,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
19563
19563
  init_adapter();
19564
19564
  init_config();
19565
19565
  init_discover();
19566
- AUTO_SYNC_CONFIG_PATH = join4(homedir4(), ".hasna", "cloud", "config.json");
19566
+ AUTO_SYNC_CONFIG_PATH = join42(homedir42(), ".hasna", "cloud", "config.json");
19567
19567
  DEFAULT_AUTO_SYNC_CONFIG = {
19568
19568
  auto_sync_on_start: true,
19569
19569
  auto_sync_on_stop: true
@@ -19573,7 +19573,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
19573
19573
  init_adapter();
19574
19574
  init_dotfile();
19575
19575
  init_config();
19576
- CONFIG_DIR2 = join6(homedir5(), ".hasna", "cloud");
19576
+ CONFIG_DIR2 = join6(homedir52(), ".hasna", "cloud");
19577
19577
  init_adapter();
19578
19578
  init_config();
19579
19579
  init_discover();
@@ -29440,6 +29440,29 @@ var _deployments_endpoints = new Set([
29440
29440
  var openai_default = OpenAI;
29441
29441
 
29442
29442
  // src/core/judge.ts
29443
+ import { existsSync, readFileSync } from "fs";
29444
+ import { homedir } from "os";
29445
+ import { join } from "path";
29446
+ function resolveKey(envVar, secretsRelPath, secretsKey) {
29447
+ if (process.env[envVar])
29448
+ return process.env[envVar];
29449
+ const p = join(homedir(), ".secrets", secretsRelPath);
29450
+ if (existsSync(p)) {
29451
+ for (const line of readFileSync(p, "utf8").split(`
29452
+ `)) {
29453
+ if (line.trim().startsWith(secretsKey + "=")) {
29454
+ const v = line.trim().slice(secretsKey.length + 1).replace(/^["']|["']$/g, "");
29455
+ if (v) {
29456
+ process.env[envVar] = v;
29457
+ return v;
29458
+ }
29459
+ }
29460
+ }
29461
+ }
29462
+ return;
29463
+ }
29464
+ resolveKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
29465
+ resolveKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
29443
29466
  var DEFAULT_MODEL = "claude-sonnet-4-6";
29444
29467
  var DEFAULT_PROVIDER = "anthropic";
29445
29468
  var JUDGE_SYSTEM_PROMPT = `You are a precise AI output evaluator. Your job is to judge whether an AI response meets a given rubric.
@@ -30455,17 +30478,44 @@ function kappaLabel(k) {
30455
30478
  }
30456
30479
 
30457
30480
  // src/cli/commands/doctor.ts
30481
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
30482
+ import { homedir as homedir3 } from "os";
30483
+ import { join as join3 } from "path";
30484
+ function resolveApiKey(envVar, secretsPath, secretsKey) {
30485
+ if (process.env[envVar])
30486
+ return process.env[envVar];
30487
+ const fullPath = join3(homedir3(), ".secrets", secretsPath);
30488
+ if (existsSync2(fullPath)) {
30489
+ try {
30490
+ const content = readFileSync2(fullPath, "utf8");
30491
+ for (const line of content.split(`
30492
+ `)) {
30493
+ const trimmed = line.trim();
30494
+ if (trimmed.startsWith(secretsKey + "=")) {
30495
+ const value = trimmed.slice(secretsKey.length + 1).replace(/^["']|["']$/g, "");
30496
+ if (value) {
30497
+ process.env[envVar] = value;
30498
+ return value;
30499
+ }
30500
+ }
30501
+ }
30502
+ } catch {}
30503
+ }
30504
+ return;
30505
+ }
30458
30506
  function doctorCommand() {
30459
30507
  return new Command("doctor").description("Health check \u2014 verify API keys, DB, and config").action(async () => {
30460
30508
  const checks = [];
30509
+ const anthropicKey = resolveApiKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
30461
30510
  checks.push({
30462
30511
  name: "ANTHROPIC_API_KEY",
30463
- ok: !!process.env["ANTHROPIC_API_KEY"],
30464
- hint: "export ANTHROPIC_API_KEY=<your-key>"
30512
+ ok: !!anthropicKey,
30513
+ hint: "export ANTHROPIC_API_KEY=<your-key> (or add to ~/.secrets/hasnaxyz/anthropic/live.env)"
30465
30514
  });
30515
+ const openaiKey = resolveApiKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
30466
30516
  checks.push({
30467
30517
  name: "OPENAI_API_KEY (optional)",
30468
- ok: !!process.env["OPENAI_API_KEY"],
30518
+ ok: !!openaiKey,
30469
30519
  hint: "export OPENAI_API_KEY=<your-key> (only needed for OpenAI adapter/judge)"
30470
30520
  });
30471
30521
  try {
@@ -30480,11 +30530,23 @@ function doctorCommand() {
30480
30530
  }
30481
30531
  try {
30482
30532
  const { loadDataset: loadDataset2 } = await Promise.resolve().then(() => (init_loader(), exports_loader));
30483
- const examplesPath = new URL("../../../datasets/examples/smoke.jsonl", import.meta.url).pathname;
30484
- const { cases } = await loadDataset2(examplesPath);
30485
- checks.push({ name: `Example dataset (${cases.length} cases)`, ok: cases.length > 0, hint: "datasets/examples/smoke.jsonl missing" });
30533
+ const { existsSync: existsSync3 } = await import("fs");
30534
+ const { join: join4 } = await import("path");
30535
+ const { homedir: homedir4 } = await import("os");
30536
+ const candidates = [
30537
+ new URL("../../../datasets/examples/smoke.jsonl", import.meta.url).pathname,
30538
+ join4(import.meta.dir, "../../../datasets/examples/smoke.jsonl"),
30539
+ join4(import.meta.dir, "../../datasets/examples/smoke.jsonl"),
30540
+ join4(import.meta.dir, "../datasets/examples/smoke.jsonl"),
30541
+ join4(homedir4(), ".hasna", "evals", "examples", "smoke.jsonl")
30542
+ ];
30543
+ const found = candidates.find((p) => existsSync3(p));
30544
+ if (!found)
30545
+ throw new Error("not found");
30546
+ const { cases } = await loadDataset2(found);
30547
+ checks.push({ name: `Example dataset (${cases.length} cases)`, ok: cases.length > 0 });
30486
30548
  } catch {
30487
- checks.push({ name: "Example dataset", ok: false, hint: "Run from the open-evals project directory" });
30549
+ checks.push({ name: "Example dataset (optional)", ok: false, hint: "datasets/examples/smoke.jsonl not found \u2014 install @hasna/evals globally to include examples" });
30488
30550
  }
30489
30551
  console.log(`
30490
30552
  \x1B[1mevals doctor\x1B[0m
@@ -30494,7 +30556,7 @@ function doctorCommand() {
30494
30556
  console.log(` ${icon} ${c.name}${!c.ok && c.hint ? `
30495
30557
  hint: ${c.hint}` : ""}`);
30496
30558
  }
30497
- const allOk = checks.every((c) => c.ok || c.name.includes("optional"));
30559
+ const allOk = checks.every((c) => c.ok || c.name.toLowerCase().includes("optional"));
30498
30560
  console.log(allOk ? `
30499
30561
  \x1B[32m All checks passed.\x1B[0m
30500
30562
  ` : `
@@ -30505,9 +30567,9 @@ function doctorCommand() {
30505
30567
  }
30506
30568
 
30507
30569
  // src/cli/commands/mcp.ts
30508
- import { readFileSync, writeFileSync as writeFileSync2, existsSync } from "fs";
30509
- import { homedir as homedir2 } from "os";
30510
- import { join as join2 } from "path";
30570
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
30571
+ import { homedir as homedir4 } from "os";
30572
+ import { join as join4 } from "path";
30511
30573
  function mcpCommand() {
30512
30574
  const cmd = new Command("mcp").description("MCP server management");
30513
30575
  cmd.addCommand(new Command("register").description("Register evals-mcp with an agent (Claude Code, Codex, Gemini)").option("--claude", "Register with Claude Code (~/.claude/mcp.json)").option("--codex", "Register with Codex (~/.codex/config.json)").option("--gemini", "Register with Gemini (~/.gemini/settings.json)").option("--all", "Register with all agents").action((opts) => {
@@ -30523,16 +30585,16 @@ function mcpCommand() {
30523
30585
  }));
30524
30586
  cmd.addCommand(new Command("start").description("Start MCP server (stdio)").action(() => {
30525
30587
  const { spawnSync } = __require("child_process");
30526
- spawnSync(process.execPath, [join2(import.meta.dir, "../../mcp/index.js")], { stdio: "inherit" });
30588
+ spawnSync(process.execPath, [join4(import.meta.dir, "../../mcp/index.js")], { stdio: "inherit" });
30527
30589
  }));
30528
30590
  return cmd;
30529
30591
  }
30530
30592
  var ENTRY = { command: "/home/hasna/.bun/bin/evals-mcp", args: [] };
30531
30593
  function registerClaude() {
30532
- const mcpPath = join2(homedir2(), ".claude", "mcp.json");
30594
+ const mcpPath = join4(homedir4(), ".claude", "mcp.json");
30533
30595
  let config = {};
30534
- if (existsSync(mcpPath)) {
30535
- config = JSON.parse(readFileSync(mcpPath, "utf8"));
30596
+ if (existsSync3(mcpPath)) {
30597
+ config = JSON.parse(readFileSync3(mcpPath, "utf8"));
30536
30598
  }
30537
30599
  config.mcpServers = { ...config.mcpServers ?? {}, evals: ENTRY };
30538
30600
  writeFileSync2(mcpPath, JSON.stringify(config, null, 2) + `
@@ -30541,10 +30603,10 @@ function registerClaude() {
30541
30603
  console.log(" Restart Claude Code to load the new MCP server.");
30542
30604
  }
30543
30605
  function registerCodex() {
30544
- const cfgPath = join2(homedir2(), ".codex", "config.json");
30606
+ const cfgPath = join4(homedir4(), ".codex", "config.json");
30545
30607
  let config = {};
30546
- if (existsSync(cfgPath)) {
30547
- config = JSON.parse(readFileSync(cfgPath, "utf8"));
30608
+ if (existsSync3(cfgPath)) {
30609
+ config = JSON.parse(readFileSync3(cfgPath, "utf8"));
30548
30610
  }
30549
30611
  config.mcpServers = { ...config.mcpServers ?? {}, evals: { type: "stdio", ...ENTRY, env: {} } };
30550
30612
  writeFileSync2(cfgPath, JSON.stringify(config, null, 2) + `
@@ -30552,10 +30614,10 @@ function registerCodex() {
30552
30614
  console.log("\x1B[32m\u2713 Registered evals-mcp in ~/.codex/config.json\x1B[0m");
30553
30615
  }
30554
30616
  function registerGemini() {
30555
- const cfgPath = join2(homedir2(), ".gemini", "settings.json");
30617
+ const cfgPath = join4(homedir4(), ".gemini", "settings.json");
30556
30618
  let config = {};
30557
- if (existsSync(cfgPath)) {
30558
- config = JSON.parse(readFileSync(cfgPath, "utf8"));
30619
+ if (existsSync3(cfgPath)) {
30620
+ config = JSON.parse(readFileSync3(cfgPath, "utf8"));
30559
30621
  }
30560
30622
  config.mcpServers = { ...config.mcpServers ?? {}, evals: ENTRY };
30561
30623
  writeFileSync2(cfgPath, JSON.stringify(config, null, 2) + `
@@ -1 +1 @@
1
- {"version":3,"file":"judge.d.ts","sourceRoot":"","sources":["../../src/core/judge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAW,MAAM,mBAAmB,CAAC;AAsD3E,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAmBtB;AA4ED,kEAAkE;AAClE,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,WAAW,CAAC,CAOvB"}
1
+ {"version":3,"file":"judge.d.ts","sourceRoot":"","sources":["../../src/core/judge.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAW,MAAM,mBAAmB,CAAC;AA4E3E,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAmBtB;AA4ED,kEAAkE;AAClE,wBAAsB,SAAS,CAAC,MAAM,EAAE;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,WAAW,CAAC,CAOvB"}
package/dist/index.js CHANGED
@@ -16810,6 +16810,29 @@ var _deployments_endpoints = new Set([
16810
16810
  var openai_default = OpenAI;
16811
16811
 
16812
16812
  // src/core/judge.ts
16813
+ import { existsSync, readFileSync } from "fs";
16814
+ import { homedir } from "os";
16815
+ import { join } from "path";
16816
+ function resolveKey(envVar, secretsRelPath, secretsKey) {
16817
+ if (process.env[envVar])
16818
+ return process.env[envVar];
16819
+ const p = join(homedir(), ".secrets", secretsRelPath);
16820
+ if (existsSync(p)) {
16821
+ for (const line of readFileSync(p, "utf8").split(`
16822
+ `)) {
16823
+ if (line.trim().startsWith(secretsKey + "=")) {
16824
+ const v = line.trim().slice(secretsKey.length + 1).replace(/^["']|["']$/g, "");
16825
+ if (v) {
16826
+ process.env[envVar] = v;
16827
+ return v;
16828
+ }
16829
+ }
16830
+ }
16831
+ }
16832
+ return;
16833
+ }
16834
+ resolveKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
16835
+ resolveKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
16813
16836
  var DEFAULT_MODEL = "claude-sonnet-4-6";
16814
16837
  var DEFAULT_PROVIDER = "anthropic";
16815
16838
  var JUDGE_SYSTEM_PROMPT = `You are a precise AI output evaluator. Your job is to judge whether an AI response meets a given rubric.
@@ -23852,18 +23875,18 @@ async function* streamDataset(path2, opts = {}) {
23852
23875
  // src/db/store.ts
23853
23876
  import { Database } from "bun:sqlite";
23854
23877
  import { mkdirSync } from "fs";
23855
- import { homedir } from "os";
23856
- import { join } from "path";
23878
+ import { homedir as homedir2 } from "os";
23879
+ import { join as join2 } from "path";
23857
23880
  var _db = null;
23858
23881
  function getDbPath() {
23859
- return process.env["EVALS_DB_PATH"] ?? join(homedir(), ".hasna", "evals", "evals.db");
23882
+ return process.env["EVALS_DB_PATH"] ?? join2(homedir2(), ".hasna", "evals", "evals.db");
23860
23883
  }
23861
23884
  function getDatabase() {
23862
23885
  if (_db)
23863
23886
  return _db;
23864
23887
  const path2 = getDbPath();
23865
23888
  if (path2 !== ":memory:") {
23866
- mkdirSync(join(path2, ".."), { recursive: true });
23889
+ mkdirSync(join2(path2, ".."), { recursive: true });
23867
23890
  }
23868
23891
  _db = new Database(path2);
23869
23892
  _db.exec("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;");
package/dist/mcp/index.js CHANGED
@@ -10501,17 +10501,17 @@ __export(exports_store, {
10501
10501
  });
10502
10502
  import { Database } from "bun:sqlite";
10503
10503
  import { mkdirSync } from "fs";
10504
- import { homedir } from "os";
10505
- import { join } from "path";
10504
+ import { homedir as homedir2 } from "os";
10505
+ import { join as join2 } from "path";
10506
10506
  function getDbPath() {
10507
- return process.env["EVALS_DB_PATH"] ?? join(homedir(), ".hasna", "evals", "evals.db");
10507
+ return process.env["EVALS_DB_PATH"] ?? join2(homedir2(), ".hasna", "evals", "evals.db");
10508
10508
  }
10509
10509
  function getDatabase() {
10510
10510
  if (_db)
10511
10511
  return _db;
10512
10512
  const path2 = getDbPath();
10513
10513
  if (path2 !== ":memory:") {
10514
- mkdirSync(join(path2, ".."), { recursive: true });
10514
+ mkdirSync(join2(path2, ".."), { recursive: true });
10515
10515
  }
10516
10516
  _db = new Database(path2);
10517
10517
  _db.exec("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;");
@@ -20314,6 +20314,29 @@ var _deployments_endpoints = new Set([
20314
20314
  var openai_default = OpenAI;
20315
20315
 
20316
20316
  // src/core/judge.ts
20317
+ import { existsSync, readFileSync } from "fs";
20318
+ import { homedir } from "os";
20319
+ import { join } from "path";
20320
+ function resolveKey(envVar, secretsRelPath, secretsKey) {
20321
+ if (process.env[envVar])
20322
+ return process.env[envVar];
20323
+ const p = join(homedir(), ".secrets", secretsRelPath);
20324
+ if (existsSync(p)) {
20325
+ for (const line of readFileSync(p, "utf8").split(`
20326
+ `)) {
20327
+ if (line.trim().startsWith(secretsKey + "=")) {
20328
+ const v = line.trim().slice(secretsKey.length + 1).replace(/^["']|["']$/g, "");
20329
+ if (v) {
20330
+ process.env[envVar] = v;
20331
+ return v;
20332
+ }
20333
+ }
20334
+ }
20335
+ }
20336
+ return;
20337
+ }
20338
+ resolveKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
20339
+ resolveKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
20317
20340
  var DEFAULT_MODEL = "claude-sonnet-4-6";
20318
20341
  var DEFAULT_PROVIDER = "anthropic";
20319
20342
  var JUDGE_SYSTEM_PROMPT = `You are a precise AI output evaluator. Your job is to judge whether an AI response meets a given rubric.
@@ -16809,6 +16809,29 @@ var _deployments_endpoints = new Set([
16809
16809
  var openai_default = OpenAI;
16810
16810
 
16811
16811
  // src/core/judge.ts
16812
+ import { existsSync, readFileSync } from "fs";
16813
+ import { homedir } from "os";
16814
+ import { join } from "path";
16815
+ function resolveKey(envVar, secretsRelPath, secretsKey) {
16816
+ if (process.env[envVar])
16817
+ return process.env[envVar];
16818
+ const p = join(homedir(), ".secrets", secretsRelPath);
16819
+ if (existsSync(p)) {
16820
+ for (const line of readFileSync(p, "utf8").split(`
16821
+ `)) {
16822
+ if (line.trim().startsWith(secretsKey + "=")) {
16823
+ const v = line.trim().slice(secretsKey.length + 1).replace(/^["']|["']$/g, "");
16824
+ if (v) {
16825
+ process.env[envVar] = v;
16826
+ return v;
16827
+ }
16828
+ }
16829
+ }
16830
+ }
16831
+ return;
16832
+ }
16833
+ resolveKey("ANTHROPIC_API_KEY", "hasnaxyz/anthropic/live.env", "HASNAXYZ_ANTHROPIC_LIVE_API_KEY");
16834
+ resolveKey("OPENAI_API_KEY", "hasnaxyz/openai/live.env", "HASNAXYZ_OPENAI_LIVE_API_KEY");
16812
16835
  var DEFAULT_MODEL = "claude-sonnet-4-6";
16813
16836
  var DEFAULT_PROVIDER = "anthropic";
16814
16837
  var JUDGE_SYSTEM_PROMPT = `You are a precise AI output evaluator. Your job is to judge whether an AI response meets a given rubric.
@@ -23744,18 +23767,18 @@ function toMarkdown(run) {
23744
23767
  // src/db/store.ts
23745
23768
  import { Database } from "bun:sqlite";
23746
23769
  import { mkdirSync } from "fs";
23747
- import { homedir } from "os";
23748
- import { join } from "path";
23770
+ import { homedir as homedir2 } from "os";
23771
+ import { join as join2 } from "path";
23749
23772
  var _db = null;
23750
23773
  function getDbPath() {
23751
- return process.env["EVALS_DB_PATH"] ?? join(homedir(), ".hasna", "evals", "evals.db");
23774
+ return process.env["EVALS_DB_PATH"] ?? join2(homedir2(), ".hasna", "evals", "evals.db");
23752
23775
  }
23753
23776
  function getDatabase() {
23754
23777
  if (_db)
23755
23778
  return _db;
23756
23779
  const path2 = getDbPath();
23757
23780
  if (path2 !== ":memory:") {
23758
- mkdirSync(join(path2, ".."), { recursive: true });
23781
+ mkdirSync(join2(path2, ".."), { recursive: true });
23759
23782
  }
23760
23783
  _db = new Database(path2);
23761
23784
  _db.exec("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/evals",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Open source AI evaluation framework — LLM-as-judge + assertion-based evals for any AI app. CLI + MCP server.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",