reasonix 0.22.0 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -477,10 +477,10 @@ function globalSettingsPath(homeDirOverride) {
477
477
  function projectSettingsPath(projectRoot) {
478
478
  return join(projectRoot, HOOK_SETTINGS_DIRNAME, HOOK_SETTINGS_FILENAME);
479
479
  }
480
- function readSettingsFile(path) {
481
- if (!existsSync(path)) return null;
480
+ function readSettingsFile(path2) {
481
+ if (!existsSync(path2)) return null;
482
482
  try {
483
- const raw = readFileSync(path, "utf8");
483
+ const raw = readFileSync(path2, "utf8");
484
484
  const parsed = JSON.parse(raw);
485
485
  if (parsed && typeof parsed === "object") return parsed;
486
486
  } catch {
@@ -890,14 +890,14 @@ function collect(prefix, schema, out, required, isRootRequired) {
890
890
  out[prefix] = schema;
891
891
  if (isRootRequired) required.push(prefix);
892
892
  }
893
- function setByPath(target, path, value) {
893
+ function setByPath(target, path2, value) {
894
894
  let cur = target;
895
- for (let i = 0; i < path.length - 1; i++) {
896
- const key = path[i];
895
+ for (let i = 0; i < path2.length - 1; i++) {
896
+ const key = path2[i];
897
897
  if (typeof cur[key] !== "object" || cur[key] === null) cur[key] = {};
898
898
  cur = cur[key];
899
899
  }
900
- cur[path[path.length - 1]] = value;
900
+ cur[path2[path2.length - 1]] = value;
901
901
  }
902
902
 
903
903
  // src/tools.ts
@@ -1311,10 +1311,10 @@ function sanitizeName(name) {
1311
1311
  return cleaned || "default";
1312
1312
  }
1313
1313
  function loadSessionMessages(name) {
1314
- const path = sessionPath(name);
1315
- if (!existsSync3(path)) return [];
1314
+ const path2 = sessionPath(name);
1315
+ if (!existsSync3(path2)) return [];
1316
1316
  try {
1317
- const raw = readFileSync3(path, "utf8");
1317
+ const raw = readFileSync3(path2, "utf8");
1318
1318
  const out = [];
1319
1319
  for (const line of raw.split(/\r?\n/)) {
1320
1320
  const trimmed = line.trim();
@@ -1331,12 +1331,12 @@ function loadSessionMessages(name) {
1331
1331
  }
1332
1332
  }
1333
1333
  function appendSessionMessage(name, message) {
1334
- const path = sessionPath(name);
1335
- mkdirSync(dirname2(path), { recursive: true });
1336
- appendFileSync(path, `${JSON.stringify(message)}
1334
+ const path2 = sessionPath(name);
1335
+ mkdirSync(dirname2(path2), { recursive: true });
1336
+ appendFileSync(path2, `${JSON.stringify(message)}
1337
1337
  `, "utf8");
1338
1338
  try {
1339
- chmodSync(path, 384);
1339
+ chmodSync(path2, 384);
1340
1340
  } catch {
1341
1341
  }
1342
1342
  }
@@ -1348,13 +1348,13 @@ function listSessions() {
1348
1348
  (f) => f.endsWith(".jsonl") && !f.endsWith(".events.jsonl")
1349
1349
  );
1350
1350
  return files.map((file) => {
1351
- const path = join3(dir, file);
1352
- const stat2 = statSync(path);
1351
+ const path2 = join3(dir, file);
1352
+ const stat2 = statSync(path2);
1353
1353
  const name = file.replace(/\.jsonl$/, "");
1354
- const messageCount = countLines(path);
1354
+ const messageCount = countLines(path2);
1355
1355
  return {
1356
1356
  name,
1357
- path,
1357
+ path: path2,
1358
1358
  size: stat2.size,
1359
1359
  messageCount,
1360
1360
  mtime: stat2.mtime,
@@ -1379,11 +1379,11 @@ function loadSessionMeta(name) {
1379
1379
  }
1380
1380
  }
1381
1381
  function deleteSession(name) {
1382
- const path = sessionPath(name);
1382
+ const path2 = sessionPath(name);
1383
1383
  try {
1384
- unlinkSync(path);
1384
+ unlinkSync(path2);
1385
1385
  for (const ext of [".events.jsonl", ".pending.json", ".meta.json", ".plan.json"]) {
1386
- const sidecar = path.replace(/\.jsonl$/, ext);
1386
+ const sidecar = path2.replace(/\.jsonl$/, ext);
1387
1387
  try {
1388
1388
  unlinkSync(sidecar);
1389
1389
  } catch {
@@ -1395,19 +1395,19 @@ function deleteSession(name) {
1395
1395
  }
1396
1396
  }
1397
1397
  function rewriteSession(name, messages) {
1398
- const path = sessionPath(name);
1399
- mkdirSync(dirname2(path), { recursive: true });
1398
+ const path2 = sessionPath(name);
1399
+ mkdirSync(dirname2(path2), { recursive: true });
1400
1400
  const body = messages.map((m) => JSON.stringify(m)).join("\n");
1401
- writeFileSync(path, body ? `${body}
1401
+ writeFileSync(path2, body ? `${body}
1402
1402
  ` : "", "utf8");
1403
1403
  try {
1404
- chmodSync(path, 384);
1404
+ chmodSync(path2, 384);
1405
1405
  } catch {
1406
1406
  }
1407
1407
  }
1408
- function countLines(path) {
1408
+ function countLines(path2) {
1409
1409
  try {
1410
- const raw = readFileSync3(path, "utf8");
1410
+ const raw = readFileSync3(path2, "utf8");
1411
1411
  return raw.split(/\r?\n/).filter((l) => l.trim()).length;
1412
1412
  } catch {
1413
1413
  return 0;
@@ -1573,7 +1573,7 @@ var StormBreaker = class {
1573
1573
  if (count >= this.threshold - 1) {
1574
1574
  return {
1575
1575
  suppress: true,
1576
- reason: `call-storm suppressed: ${name} called with identical args ${count + 1} times within window=${this.windowSize}`
1576
+ reason: `${name} called with identical args ${count + 1} times \u2014 repeat-loop guard tripped`
1577
1577
  };
1578
1578
  }
1579
1579
  this.recent.push({ name, args, readOnly });
@@ -1858,6 +1858,7 @@ var CacheFirstLoop = class {
1858
1858
  _escalateThisTurn = false;
1859
1859
  _turnFailureCount = 0;
1860
1860
  _turnFailureTypes = {};
1861
+ _turnSelfCorrected = false;
1861
1862
  constructor(opts) {
1862
1863
  this.client = opts.client;
1863
1864
  this.prefix = opts.prefix;
@@ -1902,7 +1903,12 @@ var CacheFirstLoop = class {
1902
1903
  }
1903
1904
  return def.readOnly !== true;
1904
1905
  };
1905
- this.repair = new ToolCallRepair({ allowedToolNames: allowedNames, isMutating });
1906
+ this.repair = new ToolCallRepair({
1907
+ allowedToolNames: allowedNames,
1908
+ isMutating,
1909
+ stormThreshold: parsePositiveIntEnv(process.env.REASONIX_STORM_THRESHOLD),
1910
+ stormWindow: parsePositiveIntEnv(process.env.REASONIX_STORM_WINDOW)
1911
+ });
1906
1912
  this.sessionName = opts.session ?? null;
1907
1913
  if (this.sessionName) {
1908
1914
  const prior = loadSessionMessages(this.sessionName);
@@ -1984,6 +1990,21 @@ var CacheFirstLoop = class {
1984
1990
  }
1985
1991
  }
1986
1992
  }
1993
+ /** Swap the just-appended assistant entry — used by self-correction to restore the original tool_calls without dropping reasoning_content. */
1994
+ replaceTailAssistantMessage(message) {
1995
+ const entries = this.log.entries;
1996
+ const tail = entries[entries.length - 1];
1997
+ if (!tail || tail.role !== "assistant") return;
1998
+ const kept = entries.slice(0, -1);
1999
+ kept.push(message);
2000
+ this.log.compactInPlace(kept);
2001
+ if (this.sessionName) {
2002
+ try {
2003
+ rewriteSession(this.sessionName, kept);
2004
+ } catch {
2005
+ }
2006
+ }
2007
+ }
1987
2008
  /** "New chat" — drops messages but keeps session + immutable prefix (cache-first invariant). */
1988
2009
  clearLog() {
1989
2010
  const dropped = this.log.length;
@@ -2084,7 +2105,7 @@ var CacheFirstLoop = class {
2084
2105
  if (repair) {
2085
2106
  if (repair.scavenged > 0) bump("scavenged", repair.scavenged);
2086
2107
  if (repair.truncationsFixed > 0) bump("truncated", repair.truncationsFixed);
2087
- if (repair.stormsBroken > 0) bump("storm-broken", repair.stormsBroken);
2108
+ if (repair.stormsBroken > 0) bump("repeat-loop", repair.stormsBroken);
2088
2109
  }
2089
2110
  if (bumped && !this._escalateThisTurn && this.autoEscalate && this._turnFailureCount >= FAILURE_ESCALATION_THRESHOLD) {
2090
2111
  this._escalateThisTurn = true;
@@ -2154,6 +2175,7 @@ var CacheFirstLoop = class {
2154
2175
  this.repair.resetStorm();
2155
2176
  this._turnFailureCount = 0;
2156
2177
  this._turnFailureTypes = {};
2178
+ this._turnSelfCorrected = false;
2157
2179
  this._escalateThisTurn = false;
2158
2180
  let armedConsumed = false;
2159
2181
  if (this._proArmedForNextTurn) {
@@ -2505,10 +2527,35 @@ var CacheFirstLoop = class {
2505
2527
  content: `\u21E7 auto-escalating to ${ESCALATION_MODEL} for the rest of this turn \u2014 flash hit ${this.formatFailureBreakdown()}. Next turn falls back to ${this.model} unless /pro is armed.`
2506
2528
  };
2507
2529
  }
2530
+ const allSuppressed = report.stormsBroken > 0 && repairedCalls.length === 0 && toolCalls.length > 0;
2531
+ if (allSuppressed && !this._turnSelfCorrected) {
2532
+ this._turnSelfCorrected = true;
2533
+ this.replaceTailAssistantMessage(
2534
+ this.assistantMessage(
2535
+ assistantContent,
2536
+ toolCalls,
2537
+ this.modelForCurrentCall(),
2538
+ reasoningContent
2539
+ )
2540
+ );
2541
+ for (const call of toolCalls) {
2542
+ this.appendAndPersist({
2543
+ role: "tool",
2544
+ tool_call_id: call.id ?? "",
2545
+ name: call.function?.name ?? "",
2546
+ content: "[repeat-loop guard] this call was suppressed because it was identical to a previous call in this turn. Earlier results for it are above \u2014 try a meaningfully different approach, or stop and answer if you have enough."
2547
+ });
2548
+ }
2549
+ yield {
2550
+ turn: this._turn,
2551
+ role: "warning",
2552
+ content: "Caught a repeated tool call \u2014 let the model see the issue and retry with a different approach."
2553
+ };
2554
+ continue;
2555
+ }
2508
2556
  if (report.stormsBroken > 0) {
2509
2557
  const noteTail = report.notes.length ? ` \u2014 ${report.notes[report.notes.length - 1]}` : "";
2510
- const allSuppressed = repairedCalls.length === 0 && toolCalls.length > 0;
2511
- const phrase = allSuppressed ? `stopped the model from calling the same tool with identical args repeatedly (all ${toolCalls.length} call(s) this turn were already in the recent-repeat window). Likely a stuck retry \u2014 reword your instruction, rule out the underlying blocker, or try /retry after fixing it` : `suppressed ${report.stormsBroken} repeat tool call(s) that had fired 3+ times with identical args in a sliding window`;
2558
+ const phrase = allSuppressed ? "Stopped a stuck retry loop \u2014 the model kept calling the same tool with identical args after a self-correction nudge. Try /retry, rephrase, or rule out the underlying blocker." : `Suppressed ${report.stormsBroken} repeated tool call(s) \u2014 same name + args fired 3+ times.`;
2512
2559
  yield {
2513
2560
  turn: this._turn,
2514
2561
  role: "warning",
@@ -2516,7 +2563,6 @@ var CacheFirstLoop = class {
2516
2563
  };
2517
2564
  }
2518
2565
  if (repairedCalls.length === 0) {
2519
- const allSuppressed = report.stormsBroken > 0 && toolCalls.length > 0;
2520
2566
  if (allSuppressed) {
2521
2567
  yield* this.forceSummaryAfterIterLimit({ reason: "stuck" });
2522
2568
  return;
@@ -2741,6 +2787,11 @@ function stripHallucinatedToolMarkup(s) {
2741
2787
  out = out.replace(/<|DSML|[\s\S]*$/g, "");
2742
2788
  return out.trim();
2743
2789
  }
2790
+ function parsePositiveIntEnv(raw) {
2791
+ if (!raw) return void 0;
2792
+ const n = Number.parseInt(raw, 10);
2793
+ return Number.isFinite(n) && n > 0 ? n : void 0;
2794
+ }
2744
2795
  function safeParseToolArgs(raw) {
2745
2796
  try {
2746
2797
  return JSON.parse(raw);
@@ -2982,9 +3033,39 @@ function extractDeepSeekErrorMessage(body) {
2982
3033
  }
2983
3034
 
2984
3035
  // src/at-mentions.ts
2985
- import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
3036
+ import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2986
3037
  import { readdir, stat } from "fs/promises";
2987
3038
  import { isAbsolute, join as join4, relative, resolve } from "path";
3039
+
3040
+ // src/gitignore.ts
3041
+ import { readFileSync as readFileSync4 } from "fs";
3042
+ import { readFile } from "fs/promises";
3043
+ import path from "path";
3044
+ import ignore from "ignore";
3045
+ async function loadGitignoreAt(dirAbs) {
3046
+ try {
3047
+ return ignore().add(await readFile(path.join(dirAbs, ".gitignore"), "utf8"));
3048
+ } catch {
3049
+ return null;
3050
+ }
3051
+ }
3052
+ function loadGitignoreAtSync(dirAbs) {
3053
+ try {
3054
+ return ignore().add(readFileSync4(path.join(dirAbs, ".gitignore"), "utf8"));
3055
+ } catch {
3056
+ return null;
3057
+ }
3058
+ }
3059
+ function ignoredByLayers(layers, abs, isDir) {
3060
+ for (const layer of layers) {
3061
+ const rel = path.relative(layer.dirAbs, abs).split(path.sep).join("/");
3062
+ if (!rel || rel.startsWith("..")) continue;
3063
+ if (layer.ig.ignores(isDir ? `${rel}/` : rel)) return true;
3064
+ }
3065
+ return false;
3066
+ }
3067
+
3068
+ // src/at-mentions.ts
2988
3069
  var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
2989
3070
  var DEFAULT_PICKER_IGNORE_DIRS = [
2990
3071
  "node_modules",
@@ -3006,12 +3087,18 @@ function listFilesSync(root, opts = {}) {
3006
3087
  return listFilesWithStatsSync(root, opts).map((e) => e.path);
3007
3088
  }
3008
3089
  function listFilesWithStatsSync(root, opts = {}) {
3009
- const maxResults = Math.max(1, opts.maxResults ?? 500);
3010
- const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3090
+ const maxResults = Math.max(1, opts.maxResults ?? 2e3);
3091
+ const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3011
3092
  const rootAbs = resolve(root);
3093
+ const respectGi = opts.respectGitignore !== false;
3012
3094
  const out = [];
3013
- const walk2 = (dirAbs, dirRel) => {
3095
+ const walk2 = (dirAbs, dirRel, layers) => {
3014
3096
  if (out.length >= maxResults) return;
3097
+ let effectiveLayers = layers;
3098
+ if (respectGi) {
3099
+ const ig = loadGitignoreAtSync(dirAbs);
3100
+ if (ig) effectiveLayers = [...layers, { dirAbs, ig }];
3101
+ }
3015
3102
  let entries;
3016
3103
  try {
3017
3104
  entries = readdirSync2(dirAbs, { withFileTypes: true });
@@ -3022,29 +3109,38 @@ function listFilesWithStatsSync(root, opts = {}) {
3022
3109
  for (const ent of entries) {
3023
3110
  if (out.length >= maxResults) return;
3024
3111
  const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
3112
+ const absPath = join4(dirAbs, ent.name);
3025
3113
  if (ent.isDirectory()) {
3026
- if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
3027
- walk2(join4(dirAbs, ent.name), relPath);
3114
+ if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
3115
+ if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
3116
+ walk2(absPath, relPath, effectiveLayers);
3028
3117
  } else if (ent.isFile()) {
3118
+ if (ignoredByLayers(effectiveLayers, absPath, false)) continue;
3029
3119
  let mtimeMs = 0;
3030
3120
  try {
3031
- mtimeMs = statSync2(join4(dirAbs, ent.name)).mtimeMs;
3121
+ mtimeMs = statSync2(absPath).mtimeMs;
3032
3122
  } catch {
3033
3123
  }
3034
3124
  out.push({ path: relPath, mtimeMs });
3035
3125
  }
3036
3126
  }
3037
3127
  };
3038
- walk2(rootAbs, "");
3128
+ walk2(rootAbs, "", []);
3039
3129
  return out;
3040
3130
  }
3041
3131
  async function listFilesWithStatsAsync(root, opts = {}) {
3042
- const maxResults = Math.max(1, opts.maxResults ?? 500);
3043
- const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3132
+ const maxResults = Math.max(1, opts.maxResults ?? 2e3);
3133
+ const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3044
3134
  const rootAbs = resolve(root);
3135
+ const respectGi = opts.respectGitignore !== false;
3045
3136
  const out = [];
3046
- const walk2 = async (dirAbs, dirRel) => {
3137
+ const walk2 = async (dirAbs, dirRel, layers) => {
3047
3138
  if (out.length >= maxResults) return;
3139
+ let effectiveLayers = layers;
3140
+ if (respectGi) {
3141
+ const ig = await loadGitignoreAt(dirAbs);
3142
+ if (ig) effectiveLayers = [...layers, { dirAbs, ig }];
3143
+ }
3048
3144
  let entries;
3049
3145
  try {
3050
3146
  entries = await readdir(dirAbs, { withFileTypes: true });
@@ -3055,35 +3151,42 @@ async function listFilesWithStatsAsync(root, opts = {}) {
3055
3151
  const fileEnts = [];
3056
3152
  for (const ent of entries) {
3057
3153
  if (out.length >= maxResults) break;
3154
+ const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
3155
+ const absPath = join4(dirAbs, ent.name);
3058
3156
  if (ent.isDirectory()) {
3059
- if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
3157
+ if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
3158
+ if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
3060
3159
  if (fileEnts.length > 0) {
3061
- await statBatch(fileEnts, dirAbs, dirRel, out, maxResults);
3160
+ await statBatch(fileEnts, dirAbs, dirRel, out, maxResults, effectiveLayers);
3062
3161
  fileEnts.length = 0;
3063
3162
  if (out.length >= maxResults) return;
3064
3163
  }
3065
- await walk2(join4(dirAbs, ent.name), dirRel ? `${dirRel}/${ent.name}` : ent.name);
3164
+ await walk2(absPath, relPath, effectiveLayers);
3066
3165
  } else if (ent.isFile()) {
3067
3166
  fileEnts.push(ent);
3068
3167
  }
3069
3168
  }
3070
3169
  if (fileEnts.length > 0 && out.length < maxResults) {
3071
- await statBatch(fileEnts, dirAbs, dirRel, out, maxResults);
3170
+ await statBatch(fileEnts, dirAbs, dirRel, out, maxResults, effectiveLayers);
3072
3171
  }
3073
3172
  };
3074
- await walk2(rootAbs, "");
3173
+ await walk2(rootAbs, "", []);
3075
3174
  return out;
3076
3175
  }
3077
- async function statBatch(ents, dirAbs, dirRel, out, maxResults) {
3078
- const remaining = Math.max(0, maxResults - out.length);
3079
- const batch = ents.slice(0, remaining);
3176
+ async function statBatch(ents, dirAbs, dirRel, out, maxResults, layers) {
3177
+ const accepted = [];
3178
+ for (const e of ents) {
3179
+ if (out.length + accepted.length >= maxResults) break;
3180
+ if (ignoredByLayers(layers, join4(dirAbs, e.name), false)) continue;
3181
+ accepted.push(e);
3182
+ }
3080
3183
  const stats = await Promise.all(
3081
- batch.map(
3184
+ accepted.map(
3082
3185
  (e) => stat(join4(dirAbs, e.name)).then((s) => s.mtimeMs).catch(() => 0)
3083
3186
  )
3084
3187
  );
3085
- for (let i = 0; i < batch.length; i++) {
3086
- const ent = batch[i];
3188
+ for (let i = 0; i < accepted.length; i++) {
3189
+ const ent = accepted[i];
3087
3190
  out.push({
3088
3191
  path: dirRel ? `${dirRel}/${ent.name}` : ent.name,
3089
3192
  mtimeMs: stats[i] ?? 0
@@ -3224,20 +3327,20 @@ var defaultFs = {
3224
3327
  return 0;
3225
3328
  }
3226
3329
  },
3227
- read: (p) => readFileSync4(p, "utf8")
3330
+ read: (p) => readFileSync5(p, "utf8")
3228
3331
  };
3229
3332
 
3230
3333
  // src/memory/project.ts
3231
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3334
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
3232
3335
  import { join as join5 } from "path";
3233
3336
  var PROJECT_MEMORY_FILE = "REASONIX.md";
3234
3337
  var PROJECT_MEMORY_MAX_CHARS = 8e3;
3235
3338
  function readProjectMemory(rootDir) {
3236
- const path = join5(rootDir, PROJECT_MEMORY_FILE);
3237
- if (!existsSync5(path)) return null;
3339
+ const path2 = join5(rootDir, PROJECT_MEMORY_FILE);
3340
+ if (!existsSync5(path2)) return null;
3238
3341
  let raw;
3239
3342
  try {
3240
- raw = readFileSync5(path, "utf8");
3343
+ raw = readFileSync6(path2, "utf8");
3241
3344
  } catch {
3242
3345
  return null;
3243
3346
  }
@@ -3247,7 +3350,7 @@ function readProjectMemory(rootDir) {
3247
3350
  const truncated = originalChars > PROJECT_MEMORY_MAX_CHARS;
3248
3351
  const content = truncated ? `${trimmed.slice(0, PROJECT_MEMORY_MAX_CHARS)}
3249
3352
  \u2026 (truncated ${originalChars - PROJECT_MEMORY_MAX_CHARS} chars)` : trimmed;
3250
- return { path, content, originalChars, truncated };
3353
+ return { path: path2, content, originalChars, truncated };
3251
3354
  }
3252
3355
  function memoryEnabled() {
3253
3356
  const env = process.env.REASONIX_MEMORY;
@@ -3275,7 +3378,7 @@ import { createHash as createHash2 } from "crypto";
3275
3378
  import {
3276
3379
  existsSync as existsSync7,
3277
3380
  mkdirSync as mkdirSync2,
3278
- readFileSync as readFileSync7,
3381
+ readFileSync as readFileSync8,
3279
3382
  readdirSync as readdirSync4,
3280
3383
  unlinkSync as unlinkSync2,
3281
3384
  writeFileSync as writeFileSync2
@@ -3284,7 +3387,7 @@ import { homedir as homedir4 } from "os";
3284
3387
  import { join as join7, resolve as resolve3 } from "path";
3285
3388
 
3286
3389
  // src/skills.ts
3287
- import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3390
+ import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3288
3391
  import { homedir as homedir3 } from "os";
3289
3392
  import { join as join6, resolve as resolve2 } from "path";
3290
3393
 
@@ -3421,10 +3524,10 @@ var SkillStore = class {
3421
3524
  }
3422
3525
  return null;
3423
3526
  }
3424
- parse(path, stem, scope) {
3527
+ parse(path2, stem, scope) {
3425
3528
  let raw;
3426
3529
  try {
3427
- raw = readFileSync6(path, "utf8");
3530
+ raw = readFileSync7(path2, "utf8");
3428
3531
  } catch {
3429
3532
  return null;
3430
3533
  }
@@ -3435,7 +3538,7 @@ var SkillStore = class {
3435
3538
  description: (data.description ?? "").trim(),
3436
3539
  body: body.trim(),
3437
3540
  scope,
3438
- path,
3541
+ path: path2,
3439
3542
  allowedTools: data["allowed-tools"],
3440
3543
  runAs: parseRunAs(data.runAs),
3441
3544
  model: data.model?.startsWith("deepseek-") ? data.model : void 0
@@ -3758,7 +3861,7 @@ var MemoryStore = class {
3758
3861
  if (!existsSync7(file)) return null;
3759
3862
  let raw;
3760
3863
  try {
3761
- raw = readFileSync7(file, "utf8");
3864
+ raw = readFileSync8(file, "utf8");
3762
3865
  } catch {
3763
3866
  return null;
3764
3867
  }
@@ -3776,7 +3879,7 @@ var MemoryStore = class {
3776
3879
  if (!existsSync7(file)) {
3777
3880
  throw new Error(`memory not found: scope=${scope} name=${name}`);
3778
3881
  }
3779
- const raw = readFileSync7(file, "utf8");
3882
+ const raw = readFileSync8(file, "utf8");
3780
3883
  const { data, body } = parseFrontmatter2(raw);
3781
3884
  return {
3782
3885
  name: data.name ?? name,
@@ -3878,11 +3981,11 @@ var MemoryStore = class {
3878
3981
  }
3879
3982
  };
3880
3983
  function readGlobalReasonixMemory(homeDir = join7(homedir4(), ".reasonix")) {
3881
- const path = join7(homeDir, "REASONIX.md");
3882
- if (!existsSync7(path)) return null;
3984
+ const path2 = join7(homeDir, "REASONIX.md");
3985
+ if (!existsSync7(path2)) return null;
3883
3986
  let raw;
3884
3987
  try {
3885
- raw = readFileSync7(path, "utf8");
3988
+ raw = readFileSync8(path2, "utf8");
3886
3989
  } catch {
3887
3990
  return null;
3888
3991
  }
@@ -3892,7 +3995,7 @@ function readGlobalReasonixMemory(homeDir = join7(homedir4(), ".reasonix")) {
3892
3995
  const truncated = originalChars > 8e3;
3893
3996
  const content = truncated ? `${trimmed.slice(0, 8e3)}
3894
3997
  \u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
3895
- return { path, content, originalChars, truncated };
3998
+ return { path: path2, content, originalChars, truncated };
3896
3999
  }
3897
4000
  function applyGlobalReasonixMemory(basePrompt, homeDir) {
3898
4001
  if (!memoryEnabled()) return basePrompt;
@@ -4613,7 +4716,7 @@ function registerMemoryTools(registry, opts = {}) {
4613
4716
  });
4614
4717
  }
4615
4718
  try {
4616
- const path = store.write({
4719
+ const path2 = store.write({
4617
4720
  name: args.name,
4618
4721
  type: args.type,
4619
4722
  scope: args.scope,
@@ -4626,7 +4729,7 @@ function registerMemoryTools(registry, opts = {}) {
4626
4729
  "",
4627
4730
  "TREAT THIS AS ESTABLISHED FACT for the rest of this session.",
4628
4731
  "The user just told you \u2014 don't re-explore the filesystem to re-derive it.",
4629
- `(Saved to ${path}; pins into the system prompt on next /new or launch.)`
4732
+ `(Saved to ${path2}; pins into the system prompt on next /new or launch.)`
4630
4733
  ].join("\n");
4631
4734
  } catch (err) {
4632
4735
  return JSON.stringify({ error: `remember failed: ${err.message}` });
@@ -6355,12 +6458,12 @@ ${i + 1}. ${r.title}`);
6355
6458
  }
6356
6459
 
6357
6460
  // src/env.ts
6358
- import { readFileSync as readFileSync8 } from "fs";
6461
+ import { readFileSync as readFileSync9 } from "fs";
6359
6462
  import { resolve as resolve7 } from "path";
6360
- function loadDotenv(path = ".env") {
6463
+ function loadDotenv(path2 = ".env") {
6361
6464
  let raw;
6362
6465
  try {
6363
- raw = readFileSync8(resolve7(process.cwd(), path), "utf8");
6466
+ raw = readFileSync9(resolve7(process.cwd(), path2), "utf8");
6364
6467
  } catch {
6365
6468
  return;
6366
6469
  }
@@ -6379,7 +6482,7 @@ function loadDotenv(path = ".env") {
6379
6482
  }
6380
6483
 
6381
6484
  // src/transcript/log.ts
6382
- import { createWriteStream, readFileSync as readFileSync9 } from "fs";
6485
+ import { createWriteStream, readFileSync as readFileSync10 } from "fs";
6383
6486
  function recordFromLoopEvent(ev, extra) {
6384
6487
  const rec = {
6385
6488
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6424,13 +6527,13 @@ function writeMeta(stream, meta) {
6424
6527
  stream.write(`${JSON.stringify(line)}
6425
6528
  `);
6426
6529
  }
6427
- function openTranscriptFile(path, meta) {
6428
- const stream = createWriteStream(path, { flags: "a" });
6530
+ function openTranscriptFile(path2, meta) {
6531
+ const stream = createWriteStream(path2, { flags: "a" });
6429
6532
  writeMeta(stream, meta);
6430
6533
  return stream;
6431
6534
  }
6432
- function readTranscript(path) {
6433
- const raw = readFileSync9(path, "utf8");
6535
+ function readTranscript(path2) {
6536
+ const raw = readFileSync10(path2, "utf8");
6434
6537
  return parseTranscript(raw);
6435
6538
  }
6436
6539
  function isPlanStateEmptyShape(s) {
@@ -6461,8 +6564,8 @@ function parseTranscript(raw) {
6461
6564
  }
6462
6565
 
6463
6566
  // src/transcript/replay.ts
6464
- function replayFromFile(path) {
6465
- const parsed = readTranscript(path);
6567
+ function replayFromFile(path2) {
6568
+ const parsed = readTranscript(path2);
6466
6569
  return { parsed, stats: computeReplayStats(parsed.records) };
6467
6570
  }
6468
6571
  function computeReplayStats(records) {
@@ -6877,7 +6980,7 @@ function truncate(s, n) {
6877
6980
  }
6878
6981
 
6879
6982
  // src/version.ts
6880
- import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
6983
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
6881
6984
  import { homedir as homedir5 } from "os";
6882
6985
  import { dirname as dirname4, join as join9 } from "path";
6883
6986
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -6890,7 +6993,7 @@ function readPackageVersion() {
6890
6993
  for (let i = 0; i < 6; i++) {
6891
6994
  const p = join9(dir, "package.json");
6892
6995
  if (existsSync9(p)) {
6893
- const pkg = JSON.parse(readFileSync10(p, "utf8"));
6996
+ const pkg = JSON.parse(readFileSync11(p, "utf8"));
6894
6997
  if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
6895
6998
  return pkg.version;
6896
6999
  }
@@ -6909,7 +7012,7 @@ function cachePath(homeDirOverride) {
6909
7012
  }
6910
7013
  function readCache(homeDirOverride) {
6911
7014
  try {
6912
- const raw = readFileSync10(cachePath(homeDirOverride), "utf8");
7015
+ const raw = readFileSync11(cachePath(homeDirOverride), "utf8");
6913
7016
  const parsed = JSON.parse(raw);
6914
7017
  if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
6915
7018
  return parsed;
@@ -7715,7 +7818,7 @@ async function trySection(load) {
7715
7818
  }
7716
7819
 
7717
7820
  // src/code/edit-blocks.ts
7718
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
7821
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync12, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
7719
7822
  import { dirname as dirname5, resolve as resolve8 } from "path";
7720
7823
  var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
7721
7824
  function parseEditBlocks(text) {
@@ -7758,7 +7861,7 @@ function applyEditBlock(block, rootDir) {
7758
7861
  writeFileSync4(absTarget, block.replace, "utf8");
7759
7862
  return { path: block.path, status: "created" };
7760
7863
  }
7761
- const content = readFileSync11(absTarget, "utf8");
7864
+ const content = readFileSync12(absTarget, "utf8");
7762
7865
  if (searchEmpty) {
7763
7866
  return {
7764
7867
  path: block.path,
@@ -7797,7 +7900,7 @@ function snapshotBeforeEdits(blocks, rootDir) {
7797
7900
  continue;
7798
7901
  }
7799
7902
  try {
7800
- snapshots.push({ path: b.path, prevContent: readFileSync11(abs, "utf8") });
7903
+ snapshots.push({ path: b.path, prevContent: readFileSync12(abs, "utf8") });
7801
7904
  } catch {
7802
7905
  snapshots.push({ path: b.path, prevContent: null });
7803
7906
  }
@@ -7840,7 +7943,7 @@ function sep() {
7840
7943
  }
7841
7944
 
7842
7945
  // src/code/prompt.ts
7843
- import { existsSync as existsSync11, readFileSync as readFileSync12 } from "fs";
7946
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
7844
7947
  import { join as join10 } from "path";
7845
7948
  var CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, list_directory, directory_tree, search_files, search_content, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell.
7846
7949
 
@@ -8048,7 +8151,7 @@ function codeSystemPrompt(rootDir, opts = {}) {
8048
8151
  if (existsSync11(gitignorePath)) {
8049
8152
  let content;
8050
8153
  try {
8051
- content = readFileSync12(gitignorePath, "utf8");
8154
+ content = readFileSync13(gitignorePath, "utf8");
8052
8155
  } catch {
8053
8156
  }
8054
8157
  if (content !== void 0) {
@@ -8079,37 +8182,37 @@ ${appendParts.join("\n\n")}`;
8079
8182
  }
8080
8183
 
8081
8184
  // src/config.ts
8082
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
8185
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
8083
8186
  import { homedir as homedir6 } from "os";
8084
8187
  import { dirname as dirname6, join as join11 } from "path";
8085
8188
  function defaultConfigPath() {
8086
8189
  return join11(homedir6(), ".reasonix", "config.json");
8087
8190
  }
8088
- function readConfig(path = defaultConfigPath()) {
8191
+ function readConfig(path2 = defaultConfigPath()) {
8089
8192
  try {
8090
- const raw = readFileSync13(path, "utf8");
8193
+ const raw = readFileSync14(path2, "utf8");
8091
8194
  const parsed = JSON.parse(raw);
8092
8195
  if (parsed && typeof parsed === "object") return parsed;
8093
8196
  } catch {
8094
8197
  }
8095
8198
  return {};
8096
8199
  }
8097
- function writeConfig(cfg, path = defaultConfigPath()) {
8098
- mkdirSync5(dirname6(path), { recursive: true });
8099
- writeFileSync5(path, JSON.stringify(cfg, null, 2), "utf8");
8200
+ function writeConfig(cfg, path2 = defaultConfigPath()) {
8201
+ mkdirSync5(dirname6(path2), { recursive: true });
8202
+ writeFileSync5(path2, JSON.stringify(cfg, null, 2), "utf8");
8100
8203
  try {
8101
- chmodSync2(path, 384);
8204
+ chmodSync2(path2, 384);
8102
8205
  } catch {
8103
8206
  }
8104
8207
  }
8105
- function loadApiKey(path = defaultConfigPath()) {
8208
+ function loadApiKey(path2 = defaultConfigPath()) {
8106
8209
  if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;
8107
- return readConfig(path).apiKey;
8210
+ return readConfig(path2).apiKey;
8108
8211
  }
8109
- function saveApiKey(key, path = defaultConfigPath()) {
8110
- const cfg = readConfig(path);
8212
+ function saveApiKey(key, path2 = defaultConfigPath()) {
8213
+ const cfg = readConfig(path2);
8111
8214
  cfg.apiKey = key.trim();
8112
- writeConfig(cfg, path);
8215
+ writeConfig(cfg, path2);
8113
8216
  }
8114
8217
  function isPlausibleKey(key) {
8115
8218
  const trimmed = key.trim();
@@ -8126,7 +8229,7 @@ import {
8126
8229
  appendFileSync as appendFileSync2,
8127
8230
  existsSync as existsSync12,
8128
8231
  mkdirSync as mkdirSync6,
8129
- readFileSync as readFileSync14,
8232
+ readFileSync as readFileSync15,
8130
8233
  statSync as statSync5,
8131
8234
  writeFileSync as writeFileSync6
8132
8235
  } from "fs";
@@ -8137,10 +8240,10 @@ function defaultUsageLogPath(homeDirOverride) {
8137
8240
  }
8138
8241
  var USAGE_COMPACTION_THRESHOLD_BYTES = 5 * 1024 * 1024;
8139
8242
  var USAGE_RETENTION_DAYS = 365;
8140
- function compactUsageLogIfLarge(path, now) {
8243
+ function compactUsageLogIfLarge(path2, now) {
8141
8244
  let size;
8142
8245
  try {
8143
- size = statSync5(path).size;
8246
+ size = statSync5(path2).size;
8144
8247
  } catch {
8145
8248
  return;
8146
8249
  }
@@ -8148,7 +8251,7 @@ function compactUsageLogIfLarge(path, now) {
8148
8251
  const cutoff = now - USAGE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
8149
8252
  let raw;
8150
8253
  try {
8151
- raw = readFileSync14(path, "utf8");
8254
+ raw = readFileSync15(path2, "utf8");
8152
8255
  } catch {
8153
8256
  return;
8154
8257
  }
@@ -8164,7 +8267,7 @@ function compactUsageLogIfLarge(path, now) {
8164
8267
  }
8165
8268
  if (kept.length === lines.filter((l) => l.trim()).length) return;
8166
8269
  try {
8167
- writeFileSync6(path, kept.length > 0 ? `${kept.join("\n")}
8270
+ writeFileSync6(path2, kept.length > 0 ? `${kept.join("\n")}
8168
8271
  ` : "", "utf8");
8169
8272
  } catch {
8170
8273
  }
@@ -8183,21 +8286,21 @@ function appendUsage(input) {
8183
8286
  };
8184
8287
  if (input.kind === "subagent") record.kind = "subagent";
8185
8288
  if (input.subagent) record.subagent = input.subagent;
8186
- const path = input.path ?? defaultUsageLogPath();
8289
+ const path2 = input.path ?? defaultUsageLogPath();
8187
8290
  try {
8188
- mkdirSync6(dirname7(path), { recursive: true });
8189
- appendFileSync2(path, `${JSON.stringify(record)}
8291
+ mkdirSync6(dirname7(path2), { recursive: true });
8292
+ appendFileSync2(path2, `${JSON.stringify(record)}
8190
8293
  `, "utf8");
8191
- compactUsageLogIfLarge(path, record.ts);
8294
+ compactUsageLogIfLarge(path2, record.ts);
8192
8295
  } catch {
8193
8296
  }
8194
8297
  return record;
8195
8298
  }
8196
- function readUsageLog(path = defaultUsageLogPath()) {
8197
- if (!existsSync12(path)) return [];
8299
+ function readUsageLog(path2 = defaultUsageLogPath()) {
8300
+ if (!existsSync12(path2)) return [];
8198
8301
  let raw;
8199
8302
  try {
8200
- raw = readFileSync14(path, "utf8");
8303
+ raw = readFileSync15(path2, "utf8");
8201
8304
  } catch {
8202
8305
  return [];
8203
8306
  }
@@ -8303,10 +8406,10 @@ function aggregateUsage(records, opts = {}) {
8303
8406
  subagents
8304
8407
  };
8305
8408
  }
8306
- function formatLogSize(path = defaultUsageLogPath()) {
8307
- if (!existsSync12(path)) return "";
8409
+ function formatLogSize(path2 = defaultUsageLogPath()) {
8410
+ if (!existsSync12(path2)) return "";
8308
8411
  try {
8309
- const s = statSync5(path);
8412
+ const s = statSync5(path2);
8310
8413
  const bytes = s.size;
8311
8414
  if (bytes < 1024) return `${bytes} B`;
8312
8415
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;