@wix/evalforge-evaluator 0.68.0 → 0.69.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/build/index.mjs CHANGED
@@ -6437,8 +6437,7 @@ async function writeSkillFiles(skillDir, files) {
6437
6437
  import { randomUUID } from "crypto";
6438
6438
 
6439
6439
  // src/run-scenario/agents/claude-code/write-mcp.ts
6440
- import { writeFile as writeFile2, readFile } from "fs/promises";
6441
- import { spawn } from "child_process";
6440
+ import { writeFile as writeFile2 } from "fs/promises";
6442
6441
  import { join as join3 } from "path";
6443
6442
  import { MCP_SERVERS_JSON_KEY } from "@wix/evalforge-types";
6444
6443
  async function writeMcpToFilesystem(cwd, mcps) {
@@ -6464,6 +6463,11 @@ async function writeMcpToFilesystem(cwd, mcps) {
6464
6463
  await writeFile2(filePath, content, "utf8");
6465
6464
  console.log(`[MCP] Written to ${filePath}`);
6466
6465
  }
6466
+
6467
+ // src/run-scenario/agents/claude-code/mcp-setup.ts
6468
+ import { readFile } from "fs/promises";
6469
+ import { spawn } from "child_process";
6470
+ import { join as join4 } from "path";
6467
6471
  async function probeMcpServers(mcps, probeMs = 5e3) {
6468
6472
  const results = [];
6469
6473
  for (const mcp of mcps) {
@@ -6531,10 +6535,125 @@ spawn error: ${err.message}`;
6531
6535
  }, probeMs);
6532
6536
  });
6533
6537
  }
6538
+ async function preInstallMcpPackages(mcps, timeoutMs = 12e4) {
6539
+ const packages = extractNpxPackages(mcps);
6540
+ if (packages.length === 0) return [];
6541
+ const results = [];
6542
+ for (const pkg of packages) {
6543
+ const startMs = Date.now();
6544
+ const alreadyInstalled = await isPackageGloballyInstalled(pkg);
6545
+ if (alreadyInstalled) {
6546
+ const durationMs2 = Date.now() - startMs;
6547
+ console.log(
6548
+ `[MCP] Package already installed globally, skipping: ${pkg} (${durationMs2}ms)`
6549
+ );
6550
+ results.push({
6551
+ package: pkg,
6552
+ success: true,
6553
+ skipped: true,
6554
+ output: "already installed",
6555
+ durationMs: durationMs2
6556
+ });
6557
+ continue;
6558
+ }
6559
+ console.log(`[MCP] Pre-installing npx package globally: ${pkg}`);
6560
+ const result = await installPackageGlobally(pkg, timeoutMs);
6561
+ const durationMs = Date.now() - startMs;
6562
+ results.push({ package: pkg, skipped: false, durationMs, ...result });
6563
+ console.log(
6564
+ `[MCP] Install ${pkg}: ${result.success ? "SUCCESS" : "FAILED"} (${durationMs}ms)`
6565
+ );
6566
+ }
6567
+ return results;
6568
+ }
6569
+ function isPackageGloballyInstalled(pkg) {
6570
+ return new Promise((resolve2) => {
6571
+ let settled = false;
6572
+ const child = spawn("npm", ["ls", "-g", "--depth=0", pkg], {
6573
+ stdio: ["pipe", "pipe", "pipe"],
6574
+ env: process.env
6575
+ });
6576
+ child.on("close", (code2) => {
6577
+ if (!settled) {
6578
+ settled = true;
6579
+ resolve2(code2 === 0);
6580
+ }
6581
+ });
6582
+ child.on("error", () => {
6583
+ if (!settled) {
6584
+ settled = true;
6585
+ resolve2(false);
6586
+ }
6587
+ });
6588
+ setTimeout(() => {
6589
+ if (!settled) {
6590
+ settled = true;
6591
+ child.kill("SIGTERM");
6592
+ resolve2(false);
6593
+ }
6594
+ }, 5e3);
6595
+ });
6596
+ }
6597
+ function extractNpxPackages(mcps) {
6598
+ const packages = [];
6599
+ for (const mcp of mcps) {
6600
+ const config = mcp.config;
6601
+ for (const [, value] of Object.entries(config)) {
6602
+ if (typeof value !== "object" || value === null) continue;
6603
+ const cfg = value;
6604
+ if (cfg.command !== "npx" || !Array.isArray(cfg.args)) continue;
6605
+ for (const arg of cfg.args) {
6606
+ if (!arg.startsWith("-")) {
6607
+ packages.push(arg);
6608
+ break;
6609
+ }
6610
+ }
6611
+ }
6612
+ }
6613
+ return [...new Set(packages)];
6614
+ }
6615
+ function installPackageGlobally(pkg, timeoutMs) {
6616
+ return new Promise((resolve2) => {
6617
+ let output = "";
6618
+ let settled = false;
6619
+ const child = spawn("sh", ["-c", `npm install -g ${pkg} 2>&1`], {
6620
+ stdio: ["pipe", "pipe", "pipe"],
6621
+ env: process.env
6622
+ });
6623
+ child.stdout.on("data", (chunk) => {
6624
+ output += chunk.toString();
6625
+ });
6626
+ child.stderr.on("data", (chunk) => {
6627
+ output += chunk.toString();
6628
+ });
6629
+ child.on("close", (code2) => {
6630
+ if (!settled) {
6631
+ settled = true;
6632
+ resolve2({ success: code2 === 0, output: output.slice(-1e3) });
6633
+ }
6634
+ });
6635
+ child.on("error", (err) => {
6636
+ if (!settled) {
6637
+ settled = true;
6638
+ resolve2({ success: false, output: `spawn error: ${err.message}` });
6639
+ }
6640
+ });
6641
+ setTimeout(() => {
6642
+ if (!settled) {
6643
+ settled = true;
6644
+ child.kill("SIGTERM");
6645
+ resolve2({
6646
+ success: false,
6647
+ output: output.slice(-1e3) + "\n[install timed out]"
6648
+ });
6649
+ }
6650
+ }, timeoutMs);
6651
+ });
6652
+ }
6534
6653
  async function probeNpmConfig(cwd) {
6535
6654
  const homedir = process.env.HOME ?? "~";
6536
6655
  const [wixAuthFile, npmInstallDryRun, mcpPackageInstalled] = await Promise.all([
6537
- readFile(join3(homedir, ".wix", "auth", "api-key.json"), "utf8").catch(
6656
+ readFile(join4(homedir, ".wix", "auth", "api-key.json"), "utf8").catch(
6538
6657
  (e) => `[not found: ${e.message}]`
6539
6658
  ),
6540
6659
  runShellCapture(
@@ -6618,7 +6737,7 @@ function runShellCapture(cmd, cwd, timeoutMs) {
6618
6737
 
6619
6738
  // src/run-scenario/agents/claude-code/write-sub-agents.ts
6620
6739
  import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
6621
- import { join as join4 } from "path";
6740
+ import { join as join5 } from "path";
6622
6741
  var AGENTS_DIR = ".claude/agents";
6623
6742
  function toAgentFilename(name2, index, nameCount) {
6624
6743
  const base = (name2 || "").toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-+|-+$/g, "") || `sub-agent-${index}`;
@@ -6628,12 +6747,12 @@ function toAgentFilename(name2, index, nameCount) {
6628
6747
  }
6629
6748
  async function writeSubAgentsToFilesystem(cwd, subAgents) {
6630
6749
  if (subAgents.length === 0) return;
6631
- const agentsDir = join4(cwd, AGENTS_DIR);
6750
+ const agentsDir = join5(cwd, AGENTS_DIR);
6632
6751
  await mkdir3(agentsDir, { recursive: true });
6633
6752
  const nameCount = /* @__PURE__ */ new Map();
6634
6753
  for (const [i, agent] of subAgents.entries()) {
6635
6754
  const filename = toAgentFilename(agent.name, i, nameCount);
6636
- const filePath = join4(agentsDir, `${filename}.md`);
6755
+ const filePath = join5(agentsDir, `${filename}.md`);
6637
6756
  await writeFile3(filePath, agent.subAgentMd, "utf8");
6638
6757
  }
6639
6758
  console.log(`[SubAgents] Written to ${agentsDir}`);
@@ -6869,6 +6988,29 @@ async function executeWithClaudeCode(skills, scenario, options) {
6869
6988
  const allMessages = [];
6870
6989
  if (options.mcps && options.mcps.length > 0) {
6871
6990
  await writeMcpToFilesystem(options.cwd, options.mcps);
6991
+ const installResults = await preInstallMcpPackages(options.mcps);
6992
+ if (installResults.length > 0 && options.traceContext) {
6993
+ emitTraceEvent(
6994
+ {
6995
+ evalRunId: options.traceContext.evalRunId,
6996
+ scenarioId: options.traceContext.scenarioId,
6997
+ scenarioName: options.traceContext.scenarioName,
6998
+ targetId: options.traceContext.targetId,
6999
+ targetName: options.traceContext.targetName,
7000
+ stepNumber: 0,
7001
+ type: LiveTraceEventType.DIAGNOSTIC,
7002
+ outputPreview: JSON.stringify({
7003
+ event: "mcp-pre-install",
7004
+ results: installResults
7005
+ }).slice(0, 2e3),
7006
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7007
+ isComplete: false
7008
+ },
7009
+ options.traceContext.tracePushUrl,
7010
+ options.traceContext.routeHeader,
7011
+ options.traceContext.authToken
7012
+ );
7013
+ }
6872
7014
  const probeResults = await probeMcpServers(options.mcps);
6873
7015
  if (options.traceContext) {
6874
7016
  emitTraceEvent(
@@ -7739,7 +7881,7 @@ defaultRegistry.register(claudeCodeAdapter);
7739
7881
 
7740
7882
  // src/run-scenario/file-diff.ts
7741
7883
  import { readdirSync as readdirSync2, readFileSync, statSync, existsSync as existsSync2 } from "fs";
7742
- import { join as join6, relative } from "path";
7884
+ import { join as join7, relative } from "path";
7743
7885
 
7744
7886
  // ../../node_modules/diff/lib/index.mjs
7745
7887
  function Diff() {
@@ -7915,7 +8057,7 @@ Diff.prototype = {
7915
8057
  tokenize: function tokenize(value) {
7916
8058
  return Array.from(value);
7917
8059
  },
7918
- join: function join5(chars) {
8060
+ join: function join6(chars) {
7919
8061
  return chars.join("");
7920
8062
  },
7921
8063
  postProcess: function postProcess(changeObjects) {
@@ -8355,7 +8497,7 @@ function snapshotDirectory(dir, baseDir) {
8355
8497
  }
8356
8498
  const entries = readdirSync2(dir, { withFileTypes: true });
8357
8499
  for (const entry of entries) {
8358
- const fullPath = join6(dir, entry.name);
8500
+ const fullPath = join7(dir, entry.name);
8359
8501
  const relativePath = relative(base, fullPath);
8360
8502
  if (shouldIgnore(entry.name)) {
8361
8503
  continue;