reflex-skills 0.5.0 → 0.5.2

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -4
  3. package/dist/reflex.js +1404 -576
  4. package/package.json +2 -1
package/dist/reflex.js CHANGED
@@ -590,8 +590,8 @@ var require_help = __commonJS({
590
590
  helper.visibleCommands(cmd),
591
591
  (sub) => sub.helpGroup() || "Commands:"
592
592
  );
593
- commandGroups.forEach((commands, group) => {
594
- const commandList = commands.map((sub) => {
593
+ commandGroups.forEach((commands2, group) => {
594
+ const commandList = commands2.map((sub) => {
595
595
  return callFormatItem(
596
596
  helper.styleSubcommandTerm(helper.subcommandTerm(sub)),
597
597
  helper.styleSubcommandDescription(helper.subcommandDescription(sub))
@@ -742,8 +742,8 @@ ${itemIndentStr}`);
742
742
  const rawLines = str3.split(/\r\n|\n/);
743
743
  const chunkPattern = /[\s]*[^\s]+/g;
744
744
  const wrappedLines = [];
745
- rawLines.forEach((line) => {
746
- const chunks = line.match(chunkPattern);
745
+ rawLines.forEach((line2) => {
746
+ const chunks = line2.match(chunkPattern);
747
747
  if (chunks === null) {
748
748
  wrappedLines.push("");
749
749
  return;
@@ -3461,12 +3461,12 @@ var require_src = __commonJS({
3461
3461
  else if (y3 > 0) ret += `${CSI}${y3}B`;
3462
3462
  return ret;
3463
3463
  },
3464
- up: (count2 = 1) => `${CSI}${count2}A`,
3465
- down: (count2 = 1) => `${CSI}${count2}B`,
3466
- forward: (count2 = 1) => `${CSI}${count2}C`,
3467
- backward: (count2 = 1) => `${CSI}${count2}D`,
3468
- nextLine: (count2 = 1) => `${CSI}E`.repeat(count2),
3469
- prevLine: (count2 = 1) => `${CSI}F`.repeat(count2),
3464
+ up: (count3 = 1) => `${CSI}${count3}A`,
3465
+ down: (count3 = 1) => `${CSI}${count3}B`,
3466
+ forward: (count3 = 1) => `${CSI}${count3}C`,
3467
+ backward: (count3 = 1) => `${CSI}${count3}D`,
3468
+ nextLine: (count3 = 1) => `${CSI}E`.repeat(count3),
3469
+ prevLine: (count3 = 1) => `${CSI}F`.repeat(count3),
3470
3470
  left: `${CSI}G`,
3471
3471
  hide: `${CSI}?25l`,
3472
3472
  show: `${CSI}?25h`,
@@ -3474,21 +3474,21 @@ var require_src = __commonJS({
3474
3474
  restore: `${ESC}8`
3475
3475
  };
3476
3476
  var scroll = {
3477
- up: (count2 = 1) => `${CSI}S`.repeat(count2),
3478
- down: (count2 = 1) => `${CSI}T`.repeat(count2)
3477
+ up: (count3 = 1) => `${CSI}S`.repeat(count3),
3478
+ down: (count3 = 1) => `${CSI}T`.repeat(count3)
3479
3479
  };
3480
3480
  var erase = {
3481
3481
  screen: `${CSI}2J`,
3482
- up: (count2 = 1) => `${CSI}1J`.repeat(count2),
3483
- down: (count2 = 1) => `${CSI}J`.repeat(count2),
3482
+ up: (count3 = 1) => `${CSI}1J`.repeat(count3),
3483
+ down: (count3 = 1) => `${CSI}J`.repeat(count3),
3484
3484
  line: `${CSI}2K`,
3485
3485
  lineEnd: `${CSI}K`,
3486
3486
  lineStart: `${CSI}1K`,
3487
- lines(count2) {
3487
+ lines(count3) {
3488
3488
  let clear = "";
3489
- for (let i = 0; i < count2; i++)
3490
- clear += this.line + (i < count2 - 1 ? cursor.up() : "");
3491
- if (count2)
3489
+ for (let i = 0; i < count3; i++)
3490
+ clear += this.line + (i < count3 - 1 ? cursor.up() : "");
3491
+ if (count3)
3492
3492
  clear += cursor.left;
3493
3493
  return clear;
3494
3494
  }
@@ -3571,12 +3571,103 @@ var require_picocolors = __commonJS({
3571
3571
  });
3572
3572
 
3573
3573
  // src/guard.ts
3574
+ import dgram from "node:dgram";
3575
+ import dns from "node:dns";
3576
+ import { syncBuiltinESMExports } from "node:module";
3574
3577
  import net from "node:net";
3578
+ import threads from "node:worker_threads";
3579
+ var MESSAGE = "Reflex does not make network connections";
3580
+ var MODEL_HOSTS = ["huggingface.co", "hf.co"];
3581
+ var DNS_QUERIES = /^(lookup|lookupService|resolve\w*|reverse)$/;
3582
+ var WORKER_GUARD = `{
3583
+ const blocked = () => { throw new Error(${JSON.stringify(`${MESSAGE}.`)}); };
3584
+ const get = process.getBuiltinModule;
3585
+ get("node:net").Socket.prototype.connect = blocked;
3586
+ const udp = get("node:dgram").Socket.prototype;
3587
+ udp.send = udp.connect = blocked;
3588
+ const dns = get("node:dns");
3589
+ for (const target of [dns, dns.promises, dns.Resolver.prototype, dns.promises.Resolver.prototype])
3590
+ for (const key of Object.getOwnPropertyNames(target))
3591
+ if (${DNS_QUERIES}.test(key) && typeof target[key] === "function") target[key] = blocked;
3592
+ }`;
3593
+ var allowed = [];
3594
+ function hostAllowed(host) {
3595
+ if (typeof host !== "string") return false;
3596
+ const h2 = host.toLowerCase().replace(/\.$/, "");
3597
+ return allowed.some((a) => h2 === a || h2.endsWith(`.${a}`));
3598
+ }
3599
+ function connectHost(args) {
3600
+ const first = Array.isArray(args[0]) ? args[0][0] : args[0];
3601
+ if (typeof first === "object" && first !== null) {
3602
+ const o2 = first;
3603
+ return o2.path === void 0 ? o2.host ?? "localhost" : void 0;
3604
+ }
3605
+ if (typeof first === "number" || /^\d+$/.test(String(first))) return typeof args[1] === "string" ? args[1] : "localhost";
3606
+ return void 0;
3607
+ }
3608
+ var refuse = (host) => {
3609
+ throw new Error(typeof host === "string" ? `${MESSAGE} (blocked ${host}).` : `${MESSAGE}.`);
3610
+ };
3575
3611
  function installNetworkGuard() {
3576
- const blocked = function connect() {
3577
- throw new Error("Reflex does not make network connections.");
3612
+ const undo = [];
3613
+ const patch = (target, key3, make) => {
3614
+ const t = target;
3615
+ const original = t[key3];
3616
+ t[key3] = make(original);
3617
+ undo.push(() => t[key3] = original);
3618
+ };
3619
+ patch(
3620
+ net.Socket.prototype,
3621
+ "connect",
3622
+ (original) => function connect(...args) {
3623
+ const host = connectHost(args);
3624
+ return hostAllowed(host) ? original.apply(this, args) : refuse(host);
3625
+ }
3626
+ );
3627
+ for (const key3 of ["send", "connect"]) patch(dgram.Socket.prototype, key3, () => () => refuse(void 0));
3628
+ for (const target of [dns, dns.promises, dns.Resolver.prototype, dns.promises.Resolver.prototype]) {
3629
+ for (const key3 of Object.getOwnPropertyNames(target)) {
3630
+ if (!DNS_QUERIES.test(key3) || typeof target[key3] !== "function") continue;
3631
+ patch(
3632
+ target,
3633
+ key3,
3634
+ (original) => key3 === "lookup" ? function lookup(...args) {
3635
+ return hostAllowed(args[0]) ? original.apply(this, args) : refuse(args[0]);
3636
+ } : () => refuse(void 0)
3637
+ );
3638
+ }
3639
+ }
3640
+ const Base = threads.Worker;
3641
+ class GuardedWorker extends Base {
3642
+ constructor(filename, options = {}) {
3643
+ const inline = options.eval === true && typeof filename === "string";
3644
+ const guard = ["--import", `data:text/javascript,${encodeURIComponent(WORKER_GUARD)}`];
3645
+ super(inline ? `${WORKER_GUARD}
3646
+ ${filename}` : filename, inline ? options : { ...options, execArgv: [...options.execArgv ?? process.execArgv, ...guard] });
3647
+ }
3648
+ }
3649
+ patch(threads, "Worker", () => GuardedWorker);
3650
+ syncBuiltinESMExports();
3651
+ return () => {
3652
+ for (const fn of undo.reverse()) fn();
3653
+ syncBuiltinESMExports();
3578
3654
  };
3579
- net.Socket.prototype.connect = blocked;
3655
+ }
3656
+ function allowHosts(hosts) {
3657
+ const before = allowed;
3658
+ allowed = [...before, ...hosts, ...proxyHosts()];
3659
+ return () => {
3660
+ allowed = before;
3661
+ };
3662
+ }
3663
+ function proxyHosts() {
3664
+ if (!process.env.NODE_USE_ENV_PROXY) return [];
3665
+ const url2 = process.env.HTTPS_PROXY ?? process.env.https_proxy;
3666
+ try {
3667
+ return url2 ? [new URL(url2).hostname.toLowerCase()] : [];
3668
+ } catch {
3669
+ return [];
3670
+ }
3580
3671
  }
3581
3672
  function quietSqliteWarning() {
3582
3673
  const listeners = process.listeners("warning");
@@ -4286,8 +4377,8 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
4286
4377
  var import_picocolors3 = __toESM(require_picocolors(), 1);
4287
4378
  var c = import_picocolors3.default;
4288
4379
  var interactive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
4289
- function out(line = "") {
4290
- process.stdout.write(line + "\n");
4380
+ function out(line2 = "") {
4381
+ process.stdout.write(line2 + "\n");
4291
4382
  }
4292
4383
  function title(text) {
4293
4384
  out();
@@ -4359,7 +4450,7 @@ async function ask(message, initial, validate3) {
4359
4450
  }
4360
4451
  function fileBlock(path, content) {
4361
4452
  out(c.dim(`\u250C\u2500 ${path}`));
4362
- for (const line of content.trimEnd().split("\n")) out(`${c.dim("\u2502")} ${line}`);
4453
+ for (const line2 of content.trimEnd().split("\n")) out(`${c.dim("\u2502")} ${line2}`);
4363
4454
  out(c.dim("\u2514\u2500"));
4364
4455
  }
4365
4456
  function spinner() {
@@ -5151,9 +5242,9 @@ function assertNever(_x) {
5151
5242
  }
5152
5243
  function assert(_3) {
5153
5244
  }
5154
- function getEnumValues(entries) {
5155
- const numericValues = Object.values(entries).filter((v2) => typeof v2 === "number");
5156
- const values = Object.entries(entries).filter(([k3, _3]) => numericValues.indexOf(+k3) === -1).map(([_3, v2]) => v2);
5245
+ function getEnumValues(entries2) {
5246
+ const numericValues = Object.values(entries2).filter((v2) => typeof v2 === "number");
5247
+ const values = Object.entries(entries2).filter(([k3, _3]) => numericValues.indexOf(+k3) === -1).map(([_3, v2]) => v2);
5157
5248
  return values;
5158
5249
  }
5159
5250
  function joinValues(array2, separator = "|") {
@@ -5690,14 +5781,14 @@ function codePointLength(str3) {
5690
5781
  const units = str3.length;
5691
5782
  if (!highSurrogate.test(str3))
5692
5783
  return units;
5693
- let count2 = units;
5784
+ let count3 = units;
5694
5785
  for (let i = 0; i < units - 1; i++) {
5695
5786
  if ((str3.charCodeAt(i) & 64512) === 55296 && (str3.charCodeAt(i + 1) & 64512) === 56320) {
5696
- count2--;
5787
+ count3--;
5697
5788
  i++;
5698
5789
  }
5699
5790
  }
5700
- return count2;
5791
+ return count3;
5701
5792
  }
5702
5793
  function getLengthableOrigin(input2) {
5703
5794
  if (Array.isArray(input2))
@@ -6976,16 +7067,16 @@ var $ZodCheckProperties = /* @__PURE__ */ $constructor("$ZodCheckProperties", (i
6976
7067
  hide(inst, Symbol.iterator, function* () {
6977
7068
  yield inst;
6978
7069
  });
6979
- let entries;
7070
+ let entries2;
6980
7071
  inst._zod.check = (payload) => {
6981
7072
  if (payload.value == null) {
6982
7073
  payload.issues.push({ expected: "object", code: "invalid_type", input: payload.value, inst });
6983
7074
  return void 0;
6984
7075
  }
6985
- entries ?? (entries = Reflect.ownKeys(def.shape).map((key3) => [key3, def.shape[key3]]));
7076
+ entries2 ?? (entries2 = Reflect.ownKeys(def.shape).map((key3) => [key3, def.shape[key3]]));
6986
7077
  const input2 = payload.value;
6987
7078
  let proms;
6988
- for (const [key3, schema] of entries) {
7079
+ for (const [key3, schema] of entries2) {
6989
7080
  const result = schema._zod.run({ value: input2[key3], issues: [] }, {});
6990
7081
  if (result instanceof Promise) {
6991
7082
  proms ?? (proms = []);
@@ -7048,8 +7139,8 @@ var Doc = class {
7048
7139
  const lines = content.split("\n").filter((x2) => x2);
7049
7140
  const minIndent = Math.min(...lines.map((x2) => x2.length - x2.trimStart().length));
7050
7141
  const dedented = lines.map((x2) => x2.slice(minIndent)).map((x2) => " ".repeat(this.indent * 2) + x2);
7051
- for (const line of dedented) {
7052
- this.content.push(line);
7142
+ for (const line2 of dedented) {
7143
+ this.content.push(line2);
7053
7144
  }
7054
7145
  }
7055
7146
  compile() {
@@ -10052,8 +10143,8 @@ function az_default() {
10052
10143
  }
10053
10144
 
10054
10145
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/be.js
10055
- function getBelarusianPlural(count2, one, few, many) {
10056
- const absCount = Math.abs(count2);
10146
+ function getBelarusianPlural(count3, one, few, many) {
10147
+ const absCount = Math.abs(count3);
10057
10148
  const lastDigit = absCount % 10;
10058
10149
  const lastTwoDigits = absCount % 100;
10059
10150
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -12700,8 +12791,8 @@ function hu_default() {
12700
12791
  }
12701
12792
 
12702
12793
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/hy.js
12703
- function getArmenianPlural(count2, one, many) {
12704
- return Math.abs(count2) === 1 ? one : many;
12794
+ function getArmenianPlural(count3, one, many) {
12795
+ return Math.abs(count3) === 1 ? one : many;
12705
12796
  }
12706
12797
  function withDefiniteArticle(word) {
12707
12798
  if (!word)
@@ -15439,8 +15530,8 @@ function ro_default() {
15439
15530
  }
15440
15531
 
15441
15532
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/locales/ru.js
15442
- function getRussianPlural(count2, one, few, many) {
15443
- const absCount = Math.abs(count2);
15533
+ function getRussianPlural(count3, one, few, many) {
15534
+ const absCount = Math.abs(count3);
15444
15535
  const lastDigit = absCount % 10;
15445
15536
  const lastTwoDigits = absCount % 100;
15446
15537
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -17337,10 +17428,10 @@ var $ZodRegistry = class {
17337
17428
  this._idmap = /* @__PURE__ */ new Map();
17338
17429
  }
17339
17430
  add(schema, ..._meta) {
17340
- const meta3 = _meta[0];
17341
- this._map.set(schema, meta3);
17342
- if (meta3 && typeof meta3 === "object" && "id" in meta3) {
17343
- this._idmap.set(meta3.id, schema);
17431
+ const meta4 = _meta[0];
17432
+ this._map.set(schema, meta4);
17433
+ if (meta4 && typeof meta4 === "object" && "id" in meta4) {
17434
+ this._idmap.set(meta4.id, schema);
17344
17435
  }
17345
17436
  return this;
17346
17437
  }
@@ -17350,9 +17441,9 @@ var $ZodRegistry = class {
17350
17441
  return this;
17351
17442
  }
17352
17443
  remove(schema) {
17353
- const meta3 = this._map.get(schema);
17354
- if (meta3 && typeof meta3 === "object" && "id" in meta3) {
17355
- this._idmap.delete(meta3.id);
17444
+ const meta4 = this._map.get(schema);
17445
+ if (meta4 && typeof meta4 === "object" && "id" in meta4) {
17446
+ this._idmap.delete(meta4.id);
17356
17447
  }
17357
17448
  this._map.delete(schema);
17358
17449
  return this;
@@ -19767,18 +19858,18 @@ function _set(Class2, valueType, params) {
19767
19858
  }
19768
19859
  // @__NO_SIDE_EFFECTS__
19769
19860
  function _enum(Class2, values, params) {
19770
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
19861
+ const entries2 = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
19771
19862
  return new Class2({
19772
19863
  type: "enum",
19773
- entries,
19864
+ entries: entries2,
19774
19865
  ...normalizeParams(params)
19775
19866
  });
19776
19867
  }
19777
19868
  // @__NO_SIDE_EFFECTS__
19778
- function _nativeEnum(Class2, entries, params) {
19869
+ function _nativeEnum(Class2, entries2, params) {
19779
19870
  return new Class2({
19780
19871
  type: "enum",
19781
- entries,
19872
+ entries: entries2,
19782
19873
  ...normalizeParams(params)
19783
19874
  });
19784
19875
  }
@@ -20074,13 +20165,13 @@ function initializeContext(params) {
20074
20165
  external: params?.external ?? void 0
20075
20166
  };
20076
20167
  }
20077
- function handleUnrepresentable(schema, ctx, json2, params, message) {
20168
+ function handleUnrepresentable(schema, ctx, json3, params, message) {
20078
20169
  const result = typeof ctx.unrepresentable === "function" ? ctx.unrepresentable({ zodSchema: schema, path: params.path, message }) : ctx.unrepresentable;
20079
20170
  if (result === "any")
20080
20171
  return false;
20081
20172
  if (result === void 0 || result === "throw")
20082
20173
  throw new Error(message);
20083
- Object.assign(json2, result);
20174
+ Object.assign(json3, result);
20084
20175
  return true;
20085
20176
  }
20086
20177
  function processSchema(schema, ctx, _params = { path: [], schemaPath: [] }) {
@@ -20126,9 +20217,9 @@ function processSchema(schema, ctx, _params = { path: [], schemaPath: [] }) {
20126
20217
  ctx.seen.get(parent).isParent = true;
20127
20218
  }
20128
20219
  }
20129
- const meta3 = ctx.metadataRegistry.get(schema);
20130
- if (meta3)
20131
- assignProps(result.schema, meta3);
20220
+ const meta4 = ctx.metadataRegistry.get(schema);
20221
+ if (meta4)
20222
+ assignProps(result.schema, meta4);
20132
20223
  if (ctx.io === "input" && isTransforming(schema)) {
20133
20224
  delete result.schema.examples;
20134
20225
  delete result.schema.default;
@@ -20316,12 +20407,12 @@ function foldObjects(members2) {
20316
20407
  }
20317
20408
  return folded;
20318
20409
  }
20319
- function foldIntersection(json2) {
20320
- const allOf = json2.allOf;
20410
+ function foldIntersection(json3) {
20411
+ const allOf = json3.allOf;
20321
20412
  if (!Array.isArray(allOf) || allOf.length < 2)
20322
20413
  return;
20323
20414
  for (const key3 of FOLDABLE_KEYS)
20324
- if (key3 in json2)
20415
+ if (key3 in json3)
20325
20416
  return;
20326
20417
  const unions = allOf.filter((m2) => UNION_KEYS.some((k3) => Array.isArray(m2[k3])));
20327
20418
  let folded = null;
@@ -20340,8 +20431,8 @@ function foldIntersection(json2) {
20340
20431
  }
20341
20432
  if (!folded)
20342
20433
  return;
20343
- delete json2.allOf;
20344
- assignProps(json2, folded);
20434
+ delete json3.allOf;
20435
+ assignProps(json3, folded);
20345
20436
  }
20346
20437
  function finalize(ctx, schema) {
20347
20438
  const root = ctx.seen.get(schema);
@@ -20423,20 +20514,20 @@ function finalize(ctx, schema) {
20423
20514
  if (ctx.intersections.length) {
20424
20515
  const carriers = /* @__PURE__ */ new Map();
20425
20516
  for (const seen of ctx.seen.values()) {
20426
- for (const json2 of [seen.schema, seen.def]) {
20427
- const allOf = json2?.allOf;
20517
+ for (const json3 of [seen.schema, seen.def]) {
20518
+ const allOf = json3?.allOf;
20428
20519
  if (!Array.isArray(allOf))
20429
20520
  continue;
20430
20521
  const existing = carriers.get(allOf);
20431
20522
  if (existing)
20432
- existing.push(json2);
20523
+ existing.push(json3);
20433
20524
  else
20434
- carriers.set(allOf, [json2]);
20525
+ carriers.set(allOf, [json3]);
20435
20526
  }
20436
20527
  }
20437
20528
  for (const allOf of ctx.intersections) {
20438
- for (const json2 of carriers.get(allOf) ?? [])
20439
- foldIntersection(json2);
20529
+ for (const json3 of carriers.get(allOf) ?? [])
20530
+ foldIntersection(json3);
20440
20531
  }
20441
20532
  }
20442
20533
  }
@@ -20671,29 +20762,29 @@ var exactPatterns = /* @__PURE__ */ new Map([
20671
20762
  ]);
20672
20763
  var exactPattern = (p3) => exactPatterns.get(p3) ?? p3;
20673
20764
  var stringProcessor = (schema, ctx, _json, _params) => {
20674
- const json2 = _json;
20675
- json2.type = "string";
20765
+ const json3 = _json;
20766
+ json3.type = "string";
20676
20767
  const { minimum, maximum, format, patterns, contentEncoding, laxFormat } = aggregateChecks(schema);
20677
20768
  if (typeof minimum === "number")
20678
- json2.minLength = minimum;
20769
+ json3.minLength = minimum;
20679
20770
  if (typeof maximum === "number")
20680
- json2.maxLength = maximum;
20771
+ json3.maxLength = maximum;
20681
20772
  if (format) {
20682
- json2.format = formatMap[format] ?? format;
20683
- if (json2.format === "")
20684
- delete json2.format;
20773
+ json3.format = formatMap[format] ?? format;
20774
+ if (json3.format === "")
20775
+ delete json3.format;
20685
20776
  if (format === "time" || laxFormat) {
20686
- delete json2.format;
20777
+ delete json3.format;
20687
20778
  }
20688
20779
  }
20689
20780
  if (contentEncoding)
20690
- json2.contentEncoding = contentEncoding;
20781
+ json3.contentEncoding = contentEncoding;
20691
20782
  if (patterns && patterns.size > 0) {
20692
20783
  const patternList = [...patterns].map(exactPattern);
20693
20784
  if (patternList.length === 1)
20694
- json2.pattern = patternList[0].source;
20785
+ json3.pattern = patternList[0].source;
20695
20786
  else if (patternList.length > 1) {
20696
- json2.allOf = [
20787
+ json3.allOf = [
20697
20788
  ...patternList.map((regex) => ({
20698
20789
  ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {},
20699
20790
  pattern: regex.source
@@ -20703,31 +20794,31 @@ var stringProcessor = (schema, ctx, _json, _params) => {
20703
20794
  }
20704
20795
  };
20705
20796
  var numberProcessor = (schema, ctx, _json, params) => {
20706
- const json2 = _json;
20797
+ const json3 = _json;
20707
20798
  const { minimum, maximum, multipleOf, exclusiveMaximum, exclusiveMinimum, isInt: isInt2 } = aggregateChecks(schema);
20708
- json2.type = isInt2 ? "integer" : "number";
20799
+ json3.type = isInt2 ? "integer" : "number";
20709
20800
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
20710
20801
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
20711
20802
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
20712
20803
  if (exMin) {
20713
20804
  if (legacy) {
20714
- json2.minimum = exclusiveMinimum;
20715
- json2.exclusiveMinimum = true;
20805
+ json3.minimum = exclusiveMinimum;
20806
+ json3.exclusiveMinimum = true;
20716
20807
  } else {
20717
- json2.exclusiveMinimum = exclusiveMinimum;
20808
+ json3.exclusiveMinimum = exclusiveMinimum;
20718
20809
  }
20719
20810
  } else if (typeof minimum === "number") {
20720
- json2.minimum = minimum;
20811
+ json3.minimum = minimum;
20721
20812
  }
20722
20813
  if (exMax) {
20723
20814
  if (legacy) {
20724
- json2.maximum = exclusiveMaximum;
20725
- json2.exclusiveMaximum = true;
20815
+ json3.maximum = exclusiveMaximum;
20816
+ json3.exclusiveMaximum = true;
20726
20817
  } else {
20727
- json2.exclusiveMaximum = exclusiveMaximum;
20818
+ json3.exclusiveMaximum = exclusiveMaximum;
20728
20819
  }
20729
20820
  } else if (typeof maximum === "number") {
20730
- json2.maximum = maximum;
20821
+ json3.maximum = maximum;
20731
20822
  }
20732
20823
  if (multipleOf) {
20733
20824
  const divisors = /* @__PURE__ */ new Set();
@@ -20735,75 +20826,75 @@ var numberProcessor = (schema, ctx, _json, params) => {
20735
20826
  if (Number.isFinite(divisor) && divisor !== 0)
20736
20827
  divisors.add(Math.abs(divisor));
20737
20828
  else
20738
- handleUnrepresentable(schema, ctx, json2, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
20829
+ handleUnrepresentable(schema, ctx, json3, params, `A multipleOf divisor of ${divisor} cannot be represented in JSON Schema`);
20739
20830
  }
20740
20831
  const [first, ...rest] = divisors;
20741
20832
  if (first !== void 0)
20742
- json2.multipleOf = first;
20833
+ json3.multipleOf = first;
20743
20834
  if (rest.length)
20744
- json2.allOf = [...json2.allOf ?? [], ...rest.map((m2) => ({ multipleOf: m2 }))];
20835
+ json3.allOf = [...json3.allOf ?? [], ...rest.map((m2) => ({ multipleOf: m2 }))];
20745
20836
  }
20746
20837
  };
20747
- var booleanProcessor = (_schema, _ctx, json2, _params) => {
20748
- json2.type = "boolean";
20838
+ var booleanProcessor = (_schema, _ctx, json3, _params) => {
20839
+ json3.type = "boolean";
20749
20840
  };
20750
- var bigintProcessor = (schema, ctx, json2, params) => {
20751
- handleUnrepresentable(schema, ctx, json2, params, "BigInt cannot be represented in JSON Schema");
20841
+ var bigintProcessor = (schema, ctx, json3, params) => {
20842
+ handleUnrepresentable(schema, ctx, json3, params, "BigInt cannot be represented in JSON Schema");
20752
20843
  };
20753
- var symbolProcessor = (schema, ctx, json2, params) => {
20754
- handleUnrepresentable(schema, ctx, json2, params, "Symbols cannot be represented in JSON Schema");
20844
+ var symbolProcessor = (schema, ctx, json3, params) => {
20845
+ handleUnrepresentable(schema, ctx, json3, params, "Symbols cannot be represented in JSON Schema");
20755
20846
  };
20756
- var nullProcessor = (_schema, ctx, json2, _params) => {
20847
+ var nullProcessor = (_schema, ctx, json3, _params) => {
20757
20848
  if (ctx.target === "openapi-3.0") {
20758
- json2.type = "string";
20759
- json2.nullable = true;
20760
- json2.enum = [null];
20849
+ json3.type = "string";
20850
+ json3.nullable = true;
20851
+ json3.enum = [null];
20761
20852
  } else {
20762
- json2.type = "null";
20853
+ json3.type = "null";
20763
20854
  }
20764
20855
  };
20765
- var undefinedProcessor = (schema, ctx, json2, params) => {
20766
- handleUnrepresentable(schema, ctx, json2, params, "Undefined cannot be represented in JSON Schema");
20856
+ var undefinedProcessor = (schema, ctx, json3, params) => {
20857
+ handleUnrepresentable(schema, ctx, json3, params, "Undefined cannot be represented in JSON Schema");
20767
20858
  };
20768
- var voidProcessor = (schema, ctx, json2, params) => {
20769
- handleUnrepresentable(schema, ctx, json2, params, "Void cannot be represented in JSON Schema");
20859
+ var voidProcessor = (schema, ctx, json3, params) => {
20860
+ handleUnrepresentable(schema, ctx, json3, params, "Void cannot be represented in JSON Schema");
20770
20861
  };
20771
- var neverProcessor = (_schema, _ctx, json2, _params) => {
20772
- json2.not = {};
20862
+ var neverProcessor = (_schema, _ctx, json3, _params) => {
20863
+ json3.not = {};
20773
20864
  };
20774
20865
  var anyProcessor = (_schema, _ctx, _json, _params) => {
20775
20866
  };
20776
20867
  var unknownProcessor = (_schema, _ctx, _json, _params) => {
20777
20868
  };
20778
- var dateProcessor = (schema, ctx, json2, params) => {
20779
- handleUnrepresentable(schema, ctx, json2, params, "Date cannot be represented in JSON Schema");
20869
+ var dateProcessor = (schema, ctx, json3, params) => {
20870
+ handleUnrepresentable(schema, ctx, json3, params, "Date cannot be represented in JSON Schema");
20780
20871
  };
20781
- var enumProcessor = (schema, _ctx, json2, _params) => {
20872
+ var enumProcessor = (schema, _ctx, json3, _params) => {
20782
20873
  const def = schema._zod.def;
20783
20874
  const values = getEnumValues(def.entries);
20784
20875
  if (values.length === 0) {
20785
- json2.not = {};
20876
+ json3.not = {};
20786
20877
  return;
20787
20878
  }
20788
20879
  if (values.every((v2) => typeof v2 === "number"))
20789
- json2.type = "number";
20880
+ json3.type = "number";
20790
20881
  if (values.every((v2) => typeof v2 === "string"))
20791
- json2.type = "string";
20792
- json2.enum = values;
20882
+ json3.type = "string";
20883
+ json3.enum = values;
20793
20884
  };
20794
- var literalProcessor = (schema, ctx, json2, params) => {
20885
+ var literalProcessor = (schema, ctx, json3, params) => {
20795
20886
  const def = schema._zod.def;
20796
20887
  if (def.values.length === 0) {
20797
- json2.not = {};
20888
+ json3.not = {};
20798
20889
  return;
20799
20890
  }
20800
20891
  const vals = [];
20801
20892
  for (const val of def.values) {
20802
20893
  if (val === void 0) {
20803
- if (handleUnrepresentable(schema, ctx, json2, params, "Literal `undefined` cannot be represented in JSON Schema"))
20894
+ if (handleUnrepresentable(schema, ctx, json3, params, "Literal `undefined` cannot be represented in JSON Schema"))
20804
20895
  return;
20805
20896
  } else if (typeof val === "bigint") {
20806
- if (handleUnrepresentable(schema, ctx, json2, params, "BigInt literals cannot be represented in JSON Schema"))
20897
+ if (handleUnrepresentable(schema, ctx, json3, params, "BigInt literals cannot be represented in JSON Schema"))
20807
20898
  return;
20808
20899
  vals.push(Number(val));
20809
20900
  } else {
@@ -20813,37 +20904,37 @@ var literalProcessor = (schema, ctx, json2, params) => {
20813
20904
  if (vals.length === 0) {
20814
20905
  } else if (vals.length === 1) {
20815
20906
  const val = vals[0];
20816
- json2.type = val === null ? "null" : typeof val;
20907
+ json3.type = val === null ? "null" : typeof val;
20817
20908
  if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
20818
- json2.enum = [val];
20909
+ json3.enum = [val];
20819
20910
  } else {
20820
- json2.const = val;
20911
+ json3.const = val;
20821
20912
  }
20822
20913
  } else {
20823
20914
  if (vals.every((v2) => typeof v2 === "number"))
20824
- json2.type = "number";
20915
+ json3.type = "number";
20825
20916
  if (vals.every((v2) => typeof v2 === "string"))
20826
- json2.type = "string";
20917
+ json3.type = "string";
20827
20918
  if (vals.every((v2) => typeof v2 === "boolean"))
20828
- json2.type = "boolean";
20919
+ json3.type = "boolean";
20829
20920
  if (vals.every((v2) => v2 === null))
20830
- json2.type = "null";
20831
- json2.enum = vals;
20921
+ json3.type = "null";
20922
+ json3.enum = vals;
20832
20923
  }
20833
20924
  };
20834
- var nanProcessor = (schema, ctx, json2, params) => {
20835
- handleUnrepresentable(schema, ctx, json2, params, "NaN cannot be represented in JSON Schema");
20925
+ var nanProcessor = (schema, ctx, json3, params) => {
20926
+ handleUnrepresentable(schema, ctx, json3, params, "NaN cannot be represented in JSON Schema");
20836
20927
  };
20837
- var templateLiteralProcessor = (schema, _ctx, json2, _params) => {
20838
- const _json = json2;
20928
+ var templateLiteralProcessor = (schema, _ctx, json3, _params) => {
20929
+ const _json = json3;
20839
20930
  const pattern = schema._zod.pattern;
20840
20931
  if (!pattern)
20841
20932
  throw new Error("Pattern not found in template literal");
20842
20933
  _json.type = "string";
20843
20934
  _json.pattern = pattern.source;
20844
20935
  };
20845
- var fileProcessor = (schema, _ctx, json2, _params) => {
20846
- const _json = json2;
20936
+ var fileProcessor = (schema, _ctx, json3, _params) => {
20937
+ const _json = json3;
20847
20938
  _json.type = "string";
20848
20939
  _json.format = "binary";
20849
20940
  _json.contentEncoding = "binary";
@@ -20861,34 +20952,34 @@ var fileProcessor = (schema, _ctx, json2, _params) => {
20861
20952
  else
20862
20953
  _json.anyOf = mime.map((m2) => ({ contentMediaType: m2 }));
20863
20954
  };
20864
- var successProcessor = (_schema, _ctx, json2, _params) => {
20865
- json2.type = "boolean";
20955
+ var successProcessor = (_schema, _ctx, json3, _params) => {
20956
+ json3.type = "boolean";
20866
20957
  };
20867
- var customProcessor = (schema, ctx, json2, params) => {
20868
- handleUnrepresentable(schema, ctx, json2, params, "Custom types cannot be represented in JSON Schema");
20958
+ var customProcessor = (schema, ctx, json3, params) => {
20959
+ handleUnrepresentable(schema, ctx, json3, params, "Custom types cannot be represented in JSON Schema");
20869
20960
  };
20870
- var functionProcessor = (schema, ctx, json2, params) => {
20871
- handleUnrepresentable(schema, ctx, json2, params, "Function types cannot be represented in JSON Schema");
20961
+ var functionProcessor = (schema, ctx, json3, params) => {
20962
+ handleUnrepresentable(schema, ctx, json3, params, "Function types cannot be represented in JSON Schema");
20872
20963
  };
20873
- var transformProcessor = (schema, ctx, json2, params) => {
20874
- handleUnrepresentable(schema, ctx, json2, params, "Transforms cannot be represented in JSON Schema");
20964
+ var transformProcessor = (schema, ctx, json3, params) => {
20965
+ handleUnrepresentable(schema, ctx, json3, params, "Transforms cannot be represented in JSON Schema");
20875
20966
  };
20876
- var mapProcessor = (schema, ctx, json2, params) => {
20877
- handleUnrepresentable(schema, ctx, json2, params, "Map cannot be represented in JSON Schema");
20967
+ var mapProcessor = (schema, ctx, json3, params) => {
20968
+ handleUnrepresentable(schema, ctx, json3, params, "Map cannot be represented in JSON Schema");
20878
20969
  };
20879
- var setProcessor = (schema, ctx, json2, params) => {
20880
- handleUnrepresentable(schema, ctx, json2, params, "Set cannot be represented in JSON Schema");
20970
+ var setProcessor = (schema, ctx, json3, params) => {
20971
+ handleUnrepresentable(schema, ctx, json3, params, "Set cannot be represented in JSON Schema");
20881
20972
  };
20882
20973
  var arrayProcessor = (schema, ctx, _json, params) => {
20883
- const json2 = _json;
20974
+ const json3 = _json;
20884
20975
  const def = schema._zod.def;
20885
20976
  const { minimum, maximum } = aggregateChecks(schema);
20886
20977
  if (typeof minimum === "number")
20887
- json2.minItems = minimum;
20978
+ json3.minItems = minimum;
20888
20979
  if (typeof maximum === "number")
20889
- json2.maxItems = maximum;
20890
- json2.type = "array";
20891
- json2.items = processSchema(def.element, ctx, {
20980
+ json3.maxItems = maximum;
20981
+ json3.type = "array";
20982
+ json3.items = processSchema(def.element, ctx, {
20892
20983
  ...params,
20893
20984
  path: [...params.path, "items"]
20894
20985
  });
@@ -20904,17 +20995,17 @@ function inputOptin(schema) {
20904
20995
  return schema._zod.optin;
20905
20996
  }
20906
20997
  var objectProcessor = (schema, ctx, _json, params) => {
20907
- const json2 = _json;
20998
+ const json3 = _json;
20908
20999
  const def = schema._zod.def;
20909
21000
  const shape = def.shape;
20910
21001
  const symbolKeys = Object.getOwnPropertySymbols(shape);
20911
- if (symbolKeys.length && handleUnrepresentable(schema, ctx, json2, params, "Symbol keys cannot be represented in JSON Schema")) {
21002
+ if (symbolKeys.length && handleUnrepresentable(schema, ctx, json3, params, "Symbol keys cannot be represented in JSON Schema")) {
20912
21003
  return;
20913
21004
  }
20914
- json2.type = "object";
20915
- json2.properties = {};
21005
+ json3.type = "object";
21006
+ json3.properties = {};
20916
21007
  for (const key3 in shape) {
20917
- assignProp(json2.properties, key3, processSchema(shape[key3], ctx, {
21008
+ assignProp(json3.properties, key3, processSchema(shape[key3], ctx, {
20918
21009
  ...params,
20919
21010
  path: [...params.path, "properties", key3]
20920
21011
  }));
@@ -20927,21 +21018,21 @@ var objectProcessor = (schema, ctx, _json, params) => {
20927
21018
  }
20928
21019
  }
20929
21020
  if (requiredKeys.length > 0) {
20930
- json2.required = requiredKeys;
21021
+ json3.required = requiredKeys;
20931
21022
  }
20932
21023
  if (def.catchall?._zod.def.type === "never") {
20933
- json2.additionalProperties = false;
21024
+ json3.additionalProperties = false;
20934
21025
  } else if (!def.catchall) {
20935
21026
  if (ctx.io === "output")
20936
- json2.additionalProperties = false;
21027
+ json3.additionalProperties = false;
20937
21028
  } else if (def.catchall) {
20938
- json2.additionalProperties = processSchema(def.catchall, ctx, {
21029
+ json3.additionalProperties = processSchema(def.catchall, ctx, {
20939
21030
  ...params,
20940
21031
  path: [...params.path, "additionalProperties"]
20941
21032
  });
20942
21033
  }
20943
21034
  };
20944
- var unionProcessor = (schema, ctx, json2, params) => {
21035
+ var unionProcessor = (schema, ctx, json3, params) => {
20945
21036
  const def = schema._zod.def;
20946
21037
  const isExclusive = def.inclusive === false;
20947
21038
  const options = def.options.map((x2, i) => processSchema(x2, ctx, {
@@ -20949,12 +21040,12 @@ var unionProcessor = (schema, ctx, json2, params) => {
20949
21040
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i]
20950
21041
  }));
20951
21042
  if (isExclusive) {
20952
- json2.oneOf = options;
21043
+ json3.oneOf = options;
20953
21044
  } else {
20954
- json2.anyOf = options;
21045
+ json3.anyOf = options;
20955
21046
  }
20956
21047
  };
20957
- var intersectionProcessor = (schema, ctx, json2, params) => {
21048
+ var intersectionProcessor = (schema, ctx, json3, params) => {
20958
21049
  const def = schema._zod.def;
20959
21050
  const a = processSchema(def.left, ctx, {
20960
21051
  ...params,
@@ -20969,13 +21060,13 @@ var intersectionProcessor = (schema, ctx, json2, params) => {
20969
21060
  ...isSimpleIntersection(a) ? a.allOf : [a],
20970
21061
  ...isSimpleIntersection(b3) ? b3.allOf : [b3]
20971
21062
  ];
20972
- json2.allOf = allOf;
21063
+ json3.allOf = allOf;
20973
21064
  ctx.intersections.push(allOf);
20974
21065
  };
20975
21066
  var tupleProcessor = (schema, ctx, _json, params) => {
20976
- const json2 = _json;
21067
+ const json3 = _json;
20977
21068
  const def = schema._zod.def;
20978
- json2.type = "array";
21069
+ json3.type = "array";
20979
21070
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
20980
21071
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
20981
21072
  const prefixItems = def.items.map((x2, i) => processSchema(x2, ctx, {
@@ -20997,70 +21088,70 @@ var tupleProcessor = (schema, ctx, _json, params) => {
20997
21088
  const maxItems = def.items.length;
20998
21089
  const isClosed = !def.rest;
20999
21090
  if (ctx.target === "draft-2020-12") {
21000
- json2.prefixItems = prefixItems;
21091
+ json3.prefixItems = prefixItems;
21001
21092
  if (isClosed) {
21002
- json2.items = false;
21093
+ json3.items = false;
21003
21094
  } else if (rest) {
21004
- json2.items = rest;
21095
+ json3.items = rest;
21005
21096
  }
21006
21097
  if (minItems > 0)
21007
- json2.minItems = minItems;
21098
+ json3.minItems = minItems;
21008
21099
  if (isClosed)
21009
- json2.maxItems = maxItems;
21100
+ json3.maxItems = maxItems;
21010
21101
  } else if (ctx.target === "openapi-3.0") {
21011
- json2.items = {
21102
+ json3.items = {
21012
21103
  anyOf: prefixItems
21013
21104
  };
21014
21105
  if (rest) {
21015
- json2.items.anyOf.push(rest);
21106
+ json3.items.anyOf.push(rest);
21016
21107
  }
21017
21108
  if (minItems > 0)
21018
- json2.minItems = minItems;
21109
+ json3.minItems = minItems;
21019
21110
  if (isClosed)
21020
- json2.maxItems = maxItems;
21111
+ json3.maxItems = maxItems;
21021
21112
  } else {
21022
- json2.items = prefixItems;
21113
+ json3.items = prefixItems;
21023
21114
  if (isClosed) {
21024
- json2.additionalItems = false;
21115
+ json3.additionalItems = false;
21025
21116
  } else if (rest) {
21026
- json2.additionalItems = rest;
21117
+ json3.additionalItems = rest;
21027
21118
  }
21028
21119
  if (minItems > 0)
21029
- json2.minItems = minItems;
21120
+ json3.minItems = minItems;
21030
21121
  if (isClosed)
21031
- json2.maxItems = maxItems;
21122
+ json3.maxItems = maxItems;
21032
21123
  }
21033
21124
  const { minimum, maximum } = aggregateChecks(schema);
21034
21125
  if (typeof minimum === "number")
21035
- json2.minItems = minimum;
21126
+ json3.minItems = minimum;
21036
21127
  if (typeof maximum === "number")
21037
- json2.maxItems = maximum;
21128
+ json3.maxItems = maximum;
21038
21129
  };
21039
- function stringifyKeyNames(bySchema, json2, visited) {
21040
- if (json2.$ref) {
21041
- if (visited.has(json2))
21042
- return json2;
21043
- visited.add(json2);
21044
- const def = bySchema.get(json2)?.def;
21130
+ function stringifyKeyNames(bySchema, json3, visited) {
21131
+ if (json3.$ref) {
21132
+ if (visited.has(json3))
21133
+ return json3;
21134
+ visited.add(json3);
21135
+ const def = bySchema.get(json3)?.def;
21045
21136
  if (!def)
21046
- return json2;
21137
+ return json3;
21047
21138
  const inlined = stringifyKeyNames(bySchema, def, visited);
21048
- return inlined === def ? json2 : inlined;
21139
+ return inlined === def ? json3 : inlined;
21049
21140
  }
21050
21141
  for (const keyword of ["anyOf", "oneOf"]) {
21051
- const branches = json2[keyword];
21142
+ const branches = json3[keyword];
21052
21143
  if (!Array.isArray(branches))
21053
21144
  continue;
21054
21145
  const mapped = branches.map((branch) => stringifyKeyNames(bySchema, branch, visited));
21055
21146
  if (mapped.some((branch, i) => branch !== branches[i]))
21056
- json2 = { ...json2, [keyword]: mapped };
21147
+ json3 = { ...json3, [keyword]: mapped };
21057
21148
  }
21058
- const types = Array.isArray(json2.type) ? json2.type : [json2.type];
21149
+ const types = Array.isArray(json3.type) ? json3.type : [json3.type];
21059
21150
  const numericType = !types.includes("string") && types.some((t) => t === "number" || t === "integer");
21060
- const values = json2.enum ?? (json2.const !== void 0 ? [json2.const] : void 0);
21151
+ const values = json3.enum ?? (json3.const !== void 0 ? [json3.const] : void 0);
21061
21152
  if (!numericType && !values?.some((v2) => typeof v2 === "number"))
21062
- return json2;
21063
- const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json2;
21153
+ return json3;
21154
+ const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, format, id, ...rest } = json3;
21064
21155
  if (rest.enum)
21065
21156
  rest.enum = rest.enum.map((v2) => typeof v2 === "number" ? String(v2) : v2);
21066
21157
  else if (typeof rest.const === "number")
@@ -21100,9 +21191,9 @@ function rewriteKeyNames(ctx) {
21100
21191
  }
21101
21192
  }
21102
21193
  var recordProcessor = (schema, ctx, _json, params) => {
21103
- const json2 = _json;
21194
+ const json3 = _json;
21104
21195
  const def = schema._zod.def;
21105
- json2.type = "object";
21196
+ json3.type = "object";
21106
21197
  const keyType = def.keyType;
21107
21198
  const patterns = aggregateChecks(keyType).patterns;
21108
21199
  if (def.mode === "loose" && patterns && patterns.size > 0) {
@@ -21110,13 +21201,13 @@ var recordProcessor = (schema, ctx, _json, params) => {
21110
21201
  ...params,
21111
21202
  path: [...params.path, "patternProperties", "*"]
21112
21203
  });
21113
- json2.patternProperties = {};
21204
+ json3.patternProperties = {};
21114
21205
  for (const pattern of patterns) {
21115
- assignProp(json2.patternProperties, exactPattern(pattern).source, valueSchema);
21206
+ assignProp(json3.patternProperties, exactPattern(pattern).source, valueSchema);
21116
21207
  }
21117
21208
  } else {
21118
21209
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
21119
- json2.propertyNames = processSchema(def.keyType, ctx, {
21210
+ json3.propertyNames = processSchema(def.keyType, ctx, {
21120
21211
  ...params,
21121
21212
  path: [...params.path, "propertyNames"]
21122
21213
  });
@@ -21128,7 +21219,7 @@ var recordProcessor = (schema, ctx, _json, params) => {
21128
21219
  }
21129
21220
  pending.push(schema);
21130
21221
  }
21131
- json2.additionalProperties = processSchema(def.valueType, ctx, {
21222
+ json3.additionalProperties = processSchema(def.valueType, ctx, {
21132
21223
  ...params,
21133
21224
  path: [...params.path, "additionalProperties"]
21134
21225
  });
@@ -21138,19 +21229,19 @@ var recordProcessor = (schema, ctx, _json, params) => {
21138
21229
  if (keyValues && !def.partial && !omittableOnInput) {
21139
21230
  const validKeyValues = [...keyValues].filter((v2) => typeof v2 === "string" || typeof v2 === "number");
21140
21231
  if (validKeyValues.length > 0) {
21141
- json2.required = validKeyValues.map(String);
21232
+ json3.required = validKeyValues.map(String);
21142
21233
  }
21143
21234
  }
21144
21235
  };
21145
- var nullableProcessor = (schema, ctx, json2, params) => {
21236
+ var nullableProcessor = (schema, ctx, json3, params) => {
21146
21237
  const def = schema._zod.def;
21147
21238
  const inner = processSchema(def.innerType, ctx, params);
21148
21239
  const seen = ctx.seen.get(schema);
21149
21240
  if (ctx.target === "openapi-3.0") {
21150
21241
  seen.ref = def.innerType;
21151
- json2.nullable = true;
21242
+ json3.nullable = true;
21152
21243
  } else {
21153
- json2.anyOf = [inner, { type: "null" }];
21244
+ json3.anyOf = [inner, { type: "null" }];
21154
21245
  }
21155
21246
  };
21156
21247
  var nonoptionalProcessor = (schema, ctx, _json, params) => {
@@ -21160,7 +21251,7 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
21160
21251
  seen.ref = def.innerType;
21161
21252
  };
21162
21253
  var UNREPRESENTABLE_DEFAULT = /* @__PURE__ */ Symbol();
21163
- function serializeDefaultValue(value, schema, ctx, json2, params) {
21254
+ function serializeDefaultValue(value, schema, ctx, json3, params) {
21164
21255
  let unrepresentable = false;
21165
21256
  const serialized = JSON.stringify(value, (_3, val) => {
21166
21257
  if (typeof val !== "bigint")
@@ -21170,30 +21261,30 @@ function serializeDefaultValue(value, schema, ctx, json2, params) {
21170
21261
  });
21171
21262
  if (!unrepresentable)
21172
21263
  return JSON.parse(serialized);
21173
- handleUnrepresentable(schema, ctx, json2, params, "BigInt defaults cannot be represented in JSON Schema");
21264
+ handleUnrepresentable(schema, ctx, json3, params, "BigInt defaults cannot be represented in JSON Schema");
21174
21265
  return UNREPRESENTABLE_DEFAULT;
21175
21266
  }
21176
- var defaultProcessor = (schema, ctx, json2, params) => {
21267
+ var defaultProcessor = (schema, ctx, json3, params) => {
21177
21268
  const def = schema._zod.def;
21178
21269
  processSchema(def.innerType, ctx, params);
21179
21270
  const seen = ctx.seen.get(schema);
21180
21271
  seen.ref = def.innerType;
21181
- const value = serializeDefaultValue(def.defaultValue, schema, ctx, json2, params);
21272
+ const value = serializeDefaultValue(def.defaultValue, schema, ctx, json3, params);
21182
21273
  if (value !== UNREPRESENTABLE_DEFAULT)
21183
- json2.default = value;
21274
+ json3.default = value;
21184
21275
  };
21185
- var prefaultProcessor = (schema, ctx, json2, params) => {
21276
+ var prefaultProcessor = (schema, ctx, json3, params) => {
21186
21277
  const def = schema._zod.def;
21187
21278
  processSchema(def.innerType, ctx, params);
21188
21279
  const seen = ctx.seen.get(schema);
21189
21280
  seen.ref = def.innerType;
21190
21281
  if (ctx.io !== "input")
21191
21282
  return;
21192
- const value = serializeDefaultValue(def.defaultValue, schema, ctx, json2, params);
21283
+ const value = serializeDefaultValue(def.defaultValue, schema, ctx, json3, params);
21193
21284
  if (value !== UNREPRESENTABLE_DEFAULT)
21194
- json2._prefault = value;
21285
+ json3._prefault = value;
21195
21286
  };
21196
- var catchProcessor = (schema, ctx, json2, params) => {
21287
+ var catchProcessor = (schema, ctx, json3, params) => {
21197
21288
  const def = schema._zod.def;
21198
21289
  processSchema(def.innerType, ctx, params);
21199
21290
  const seen = ctx.seen.get(schema);
@@ -21202,10 +21293,10 @@ var catchProcessor = (schema, ctx, json2, params) => {
21202
21293
  try {
21203
21294
  catchValue = def.catchValue(void 0);
21204
21295
  } catch {
21205
- handleUnrepresentable(schema, ctx, json2, params, "Dynamic catch values are not supported in JSON Schema");
21296
+ handleUnrepresentable(schema, ctx, json3, params, "Dynamic catch values are not supported in JSON Schema");
21206
21297
  return;
21207
21298
  }
21208
- json2.default = catchValue;
21299
+ json3.default = catchValue;
21209
21300
  };
21210
21301
  var pipeProcessor = (schema, ctx, _json, params) => {
21211
21302
  const def = schema._zod.def;
@@ -21215,12 +21306,12 @@ var pipeProcessor = (schema, ctx, _json, params) => {
21215
21306
  const seen = ctx.seen.get(schema);
21216
21307
  seen.ref = innerType;
21217
21308
  };
21218
- var readonlyProcessor = (schema, ctx, json2, params) => {
21309
+ var readonlyProcessor = (schema, ctx, json3, params) => {
21219
21310
  const def = schema._zod.def;
21220
21311
  processSchema(def.innerType, ctx, params);
21221
21312
  const seen = ctx.seen.get(schema);
21222
21313
  seen.ref = def.innerType;
21223
- json2.readOnly = true;
21314
+ json3.readOnly = true;
21224
21315
  };
21225
21316
  var promiseProcessor = (schema, ctx, _json, params) => {
21226
21317
  const def = schema._zod.def;
@@ -21707,8 +21798,8 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
21707
21798
  brand() {
21708
21799
  return this;
21709
21800
  },
21710
- register(reg, meta3) {
21711
- reg.add(this, meta3);
21801
+ register(reg, meta4) {
21802
+ reg.add(this, meta4);
21712
21803
  return this;
21713
21804
  },
21714
21805
  refine(check2, params) {
@@ -21862,7 +21953,7 @@ var _ZodString = /* @__PURE__ */ $constructor(
21862
21953
  (inst, def) => {
21863
21954
  $ZodString.init(inst, def);
21864
21955
  ZodType.init(inst, def);
21865
- inst._zod.processJSONSchema = (ctx, json2, params) => stringProcessor(inst, ctx, json2, params);
21956
+ inst._zod.processJSONSchema = (ctx, json3, params) => stringProcessor(inst, ctx, json3, params);
21866
21957
  },
21867
21958
  /* @__PURE__ */ util_exports.derived({
21868
21959
  format: (inst) => aggregateChecks(inst).format ?? null,
@@ -22221,7 +22312,7 @@ var ZodNumber = /* @__PURE__ */ $constructor(
22221
22312
  (inst, def) => {
22222
22313
  $ZodNumber.init(inst, def);
22223
22314
  ZodType.init(inst, def);
22224
- inst._zod.processJSONSchema = (ctx, json2, params) => numberProcessor(inst, ctx, json2, params);
22315
+ inst._zod.processJSONSchema = (ctx, json3, params) => numberProcessor(inst, ctx, json3, params);
22225
22316
  inst.isFinite = true;
22226
22317
  },
22227
22318
  /* @__PURE__ */ util_exports.derived({
@@ -22311,7 +22402,7 @@ function uint32(params) {
22311
22402
  var ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
22312
22403
  $ZodBoolean.init(inst, def);
22313
22404
  ZodType.init(inst, def);
22314
- inst._zod.processJSONSchema = (ctx, json2, params) => booleanProcessor(inst, ctx, json2, params);
22405
+ inst._zod.processJSONSchema = (ctx, json3, params) => booleanProcessor(inst, ctx, json3, params);
22315
22406
  });
22316
22407
  function boolean2(params) {
22317
22408
  return _boolean(ZodBoolean, params);
@@ -22321,7 +22412,7 @@ var ZodBigInt = /* @__PURE__ */ $constructor(
22321
22412
  (inst, def) => {
22322
22413
  $ZodBigInt.init(inst, def);
22323
22414
  ZodType.init(inst, def);
22324
- inst._zod.processJSONSchema = (ctx, json2, params) => bigintProcessor(inst, ctx, json2, params);
22415
+ inst._zod.processJSONSchema = (ctx, json3, params) => bigintProcessor(inst, ctx, json3, params);
22325
22416
  },
22326
22417
  /* @__PURE__ */ util_exports.derived({
22327
22418
  minValue: (inst) => aggregateChecks(inst).minimum ?? null,
@@ -22379,7 +22470,7 @@ function uint64(params) {
22379
22470
  var ZodSymbol = /* @__PURE__ */ $constructor("ZodSymbol", (inst, def) => {
22380
22471
  $ZodSymbol.init(inst, def);
22381
22472
  ZodType.init(inst, def);
22382
- inst._zod.processJSONSchema = (ctx, json2, params) => symbolProcessor(inst, ctx, json2, params);
22473
+ inst._zod.processJSONSchema = (ctx, json3, params) => symbolProcessor(inst, ctx, json3, params);
22383
22474
  });
22384
22475
  function symbol(params) {
22385
22476
  return _symbol(ZodSymbol, params);
@@ -22387,7 +22478,7 @@ function symbol(params) {
22387
22478
  var ZodUndefined = /* @__PURE__ */ $constructor("ZodUndefined", (inst, def) => {
22388
22479
  $ZodUndefined.init(inst, def);
22389
22480
  ZodType.init(inst, def);
22390
- inst._zod.processJSONSchema = (ctx, json2, params) => undefinedProcessor(inst, ctx, json2, params);
22481
+ inst._zod.processJSONSchema = (ctx, json3, params) => undefinedProcessor(inst, ctx, json3, params);
22391
22482
  });
22392
22483
  function _undefined3(params) {
22393
22484
  return _undefined2(ZodUndefined, params);
@@ -22395,7 +22486,7 @@ function _undefined3(params) {
22395
22486
  var ZodNull = /* @__PURE__ */ $constructor("ZodNull", (inst, def) => {
22396
22487
  $ZodNull.init(inst, def);
22397
22488
  ZodType.init(inst, def);
22398
- inst._zod.processJSONSchema = (ctx, json2, params) => nullProcessor(inst, ctx, json2, params);
22489
+ inst._zod.processJSONSchema = (ctx, json3, params) => nullProcessor(inst, ctx, json3, params);
22399
22490
  });
22400
22491
  function _null3(params) {
22401
22492
  return _null2(ZodNull, params);
@@ -22403,7 +22494,7 @@ function _null3(params) {
22403
22494
  var ZodAny = /* @__PURE__ */ $constructor("ZodAny", (inst, def) => {
22404
22495
  $ZodAny.init(inst, def);
22405
22496
  ZodType.init(inst, def);
22406
- inst._zod.processJSONSchema = (ctx, json2, params) => anyProcessor(inst, ctx, json2, params);
22497
+ inst._zod.processJSONSchema = (ctx, json3, params) => anyProcessor(inst, ctx, json3, params);
22407
22498
  });
22408
22499
  function any() {
22409
22500
  return _any(ZodAny);
@@ -22411,7 +22502,7 @@ function any() {
22411
22502
  var ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
22412
22503
  $ZodUnknown.init(inst, def);
22413
22504
  ZodType.init(inst, def);
22414
- inst._zod.processJSONSchema = (ctx, json2, params) => unknownProcessor(inst, ctx, json2, params);
22505
+ inst._zod.processJSONSchema = (ctx, json3, params) => unknownProcessor(inst, ctx, json3, params);
22415
22506
  });
22416
22507
  function unknown() {
22417
22508
  return _unknown(ZodUnknown);
@@ -22419,7 +22510,7 @@ function unknown() {
22419
22510
  var ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
22420
22511
  $ZodNever.init(inst, def);
22421
22512
  ZodType.init(inst, def);
22422
- inst._zod.processJSONSchema = (ctx, json2, params) => neverProcessor(inst, ctx, json2, params);
22513
+ inst._zod.processJSONSchema = (ctx, json3, params) => neverProcessor(inst, ctx, json3, params);
22423
22514
  });
22424
22515
  function never(params) {
22425
22516
  return _never(ZodNever, params);
@@ -22427,7 +22518,7 @@ function never(params) {
22427
22518
  var ZodVoid = /* @__PURE__ */ $constructor("ZodVoid", (inst, def) => {
22428
22519
  $ZodVoid.init(inst, def);
22429
22520
  ZodType.init(inst, def);
22430
- inst._zod.processJSONSchema = (ctx, json2, params) => voidProcessor(inst, ctx, json2, params);
22521
+ inst._zod.processJSONSchema = (ctx, json3, params) => voidProcessor(inst, ctx, json3, params);
22431
22522
  });
22432
22523
  function _void2(params) {
22433
22524
  return _void(ZodVoid, params);
@@ -22437,7 +22528,7 @@ var ZodDate = /* @__PURE__ */ $constructor(
22437
22528
  (inst, def) => {
22438
22529
  $ZodDate.init(inst, def);
22439
22530
  ZodType.init(inst, def);
22440
- inst._zod.processJSONSchema = (ctx, json2, params) => dateProcessor(inst, ctx, json2, params);
22531
+ inst._zod.processJSONSchema = (ctx, json3, params) => dateProcessor(inst, ctx, json3, params);
22441
22532
  inst.min = (value, params) => inst.check(_gte(value, params));
22442
22533
  inst.max = (value, params) => inst.check(_lte(value, params));
22443
22534
  },
@@ -22459,7 +22550,7 @@ var ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
22459
22550
  _ensureDefaultMemoizer();
22460
22551
  $ZodArray.init(inst, def);
22461
22552
  ZodType.init(inst, def);
22462
- inst._zod.processJSONSchema = (ctx, json2, params) => arrayProcessor(inst, ctx, json2, params);
22553
+ inst._zod.processJSONSchema = (ctx, json3, params) => arrayProcessor(inst, ctx, json3, params);
22463
22554
  inst.element = def.element;
22464
22555
  }, {
22465
22556
  min(n, params) {
@@ -22489,7 +22580,7 @@ var ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
22489
22580
  _ensureDefaultMemoizer();
22490
22581
  $ZodObjectJIT.init(inst, def);
22491
22582
  ZodType.init(inst, def);
22492
- inst._zod.processJSONSchema = (ctx, json2, params) => objectProcessor(inst, ctx, json2, params);
22583
+ inst._zod.processJSONSchema = (ctx, json3, params) => objectProcessor(inst, ctx, json3, params);
22493
22584
  util_exports.installLazyProp(inst, "shape", (self) => self._zod.def.shape, false);
22494
22585
  }, {
22495
22586
  keyof() {
@@ -22562,7 +22653,7 @@ function looseObject(shape, params) {
22562
22653
  var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
22563
22654
  $ZodUnion.init(inst, def);
22564
22655
  ZodType.init(inst, def);
22565
- inst._zod.processJSONSchema = (ctx, json2, params) => unionProcessor(inst, ctx, json2, params);
22656
+ inst._zod.processJSONSchema = (ctx, json3, params) => unionProcessor(inst, ctx, json3, params);
22566
22657
  inst.options = def.options;
22567
22658
  });
22568
22659
  function union(options, params) {
@@ -22575,7 +22666,7 @@ function union(options, params) {
22575
22666
  var ZodXor = /* @__PURE__ */ $constructor("ZodXor", (inst, def) => {
22576
22667
  ZodUnion.init(inst, def);
22577
22668
  $ZodXor.init(inst, def);
22578
- inst._zod.processJSONSchema = (ctx, json2, params) => unionProcessor(inst, ctx, json2, params);
22669
+ inst._zod.processJSONSchema = (ctx, json3, params) => unionProcessor(inst, ctx, json3, params);
22579
22670
  inst.options = def.options;
22580
22671
  });
22581
22672
  function xor(options, params) {
@@ -22601,7 +22692,7 @@ function discriminatedUnion(discriminator, options, params) {
22601
22692
  var ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
22602
22693
  $ZodIntersection.init(inst, def);
22603
22694
  ZodType.init(inst, def);
22604
- inst._zod.processJSONSchema = (ctx, json2, params) => intersectionProcessor(inst, ctx, json2, params);
22695
+ inst._zod.processJSONSchema = (ctx, json3, params) => intersectionProcessor(inst, ctx, json3, params);
22605
22696
  });
22606
22697
  function intersection(left, right) {
22607
22698
  return new ZodIntersection({
@@ -22614,7 +22705,7 @@ var ZodTuple = /* @__PURE__ */ $constructor("ZodTuple", (inst, def) => {
22614
22705
  _ensureDefaultMemoizer();
22615
22706
  $ZodTuple.init(inst, def);
22616
22707
  ZodType.init(inst, def);
22617
- inst._zod.processJSONSchema = (ctx, json2, params) => tupleProcessor(inst, ctx, json2, params);
22708
+ inst._zod.processJSONSchema = (ctx, json3, params) => tupleProcessor(inst, ctx, json3, params);
22618
22709
  }, {
22619
22710
  rest(rest) {
22620
22711
  return this.clone({
@@ -22647,7 +22738,7 @@ var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
22647
22738
  _ensureDefaultMemoizer();
22648
22739
  $ZodRecord.init(inst, def);
22649
22740
  ZodType.init(inst, def);
22650
- inst._zod.processJSONSchema = (ctx, json2, params) => recordProcessor(inst, ctx, json2, params);
22741
+ inst._zod.processJSONSchema = (ctx, json3, params) => recordProcessor(inst, ctx, json3, params);
22651
22742
  inst.keyType = def.keyType;
22652
22743
  inst.valueType = def.valueType;
22653
22744
  });
@@ -22689,7 +22780,7 @@ var ZodMap = /* @__PURE__ */ $constructor("ZodMap", (inst, def) => {
22689
22780
  _ensureDefaultMemoizer();
22690
22781
  $ZodMap.init(inst, def);
22691
22782
  ZodType.init(inst, def);
22692
- inst._zod.processJSONSchema = (ctx, json2, params) => mapProcessor(inst, ctx, json2, params);
22783
+ inst._zod.processJSONSchema = (ctx, json3, params) => mapProcessor(inst, ctx, json3, params);
22693
22784
  inst.keyType = def.keyType;
22694
22785
  inst.valueType = def.valueType;
22695
22786
  inst.min = (...args) => inst.check(_minSize(...args));
@@ -22709,7 +22800,7 @@ var ZodSet = /* @__PURE__ */ $constructor("ZodSet", (inst, def) => {
22709
22800
  _ensureDefaultMemoizer();
22710
22801
  $ZodSet.init(inst, def);
22711
22802
  ZodType.init(inst, def);
22712
- inst._zod.processJSONSchema = (ctx, json2, params) => setProcessor(inst, ctx, json2, params);
22803
+ inst._zod.processJSONSchema = (ctx, json3, params) => setProcessor(inst, ctx, json3, params);
22713
22804
  inst.min = (...args) => inst.check(_minSize(...args));
22714
22805
  inst.nonempty = (params) => inst.check(_minSize(1, params));
22715
22806
  inst.max = (...args) => inst.check(_maxSize(...args));
@@ -22725,7 +22816,7 @@ function set(valueType, params) {
22725
22816
  var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
22726
22817
  $ZodEnum.init(inst, def);
22727
22818
  ZodType.init(inst, def);
22728
- inst._zod.processJSONSchema = (ctx, json2, params) => enumProcessor(inst, ctx, json2, params);
22819
+ inst._zod.processJSONSchema = (ctx, json3, params) => enumProcessor(inst, ctx, json3, params);
22729
22820
  inst.enum = def.entries;
22730
22821
  inst.options = [...inst._zod.values];
22731
22822
  const keys = new Set(Object.keys(def.entries));
@@ -22761,24 +22852,24 @@ var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
22761
22852
  };
22762
22853
  });
22763
22854
  function _enum2(values, params) {
22764
- const entries = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
22855
+ const entries2 = Array.isArray(values) ? Object.fromEntries(values.map((v2) => [v2, v2])) : values;
22765
22856
  return new ZodEnum({
22766
22857
  type: "enum",
22767
- entries,
22858
+ entries: entries2,
22768
22859
  ...util_exports.normalizeParams(params)
22769
22860
  });
22770
22861
  }
22771
- function nativeEnum(entries, params) {
22862
+ function nativeEnum(entries2, params) {
22772
22863
  return new ZodEnum({
22773
22864
  type: "enum",
22774
- entries,
22865
+ entries: entries2,
22775
22866
  ...util_exports.normalizeParams(params)
22776
22867
  });
22777
22868
  }
22778
22869
  var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
22779
22870
  $ZodLiteral.init(inst, def);
22780
22871
  ZodType.init(inst, def);
22781
- inst._zod.processJSONSchema = (ctx, json2, params) => literalProcessor(inst, ctx, json2, params);
22872
+ inst._zod.processJSONSchema = (ctx, json3, params) => literalProcessor(inst, ctx, json3, params);
22782
22873
  inst.values = new Set(def.values);
22783
22874
  Object.defineProperty(inst, "value", {
22784
22875
  get() {
@@ -22799,7 +22890,7 @@ function literal(value, params) {
22799
22890
  var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
22800
22891
  $ZodFile.init(inst, def);
22801
22892
  ZodType.init(inst, def);
22802
- inst._zod.processJSONSchema = (ctx, json2, params) => fileProcessor(inst, ctx, json2, params);
22893
+ inst._zod.processJSONSchema = (ctx, json3, params) => fileProcessor(inst, ctx, json3, params);
22803
22894
  inst.min = (size2, params) => inst.check(_minSize(size2, params));
22804
22895
  inst.max = (size2, params) => inst.check(_maxSize(size2, params));
22805
22896
  inst.mime = (types, params) => inst.check(_mime(Array.isArray(types) ? types : [types], params));
@@ -22811,7 +22902,7 @@ var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
22811
22902
  _ensureDefaultMemoizer();
22812
22903
  $ZodTransform.init(inst, def);
22813
22904
  ZodType.init(inst, def);
22814
- inst._zod.processJSONSchema = (ctx, json2, params) => transformProcessor(inst, ctx, json2, params);
22905
+ inst._zod.processJSONSchema = (ctx, json3, params) => transformProcessor(inst, ctx, json3, params);
22815
22906
  inst._zod.parse = (payload, _ctx) => {
22816
22907
  if (_ctx.direction === "backward") {
22817
22908
  throw new $ZodEncodeError(inst.constructor.name);
@@ -22850,7 +22941,7 @@ function transform(fn) {
22850
22941
  var ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => {
22851
22942
  $ZodOptional.init(inst, def);
22852
22943
  ZodType.init(inst, def);
22853
- inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
22944
+ inst._zod.processJSONSchema = (ctx, json3, params) => optionalProcessor(inst, ctx, json3, params);
22854
22945
  inst.unwrap = () => inst._zod.def.innerType;
22855
22946
  });
22856
22947
  function optional(innerType) {
@@ -22862,7 +22953,7 @@ function optional(innerType) {
22862
22953
  var ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => {
22863
22954
  $ZodExactOptional.init(inst, def);
22864
22955
  ZodType.init(inst, def);
22865
- inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
22956
+ inst._zod.processJSONSchema = (ctx, json3, params) => optionalProcessor(inst, ctx, json3, params);
22866
22957
  inst.unwrap = () => inst._zod.def.innerType;
22867
22958
  });
22868
22959
  function exactOptional(innerType) {
@@ -22874,7 +22965,7 @@ function exactOptional(innerType) {
22874
22965
  var ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => {
22875
22966
  $ZodNullable.init(inst, def);
22876
22967
  ZodType.init(inst, def);
22877
- inst._zod.processJSONSchema = (ctx, json2, params) => nullableProcessor(inst, ctx, json2, params);
22968
+ inst._zod.processJSONSchema = (ctx, json3, params) => nullableProcessor(inst, ctx, json3, params);
22878
22969
  inst.unwrap = () => inst._zod.def.innerType;
22879
22970
  });
22880
22971
  function nullable(innerType) {
@@ -22889,7 +22980,7 @@ function nullish2(innerType) {
22889
22980
  var ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => {
22890
22981
  $ZodDefault.init(inst, def);
22891
22982
  ZodType.init(inst, def);
22892
- inst._zod.processJSONSchema = (ctx, json2, params) => defaultProcessor(inst, ctx, json2, params);
22983
+ inst._zod.processJSONSchema = (ctx, json3, params) => defaultProcessor(inst, ctx, json3, params);
22893
22984
  inst.unwrap = () => inst._zod.def.innerType;
22894
22985
  inst.removeDefault = inst.unwrap;
22895
22986
  });
@@ -22905,7 +22996,7 @@ function _default2(innerType, defaultValue) {
22905
22996
  var ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => {
22906
22997
  $ZodPrefault.init(inst, def);
22907
22998
  ZodType.init(inst, def);
22908
- inst._zod.processJSONSchema = (ctx, json2, params) => prefaultProcessor(inst, ctx, json2, params);
22999
+ inst._zod.processJSONSchema = (ctx, json3, params) => prefaultProcessor(inst, ctx, json3, params);
22909
23000
  inst.unwrap = () => inst._zod.def.innerType;
22910
23001
  });
22911
23002
  function prefault(innerType, defaultValue) {
@@ -22920,7 +23011,7 @@ function prefault(innerType, defaultValue) {
22920
23011
  var ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => {
22921
23012
  $ZodNonOptional.init(inst, def);
22922
23013
  ZodType.init(inst, def);
22923
- inst._zod.processJSONSchema = (ctx, json2, params) => nonoptionalProcessor(inst, ctx, json2, params);
23014
+ inst._zod.processJSONSchema = (ctx, json3, params) => nonoptionalProcessor(inst, ctx, json3, params);
22924
23015
  inst.unwrap = () => inst._zod.def.innerType;
22925
23016
  });
22926
23017
  function nonoptional(innerType, params) {
@@ -22933,7 +23024,7 @@ function nonoptional(innerType, params) {
22933
23024
  var ZodSuccess = /* @__PURE__ */ $constructor("ZodSuccess", (inst, def) => {
22934
23025
  $ZodSuccess.init(inst, def);
22935
23026
  ZodType.init(inst, def);
22936
- inst._zod.processJSONSchema = (ctx, json2, params) => successProcessor(inst, ctx, json2, params);
23027
+ inst._zod.processJSONSchema = (ctx, json3, params) => successProcessor(inst, ctx, json3, params);
22937
23028
  inst.unwrap = () => inst._zod.def.innerType;
22938
23029
  });
22939
23030
  function success(innerType) {
@@ -22945,7 +23036,7 @@ function success(innerType) {
22945
23036
  var ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => {
22946
23037
  $ZodCatch.init(inst, def);
22947
23038
  ZodType.init(inst, def);
22948
- inst._zod.processJSONSchema = (ctx, json2, params) => catchProcessor(inst, ctx, json2, params);
23039
+ inst._zod.processJSONSchema = (ctx, json3, params) => catchProcessor(inst, ctx, json3, params);
22949
23040
  inst.unwrap = () => inst._zod.def.innerType;
22950
23041
  inst.removeCatch = inst.unwrap;
22951
23042
  });
@@ -22959,7 +23050,7 @@ function _catch2(innerType, catchValue) {
22959
23050
  var ZodNaN = /* @__PURE__ */ $constructor("ZodNaN", (inst, def) => {
22960
23051
  $ZodNaN.init(inst, def);
22961
23052
  ZodType.init(inst, def);
22962
- inst._zod.processJSONSchema = (ctx, json2, params) => nanProcessor(inst, ctx, json2, params);
23053
+ inst._zod.processJSONSchema = (ctx, json3, params) => nanProcessor(inst, ctx, json3, params);
22963
23054
  });
22964
23055
  function nan(params) {
22965
23056
  return _nan(ZodNaN, params);
@@ -22967,7 +23058,7 @@ function nan(params) {
22967
23058
  var ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
22968
23059
  $ZodPipe.init(inst, def);
22969
23060
  ZodType.init(inst, def);
22970
- inst._zod.processJSONSchema = (ctx, json2, params) => pipeProcessor(inst, ctx, json2, params);
23061
+ inst._zod.processJSONSchema = (ctx, json3, params) => pipeProcessor(inst, ctx, json3, params);
22971
23062
  inst.in = def.in;
22972
23063
  inst.out = def.out;
22973
23064
  });
@@ -23009,7 +23100,7 @@ var ZodPreprocess = /* @__PURE__ */ $constructor("ZodPreprocess", (inst, def) =>
23009
23100
  var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
23010
23101
  $ZodReadonly.init(inst, def);
23011
23102
  ZodType.init(inst, def);
23012
- inst._zod.processJSONSchema = (ctx, json2, params) => readonlyProcessor(inst, ctx, json2, params);
23103
+ inst._zod.processJSONSchema = (ctx, json3, params) => readonlyProcessor(inst, ctx, json3, params);
23013
23104
  inst.unwrap = () => inst._zod.def.innerType;
23014
23105
  });
23015
23106
  function readonly(innerType) {
@@ -23021,7 +23112,7 @@ function readonly(innerType) {
23021
23112
  var ZodTemplateLiteral = /* @__PURE__ */ $constructor("ZodTemplateLiteral", (inst, def) => {
23022
23113
  $ZodTemplateLiteral.init(inst, def);
23023
23114
  ZodType.init(inst, def);
23024
- inst._zod.processJSONSchema = (ctx, json2, params) => templateLiteralProcessor(inst, ctx, json2, params);
23115
+ inst._zod.processJSONSchema = (ctx, json3, params) => templateLiteralProcessor(inst, ctx, json3, params);
23025
23116
  });
23026
23117
  function templateLiteral(parts, params) {
23027
23118
  return new ZodTemplateLiteral({
@@ -23033,7 +23124,7 @@ function templateLiteral(parts, params) {
23033
23124
  var ZodLazy = /* @__PURE__ */ $constructor("ZodLazy", (inst, def) => {
23034
23125
  $ZodLazy.init(inst, def);
23035
23126
  ZodType.init(inst, def);
23036
- inst._zod.processJSONSchema = (ctx, json2, params) => lazyProcessor(inst, ctx, json2, params);
23127
+ inst._zod.processJSONSchema = (ctx, json3, params) => lazyProcessor(inst, ctx, json3, params);
23037
23128
  inst.unwrap = () => inst._zod.def.getter();
23038
23129
  });
23039
23130
  function lazy(getter) {
@@ -23045,7 +23136,7 @@ function lazy(getter) {
23045
23136
  var ZodPromise = /* @__PURE__ */ $constructor("ZodPromise", (inst, def) => {
23046
23137
  $ZodPromise.init(inst, def);
23047
23138
  ZodType.init(inst, def);
23048
- inst._zod.processJSONSchema = (ctx, json2, params) => promiseProcessor(inst, ctx, json2, params);
23139
+ inst._zod.processJSONSchema = (ctx, json3, params) => promiseProcessor(inst, ctx, json3, params);
23049
23140
  inst.unwrap = () => inst._zod.def.innerType;
23050
23141
  });
23051
23142
  function promise(innerType) {
@@ -23057,7 +23148,7 @@ function promise(innerType) {
23057
23148
  var ZodFunction = /* @__PURE__ */ $constructor("ZodFunction", (inst, def) => {
23058
23149
  $ZodFunction.init(inst, def);
23059
23150
  ZodType.init(inst, def);
23060
- inst._zod.processJSONSchema = (ctx, json2, params) => functionProcessor(inst, ctx, json2, params);
23151
+ inst._zod.processJSONSchema = (ctx, json3, params) => functionProcessor(inst, ctx, json3, params);
23061
23152
  });
23062
23153
  function _function(params) {
23063
23154
  return new ZodFunction({
@@ -23069,7 +23160,7 @@ function _function(params) {
23069
23160
  var ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => {
23070
23161
  $ZodCustom.init(inst, def);
23071
23162
  ZodType.init(inst, def);
23072
- inst._zod.processJSONSchema = (ctx, json2, params) => customProcessor(inst, ctx, json2, params);
23163
+ inst._zod.processJSONSchema = (ctx, json3, params) => customProcessor(inst, ctx, json3, params);
23073
23164
  });
23074
23165
  function check(fn) {
23075
23166
  const ch = new $ZodCheck({
@@ -24158,7 +24249,7 @@ var RULES = [
24158
24249
  // DATABASE_URL=..., OPENAI_API_KEY="...", export AWS_SECRET_ACCESS_KEY=...
24159
24250
  name: "sensitive-assignment",
24160
24251
  pattern: new RegExp(`\\b(${SENSITIVE_KEY})(\\s*[=:]\\s*)("[^"\\n]*"|'[^'\\n]*'|[^\\s"',;]+)`, "g"),
24161
- replace: (_m, key3, sep3) => `${key3}${sep3.includes(":") ? ": " : "="}[REDACTED]`
24252
+ replace: (_m, key3, sep4) => `${key3}${sep4.includes(":") ? ": " : "="}[REDACTED]`
24162
24253
  },
24163
24254
  {
24164
24255
  // aws configure set aws_secret_access_key VALUE
@@ -24170,7 +24261,7 @@ var RULES = [
24170
24261
  // password=..., "token": "...", api_key: ...
24171
24262
  name: "credential-field",
24172
24263
  pattern: /(["']?)\b(password|passwd|pwd|pass|secret|token|api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|id[_-]?token|client[_-]?secret|auth[_-]?token|private[_-]?key)\b\1(\s*[=:]\s*)("[^"\n]*"|'[^'\n]*'|[^\s&,;"'}]+)/gi,
24173
- replace: (_m, q2, key3, sep3) => `${q2}${key3}${q2}${sep3}[REDACTED]`
24264
+ replace: (_m, q2, key3, sep4) => `${q2}${key3}${q2}${sep4}[REDACTED]`
24174
24265
  },
24175
24266
  {
24176
24267
  name: "authorization-header",
@@ -24221,25 +24312,39 @@ var RULES = [
24221
24312
  replace: "[REDACTED_TOKEN]"
24222
24313
  }
24223
24314
  ];
24224
- function currentUserPattern() {
24225
- let name;
24315
+ var COMMON_NAMES = /* @__PURE__ */ new Set([
24316
+ // System, CI and container accounts
24317
+ ...["root", "admin", "administrator", "user", "guest", "test", "tester", "dev", "developer", "build", "builder"],
24318
+ ...["runner", "deploy", "app", "node", "git", "www", "web", "server", "ubuntu", "debian", "centos", "fedora"],
24319
+ ...["alpine", "vagrant", "docker", "jenkins", "codespace", "vscode", "coder", "gitpod", "default", "owner"],
24320
+ ...["local", "home", "work", "ops", "operator", "service", "bot", "agent", "demo", "sandbox", "main", "master"],
24321
+ // Given names that are also everyday words
24322
+ ...["will", "mark", "max", "bill", "rob", "pat", "sue", "may", "june", "april", "august", "art", "grant"],
24323
+ ...["hunter", "chase", "rose", "frank", "gene", "ray", "jack", "joy", "hope", "grace", "dawn", "summer", "guy"]
24324
+ ]);
24325
+ function currentUserName() {
24226
24326
  try {
24227
- name = process.env.REFLEX_REDACT_USER ?? userInfo().username;
24327
+ return process.env.REFLEX_REDACT_USER ?? userInfo().username;
24228
24328
  } catch {
24229
- name = void 0;
24329
+ return void 0;
24230
24330
  }
24231
- if (!name || name.length < 3) return void 0;
24232
- const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24233
- return new RegExp(`\\b${escaped}\\b`, "gi");
24234
24331
  }
24235
- var userPattern = currentUserPattern();
24236
- function redactionFingerprint() {
24237
- let name = "";
24238
- try {
24239
- name = process.env.REFLEX_REDACT_USER ?? userInfo().username;
24240
- } catch {
24241
- name = "";
24332
+ var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24333
+ function userRules() {
24334
+ const rules2 = [];
24335
+ const name = currentUserName();
24336
+ const homeFolder = homedir().replace(/[\\/]+$/, "");
24337
+ if (homeFolder.length >= 2) {
24338
+ rules2.push({ name: "home", pattern: new RegExp(`(?<![\\w.-])${escapeRegExp(homeFolder)}(?![\\w.-])`, "g"), replace: "~" });
24339
+ }
24340
+ if (name && name.length >= 3 && !COMMON_NAMES.has(name.toLowerCase())) {
24341
+ rules2.push({ name: "username", pattern: new RegExp(`\\b${escapeRegExp(name)}\\b`, "gi"), replace: "<user>" });
24242
24342
  }
24343
+ return rules2;
24344
+ }
24345
+ var USER_RULES = userRules();
24346
+ function redactionFingerprint() {
24347
+ const name = currentUserName() ?? "";
24243
24348
  return createHash2("sha256").update(`${name}
24244
24349
  ${homedir()}`).digest("hex").slice(0, 16);
24245
24350
  }
@@ -24254,37 +24359,34 @@ function redactDeep(value) {
24254
24359
  function redactWithReport(input2) {
24255
24360
  let text = input2;
24256
24361
  let redactions = 0;
24257
- const rules = /* @__PURE__ */ new Set();
24258
- for (const rule of RULES) {
24362
+ const rules2 = /* @__PURE__ */ new Set();
24363
+ for (const rule of [...RULES, ...USER_RULES]) {
24259
24364
  text = text.replace(rule.pattern, (...args) => {
24260
24365
  redactions++;
24261
- rules.add(rule.name);
24366
+ rules2.add(rule.name);
24262
24367
  if (typeof rule.replace === "string") return rule.replace;
24263
24368
  const offsetIndex = args.findIndex((a) => typeof a === "number");
24264
24369
  const groups = args.slice(0, offsetIndex).map((a) => typeof a === "string" ? a : "");
24265
24370
  return rule.replace(...groups);
24266
24371
  });
24267
24372
  }
24268
- if (userPattern) {
24269
- text = text.replace(userPattern, () => {
24270
- redactions++;
24271
- rules.add("username");
24272
- return "<user>";
24273
- });
24274
- }
24275
- return { text, redactions, rules: [...rules] };
24373
+ return { text, redactions, rules: [...rules2] };
24276
24374
  }
24277
24375
  function redact(input2) {
24278
24376
  return redactWithReport(input2).text;
24279
24377
  }
24280
- var PATH_RULES = /* @__PURE__ */ new Set(["macos-home", "linux-home", "windows-home", "encoded-home", "email"]);
24378
+ var PATH_RULES = /* @__PURE__ */ new Set(["macos-home", "linux-home", "windows-home", "encoded-home", "email", "home", "username"]);
24281
24379
  function redactPath(input2) {
24282
24380
  let text = input2;
24283
- for (const rule of RULES) {
24381
+ for (const rule of [...RULES, ...USER_RULES]) {
24284
24382
  if (!PATH_RULES.has(rule.name) || typeof rule.replace !== "string") continue;
24285
24383
  text = text.replace(rule.pattern, rule.replace);
24286
24384
  }
24287
- return userPattern ? text.replace(userPattern, "<user>") : text;
24385
+ return text;
24386
+ }
24387
+ var REDACT_MARGIN = 1024;
24388
+ function redactTruncated(input2, max) {
24389
+ return redact(input2.slice(0, max + REDACT_MARGIN)).slice(0, max);
24288
24390
  }
24289
24391
  function excerpt(input2, maxLength = 160) {
24290
24392
  const flat = redact(input2).replace(/\s+/g, " ").trim();
@@ -24385,6 +24487,47 @@ async function replaceOwnedFile(path, content, mode = 420) {
24385
24487
  }
24386
24488
  }
24387
24489
 
24490
+ // ../../packages/safety/src/spawn.ts
24491
+ import { statSync } from "node:fs";
24492
+ import { posix, win32 } from "node:path";
24493
+ var isFile = (path) => {
24494
+ try {
24495
+ return statSync(path).isFile();
24496
+ } catch {
24497
+ return false;
24498
+ }
24499
+ };
24500
+ function findOnPath(name, host = {}) {
24501
+ const env = host.env ?? process.env;
24502
+ const exists2 = host.isFile ?? isFile;
24503
+ if ((host.platform ?? process.platform) !== "win32") {
24504
+ for (const dir of (env.PATH ?? "").split(posix.delimiter)) if (dir && exists2(posix.join(dir, name))) return posix.join(dir, name);
24505
+ return void 0;
24506
+ }
24507
+ const exts = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").toLowerCase().split(";").filter(Boolean);
24508
+ const names = exts.some((e2) => name.toLowerCase().endsWith(e2)) ? [name] : exts.map((e2) => name + e2);
24509
+ for (const dir of (env.Path ?? env.PATH ?? "").split(win32.delimiter)) {
24510
+ if (!dir) continue;
24511
+ for (const n of names) if (exists2(win32.join(dir, n))) return win32.join(dir, n);
24512
+ }
24513
+ return void 0;
24514
+ }
24515
+ var UNSAFE_FOR_CMD = /["%\r\n\0]/;
24516
+ function agentLaunch(command, args, host = {}) {
24517
+ if ((host.platform ?? process.platform) !== "win32") return { command, args };
24518
+ const path = findOnPath(command, host);
24519
+ if (!path) return { command, args };
24520
+ if (!/\.(cmd|bat)$/i.test(path)) return { command: path, args };
24521
+ if ([path, ...args].some((a) => UNSAFE_FOR_CMD.test(a))) {
24522
+ throw new Error(
24523
+ `${win32.basename(path)} is a Windows batch launcher, which can't be given quotes, % or line breaks safely. Leave them out, or install ${command} as an .exe.`
24524
+ );
24525
+ }
24526
+ const line2 = [path, ...args].map((a) => `"${a.replace(/(\\+)$/, "$1$1")}"`).join(" ");
24527
+ const env = host.env ?? process.env;
24528
+ return { command: env.ComSpec ?? "cmd.exe", args: ["/d", "/s", "/v:off", "/c", `"${line2}"`], windowsVerbatimArguments: true };
24529
+ }
24530
+
24388
24531
  // ../../packages/adapters/src/jsonl.ts
24389
24532
  import { createReadStream } from "node:fs";
24390
24533
  import { createInterface as createInterface2 } from "node:readline";
@@ -24392,19 +24535,19 @@ var MAX_LINE_BYTES = 4 * 1024 * 1024;
24392
24535
  async function* readJsonl(path) {
24393
24536
  const stream = createReadStream(path, { encoding: "utf8" });
24394
24537
  const rl = createInterface2({ input: stream, crlfDelay: Infinity });
24395
- let line = 0;
24538
+ let line2 = 0;
24396
24539
  try {
24397
24540
  for await (const raw of rl) {
24398
- line++;
24541
+ line2++;
24399
24542
  if (!raw.trim()) continue;
24400
24543
  if (raw.length > MAX_LINE_BYTES) {
24401
- yield { line, error: "too-large" };
24544
+ yield { line: line2, error: "too-large" };
24402
24545
  continue;
24403
24546
  }
24404
24547
  try {
24405
- yield { line, value: JSON.parse(raw) };
24548
+ yield { line: line2, value: JSON.parse(raw) };
24406
24549
  } catch {
24407
- yield { line, error: "invalid-json" };
24550
+ yield { line: line2, error: "invalid-json" };
24408
24551
  }
24409
24552
  }
24410
24553
  } finally {
@@ -24422,10 +24565,10 @@ var MAX_REQUEST_CHARS = 2e3;
24422
24565
  var MAX_COMMAND_CHARS = 600;
24423
24566
  var MAX_ASSISTANT_CHARS = 400;
24424
24567
  var clean = {
24425
- request: (text) => redact(text.slice(0, MAX_REQUEST_CHARS)).trim(),
24426
- command: (text) => redact(text.slice(0, MAX_COMMAND_CHARS)).trim(),
24427
- assistant: (text) => redact(text.slice(0, MAX_ASSISTANT_CHARS)).trim(),
24428
- path: (text) => redact(text.slice(0, 400))
24568
+ request: (text) => redactTruncated(text, MAX_REQUEST_CHARS).trim(),
24569
+ command: (text) => redactTruncated(text, MAX_COMMAND_CHARS).trim(),
24570
+ assistant: (text) => redactTruncated(text, MAX_ASSISTANT_CHARS).trim(),
24571
+ path: (text) => redactTruncated(text, 400)
24429
24572
  };
24430
24573
  function isHarnessText(text) {
24431
24574
  const t = text.trimStart();
@@ -24444,13 +24587,13 @@ function patchedFiles(patch) {
24444
24587
  async function listFiles(dir, ext, depth) {
24445
24588
  const out2 = [];
24446
24589
  async function walk(current, level) {
24447
- let entries;
24590
+ let entries2;
24448
24591
  try {
24449
- entries = await readdir(current, { withFileTypes: true });
24592
+ entries2 = await readdir(current, { withFileTypes: true });
24450
24593
  } catch {
24451
24594
  return;
24452
24595
  }
24453
- for (const entry of entries) {
24596
+ for (const entry of entries2) {
24454
24597
  if (entry.isSymbolicLink()) continue;
24455
24598
  const full = join2(current, entry.name);
24456
24599
  if (level < depth) {
@@ -24647,13 +24790,13 @@ var ClaudeCodeAdapter = class {
24647
24790
  let skippedRecords = 0;
24648
24791
  const fallbackId = basename2(file2.path, ".jsonl");
24649
24792
  try {
24650
- for await (const line of readJsonl(file2.path)) {
24793
+ for await (const line2 of readJsonl(file2.path)) {
24651
24794
  totalRecords++;
24652
- if (line.error) {
24795
+ if (line2.error) {
24653
24796
  skippedRecords++;
24654
24797
  continue;
24655
24798
  }
24656
- const parsed = ClaudeRecord.safeParse(line.value);
24799
+ const parsed = ClaudeRecord.safeParse(line2.value);
24657
24800
  if (!parsed.success) {
24658
24801
  skippedRecords++;
24659
24802
  continue;
@@ -24835,27 +24978,27 @@ var CodexAdapter = class {
24835
24978
  const eventUserMessages = [];
24836
24979
  let model2;
24837
24980
  try {
24838
- for await (const line of readJsonl(file2.path)) {
24981
+ for await (const line2 of readJsonl(file2.path)) {
24839
24982
  totalRecords++;
24840
- if (line.error) {
24983
+ if (line2.error) {
24841
24984
  skippedRecords++;
24842
24985
  continue;
24843
24986
  }
24844
- const wrapped = RolloutLine.safeParse(line.value);
24987
+ const wrapped = RolloutLine.safeParse(line2.value);
24845
24988
  if (!wrapped.success) {
24846
24989
  skippedRecords++;
24847
24990
  continue;
24848
24991
  }
24849
24992
  const at = wrapped.data.timestamp;
24850
24993
  const kind = wrapped.data.type;
24851
- const body = wrapped.data.payload ?? line.value;
24994
+ const body = wrapped.data.payload ?? line2.value;
24852
24995
  b3.touch(at);
24853
24996
  if (kind === "session_meta") {
24854
- const meta3 = Item.safeParse({ type: "session_meta", ...body });
24855
- if (meta3.success) {
24856
- if (meta3.data.id) b3.nativeId = meta3.data.id.slice(0, 80);
24857
- if (meta3.data.cwd) b3.cwd = meta3.data.cwd;
24858
- b3.touch(meta3.data.timestamp);
24997
+ const meta4 = Item.safeParse({ type: "session_meta", ...body });
24998
+ if (meta4.success) {
24999
+ if (meta4.data.id) b3.nativeId = meta4.data.id.slice(0, 80);
25000
+ if (meta4.data.cwd) b3.cwd = meta4.data.cwd;
25001
+ b3.touch(meta4.data.timestamp);
24859
25002
  }
24860
25003
  continue;
24861
25004
  }
@@ -24951,7 +25094,7 @@ var CodexAdapter = class {
24951
25094
  };
24952
25095
 
24953
25096
  // ../../packages/adapters/src/cursor.ts
24954
- import { existsSync, statSync } from "node:fs";
25097
+ import { existsSync, statSync as statSync2 } from "node:fs";
24955
25098
  import { lstat as lstat3, readdir as readdir2 } from "node:fs/promises";
24956
25099
  import { homedir as homedir6 } from "node:os";
24957
25100
  import { basename as basename4, dirname as dirname2, join as join6 } from "node:path";
@@ -25014,6 +25157,95 @@ var CursorModelIndex = class {
25014
25157
  }
25015
25158
  };
25016
25159
 
25160
+ // ../../packages/adapters/src/cursor-usage.ts
25161
+ import { closeSync, fstatSync, openSync, readSync } from "node:fs";
25162
+ var MAX_LOG_BYTES = 64 * 1024 * 1024;
25163
+ var ID2 = /^[A-Za-z0-9-]{1,80}$/;
25164
+ var MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,79}$/;
25165
+ var CLAUDE = /^(?:claude-)?(?:(\d+(?:[.-]\d+)?)-(opus|sonnet|haiku|fable|mythos)|(opus|sonnet|haiku|fable|mythos)-(\d+(?:[.-]\d+)?))(?:-.*)?$/;
25166
+ function cursorModelName(id) {
25167
+ const m2 = id.toLowerCase().match(CLAUDE);
25168
+ if (!m2) return id;
25169
+ const name = `claude-${m2[2] ?? m2[3]}-${(m2[1] ?? m2[4]).replace(".", "-")}`;
25170
+ return priceOf(name) ? name : id;
25171
+ }
25172
+ function tail(path, max) {
25173
+ let fd;
25174
+ try {
25175
+ fd = openSync(path, "r");
25176
+ const size2 = fstatSync(fd).size;
25177
+ const start = Math.max(0, size2 - max);
25178
+ const buf = Buffer.alloc(size2 - start);
25179
+ readSync(fd, buf, 0, buf.length, start);
25180
+ const text = buf.toString("utf8");
25181
+ return start ? text.slice(text.indexOf("\n") + 1) : text;
25182
+ } catch {
25183
+ return "";
25184
+ } finally {
25185
+ if (fd !== void 0) closeSync(fd);
25186
+ }
25187
+ }
25188
+ var count = (v2) => typeof v2 === "number" && Number.isFinite(v2) && v2 > 0 ? Math.round(v2) : 0;
25189
+ var CursorUsageLog = class {
25190
+ constructor(path) {
25191
+ this.path = path;
25192
+ }
25193
+ path;
25194
+ turns;
25195
+ load() {
25196
+ if (this.turns) return this.turns;
25197
+ const turns = /* @__PURE__ */ new Map();
25198
+ this.turns = turns;
25199
+ for (const line2 of tail(this.path, MAX_LOG_BYTES).split("\n")) {
25200
+ let r2;
25201
+ try {
25202
+ r2 = JSON.parse(line2);
25203
+ } catch {
25204
+ continue;
25205
+ }
25206
+ const conv = typeof r2.conversation_id === "string" && ID2.test(r2.conversation_id) ? r2.conversation_id : void 0;
25207
+ const gen = typeof r2.generation_id === "string" && ID2.test(r2.generation_id) ? r2.generation_id : void 0;
25208
+ if (!conv || !gen) continue;
25209
+ const cacheRead = count(r2.cache_read_tokens);
25210
+ const cacheWrite = count(r2.cache_write_tokens);
25211
+ const usage2 = { input: Math.max(0, count(r2.input_tokens) - cacheRead - cacheWrite), output: count(r2.output_tokens), cacheRead, cacheWrite };
25212
+ const turn = {
25213
+ event: r2.event === "stop" ? "stop" : "afterAgentResponse",
25214
+ at: typeof r2.at === "string" ? Date.parse(r2.at) || 0 : 0,
25215
+ model: typeof r2.model === "string" && MODEL.test(r2.model) ? cursorModelName(r2.model) : void 0,
25216
+ usage: usage2
25217
+ };
25218
+ const byGen = turns.get(conv) ?? /* @__PURE__ */ new Map();
25219
+ turns.set(conv, byGen);
25220
+ const prev = byGen.get(gen);
25221
+ if (!prev || turn.event === "stop" || prev.event !== "stop") byGen.set(gen, turn);
25222
+ }
25223
+ return turns;
25224
+ }
25225
+ /** Usage for these conversations, in total and per model. */
25226
+ usageFor(ids) {
25227
+ let usage2;
25228
+ const byModel2 = {};
25229
+ for (const id of ids)
25230
+ for (const t of this.load().get(id)?.values() ?? []) {
25231
+ usage2 = addUsage(usage2, t.usage);
25232
+ if (t.model) byModel2[t.model] = addUsage(byModel2[t.model], t.usage);
25233
+ }
25234
+ return usage2 ? { usage: usage2, byModel: byModel2 } : void 0;
25235
+ }
25236
+ /** How many turns were recorded for these conversations, and when the latest was: part of a chat's identity for the scan cache. */
25237
+ signature(ids) {
25238
+ let turns = 0;
25239
+ let latest = 0;
25240
+ for (const id of ids)
25241
+ for (const t of this.load().get(id)?.values() ?? []) {
25242
+ turns++;
25243
+ latest = Math.max(latest, t.at);
25244
+ }
25245
+ return { turns, latest };
25246
+ }
25247
+ };
25248
+
25017
25249
  // ../../packages/adapters/src/cursor.ts
25018
25250
  var CONTROL = /[\x00-\x1f\x7f-\x9f]/g;
25019
25251
  var Block = external_exports.object({
@@ -25042,7 +25274,7 @@ var MAX_AGENT_TRANSCRIPTS = 300;
25042
25274
  async function agentTranscripts(chatFile) {
25043
25275
  return listFiles(join6(dirname2(chatFile), "subagents"), ".jsonl", 0);
25044
25276
  }
25045
- async function isFile(path) {
25277
+ async function isFile2(path) {
25046
25278
  try {
25047
25279
  return (await lstat3(path)).isFile();
25048
25280
  } catch {
@@ -25070,7 +25302,7 @@ function decodeWorkspace(encoded, root = "/") {
25070
25302
  budget--;
25071
25303
  const candidate = join6(dir, tokens2.slice(i, j2).join("-"));
25072
25304
  try {
25073
- if (existsSync(candidate) && statSync(candidate).isDirectory()) {
25305
+ if (existsSync(candidate) && statSync2(candidate).isDirectory()) {
25074
25306
  const found = walk(candidate, j2);
25075
25307
  if (found) return found;
25076
25308
  }
@@ -25089,10 +25321,21 @@ var CursorAdapter = class {
25089
25321
  /** Cursor's app database, for model names. Undefined for a custom transcript folder, which reads only that folder. */
25090
25322
  stateDb;
25091
25323
  models;
25092
- constructor(root, stateDb) {
25324
+ /** Token counts recorded by Reflex's Cursor hook, when it was turned on. */
25325
+ usage;
25326
+ constructor(root, stateDb, opts = {}) {
25093
25327
  this.root = root ?? process.env.REFLEX_CURSOR_DIR ?? join6(homedir6(), ".cursor", "projects");
25094
25328
  const custom2 = root ?? process.env.REFLEX_CURSOR_DIR;
25095
25329
  this.stateDb = stateDb ?? process.env.REFLEX_CURSOR_STATE_DB ?? (custom2 ? void 0 : defaultCursorStateDb());
25330
+ if (opts.usageLog) this.usage = new CursorUsageLog(opts.usageLog);
25331
+ }
25332
+ /**
25333
+ * The conversation ids whose recorded turns belong to this chat: the chat's own. Agents it
25334
+ * launched may report their own turns too, and whether the chat's totals already include them
25335
+ * is not known yet, so they are left out rather than possibly counted twice.
25336
+ */
25337
+ conversationIds(chatFile) {
25338
+ return [basename4(chatFile, ".jsonl")];
25096
25339
  }
25097
25340
  /** Whether the user allowed reading model names from Cursor's app database in this scan. */
25098
25341
  get readsModels() {
@@ -25122,11 +25365,11 @@ var CursorAdapter = class {
25122
25365
  }
25123
25366
  async requestPermission(ask2, days) {
25124
25367
  if (!await ask2(`Read Cursor agent sessions from the last ${days} day${days === 1 ? "" : "s"} at ${displayPath(this.root)}?`)) return false;
25125
- if (this.stateDb && await isFile(this.stateDb)) {
25126
- const allowed = await ask2(
25368
+ if (this.stateDb && await isFile2(this.stateDb)) {
25369
+ const allowed2 = await ask2(
25127
25370
  `Also read which model each Cursor chat used, from Cursor's app database at ${displayPath(this.stateDb)}? Read-only; only model names are extracted, never messages.`
25128
25371
  );
25129
- if (allowed) this.models = new CursorModelIndex(this.stateDb);
25372
+ if (allowed2) this.models = new CursorModelIndex(this.stateDb);
25130
25373
  }
25131
25374
  return true;
25132
25375
  }
@@ -25150,6 +25393,11 @@ var CursorAdapter = class {
25150
25393
  f.identity.ctimeMs = Math.max(f.identity.ctimeMs, agent.identity.ctimeMs);
25151
25394
  }
25152
25395
  }
25396
+ if (this.usage) {
25397
+ const sig = this.usage.signature(this.conversationIds(f.path));
25398
+ f.sizeBytes += sig.turns;
25399
+ if (f.identity && sig.latest) f.identity.ctimeMs = Math.max(f.identity.ctimeMs, sig.latest);
25400
+ }
25153
25401
  if (f.modifiedAt >= cutoff) out2.push(f);
25154
25402
  }
25155
25403
  return out2;
@@ -25194,6 +25442,11 @@ var CursorAdapter = class {
25194
25442
  }
25195
25443
  if (delegated.length) b3.events.splice(firstSpawn ?? b3.events.length, 0, ...delegated.slice(0, Math.max(0, MAX_EVENTS_PER_SESSION - b3.events.length)));
25196
25444
  b3.touch(file2.modifiedAt.toISOString());
25445
+ const recorded2 = this.usage?.usageFor(this.conversationIds(file2.path));
25446
+ if (recorded2) {
25447
+ b3.usage = recorded2.usage;
25448
+ if (Object.keys(recorded2.byModel).length) b3.usageByModel = recorded2.byModel;
25449
+ }
25197
25450
  const session = b3.build();
25198
25451
  if (spawned.length || transcripts) session.agents = { spawned, transcripts };
25199
25452
  if (this.models) session.models = this.models.modelsFor(b3.nativeId);
@@ -25205,13 +25458,13 @@ var CursorAdapter = class {
25205
25458
  }
25206
25459
  /** Streams a transcript's user and assistant content blocks; malformed lines and blocks are counted and skipped. */
25207
25460
  async readBlocks(path, b3, counts, onBlock) {
25208
- for await (const line of readJsonl(path)) {
25461
+ for await (const line2 of readJsonl(path)) {
25209
25462
  counts.total++;
25210
- if (line.error) {
25463
+ if (line2.error) {
25211
25464
  counts.skipped++;
25212
25465
  continue;
25213
25466
  }
25214
- const parsed = CursorRecord.safeParse(line.value);
25467
+ const parsed = CursorRecord.safeParse(line2.value);
25215
25468
  if (!parsed.success) {
25216
25469
  counts.skipped++;
25217
25470
  continue;
@@ -25801,7 +26054,7 @@ function bigrams(stems) {
25801
26054
  }
25802
26055
  var BIGRAM_BLEND = 0.3;
25803
26056
  function termSimilarities(termLists, weights) {
25804
- const stems = termLists.map((terms) => terms.map(stem));
26057
+ const stems = termLists.map((terms2) => terms2.map(stem));
25805
26058
  const words2 = buildTfIdf(stems, weights && new Map([...weights].map(([t, w2]) => [stem(t), w2]))).vectors;
25806
26059
  const pairs = buildTfIdf(stems.map(bigrams)).vectors;
25807
26060
  return (i, j2) => {
@@ -25829,9 +26082,9 @@ var CONCEPT_WORDS = {
25829
26082
  var CONCEPT_OF = /* @__PURE__ */ new Map();
25830
26083
  var DEVELOPER_WORDS = /* @__PURE__ */ new Set([...Object.values(CONCEPT_WORDS).flat(), ...Object.values(CANONICAL)]);
25831
26084
  for (const [concept, words2] of Object.entries(CONCEPT_WORDS)) for (const w2 of words2) CONCEPT_OF.set(w2, concept);
25832
- function concepts(terms) {
26085
+ function concepts(terms2) {
25833
26086
  const v2 = /* @__PURE__ */ new Map();
25834
- for (const t of terms) {
26087
+ for (const t of terms2) {
25835
26088
  const c2 = t.startsWith("@") ? "dependency" : CONCEPT_OF.get(t) ?? CONCEPT_OF.get(stem(t));
25836
26089
  if (c2) v2.set(c2, (v2.get(c2) ?? 0) + 1);
25837
26090
  }
@@ -25846,14 +26099,14 @@ function buildTfIdf(docs, weights) {
25846
26099
  for (const doc of docs) for (const term of new Set(doc)) df.set(term, (df.get(term) ?? 0) + 1);
25847
26100
  const n = docs.length;
25848
26101
  const idf = /* @__PURE__ */ new Map();
25849
- for (const [term, count2] of df) idf.set(term, Math.log((n + 1) / (count2 + 1)) + 1);
26102
+ for (const [term, count3] of df) idf.set(term, Math.log((n + 1) / (count3 + 1)) + 1);
25850
26103
  const vectors = docs.map((doc) => {
25851
26104
  const tf = /* @__PURE__ */ new Map();
25852
26105
  for (const term of doc) tf.set(term, (tf.get(term) ?? 0) + 1);
25853
26106
  const v2 = /* @__PURE__ */ new Map();
25854
26107
  let norm = 0;
25855
- for (const [term, count2] of tf) {
25856
- const w2 = (1 + Math.log(count2)) * (idf.get(term) ?? 1) * (weights?.get(term) ?? 1);
26108
+ for (const [term, count3] of tf) {
26109
+ const w2 = (1 + Math.log(count3)) * (idf.get(term) ?? 1) * (weights?.get(term) ?? 1);
25857
26110
  v2.set(term, w2);
25858
26111
  norm += w2 * w2;
25859
26112
  }
@@ -25879,24 +26132,33 @@ var WEIGHTS = {
25879
26132
  repository: 0.05
25880
26133
  };
25881
26134
  function jaccard(a, b3) {
25882
- const A3 = new Set(a);
25883
- const B2 = new Set(b3);
26135
+ return setJaccard(new Set(a), new Set(b3));
26136
+ }
26137
+ function setJaccard(A3, B2) {
25884
26138
  if (!A3.size && !B2.size) return 0;
25885
26139
  let inter = 0;
25886
26140
  for (const x2 of A3) if (B2.has(x2)) inter++;
25887
26141
  return inter / (A3.size + B2.size - inter);
25888
26142
  }
26143
+ var lcsRows = new Int32Array(0);
25889
26144
  function lcsLength(a, b3) {
25890
26145
  if (!a.length || !b3.length) return 0;
25891
- let prev = new Array(b3.length + 1).fill(0);
26146
+ const width = b3.length + 1;
26147
+ if (lcsRows.length < 2 * width) lcsRows = new Int32Array(2 * width);
26148
+ const rows2 = lcsRows;
26149
+ let prev = 0;
26150
+ let cur = width;
26151
+ rows2.fill(0, prev, prev + width);
25892
26152
  for (let i = 1; i <= a.length; i++) {
25893
- const cur = new Array(b3.length + 1).fill(0);
26153
+ rows2[cur] = 0;
25894
26154
  for (let j2 = 1; j2 <= b3.length; j2++) {
25895
- cur[j2] = a[i - 1] === b3[j2 - 1] ? prev[j2 - 1] + 1 : Math.max(prev[j2], cur[j2 - 1]);
26155
+ rows2[cur + j2] = a[i - 1] === b3[j2 - 1] ? rows2[prev + j2 - 1] + 1 : Math.max(rows2[prev + j2], rows2[cur + j2 - 1]);
25896
26156
  }
26157
+ const done = prev;
25897
26158
  prev = cur;
26159
+ cur = done;
25898
26160
  }
25899
- return prev[b3.length];
26161
+ return rows2[prev + b3.length];
25900
26162
  }
25901
26163
  var COARSE = {
25902
26164
  "inspect-git": "git",
@@ -25920,16 +26182,21 @@ var COARSE = {
25920
26182
  function collapse(seq) {
25921
26183
  return seq.filter((s, i) => i === 0 || seq[i - 1] !== s);
25922
26184
  }
26185
+ var steps = (seq) => ({ seq, set: new Set(seq) });
26186
+ function actionShape(sequence) {
26187
+ const fine = sequence.filter((s) => s !== "summarize");
26188
+ return { fine: steps(fine), coarse: steps(collapse(fine.map((v2) => COARSE[v2] ?? v2))) };
26189
+ }
25923
26190
  function sequenceAgreement(x2, y3) {
25924
- if (!x2.length || !y3.length) return 0;
25925
- const lcs = 2 * lcsLength(x2, y3) / (x2.length + y3.length);
25926
- return 0.5 * lcs + 0.5 * jaccard(x2, y3);
26191
+ if (!x2.seq.length || !y3.seq.length) return 0;
26192
+ const lcs = 2 * lcsLength(x2.seq, y3.seq) / (x2.seq.length + y3.seq.length);
26193
+ return 0.5 * lcs + 0.5 * setJaccard(x2.set, y3.set);
26194
+ }
26195
+ function shapeSimilarity(a, b3) {
26196
+ return 0.5 * sequenceAgreement(a.fine, b3.fine) + 0.5 * sequenceAgreement(a.coarse, b3.coarse);
25927
26197
  }
25928
26198
  function actionSimilarity(a, b3) {
25929
- const x2 = a.filter((s) => s !== "summarize");
25930
- const y3 = b3.filter((s) => s !== "summarize");
25931
- const coarse = (s) => collapse(s.map((v2) => COARSE[v2] ?? v2));
25932
- return 0.5 * sequenceAgreement(x2, y3) + 0.5 * sequenceAgreement(coarse(x2), coarse(y3));
26199
+ return shapeSimilarity(actionShape(a), actionShape(b3));
25933
26200
  }
25934
26201
  function opKeys(t) {
25935
26202
  const keys = new Set(t.commands.map(opKey));
@@ -25941,12 +26208,15 @@ function opKeys(t) {
25941
26208
  keys.delete("");
25942
26209
  return keys;
25943
26210
  }
25944
- function similarity(a, b3, intentScore, keysA = opKeys(a), keysB = opKeys(b3)) {
26211
+ function traceFeatures(t) {
26212
+ return { actions: actionShape(t.actionSequence), keys: opKeys(t), files: new Set(t.fileCategories) };
26213
+ }
26214
+ function similarity(a, b3, intentScore, fa = traceFeatures(a), fb = traceFeatures(b3)) {
25945
26215
  const parts = {
25946
26216
  intent: intentScore,
25947
- actions: actionSimilarity(a.actionSequence, b3.actionSequence),
25948
- commands: jaccard(keysA, keysB),
25949
- files: jaccard(a.fileCategories, b3.fileCategories),
26217
+ actions: shapeSimilarity(fa.actions, fb.actions),
26218
+ commands: setJaccard(fa.keys, fb.keys),
26219
+ files: setJaccard(fa.files, fb.files),
25950
26220
  repository: a.projectHash && a.projectHash === b3.projectHash ? 1 : 0
25951
26221
  };
25952
26222
  const total = WEIGHTS.intent * parts.intent + WEIGHTS.actions * parts.actions + WEIGHTS.commands * parts.commands + WEIGHTS.files * parts.files + WEIGHTS.repository * parts.repository;
@@ -26040,8 +26310,11 @@ function render(polarity, ws) {
26040
26310
  return polarity === "avoid" ? `Don't ${phrase}.` : `${phrase[0].toUpperCase()}${phrase.slice(1)}.`;
26041
26311
  }
26042
26312
  function recurringCorrections(perInstance) {
26313
+ return recurringCorrectionsBySession(perInstance).map(({ instances: _3, ...c2 }) => c2);
26314
+ }
26315
+ function recurringCorrectionsBySession(perInstance) {
26043
26316
  const items = perInstance.flatMap((cs, inst) => cs.map((c2) => ({ ...c2, inst, keys: matchKeys(c2.words) })));
26044
- const rules = /* @__PURE__ */ new Map();
26317
+ const rules2 = /* @__PURE__ */ new Map();
26045
26318
  for (let i = 0; i < items.length; i++) {
26046
26319
  for (let j2 = i + 1; j2 < items.length; j2++) {
26047
26320
  const a = items[i];
@@ -26051,16 +26324,16 @@ function recurringCorrections(perInstance) {
26051
26324
  const shared = a.words.filter((_3, k3) => other.has(a.keys[k3]));
26052
26325
  if (!wellFormed(a.polarity, shared)) continue;
26053
26326
  const id = `${a.polarity}:${shared.join(" ")}`;
26054
- const rule = rules.get(id) ?? { polarity: a.polarity, words: shared, sessions: /* @__PURE__ */ new Set() };
26327
+ const rule = rules2.get(id) ?? { polarity: a.polarity, words: shared, sessions: /* @__PURE__ */ new Set() };
26055
26328
  rule.sessions.add(a.inst).add(b3.inst);
26056
- rules.set(id, rule);
26329
+ rules2.set(id, rule);
26057
26330
  }
26058
26331
  }
26059
- const all = [...rules.values()];
26332
+ const all = [...rules2.values()];
26060
26333
  const covered = (r2) => all.some(
26061
26334
  (s) => s !== r2 && s.polarity === r2.polarity && s.words.length < r2.words.length && s.words.every((w2) => r2.words.includes(w2)) && [...r2.sessions].every((x2) => s.sessions.has(x2))
26062
26335
  );
26063
- return all.filter((r2) => !covered(r2)).map((r2) => ({ polarity: r2.polarity, text: render(r2.polarity, r2.words), sessions: r2.sessions.size })).sort((a, b3) => b3.sessions - a.sessions || a.text.localeCompare(b3.text));
26336
+ return all.filter((r2) => !covered(r2)).map((r2) => ({ polarity: r2.polarity, text: render(r2.polarity, r2.words), sessions: r2.sessions.size, instances: [...r2.sessions].sort((a, b3) => a - b3) })).sort((a, b3) => b3.sessions - a.sessions || a.text.localeCompare(b3.text));
26064
26337
  }
26065
26338
 
26066
26339
  // ../../packages/analysis/src/context.ts
@@ -26068,12 +26341,12 @@ function withFloor(vectors, floor) {
26068
26341
  return Object.assign(vectors, { floor });
26069
26342
  }
26070
26343
  var CONTEXT_CHARS = 2e3;
26071
- function isNoiseLine(line) {
26072
- return /^\s*at\s/.test(line) || /\d{4}-\d\d-\d\dT\d\d:\d\d/.test(line) || /^\s*[✓✗✔✘×√]\s/.test(line) || /^\s*\[[\w-]+\]/.test(line) || // Mostly digits and symbols. Letters of any script count, so non-English text is never noise.
26073
- line.length > 30 && (line.match(new RegExp("\\p{L}{2,}", "gu")) ?? []).join("").length / line.length < 0.4;
26344
+ function isNoiseLine(line2) {
26345
+ return /^\s*at\s/.test(line2) || /\d{4}-\d\d-\d\dT\d\d:\d\d/.test(line2) || /^\s*[✓✗✔✘×√]\s/.test(line2) || /^\s*\[[\w-]+\]/.test(line2) || // Mostly digits and symbols. Letters of any script count, so non-English text is never noise.
26346
+ line2.length > 30 && (line2.match(new RegExp("\\p{L}{2,}", "gu")) ?? []).join("").length / line2.length < 0.4;
26074
26347
  }
26075
26348
  function requestWords(text) {
26076
- const kept = text.replace(/```[\s\S]*?(```|$)/g, " ").split("\n").filter((line) => !isNoiseLine(line)).join("\n").replace(/\bat [\w.<>$]+ \([^)]*:\d+:\d+\)/g, " ").trim();
26349
+ const kept = text.replace(/```[\s\S]*?(```|$)/g, " ").split("\n").filter((line2) => !isNoiseLine(line2)).join("\n").replace(/\bat [\w.<>$]+ \([^)]*:\d+:\d+\)/g, " ").trim();
26077
26350
  return kept || text;
26078
26351
  }
26079
26352
  function contextDocument(t, request) {
@@ -26122,8 +26395,8 @@ function usedSkill(trace, name) {
26122
26395
  return (trace.skillsUsed ?? []).some((s) => s === name || s.endsWith(`:${name}`));
26123
26396
  }
26124
26397
  function buildTrace(session) {
26125
- const steps = [];
26126
- const commands = [];
26398
+ const steps2 = [];
26399
+ const commands2 = [];
26127
26400
  const tools = /* @__PURE__ */ new Set();
26128
26401
  const fileCategories = /* @__PURE__ */ new Set();
26129
26402
  const eventHashes = [];
@@ -26140,8 +26413,8 @@ function buildTrace(session) {
26140
26413
  tools.add("shell");
26141
26414
  for (const s of skillsIn(ev.command)) skills.add(s);
26142
26415
  for (const fp of classifyCommand(ev.command)) {
26143
- commands.push(ev.isError ? { ...fp, failed: true } : fp);
26144
- steps.push({ action: fp.action, isError: ev.isError, command: fp });
26416
+ commands2.push(ev.isError ? { ...fp, failed: true } : fp);
26417
+ steps2.push({ action: fp.action, isError: ev.isError, command: fp });
26145
26418
  show2(fp.normalized);
26146
26419
  }
26147
26420
  eventHashes.push(shortHash(`shell|${ev.at ?? ""}|${ev.command}`));
@@ -26152,7 +26425,7 @@ function buildTrace(session) {
26152
26425
  if (ev.op === "read") for (const s of skillsIn(ev.path)) skills.add(s);
26153
26426
  const category = fileCategory(ev.path);
26154
26427
  fileCategories.add(category);
26155
- steps.push({ action: fileAction(ev.op, category), isError: ev.isError });
26428
+ steps2.push({ action: fileAction(ev.op, category), isError: ev.isError });
26156
26429
  show2(`${ev.op === "read" ? "read" : "edit"} ${FILE_LABEL[category]}`);
26157
26430
  eventHashes.push(shortHash(`file|${ev.at ?? ""}|${ev.op}|${ev.path}`));
26158
26431
  break;
@@ -26162,7 +26435,7 @@ function buildTrace(session) {
26162
26435
  if (ev.skill) skills.add(ev.skill);
26163
26436
  const action = TOOL_ACTIONS[ev.tool];
26164
26437
  if (action) {
26165
- steps.push({ action, isError: ev.isError });
26438
+ steps2.push({ action, isError: ev.isError });
26166
26439
  show2(action === "search-code" ? "search code" : "look up docs");
26167
26440
  }
26168
26441
  break;
@@ -26174,14 +26447,14 @@ function buildTrace(session) {
26174
26447
  break;
26175
26448
  }
26176
26449
  }
26177
- for (const fp of commands) {
26450
+ for (const fp of commands2) {
26178
26451
  if (fp.action === "inspect-ci") fileCategories.add("ci-config");
26179
26452
  if (fp.action === "inspect-dependencies" && /<file>/.test(fp.normalized)) fileCategories.add("dependency-manifest");
26180
26453
  }
26181
26454
  const lastAssistant = [...session.events].reverse().find((e2) => e2.kind !== "error");
26182
26455
  const summarized = lastAssistant?.kind === "assistant";
26183
26456
  const actionSequence = [];
26184
- for (const s of steps) {
26457
+ for (const s of steps2) {
26185
26458
  if (actionSequence[actionSequence.length - 1] !== s.action) actionSequence.push(s.action);
26186
26459
  }
26187
26460
  if (summarized) actionSequence.push("summarize");
@@ -26200,11 +26473,11 @@ function buildTrace(session) {
26200
26473
  projectHash: session.project?.pathHash,
26201
26474
  intents,
26202
26475
  tools: [...tools].sort(),
26203
- commands,
26476
+ commands: commands2,
26204
26477
  fileCategories: [...fileCategories].sort(),
26205
26478
  actionSequence: actionSequence.slice(0, MAX_SEQUENCE),
26206
26479
  displaySteps,
26207
- outcome: outcomeOf(steps, summarized),
26480
+ outcome: outcomeOf(steps2, summarized),
26208
26481
  excerpt: excerpt(session.requests[0]?.text ?? "", 180),
26209
26482
  fingerprint,
26210
26483
  eventHashes,
@@ -26237,14 +26510,14 @@ function summarizeAgents(session) {
26237
26510
  toolCalls: session.events.filter((e2) => (e2.kind === "shell" || e2.kind === "file" || e2.kind === "tool") && e2.byAgent).length
26238
26511
  };
26239
26512
  }
26240
- function outcomeOf(steps, summarized) {
26513
+ function outcomeOf(steps2, summarized) {
26241
26514
  let lastModify = -1;
26242
- steps.forEach((s, i) => {
26515
+ steps2.forEach((s, i) => {
26243
26516
  if (MODIFY_ACTIONS.has(s.action)) lastModify = i;
26244
26517
  });
26245
- const verified = steps.some((s, i) => i > lastModify && VERIFY_ACTIONS.has(s.action) && !s.isError);
26246
- const failedAt = steps.findIndex((s) => s.isError);
26247
- const recoveredFromFailure = failedAt >= 0 && steps.slice(failedAt + 1).some((s) => VERIFY_ACTIONS.has(s.action) && !s.isError);
26518
+ const verified = steps2.some((s, i) => i > lastModify && VERIFY_ACTIONS.has(s.action) && !s.isError);
26519
+ const failedAt = steps2.findIndex((s) => s.isError);
26520
+ const recoveredFromFailure = failedAt >= 0 && steps2.slice(failedAt + 1).some((s) => VERIFY_ACTIONS.has(s.action) && !s.isError);
26248
26521
  return { verified, recoveredFromFailure, modified: lastModify >= 0, summarized };
26249
26522
  }
26250
26523
  function isGenericTrace(trace) {
@@ -26362,6 +26635,30 @@ function fillerWeights(traces) {
26362
26635
  var CLUSTER_THRESHOLD = 0.45;
26363
26636
  var MIN_INTENT_COHESION = 0.2;
26364
26637
  var MIN_INTENT_LINK = 0.35;
26638
+ var PairMatrix = class _PairMatrix {
26639
+ constructor(size2) {
26640
+ this.size = size2;
26641
+ this.values = new Float64Array(size2 * (size2 - 1) / 2);
26642
+ }
26643
+ size;
26644
+ values;
26645
+ index(i, j2) {
26646
+ const a = i < j2 ? i : j2;
26647
+ const b3 = i < j2 ? j2 : i;
26648
+ return a * (2 * this.size - a - 1) / 2 + b3 - a - 1;
26649
+ }
26650
+ get(i, j2) {
26651
+ return i === j2 ? 1 : this.values[this.index(i, j2)];
26652
+ }
26653
+ set(i, j2, value) {
26654
+ this.values[this.index(i, j2)] = value;
26655
+ }
26656
+ copy() {
26657
+ const m2 = new _PairMatrix(this.size);
26658
+ m2.values.set(this.values);
26659
+ return m2;
26660
+ }
26661
+ };
26365
26662
  var EMBEDDING_FLOOR = 0.05;
26366
26663
  function rescaleEmbedding(cos, floor = EMBEDDING_FLOOR) {
26367
26664
  return Math.min(1, Math.max(0, (cos - floor) / (1 - floor)));
@@ -26382,21 +26679,15 @@ function intentSimilarities(traces, vectors) {
26382
26679
  }
26383
26680
  function similarityMatrices(traces, vectors) {
26384
26681
  const intentOf = intentSimilarities(traces, vectors);
26385
- const keys = traces.map(opKeys);
26682
+ const features = traces.map(traceFeatures);
26386
26683
  const n = traces.length;
26387
- const make = () => Array.from({ length: n }, () => new Array(n).fill(1));
26388
- const m2 = { total: make(), intent: make(), actions: make() };
26684
+ const m2 = { total: new PairMatrix(n), intent: new PairMatrix(n), actions: new PairMatrix(n) };
26389
26685
  for (let i = 0; i < n; i++) {
26390
26686
  for (let j2 = i + 1; j2 < n; j2++) {
26391
- const s = similarity(traces[i], traces[j2], intentOf(i, j2), keys[i], keys[j2]);
26392
- for (const [name, v2] of [
26393
- ["total", s.total],
26394
- ["intent", s.intent],
26395
- ["actions", s.actions]
26396
- ]) {
26397
- m2[name][i][j2] = v2;
26398
- m2[name][j2][i] = v2;
26399
- }
26687
+ const s = similarity(traces[i], traces[j2], intentOf(i, j2), features[i], features[j2]);
26688
+ m2.total.set(i, j2, s.total);
26689
+ m2.intent.set(i, j2, s.intent);
26690
+ m2.actions.set(i, j2, s.actions);
26400
26691
  }
26401
26692
  }
26402
26693
  return m2;
@@ -26406,7 +26697,7 @@ function meanPairwise(matrix, members2) {
26406
26697
  let pairs = 0;
26407
26698
  for (let x2 = 0; x2 < members2.length; x2++)
26408
26699
  for (let y3 = x2 + 1; y3 < members2.length; y3++) {
26409
- total += matrix[members2[x2]][members2[y3]];
26700
+ total += matrix.get(members2[x2], members2[y3]);
26410
26701
  pairs++;
26411
26702
  }
26412
26703
  return pairs ? total / pairs : 1;
@@ -26415,37 +26706,56 @@ function clusterTraces(traces, threshold = CLUSTER_THRESHOLD, vectors, minIntent
26415
26706
  const sim = similarityMatrices(traces, vectors);
26416
26707
  const n = traces.length;
26417
26708
  const members2 = traces.map((_3, i) => [i]);
26418
- const link = sim.total.map((row) => [...row]);
26419
- const intentLink = sim.intent.map((row) => [...row]);
26709
+ const link = sim.total.copy();
26710
+ const intentLink = sim.intent.copy();
26711
+ const bestJ = new Int32Array(n).fill(-1);
26712
+ const bestLink = new Float64Array(n).fill(-1);
26713
+ const findBest = (i) => {
26714
+ bestJ[i] = -1;
26715
+ bestLink[i] = -1;
26716
+ for (let j2 = i + 1; j2 < n; j2++) {
26717
+ if (!members2[j2] || intentLink.get(i, j2) < minIntent) continue;
26718
+ const v2 = link.get(i, j2);
26719
+ if (v2 > bestLink[i]) {
26720
+ bestLink[i] = v2;
26721
+ bestJ[i] = j2;
26722
+ }
26723
+ }
26724
+ };
26725
+ for (let i = 0; i < n; i++) findBest(i);
26420
26726
  for (; ; ) {
26421
26727
  let best = -1;
26422
26728
  let bi = -1;
26423
- let bj = -1;
26424
26729
  for (let i = 0; i < n; i++) {
26425
- if (!members2[i]) continue;
26426
- for (let j2 = i + 1; j2 < n; j2++) {
26427
- if (!members2[j2] || intentLink[i][j2] < minIntent) continue;
26428
- if (link[i][j2] > best) {
26429
- best = link[i][j2];
26430
- bi = i;
26431
- bj = j2;
26432
- }
26730
+ if (members2[i] && bestJ[i] >= 0 && bestLink[i] > best) {
26731
+ best = bestLink[i];
26732
+ bi = i;
26433
26733
  }
26434
26734
  }
26435
26735
  if (bi < 0 || best < threshold) break;
26736
+ const bj = bestJ[bi];
26436
26737
  const a = members2[bi];
26437
26738
  const b3 = members2[bj];
26438
26739
  for (let k3 = 0; k3 < n; k3++) {
26439
26740
  if (!members2[k3] || k3 === bi || k3 === bj) continue;
26440
- const v2 = (a.length * link[bi][k3] + b3.length * link[bj][k3]) / (a.length + b3.length);
26441
- link[bi][k3] = v2;
26442
- link[k3][bi] = v2;
26443
- const w2 = (a.length * intentLink[bi][k3] + b3.length * intentLink[bj][k3]) / (a.length + b3.length);
26444
- intentLink[bi][k3] = w2;
26445
- intentLink[k3][bi] = w2;
26741
+ link.set(bi, k3, (a.length * link.get(bi, k3) + b3.length * link.get(bj, k3)) / (a.length + b3.length));
26742
+ intentLink.set(bi, k3, (a.length * intentLink.get(bi, k3) + b3.length * intentLink.get(bj, k3)) / (a.length + b3.length));
26446
26743
  }
26447
26744
  members2[bi] = [...a, ...b3].sort((x2, y3) => x2 - y3);
26448
26745
  members2[bj] = null;
26746
+ bestJ[bj] = -1;
26747
+ findBest(bi);
26748
+ for (let k3 = 0; k3 < bj; k3++) {
26749
+ if (!members2[k3] || k3 === bi) continue;
26750
+ if (bestJ[k3] === bi || bestJ[k3] === bj) findBest(k3);
26751
+ else if (k3 < bi && intentLink.get(k3, bi) >= minIntent) {
26752
+ const v2 = link.get(k3, bi);
26753
+ if (v2 > bestLink[k3] || v2 === bestLink[k3] && bi < bestJ[k3]) {
26754
+ bestLink[k3] = v2;
26755
+ bestJ[k3] = bi;
26756
+ }
26757
+ }
26758
+ }
26449
26759
  }
26450
26760
  return members2.filter((m2) => m2 !== null).map((m2) => ({
26451
26761
  members: m2,
@@ -26698,15 +27008,15 @@ function stepOrder(inst) {
26698
27008
  return at;
26699
27009
  }
26700
27010
  var LAST_OCCURRENCE = /* @__PURE__ */ new Set(["run-tests", "run-build", "run-lint", "inspect-diff"]);
26701
- function completionCriteria(steps) {
27011
+ function completionCriteria(steps2) {
26702
27012
  const out2 = [];
26703
- if (steps.has("inspect-ci")) out2.push("The CI-equivalent command succeeds locally where it can be reproduced.");
26704
- if (steps.has("run-tests")) out2.push("Relevant tests pass.");
26705
- if (steps.has("run-build")) out2.push("Build or typecheck succeeds.");
26706
- if (steps.has("run-lint")) out2.push("Linter passes.");
26707
- if (steps.has("inspect-diff") || steps.has("inspect-git")) out2.push("Repository state and the final diff have been reviewed; the diff contains only intended changes.");
26708
- if (steps.has("submit-review")) out2.push("The review is posted with concrete findings, or explicitly states that none were found.");
26709
- if (steps.has("summarize")) out2.push("A summary states the root cause (or findings), what changed, and how it was verified.");
27013
+ if (steps2.has("inspect-ci")) out2.push("The CI-equivalent command succeeds locally where it can be reproduced.");
27014
+ if (steps2.has("run-tests")) out2.push("Relevant tests pass.");
27015
+ if (steps2.has("run-build")) out2.push("Build or typecheck succeeds.");
27016
+ if (steps2.has("run-lint")) out2.push("Linter passes.");
27017
+ if (steps2.has("inspect-diff") || steps2.has("inspect-git")) out2.push("Repository state and the final diff have been reviewed; the diff contains only intended changes.");
27018
+ if (steps2.has("submit-review")) out2.push("The review is posted with concrete findings, or explicitly states that none were found.");
27019
+ if (steps2.has("summarize")) out2.push("A summary states the root cause (or findings), what changed, and how it was verified.");
26710
27020
  return out2;
26711
27021
  }
26712
27022
  function frequentTerms(instances, limit = 6) {
@@ -26770,15 +27080,15 @@ function analyze(traces, opts = {}) {
26770
27080
  if (cluster.members.length < MIN_INSTANCES) continue;
26771
27081
  if (cluster.intentCohesion < MIN_INTENT_COHESION || cluster.actionCohesion < MIN_ACTION_COHESION) continue;
26772
27082
  const group = cluster.members.map((i) => candidates[i]);
26773
- const steps = consensusSteps(group);
26774
- const stepKinds = new Set(steps.map((s) => s.kind));
27083
+ const steps2 = consensusSteps(group);
27084
+ const stepKinds = new Set(steps2.map((s) => s.kind));
26775
27085
  if (stepKinds.size - (stepKinds.has("summarize") ? 1 : 0) < 3) continue;
26776
- const terms = distinctiveTerms(group, context);
27086
+ const terms2 = distinctiveTerms(group, context);
26777
27087
  const frequent = frequentTerms(group);
26778
27088
  const fileCats = new Set(group.flatMap((g2) => g2.primary.fileCategories));
26779
27089
  const family = FAMILIES.filter((f) => f.requires(stepKinds, fileCats)).map((f) => ({ f, score: f.terms.filter((t) => frequent.includes(t)).length })).filter((x2) => x2.score > 0).sort((a, b3) => b3.score - a.score)[0]?.f;
26780
- const fallbackTerms = terms.slice(0, 3);
26781
- const baseSlug = family?.slug ?? toSlug(fallbackTerms.join(" ") || steps.map((s) => s.kind).slice(0, 2).join(" "));
27090
+ const fallbackTerms = terms2.slice(0, 3);
27091
+ const baseSlug = family?.slug ?? toSlug(fallbackTerms.join(" ") || steps2.map((s) => s.kind).slice(0, 2).join(" "));
26782
27092
  const inside = /* @__PURE__ */ new Map();
26783
27093
  for (const g2 of group) for (const s of skillsOf(g2)) inside.set(s, (inside.get(s) ?? 0) + 1);
26784
27094
  const rest = Math.max(1, instances.length - group.length);
@@ -26808,13 +27118,13 @@ function analyze(traces, opts = {}) {
26808
27118
  const repoNames = [...new Set(group.map((g2) => g2.primary.projectName).filter((x2) => !!x2))].sort();
26809
27119
  const sources = {};
26810
27120
  for (const id of SOURCE_IDS) {
26811
- const count2 = group.filter((g2) => g2.primary.source === id).length;
26812
- if (count2) sources[id] = count2;
27121
+ const count3 = group.filter((g2) => g2.primary.source === id).length;
27122
+ if (count3) sources[id] = count3;
26813
27123
  }
26814
27124
  const dates = group.map((g2) => g2.primary.startedAt).filter((d3) => !!d3).sort();
26815
27125
  const verifiedRate = group.filter((g2) => g2.primary.outcome.verified).length / group.length;
26816
27126
  const durations = group.map((g2) => g2.primary.startedAt && g2.primary.endedAt ? (Date.parse(g2.primary.endedAt) - Date.parse(g2.primary.startedAt)) / 6e4 : NaN).filter((m2) => Number.isFinite(m2) && m2 > 0);
26817
- const consensus = steps.reduce((acc, s) => acc + s.support, 0) / steps.length;
27127
+ const consensus = steps2.reduce((acc, s) => acc + s.support, 0) / steps2.length;
26818
27128
  const confidence = 0.3 * Math.min(1, cluster.cohesion / 0.75) + 0.2 * Math.min(1, group.length / 6) + 0.15 * Math.min(1, repos.length / 3) + 0.2 * consensus + 0.15 * verifiedRate;
26819
27129
  const notes = [];
26820
27130
  if (repos.length === 1) notes.push("All evidence comes from a single repository; the skill may be repository-specific.");
@@ -26825,8 +27135,8 @@ function analyze(traces, opts = {}) {
26825
27135
  suggestions.push({
26826
27136
  slug,
26827
27137
  title: family?.title ?? `Repeated workflow: ${fallbackTerms.join(", ") || slug}`,
26828
- description: family?.description ?? `Repeated workflow involving ${steps.map((s) => s.label).slice(0, 3).join(", ")}.`,
26829
- whenToUse: family?.whenToUse ?? `Use for requests similar to: ${terms.slice(0, 5).join(", ")}.`,
27138
+ description: family?.description ?? `Repeated workflow involving ${steps2.map((s) => s.label).slice(0, 3).join(", ")}.`,
27139
+ whenToUse: family?.whenToUse ?? `Use for requests similar to: ${terms2.slice(0, 5).join(", ")}.`,
26830
27140
  confidence: Math.round(confidence * 100) / 100,
26831
27141
  cohesion: Math.round(cluster.cohesion * 100) / 100,
26832
27142
  instances: group.length,
@@ -26835,9 +27145,9 @@ function analyze(traces, opts = {}) {
26835
27145
  sources,
26836
27146
  firstSeen: dates[0],
26837
27147
  lastSeen: dates[dates.length - 1],
26838
- steps,
27148
+ steps: steps2,
26839
27149
  completion: completionCriteria(stepKinds),
26840
- topTerms: terms,
27150
+ topTerms: terms2,
26841
27151
  evidence: group.map((g2) => evidenceFor(g2, slug)).sort((a, b3) => (a.date ?? "").localeCompare(b3.date ?? "")),
26842
27152
  notes,
26843
27153
  verifiedRate: Math.round(verifiedRate * 100) / 100,
@@ -26974,8 +27284,8 @@ var requestDocument = (request) => contextDocument({ excerpt: "", fileCategories
26974
27284
  var DEFAULT_ROUTER_SETTINGS = { autopilot: false, explore: 0, protect: [] };
26975
27285
  function chooseRoute(guess, table2, opts) {
26976
27286
  const fallback = opts.sources[0] ?? "claude-code";
26977
- const allowed = (a) => opts.sources.includes(a.source);
26978
- const arms = (guess.kind ? table2.find((k3) => k3.kind.key === guess.kind.key)?.arms ?? [] : []).filter(allowed);
27287
+ const allowed2 = (a) => opts.sources.includes(a.source);
27288
+ const arms = (guess.kind ? table2.find((k3) => k3.kind.key === guess.kind.key)?.arms ?? [] : []).filter(allowed2);
26979
27289
  const p3 = pickArm(arms);
26980
27290
  const base = { guess, randomized: false, pick: p3.arm, arms };
26981
27291
  const explore = Math.min(MAX_EXPLORE, Math.max(0, opts.settings.explore));
@@ -27156,13 +27466,13 @@ function reviewSkill(skill, content, traces) {
27156
27466
  protected: fixed
27157
27467
  };
27158
27468
  if (n < MIN_REVIEW_SESSIONS) return { ...base, commands: [], missing: [], rarelyTaken: [], constraints: [] };
27159
- const steps = consensusSteps(instances).filter((s) => !GENERIC.has(s.kind) && MENTIONS[s.kind]);
27160
- const commands = steps.filter((s) => mentions(text, s.kind)).map((s) => ({ ...s, examples: s.examples.filter((e2) => !text.includes(e2.toLowerCase()) && !(s.kind.startsWith("inspect-") && WRITES.test(e2))) })).filter((s) => s.examples.length);
27161
- const missing = steps.filter((s) => !mentions(text, s.kind) && !(fixed.length && s.kind === "summarize"));
27469
+ const steps2 = consensusSteps(instances).filter((s) => !GENERIC.has(s.kind) && MENTIONS[s.kind]);
27470
+ const commands2 = steps2.filter((s) => mentions(text, s.kind)).map((s) => ({ ...s, examples: s.examples.filter((e2) => !text.includes(e2.toLowerCase()) && !(s.kind.startsWith("inspect-") && WRITES.test(e2))) })).filter((s) => s.examples.length);
27471
+ const missing = steps2.filter((s) => !mentions(text, s.kind) && !(fixed.length && s.kind === "summarize"));
27162
27472
  const share = (kind) => runs.filter((t) => kind === "apply-fix" ? t.actionSequence.some((a) => a.startsWith("modify-")) : t.actionSequence.includes(kind)).length / n;
27163
27473
  const rarelyTaken = Object.keys(MENTIONS).filter((k3) => !GENERIC.has(k3) && !k3.startsWith("modify-") && k3 !== "summarize" && mentions(text, k3) && share(k3) < STALE_BELOW).map((k3) => ({ kind: k3, label: STEP_TEXT[k3].label, share: share(k3) })).sort((a, b3) => a.share - b3.share).slice(0, MAX_RARELY);
27164
27474
  const constraints = recurringCorrections(runs.map((t) => t.corrections ?? [])).filter(isSafeConstraint).filter((c2) => c2.text.toLowerCase().replace(/[^a-z\s-]/g, "").split(/\s+/).some((w2) => w2.length > 2 && !VAGUE.has(w2) && !/^(don't|dont|never|always|avoid|use|prefer|run|keep)$/.test(w2))).filter((c2) => !(fixed.length && OUTPUT_WORDS.test(c2.text))).filter((c2) => !c2.text.toLowerCase().split(/\s+/).every((w2) => w2.length < 3 || text.includes(w2))).slice(0, MAX_CONSTRAINTS2);
27165
- return { ...base, commands, model: modelAdvice(runs), missing, rarelyTaken, constraints };
27475
+ return { ...base, commands: commands2, model: modelAdvice(runs), missing, rarelyTaken, constraints };
27166
27476
  }
27167
27477
  function outputShape(text) {
27168
27478
  const trimmed = text.trim();
@@ -27178,21 +27488,21 @@ function outputShape(text) {
27178
27488
  let fence = false;
27179
27489
  let prev = "";
27180
27490
  for (const raw of trimmed.split("\n")) {
27181
- const line = raw.trimEnd();
27182
- if (/^\s*```/.test(line)) {
27183
- shape.push(fence ? "code:end" : `code:${line.trim().slice(3).trim() || "text"}`);
27491
+ const line2 = raw.trimEnd();
27492
+ if (/^\s*```/.test(line2)) {
27493
+ shape.push(fence ? "code:end" : `code:${line2.trim().slice(3).trim() || "text"}`);
27184
27494
  fence = !fence;
27185
27495
  prev = "";
27186
27496
  continue;
27187
27497
  }
27188
27498
  if (fence) continue;
27189
27499
  let kind = "";
27190
- const h2 = /^(#{1,6})\s+(.+)$/.exec(line);
27500
+ const h2 = /^(#{1,6})\s+(.+)$/.exec(line2);
27191
27501
  if (h2) kind = `h${h2[1].length}:${h2[2].split(":")[0].replace(/[\d.,/-]+/g, "#").trim().toLowerCase()}`;
27192
- else if (/^\s*\|.*\|\s*$/.test(line)) kind = /^\s*\|[\s:|-]+\|\s*$/.test(line) ? "" : prev.startsWith("table") ? "table:row" : `table:${line.split("|").filter((c2) => c2.trim()).length}`;
27193
- else if (/^\s*[-*+]\s+/.test(line)) kind = "list";
27194
- else if (/^\s*\d+[.)]\s+/.test(line)) kind = "numbered";
27195
- else if (/^\s*\*\*[^*]+\*\*:?/.test(line)) kind = `label:${/\*\*([^*]+)\*\*/.exec(line)[1].toLowerCase()}`;
27502
+ else if (/^\s*\|.*\|\s*$/.test(line2)) kind = /^\s*\|[\s:|-]+\|\s*$/.test(line2) ? "" : prev.startsWith("table") ? "table:row" : `table:${line2.split("|").filter((c2) => c2.trim()).length}`;
27503
+ else if (/^\s*[-*+]\s+/.test(line2)) kind = "list";
27504
+ else if (/^\s*\d+[.)]\s+/.test(line2)) kind = "numbered";
27505
+ else if (/^\s*\*\*[^*]+\*\*:?/.test(line2)) kind = `label:${/\*\*([^*]+)\*\*/.exec(line2)[1].toLowerCase()}`;
27196
27506
  if (!kind || kind === prev && (kind === "list" || kind === "numbered" || kind === "table:row")) {
27197
27507
  if (kind) prev = kind;
27198
27508
  continue;
@@ -27203,6 +27513,136 @@ function outputShape(text) {
27203
27513
  return shape;
27204
27514
  }
27205
27515
 
27516
+ // ../../packages/analysis/src/handbook.ts
27517
+ var MAX_SOURCES = 5;
27518
+ var MIN_COMMAND_SESSIONS = 2;
27519
+ var WHEN_SHARE = 2 / 3;
27520
+ var WHEN_LIFT = 2;
27521
+ var SITUATIONS = [
27522
+ { category: "dependency-manifest", when: "when changing dependencies", words: ["dependency", "package", "install", "lockfile", "upgrade"] },
27523
+ { category: "migration", when: "when changing the database schema", words: ["migration", "schema", "database", "db", "sql"] },
27524
+ { category: "ci-config", when: "when working on CI", words: ["ci", "pipeline", "workflow", "github", "action"] },
27525
+ { category: "test", when: "when writing or changing tests", words: ["test", "spec"] },
27526
+ { category: "config", when: "when changing configuration", words: ["config", "configuration", "setting"] },
27527
+ { category: "docs", when: "when editing docs", words: ["doc", "readme", "documentation"] }
27528
+ ];
27529
+ var VERIFY = [
27530
+ { action: "run-tests", label: "Run tests with", words: ["test", "spec", "unit", "e2e"] },
27531
+ { action: "run-build", label: "Build or typecheck with", words: ["build", "compile", "typecheck", "type", "tsc"] },
27532
+ { action: "run-lint", label: "Lint with", words: ["lint", "format", "style", "prettier", "eslint"] }
27533
+ ];
27534
+ var projectOf = (i) => i.primary.projectHash;
27535
+ var time4 = (t) => t.startedAt ? Date.parse(t.startedAt) || 0 : 0;
27536
+ function sourcesOf(group) {
27537
+ const newest = [...group].sort((a, b3) => time4(b3.primary) - time4(a.primary));
27538
+ return {
27539
+ last: newest[0]?.primary.startedAt,
27540
+ sources: newest.slice(0, MAX_SOURCES).map((i) => ({ date: i.primary.startedAt, tool: i.primary.source, request: i.primary.excerpt }))
27541
+ };
27542
+ }
27543
+ function scopeOf(group) {
27544
+ const hashes = new Set(group.map(projectOf));
27545
+ if (hashes.size !== 1) return void 0;
27546
+ const hash2 = [...hashes][0];
27547
+ return hash2 ? { name: group[0].primary.projectName, hash: hash2 } : void 0;
27548
+ }
27549
+ function situation(group, others) {
27550
+ const count3 = (xs, cat) => xs.filter((i) => i.primary.fileCategories.includes(cat)).length;
27551
+ let best;
27552
+ for (const s of SITUATIONS) {
27553
+ const inside = count3(group, s.category) / group.length;
27554
+ if (inside < WHEN_SHARE) continue;
27555
+ const lift = inside / ((count3(others, s.category) + 0.5) / (others.length + 1));
27556
+ if (lift >= WHEN_LIFT && (!best || lift > best.lift)) best = { when: s.when, lift };
27557
+ }
27558
+ return best?.when;
27559
+ }
27560
+ function rules(instances, forgotten) {
27561
+ const out2 = [];
27562
+ for (const r2 of recurringCorrectionsBySession(instances.map((i) => i.primary.corrections ?? []))) {
27563
+ if (forgotten.has(r2.text) || !isSafeConstraint(r2)) continue;
27564
+ const group = r2.instances.map((k3) => instances[k3]);
27565
+ const project = scopeOf(group);
27566
+ const members2 = new Set(group);
27567
+ const others = instances.filter((i) => !members2.has(i) && (!project || projectOf(i) === project.hash));
27568
+ const when = situation(group, others);
27569
+ out2.push({ id: practiceId("rule", project?.hash, r2.text), kind: "rule", project, text: r2.text, when, sessions: r2.sessions, ...sourcesOf(group) });
27570
+ }
27571
+ return out2;
27572
+ }
27573
+ function commands(instances) {
27574
+ const byProject2 = /* @__PURE__ */ new Map();
27575
+ for (const i of instances) {
27576
+ const h2 = projectOf(i);
27577
+ if (h2) byProject2.set(h2, [...byProject2.get(h2) ?? [], i]);
27578
+ }
27579
+ const out2 = [];
27580
+ for (const [hash2, group] of byProject2) {
27581
+ for (const v2 of VERIFY) {
27582
+ const worked = /* @__PURE__ */ new Map();
27583
+ const failed = /* @__PURE__ */ new Map();
27584
+ for (const i of group) {
27585
+ const runs = i.primary.commands.filter((c2) => c2.action === v2.action);
27586
+ for (const cmd2 of new Set(runs.map((c2) => c2.normalized).filter(isSafeExample))) {
27587
+ const same = runs.filter((c2) => c2.normalized === cmd2);
27588
+ if (same.some((c2) => !c2.failed)) worked.set(cmd2, [...worked.get(cmd2) ?? [], i]);
27589
+ else failed.set(cmd2, (failed.get(cmd2) ?? 0) + 1);
27590
+ }
27591
+ }
27592
+ const top = [...worked].sort((a, b3) => b3[1].length - a[1].length || a[0].localeCompare(b3[0]))[0];
27593
+ if (!top || top[1].length < MIN_COMMAND_SESSIONS) continue;
27594
+ const [cmd, sessions2] = top;
27595
+ const notThis = [...failed].filter(([other, n]) => other !== cmd && n >= MIN_COMMAND_SESSIONS && !worked.has(other)).sort((a, b3) => b3[1] - a[1])[0];
27596
+ const text = `${v2.label} \`${cmd}\`.${notThis ? ` Not \`${notThis[0]}\`: it failed in ${notThis[1]} sessions.` : ""}`;
27597
+ out2.push({
27598
+ id: practiceId("command", hash2, `${v2.action}:${cmd}`),
27599
+ kind: "command",
27600
+ project: { name: sessions2[0].primary.projectName, hash: hash2 },
27601
+ text,
27602
+ sessions: sessions2.length,
27603
+ ...sourcesOf(sessions2)
27604
+ });
27605
+ }
27606
+ }
27607
+ return out2;
27608
+ }
27609
+ function practiceId(kind, project, key3) {
27610
+ return shortHash(`${kind}|${project ?? "*"}|${key3}`, 8);
27611
+ }
27612
+ function buildHandbook(traces, opts = {}) {
27613
+ const { instances } = deduplicate(traces);
27614
+ return [...commands(instances), ...rules(instances, opts.forgotten ?? /* @__PURE__ */ new Set())].sort(
27615
+ (a, b3) => b3.sessions - a.sessions || a.kind.localeCompare(b3.kind) || a.text.localeCompare(b3.text)
27616
+ );
27617
+ }
27618
+ function practicesFor(practices, projectHash) {
27619
+ return practices.filter((p3) => !p3.project || p3.project.hash === projectHash).sort((a, b3) => Number(!a.project) - Number(!b3.project));
27620
+ }
27621
+ var QUESTION_FILLER = new Set(
27622
+ "a an the to it is are be do does did how what when where which who why we i you our my your here there this that in on of for with and or should can could would will".split(" ")
27623
+ );
27624
+ function terms(text) {
27625
+ return new Set(
27626
+ text.toLowerCase().split(/[^a-z0-9.-]+/).map((w2) => w2.replace(/^[.-]+|[.-]+$/g, "")).filter((w2) => w2.length > 1 && !QUESTION_FILLER.has(w2)).map(stem)
27627
+ );
27628
+ }
27629
+ function practiceTerms(p3) {
27630
+ const extra = [];
27631
+ for (const s of SITUATIONS) if (p3.when === s.when) extra.push(...s.words);
27632
+ for (const v2 of VERIFY) if (p3.text.startsWith(v2.label)) extra.push(...v2.words, "command", "run");
27633
+ return terms(`${p3.text} ${p3.when ?? ""} ${extra.join(" ")}`);
27634
+ }
27635
+ function askHandbook(practices, question, projectHash, limit = 3) {
27636
+ const q2 = terms(question);
27637
+ if (!q2.size) return [];
27638
+ return practices.map((p3) => {
27639
+ const t = practiceTerms(p3);
27640
+ const hits = [...q2].filter((w2) => t.has(w2)).length;
27641
+ const local = p3.project ? p3.project.hash === projectHash ? 1.5 : 0.5 : 1;
27642
+ return { practice: p3, score: hits / q2.size * local };
27643
+ }).filter((a) => a.score > 0).sort((a, b3) => b3.score - a.score || b3.practice.sessions - a.practice.sessions).slice(0, limit);
27644
+ }
27645
+
27206
27646
  // src/commands/scan.ts
27207
27647
  import { totalmem as totalmem2 } from "node:os";
27208
27648
 
@@ -27304,8 +27744,8 @@ function parseFrontmatter(content) {
27304
27744
  const end = content.indexOf("\n---", 3);
27305
27745
  if (end < 0) return void 0;
27306
27746
  const out2 = {};
27307
- for (const line of content.slice(4, end).split("\n")) {
27308
- const m2 = /^([a-z][a-z0-9-]*):\s*(.*)$/i.exec(line);
27747
+ for (const line2 of content.slice(4, end).split("\n")) {
27748
+ const m2 = /^([a-z][a-z0-9-]*):\s*(.*)$/i.exec(line2);
27309
27749
  if (!m2) continue;
27310
27750
  let v2 = m2[2].trim();
27311
27751
  if (v2.startsWith('"')) {
@@ -27331,15 +27771,15 @@ function checkSkill(content, expectedName) {
27331
27771
  const description = fm?.description ?? "";
27332
27772
  if (!description) errors.push("frontmatter `description` is missing");
27333
27773
  if (description.length > 1024) errors.push("description is longer than 1024 characters");
27334
- for (const section of REQUIRED_SECTIONS) if (!content.includes(`
27335
- ${section}
27336
- `)) errors.push(`missing section "${section}"`);
27337
- const steps = (content.split("## Workflow")[1]?.split("\n## ")[0] ?? "").split("\n").filter((l2) => /^\d+\. /.test(l2)).length;
27338
- if (steps < 3) errors.push(`workflow has ${steps} steps; at least 3 expected`);
27774
+ for (const section2 of REQUIRED_SECTIONS) if (!content.includes(`
27775
+ ${section2}
27776
+ `)) errors.push(`missing section "${section2}"`);
27777
+ const steps2 = (content.split("## Workflow")[1]?.split("\n## ")[0] ?? "").split("\n").filter((l2) => /^\d+\. /.test(l2)).length;
27778
+ if (steps2 < 3) errors.push(`workflow has ${steps2} steps; at least 3 expected`);
27339
27779
  if (findLeaks(content).length) errors.push("contains sensitive-looking content (secret, email, or home path)");
27340
27780
  if (/(^|[\s`'"(])(\/Users\/|\/home\/|[A-Z]:\\Users\\)/m.test(content)) errors.push("contains a local absolute path");
27341
27781
  if (!/generator: reflex/.test(content)) warnings.push("no Reflex provenance metadata (hand-written or edited skill)");
27342
- return { ok: errors.length === 0, errors, warnings, name, steps, lines };
27782
+ return { ok: errors.length === 0, errors, warnings, name, steps: steps2, lines };
27343
27783
  }
27344
27784
 
27345
27785
  // ../../packages/skills/src/diff.ts
@@ -27579,8 +28019,9 @@ function runClaudeInSandbox(sandbox, skillName2, timeoutMs = 6 * 60 * 1e3) {
27579
28019
  "--allowedTools",
27580
28020
  ...ALLOWED_TOOLS
27581
28021
  ];
28022
+ const launch = agentLaunch("claude", args);
27582
28023
  return new Promise((resolve5) => {
27583
- const child = spawn("claude", args, { cwd: sandbox.dir, stdio: ["ignore", "pipe", "ignore"] });
28024
+ const child = spawn(launch.command, launch.args, { cwd: sandbox.dir, stdio: ["ignore", "pipe", "ignore"], windowsVerbatimArguments: launch.windowsVerbatimArguments });
27584
28025
  let buffer = "";
27585
28026
  let timedOut = false;
27586
28027
  const run2 = { exitCode: null, skillUsed: false, commands: [], editedFiles: [], testsPass: false, timedOut: false };
@@ -27593,19 +28034,19 @@ function runClaudeInSandbox(sandbox, skillName2, timeoutMs = 6 * 60 * 1e3) {
27593
28034
  const base = bases.find((b3) => p3.startsWith(b3));
27594
28035
  return base ? p3.slice(base.length) : displayPath(p3);
27595
28036
  };
27596
- const handle = (line) => {
28037
+ const handle = (line2) => {
27597
28038
  let msg;
27598
28039
  try {
27599
- msg = JSON.parse(line);
28040
+ msg = JSON.parse(line2);
27600
28041
  } catch {
27601
28042
  return;
27602
28043
  }
27603
- if (msg.type === "result" && typeof msg.result === "string") run2.finalMessage = redact(msg.result.slice(0, 2e3));
28044
+ if (msg.type === "result" && typeof msg.result === "string") run2.finalMessage = redactTruncated(msg.result, 2e3);
27604
28045
  if (msg.type !== "assistant" || !Array.isArray(msg.message?.content)) return;
27605
28046
  for (const block of msg.message.content) {
27606
28047
  if (block.type !== "tool_use") continue;
27607
28048
  if (block.name === "Skill" && String(block.input?.skill ?? "").replace(/^.*:/, "") === skillName2) run2.skillUsed = true;
27608
- if (block.name === "Bash" && typeof block.input?.command === "string") run2.commands.push(redact(block.input.command.slice(0, 200)));
28049
+ if (block.name === "Bash" && typeof block.input?.command === "string") run2.commands.push(redactTruncated(block.input.command, 200));
27609
28050
  if ((block.name === "Edit" || block.name === "Write") && typeof block.input?.file_path === "string")
27610
28051
  run2.editedFiles.push(sandboxRelative(block.input.file_path));
27611
28052
  }
@@ -27687,15 +28128,16 @@ function cleanMemoryText(text) {
27687
28128
  if (!t || redactions > 0 || findLeaks(t).length) return void 0;
27688
28129
  return t;
27689
28130
  }
27690
- function renderMemoryBlock(rules) {
28131
+ function renderMemoryBlock(rules2) {
27691
28132
  const lines = [
27692
28133
  MEMORY_START,
27693
28134
  "## Remembered by Reflex",
27694
28135
  "",
27695
28136
  "Corrections the developer gave coding agents in more than one past session. Follow them unless the current task says otherwise.",
27696
28137
  "Managed by `reflex memory`: edits inside this block are replaced on the next scan.",
28138
+ 'To see how work is done in the current repository (commands that work, rules the developer gave), run `reflex handbook --json`, or `reflex handbook ask "<question>" --json`. Both are read-only.',
27697
28139
  "",
27698
- ...rules.map((r2) => `- ${r2.text}${r2.sessions ? ` (${r2.sessions} sessions)` : ""}`),
28140
+ ...rules2.map((r2) => `- ${r2.text}${r2.sessions ? ` (${r2.sessions} sessions)` : ""}`),
27699
28141
  MEMORY_END
27700
28142
  ];
27701
28143
  return lines.join("\n");
@@ -27774,19 +28216,19 @@ function learnedSection(review, opts = {}) {
27774
28216
  for (const c2 of constraints) lines.push(`- ${c2.text} (${c2.sessions} sessions)`);
27775
28217
  }
27776
28218
  lines.push(LEARNED_END);
27777
- const section = redact(lines.join("\n"));
27778
- if (findLeaks(section).length) throw new Error("The proposed section still contains sensitive-looking content; refusing to propose it.");
27779
- return section;
28219
+ const section2 = redact(lines.join("\n"));
28220
+ if (findLeaks(section2).length) throw new Error("The proposed section still contains sensitive-looking content; refusing to propose it.");
28221
+ return section2;
27780
28222
  }
27781
- function applyLearned(content, section) {
28223
+ function applyLearned(content, section2) {
27782
28224
  const starts = content.split(LEARNED_START).length - 1;
27783
28225
  const ends = content.split(LEARNED_END).length - 1;
27784
28226
  if (starts > 1 || ends > 1 || starts !== ends || starts && content.indexOf(LEARNED_END) < content.indexOf(LEARNED_START))
27785
28227
  throw new Error(`The skill's "Learned from your sessions" markers are incomplete or repeated. Fix or remove ${LEARNED_START} and ${LEARNED_END}, then run reflex improve again.`);
27786
28228
  const start = content.indexOf(LEARNED_START);
27787
28229
  const end = start >= 0 ? content.indexOf(LEARNED_END, start) : -1;
27788
- if (start >= 0 && end >= 0) return content.slice(0, start) + section + content.slice(end + LEARNED_END.length);
27789
- return content.replace(/\n*$/, "\n\n") + section + "\n";
28230
+ if (start >= 0 && end >= 0) return content.slice(0, start) + section2 + content.slice(end + LEARNED_END.length);
28231
+ return content.replace(/\n*$/, "\n\n") + section2 + "\n";
27790
28232
  }
27791
28233
  function withoutLearned(content) {
27792
28234
  const start = content.indexOf(LEARNED_START);
@@ -27809,6 +28251,7 @@ async function applyToOwnSkill(path, readHash, next, backupDir, name, now = /* @
27809
28251
  if (sha256(current) !== readHash) throw new Error("The skill changed since Reflex read it; run `reflex improve` again.");
27810
28252
  const stat4 = await lstat6(path);
27811
28253
  if (!stat4.isFile()) throw new Error("Not a regular file.");
28254
+ if ((stat4.mode & 146) === 0) throw new Error("You can't write to this skill file, so Reflex won't change it.");
27812
28255
  await access(path, constants3.W_OK).catch(() => {
27813
28256
  throw new Error("You can't write to this skill file, so Reflex won't change it.");
27814
28257
  });
@@ -27876,19 +28319,20 @@ function runClaudeBench(dir, task, model2, tools, timeoutMs) {
27876
28319
  "--allowedTools",
27877
28320
  ...tools
27878
28321
  ];
28322
+ const launch = agentLaunch("claude", args);
27879
28323
  const started = Date.now();
27880
28324
  return new Promise((resolve5) => {
27881
- const child = spawn2("claude", args, { cwd: dir, stdio: ["ignore", "pipe", "ignore"] });
28325
+ const child = spawn2(launch.command, launch.args, { cwd: dir, stdio: ["ignore", "pipe", "ignore"], windowsVerbatimArguments: launch.windowsVerbatimArguments });
27882
28326
  const run2 = { exitCode: null, timedOut: false, durationMs: 0 };
27883
28327
  let buffer = "";
27884
28328
  const timer = setTimeout(() => {
27885
28329
  run2.timedOut = true;
27886
28330
  child.kill("SIGTERM");
27887
28331
  }, timeoutMs);
27888
- const handle = (line) => {
28332
+ const handle = (line2) => {
27889
28333
  let msg;
27890
28334
  try {
27891
- msg = JSON.parse(line);
28335
+ msg = JSON.parse(line2);
27892
28336
  } catch {
27893
28337
  return;
27894
28338
  }
@@ -27940,7 +28384,10 @@ var paths = {
27940
28384
  home: reflexHome,
27941
28385
  db: () => join13(reflexHome(), "reflex.db"),
27942
28386
  skills: () => join13(reflexHome(), "skills"),
27943
- models: () => join13(reflexHome(), "models")
28387
+ models: () => join13(reflexHome(), "models"),
28388
+ /** Token counts Reflex's Cursor hook records (`reflex cursor-usage on`). */
28389
+ cursorUsage: () => join13(reflexHome(), "cursor-usage.jsonl"),
28390
+ hooks: () => join13(reflexHome(), "hooks")
27944
28391
  };
27945
28392
 
27946
28393
  // ../../packages/storage/src/db.ts
@@ -28067,6 +28514,7 @@ function parseJson(raw, shape, what) {
28067
28514
  if (!result.success) throw new Error(`Reflex database has a malformed ${what}. Run \`reflex scan\` again.`);
28068
28515
  return result.data;
28069
28516
  }
28517
+ var BUSY_TIMEOUT_MS = 1e4;
28070
28518
  var Store = class {
28071
28519
  db;
28072
28520
  constructor(file2 = paths.db()) {
@@ -28075,6 +28523,8 @@ var Store = class {
28075
28523
  mkdirSync(dir, { recursive: true, mode: 448 });
28076
28524
  this.db = new DatabaseSync2(file2);
28077
28525
  chmodSync(file2, 384);
28526
+ this.db.exec(`PRAGMA busy_timeout = ${BUSY_TIMEOUT_MS}`);
28527
+ this.db.exec("PRAGMA journal_mode = WAL");
28078
28528
  const version2 = Number(this.db.prepare("PRAGMA user_version").get().user_version);
28079
28529
  if (version2 < 4) this.db.exec("DROP TABLE IF EXISTS sessions");
28080
28530
  this.db.exec(SCHEMA);
@@ -28089,7 +28539,7 @@ var Store = class {
28089
28539
  }
28090
28540
  /** Record a scan and make the given cached traces its working set (what suggest, stats and the TUI see). */
28091
28541
  saveScan(scan2, traceRows) {
28092
- this.db.exec("BEGIN");
28542
+ this.db.exec("BEGIN IMMEDIATE");
28093
28543
  try {
28094
28544
  const res = this.db.prepare(
28095
28545
  "INSERT INTO scans (started_at, days, mode, sources_json, files, sessions, partial, unreadable, skipped_records) VALUES (?,?,?,?,?,?,?,?,?)"
@@ -28129,7 +28579,7 @@ var Store = class {
28129
28579
  }
28130
28580
  /** Replace what is cached for one file (its identity and its traces) atomically. */
28131
28581
  saveFile(file2, traces) {
28132
- this.db.exec("BEGIN");
28582
+ this.db.exec("BEGIN IMMEDIATE");
28133
28583
  try {
28134
28584
  this.db.prepare("DELETE FROM traces WHERE path = ?").run(file2.path);
28135
28585
  this.db.prepare(
@@ -28160,7 +28610,7 @@ var Store = class {
28160
28610
  }
28161
28611
  /** Rewrite a kept trace in place (re-redaction after the rules or the user's identity changed). */
28162
28612
  updateKeptTraces(path, traces, keys) {
28163
- this.db.exec("BEGIN");
28613
+ this.db.exec("BEGIN IMMEDIATE");
28164
28614
  try {
28165
28615
  const update = this.db.prepare("UPDATE traces SET trace_json = ? WHERE row_id = ?");
28166
28616
  for (const t of traces) update.run(JSON.stringify(t.trace), t.row);
@@ -28205,7 +28655,7 @@ var Store = class {
28205
28655
  /** Store the current suggestions, keeping any earlier approve/reject decision for the same slug. */
28206
28656
  saveSuggestions(scanId, suggestions) {
28207
28657
  const now = (/* @__PURE__ */ new Date()).toISOString();
28208
- this.db.exec("BEGIN");
28658
+ this.db.exec("BEGIN IMMEDIATE");
28209
28659
  try {
28210
28660
  this.db.prepare("UPDATE suggestions SET rank = NULL").run();
28211
28661
  const upsert = this.db.prepare(
@@ -28299,11 +28749,11 @@ var Store = class {
28299
28749
  }
28300
28750
  return out2;
28301
28751
  }
28302
- saveEmbeddings(model2, entries) {
28752
+ saveEmbeddings(model2, entries2) {
28303
28753
  const put = this.db.prepare("INSERT OR REPLACE INTO embeddings (key, model, vector) VALUES (?,?,COALESCE(?, zeroblob(0)))");
28304
- this.db.exec("BEGIN");
28754
+ this.db.exec("BEGIN IMMEDIATE");
28305
28755
  try {
28306
- for (const [key3, v2] of entries) put.run(key3, model2, new Uint8Array(v2.buffer, v2.byteOffset, v2.byteLength));
28756
+ for (const [key3, v2] of entries2) put.run(key3, model2, new Uint8Array(v2.buffer, v2.byteOffset, v2.byteLength));
28307
28757
  this.db.exec("COMMIT");
28308
28758
  } catch (err) {
28309
28759
  this.db.exec("ROLLBACK");
@@ -28315,11 +28765,11 @@ var Store = class {
28315
28765
  this.db.prepare("DELETE FROM embeddings WHERE key NOT IN (SELECT value FROM json_each(?))").run(JSON.stringify(keep));
28316
28766
  }
28317
28767
  /** Replace the mined memory with the latest result. User decisions (forgotten, added) are kept. */
28318
- syncMinedMemory(rules) {
28768
+ syncMinedMemory(rules2) {
28319
28769
  const now = (/* @__PURE__ */ new Date()).toISOString();
28320
- this.db.exec("BEGIN");
28770
+ this.db.exec("BEGIN IMMEDIATE");
28321
28771
  try {
28322
- const keep = new Set(rules.map((r2) => r2.text));
28772
+ const keep = new Set(rules2.map((r2) => r2.text));
28323
28773
  for (const row of this.db.prepare("SELECT text FROM memory_entries WHERE origin = 'mined' AND status = 'active'").all()) {
28324
28774
  if (!keep.has(row.text)) this.db.prepare("DELETE FROM memory_entries WHERE text = ?").run(row.text);
28325
28775
  }
@@ -28327,7 +28777,7 @@ var Store = class {
28327
28777
  `INSERT INTO memory_entries (text, origin, status, sessions, updated_at) VALUES (?, 'mined', 'active', ?, ?)
28328
28778
  ON CONFLICT(text) DO UPDATE SET sessions = excluded.sessions, updated_at = excluded.updated_at`
28329
28779
  );
28330
- for (const r2 of rules) upsert.run(r2.text, r2.sessions, now);
28780
+ for (const r2 of rules2) upsert.run(r2.text, r2.sessions, now);
28331
28781
  this.db.exec("COMMIT");
28332
28782
  } catch (err) {
28333
28783
  this.db.exec("ROLLBACK");
@@ -28684,8 +29134,8 @@ var COMFORTABLE = { memoryGB: 8, cores: 4 };
28684
29134
  function machineIsSmall(totalBytes = totalmem(), cores = availableParallelism()) {
28685
29135
  return totalBytes / 1e9 < COMFORTABLE.memoryGB - 0.5 || cores < COMFORTABLE.cores;
28686
29136
  }
28687
- function embeddingSeconds(model2, sessions2, threads = embeddingThreads()) {
28688
- const speedup = 1 + (threads - 1) * 0.83;
29137
+ function embeddingSeconds(model2, sessions2, threads2 = embeddingThreads()) {
29138
+ const speedup = 1 + (threads2 - 1) * 0.83;
28689
29139
  return sessions2 * model2.secondsPerSession / speedup;
28690
29140
  }
28691
29141
 
@@ -28705,8 +29155,8 @@ async function tokenizerFor(dir, model2) {
28705
29155
  return (text) => tokenizer2.encode(text, model2.maxTokens);
28706
29156
  }
28707
29157
  const { Tokenizer } = await import("./tokenizers-CLBWC4RJ.js");
28708
- const [json2, config2] = await Promise.all([readVerified(dir, "tokenizer.json", model2), readVerified(dir, "tokenizer_config.json", model2)]);
28709
- const tokenizer = new Tokenizer(JSON.parse(json2.toString("utf8")), JSON.parse(config2.toString("utf8")));
29158
+ const [json3, config2] = await Promise.all([readVerified(dir, "tokenizer.json", model2), readVerified(dir, "tokenizer_config.json", model2)]);
29159
+ const tokenizer = new Tokenizer(JSON.parse(json3.toString("utf8")), JSON.parse(config2.toString("utf8")));
28710
29160
  return (text) => {
28711
29161
  const ids = tokenizer.encode(text).ids;
28712
29162
  return ids.length > model2.maxTokens ? [...ids.slice(0, model2.maxTokens - 1), ids[ids.length - 1]] : ids;
@@ -30430,13 +30880,13 @@ import { join as join17 } from "node:path";
30430
30880
  async function skillFiles() {
30431
30881
  const out2 = [];
30432
30882
  for (const t of await detectTargets()) {
30433
- let entries;
30883
+ let entries2;
30434
30884
  try {
30435
- entries = await readdir3(t.skillsDir, { withFileTypes: true });
30885
+ entries2 = await readdir3(t.skillsDir, { withFileTypes: true });
30436
30886
  } catch {
30437
30887
  continue;
30438
30888
  }
30439
- for (const e2 of entries) {
30889
+ for (const e2 of entries2) {
30440
30890
  if (!(e2.isDirectory() || e2.isSymbolicLink()) || !OWN_SKILL_NAME.test(e2.name)) continue;
30441
30891
  const entry = join17(t.skillsDir, e2.name);
30442
30892
  try {
@@ -30502,7 +30952,7 @@ function chooseAdapters(opts) {
30502
30952
  if (opts.cursorDir) adapters.push(new CursorAdapter(opts.cursorDir));
30503
30953
  return { adapters: only(adapters), mode: "custom" };
30504
30954
  }
30505
- return { adapters: only([new ClaudeCodeAdapter(), new CodexAdapter(), new CursorAdapter()]), mode: "local" };
30955
+ return { adapters: only([new ClaudeCodeAdapter(), new CodexAdapter(), new CursorAdapter(void 0, void 0, { usageLog: paths.cursorUsage() })]), mode: "local" };
30506
30956
  }
30507
30957
  async function scan(opts) {
30508
30958
  const { adapters, mode } = chooseAdapters(opts);
@@ -30939,7 +31389,8 @@ async function validate2(name, opts) {
30939
31389
  out(c.dim(` Or let Reflex run it: reflex validate ${name} --run`));
30940
31390
  return;
30941
31391
  }
30942
- if (spawnSync3("claude", ["--version"], { stdio: "ignore" }).status !== 0) {
31392
+ const claude = agentLaunch("claude", ["--version"]);
31393
+ if (spawnSync3(claude.command, claude.args, { stdio: "ignore", windowsVerbatimArguments: claude.windowsVerbatimArguments }).status !== 0) {
30943
31394
  fail("The `claude` CLI was not found on PATH.");
30944
31395
  return;
30945
31396
  }
@@ -30960,7 +31411,7 @@ async function validate2(name, opts) {
30960
31411
  if (run2.finalMessage) {
30961
31412
  out();
30962
31413
  out(c.dim(" Final message:"));
30963
- for (const line of run2.finalMessage.split("\n").slice(0, 14)) out(c.dim(` ${line}`));
31414
+ for (const line2 of run2.finalMessage.split("\n").slice(0, 14)) out(c.dim(` ${line2}`));
30964
31415
  }
30965
31416
  out();
30966
31417
  if (run2.skillUsed && run2.testsPass) ok(`${name} worked on a new task.`);
@@ -30971,9 +31422,9 @@ async function validate2(name, opts) {
30971
31422
  var sourceSummary = (s) => Object.entries(s.sources).map(([k3, n]) => `${SOURCE_LABELS[k3] ?? k3} ${n}`).join(", ");
30972
31423
  function costLine(s) {
30973
31424
  const cost = s.cost;
30974
- const line = describeCost(cost);
30975
- if (cost.runsWithTokens) return line;
30976
- return s.sources.cursor ? `${line} ${c.dim("(Cursor doesn't record tokens)")}` : line;
31425
+ const line2 = describeCost(cost);
31426
+ if (cost.runsWithTokens) return line2;
31427
+ return s.sources.cursor ? `${line2} ${c.dim("(Cursor doesn't record tokens)")}` : line2;
30977
31428
  }
30978
31429
  function renderSuggestion(entry) {
30979
31430
  const s = entry.data;
@@ -31187,14 +31638,168 @@ async function reject(ref) {
31187
31638
  // src/commands/misc.ts
31188
31639
  import { spawnSync as spawnSync4 } from "node:child_process";
31189
31640
  import { readdir as readdir4, rm as rm3, stat as stat3 } from "node:fs/promises";
31641
+ import { homedir as homedir11 } from "node:os";
31642
+ import { join as join20 } from "node:path";
31643
+
31644
+ // src/cursor-hook.ts
31645
+ import { realpathSync as realpathSync2 } from "node:fs";
31646
+ import { readFile as readFile7 } from "node:fs/promises";
31190
31647
  import { homedir as homedir10 } from "node:os";
31191
- import { join as join19 } from "node:path";
31192
- var conductorRoot = () => process.env.REFLEX_CONDUCTOR_DIR ?? join19(homedir10(), "conductor", "workspaces");
31648
+ import { delimiter, join as join19, sep as sep3 } from "node:path";
31649
+ var HOOK_EVENTS = ["stop", "afterAgentResponse"];
31650
+ var SCRIPT_NAME = "cursor-usage.mjs";
31651
+ function assertHookSupported(platform2 = process.platform) {
31652
+ if (platform2 === "win32") throw new Error("reflex cursor-usage isn't available on Windows yet: Reflex can't yet write a hook command Cursor runs there.");
31653
+ }
31654
+ var cursorHooksFile = () => process.env.REFLEX_CURSOR_HOOKS_FILE ?? join19(homedir10(), ".cursor", "hooks.json");
31655
+ var hookScript = () => join19(paths.hooks(), SCRIPT_NAME);
31656
+ function hookSource(logPath) {
31657
+ return `// Written by Reflex (reflex cursor-usage on). Records token counts per Cursor agent turn; never text.
31658
+ import { appendFileSync } from "node:fs";
31659
+ const LOG = ${JSON.stringify(logPath)};
31660
+ const ID = /^[A-Za-z0-9-]{1,80}$/;
31661
+ const MODEL = /^[A-Za-z0-9][A-Za-z0-9._:\\/-]{0,79}$/;
31662
+ const id = (v) => (typeof v === "string" && ID.test(v) ? v : undefined);
31663
+ const model = (v) => (typeof v === "string" && MODEL.test(v) ? v : undefined);
31664
+ const n = (v) => (typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : undefined);
31665
+ let raw = "";
31666
+ process.stdin.setEncoding("utf8");
31667
+ process.stdin.on("data", (c) => { if (raw.length < 8000000) raw += c; });
31668
+ process.stdin.on("end", () => {
31669
+ try {
31670
+ const p = JSON.parse(raw);
31671
+ const event = p.hook_event_name;
31672
+ const rec = {
31673
+ v: 1,
31674
+ at: new Date().toISOString(),
31675
+ event,
31676
+ conversation_id: id(p.conversation_id),
31677
+ generation_id: id(p.generation_id),
31678
+ model: model(p.model_id) ?? model(p.model),
31679
+ input_tokens: n(p.input_tokens),
31680
+ output_tokens: n(p.output_tokens),
31681
+ cache_read_tokens: n(p.cache_read_tokens),
31682
+ cache_write_tokens: n(p.cache_write_tokens),
31683
+ };
31684
+ const counted = rec.input_tokens !== undefined || rec.output_tokens !== undefined;
31685
+ if ((event === "stop" || event === "afterAgentResponse") && rec.conversation_id && rec.generation_id && counted) {
31686
+ appendFileSync(LOG, JSON.stringify(rec) + "\\n", { mode: 0o600 });
31687
+ }
31688
+ } catch {}
31689
+ process.stdout.write("{}");
31690
+ });
31691
+ `;
31692
+ }
31693
+ function stableNode(execPath = process.execPath, pathEnv = process.env.PATH ?? "") {
31694
+ let real;
31695
+ try {
31696
+ real = realpathSync2(execPath);
31697
+ } catch {
31698
+ return execPath;
31699
+ }
31700
+ for (const dir of pathEnv.split(delimiter)) {
31701
+ if (!dir) continue;
31702
+ const candidate = join19(dir, "node");
31703
+ try {
31704
+ if (candidate !== execPath && realpathSync2(candidate) === real) return candidate;
31705
+ } catch {
31706
+ continue;
31707
+ }
31708
+ }
31709
+ return execPath;
31710
+ }
31711
+ function hookCommand(node2 = stableNode(), script = hookScript()) {
31712
+ for (const p3 of [node2, script]) if (p3.includes("'")) throw new Error(`Reflex can't quote the path ${p3} for a hook command.`);
31713
+ return `'${node2}' '${script}'`;
31714
+ }
31715
+ var ours = (e2) => typeof e2?.command === "string" && e2.command.endsWith(`${sep3}hooks${sep3}${SCRIPT_NAME}'`);
31716
+ function entries(hooks, event, file2) {
31717
+ const v2 = hooks[event];
31718
+ if (v2 === void 0) return [];
31719
+ if (!Array.isArray(v2)) throw new Error(`${file2} has "${event}" that isn't a list; Reflex won't overwrite it. Fix it, then run this again.`);
31720
+ return [...v2];
31721
+ }
31722
+ async function readHooks(file2) {
31723
+ if (await isSymlink(file2)) throw new Error(`${file2} is a symlink; Reflex won't write through it. Add the hook entry yourself (see reflex cursor-usage status).`);
31724
+ if (!await pathExists(file2)) return { data: { version: 1, hooks: {} } };
31725
+ const raw = await readFile7(file2, "utf8");
31726
+ let data;
31727
+ try {
31728
+ data = JSON.parse(raw);
31729
+ } catch {
31730
+ throw new Error(`${file2} is not valid JSON; Reflex won't overwrite it. Fix it, then run this again.`);
31731
+ }
31732
+ if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error(`${file2} is not a hooks object; Reflex won't overwrite it.`);
31733
+ return { data, raw };
31734
+ }
31735
+ async function hookStatus(file2 = cursorHooksFile()) {
31736
+ try {
31737
+ const { data } = await readHooks(file2);
31738
+ const hooks = data.hooks ?? {};
31739
+ return { events: HOOK_EVENTS.filter((e2) => Array.isArray(hooks[e2]) && hooks[e2].some(ours)) };
31740
+ } catch (e2) {
31741
+ return { events: [], error: e2 instanceof Error ? e2.message : String(e2) };
31742
+ }
31743
+ }
31744
+ async function writeHooks(file2, data, raw) {
31745
+ let backup;
31746
+ if (raw !== void 0) {
31747
+ const dir = join19(paths.home(), "backups");
31748
+ await ensureDir(paths.home(), 448);
31749
+ await ensureDir(dir, 448);
31750
+ backup = join19(dir, `cursor-hooks-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`);
31751
+ await writeNewFile(backup, raw, 384);
31752
+ }
31753
+ await ensureDir(join19(file2, ".."), 493);
31754
+ await replaceOwnedFile(file2, JSON.stringify(data, null, 2) + "\n", 420);
31755
+ return backup;
31756
+ }
31757
+ async function installHook(file2 = cursorHooksFile()) {
31758
+ assertHookSupported();
31759
+ await ensureDir(paths.home(), 448);
31760
+ await ensureDir(paths.hooks(), 448);
31761
+ await replaceOwnedFile(hookScript(), hookSource(paths.cursorUsage()), 448);
31762
+ const { data, raw } = await readHooks(file2);
31763
+ const hooks = { ...data.hooks ?? {} };
31764
+ const command = hookCommand();
31765
+ const added = [];
31766
+ for (const event of HOOK_EVENTS) {
31767
+ const list = entries(hooks, event, file2);
31768
+ if (list.some(ours)) {
31769
+ hooks[event] = list.map((e2) => ours(e2) ? { ...e2, command } : e2);
31770
+ continue;
31771
+ }
31772
+ hooks[event] = [...list, { command, timeout: 5 }];
31773
+ added.push(event);
31774
+ }
31775
+ const backup = await writeHooks(file2, { ...data, version: data.version ?? 1, hooks }, raw);
31776
+ return { added, backup };
31777
+ }
31778
+ async function removeHook(file2 = cursorHooksFile()) {
31779
+ if (!await pathExists(file2)) return { removed: [] };
31780
+ const { data, raw } = await readHooks(file2);
31781
+ const hooks = { ...data.hooks ?? {} };
31782
+ const removed = [];
31783
+ for (const event of HOOK_EVENTS) {
31784
+ const list = entries(hooks, event, file2);
31785
+ const kept = list.filter((e2) => !ours(e2));
31786
+ if (kept.length === list.length) continue;
31787
+ removed.push(event);
31788
+ if (kept.length) hooks[event] = kept;
31789
+ else delete hooks[event];
31790
+ }
31791
+ if (!removed.length) return { removed };
31792
+ const backup = await writeHooks(file2, { ...data, hooks }, raw);
31793
+ return { removed, backup };
31794
+ }
31795
+
31796
+ // src/commands/misc.ts
31797
+ var conductorRoot = () => process.env.REFLEX_CONDUCTOR_DIR ?? join20(homedir11(), "conductor", "workspaces");
31193
31798
  async function conductorWorkspaces() {
31194
31799
  const dir = conductorRoot();
31195
31800
  try {
31196
- const entries = await readdir4(dir, { withFileTypes: true });
31197
- return { dir, repos: entries.filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).length };
31801
+ const entries2 = await readdir4(dir, { withFileTypes: true });
31802
+ return { dir, repos: entries2.filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).length };
31198
31803
  } catch {
31199
31804
  return void 0;
31200
31805
  }
@@ -31228,10 +31833,15 @@ async function doctor() {
31228
31833
  out();
31229
31834
  out("Agent CLIs (for fresh-task validation)");
31230
31835
  for (const bin of ["claude", "codex"]) {
31231
- const found = spawnSync4(bin, ["--version"], { stdio: "ignore" }).status === 0;
31836
+ const launch = agentLaunch(bin, ["--version"]);
31837
+ const found = spawnSync4(launch.command, launch.args, { stdio: "ignore", windowsVerbatimArguments: launch.windowsVerbatimArguments }).status === 0;
31232
31838
  out(` ${found ? c.green("\u2714") : c.dim("\xB7")} ${bin}`);
31233
31839
  }
31234
31840
  out();
31841
+ const hook = await hookStatus();
31842
+ out("Cursor token usage");
31843
+ out(` ${hook.events.length ? c.green("\u2714") : c.dim("\xB7")} ${"Cursor hook".padEnd(12)} ${hook.events.length ? `recording (${hook.events.join(", ")})` : c.dim("off \xB7 reflex cursor-usage on")}`);
31844
+ out();
31235
31845
  }
31236
31846
  async function sessions() {
31237
31847
  const store = new Store();
@@ -31323,12 +31933,18 @@ async function reset(opts) {
31323
31933
  out("Nothing to reset.");
31324
31934
  return;
31325
31935
  }
31326
- out(`This deletes Reflex's own data in ${displayPath(home)}: the local database (including sessions kept from deleted transcripts), generated skills and validation sandboxes.`);
31936
+ out(`This deletes Reflex's own data in ${displayPath(home)}: the local database (including sessions kept from deleted transcripts), generated skills, validation sandboxes and recorded Cursor token counts.`);
31327
31937
  out(c.dim("Skills you installed into Claude Code, Codex or Cursor are not touched; Reflex's agent-memory block is removed. The embedding model is kept (`reflex model remove`)."));
31328
31938
  if (!await confirm("Delete Reflex data?", opts)) return;
31329
31939
  for (const w2 of await removeMemory()) if (w2.changed) ok(`Removed Reflex's memory block from ${displayPath(w2.path)}`);
31330
- for (const child of ["reflex.db", "reflex.db-journal", "skills", "validation"]) {
31331
- await rm3(join19(home, child), { recursive: true, force: true });
31940
+ try {
31941
+ const { removed } = await removeHook();
31942
+ if (removed.length) ok(`Removed Reflex's hook from ${displayPath(cursorHooksFile())}`);
31943
+ } catch (e2) {
31944
+ warn(`Could not remove Reflex's Cursor hook: ${e2 instanceof Error ? e2.message : String(e2)}`);
31945
+ }
31946
+ for (const child of ["reflex.db", "reflex.db-journal", "reflex.db-wal", "reflex.db-shm", "skills", "validation", "cursor-usage.jsonl", "hooks"]) {
31947
+ await rm3(join20(home, child), { recursive: true, force: true });
31332
31948
  }
31333
31949
  ok("Reset.");
31334
31950
  }
@@ -31341,9 +31957,9 @@ function reportWrites(writes) {
31341
31957
  else out(c.dim(` ${w2.target.label}: ${displayPath(w2.path)} already up to date`));
31342
31958
  }
31343
31959
  }
31344
- function find(entries, ref) {
31960
+ function find(entries2, ref) {
31345
31961
  const n = Number(ref.replace(/^#/, ""));
31346
- const e2 = Number.isInteger(n) && n > 0 ? entries[n - 1] : entries.find((x2) => x2.text === ref);
31962
+ const e2 = Number.isInteger(n) && n > 0 ? entries2[n - 1] : entries2.find((x2) => x2.text === ref);
31347
31963
  if (!e2) throw new Error(`No memory entry "${ref.slice(0, 40)}". Run \`reflex memory\` to list them.`);
31348
31964
  return e2;
31349
31965
  }
@@ -31352,7 +31968,7 @@ async function memoryStatus() {
31352
31968
  try {
31353
31969
  await syncMemory(store, { mine: Boolean(store.latestScan()) });
31354
31970
  const { enabled } = store.memoryState();
31355
- const entries = store.memoryEntries();
31971
+ const entries2 = store.memoryEntries();
31356
31972
  const targets = (await memoryTargets()).filter((t) => t.detected);
31357
31973
  title(`Agent memory \xB7 ${enabled ? c.green("on") : c.dim("off")}`);
31358
31974
  out(
@@ -31360,15 +31976,15 @@ async function memoryStatus() {
31360
31976
  );
31361
31977
  rows(targets.map((t) => [t.label, displayPath(t.file)]));
31362
31978
  out();
31363
- if (!entries.length) {
31979
+ if (!entries2.length) {
31364
31980
  out(`Nothing to remember yet. Memory comes from corrections you gave in at least 2 independent sessions${store.latestScan() ? "" : "; run `reflex scan` first"}.`);
31365
31981
  out(c.dim('Add your own: reflex memory add "use pnpm, not npm"'));
31366
31982
  return;
31367
31983
  }
31368
- entries.forEach((e2, i) => {
31369
- const meta3 = e2.origin === "added" ? "added by you" : plural(e2.sessions, "session");
31370
- const line = ` ${String(i + 1).padStart(2)}. ${e2.text} ${c.dim(`(${meta3})`)}`;
31371
- out(e2.status === "forgotten" ? c.dim(`${line} forgotten`) : line);
31984
+ entries2.forEach((e2, i) => {
31985
+ const meta4 = e2.origin === "added" ? "added by you" : plural(e2.sessions, "session");
31986
+ const line2 = ` ${String(i + 1).padStart(2)}. ${e2.text} ${c.dim(`(${meta4})`)}`;
31987
+ out(e2.status === "forgotten" ? c.dim(`${line2} forgotten`) : line2);
31372
31988
  });
31373
31989
  out();
31374
31990
  out(c.dim('reflex memory forget <n> \xB7 remember <n> \xB7 add "<text>" \xB7 on \xB7 off'));
@@ -31461,12 +32077,12 @@ async function storedSessions() {
31461
32077
  }
31462
32078
  }
31463
32079
  async function machineCheck(model2) {
31464
- const threads = embeddingThreads();
32080
+ const threads2 = embeddingThreads();
31465
32081
  const memGB = totalmem3() / 1e9;
31466
32082
  const sessions2 = await storedSessions();
31467
- const estimate = sessions2 ? `about ${duration3(embeddingSeconds(model2, sessions2, threads))} for your ${sessions2} stored sessions` : `about ${duration3(embeddingSeconds(model2, 100, threads))} per 100 sessions`;
32083
+ const estimate = sessions2 ? `about ${duration3(embeddingSeconds(model2, sessions2, threads2))} for your ${sessions2} stored sessions` : `about ${duration3(embeddingSeconds(model2, 100, threads2))} per 100 sessions`;
31468
32084
  rows([
31469
- ["This machine", `${memGB.toFixed(0)} GB memory, ${availableParallelism2()} cores (${threads} used for embedding)`],
32085
+ ["This machine", `${memGB.toFixed(0)} GB memory, ${availableParallelism2()} cores (${threads2} used for embedding)`],
31470
32086
  ["First scan", `${estimate}; later scans only embed new sessions (older CPUs can take up to 3x longer)`]
31471
32087
  ]);
31472
32088
  out();
@@ -31527,6 +32143,7 @@ async function modelFetch(opts) {
31527
32143
  const total = modelBytes(model2);
31528
32144
  let done = 0;
31529
32145
  let last = 0;
32146
+ const closeNetwork = allowHosts(MODEL_HOSTS);
31530
32147
  try {
31531
32148
  await fetchModel(
31532
32149
  paths.models(),
@@ -31545,6 +32162,8 @@ async function modelFetch(opts) {
31545
32162
  } catch (err) {
31546
32163
  spin.stop("Download failed");
31547
32164
  throw err;
32165
+ } finally {
32166
+ closeNetwork();
31548
32167
  }
31549
32168
  await setActiveModel(paths.models(), model2);
31550
32169
  spin.stop("Downloaded and verified");
@@ -31575,11 +32194,87 @@ async function modelRemove(opts) {
31575
32194
  ok(next ? `Removed ${target.name}. Scans now use ${next.name}.` : `Removed ${target.name}. Scans will compare requests by words only.`);
31576
32195
  }
31577
32196
 
32197
+ // src/commands/cursor-usage.ts
32198
+ import { readFile as readFile8 } from "node:fs/promises";
32199
+ async function recorded() {
32200
+ const conversations = /* @__PURE__ */ new Set();
32201
+ let turns = 0;
32202
+ let latest;
32203
+ try {
32204
+ for (const line2 of (await readFile8(paths.cursorUsage(), "utf8")).split("\n")) {
32205
+ try {
32206
+ const r2 = JSON.parse(line2);
32207
+ if (r2.event !== "stop" || !r2.conversation_id) continue;
32208
+ turns++;
32209
+ conversations.add(r2.conversation_id);
32210
+ if (r2.at && (!latest || r2.at > latest)) latest = r2.at;
32211
+ } catch {
32212
+ continue;
32213
+ }
32214
+ }
32215
+ } catch {
32216
+ }
32217
+ return { turns, conversations, latest };
32218
+ }
32219
+ async function cursorUsageStatus() {
32220
+ const file2 = cursorHooksFile();
32221
+ const status = await hookStatus(file2);
32222
+ const rec = await recorded();
32223
+ title("Cursor token usage");
32224
+ const on = status.events.length === HOOK_EVENTS.length;
32225
+ rows([
32226
+ ["Hook", on ? `${c.green("on")} ${c.dim(`\xB7 ${displayPath(file2)} (${status.events.join(", ")})`)}` : status.events.length ? c.yellow(`partly on (${status.events.join(", ")})`) : `off ${c.dim("\xB7 reflex cursor-usage on")}`],
32227
+ ["Recorded", rec.turns ? `${plural(rec.turns, "turn")} in ${plural(rec.conversations.size, "chat")}${rec.latest ? c.dim(` \xB7 latest ${rec.latest.slice(0, 16).replace("T", " ")} UTC`) : ""}` : c.dim("nothing yet")],
32228
+ ["Log", displayPath(paths.cursorUsage())]
32229
+ ]);
32230
+ if (status.error) warn(status.error);
32231
+ if (on && !await pathExists(hookScript())) warn("The hook script is missing; run reflex cursor-usage on again.");
32232
+ const store = new Store();
32233
+ try {
32234
+ if (store.latestScan() && rec.conversations.size) {
32235
+ const priced = store.traces().filter((t) => t.source === "cursor" && t.usage).length;
32236
+ out();
32237
+ out(` ${plural(priced, "Cursor chat")} in the last scan ${priced === 1 ? "has" : "have"} token counts. ${c.dim("reflex scan picks up new turns.")}`);
32238
+ }
32239
+ } finally {
32240
+ store.close();
32241
+ }
32242
+ out();
32243
+ out(c.dim("Cursor saves no token usage in its transcripts; its hooks receive it at the end of each agent turn. Only chats from when"));
32244
+ out(c.dim("the hook is on get counts. Cursor's command-line agent in -p mode sends no end-of-turn hook, so those runs have none."));
32245
+ }
32246
+ async function cursorUsageOn(opts) {
32247
+ assertHookSupported();
32248
+ const file2 = cursorHooksFile();
32249
+ title("Record Cursor token usage");
32250
+ out(" Cursor sends each agent turn's token counts to its hooks. Reflex adds one hook that writes only the chat and turn");
32251
+ out(" ids, the model and the four token counts to a local file. Never your prompt or the answer; no network.");
32252
+ out();
32253
+ rows([
32254
+ ["Hooks file", `${displayPath(file2)} ${c.dim(`(adds ${HOOK_EVENTS.join(" and ")}; your other hooks stay as they are; a backup goes to ~/.reflex/backups)`)}`],
32255
+ ["Runs", c.dim(hookCommand().replace(/'/g, ""))],
32256
+ ["Writes to", displayPath(paths.cursorUsage())]
32257
+ ]);
32258
+ out();
32259
+ if (!await confirm(`Add the hook to ${displayPath(file2)}?`, opts)) return;
32260
+ const { added, backup } = await installHook(file2);
32261
+ ok(added.length ? `Hook on (${added.join(", ")}). Cursor reloads hooks.json by itself; new turns are recorded from now on.` : "Hook was already on; its command is refreshed.");
32262
+ if (backup) out(c.dim(` Previous hooks file: ${displayPath(backup)}`));
32263
+ out(c.dim(" reflex scan attaches the counts to your Cursor chats. reflex cursor-usage off removes the hook."));
32264
+ }
32265
+ async function cursorUsageOff() {
32266
+ const { removed, backup } = await removeHook();
32267
+ if (!removed.length) ok("The hook was not on.");
32268
+ else ok(`Hook off (removed ${removed.join(", ")} from ${displayPath(cursorHooksFile())}).`);
32269
+ if (backup) out(c.dim(` Previous hooks file: ${displayPath(backup)}`));
32270
+ out(c.dim(` Recorded counts stay in ${displayPath(paths.cursorUsage())}; reflex reset deletes them.`));
32271
+ }
32272
+
31578
32273
  // src/commands/improve.ts
31579
32274
  import { randomUUID } from "node:crypto";
31580
32275
  import { existsSync as existsSync5 } from "node:fs";
31581
- import { delimiter, join as join20, resolve as resolve4 } from "node:path";
31582
- var onPath = (cmd) => (process.env.PATH ?? "").split(delimiter).some((d3) => d3 && existsSync5(join20(d3, cmd)));
32276
+ import { delimiter as delimiter2, join as join21, resolve as resolve4 } from "node:path";
32277
+ var onPath = (cmd) => (process.env.PATH ?? "").split(delimiter2).some((d3) => d3 && existsSync5(join21(d3, cmd)));
31583
32278
  var unique = (xs) => [...new Map(xs.map((x2) => [x2.sessionId, x2])).values()];
31584
32279
  async function listSkills2(store) {
31585
32280
  const traces = unique(store.traces());
@@ -31595,8 +32290,8 @@ async function listSkills2(store) {
31595
32290
  for (const n of names.sort((a, b3) => loaded(b3) - loaded(a) || a.localeCompare(b3))) {
31596
32291
  const mine = found.filter((f) => f.name === n);
31597
32292
  const where = [...mine.map((f) => f.target), ...mine.some((f) => f.link) ? ["linked"] : []];
31598
- const count2 = loaded(n);
31599
- out(` ${n.padEnd(28)} ${c.dim(where.join(", ").padEnd(28))} ${count2 ? `loaded in ${plural(count2, "session")}` : c.dim("not loaded in the last scan")}${own2.has(n) ? c.dim(" \xB7 generated by Reflex") : ""}`);
32293
+ const count3 = loaded(n);
32294
+ out(` ${n.padEnd(28)} ${c.dim(where.join(", ").padEnd(28))} ${count3 ? `loaded in ${plural(count3, "session")}` : c.dim("not loaded in the last scan")}${own2.has(n) ? c.dim(" \xB7 generated by Reflex") : ""}`);
31600
32295
  }
31601
32296
  out();
31602
32297
  out(c.dim(` reflex improve <name> compares a skill with the sessions that loaded it (needs ${MIN_REVIEW_SESSIONS}+).`));
@@ -31646,7 +32341,7 @@ async function verifyOutput(name, current, next, opts) {
31646
32341
  if (!Number.isInteger(runs) || runs < 1 || runs > 5) throw new Error("--runs must be 1 to 5.");
31647
32342
  if (!Number.isFinite(minutes) || minutes < 1 || minutes > 120) throw new Error("--timeout is minutes per run, 1 to 120.");
31648
32343
  out(c.dim(` The check runs "${task}" ${plural(runs, "time")} with each version: ${plural(runs * 2, "non-persistent Claude Code session")} on your account, project settings only,`));
31649
- const benchRoot = join20(paths.home(), "bench");
32344
+ const benchRoot = join21(paths.home(), "bench");
31650
32345
  out(c.dim(` in fresh copies of ${displayPath(root)} at ${headCommit(root) ?? "HEAD"} under ${displayPath(benchRoot)} (deleted afterwards). Answers are compared in memory, never saved.`));
31651
32346
  if (!await confirm(`Run the before/after check?`, opts)) return void 0;
31652
32347
  await ensureDir(paths.home(), 448);
@@ -31658,7 +32353,7 @@ async function verifyOutput(name, current, next, opts) {
31658
32353
  for (let i = 0; i < runs; i++) {
31659
32354
  const shapes = { before: [], after: [] };
31660
32355
  for (const side of ["before", "after"]) {
31661
- const dir = join20(benchRoot, `improve-${name}-${side}-${randomUUID().slice(0, 8)}`);
32356
+ const dir = join21(benchRoot, `improve-${name}-${side}-${randomUUID().slice(0, 8)}`);
31662
32357
  cloneRepo(root, dir);
31663
32358
  const spin = spinner();
31664
32359
  try {
@@ -31724,19 +32419,19 @@ async function improve(name, opts) {
31724
32419
  const behavior = opts.behavior === true;
31725
32420
  out();
31726
32421
  renderReview(review, behavior);
31727
- const section = learnedSection(review, { behavior });
31728
- if (!section) {
32422
+ const section2 = learnedSection(review, { behavior });
32423
+ if (!section2) {
31729
32424
  ok(
31730
32425
  behavior || !review.missing.length && !review.constraints.length ? `Nothing to add: ${name} already covers what these sessions did.` : `Nothing to add that keeps ${name} doing exactly what it does. --behavior proposes the steps and corrections above.`
31731
32426
  );
31732
32427
  return;
31733
32428
  }
31734
- const next = applyLearned(content, section);
31735
- const proposalDir = assertInside(paths.home(), join20(paths.home(), "proposals", name));
32429
+ const next = applyLearned(content, section2);
32430
+ const proposalDir = assertInside(paths.home(), join21(paths.home(), "proposals", name));
31736
32431
  await ensureDir(paths.home(), 448);
31737
- await ensureDir(join20(paths.home(), "proposals"), 448);
32432
+ await ensureDir(join21(paths.home(), "proposals"), 448);
31738
32433
  await ensureDir(proposalDir, 448);
31739
- const proposal = join20(proposalDir, "SKILL.md");
32434
+ const proposal = join21(proposalDir, "SKILL.md");
31740
32435
  await replaceOwnedFile(proposal, next, 384);
31741
32436
  out(c.bold("Proposed change"));
31742
32437
  fileBlock(displayPath(target.path), lineDiff(content, next));
@@ -31782,7 +32477,7 @@ async function improve(name, opts) {
31782
32477
  if (store.installations(name).some((i) => resolve4(i.path) === resolve4(target.path)))
31783
32478
  warn("Reflex installed this copy; after the change it counts as edited, so `reflex install`/remove will leave it alone.");
31784
32479
  if (!await confirm(`Apply it to ${displayPath(target.path)}? The current file is backed up first.`, opts)) return;
31785
- const backup = await applyToOwnSkill(target.path, sha256(content), next, join20(paths.home(), "backups"), name);
32480
+ const backup = await applyToOwnSkill(target.path, sha256(content), next, join21(paths.home(), "backups"), name);
31786
32481
  store.updateSkillChange(changeId, { applied: true, backup: displayPath(backup) });
31787
32482
  ok(`Updated ${displayPath(target.path)}. Backup: ${displayPath(backup)}`);
31788
32483
  } finally {
@@ -31790,15 +32485,136 @@ async function improve(name, opts) {
31790
32485
  }
31791
32486
  }
31792
32487
 
32488
+ // src/commands/handbook.ts
32489
+ import { dirname as dirname8 } from "node:path";
32490
+ var TOOL = { "claude-code": "Claude Code", codex: "Codex", cursor: "Cursor" };
32491
+ function load() {
32492
+ const store = new Store();
32493
+ try {
32494
+ if (!store.latestScan()) throw new Error("No scan yet. Run `reflex scan --days 30` first.");
32495
+ const forgotten = new Set(store.memoryEntries().filter((e2) => e2.status === "forgotten").map((e2) => e2.text));
32496
+ return buildHandbook(store.traces(), { forgotten });
32497
+ } finally {
32498
+ store.close();
32499
+ }
32500
+ }
32501
+ function scope(practices, opts) {
32502
+ const known = new Map(practices.filter((p3) => p3.project).map((p3) => [p3.project.hash, p3.project]));
32503
+ if (opts.project) {
32504
+ const hit = [...known.values()].find((p3) => p3.name === opts.project || p3.hash === opts.project);
32505
+ if (!hit) throw new Error(`No practices for a repository named "${opts.project}". \`reflex handbook --all\` lists them.`);
32506
+ return hit;
32507
+ }
32508
+ for (let dir = process.cwd(); ; dir = dirname8(dir)) {
32509
+ const hit = known.get(shortHash(dir));
32510
+ if (hit) return hit;
32511
+ if (dirname8(dir) === dir) return {};
32512
+ }
32513
+ }
32514
+ function meta3(p3) {
32515
+ return `${plural(p3.sessions, "session")}${p3.last ? ` \xB7 last ${shortDate(p3.last)}` : ""} \xB7 ${p3.id}`;
32516
+ }
32517
+ function line(p3) {
32518
+ return ` ${p3.text}${p3.when ? c.cyan(` (${p3.when})`) : ""} ${c.dim(meta3(p3))}`;
32519
+ }
32520
+ function section(name, items) {
32521
+ if (!items.length) return;
32522
+ out(c.bold(` ${name}`));
32523
+ for (const p3 of items) out(line(p3));
32524
+ out();
32525
+ }
32526
+ var json2 = (value) => out(JSON.stringify(value, null, 2));
32527
+ async function handbook(opts) {
32528
+ const all = load();
32529
+ if (opts.all) {
32530
+ if (opts.json) return json2({ project: null, practices: all });
32531
+ title(`Handbook \xB7 every repository \xB7 ${plural(all.length, "practice")}`);
32532
+ const groups = /* @__PURE__ */ new Map();
32533
+ for (const p3 of all) groups.set(p3.project?.name ?? "Across repositories", [...groups.get(p3.project?.name ?? "Across repositories") ?? [], p3]);
32534
+ for (const [name, items] of groups) section(name, items);
32535
+ return;
32536
+ }
32537
+ const where = scope(all, opts);
32538
+ const practices = practicesFor(all, where.hash);
32539
+ if (opts.json) return json2({ project: where.hash ? where : null, practices });
32540
+ title(`Handbook \xB7 ${where.name ?? "no repository matched this folder"}`);
32541
+ if (!practices.length) {
32542
+ out("Nothing learned yet. Practices come from commands that worked and corrections you repeated, in at least 2 independent sessions.");
32543
+ return;
32544
+ }
32545
+ const own2 = practices.filter((p3) => p3.project);
32546
+ section("Commands that work here", own2.filter((p3) => p3.kind === "command"));
32547
+ section("Rules you gave agents here", own2.filter((p3) => p3.kind === "rule"));
32548
+ section("Rules across your repositories", practices.filter((p3) => !p3.project));
32549
+ out(c.dim(`reflex handbook show <id> \xB7 ask "<question>" \xB7 export \xB7 --json${where.hash ? "" : " \xB7 --project <name> \xB7 --all"}`));
32550
+ }
32551
+ async function handbookShow(id, opts) {
32552
+ const p3 = load().find((x2) => x2.id === id);
32553
+ if (!p3) throw new Error(`No practice ${id}. \`reflex handbook\` lists them with their ids.`);
32554
+ if (opts.json) return json2(p3);
32555
+ title(p3.text);
32556
+ if (p3.when) out(` Applies ${p3.when}.`);
32557
+ out(` ${p3.project?.name ? `In ${p3.project.name}` : "Across your repositories"} \xB7 ${plural(p3.sessions, "independent session")}`);
32558
+ out();
32559
+ out(c.bold(` Sessions behind it${p3.sessions > p3.sources.length ? ` (newest ${p3.sources.length})` : ""}`));
32560
+ for (const s of p3.sources) out(` ${shortDate(s.date)} ${(TOOL[s.tool] ?? s.tool).padEnd(11)} ${c.dim(s.request || "(no request text)")}`);
32561
+ }
32562
+ async function handbookAsk(words2, opts) {
32563
+ const question = words2.join(" ").trim();
32564
+ if (!question) throw new Error('Ask a question: reflex handbook ask "how do we run tests here?"');
32565
+ const all = load();
32566
+ const where = scope(all, opts);
32567
+ const answers = askHandbook(practicesFor(all, where.hash), question, where.hash);
32568
+ if (opts.json) return json2({ question, project: where.hash ? where : null, answers: answers.map((a) => ({ score: Number(a.score.toFixed(3)), ...a.practice })) });
32569
+ out();
32570
+ if (!answers.length) {
32571
+ out(`Nothing in the handbook${where.name ? ` for ${where.name}` : ""} answers that. Reflex only knows what past sessions showed.`);
32572
+ return;
32573
+ }
32574
+ for (const { practice: p3 } of answers) {
32575
+ out(`${c.green("\u203A")} ${p3.text}${p3.when ? c.cyan(` (${p3.when})`) : ""}`);
32576
+ out(c.dim(` ${p3.project?.name ? `in ${p3.project.name}` : "across your repositories"} \xB7 ${meta3(p3)} \xB7 reflex handbook show ${p3.id}`));
32577
+ }
32578
+ }
32579
+ async function handbookExport(opts) {
32580
+ const all = load();
32581
+ const where = opts.all ? {} : scope(all, opts);
32582
+ const practices = opts.all ? all : practicesFor(all, where.hash);
32583
+ const name = opts.all ? "all repositories" : where.name ?? "this folder";
32584
+ const entry = (p3) => `- ${p3.text}${p3.when ? ` *(${p3.when})*` : ""} \xB7 ${plural(p3.sessions, "session")}${p3.last ? `, last ${shortDate(p3.last)}` : ""}`;
32585
+ const lines = [
32586
+ `# Handbook: ${name}`,
32587
+ "",
32588
+ `Learned by Reflex from past coding-agent sessions, ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}. Each item held in at least 2 independent sessions; the count says how many.`,
32589
+ ""
32590
+ ];
32591
+ const groups = [
32592
+ ["Commands that work", practices.filter((p3) => p3.kind === "command")],
32593
+ ["Rules", practices.filter((p3) => p3.kind === "rule" && p3.project)],
32594
+ ["Rules across repositories", practices.filter((p3) => p3.kind === "rule" && !p3.project)]
32595
+ ];
32596
+ for (const [heading, items] of groups) {
32597
+ if (!items.length) continue;
32598
+ lines.push(`## ${heading}`, "");
32599
+ if (opts.all && heading !== "Rules across repositories") {
32600
+ const byRepo = /* @__PURE__ */ new Map();
32601
+ for (const p3 of items) byRepo.set(p3.project?.name ?? "unnamed", [...byRepo.get(p3.project?.name ?? "unnamed") ?? [], p3]);
32602
+ for (const [repo, ps] of byRepo) lines.push(`### ${repo}`, "", ...ps.map(entry), "");
32603
+ } else lines.push(...items.map(entry), "");
32604
+ }
32605
+ if (!practices.length) lines.push("Nothing learned yet.", "");
32606
+ out(lines.join("\n").trimEnd());
32607
+ }
32608
+
31793
32609
  // src/commands/route.ts
31794
32610
  import { spawnSync as spawnSync5 } from "node:child_process";
31795
32611
  import { randomInt, randomUUID as randomUUID2 } from "node:crypto";
31796
32612
  import { existsSync as existsSync6 } from "node:fs";
31797
- import { basename as basename7, delimiter as delimiter2, join as join21 } from "node:path";
32613
+ import { basename as basename7, delimiter as delimiter3, join as join22 } from "node:path";
31798
32614
  var CLI = { "claude-code": "claude", codex: "codex" };
31799
32615
  var MODEL_NAME2 = /^[A-Za-z0-9][A-Za-z0-9._:[\]-]{0,63}$/;
31800
32616
  var CODEX_MODEL = /^(gpt|o\d|codex)/i;
31801
- var onPath2 = (cmd) => (process.env.PATH ?? "").split(delimiter2).some((d3) => d3 && existsSync6(join21(d3, cmd)));
32617
+ var onPath2 = (cmd) => (process.env.PATH ?? "").split(delimiter3).some((d3) => d3 && existsSync6(join22(d3, cmd)));
31802
32618
  var unique2 = (traces) => [...new Map(traces.map((t) => [t.sessionId, t])).values()];
31803
32619
  var usd = (n) => n === void 0 ? "\u2014" : n < 0.01 ? "<$0.01" : `$${n.toFixed(2)}`;
31804
32620
  var fixes = (f) => `${f.toFixed(2)} fixes/request`;
@@ -31903,7 +32719,8 @@ async function runRouted(words2, opts) {
31903
32719
  if (!run2) return;
31904
32720
  const model2 = run2.model ? ["--model", run2.model] : [];
31905
32721
  const args = run2.source === "claude-code" ? [...model2, "--session-id", run2.nativeId, request] : [...model2, request];
31906
- const res = spawnSync5(CLI[run2.source], args, { stdio: "inherit" });
32722
+ const launch = agentLaunch(CLI[run2.source], args);
32723
+ const res = spawnSync5(launch.command, launch.args, { stdio: "inherit", windowsVerbatimArguments: launch.windowsVerbatimArguments });
31907
32724
  if (res.error) throw new Error(`Could not start ${CLI[run2.source]}: ${res.error.message}`);
31908
32725
  process.exitCode = res.status ?? 0;
31909
32726
  if (opts.ask !== false && interactive()) await askOutcome(runId);
@@ -32017,7 +32834,7 @@ async function bench(words2, opts) {
32017
32834
  const traces = unique2(store.traces());
32018
32835
  const kind = classifyRequest(task, traces).kind;
32019
32836
  const { tools, agentCanRunCheck } = benchTools(opts.check);
32020
- const benchRoot = join21(paths.home(), "bench");
32837
+ const benchRoot = join22(paths.home(), "bench");
32021
32838
  const total = runs * models.length;
32022
32839
  const table2 = routingTable(traces);
32023
32840
  const typical = models.map((m2) => ({ m: m2, cost: typicalCost(table2, "claude-code", m2) }));
@@ -32051,7 +32868,7 @@ async function bench(words2, opts) {
32051
32868
  await ensureDir(benchRoot, 448);
32052
32869
  const batch = randomUUID2().slice(0, 8);
32053
32870
  const timeoutMs = minutes * 6e4;
32054
- const baseline = join21(benchRoot, `${batch}-before`);
32871
+ const baseline = join22(benchRoot, `${batch}-before`);
32055
32872
  cloneRepo(root, baseline);
32056
32873
  try {
32057
32874
  if (opts.setup && !runUserCommand(baseline, opts.setup, timeoutMs)) throw new Error(`The setup command failed in a fresh copy: \`${opts.setup}\`. Fix it, then run bench again.`);
@@ -32064,7 +32881,7 @@ async function bench(words2, opts) {
32064
32881
  for (let i = 0; i < runs; i++) {
32065
32882
  const order = models.map((_3, j2) => models[(i + j2) % models.length]);
32066
32883
  for (const model2 of order) {
32067
- const dir = join21(benchRoot, `${batch}-${model2.replace(/[^A-Za-z0-9.-]/g, "_")}-${i + 1}`);
32884
+ const dir = join22(benchRoot, `${batch}-${model2.replace(/[^A-Za-z0-9.-]/g, "_")}-${i + 1}`);
32068
32885
  cloneRepo(root, dir);
32069
32886
  const spin = spinner();
32070
32887
  try {
@@ -32207,8 +33024,8 @@ function hcat(blocks, gap) {
32207
33024
  for (let i = 0; i < h2; i++) {
32208
33025
  let l2 = [];
32209
33026
  blocks.forEach((b3, j2) => {
32210
- const line = b3.lines[i];
32211
- l2 = l2.concat(line ? fit(line, b3.w) : [S2(" ".repeat(b3.w))]);
33027
+ const line2 = b3.lines[i];
33028
+ l2 = l2.concat(line2 ? fit(line2, b3.w) : [S2(" ".repeat(b3.w))]);
32212
33029
  if (j2 < blocks.length - 1) l2.push(S2(" ".repeat(gap)));
32213
33030
  });
32214
33031
  out2.push(l2);
@@ -32381,18 +33198,18 @@ function hbars(title2, items, w2, o2 = {}) {
32381
33198
  function mdLines(src, w2) {
32382
33199
  const out2 = [];
32383
33200
  let fm = 0;
32384
- src.forEach((line) => {
33201
+ src.forEach((line2) => {
32385
33202
  let c2 = "fg";
32386
33203
  let b3 = null;
32387
- if (line === "---") {
33204
+ if (line2 === "---") {
32388
33205
  fm++;
32389
33206
  c2 = "dim";
32390
33207
  } else if (fm === 1) c2 = "dim";
32391
- else if (line.startsWith("#")) {
33208
+ else if (line2.startsWith("#")) {
32392
33209
  c2 = "hi";
32393
33210
  b3 = BOLD;
32394
33211
  }
32395
- wrap(line, w2).forEach((t) => out2.push([S2(t, c2, b3)]));
33212
+ wrap(line2, w2).forEach((t) => out2.push([S2(t, c2, b3)]));
32396
33213
  });
32397
33214
  return out2;
32398
33215
  }
@@ -32702,8 +33519,8 @@ function renderMorning(w2, h2, data, _ui) {
32702
33519
  ...data.skills.items.map((x2) => ({ k: "skill", x: x2 })),
32703
33520
  ...(data.workflows?.items ?? []).map((x2) => ({ k: "wf", x: x2 }))
32704
33521
  ];
32705
- const tail = 4;
32706
- const cap = Math.max(2, Math.min(8, h2 - L3.length - tail - 3));
33522
+ const tail2 = 4;
33523
+ const cap = Math.max(2, Math.min(8, h2 - L3.length - tail2 - 3));
32707
33524
  const cw3 = Math.floor((w2 - 6) / 3);
32708
33525
  const col = (k3) => {
32709
33526
  const xs = all.filter((e2) => e2.x.state === k3);
@@ -34145,7 +34962,12 @@ function runTui(opts) {
34145
34962
  const resume = async (c2) => {
34146
34963
  let error62;
34147
34964
  await term.suspend(() => {
34148
- error62 = spawnSync6(c2.cmd, c2.args, { stdio: "inherit", cwd: c2.cwd }).error;
34965
+ try {
34966
+ const launch = agentLaunch(c2.cmd, c2.args);
34967
+ error62 = spawnSync6(launch.command, launch.args, { stdio: "inherit", cwd: c2.cwd, windowsVerbatimArguments: launch.windowsVerbatimArguments }).error;
34968
+ } catch (e2) {
34969
+ error62 = e2 instanceof Error ? e2 : new Error(String(e2));
34970
+ }
34149
34971
  });
34150
34972
  term.invalidate();
34151
34973
  await reload();
@@ -34235,12 +35057,12 @@ var weekdayLabel = (d3) => `${WEEKDAYS[d3.getDay()]} ${dayLabel(d3).toLowerCase(
34235
35057
  var rangeLabel = (from, to) => `${dayLabel(from).toLowerCase()} \u2013 ${dayLabel(to).toLowerCase()}`;
34236
35058
  var clockLabel = (d3) => `${pad2(d3.getHours())}:${pad2(d3.getMinutes())}`;
34237
35059
  var dayStart = (d3, n = 0) => new Date(d3.getFullYear(), d3.getMonth(), d3.getDate() + n);
34238
- var count = (n) => n.toLocaleString("en-US");
35060
+ var count2 = (n) => n.toLocaleString("en-US");
34239
35061
 
34240
35062
  // ../../packages/tui/src/live/skills.ts
34241
35063
  import { constants as constants4 } from "node:fs";
34242
35064
  import { lstat as lstat9, open as open6 } from "node:fs/promises";
34243
- import { join as join22 } from "node:path";
35065
+ import { join as join23 } from "node:path";
34244
35066
  var MAX_SKILL_BYTES = 64 * 1024;
34245
35067
  var TOOL_OF = { "claude-code": "claude", codex: "codex", cursor: "cursor" };
34246
35068
  var toolName = (target) => toCells(TOOL_OF[target] ?? target);
@@ -34264,11 +35086,11 @@ async function readCapped(file2) {
34264
35086
  }
34265
35087
  async function readReflexCopy(name) {
34266
35088
  if (!isValidSlug(name)) return void 0;
34267
- const dir = join22(paths.skills(), name);
35089
+ const dir = join23(paths.skills(), name);
34268
35090
  if (await isSymlink(paths.skills()) || await isSymlink(dir)) return void 0;
34269
- return readCapped(join22(dir, "SKILL.md"));
35091
+ return readCapped(join23(dir, "SKILL.md"));
34270
35092
  }
34271
- async function isFile2(path) {
35093
+ async function isFile3(path) {
34272
35094
  try {
34273
35095
  return (await lstat9(path)).isFile();
34274
35096
  } catch {
@@ -34292,7 +35114,7 @@ async function skillItems(store, scan2, targets, now) {
34292
35114
  const names = new Set(generated.map((k3) => k3.name));
34293
35115
  const installs = store.installations();
34294
35116
  const installed = async (name) => {
34295
- for (const r2 of installs) if (r2.skill === name && await isFile2(r2.path)) return true;
35117
+ for (const r2 of installs) if (r2.skill === name && await isFile3(r2.path)) return true;
34296
35118
  return false;
34297
35119
  };
34298
35120
  const path = (name) => claude ? toCells(`${displayPath(claude.skillsDir)}/${name}/SKILL.md`) : "";
@@ -34315,7 +35137,7 @@ async function skillItems(store, scan2, targets, now) {
34315
35137
  state: found.has(k3.suggestionSlug) ? "" : "retired",
34316
35138
  steps: s?.steps.length ?? 0,
34317
35139
  path: path(name),
34318
- markdown: text === void 0 ? [toCells(`could not read ${displayPath(join22(paths.skills(), k3.name, "SKILL.md"))}`)] : toLines(text)
35140
+ markdown: text === void 0 ? [toCells(`could not read ${displayPath(join23(paths.skills(), k3.name, "SKILL.md"))}`)] : toLines(text)
34319
35141
  });
34320
35142
  }
34321
35143
  return { items, targets: targets.filter((t) => t.detected).map((t) => toCells(`${displayPath(t.skillsDir)}/<name>/SKILL.md`)) };
@@ -34516,29 +35338,29 @@ function buildRouter(priced, rebuiltAt, windowDays2, autopilot = false) {
34516
35338
  }
34517
35339
 
34518
35340
  // ../../packages/tui/src/live/search.ts
34519
- import { closeSync, constants as constants5, existsSync as existsSync7, lstatSync as lstatSync2, openSync, readSync, readdirSync, statSync as statSync2 } from "node:fs";
34520
- import { basename as basename8, delimiter as delimiter3, join as join23 } from "node:path";
35341
+ import { closeSync as closeSync2, constants as constants5, existsSync as existsSync7, lstatSync as lstatSync2, openSync as openSync2, readSync as readSync2, readdirSync, statSync as statSync3 } from "node:fs";
35342
+ import { basename as basename8, join as join24 } from "node:path";
34521
35343
  var SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$/;
34522
35344
  var MAX_CWD_SCAN_BYTES = 256 * 1024;
34523
35345
  function buildSearch(priced) {
34524
35346
  const sessions2 = /* @__PURE__ */ new Map();
34525
35347
  const bySession = /* @__PURE__ */ new Map();
34526
- const meta3 = /* @__PURE__ */ new Map();
35348
+ const meta4 = /* @__PURE__ */ new Map();
34527
35349
  const all = [];
34528
35350
  for (const { t, at, tool, cost } of priced) {
34529
35351
  const nativeId = t.sessionId.slice(t.source.length + 1);
34530
35352
  const key3 = sessions2.has(nativeId.slice(0, 8)) ? nativeId : nativeId.slice(0, 8);
34531
35353
  sessions2.set(key3, { source: t.source, nativeId });
34532
- meta3.set(key3, { usd: cost?.usd, turnCount: t.requests });
35354
+ meta4.set(key3, { usd: cost?.usd, turnCount: t.requests });
34533
35355
  const base = { date: at ? dayLabel(new Date(at)) : "\u2014", tool, project: toCells(t.projectName ?? "\u2014"), session: toCells(key3), at };
34534
35356
  const texts = [["you", t.excerpt], ...t.displaySteps.map((s) => ["ai", s])];
34535
- const entries = [];
35357
+ const entries2 = [];
34536
35358
  texts.forEach(([role, raw], i) => {
34537
35359
  const text = toCells(raw).trim();
34538
- if (text) entries.push({ ...base, turn: i + 1, role, text, lower: text.toLowerCase() });
35360
+ if (text) entries2.push({ ...base, turn: i + 1, role, text, lower: text.toLowerCase() });
34539
35361
  });
34540
- bySession.set(key3, entries);
34541
- all.push(...entries);
35362
+ bySession.set(key3, entries2);
35363
+ all.push(...entries2);
34542
35364
  }
34543
35365
  all.sort((a, b3) => b3.at - a.at || b3.turn - a.turn);
34544
35366
  const index = {
@@ -34548,7 +35370,7 @@ function buildSearch(priced) {
34548
35370
  return all.filter((e2) => (tool === "all" || e2.tool === tool) && (!needle || e2.lower.includes(needle)));
34549
35371
  },
34550
35372
  session(id) {
34551
- return { turns: bySession.get(id) ?? [], ...meta3.get(id) };
35373
+ return { turns: bySession.get(id) ?? [], ...meta4.get(id) };
34552
35374
  }
34553
35375
  };
34554
35376
  return { index, sessions: sessions2 };
@@ -34562,24 +35384,24 @@ function claudeCwd(nativeId) {
34562
35384
  return void 0;
34563
35385
  }
34564
35386
  for (const dir of dirs) {
34565
- const file2 = join23(root, dir, `${nativeId}.jsonl`);
35387
+ const file2 = join24(root, dir, `${nativeId}.jsonl`);
34566
35388
  try {
34567
35389
  if (!lstatSync2(file2).isFile()) continue;
34568
35390
  } catch {
34569
35391
  continue;
34570
35392
  }
34571
- const fd = openSync(file2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
35393
+ const fd = openSync2(file2, constants5.O_RDONLY | constants5.O_NOFOLLOW);
34572
35394
  const buf = Buffer.alloc(MAX_CWD_SCAN_BYTES);
34573
35395
  let n;
34574
35396
  try {
34575
- n = readSync(fd, buf, 0, buf.length, 0);
35397
+ n = readSync2(fd, buf, 0, buf.length, 0);
34576
35398
  } finally {
34577
- closeSync(fd);
35399
+ closeSync2(fd);
34578
35400
  }
34579
- for (const line of buf.subarray(0, n).toString("utf8").split("\n")) {
35401
+ for (const line2 of buf.subarray(0, n).toString("utf8").split("\n")) {
34580
35402
  try {
34581
- const cwd = JSON.parse(line).cwd;
34582
- if (typeof cwd === "string" && statSync2(cwd).isDirectory()) return cwd;
35403
+ const cwd = JSON.parse(line2).cwd;
35404
+ if (typeof cwd === "string" && statSync3(cwd).isDirectory()) return cwd;
34583
35405
  } catch {
34584
35406
  continue;
34585
35407
  }
@@ -34596,10 +35418,9 @@ function cursorWorkspace(nativeId) {
34596
35418
  } catch {
34597
35419
  return void 0;
34598
35420
  }
34599
- const dir = dirs.find((d3) => existsSync7(join23(root, d3, "agent-transcripts", nativeId)));
35421
+ const dir = dirs.find((d3) => existsSync7(join24(root, d3, "agent-transcripts", nativeId)));
34600
35422
  return dir ? decodeWorkspace(dir) : void 0;
34601
35423
  }
34602
- var onPath3 = (cmd) => (process.env.PATH ?? "").split(delimiter3).some((d3) => d3 && existsSync7(join23(d3, cmd)));
34603
35424
  function resumeCommand(ref) {
34604
35425
  if (!ref || !SESSION_ID.test(ref.nativeId)) return { ok: false, message: "this session cannot be resumed", tone: "dim" };
34605
35426
  const id = ref.nativeId;
@@ -34612,14 +35433,14 @@ function resumeCommand(ref) {
34612
35433
  const dir = cursorWorkspace(id);
34613
35434
  if (!dir) return { ok: false, message: "this Cursor chat has no workspace folder on this machine", tone: "dim" };
34614
35435
  const done = `opened ${toCells(basename8(dir))} in Cursor \xB7 the chat is in its agent history`;
34615
- if (onPath3("cursor")) return { cmd: "cursor", args: [dir], done };
35436
+ if (findOnPath("cursor")) return { cmd: "cursor", args: [dir], done };
34616
35437
  if (process.platform === "darwin") return { cmd: "open", args: ["-a", "Cursor", dir], done };
34617
35438
  return { ok: false, message: `open ${toCells(dir)} in Cursor; the chat is in its agent history`, tone: "dim" };
34618
35439
  }
34619
35440
 
34620
35441
  // ../../packages/tui/src/live/workflows.ts
34621
35442
  var MAX_EVIDENCE = 12;
34622
- var plural4 = (n, one, many = `${one}s`) => `${count(n)} ${n === 1 ? one : many}`;
35443
+ var plural4 = (n, one, many = `${one}s`) => `${count2(n)} ${n === 1 ? one : many}`;
34623
35444
  function workflowMarkdown(s) {
34624
35445
  const tools = SOURCE_IDS.filter((x2) => s.sources[x2]).map((x2) => `${TOOL_OF[x2]} ${s.sources[x2]}`);
34625
35446
  const L3 = [`# ${s.title}`, "", s.description, ""];
@@ -34627,7 +35448,7 @@ function workflowMarkdown(s) {
34627
35448
  L3.push(`confidence ${s.confidence.toFixed(2)} \xB7 verified in ${Math.round(s.verifiedRate * 100)}% of runs`);
34628
35449
  const cost = [];
34629
35450
  if (s.cost?.medianTokens !== void 0) cost.push(`median ${tok2(s.cost.medianTokens)} tokens`);
34630
- if (s.cost?.medianToolCalls !== void 0) cost.push(`median ${count(s.cost.medianToolCalls)} tool calls`);
35451
+ if (s.cost?.medianToolCalls !== void 0) cost.push(`median ${count2(s.cost.medianToolCalls)} tool calls`);
34631
35452
  if (s.medianMinutes !== void 0) cost.push(`median ${s.medianMinutes < 120 ? `${Math.round(s.medianMinutes)} min` : `${(s.medianMinutes / 60).toFixed(1)} h`}`);
34632
35453
  if (cost.length) L3.push(`${cost.join(" \xB7 ")} per run`);
34633
35454
  L3.push("", "## Steps", "");
@@ -34649,7 +35470,7 @@ function workflowMarkdown(s) {
34649
35470
  const date5 = e2.date ? dayLabel(new Date(e2.date)) : "\u2014";
34650
35471
  L3.push(`- ${date5} ${TOOL_OF[e2.source]} ${e2.project ?? "\u2014"} ${e2.excerpt}`);
34651
35472
  }
34652
- if (s.evidence.length > MAX_EVIDENCE) L3.push(`- +${count(s.evidence.length - MAX_EVIDENCE)} more (reflex evidence ${s.slug})`);
35473
+ if (s.evidence.length > MAX_EVIDENCE) L3.push(`- +${count2(s.evidence.length - MAX_EVIDENCE)} more (reflex evidence ${s.slug})`);
34653
35474
  return L3.map(toCells);
34654
35475
  }
34655
35476
  function workflowItems(suggestions, skillOf, skills, foundOn) {
@@ -34801,21 +35622,21 @@ function addCosts(data, c2) {
34801
35622
  var uniqueSessions = (traces) => [...new Map(traces.map((t) => [t.sessionId, t])).values()];
34802
35623
  function totals(traces) {
34803
35624
  const usage2 = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
34804
- let recorded = 0;
35625
+ let recorded2 = 0;
34805
35626
  for (const t of traces) {
34806
35627
  if (!t.usage) continue;
34807
- recorded++;
35628
+ recorded2++;
34808
35629
  usage2.input += t.usage.input;
34809
35630
  usage2.output += t.usage.output;
34810
35631
  usage2.cacheRead += t.usage.cacheRead;
34811
35632
  usage2.cacheWrite += t.usage.cacheWrite;
34812
35633
  }
34813
- return { sessions: traces.length, usage: usage2, measured: traces.length === 0 || recorded > 0 };
35634
+ return { sessions: traces.length, usage: usage2, measured: traces.length === 0 || recorded2 > 0 };
34814
35635
  }
34815
35636
  function cursorModels(traces) {
34816
35637
  const counts = /* @__PURE__ */ new Map();
34817
35638
  for (const t of traces) {
34818
- const m2 = t.source === "cursor" ? t.models?.[0] : void 0;
35639
+ const m2 = t.source === "cursor" && !t.usage ? t.models?.[0] : void 0;
34819
35640
  if (m2) counts.set(m2, (counts.get(m2) ?? 0) + 1);
34820
35641
  }
34821
35642
  if (!counts.size) return void 0;
@@ -34861,9 +35682,9 @@ function attention2(items) {
34861
35682
  return out2;
34862
35683
  }
34863
35684
  async function agentMemory(store) {
34864
- const entries = store.memoryEntries().filter((e2) => e2.status === "active").map((e2) => ({ text: toCells(e2.text), sessions: e2.sessions, origin: e2.origin }));
35685
+ const entries2 = store.memoryEntries().filter((e2) => e2.status === "active").map((e2) => ({ text: toCells(e2.text), sessions: e2.sessions, origin: e2.origin }));
34865
35686
  const files = (await memoryTargets()).filter((t) => t.detected).map((t) => toCells(displayPath(t.file)));
34866
- return { enabled: store.memoryState().enabled, entries, files };
35687
+ return { enabled: store.memoryState().enabled, entries: entries2, files };
34867
35688
  }
34868
35689
 
34869
35690
  // src/commands/tui.ts
@@ -34906,8 +35727,7 @@ async function tui() {
34906
35727
 
34907
35728
  // src/main.ts
34908
35729
  quietSqliteWarning();
34909
- var fetchingModel = process.argv[2] === "model" && process.argv[3] === "fetch";
34910
- if (!fetchingModel) installNetworkGuard();
35730
+ installNetworkGuard();
34911
35731
  process.stdout.on("error", (err) => {
34912
35732
  if (err.code === "EPIPE") process.exit(0);
34913
35733
  throw err;
@@ -34925,7 +35745,7 @@ function run(fn) {
34925
35745
  };
34926
35746
  }
34927
35747
  var program2 = new Command();
34928
- program2.name("reflex").description("Find workflows you keep re-teaching Claude Code, Codex and Cursor, and turn proven repeats into reusable skills. Everything runs locally.").version("0.5.0").allowExcessArguments().action(
35748
+ program2.name("reflex").description("Find workflows you keep re-teaching Claude Code, Codex and Cursor, and turn proven repeats into reusable skills. Everything runs locally.").version("0.5.2").allowExcessArguments().action(
34929
35749
  run(async () => {
34930
35750
  if (program2.args.length) program2.error(`error: unknown command '${program2.args[0]}'. See \`reflex --help\`.`);
34931
35751
  if (process.stdin.isTTY && process.stdout.isTTY) await tui();
@@ -34940,6 +35760,10 @@ program2.command("scan").description("read recent coding-agent history (asks fir
34940
35760
  );
34941
35761
  program2.command("sessions").description("list sessions from the last scan (redacted)").action(run(sessions));
34942
35762
  program2.command("agents").description("sessions that launched agents (Cursor), what kinds, and how much work the agents did").action(run(agents));
35763
+ var handbookCmd = program2.command("handbook").description("how work is done in this repository, learned from past sessions (read-only, safe for agents)").option("--project <name>", "a repository by name instead of the current folder").option("--all", "every repository").option("--json", "machine-readable output").action(run(async (o2) => handbook(o2)));
35764
+ handbookCmd.command("show <id>").description("one practice and the sessions behind it").option("--json", "machine-readable output").action(run(async (id, _o, cmd) => handbookShow(id, cmd.optsWithGlobals())));
35765
+ handbookCmd.command("ask <question...>").description("practices that answer a question, with their sources").option("--project <name>", "a repository by name instead of the current folder").option("--json", "machine-readable output").action(run(async (q2, _o, cmd) => handbookAsk(q2, cmd.optsWithGlobals())));
35766
+ handbookCmd.command("export").description("a Markdown handbook for a teammate or new hire (no request text)").option("--project <name>", "a repository by name instead of the current folder").option("--all", "every repository").action(run(async (_o, cmd) => handbookExport(cmd.optsWithGlobals())));
34943
35767
  program2.command("suggest").description("detect repeated workflows and review them").option("--all", "include rejected suggestions").option("--no-interactive", "print suggestions without the review prompt").action(run(suggest));
34944
35768
  program2.command("show <suggestion>").description("show a suggestion in detail (number or name)").action(run(show));
34945
35769
  program2.command("evidence <suggestion>").description("show the sessions behind a suggestion").action(run(evidence));
@@ -34971,6 +35795,10 @@ route.command("status", { isDefault: true }).description("show picks, settings,
34971
35795
  route.command("autopilot <state>").description("on: reflex run starts on the pick without asking; off: it asks").action(run(routeAutopilot));
34972
35796
  route.command("explore <percent>").description("try another model you use on this share of reflex runs, chosen at random (off to stop)").option("--protect <kind...>", "kinds of task never explored: review, ci, debug, feature, edit, research, explore").action(run(async (value, o2) => routeExplore(value, o2)));
34973
35797
  program2.command("bench <task...>").description("run one task on several Claude Code models, each in a fresh copy of this repository, scored by your check command").requiredOption("--models <model...>", "models to compare, e.g. sonnet opus").requiredOption("--check <command>", 'command that passes (exit 0) when the task is done, e.g. "pnpm test"').option("--setup <command>", 'command to prepare each copy, e.g. "pnpm install --frozen-lockfile"').option("--runs <n>", "runs per model", "1").option("--timeout <minutes>", "time limit per run", "20").option("--keep", "keep the copies for inspection").option("-y, --yes", "start without asking").action(run(async (words2, o2) => bench(words2, o2)));
35798
+ var cursorUsage = program2.command("cursor-usage").description("record Cursor's token counts locally through a Cursor hook (Cursor saves none in its transcripts)");
35799
+ cursorUsage.command("status", { isDefault: true }).description("whether the hook is on and what it has recorded").action(run(cursorUsageStatus));
35800
+ cursorUsage.command("on").description("add Reflex's hook to ~/.cursor/hooks.json (asks first; keeps your other hooks)").option("-y, --yes", "add it without prompting").action(run(cursorUsageOn));
35801
+ cursorUsage.command("off").description("remove Reflex's hook; recorded counts stay").action(run(cursorUsageOff));
34974
35802
  program2.command("stats").description("defensible counts from local data").action(run(stats2));
34975
35803
  program2.command("reset").description("delete Reflex's own local data (not installed skills)").option("-y, --yes", "consent without prompting").action(run(reset));
34976
35804
  await program2.parseAsync(process.argv);