@wix/evalforge-evaluator 0.98.0 → 0.99.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
@@ -187,6 +187,53 @@ import {
187
187
  isSystemAssertionId,
188
188
  SYSTEM_ASSERTIONS
189
189
  } from "@wix/evalforge-types";
190
+
191
+ // src/resolve-placeholders.ts
192
+ var PLACEHOLDER_PATTERN = /\{\{([^}]+)\}\}/g;
193
+ function findPlaceholders(value) {
194
+ const keys = /* @__PURE__ */ new Set();
195
+ collectPlaceholders(value, keys);
196
+ return [...keys];
197
+ }
198
+ function collectPlaceholders(value, keys) {
199
+ if (typeof value === "string") {
200
+ for (const match of value.matchAll(PLACEHOLDER_PATTERN)) {
201
+ keys.add(match[1].trim());
202
+ }
203
+ } else if (Array.isArray(value)) {
204
+ for (const item of value) {
205
+ collectPlaceholders(item, keys);
206
+ }
207
+ } else if (typeof value === "object" && value !== null) {
208
+ for (const val of Object.values(value)) {
209
+ collectPlaceholders(val, keys);
210
+ }
211
+ }
212
+ }
213
+ function resolveValue(value, placeholders) {
214
+ if (typeof value === "string") {
215
+ return value.replace(PLACEHOLDER_PATTERN, (match, key) => {
216
+ const trimmed = key.trim();
217
+ return trimmed in placeholders ? placeholders[trimmed] : match;
218
+ });
219
+ }
220
+ if (Array.isArray(value)) {
221
+ return value.map((item) => resolveValue(item, placeholders));
222
+ }
223
+ if (typeof value === "object" && value !== null) {
224
+ const result = {};
225
+ for (const [k, v] of Object.entries(value)) {
226
+ result[k] = resolveValue(v, placeholders);
227
+ }
228
+ return result;
229
+ }
230
+ return value;
231
+ }
232
+ function resolvePlaceholdersInString(text, placeholders) {
233
+ return resolveValue(text, placeholders);
234
+ }
235
+
236
+ // src/fetch-evaluation-data.ts
190
237
  function parseSkillNamesFromParams(value) {
191
238
  if (typeof value !== "string") {
192
239
  return [];
@@ -202,13 +249,11 @@ function applyParamsToAssertion(assertion, params) {
202
249
  return assertion;
203
250
  }
204
251
  if (assertion.type === "llm_judge") {
205
- let prompt = assertion.prompt;
252
+ const stringParams = {};
206
253
  for (const [key, value] of Object.entries(params)) {
207
- const placeholder = `{{${key}}}`;
208
- const escapedPlaceholder = placeholder.replace(/[{}]/g, "\\$&");
209
- const replacement = String(value ?? "");
210
- prompt = prompt.replace(new RegExp(escapedPlaceholder, "g"), replacement);
254
+ stringParams[key] = String(value ?? "");
211
255
  }
256
+ const prompt = resolvePlaceholdersInString(assertion.prompt, stringParams);
212
257
  return {
213
258
  ...assertion,
214
259
  prompt,
@@ -689,8 +734,49 @@ import { randomUUID } from "crypto";
689
734
 
690
735
  // src/run-scenario/agents/claude-code/write-mcp.ts
691
736
  import { writeFile as writeFile2 } from "fs/promises";
692
- import { join as join2 } from "path";
737
+ import { join as join3 } from "path";
693
738
  import { MCP_SERVERS_JSON_KEY } from "@wix/evalforge-types";
739
+
740
+ // src/run-scenario/agents/claude-code/resolve-mcp-placeholders.ts
741
+ import { readFile } from "fs/promises";
742
+ import { join as join2 } from "path";
743
+ import { homedir } from "os";
744
+ var WIX_AUTH_FILE = join2(homedir(), ".wix", "auth", "api-key.json");
745
+ async function loadWixAuthPlaceholders(authFilePath = WIX_AUTH_FILE) {
746
+ try {
747
+ const content = await readFile(authFilePath, "utf-8");
748
+ const auth = JSON.parse(content);
749
+ if (!auth.token || !auth.userInfo?.userId) {
750
+ return {};
751
+ }
752
+ return {
753
+ "wix-auth-token": auth.token,
754
+ "wix-auth-user-id": auth.userInfo.userId
755
+ };
756
+ } catch (err) {
757
+ console.warn(
758
+ `[MCP] Could not load Wix auth file: ${err.message}`
759
+ );
760
+ return {};
761
+ }
762
+ }
763
+ async function resolveMcpPlaceholders(mcpServers, authFilePath) {
764
+ const needed = findPlaceholders(mcpServers);
765
+ if (needed.length === 0) {
766
+ return mcpServers;
767
+ }
768
+ const placeholders = await loadWixAuthPlaceholders(authFilePath);
769
+ const unresolved = needed.filter((key) => !(key in placeholders));
770
+ if (unresolved.length > 0) {
771
+ throw new Error(
772
+ `MCP config contains unresolvable placeholders: ${unresolved.map((k) => `{{${k}}}`).join(", ")}. Ensure ~/.wix/auth/api-key.json exists (run \`npx @wix/cli login\`).`
773
+ );
774
+ }
775
+ console.log(`[MCP] Resolved ${needed.length} placeholder(s)`);
776
+ return resolveValue(mcpServers, placeholders);
777
+ }
778
+
779
+ // src/run-scenario/agents/claude-code/write-mcp.ts
694
780
  async function writeMcpToFilesystem(cwd, mcps) {
695
781
  if (mcps.length === 0) return;
696
782
  const mcpServers = {};
@@ -705,19 +791,20 @@ async function writeMcpToFilesystem(cwd, mcps) {
705
791
  mcpServers[key] = value;
706
792
  }
707
793
  }
794
+ const resolvedServers = await resolveMcpPlaceholders(mcpServers);
708
795
  const content = JSON.stringify(
709
- { [MCP_SERVERS_JSON_KEY]: mcpServers },
796
+ { [MCP_SERVERS_JSON_KEY]: resolvedServers },
710
797
  null,
711
798
  2
712
799
  );
713
- const filePath = join2(cwd, ".mcp.json");
800
+ const filePath = join3(cwd, ".mcp.json");
714
801
  await writeFile2(filePath, content, "utf8");
715
802
  console.log(`[MCP] Written to ${filePath}`);
716
803
  }
717
804
 
718
805
  // src/run-scenario/agents/claude-code/write-sub-agents.ts
719
806
  import { mkdir as mkdir2, writeFile as writeFile3 } from "fs/promises";
720
- import { join as join3 } from "path";
807
+ import { join as join4 } from "path";
721
808
  var AGENTS_DIR = ".claude/agents";
722
809
  function toAgentFilename(name, index, nameCount) {
723
810
  const base = (name || "").toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-+|-+$/g, "") || `sub-agent-${index}`;
@@ -727,20 +814,20 @@ function toAgentFilename(name, index, nameCount) {
727
814
  }
728
815
  async function writeSubAgentsToFilesystem(cwd, subAgents) {
729
816
  if (subAgents.length === 0) return;
730
- const agentsDir = join3(cwd, AGENTS_DIR);
817
+ const agentsDir = join4(cwd, AGENTS_DIR);
731
818
  await mkdir2(agentsDir, { recursive: true });
732
819
  const nameCount = /* @__PURE__ */ new Map();
733
820
  for (const [i, agent] of subAgents.entries()) {
734
821
  const filename = toAgentFilename(agent.name, i, nameCount);
735
- const filePath = join3(agentsDir, `${filename}.md`);
822
+ const filePath = join4(agentsDir, `${filename}.md`);
736
823
  await writeFile3(filePath, agent.subAgentMd, "utf8");
737
824
  }
738
825
  console.log(`[SubAgents] Written to ${agentsDir}`);
739
826
  }
740
827
 
741
828
  // src/run-scenario/agents/claude-code/write-rules.ts
742
- import { mkdir as mkdir3, writeFile as writeFile4, readFile } from "fs/promises";
743
- import { join as join4 } from "path";
829
+ import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2 } from "fs/promises";
830
+ import { join as join5 } from "path";
744
831
  var CURSOR_RULES_DIR = ".cursor/rules";
745
832
  function toRuleFilename(name, index, nameCount) {
746
833
  const base = (name || "").toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-+|-+$/g, "") || `rule-${index}`;
@@ -751,7 +838,7 @@ function toRuleFilename(name, index, nameCount) {
751
838
  async function appendToFile(filePath, content) {
752
839
  let existing = "";
753
840
  try {
754
- existing = await readFile(filePath, "utf8");
841
+ existing = await readFile2(filePath, "utf8");
755
842
  } catch {
756
843
  }
757
844
  const merged = existing ? `${existing.trimEnd()}
@@ -766,20 +853,20 @@ async function writeRulesToFilesystem(cwd, rules) {
766
853
  for (const [i, rule] of rules.entries()) {
767
854
  switch (rule.ruleType) {
768
855
  case "claude-md": {
769
- await appendToFile(join4(cwd, "CLAUDE.md"), rule.content);
856
+ await appendToFile(join5(cwd, "CLAUDE.md"), rule.content);
770
857
  break;
771
858
  }
772
859
  case "agents-md": {
773
- await appendToFile(join4(cwd, "AGENTS.md"), rule.content);
860
+ await appendToFile(join5(cwd, "AGENTS.md"), rule.content);
774
861
  break;
775
862
  }
776
863
  case "cursor-rule": {
777
864
  if (!hasCursorRules) {
778
- await mkdir3(join4(cwd, CURSOR_RULES_DIR), { recursive: true });
865
+ await mkdir3(join5(cwd, CURSOR_RULES_DIR), { recursive: true });
779
866
  hasCursorRules = true;
780
867
  }
781
868
  const filename = toRuleFilename(rule.name, i, nameCount);
782
- const filePath = join4(cwd, CURSOR_RULES_DIR, `${filename}.md`);
869
+ const filePath = join5(cwd, CURSOR_RULES_DIR, `${filename}.md`);
783
870
  await writeFile4(filePath, rule.content, "utf8");
784
871
  break;
785
872
  }
@@ -1815,7 +1902,7 @@ defaultRegistry.register(claudeCodeAdapter);
1815
1902
 
1816
1903
  // src/run-scenario/file-diff.ts
1817
1904
  import { readdirSync, readFileSync as readFileSync2, statSync, existsSync as existsSync2 } from "fs";
1818
- import { join as join6, relative } from "path";
1905
+ import { join as join7, relative } from "path";
1819
1906
 
1820
1907
  // ../../node_modules/diff/lib/index.mjs
1821
1908
  function Diff() {
@@ -1991,7 +2078,7 @@ Diff.prototype = {
1991
2078
  tokenize: function tokenize(value) {
1992
2079
  return Array.from(value);
1993
2080
  },
1994
- join: function join5(chars) {
2081
+ join: function join6(chars) {
1995
2082
  return chars.join("");
1996
2083
  },
1997
2084
  postProcess: function postProcess(changeObjects) {
@@ -2431,7 +2518,7 @@ function snapshotDirectory(dir, baseDir) {
2431
2518
  }
2432
2519
  const entries = readdirSync(dir, { withFileTypes: true });
2433
2520
  for (const entry of entries) {
2434
- const fullPath = join6(dir, entry.name);
2521
+ const fullPath = join7(dir, entry.name);
2435
2522
  const relativePath = relative(base, fullPath);
2436
2523
  if (shouldIgnore(entry.name)) {
2437
2524
  continue;