@wix/evalforge-evaluator 0.159.0 → 0.160.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
@@ -799,7 +799,7 @@ async function writeSubAgentsToFilesystem(cwd, subAgents, fetchFn = fetchGitHubF
799
799
 
800
800
  // src/run-scenario/agents/claude-code/write-rules.ts
801
801
  import { mkdir as mkdir4, writeFile as writeFile4, readFile as readFile2 } from "fs/promises";
802
- import { join as join5 } from "path";
802
+ import { join as join5, resolve as resolve2, sep as sep2 } from "path";
803
803
  var CURSOR_RULES_DIR = ".cursor/rules";
804
804
  function toRuleFilename(name, index, nameCount) {
805
805
  const base = (name || "").toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/^-+|-+$/g, "") || `rule-${index}`;
@@ -818,6 +818,29 @@ async function appendToFile(filePath, content) {
818
818
  ${content}` : content;
819
819
  await writeFile4(filePath, merged, "utf8");
820
820
  }
821
+ function validateGenericDirectory(dir, cwd) {
822
+ const trimmed = dir.trim();
823
+ if (!trimmed) {
824
+ throw new Error(`Generic rule directory must not be empty`);
825
+ }
826
+ if (trimmed.startsWith("/") || trimmed.startsWith("\\") || trimmed.startsWith("~")) {
827
+ throw new Error(`Generic rule directory must be relative, got: "${dir}"`);
828
+ }
829
+ const segments = trimmed.split(/[\\/]/);
830
+ if (segments.some((s) => s === "..")) {
831
+ throw new Error(
832
+ `Generic rule directory may not contain "..", got: "${dir}"`
833
+ );
834
+ }
835
+ const normalizedCwd = cwd.endsWith(sep2) ? cwd.slice(0, -1) : cwd;
836
+ const resolved = resolve2(normalizedCwd, trimmed);
837
+ if (!resolved.startsWith(normalizedCwd + sep2)) {
838
+ throw new Error(
839
+ `Generic rule directory escapes the working directory: "${dir}"`
840
+ );
841
+ }
842
+ return trimmed;
843
+ }
821
844
  async function writeRulesToFilesystem(cwd, rules) {
822
845
  if (rules.length === 0) return;
823
846
  const nameCount = /* @__PURE__ */ new Map();
@@ -842,6 +865,21 @@ async function writeRulesToFilesystem(cwd, rules) {
842
865
  await writeFile4(filePath, rule.content, "utf8");
843
866
  break;
844
867
  }
868
+ case "generic": {
869
+ const directory = validateGenericDirectory(
870
+ rule.directory ?? ".opencode/rules",
871
+ cwd
872
+ );
873
+ const dirPath = join5(cwd, directory);
874
+ await mkdir4(dirPath, { recursive: true });
875
+ const filename = toRuleFilename(rule.name, i, nameCount);
876
+ await writeFile4(join5(dirPath, `${filename}.md`), rule.content, "utf8");
877
+ break;
878
+ }
879
+ default: {
880
+ const _exhaustive = rule.ruleType;
881
+ throw new Error(`Unhandled ruleType: ${_exhaustive}`);
882
+ }
845
883
  }
846
884
  }
847
885
  console.log(`[Rules] Written ${rules.length} rule(s) to ${cwd}`);
@@ -2373,12 +2411,25 @@ async function buildOpenCodeEnv(options) {
2373
2411
  ...defaultPermission,
2374
2412
  ...configPermission
2375
2413
  };
2414
+ let instructions;
2415
+ if (options.rules && options.rules.length > 0) {
2416
+ const genericDirs = /* @__PURE__ */ new Set();
2417
+ for (const rule of options.rules) {
2418
+ if (rule.ruleType === "generic") {
2419
+ genericDirs.add(rule.directory ?? ".opencode/rules");
2420
+ }
2421
+ }
2422
+ if (genericDirs.size > 0) {
2423
+ instructions = Array.from(genericDirs).sort().map((d) => `${d}/*.md`);
2424
+ }
2425
+ }
2376
2426
  const config = {
2377
2427
  model: `${providerID}/${modelID}`,
2378
2428
  provider,
2379
2429
  ...Object.keys(agentOverrides).length > 0 ? { agent: { build: agentOverrides } } : {},
2380
2430
  permission,
2381
- ...mcp ? { mcp } : {}
2431
+ ...mcp ? { mcp } : {},
2432
+ ...instructions ? { instructions } : {}
2382
2433
  };
2383
2434
  const env = {
2384
2435
  ...process.env,
@@ -2893,7 +2944,7 @@ function spawnOpenCodeProcess(opts) {
2893
2944
  traceContext,
2894
2945
  initialStepNumber
2895
2946
  } = opts;
2896
- return new Promise((resolve2) => {
2947
+ return new Promise((resolve3) => {
2897
2948
  let resolved = false;
2898
2949
  let stderr = "";
2899
2950
  let lineBuffer = "";
@@ -2913,7 +2964,7 @@ function spawnOpenCodeProcess(opts) {
2913
2964
  if (resolved) return;
2914
2965
  resolved = true;
2915
2966
  cleanup();
2916
- resolve2({
2967
+ resolve3({
2917
2968
  events,
2918
2969
  success,
2919
2970
  isIdleTimeout,
@@ -2930,7 +2981,7 @@ function spawnOpenCodeProcess(opts) {
2930
2981
  detached: true
2931
2982
  });
2932
2983
  } catch (spawnError) {
2933
- resolve2({
2984
+ resolve3({
2934
2985
  events: [],
2935
2986
  success: false,
2936
2987
  isIdleTimeout: false,
@@ -3121,6 +3172,7 @@ async function executeWithOpenCode(skills, scenario, options) {
3121
3172
  aiGatewayUrl: options.aiGatewayUrl,
3122
3173
  aiGatewayHeaders: options.aiGatewayHeaders,
3123
3174
  mcps: options.mcps,
3175
+ rules: options.rules,
3124
3176
  cwd: options.cwd,
3125
3177
  config: options.config
3126
3178
  });