rightmodeler 0.1.2 → 0.2.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.
@@ -6418,7 +6418,7 @@ var require_compile = __commonJS({
6418
6418
  const schOrFunc = root.refs[ref];
6419
6419
  if (schOrFunc)
6420
6420
  return schOrFunc;
6421
- let _sch = resolve10.call(this, root, ref);
6421
+ let _sch = resolve12.call(this, root, ref);
6422
6422
  if (_sch === void 0) {
6423
6423
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
6424
6424
  const { schemaId } = this.opts;
@@ -6445,7 +6445,7 @@ var require_compile = __commonJS({
6445
6445
  function sameSchemaEnv(s1, s2) {
6446
6446
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
6447
6447
  }
6448
- function resolve10(root, ref) {
6448
+ function resolve12(root, ref) {
6449
6449
  let sch;
6450
6450
  while (typeof (sch = this.refs[ref]) == "string")
6451
6451
  ref = sch;
@@ -7076,55 +7076,55 @@ var require_fast_uri = __commonJS({
7076
7076
  }
7077
7077
  return uri;
7078
7078
  }
7079
- function resolve10(baseURI, relativeURI, options) {
7079
+ function resolve12(baseURI, relativeURI, options) {
7080
7080
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
7081
7081
  const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
7082
7082
  schemelessOptions.skipEscape = true;
7083
7083
  return serialize(resolved, schemelessOptions);
7084
7084
  }
7085
- function resolveComponent(base, relative7, options, skipNormalization) {
7085
+ function resolveComponent(base, relative9, options, skipNormalization) {
7086
7086
  const target = {};
7087
7087
  if (!skipNormalization) {
7088
7088
  base = parse3(serialize(base, options), options);
7089
- relative7 = parse3(serialize(relative7, options), options);
7089
+ relative9 = parse3(serialize(relative9, options), options);
7090
7090
  }
7091
7091
  options = options || {};
7092
- if (!options.tolerant && relative7.scheme) {
7093
- target.scheme = relative7.scheme;
7094
- target.userinfo = relative7.userinfo;
7095
- target.host = relative7.host;
7096
- target.port = relative7.port;
7097
- target.path = removeDotSegments(relative7.path || "");
7098
- target.query = relative7.query;
7092
+ if (!options.tolerant && relative9.scheme) {
7093
+ target.scheme = relative9.scheme;
7094
+ target.userinfo = relative9.userinfo;
7095
+ target.host = relative9.host;
7096
+ target.port = relative9.port;
7097
+ target.path = removeDotSegments(relative9.path || "");
7098
+ target.query = relative9.query;
7099
7099
  } else {
7100
- if (relative7.userinfo !== void 0 || relative7.host !== void 0 || relative7.port !== void 0) {
7101
- target.userinfo = relative7.userinfo;
7102
- target.host = relative7.host;
7103
- target.port = relative7.port;
7104
- target.path = removeDotSegments(relative7.path || "");
7105
- target.query = relative7.query;
7100
+ if (relative9.userinfo !== void 0 || relative9.host !== void 0 || relative9.port !== void 0) {
7101
+ target.userinfo = relative9.userinfo;
7102
+ target.host = relative9.host;
7103
+ target.port = relative9.port;
7104
+ target.path = removeDotSegments(relative9.path || "");
7105
+ target.query = relative9.query;
7106
7106
  } else {
7107
- if (!relative7.path) {
7107
+ if (!relative9.path) {
7108
7108
  target.path = base.path;
7109
- if (relative7.query !== void 0) {
7110
- target.query = relative7.query;
7109
+ if (relative9.query !== void 0) {
7110
+ target.query = relative9.query;
7111
7111
  } else {
7112
7112
  target.query = base.query;
7113
7113
  }
7114
7114
  } else {
7115
- if (relative7.path[0] === "/") {
7116
- target.path = removeDotSegments(relative7.path);
7115
+ if (relative9.path[0] === "/") {
7116
+ target.path = removeDotSegments(relative9.path);
7117
7117
  } else {
7118
7118
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
7119
- target.path = "/" + relative7.path;
7119
+ target.path = "/" + relative9.path;
7120
7120
  } else if (!base.path) {
7121
- target.path = relative7.path;
7121
+ target.path = relative9.path;
7122
7122
  } else {
7123
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative7.path;
7123
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative9.path;
7124
7124
  }
7125
7125
  target.path = removeDotSegments(target.path);
7126
7126
  }
7127
- target.query = relative7.query;
7127
+ target.query = relative9.query;
7128
7128
  }
7129
7129
  target.userinfo = base.userinfo;
7130
7130
  target.host = base.host;
@@ -7132,7 +7132,7 @@ var require_fast_uri = __commonJS({
7132
7132
  }
7133
7133
  target.scheme = base.scheme;
7134
7134
  }
7135
- target.fragment = relative7.fragment;
7135
+ target.fragment = relative9.fragment;
7136
7136
  return target;
7137
7137
  }
7138
7138
  function equal(uriA, uriB, options) {
@@ -7340,7 +7340,7 @@ var require_fast_uri = __commonJS({
7340
7340
  var fastUri = {
7341
7341
  SCHEMES,
7342
7342
  normalize,
7343
- resolve: resolve10,
7343
+ resolve: resolve12,
7344
7344
  resolveComponent,
7345
7345
  equal,
7346
7346
  serialize,
@@ -10590,7 +10590,9 @@ var require__ = __commonJS({
10590
10590
  // src/cli.ts
10591
10591
  import { spawn } from "node:child_process";
10592
10592
  import { realpathSync } from "node:fs";
10593
- import { resolve as resolve9 } from "node:path";
10593
+ import { homedir as homedir2 } from "node:os";
10594
+ import { resolve as resolve11 } from "node:path";
10595
+ import { Writable } from "node:stream";
10594
10596
  import { fileURLToPath as fileURLToPath2 } from "node:url";
10595
10597
 
10596
10598
  // ../../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/esm.mjs
@@ -15363,8 +15365,8 @@ var error3 = () => {
15363
15365
  const sizing = getSizing(issue3.origin);
15364
15366
  if (sizing) {
15365
15367
  const maxValue = Number(issue3.maximum);
15366
- const unit = getBelarusianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
15367
- return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u0432\u044F\u043B\u0456\u043A\u0456: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435"} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${sizing.verb} ${adj}${issue3.maximum.toString()} ${unit}`;
15368
+ const unit2 = getBelarusianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
15369
+ return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u0432\u044F\u043B\u0456\u043A\u0456: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435"} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${sizing.verb} ${adj}${issue3.maximum.toString()} ${unit2}`;
15368
15370
  }
15369
15371
  return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u0432\u044F\u043B\u0456\u043A\u0456: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u044D\u043D\u043D\u0435"} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 \u0431\u044B\u0446\u044C ${adj}${issue3.maximum.toString()}`;
15370
15372
  }
@@ -15373,8 +15375,8 @@ var error3 = () => {
15373
15375
  const sizing = getSizing(issue3.origin);
15374
15376
  if (sizing) {
15375
15377
  const minValue = Number(issue3.minimum);
15376
- const unit = getBelarusianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
15377
- return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u043C\u0430\u043B\u044B: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${sizing.verb} ${adj}${issue3.minimum.toString()} ${unit}`;
15378
+ const unit2 = getBelarusianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
15379
+ return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u043C\u0430\u043B\u044B: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 ${sizing.verb} ${adj}${issue3.minimum.toString()} ${unit2}`;
15378
15380
  }
15379
15381
  return `\u0417\u0430\u043D\u0430\u0434\u0442\u0430 \u043C\u0430\u043B\u044B: \u0447\u0430\u043A\u0430\u043B\u0430\u0441\u044F, \u0448\u0442\u043E ${issue3.origin} \u043F\u0430\u0432\u0456\u043D\u043D\u0430 \u0431\u044B\u0446\u044C ${adj}${issue3.minimum.toString()}`;
15380
15382
  }
@@ -17433,8 +17435,8 @@ var error20 = () => {
17433
17435
  const sizing = getSizing(issue3.origin);
17434
17436
  if (sizing) {
17435
17437
  const maxValue = Number(issue3.maximum);
17436
- const unit = getArmenianPlural(maxValue, sizing.unit.one, sizing.unit.many);
17437
- return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0574\u0565\u056E \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin ?? "\u0561\u0580\u056A\u0565\u0584")} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${adj}${issue3.maximum.toString()} ${unit}`;
17438
+ const unit2 = getArmenianPlural(maxValue, sizing.unit.one, sizing.unit.many);
17439
+ return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0574\u0565\u056E \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin ?? "\u0561\u0580\u056A\u0565\u0584")} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${adj}${issue3.maximum.toString()} ${unit2}`;
17438
17440
  }
17439
17441
  return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0574\u0565\u056E \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin ?? "\u0561\u0580\u056A\u0565\u0584")} \u056C\u056B\u0576\u056B ${adj}${issue3.maximum.toString()}`;
17440
17442
  }
@@ -17443,8 +17445,8 @@ var error20 = () => {
17443
17445
  const sizing = getSizing(issue3.origin);
17444
17446
  if (sizing) {
17445
17447
  const minValue = Number(issue3.minimum);
17446
- const unit = getArmenianPlural(minValue, sizing.unit.one, sizing.unit.many);
17447
- return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0583\u0578\u0584\u0580 \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin)} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${adj}${issue3.minimum.toString()} ${unit}`;
17448
+ const unit2 = getArmenianPlural(minValue, sizing.unit.one, sizing.unit.many);
17449
+ return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0583\u0578\u0584\u0580 \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin)} \u056F\u0578\u0582\u0576\u0565\u0576\u0561 ${adj}${issue3.minimum.toString()} ${unit2}`;
17448
17450
  }
17449
17451
  return `\u0549\u0561\u0583\u0561\u0566\u0561\u0576\u0581 \u0583\u0578\u0584\u0580 \u0561\u0580\u056A\u0565\u0584\u2024 \u057D\u057A\u0561\u057D\u057E\u0578\u0582\u0574 \u0567, \u0578\u0580 ${withDefiniteArticle(issue3.origin)} \u056C\u056B\u0576\u056B ${adj}${issue3.minimum.toString()}`;
17450
17452
  }
@@ -18207,18 +18209,18 @@ var error27 = () => {
18207
18209
  const adj = issue3.inclusive ? "\uC774\uD558" : "\uBBF8\uB9CC";
18208
18210
  const suffix = adj === "\uBBF8\uB9CC" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
18209
18211
  const sizing = getSizing(issue3.origin);
18210
- const unit = sizing?.unit ?? "\uC694\uC18C";
18212
+ const unit2 = sizing?.unit ?? "\uC694\uC18C";
18211
18213
  if (sizing)
18212
- return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue3.maximum.toString()}${unit} ${adj}${suffix}`;
18214
+ return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue3.maximum.toString()}${unit2} ${adj}${suffix}`;
18213
18215
  return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${issue3.maximum.toString()} ${adj}${suffix}`;
18214
18216
  }
18215
18217
  case "too_small": {
18216
18218
  const adj = issue3.inclusive ? "\uC774\uC0C1" : "\uCD08\uACFC";
18217
18219
  const suffix = adj === "\uC774\uC0C1" ? "\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" : "\uC5EC\uC57C \uD569\uB2C8\uB2E4";
18218
18220
  const sizing = getSizing(issue3.origin);
18219
- const unit = sizing?.unit ?? "\uC694\uC18C";
18221
+ const unit2 = sizing?.unit ?? "\uC694\uC18C";
18220
18222
  if (sizing) {
18221
- return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue3.minimum.toString()}${unit} ${adj}${suffix}`;
18223
+ return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue3.minimum.toString()}${unit2} ${adj}${suffix}`;
18222
18224
  }
18223
18225
  return `${issue3.origin ?? "\uAC12"}\uC774 \uB108\uBB34 \uC791\uC2B5\uB2C8\uB2E4: ${issue3.minimum.toString()} ${adj}${suffix}`;
18224
18226
  }
@@ -19571,8 +19573,8 @@ var error38 = () => {
19571
19573
  const sizing = getSizing(issue3.origin);
19572
19574
  if (sizing) {
19573
19575
  const maxValue = Number(issue3.maximum);
19574
- const unit = getRussianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
19575
- return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${adj}${issue3.maximum.toString()} ${unit}`;
19576
+ const unit2 = getRussianPlural(maxValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
19577
+ return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${adj}${issue3.maximum.toString()} ${unit2}`;
19576
19578
  }
19577
19579
  return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin ?? "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"} \u0431\u0443\u0434\u0435\u0442 ${adj}${issue3.maximum.toString()}`;
19578
19580
  }
@@ -19581,8 +19583,8 @@ var error38 = () => {
19581
19583
  const sizing = getSizing(issue3.origin);
19582
19584
  if (sizing) {
19583
19585
  const minValue = Number(issue3.minimum);
19584
- const unit = getRussianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
19585
- return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${adj}${issue3.minimum.toString()} ${unit}`;
19586
+ const unit2 = getRussianPlural(minValue, sizing.unit.one, sizing.unit.few, sizing.unit.many);
19587
+ return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin} \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C ${adj}${issue3.minimum.toString()} ${unit2}`;
19586
19588
  }
19587
19589
  return `\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435: \u043E\u0436\u0438\u0434\u0430\u043B\u043E\u0441\u044C, \u0447\u0442\u043E ${issue3.origin} \u0431\u0443\u0434\u0435\u0442 ${adj}${issue3.minimum.toString()}`;
19588
19590
  }
@@ -27220,8 +27222,8 @@ function compareSignals(left, right) {
27220
27222
  // ../kernel/dist/selection.js
27221
27223
  import { createHash as createHash2 } from "node:crypto";
27222
27224
  function assignSplits(caseIds, seed) {
27223
- const unique = new Set(caseIds);
27224
- if (unique.size !== caseIds.length) {
27225
+ const unique2 = new Set(caseIds);
27226
+ if (unique2.size !== caseIds.length) {
27225
27227
  throw new Error("caseIds contains a duplicate identifier");
27226
27228
  }
27227
27229
  const ranked = [...caseIds].sort((left, right) => {
@@ -28010,10 +28012,10 @@ var AdaptiveLimiter = class {
28010
28012
  this.active += 1;
28011
28013
  return Promise.resolve();
28012
28014
  }
28013
- return new Promise((resolve10) => {
28015
+ return new Promise((resolve12) => {
28014
28016
  this.waiters.push(() => {
28015
28017
  this.active += 1;
28016
- resolve10();
28018
+ resolve12();
28017
28019
  });
28018
28020
  });
28019
28021
  }
@@ -28081,7 +28083,7 @@ function retryDelay(response, attempt) {
28081
28083
  return backoff + Math.random() * backoff * 0.25;
28082
28084
  }
28083
28085
  function sleep(milliseconds) {
28084
- return new Promise((resolve10) => setTimeout(resolve10, milliseconds));
28086
+ return new Promise((resolve12) => setTimeout(resolve12, milliseconds));
28085
28087
  }
28086
28088
  function isRetryable(status) {
28087
28089
  return status === 429 || status >= 500;
@@ -28629,7 +28631,7 @@ async function replayModeA(input) {
28629
28631
  if (refunds.length > 0) {
28630
28632
  await Promise.race(refunds);
28631
28633
  } else {
28632
- await new Promise((resolve10) => setTimeout(resolve10, 0));
28634
+ await new Promise((resolve12) => setTimeout(resolve12, 0));
28633
28635
  }
28634
28636
  continue;
28635
28637
  }
@@ -28647,8 +28649,8 @@ async function replayModeA(input) {
28647
28649
  }
28648
28650
  }
28649
28651
  let resolveRefund = () => void 0;
28650
- const refundComplete = new Promise((resolve10) => {
28651
- resolveRefund = resolve10;
28652
+ const refundComplete = new Promise((resolve12) => {
28653
+ resolveRefund = resolve12;
28652
28654
  });
28653
28655
  activeRefunds.add(refundComplete);
28654
28656
  const executionId = mintExecutionId();
@@ -28835,8 +28837,8 @@ function redactCredential(body, credential) {
28835
28837
  return Buffer.from(body.toString("utf8").split(credential).join("[REDACTED]"), "utf8");
28836
28838
  }
28837
28839
  function close(server) {
28838
- return new Promise((resolve10, reject) => {
28839
- server.close((error51) => error51 === void 0 ? resolve10() : reject(error51));
28840
+ return new Promise((resolve12, reject) => {
28841
+ server.close((error51) => error51 === void 0 ? resolve12() : reject(error51));
28840
28842
  });
28841
28843
  }
28842
28844
  async function startEgressListener(options) {
@@ -28904,9 +28906,9 @@ async function startEgressListener(options) {
28904
28906
  incoming.pipe(upstream);
28905
28907
  });
28906
28908
  const hostname5 = options.hostname ?? "0.0.0.0";
28907
- await new Promise((resolve10, reject) => {
28909
+ await new Promise((resolve12, reject) => {
28908
28910
  server.once("error", reject);
28909
- server.listen(options.port ?? 0, hostname5, resolve10);
28911
+ server.listen(options.port ?? 0, hostname5, resolve12);
28910
28912
  });
28911
28913
  const address = server.address();
28912
28914
  return {
@@ -29066,11 +29068,11 @@ function validatePricing(steps, policy, table) {
29066
29068
  }
29067
29069
  }
29068
29070
  function createWaiter() {
29069
- let resolve10 = () => void 0;
29071
+ let resolve12 = () => void 0;
29070
29072
  const promise2 = new Promise((done) => {
29071
- resolve10 = done;
29073
+ resolve12 = done;
29072
29074
  });
29073
- return { promise: promise2, resolve: resolve10 };
29075
+ return { promise: promise2, resolve: resolve12 };
29074
29076
  }
29075
29077
  async function reserveCase(input, activeRefunds) {
29076
29078
  for (; ; ) {
@@ -29173,7 +29175,7 @@ async function waitForExit(executor, handle) {
29173
29175
  const status = await executor.status(handle);
29174
29176
  if (status.state === "exited")
29175
29177
  return status;
29176
- await new Promise((resolve10) => setTimeout(resolve10, 50));
29178
+ await new Promise((resolve12) => setTimeout(resolve12, 50));
29177
29179
  }
29178
29180
  }
29179
29181
  function textFiles(collected) {
@@ -30511,12 +30513,12 @@ function enclosingSymbol(content, position) {
30511
30513
  return nearest;
30512
30514
  }
30513
30515
  function extractCallText(content, position) {
30514
- const open = content.indexOf("(", position);
30515
- if (open === -1)
30516
+ const open2 = content.indexOf("(", position);
30517
+ if (open2 === -1)
30516
30518
  return content.slice(position, position + 240);
30517
30519
  let depth = 0;
30518
30520
  let quote = null;
30519
- for (let index = open; index < content.length; index += 1) {
30521
+ for (let index = open2; index < content.length; index += 1) {
30520
30522
  const character = content[index];
30521
30523
  if (quote !== null) {
30522
30524
  if (character === "\\")
@@ -30576,11 +30578,11 @@ function splitTopLevel(value) {
30576
30578
  return parts;
30577
30579
  }
30578
30580
  function argumentKeys(callText) {
30579
- const open = callText.indexOf("(");
30581
+ const open2 = callText.indexOf("(");
30580
30582
  const close2 = callText.lastIndexOf(")");
30581
- if (open === -1 || close2 <= open)
30583
+ if (open2 === -1 || close2 <= open2)
30582
30584
  return [];
30583
- let argumentsText = callText.slice(open + 1, close2).trim();
30585
+ let argumentsText = callText.slice(open2 + 1, close2).trim();
30584
30586
  let separator = "=";
30585
30587
  if (argumentsText.startsWith("{")) {
30586
30588
  const objectClose = argumentsText.lastIndexOf("}");
@@ -33978,7 +33980,7 @@ function isRateLimited(response) {
33978
33980
  return response.status === 429 || response.status === 403 && (response.headers.has("retry-after") || response.headers.get("x-ratelimit-remaining") === "0");
33979
33981
  }
33980
33982
  function sleep2(milliseconds) {
33981
- return new Promise((resolve10) => setTimeout(resolve10, milliseconds));
33983
+ return new Promise((resolve12) => setTimeout(resolve12, milliseconds));
33982
33984
  }
33983
33985
  function parseJson(text, label) {
33984
33986
  try {
@@ -34487,10 +34489,10 @@ function lineText(content, line) {
34487
34489
  }
34488
34490
  function callEnd(content, start) {
34489
34491
  const searchable = scanSource(content).mask;
34490
- const open = searchable.indexOf("(", start);
34491
- if (open === -1) return -1;
34492
+ const open2 = searchable.indexOf("(", start);
34493
+ if (open2 === -1) return -1;
34492
34494
  let depth = 0;
34493
- for (let index = open; index < searchable.length; index += 1) {
34495
+ for (let index = open2; index < searchable.length; index += 1) {
34494
34496
  const character = searchable[index];
34495
34497
  if (character === "(") {
34496
34498
  depth += 1;
@@ -34536,13 +34538,13 @@ function splitTopLevel2(content, start, end) {
34536
34538
  return ranges;
34537
34539
  }
34538
34540
  function topLevelModelSpans(content, callStart, callEndOffset) {
34539
- const open = content.indexOf("(", callStart);
34540
- if (open === -1 || callEndOffset <= open + 1) return null;
34541
- const outer = splitTopLevel2(content, open + 1, callEndOffset - 1);
34541
+ const open2 = content.indexOf("(", callStart);
34542
+ if (open2 === -1 || callEndOffset <= open2 + 1) return null;
34543
+ const outer = splitTopLevel2(content, open2 + 1, callEndOffset - 1);
34542
34544
  if (outer === null) return null;
34543
34545
  const first = trimRange(
34544
34546
  content,
34545
- outer[0] ?? { start: open + 1, end: open + 1 }
34547
+ outer[0] ?? { start: open2 + 1, end: open2 + 1 }
34546
34548
  );
34547
34549
  let parts = outer;
34548
34550
  let separator = "=";
@@ -35195,14 +35197,14 @@ function formatterCommand(repoDir, formatter) {
35195
35197
  return null;
35196
35198
  }
35197
35199
  function runFormatter(command, filePath, cwd, input) {
35198
- return new Promise((resolve10, reject) => {
35200
+ return new Promise((resolve12, reject) => {
35199
35201
  const child = execFile2(
35200
35202
  command.executable,
35201
35203
  command.args(filePath),
35202
35204
  { cwd, encoding: "utf8" },
35203
35205
  (error51, stdout) => {
35204
35206
  if (error51 !== null) reject(error51);
35205
- else resolve10(command.stdin ? stdout : null);
35207
+ else resolve12(command.stdin ? stdout : null);
35206
35208
  }
35207
35209
  );
35208
35210
  if (command.stdin) child.stdin?.end(input);
@@ -36236,7 +36238,7 @@ function reviewersFor(verdicts) {
36236
36238
  slash === -1 ? { kind: "user", value: identity } : { kind: "team", value: identity.slice(slash + 1) }
36237
36239
  );
36238
36240
  }
36239
- const unique = [
36241
+ const unique2 = [
36240
36242
  ...new Map(
36241
36243
  selected.map((reviewer) => [
36242
36244
  `${reviewer.kind}:${reviewer.value.toLowerCase()}`,
@@ -36245,8 +36247,8 @@ function reviewersFor(verdicts) {
36245
36247
  ).values()
36246
36248
  ];
36247
36249
  return {
36248
- reviewers: unique.flatMap(({ kind, value }) => kind === "user" ? [value] : []).slice(0, reviewerLimit),
36249
- teamReviewers: unique.flatMap(({ kind, value }) => kind === "team" ? [value] : []).slice(0, reviewerLimit)
36250
+ reviewers: unique2.flatMap(({ kind, value }) => kind === "user" ? [value] : []).slice(0, reviewerLimit),
36251
+ teamReviewers: unique2.flatMap(({ kind, value }) => kind === "team" ? [value] : []).slice(0, reviewerLimit)
36250
36252
  };
36251
36253
  }
36252
36254
  async function gitOutput(repoDir, args) {
@@ -38523,7 +38525,7 @@ async function pollEvaluator(evaluator, providerRunId) {
38523
38525
  const delays = [0, 25, 50, 100, 200, 400];
38524
38526
  for (const delay of delays) {
38525
38527
  if (delay > 0) {
38526
- await new Promise((resolve10) => setTimeout(resolve10, delay));
38528
+ await new Promise((resolve12) => setTimeout(resolve12, delay));
38527
38529
  }
38528
38530
  const status = await evaluator.status(providerRunId);
38529
38531
  if (status === "complete" || status === "failed") return status;
@@ -38685,13 +38687,13 @@ async function importCorpus(config2, options) {
38685
38687
  `Cannot import an empty ${config2.provider} dataset: ${config2.dataset}`
38686
38688
  );
38687
38689
  }
38688
- const unique = /* @__PURE__ */ new Map();
38690
+ const unique2 = /* @__PURE__ */ new Map();
38689
38691
  for (const item of items) {
38690
38692
  const content = importedContent(config2.provider, item);
38691
38693
  const caseId = computeRunSpecDigest(contentJson(content));
38692
- unique.set(caseId, { caseId, content, split: "shortlist" });
38694
+ unique2.set(caseId, { caseId, content, split: "shortlist" });
38693
38695
  }
38694
- const unsplitCases = [...unique.values()];
38696
+ const unsplitCases = [...unique2.values()];
38695
38697
  const splits = assignSplits(
38696
38698
  unsplitCases.map(({ caseId }) => caseId),
38697
38699
  options.seed
@@ -40688,24 +40690,24 @@ ${marker}`
40688
40690
  await renew();
40689
40691
  observedIssueComments.push(...issueComments);
40690
40692
  const handled = new Set(state.handledEventKeys);
40691
- for (const question of questions(
40693
+ for (const question2 of questions(
40692
40694
  reviews,
40693
40695
  reviewComments,
40694
40696
  issueComments,
40695
40697
  input.prNumber
40696
40698
  )) {
40697
- const key = question.eventKey;
40699
+ const key = question2.eventKey;
40698
40700
  if (handled.has(key)) continue;
40699
40701
  const selected = affectedVerdicts(
40700
40702
  prVerdicts,
40701
- [question.body],
40702
- question.path === void 0 ? [] : [question.path]
40703
+ [question2.body],
40704
+ question2.path === void 0 ? [] : [question2.path]
40703
40705
  );
40704
40706
  const postedCommentId = await comment(key, evidenceReply(selected));
40705
40707
  const event = await record2("comment_posted", {
40706
40708
  handledEventKey: key,
40707
- source: question.source,
40708
- sourceCommentId: question.id,
40709
+ source: question2.source,
40710
+ sourceCommentId: question2.id,
40709
40711
  postedCommentId,
40710
40712
  familyIds: selected.map(({ verdict }) => verdict.familyId)
40711
40713
  });
@@ -40717,8 +40719,8 @@ ${marker}`
40717
40719
  };
40718
40720
  actions.push(
40719
40721
  action("evidence_replied", {
40720
- source: question.source,
40721
- commentId: question.id,
40722
+ source: question2.source,
40723
+ commentId: question2.id,
40722
40724
  familyIds: selected.map(({ verdict }) => verdict.familyId)
40723
40725
  })
40724
40726
  );
@@ -41287,6 +41289,17 @@ async function runPipeline(options) {
41287
41289
  recommendationExists: false
41288
41290
  };
41289
41291
  }
41292
+ await repositoryRevision(context2.repo);
41293
+ const initialState = await readSetupState(context2.store, context2.projectId);
41294
+ const ingestCheckpoint = initialState.stages.ingest;
41295
+ if (stagesThrough(options.through).includes("ingest") && context2.traces === void 0 && (ingestCheckpoint === void 0 || !await checkpointOutputExists(context2, "ingest", ingestCheckpoint))) {
41296
+ throw new ProtocolError({
41297
+ exitCode: 2,
41298
+ code: "missing_traces_path",
41299
+ message: "A trace input path is required when ingest is reached.",
41300
+ remedy: "Pass --traces <path> with an OTel GenAI JSON or OpenAI JSONL trace file."
41301
+ });
41302
+ }
41290
41303
  if (options.existingRunId !== void 0) {
41291
41304
  const existing = await requireRunningReplayRun(
41292
41305
  context2,
@@ -43938,12 +43951,40 @@ async function repositoryDigest(repo, storeRoot) {
43938
43951
  });
43939
43952
  }
43940
43953
  async function repositoryRevision(repo) {
43941
- const { stdout } = await execFileAsync6(
43942
- "git",
43943
- ["-C", repo, "rev-parse", "HEAD"],
43944
- { encoding: "utf8" }
43945
- );
43946
- return stdout.trim();
43954
+ let insideWorkTree;
43955
+ try {
43956
+ ({ stdout: insideWorkTree } = await execFileAsync6(
43957
+ "git",
43958
+ ["-C", repo, "rev-parse", "--is-inside-work-tree"],
43959
+ { encoding: "utf8" }
43960
+ ));
43961
+ } catch {
43962
+ throw notGitRepository();
43963
+ }
43964
+ if (insideWorkTree.trim() !== "true") throw notGitRepository();
43965
+ try {
43966
+ const { stdout } = await execFileAsync6(
43967
+ "git",
43968
+ ["-C", repo, "rev-parse", "--verify", "HEAD"],
43969
+ { encoding: "utf8" }
43970
+ );
43971
+ return stdout.trim();
43972
+ } catch {
43973
+ throw new ProtocolError({
43974
+ exitCode: 2,
43975
+ code: "git_repository_has_no_commits",
43976
+ message: "This git repository has no commits. Rightmodeler ties findings to your code, so make an initial commit and rerun.",
43977
+ remedy: "Create the first commit, then rerun the command."
43978
+ });
43979
+ }
43980
+ }
43981
+ function notGitRepository() {
43982
+ return new ProtocolError({
43983
+ exitCode: 2,
43984
+ code: "not_git_repository",
43985
+ message: "This folder is not a git repository. Rightmodeler ties findings to your code, so run it inside the project you want audited (or run git init and commit first).",
43986
+ remedy: "Run the command again from a Git repository with at least one commit."
43987
+ });
43947
43988
  }
43948
43989
  function corpusOutput(corpus) {
43949
43990
  return {
@@ -44564,9 +44605,399 @@ function applySwaps2(options) {
44564
44605
  });
44565
44606
  }
44566
44607
 
44608
+ // src/data/discover.ts
44609
+ import { open, readdir as readdir4, realpath as realpath2, stat } from "node:fs/promises";
44610
+ import { homedir } from "node:os";
44611
+ import { isAbsolute as isAbsolute2, join as join14, relative as relative7, resolve as resolve8 } from "node:path";
44612
+ var MAX_FILES = 50;
44613
+ var MAX_READ_BYTES = 64 * 1024;
44614
+ var MAX_SAMPLE_RECORDS = 20;
44615
+ var SOURCE_BUDGETS = { local: 20, claude: 15, codex: 15 };
44616
+ async function discoverTraces(options) {
44617
+ const repo = resolve8(options.repo);
44618
+ const homeDir = resolve8(options.homeDir ?? homedir());
44619
+ const candidates = await candidateFiles(repo, homeDir);
44620
+ const discovered = [];
44621
+ for (const candidate of candidates.slice(0, MAX_FILES)) {
44622
+ try {
44623
+ const head = await detectionHead(candidate.path, candidate.size);
44624
+ if (candidate.source === "codex" && codexSessionCwd(head.text) !== repo) {
44625
+ continue;
44626
+ }
44627
+ const adapter = detectFormat(head.text, traceAdapters);
44628
+ discovered.push({
44629
+ path: candidate.path,
44630
+ format: adapter.name,
44631
+ approximateRecords: head.approximateRecords,
44632
+ modifiedAt: new Date(candidate.modifiedAtMs),
44633
+ sourceOrder: candidate.sourceOrder
44634
+ });
44635
+ } catch {
44636
+ }
44637
+ }
44638
+ return discovered.sort(
44639
+ (left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime() || left.sourceOrder - right.sourceOrder || compareText14(left.path, right.path)
44640
+ ).map(({ sourceOrder: _sourceOrder, ...candidate }) => candidate);
44641
+ }
44642
+ function sanitizeClaudeProjectPath(repo) {
44643
+ const absolute = resolve8(repo);
44644
+ const sanitized = absolute.replace(/[^a-zA-Z0-9]/g, "-");
44645
+ if (sanitized.length <= 200) return sanitized;
44646
+ let hash2 = 0;
44647
+ for (let index = 0; index < absolute.length; index += 1) {
44648
+ hash2 = hash2 * 31 + absolute.charCodeAt(index) | 0;
44649
+ }
44650
+ return `${sanitized.slice(0, 200)}-${Math.abs(hash2).toString(36)}`;
44651
+ }
44652
+ async function candidateFiles(repo, homeDir) {
44653
+ const localPaths = await localCandidatePaths(repo);
44654
+ const claudePaths = (await jsonFiles(
44655
+ join14(homeDir, ".claude", "projects", sanitizeClaudeProjectPath(repo)),
44656
+ false
44657
+ )).sort(compareText14);
44658
+ const codexPaths = (await jsonFiles(join14(homeDir, ".codex", "sessions"), true)).filter((path) => path.endsWith(".jsonl")).sort((left, right) => compareText14(right, left));
44659
+ const sources = [
44660
+ {
44661
+ source: "local",
44662
+ files: await statCandidates(localPaths, "local", false)
44663
+ },
44664
+ {
44665
+ source: "claude",
44666
+ files: await statCandidates(claudePaths, "claude", true)
44667
+ },
44668
+ {
44669
+ source: "codex",
44670
+ files: await statCandidates(codexPaths, "codex", false)
44671
+ }
44672
+ ];
44673
+ const selected = [];
44674
+ const offsets = /* @__PURE__ */ new Map();
44675
+ for (const source of sources) {
44676
+ const count = Math.min(SOURCE_BUDGETS[source.source], source.files.length);
44677
+ selected.push(...source.files.slice(0, count));
44678
+ offsets.set(source.source, count);
44679
+ }
44680
+ for (const source of sources) {
44681
+ const remaining = MAX_FILES - selected.length;
44682
+ if (remaining === 0) break;
44683
+ const offset = offsets.get(source.source) ?? 0;
44684
+ const extra = source.files.slice(offset, offset + remaining);
44685
+ selected.push(...extra);
44686
+ offsets.set(source.source, offset + extra.length);
44687
+ }
44688
+ return selected.map((file2, sourceOrder) => ({ ...file2, sourceOrder }));
44689
+ }
44690
+ async function statCandidates(paths, source, sortNewest) {
44691
+ const selectedPaths = sortNewest ? paths : paths.slice(0, MAX_FILES);
44692
+ const files = (await Promise.all(
44693
+ selectedPaths.map(async (path) => {
44694
+ try {
44695
+ const metadata = await stat(path);
44696
+ return {
44697
+ path,
44698
+ source,
44699
+ sourceOrder: 0,
44700
+ size: metadata.size,
44701
+ modifiedAtMs: metadata.mtimeMs
44702
+ };
44703
+ } catch {
44704
+ return void 0;
44705
+ }
44706
+ })
44707
+ )).filter((file2) => file2 !== void 0);
44708
+ if (sortNewest) {
44709
+ files.sort(
44710
+ (left, right) => right.modifiedAtMs - left.modifiedAtMs || compareText14(left.path, right.path)
44711
+ );
44712
+ }
44713
+ return files.slice(0, MAX_FILES);
44714
+ }
44715
+ async function localCandidatePaths(repo) {
44716
+ const tracesDirectory = join14(repo, "traces");
44717
+ const [realRepo, realTracesDirectory] = await Promise.all([
44718
+ realpath2(repo).catch(() => void 0),
44719
+ realpath2(tracesDirectory).catch(() => void 0)
44720
+ ]);
44721
+ const nested = realRepo !== void 0 && realTracesDirectory !== void 0 && isWithin(realRepo, realTracesDirectory) ? (await jsonFiles(tracesDirectory, false)).sort(compareText14) : [];
44722
+ const topLevel = (await jsonFiles(repo, false)).sort((left, right) => {
44723
+ const leftJsonl = left.endsWith(".jsonl");
44724
+ const rightJsonl = right.endsWith(".jsonl");
44725
+ return leftJsonl === rightJsonl ? compareText14(left, right) : leftJsonl ? -1 : 1;
44726
+ });
44727
+ const topLevelSet = new Set(topLevel);
44728
+ return unique([
44729
+ ...[join14(repo, "traces.json"), join14(repo, "traces.jsonl")].filter(
44730
+ (path) => topLevelSet.has(path)
44731
+ ),
44732
+ ...nested,
44733
+ ...topLevel
44734
+ ]);
44735
+ }
44736
+ async function jsonFiles(root, recursive) {
44737
+ let entries;
44738
+ try {
44739
+ entries = await readdir4(root, { recursive, withFileTypes: true });
44740
+ } catch {
44741
+ return [];
44742
+ }
44743
+ return entries.filter(
44744
+ (entry) => entry.isFile() && (entry.name.endsWith(".json") || entry.name.endsWith(".jsonl"))
44745
+ ).map((entry) => join14(entry.parentPath, entry.name));
44746
+ }
44747
+ function isWithin(root, path) {
44748
+ const fromRoot = relative7(root, path);
44749
+ return fromRoot === "" || !fromRoot.startsWith("..") && !isAbsolute2(fromRoot);
44750
+ }
44751
+ async function detectionHead(path, fileSize) {
44752
+ const handle = await open(path, "r");
44753
+ try {
44754
+ const buffer = Buffer.alloc(Math.min(MAX_READ_BYTES, fileSize));
44755
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
44756
+ const raw = buffer.toString("utf8", 0, bytesRead);
44757
+ const complete = bytesRead === fileSize;
44758
+ const parsed2 = complete ? parseWholeJson(raw) : void 0;
44759
+ if (parsed2 !== void 0) {
44760
+ const records = Array.isArray(parsed2) ? parsed2 : [parsed2];
44761
+ return {
44762
+ text: JSON.stringify(records.slice(0, MAX_SAMPLE_RECORDS)),
44763
+ approximateRecords: Math.max(1, records.length)
44764
+ };
44765
+ }
44766
+ const trimmed = raw.trimStart();
44767
+ if (trimmed.startsWith("[")) {
44768
+ const records = leadingArrayRecords(trimmed, MAX_SAMPLE_RECORDS);
44769
+ return {
44770
+ text: JSON.stringify(records),
44771
+ approximateRecords: approximateRecordCount(
44772
+ records.length,
44773
+ bytesRead,
44774
+ fileSize
44775
+ )
44776
+ };
44777
+ }
44778
+ const completeText = complete ? raw : raw.slice(0, Math.max(0, raw.lastIndexOf("\n") + 1));
44779
+ const lines = completeText.split(/\r?\n/).filter((line) => line.trim() !== "");
44780
+ return {
44781
+ text: lines.slice(0, MAX_SAMPLE_RECORDS).join("\n"),
44782
+ approximateRecords: approximateRecordCount(
44783
+ lines.length,
44784
+ bytesRead,
44785
+ fileSize
44786
+ )
44787
+ };
44788
+ } finally {
44789
+ await handle.close();
44790
+ }
44791
+ }
44792
+ function leadingArrayRecords(text, limit) {
44793
+ const records = [];
44794
+ let start = -1;
44795
+ let depth = 0;
44796
+ let inString = false;
44797
+ let escaped = false;
44798
+ for (let index = 1; index < text.length && records.length < limit; index += 1) {
44799
+ const character = text[index];
44800
+ if (inString) {
44801
+ if (escaped) escaped = false;
44802
+ else if (character === "\\") escaped = true;
44803
+ else if (character === '"') inString = false;
44804
+ continue;
44805
+ }
44806
+ if (character === '"') {
44807
+ inString = true;
44808
+ if (start === -1) start = index;
44809
+ continue;
44810
+ }
44811
+ if (start === -1) {
44812
+ if (/\s|,/u.test(character)) continue;
44813
+ if (character === "]") break;
44814
+ start = index;
44815
+ }
44816
+ if (character === "{" || character === "[") depth += 1;
44817
+ if (character === "}" || character === "]") depth -= 1;
44818
+ if (depth === 0 && (character === "}" || character === "]")) {
44819
+ const parsed2 = parseWholeJson(text.slice(start, index + 1));
44820
+ if (parsed2 !== void 0) records.push(parsed2);
44821
+ start = -1;
44822
+ }
44823
+ }
44824
+ return records;
44825
+ }
44826
+ function codexSessionCwd(text) {
44827
+ for (const line of text.split(/\r?\n/)) {
44828
+ if (line.trim() === "") continue;
44829
+ const record2 = parseWholeJson(line);
44830
+ if (isRecord4(record2) && record2.type === "session_meta" && isRecord4(record2.payload) && typeof record2.payload.cwd === "string") {
44831
+ return resolve8(record2.payload.cwd);
44832
+ }
44833
+ }
44834
+ return void 0;
44835
+ }
44836
+ function parseWholeJson(text) {
44837
+ try {
44838
+ return JSON.parse(text);
44839
+ } catch {
44840
+ return void 0;
44841
+ }
44842
+ }
44843
+ function approximateRecordCount(observed, bytesRead, fileSize) {
44844
+ if (observed === 0) return 0;
44845
+ if (bytesRead === 0 || bytesRead === fileSize) return observed;
44846
+ return Math.max(observed, Math.round(observed * fileSize / bytesRead));
44847
+ }
44848
+ function unique(values) {
44849
+ return [...new Set(values)];
44850
+ }
44851
+ function compareText14(left, right) {
44852
+ return left < right ? -1 : left > right ? 1 : 0;
44853
+ }
44854
+
44855
+ // src/guidance.ts
44856
+ import { createInterface } from "node:readline";
44857
+ import { isAbsolute as isAbsolute3, relative as relative8, resolve as resolve9 } from "node:path";
44858
+ async function promptForTracePath(options) {
44859
+ if (options.candidates.length === 0) {
44860
+ options.output.write(
44861
+ [
44862
+ "Traces are logs that your AI tools already write.",
44863
+ "If you use Claude Code or Codex in this project, run a few tasks there and run this command again. Rightmodeler finds those logs automatically.",
44864
+ "If your app logs to Langfuse, Braintrust, LangSmith, Helicone, or W&B Weave, export a file and enter its path.",
44865
+ "See the supported sources at https://www.rightmodeler.com/integrations",
44866
+ ""
44867
+ ].join("\n")
44868
+ );
44869
+ const asked2 = await question(
44870
+ options,
44871
+ "Trace file path (leave empty to stop): "
44872
+ );
44873
+ const typed = asked2.answer.trim();
44874
+ return asked2.cancelled || typed === "" ? void 0 : resolve9(options.repo, typed);
44875
+ }
44876
+ options.output.write("Found trace files:\n");
44877
+ const now = options.now ?? /* @__PURE__ */ new Date();
44878
+ for (const [index, candidate] of options.candidates.entries()) {
44879
+ options.output.write(
44880
+ `${index + 1}. ${formatName(candidate.format)}, about ${candidate.approximateRecords} ${unit("model call", candidate.approximateRecords)}, ${formatAge(candidate.modifiedAt, now)}, ${shortPath(candidate.path, options.repo, options.homeDir)}
44881
+ `
44882
+ );
44883
+ }
44884
+ const asked = await question(
44885
+ options,
44886
+ "Choose a trace file [1]: ",
44887
+ (value) => {
44888
+ const choice = value.trim();
44889
+ if (/^[0-9]+$/u.test(choice)) {
44890
+ const selected = options.candidates[Number(choice) - 1];
44891
+ if (selected === void 0) {
44892
+ options.output.write(
44893
+ `Choose a number from 1 to ${options.candidates.length}.
44894
+ `
44895
+ );
44896
+ return false;
44897
+ }
44898
+ }
44899
+ return true;
44900
+ }
44901
+ );
44902
+ if (asked.cancelled) return void 0;
44903
+ const answer = asked.answer.trim();
44904
+ if (answer === "") return options.candidates[0].path;
44905
+ if (/^[1-9][0-9]*$/u.test(answer)) {
44906
+ const selected = options.candidates[Number(answer) - 1];
44907
+ if (selected !== void 0) return selected.path;
44908
+ }
44909
+ return resolve9(options.repo, answer);
44910
+ }
44911
+ async function promptForProviderBaseUrl(options) {
44912
+ options.output.write(
44913
+ "Replay calls cheaper models through any OpenAI-compatible endpoint, such as OpenRouter or the Vercel AI Gateway.\n"
44914
+ );
44915
+ const suffix = options.current === void 0 ? "" : ` [${options.current}]`;
44916
+ const asked = await question(options, `Provider base URL${suffix}: `);
44917
+ if (asked.cancelled) return options.current;
44918
+ const answer = asked.answer.trim();
44919
+ return answer === "" ? options.current : answer;
44920
+ }
44921
+ function question(streams, prompt, accept = () => true) {
44922
+ const readline = createInterface({
44923
+ input: streams.input,
44924
+ output: streams.output
44925
+ });
44926
+ return new Promise((resolveAnswer) => {
44927
+ let settled = false;
44928
+ const finish = (asked) => {
44929
+ if (settled) return;
44930
+ settled = true;
44931
+ resolveAnswer(asked);
44932
+ };
44933
+ const ask = () => {
44934
+ readline.question(prompt, (answer) => {
44935
+ if (!accept(answer)) {
44936
+ ask();
44937
+ return;
44938
+ }
44939
+ finish({ answer, cancelled: false });
44940
+ readline.close();
44941
+ });
44942
+ };
44943
+ readline.once("close", () => finish({ answer: "", cancelled: true }));
44944
+ streams.input.once("close", () => {
44945
+ readline.close();
44946
+ finish({ answer: "", cancelled: true });
44947
+ });
44948
+ streams.output.once("close", () => {
44949
+ readline.close();
44950
+ finish({ answer: "", cancelled: true });
44951
+ });
44952
+ ask();
44953
+ });
44954
+ }
44955
+ function formatName(format9) {
44956
+ const names = {
44957
+ "otel-genai": "OpenTelemetry GenAI export",
44958
+ "openai-jsonl": "OpenAI log",
44959
+ langfuse: "Langfuse export",
44960
+ braintrust: "Braintrust export",
44961
+ langsmith: "LangSmith export",
44962
+ openinference: "OpenInference export",
44963
+ helicone: "Helicone export",
44964
+ weave: "Weave export",
44965
+ "claude-code": "Claude Code session",
44966
+ codex: "Codex session"
44967
+ };
44968
+ return names[format9];
44969
+ }
44970
+ function shortPath(path, repo, homeDir) {
44971
+ const fromRepo = relative8(resolve9(repo), path);
44972
+ if (fromRepo !== "" && !fromRepo.startsWith("..") && !isAbsolute3(fromRepo)) {
44973
+ return `./${fromRepo}`;
44974
+ }
44975
+ const fromHome = relative8(resolve9(homeDir), path);
44976
+ if (fromHome !== "" && !fromHome.startsWith("..") && !isAbsolute3(fromHome)) {
44977
+ return `~/${fromHome}`;
44978
+ }
44979
+ return path;
44980
+ }
44981
+ function formatAge(modifiedAt, now) {
44982
+ const seconds = Math.max(
44983
+ 0,
44984
+ Math.floor((now.getTime() - modifiedAt.getTime()) / 1e3)
44985
+ );
44986
+ if (seconds < 60) return "just now";
44987
+ const minutes = Math.floor(seconds / 60);
44988
+ if (minutes < 60) return `${minutes} ${unit("minute", minutes)} ago`;
44989
+ const hours = Math.floor(minutes / 60);
44990
+ if (hours < 24) return `${hours} ${unit("hour", hours)} ago`;
44991
+ const days = Math.floor(hours / 24);
44992
+ return `${days} ${unit("day", days)} ago`;
44993
+ }
44994
+ function unit(label, value) {
44995
+ return value === 1 ? label : `${label}s`;
44996
+ }
44997
+
44567
44998
  // src/rollback.ts
44568
44999
  import { randomUUID as randomUUID12 } from "node:crypto";
44569
- import { basename as basename3, join as join14, resolve as resolve8 } from "node:path";
45000
+ import { basename as basename3, join as join15, resolve as resolve10 } from "node:path";
44570
45001
  var projectId2 = "project";
44571
45002
  var RollbackServiceError = class extends Error {
44572
45003
  code;
@@ -45166,10 +45597,10 @@ async function rollbackPreparedSwaps({
45166
45597
  }
45167
45598
  }
45168
45599
  function rollbackSwaps(options) {
45169
- const repoDir = resolve8(options.repo);
45600
+ const repoDir = resolve10(options.repo);
45170
45601
  return rollbackPreparedSwaps({
45171
45602
  store: new FsStore(
45172
- resolve8(options.store ?? join14(repoDir, ".rightmodeler"))
45603
+ resolve10(options.store ?? join15(repoDir, ".rightmodeler"))
45173
45604
  ),
45174
45605
  githubClient: createGithubClient({
45175
45606
  baseUrl: options.githubBaseUrl,
@@ -45182,10 +45613,17 @@ function rollbackSwaps(options) {
45182
45613
  }
45183
45614
 
45184
45615
  // src/version.ts
45185
- var version2 = "0.1.2";
45616
+ var version2 = "0.2.0";
45186
45617
 
45187
45618
  // src/cli.ts
45188
- function createProgram(io = processIo) {
45619
+ var processRuntime = {
45620
+ stdin: process.stdin,
45621
+ stdout: process.stdout,
45622
+ env: process.env,
45623
+ homeDir: homedir2(),
45624
+ now: () => /* @__PURE__ */ new Date()
45625
+ };
45626
+ function createProgram(io = processIo, runtime = processRuntime) {
45189
45627
  let code = 0;
45190
45628
  const program2 = new Command().name("rightmodeler").description("Find and prove safe model substitutions.").addHelpText(
45191
45629
  "after",
@@ -45213,13 +45651,23 @@ function createProgram(io = processIo) {
45213
45651
  );
45214
45652
  run(init, async (reporter, global) => {
45215
45653
  const local = init.opts();
45216
- const options = pipelineOptions(global, local, reporter);
45217
- const result2 = local.plan ? {
45218
- stages: await planPipeline(options),
45219
- executedStages: [],
45220
- verdicts: [],
45221
- recommendationExists: false
45222
- } : await runPipeline(options);
45654
+ const prepared = await guidedPipelineOptions(
45655
+ global,
45656
+ local,
45657
+ reporter,
45658
+ runtime
45659
+ );
45660
+ const result2 = await withInputGuidance(
45661
+ prepared,
45662
+ local,
45663
+ runtime,
45664
+ async (options) => local.plan ? {
45665
+ stages: await planPipeline(options),
45666
+ executedStages: [],
45667
+ verdicts: [],
45668
+ recommendationExists: false
45669
+ } : runPipeline(options)
45670
+ );
45223
45671
  reporter.result(result2);
45224
45672
  return local.plan || local.through !== void 0 && local.through !== "report" ? 0 : result2.recommendationExists ? 1 : 0;
45225
45673
  });
@@ -45231,13 +45679,23 @@ function createProgram(io = processIo) {
45231
45679
  "scope projection to one merged approved swap"
45232
45680
  );
45233
45681
  run(estimate, async (reporter, global) => {
45234
- const options = pipelineOptions(
45682
+ const local = estimate.opts();
45683
+ const prepared = await guidedPipelineOptions(
45235
45684
  global,
45236
- estimate.opts(),
45237
- reporter
45685
+ local,
45686
+ reporter,
45687
+ runtime
45688
+ );
45689
+ const result2 = await withInputGuidance(
45690
+ prepared,
45691
+ local,
45692
+ runtime,
45693
+ async (options) => {
45694
+ await runPipeline({ ...options, through: "shortlist" });
45695
+ return estimateReplay(options);
45696
+ }
45238
45697
  );
45239
- await runPipeline({ ...options, through: "shortlist" });
45240
- reporter.result(await estimateReplay(options));
45698
+ reporter.result(result2);
45241
45699
  return 0;
45242
45700
  });
45243
45701
  for (const stage of PIPELINE_STAGES.slice(0, -1)) {
@@ -45539,7 +45997,13 @@ function addPipelineOptions(command, provider) {
45539
45997
  new Option("--through <stage>", "stop after this stage").choices([
45540
45998
  ...PIPELINE_STAGES
45541
45999
  ])
45542
- ).option("--yes", "accept defaults (reserved for future prompts)");
46000
+ );
46001
+ }
46002
+ if (command.name() === "init" || command.name() === "estimate") {
46003
+ command.option(
46004
+ "--yes",
46005
+ "accept the newest discovered trace without prompting"
46006
+ );
45543
46007
  }
45544
46008
  return command;
45545
46009
  }
@@ -45582,6 +46046,97 @@ function pipelineOptions(global, local, reporter) {
45582
46046
  reporter
45583
46047
  };
45584
46048
  }
46049
+ async function guidedPipelineOptions(global, local, reporter, runtime) {
46050
+ const options = pipelineOptions(global, local, reporter);
46051
+ const interactive = global.output === "human" && runtime.stdin.isTTY === true && runtime.stdout.isTTY === true;
46052
+ if (local.traces !== void 0 || local.plan || local.through === "scan") {
46053
+ return { options, candidates: [], interactive };
46054
+ }
46055
+ const candidates = await discoverTraces({
46056
+ repo: global.repo,
46057
+ homeDir: runtime.homeDir
46058
+ });
46059
+ const traces = local.yes ? candidates[0]?.path : interactive ? await promptForTracePath({
46060
+ candidates,
46061
+ repo: resolve11(global.repo),
46062
+ homeDir: runtime.homeDir,
46063
+ now: runtime.now(),
46064
+ input: runtime.stdin,
46065
+ output: promptOutput(reporter.io, runtime.stdout.isTTY)
46066
+ }) : void 0;
46067
+ if (local.yes && traces !== void 0 && global.output === "human") {
46068
+ reporter.io.stdout(`Using trace file: ${traces}
46069
+ `);
46070
+ }
46071
+ return {
46072
+ options: traces === void 0 ? options : { ...options, traces },
46073
+ candidates,
46074
+ interactive,
46075
+ ...traces === void 0 ? {} : { selectedDiscoveredTrace: traces }
46076
+ };
46077
+ }
46078
+ async function withInputGuidance(prepared, local, runtime, operation) {
46079
+ try {
46080
+ return await operation(prepared.options);
46081
+ } catch (error51) {
46082
+ if (error51 instanceof ProtocolError && error51.code === "missing_traces_path" && prepared.candidates.length > 0) {
46083
+ throw new ProtocolError({
46084
+ exitCode: error51.exitCode,
46085
+ code: error51.code,
46086
+ message: error51.message,
46087
+ remedy: `${error51.remedy} ${candidateRemedy(prepared.candidates)}`
46088
+ });
46089
+ }
46090
+ if (prepared.selectedDiscoveredTrace !== void 0 && error51 instanceof TraceAdaptError) {
46091
+ throw new ProtocolError({
46092
+ exitCode: 2,
46093
+ code: "unusable_trace_input",
46094
+ message: error51.message,
46095
+ remedy: "Rerun the command and choose a different trace file."
46096
+ });
46097
+ }
46098
+ if (!(error51 instanceof ProtocolError) || error51.code !== "missing_provider_configuration" || !prepared.interactive) {
46099
+ throw error51;
46100
+ }
46101
+ const baseUrl = await promptForProviderBaseUrl({
46102
+ current: local.baseUrl,
46103
+ input: runtime.stdin,
46104
+ output: promptOutput(prepared.options.reporter.io, runtime.stdout.isTTY)
46105
+ });
46106
+ if (baseUrl === void 0) throw error51;
46107
+ const apiKeyEnv = local.apiKeyEnv ?? "RIGHTMODELER_API_KEY";
46108
+ if (!runtime.env[apiKeyEnv]) {
46109
+ throw new ProtocolError({
46110
+ exitCode: 2,
46111
+ code: "missing_provider_configuration",
46112
+ message: `Provider API key environment variable is not set: ${apiKeyEnv}.`,
46113
+ remedy: `Set the environment variable ${apiKeyEnv} to your provider API key, then rerun.`
46114
+ });
46115
+ }
46116
+ return operation({
46117
+ ...prepared.options,
46118
+ baseUrl,
46119
+ apiKeyEnv
46120
+ });
46121
+ }
46122
+ }
46123
+ function promptOutput(io, isTTY) {
46124
+ return Object.assign(
46125
+ new Writable({
46126
+ write(chunk, _encoding, callback) {
46127
+ io.stdout(String(chunk));
46128
+ callback();
46129
+ }
46130
+ }),
46131
+ { isTTY }
46132
+ );
46133
+ }
46134
+ function candidateRemedy(candidates) {
46135
+ const shown = candidates.slice(0, 3).map(({ path }) => path);
46136
+ const more = candidates.length - shown.length;
46137
+ const paths = more === 0 ? shown.join(", ") : `${shown.join(", ")}, and ${more} more`;
46138
+ return `Found ${candidates.length} candidate ${candidates.length === 1 ? "trace file" : "trace files"}: ${paths}. Pass --traces <path>.`;
46139
+ }
45585
46140
  function evaluatorConfig(local, gateThreshold) {
45586
46141
  const provider = local.evaluator;
45587
46142
  const scoring = {
@@ -45735,23 +46290,23 @@ async function startDetachedReplay(global, local, runId) {
45735
46290
  const args = [
45736
46291
  fileURLToPath2(import.meta.url),
45737
46292
  "--repo",
45738
- resolve9(global.repo),
46293
+ resolve11(global.repo),
45739
46294
  "--output",
45740
46295
  "json"
45741
46296
  ];
45742
46297
  if (global.store !== void 0) {
45743
- args.push("--store", resolve9(global.store));
46298
+ args.push("--store", resolve11(global.store));
45744
46299
  }
45745
46300
  args.push("replay");
45746
46301
  appendCliOption(
45747
46302
  args,
45748
46303
  "--traces",
45749
- local.traces === void 0 ? void 0 : resolve9(local.traces)
46304
+ local.traces === void 0 ? void 0 : resolve11(local.traces)
45750
46305
  );
45751
46306
  appendCliOption(
45752
46307
  args,
45753
46308
  "--modeb-config",
45754
- local.modebConfig === void 0 ? void 0 : resolve9(local.modebConfig)
46309
+ local.modebConfig === void 0 ? void 0 : resolve11(local.modebConfig)
45755
46310
  );
45756
46311
  appendCliOption(args, "--base-url", local.baseUrl);
45757
46312
  appendCliOption(args, "--api-key-env", local.apiKeyEnv);
@@ -45775,7 +46330,7 @@ async function startDetachedReplay(global, local, runId) {
45775
46330
  appendCliOption(
45776
46331
  args,
45777
46332
  "--evaluator-config",
45778
- local.evaluatorConfig === void 0 ? void 0 : resolve9(local.evaluatorConfig)
46333
+ local.evaluatorConfig === void 0 ? void 0 : resolve11(local.evaluatorConfig)
45779
46334
  );
45780
46335
  for (const scorer of local.evaluatorScorer ?? []) {
45781
46336
  appendCliOption(args, "--evaluator-scorer", scorer);
@@ -45789,7 +46344,7 @@ async function startDetachedReplay(global, local, runId) {
45789
46344
  appendCliOption(args, "--internal-run-id", runId);
45790
46345
  await new Promise((resolveSpawn, rejectSpawn) => {
45791
46346
  const child = spawn(process.execPath, args, {
45792
- cwd: resolve9(global.repo),
46347
+ cwd: resolve11(global.repo),
45793
46348
  detached: true,
45794
46349
  env: process.env,
45795
46350
  stdio: "ignore"
@@ -45803,13 +46358,13 @@ async function startDetachedReplay(global, local, runId) {
45803
46358
  }
45804
46359
  function detachedCommand(value) {
45805
46360
  if (value === void 0) return void 0;
45806
- return value.startsWith("./") || value.startsWith("../") || value.includes("/") || value.includes("\\") ? resolve9(value) : value;
46361
+ return value.startsWith("./") || value.startsWith("../") || value.includes("/") || value.includes("\\") ? resolve11(value) : value;
45807
46362
  }
45808
46363
  function appendCliOption(args, flag, value) {
45809
46364
  if (value !== void 0) args.push(flag, value);
45810
46365
  }
45811
- async function executeCli(argv, io = processIo) {
45812
- const handle = createProgram(io);
46366
+ async function executeCli(argv, io = processIo, runtime = processRuntime) {
46367
+ const handle = createProgram(io, runtime);
45813
46368
  try {
45814
46369
  await handle.program.parseAsync([...argv], { from: "user" });
45815
46370
  return handle.exitCode();
package/docs/commands.md CHANGED
@@ -84,8 +84,8 @@ Options:
84
84
  "ingest", "reconcile", "scrub", "corpus",
85
85
  "audit-sample", "shortlist", "replay",
86
86
  "aggregate", "confirm", "report")
87
- --yes accept defaults (reserved for future
88
- prompts)
87
+ --yes accept the newest discovered trace without
88
+ prompting
89
89
  -h, --help display help for command
90
90
  ```
91
91
 
@@ -125,6 +125,8 @@ Options:
125
125
  --evaluator-gate-metric <name> scorer metric used for release gates
126
126
  --evaluator-gate-threshold <value> fallback pass threshold when the evaluator
127
127
  omits a pass decision
128
+ --yes accept the newest discovered trace without
129
+ prompting
128
130
  --approved-run <digest> scope projection to one merged approved
129
131
  swap
130
132
  -h, --help display help for command
@@ -6,7 +6,7 @@ Rightmodeler reserves exit codes `0` through `3` for machine-readable outcomes.
6
6
 
7
7
  - `0`: the command completed and no recommendation is being reported. Planning and partial `--through` runs also return `0` when successful.
8
8
  - `1`: a complete `init` or `report` found an actionable recommendation.
9
- - `2`: the run needs input at a resumable boundary, such as missing traces, provider configuration, or required confirmation configuration.
9
+ - `2`: the run needs input at a resumable boundary, such as missing traces, a cancelled trace prompt, provider configuration, or required confirmation configuration.
10
10
  - `3`: the cost budget was reached at a resumable boundary.
11
11
  - `10` or greater: command-line or runtime failure.
12
12
 
@@ -9,6 +9,25 @@ Rightmodeler analyzes recorded model calls, replays them against cheaper candida
9
9
  - Trace input in a supported format.
10
10
  - An OpenAI-compatible provider base URL and the name of an environment variable containing its API key before replay begins.
11
11
 
12
+ Supported trace sources are OTel GenAI, OpenAI JSONL, Langfuse, Braintrust,
13
+ LangSmith, OpenInference, Helicone, W&B Weave, Claude Code, and Codex.
14
+
15
+ ## Start with automatic discovery
16
+
17
+ Run this from the repository you want to analyze:
18
+
19
+ ```sh
20
+ npx rightmodeler init
21
+ ```
22
+
23
+ Rightmodeler checks conventional local trace files, Claude Code transcripts for
24
+ the repository, and Codex sessions whose recorded working directory matches the
25
+ repository. In an interactive terminal it lists matches newest-first with an
26
+ approximate model-call count. If nothing is found, it explains how to produce or
27
+ export a trace and asks for a path. Leaving the answer empty, pressing Ctrl-C or
28
+ Ctrl-D, or closing standard input stops cleanly with exit code `2` and a remedy
29
+ for rerunning.
30
+
12
31
  ## Preview without changing the repository
13
32
 
14
33
  ```sh
@@ -28,6 +47,19 @@ export RIGHTMODELER_API_KEY="provider-key"
28
47
  npx rightmodeler init --traces /path/to/traces.json --base-url https://provider.example/v1 --output json --repo /path/to/repository
29
48
  ```
30
49
 
50
+ `RIGHTMODELER_API_KEY` is the default key variable. Pass
51
+ `--api-key-env <name>` to use a different exported variable. The CLI does not ask
52
+ for a secret value.
53
+
54
+ ## Estimate replay spend
55
+
56
+ ```sh
57
+ npx rightmodeler estimate --traces /path/to/traces.json --base-url https://provider.example/v1 --output json --repo /path/to/repository
58
+ ```
59
+
60
+ Estimate projects candidate replay spend from recorded token usage and the current
61
+ model catalog before paid model calls begin.
62
+
31
63
  The default store is `.rightmodeler/` inside the analyzed repository. Completed stages resume when their inputs and outputs are still current. A complete run writes `.rightmodeler/project/reports/report.md` and `.rightmodeler/project/reports/report.json`.
32
64
 
33
65
  Read the generated [command reference](commands.md), the [evaluator guide](evaluators.md), [Mode B configuration](modeb.md), and the [exit-code convention](exit-codes.md) before automating a full run.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rightmodeler",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "rightmodeler": "./dist-bundle/cli.js"