reasonix 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
@@ -1065,6 +1065,26 @@ function computeP95(samples) {
1065
1065
  // src/mcp/registry.ts
1066
1066
  var DEFAULT_MAX_RESULT_CHARS = 32e3;
1067
1067
  var DEFAULT_MAX_RESULT_TOKENS = 8e3;
1068
+ function registerSingleMcpTool(mcpTool, env) {
1069
+ if (!mcpTool.name) return "";
1070
+ const registeredName = `${env.prefix}${mcpTool.name}`;
1071
+ env.registry.register({
1072
+ name: registeredName,
1073
+ description: mcpTool.description ?? "",
1074
+ parameters: mcpTool.inputSchema,
1075
+ fn: async (args, ctx) => {
1076
+ const t0 = env.tracker ? Date.now() : 0;
1077
+ const live = env.host.client;
1078
+ const toolResult = await live.callTool(mcpTool.name, args, {
1079
+ onProgress: env.onProgress ? (info) => env.onProgress({ toolName: registeredName, ...info }) : void 0,
1080
+ signal: ctx?.signal
1081
+ });
1082
+ if (env.tracker) env.tracker.record(Date.now() - t0);
1083
+ return flattenMcpResult(toolResult, { maxChars: env.maxResultChars });
1084
+ }
1085
+ });
1086
+ return registeredName;
1087
+ }
1068
1088
  async function bridgeMcpTools(client, opts = {}) {
1069
1089
  const registry = opts.registry ?? new ToolRegistry({ autoFlatten: opts.autoFlatten });
1070
1090
  const prefix = opts.namePrefix ?? "";
@@ -1072,39 +1092,25 @@ async function bridgeMcpTools(client, opts = {}) {
1072
1092
  const result = { registry, registeredNames: [], skipped: [] };
1073
1093
  const serverName = opts.serverName ?? prefix.replace(/_$/, "") ?? "anon";
1074
1094
  const tracker = opts.onSlow ? new LatencyTracker(serverName, { thresholdMs: opts.slowThresholdMs, onSlow: opts.onSlow }) : null;
1095
+ const host = opts.host ?? { client };
1096
+ const env = {
1097
+ registry,
1098
+ host,
1099
+ prefix,
1100
+ maxResultChars,
1101
+ tracker,
1102
+ onProgress: opts.onProgress
1103
+ };
1075
1104
  const listed = await client.listTools();
1076
1105
  for (const mcpTool of listed.tools) {
1077
1106
  if (!mcpTool.name) {
1078
1107
  result.skipped.push({ name: "?", reason: "empty tool name" });
1079
1108
  continue;
1080
1109
  }
1081
- const registeredName = `${prefix}${mcpTool.name}`;
1082
- registry.register({
1083
- name: registeredName,
1084
- description: mcpTool.description ?? "",
1085
- parameters: mcpTool.inputSchema,
1086
- fn: async (args, ctx) => {
1087
- const t0 = tracker ? Date.now() : 0;
1088
- const toolResult = await client.callTool(mcpTool.name, args, {
1089
- // Forward server-side progress frames to the bridge caller,
1090
- // tagged with the registered name so multi-server UIs can
1091
- // disambiguate. No-op when `onProgress` isn't configured —
1092
- // the client then also omits the _meta.progressToken and
1093
- // the server won't emit progress.
1094
- onProgress: opts.onProgress ? (info) => opts.onProgress({ toolName: registeredName, ...info }) : void 0,
1095
- // Thread the tool-dispatch AbortSignal all the way down to
1096
- // the MCP request so Esc truly cancels in flight — the
1097
- // client will emit notifications/cancelled AND reject the
1098
- // pending promise immediately, no "wait for subprocess".
1099
- signal: ctx?.signal
1100
- });
1101
- if (tracker) tracker.record(Date.now() - t0);
1102
- return flattenMcpResult(toolResult, { maxChars: maxResultChars });
1103
- }
1104
- });
1105
- result.registeredNames.push(registeredName);
1110
+ const registeredName = registerSingleMcpTool(mcpTool, env);
1111
+ if (registeredName) result.registeredNames.push(registeredName);
1106
1112
  }
1107
- return result;
1113
+ return { ...result, env };
1108
1114
  }
1109
1115
  function flattenMcpResult(result, opts = {}) {
1110
1116
  const parts = result.content.map(blockToString);
@@ -1305,10 +1311,10 @@ function sanitizeName(name) {
1305
1311
  return cleaned || "default";
1306
1312
  }
1307
1313
  function loadSessionMessages(name) {
1308
- const path = sessionPath(name);
1309
- if (!existsSync3(path)) return [];
1314
+ const path2 = sessionPath(name);
1315
+ if (!existsSync3(path2)) return [];
1310
1316
  try {
1311
- const raw = readFileSync3(path, "utf8");
1317
+ const raw = readFileSync3(path2, "utf8");
1312
1318
  const out = [];
1313
1319
  for (const line of raw.split(/\r?\n/)) {
1314
1320
  const trimmed = line.trim();
@@ -1325,12 +1331,12 @@ function loadSessionMessages(name) {
1325
1331
  }
1326
1332
  }
1327
1333
  function appendSessionMessage(name, message) {
1328
- const path = sessionPath(name);
1329
- mkdirSync(dirname2(path), { recursive: true });
1330
- appendFileSync(path, `${JSON.stringify(message)}
1334
+ const path2 = sessionPath(name);
1335
+ mkdirSync(dirname2(path2), { recursive: true });
1336
+ appendFileSync(path2, `${JSON.stringify(message)}
1331
1337
  `, "utf8");
1332
1338
  try {
1333
- chmodSync(path, 384);
1339
+ chmodSync(path2, 384);
1334
1340
  } catch {
1335
1341
  }
1336
1342
  }
@@ -1342,13 +1348,13 @@ function listSessions() {
1342
1348
  (f) => f.endsWith(".jsonl") && !f.endsWith(".events.jsonl")
1343
1349
  );
1344
1350
  return files.map((file) => {
1345
- const path = join3(dir, file);
1346
- const stat2 = statSync(path);
1351
+ const path2 = join3(dir, file);
1352
+ const stat2 = statSync(path2);
1347
1353
  const name = file.replace(/\.jsonl$/, "");
1348
- const messageCount = countLines(path);
1354
+ const messageCount = countLines(path2);
1349
1355
  return {
1350
1356
  name,
1351
- path,
1357
+ path: path2,
1352
1358
  size: stat2.size,
1353
1359
  messageCount,
1354
1360
  mtime: stat2.mtime,
@@ -1373,11 +1379,11 @@ function loadSessionMeta(name) {
1373
1379
  }
1374
1380
  }
1375
1381
  function deleteSession(name) {
1376
- const path = sessionPath(name);
1382
+ const path2 = sessionPath(name);
1377
1383
  try {
1378
- unlinkSync(path);
1384
+ unlinkSync(path2);
1379
1385
  for (const ext of [".events.jsonl", ".pending.json", ".meta.json", ".plan.json"]) {
1380
- const sidecar = path.replace(/\.jsonl$/, ext);
1386
+ const sidecar = path2.replace(/\.jsonl$/, ext);
1381
1387
  try {
1382
1388
  unlinkSync(sidecar);
1383
1389
  } catch {
@@ -1389,19 +1395,19 @@ function deleteSession(name) {
1389
1395
  }
1390
1396
  }
1391
1397
  function rewriteSession(name, messages) {
1392
- const path = sessionPath(name);
1393
- mkdirSync(dirname2(path), { recursive: true });
1398
+ const path2 = sessionPath(name);
1399
+ mkdirSync(dirname2(path2), { recursive: true });
1394
1400
  const body = messages.map((m) => JSON.stringify(m)).join("\n");
1395
- writeFileSync(path, body ? `${body}
1401
+ writeFileSync(path2, body ? `${body}
1396
1402
  ` : "", "utf8");
1397
1403
  try {
1398
- chmodSync(path, 384);
1404
+ chmodSync(path2, 384);
1399
1405
  } catch {
1400
1406
  }
1401
1407
  }
1402
- function countLines(path) {
1408
+ function countLines(path2) {
1403
1409
  try {
1404
- const raw = readFileSync3(path, "utf8");
1410
+ const raw = readFileSync3(path2, "utf8");
1405
1411
  return raw.split(/\r?\n/).filter((l) => l.trim()).length;
1406
1412
  } catch {
1407
1413
  return 0;
@@ -2976,9 +2982,39 @@ function extractDeepSeekErrorMessage(body) {
2976
2982
  }
2977
2983
 
2978
2984
  // src/at-mentions.ts
2979
- import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2985
+ import { existsSync as existsSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2980
2986
  import { readdir, stat } from "fs/promises";
2981
2987
  import { isAbsolute, join as join4, relative, resolve } from "path";
2988
+
2989
+ // src/gitignore.ts
2990
+ import { readFileSync as readFileSync4 } from "fs";
2991
+ import { readFile } from "fs/promises";
2992
+ import path from "path";
2993
+ import ignore from "ignore";
2994
+ async function loadGitignoreAt(dirAbs) {
2995
+ try {
2996
+ return ignore().add(await readFile(path.join(dirAbs, ".gitignore"), "utf8"));
2997
+ } catch {
2998
+ return null;
2999
+ }
3000
+ }
3001
+ function loadGitignoreAtSync(dirAbs) {
3002
+ try {
3003
+ return ignore().add(readFileSync4(path.join(dirAbs, ".gitignore"), "utf8"));
3004
+ } catch {
3005
+ return null;
3006
+ }
3007
+ }
3008
+ function ignoredByLayers(layers, abs, isDir) {
3009
+ for (const layer of layers) {
3010
+ const rel = path.relative(layer.dirAbs, abs).split(path.sep).join("/");
3011
+ if (!rel || rel.startsWith("..")) continue;
3012
+ if (layer.ig.ignores(isDir ? `${rel}/` : rel)) return true;
3013
+ }
3014
+ return false;
3015
+ }
3016
+
3017
+ // src/at-mentions.ts
2982
3018
  var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
2983
3019
  var DEFAULT_PICKER_IGNORE_DIRS = [
2984
3020
  "node_modules",
@@ -3000,12 +3036,18 @@ function listFilesSync(root, opts = {}) {
3000
3036
  return listFilesWithStatsSync(root, opts).map((e) => e.path);
3001
3037
  }
3002
3038
  function listFilesWithStatsSync(root, opts = {}) {
3003
- const maxResults = Math.max(1, opts.maxResults ?? 500);
3004
- const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3039
+ const maxResults = Math.max(1, opts.maxResults ?? 2e3);
3040
+ const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3005
3041
  const rootAbs = resolve(root);
3042
+ const respectGi = opts.respectGitignore !== false;
3006
3043
  const out = [];
3007
- const walk2 = (dirAbs, dirRel) => {
3044
+ const walk2 = (dirAbs, dirRel, layers) => {
3008
3045
  if (out.length >= maxResults) return;
3046
+ let effectiveLayers = layers;
3047
+ if (respectGi) {
3048
+ const ig = loadGitignoreAtSync(dirAbs);
3049
+ if (ig) effectiveLayers = [...layers, { dirAbs, ig }];
3050
+ }
3009
3051
  let entries;
3010
3052
  try {
3011
3053
  entries = readdirSync2(dirAbs, { withFileTypes: true });
@@ -3016,29 +3058,38 @@ function listFilesWithStatsSync(root, opts = {}) {
3016
3058
  for (const ent of entries) {
3017
3059
  if (out.length >= maxResults) return;
3018
3060
  const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
3061
+ const absPath = join4(dirAbs, ent.name);
3019
3062
  if (ent.isDirectory()) {
3020
- if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
3021
- walk2(join4(dirAbs, ent.name), relPath);
3063
+ if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
3064
+ if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
3065
+ walk2(absPath, relPath, effectiveLayers);
3022
3066
  } else if (ent.isFile()) {
3067
+ if (ignoredByLayers(effectiveLayers, absPath, false)) continue;
3023
3068
  let mtimeMs = 0;
3024
3069
  try {
3025
- mtimeMs = statSync2(join4(dirAbs, ent.name)).mtimeMs;
3070
+ mtimeMs = statSync2(absPath).mtimeMs;
3026
3071
  } catch {
3027
3072
  }
3028
3073
  out.push({ path: relPath, mtimeMs });
3029
3074
  }
3030
3075
  }
3031
3076
  };
3032
- walk2(rootAbs, "");
3077
+ walk2(rootAbs, "", []);
3033
3078
  return out;
3034
3079
  }
3035
3080
  async function listFilesWithStatsAsync(root, opts = {}) {
3036
- const maxResults = Math.max(1, opts.maxResults ?? 500);
3037
- const ignore = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3081
+ const maxResults = Math.max(1, opts.maxResults ?? 2e3);
3082
+ const ignoreDirs = new Set(opts.ignoreDirs ?? DEFAULT_PICKER_IGNORE_DIRS);
3038
3083
  const rootAbs = resolve(root);
3084
+ const respectGi = opts.respectGitignore !== false;
3039
3085
  const out = [];
3040
- const walk2 = async (dirAbs, dirRel) => {
3086
+ const walk2 = async (dirAbs, dirRel, layers) => {
3041
3087
  if (out.length >= maxResults) return;
3088
+ let effectiveLayers = layers;
3089
+ if (respectGi) {
3090
+ const ig = await loadGitignoreAt(dirAbs);
3091
+ if (ig) effectiveLayers = [...layers, { dirAbs, ig }];
3092
+ }
3042
3093
  let entries;
3043
3094
  try {
3044
3095
  entries = await readdir(dirAbs, { withFileTypes: true });
@@ -3049,35 +3100,42 @@ async function listFilesWithStatsAsync(root, opts = {}) {
3049
3100
  const fileEnts = [];
3050
3101
  for (const ent of entries) {
3051
3102
  if (out.length >= maxResults) break;
3103
+ const relPath = dirRel ? `${dirRel}/${ent.name}` : ent.name;
3104
+ const absPath = join4(dirAbs, ent.name);
3052
3105
  if (ent.isDirectory()) {
3053
- if (ent.name.startsWith(".") || ignore.has(ent.name)) continue;
3106
+ if (ent.name.startsWith(".") || ignoreDirs.has(ent.name)) continue;
3107
+ if (ignoredByLayers(effectiveLayers, absPath, true)) continue;
3054
3108
  if (fileEnts.length > 0) {
3055
- await statBatch(fileEnts, dirAbs, dirRel, out, maxResults);
3109
+ await statBatch(fileEnts, dirAbs, dirRel, out, maxResults, effectiveLayers);
3056
3110
  fileEnts.length = 0;
3057
3111
  if (out.length >= maxResults) return;
3058
3112
  }
3059
- await walk2(join4(dirAbs, ent.name), dirRel ? `${dirRel}/${ent.name}` : ent.name);
3113
+ await walk2(absPath, relPath, effectiveLayers);
3060
3114
  } else if (ent.isFile()) {
3061
3115
  fileEnts.push(ent);
3062
3116
  }
3063
3117
  }
3064
3118
  if (fileEnts.length > 0 && out.length < maxResults) {
3065
- await statBatch(fileEnts, dirAbs, dirRel, out, maxResults);
3119
+ await statBatch(fileEnts, dirAbs, dirRel, out, maxResults, effectiveLayers);
3066
3120
  }
3067
3121
  };
3068
- await walk2(rootAbs, "");
3122
+ await walk2(rootAbs, "", []);
3069
3123
  return out;
3070
3124
  }
3071
- async function statBatch(ents, dirAbs, dirRel, out, maxResults) {
3072
- const remaining = Math.max(0, maxResults - out.length);
3073
- const batch = ents.slice(0, remaining);
3125
+ async function statBatch(ents, dirAbs, dirRel, out, maxResults, layers) {
3126
+ const accepted = [];
3127
+ for (const e of ents) {
3128
+ if (out.length + accepted.length >= maxResults) break;
3129
+ if (ignoredByLayers(layers, join4(dirAbs, e.name), false)) continue;
3130
+ accepted.push(e);
3131
+ }
3074
3132
  const stats = await Promise.all(
3075
- batch.map(
3133
+ accepted.map(
3076
3134
  (e) => stat(join4(dirAbs, e.name)).then((s) => s.mtimeMs).catch(() => 0)
3077
3135
  )
3078
3136
  );
3079
- for (let i = 0; i < batch.length; i++) {
3080
- const ent = batch[i];
3137
+ for (let i = 0; i < accepted.length; i++) {
3138
+ const ent = accepted[i];
3081
3139
  out.push({
3082
3140
  path: dirRel ? `${dirRel}/${ent.name}` : ent.name,
3083
3141
  mtimeMs: stats[i] ?? 0
@@ -3218,20 +3276,20 @@ var defaultFs = {
3218
3276
  return 0;
3219
3277
  }
3220
3278
  },
3221
- read: (p) => readFileSync4(p, "utf8")
3279
+ read: (p) => readFileSync5(p, "utf8")
3222
3280
  };
3223
3281
 
3224
3282
  // src/memory/project.ts
3225
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3283
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
3226
3284
  import { join as join5 } from "path";
3227
3285
  var PROJECT_MEMORY_FILE = "REASONIX.md";
3228
3286
  var PROJECT_MEMORY_MAX_CHARS = 8e3;
3229
3287
  function readProjectMemory(rootDir) {
3230
- const path = join5(rootDir, PROJECT_MEMORY_FILE);
3231
- if (!existsSync5(path)) return null;
3288
+ const path2 = join5(rootDir, PROJECT_MEMORY_FILE);
3289
+ if (!existsSync5(path2)) return null;
3232
3290
  let raw;
3233
3291
  try {
3234
- raw = readFileSync5(path, "utf8");
3292
+ raw = readFileSync6(path2, "utf8");
3235
3293
  } catch {
3236
3294
  return null;
3237
3295
  }
@@ -3241,7 +3299,7 @@ function readProjectMemory(rootDir) {
3241
3299
  const truncated = originalChars > PROJECT_MEMORY_MAX_CHARS;
3242
3300
  const content = truncated ? `${trimmed.slice(0, PROJECT_MEMORY_MAX_CHARS)}
3243
3301
  \u2026 (truncated ${originalChars - PROJECT_MEMORY_MAX_CHARS} chars)` : trimmed;
3244
- return { path, content, originalChars, truncated };
3302
+ return { path: path2, content, originalChars, truncated };
3245
3303
  }
3246
3304
  function memoryEnabled() {
3247
3305
  const env = process.env.REASONIX_MEMORY;
@@ -3269,7 +3327,7 @@ import { createHash as createHash2 } from "crypto";
3269
3327
  import {
3270
3328
  existsSync as existsSync7,
3271
3329
  mkdirSync as mkdirSync2,
3272
- readFileSync as readFileSync7,
3330
+ readFileSync as readFileSync8,
3273
3331
  readdirSync as readdirSync4,
3274
3332
  unlinkSync as unlinkSync2,
3275
3333
  writeFileSync as writeFileSync2
@@ -3278,7 +3336,7 @@ import { homedir as homedir4 } from "os";
3278
3336
  import { join as join7, resolve as resolve3 } from "path";
3279
3337
 
3280
3338
  // src/skills.ts
3281
- import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3339
+ import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3282
3340
  import { homedir as homedir3 } from "os";
3283
3341
  import { join as join6, resolve as resolve2 } from "path";
3284
3342
 
@@ -3415,10 +3473,10 @@ var SkillStore = class {
3415
3473
  }
3416
3474
  return null;
3417
3475
  }
3418
- parse(path, stem, scope) {
3476
+ parse(path2, stem, scope) {
3419
3477
  let raw;
3420
3478
  try {
3421
- raw = readFileSync6(path, "utf8");
3479
+ raw = readFileSync7(path2, "utf8");
3422
3480
  } catch {
3423
3481
  return null;
3424
3482
  }
@@ -3429,7 +3487,7 @@ var SkillStore = class {
3429
3487
  description: (data.description ?? "").trim(),
3430
3488
  body: body.trim(),
3431
3489
  scope,
3432
- path,
3490
+ path: path2,
3433
3491
  allowedTools: data["allowed-tools"],
3434
3492
  runAs: parseRunAs(data.runAs),
3435
3493
  model: data.model?.startsWith("deepseek-") ? data.model : void 0
@@ -3752,7 +3810,7 @@ var MemoryStore = class {
3752
3810
  if (!existsSync7(file)) return null;
3753
3811
  let raw;
3754
3812
  try {
3755
- raw = readFileSync7(file, "utf8");
3813
+ raw = readFileSync8(file, "utf8");
3756
3814
  } catch {
3757
3815
  return null;
3758
3816
  }
@@ -3770,7 +3828,7 @@ var MemoryStore = class {
3770
3828
  if (!existsSync7(file)) {
3771
3829
  throw new Error(`memory not found: scope=${scope} name=${name}`);
3772
3830
  }
3773
- const raw = readFileSync7(file, "utf8");
3831
+ const raw = readFileSync8(file, "utf8");
3774
3832
  const { data, body } = parseFrontmatter2(raw);
3775
3833
  return {
3776
3834
  name: data.name ?? name,
@@ -3872,11 +3930,11 @@ var MemoryStore = class {
3872
3930
  }
3873
3931
  };
3874
3932
  function readGlobalReasonixMemory(homeDir = join7(homedir4(), ".reasonix")) {
3875
- const path = join7(homeDir, "REASONIX.md");
3876
- if (!existsSync7(path)) return null;
3933
+ const path2 = join7(homeDir, "REASONIX.md");
3934
+ if (!existsSync7(path2)) return null;
3877
3935
  let raw;
3878
3936
  try {
3879
- raw = readFileSync7(path, "utf8");
3937
+ raw = readFileSync8(path2, "utf8");
3880
3938
  } catch {
3881
3939
  return null;
3882
3940
  }
@@ -3886,7 +3944,7 @@ function readGlobalReasonixMemory(homeDir = join7(homedir4(), ".reasonix")) {
3886
3944
  const truncated = originalChars > 8e3;
3887
3945
  const content = truncated ? `${trimmed.slice(0, 8e3)}
3888
3946
  \u2026 (truncated ${originalChars - 8e3} chars)` : trimmed;
3889
- return { path, content, originalChars, truncated };
3947
+ return { path: path2, content, originalChars, truncated };
3890
3948
  }
3891
3949
  function applyGlobalReasonixMemory(basePrompt, homeDir) {
3892
3950
  if (!memoryEnabled()) return basePrompt;
@@ -4607,7 +4665,7 @@ function registerMemoryTools(registry, opts = {}) {
4607
4665
  });
4608
4666
  }
4609
4667
  try {
4610
- const path = store.write({
4668
+ const path2 = store.write({
4611
4669
  name: args.name,
4612
4670
  type: args.type,
4613
4671
  scope: args.scope,
@@ -4620,7 +4678,7 @@ function registerMemoryTools(registry, opts = {}) {
4620
4678
  "",
4621
4679
  "TREAT THIS AS ESTABLISHED FACT for the rest of this session.",
4622
4680
  "The user just told you \u2014 don't re-explore the filesystem to re-derive it.",
4623
- `(Saved to ${path}; pins into the system prompt on next /new or launch.)`
4681
+ `(Saved to ${path2}; pins into the system prompt on next /new or launch.)`
4624
4682
  ].join("\n");
4625
4683
  } catch (err) {
4626
4684
  return JSON.stringify({ error: `remember failed: ${err.message}` });
@@ -6349,12 +6407,12 @@ ${i + 1}. ${r.title}`);
6349
6407
  }
6350
6408
 
6351
6409
  // src/env.ts
6352
- import { readFileSync as readFileSync8 } from "fs";
6410
+ import { readFileSync as readFileSync9 } from "fs";
6353
6411
  import { resolve as resolve7 } from "path";
6354
- function loadDotenv(path = ".env") {
6412
+ function loadDotenv(path2 = ".env") {
6355
6413
  let raw;
6356
6414
  try {
6357
- raw = readFileSync8(resolve7(process.cwd(), path), "utf8");
6415
+ raw = readFileSync9(resolve7(process.cwd(), path2), "utf8");
6358
6416
  } catch {
6359
6417
  return;
6360
6418
  }
@@ -6373,7 +6431,7 @@ function loadDotenv(path = ".env") {
6373
6431
  }
6374
6432
 
6375
6433
  // src/transcript/log.ts
6376
- import { createWriteStream, readFileSync as readFileSync9 } from "fs";
6434
+ import { createWriteStream, readFileSync as readFileSync10 } from "fs";
6377
6435
  function recordFromLoopEvent(ev, extra) {
6378
6436
  const rec = {
6379
6437
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6418,13 +6476,13 @@ function writeMeta(stream, meta) {
6418
6476
  stream.write(`${JSON.stringify(line)}
6419
6477
  `);
6420
6478
  }
6421
- function openTranscriptFile(path, meta) {
6422
- const stream = createWriteStream(path, { flags: "a" });
6479
+ function openTranscriptFile(path2, meta) {
6480
+ const stream = createWriteStream(path2, { flags: "a" });
6423
6481
  writeMeta(stream, meta);
6424
6482
  return stream;
6425
6483
  }
6426
- function readTranscript(path) {
6427
- const raw = readFileSync9(path, "utf8");
6484
+ function readTranscript(path2) {
6485
+ const raw = readFileSync10(path2, "utf8");
6428
6486
  return parseTranscript(raw);
6429
6487
  }
6430
6488
  function isPlanStateEmptyShape(s) {
@@ -6455,8 +6513,8 @@ function parseTranscript(raw) {
6455
6513
  }
6456
6514
 
6457
6515
  // src/transcript/replay.ts
6458
- function replayFromFile(path) {
6459
- const parsed = readTranscript(path);
6516
+ function replayFromFile(path2) {
6517
+ const parsed = readTranscript(path2);
6460
6518
  return { parsed, stats: computeReplayStats(parsed.records) };
6461
6519
  }
6462
6520
  function computeReplayStats(records) {
@@ -6871,7 +6929,7 @@ function truncate(s, n) {
6871
6929
  }
6872
6930
 
6873
6931
  // src/version.ts
6874
- import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
6932
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
6875
6933
  import { homedir as homedir5 } from "os";
6876
6934
  import { dirname as dirname4, join as join9 } from "path";
6877
6935
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -6884,7 +6942,7 @@ function readPackageVersion() {
6884
6942
  for (let i = 0; i < 6; i++) {
6885
6943
  const p = join9(dir, "package.json");
6886
6944
  if (existsSync9(p)) {
6887
- const pkg = JSON.parse(readFileSync10(p, "utf8"));
6945
+ const pkg = JSON.parse(readFileSync11(p, "utf8"));
6888
6946
  if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
6889
6947
  return pkg.version;
6890
6948
  }
@@ -6903,7 +6961,7 @@ function cachePath(homeDirOverride) {
6903
6961
  }
6904
6962
  function readCache(homeDirOverride) {
6905
6963
  try {
6906
- const raw = readFileSync10(cachePath(homeDirOverride), "utf8");
6964
+ const raw = readFileSync11(cachePath(homeDirOverride), "utf8");
6907
6965
  const parsed = JSON.parse(raw);
6908
6966
  if (parsed && typeof parsed.version === "string" && typeof parsed.checkedAt === "number") {
6909
6967
  return parsed;
@@ -7709,7 +7767,7 @@ async function trySection(load) {
7709
7767
  }
7710
7768
 
7711
7769
  // src/code/edit-blocks.ts
7712
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
7770
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync12, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
7713
7771
  import { dirname as dirname5, resolve as resolve8 } from "path";
7714
7772
  var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
7715
7773
  function parseEditBlocks(text) {
@@ -7752,7 +7810,7 @@ function applyEditBlock(block, rootDir) {
7752
7810
  writeFileSync4(absTarget, block.replace, "utf8");
7753
7811
  return { path: block.path, status: "created" };
7754
7812
  }
7755
- const content = readFileSync11(absTarget, "utf8");
7813
+ const content = readFileSync12(absTarget, "utf8");
7756
7814
  if (searchEmpty) {
7757
7815
  return {
7758
7816
  path: block.path,
@@ -7791,7 +7849,7 @@ function snapshotBeforeEdits(blocks, rootDir) {
7791
7849
  continue;
7792
7850
  }
7793
7851
  try {
7794
- snapshots.push({ path: b.path, prevContent: readFileSync11(abs, "utf8") });
7852
+ snapshots.push({ path: b.path, prevContent: readFileSync12(abs, "utf8") });
7795
7853
  } catch {
7796
7854
  snapshots.push({ path: b.path, prevContent: null });
7797
7855
  }
@@ -7834,7 +7892,7 @@ function sep() {
7834
7892
  }
7835
7893
 
7836
7894
  // src/code/prompt.ts
7837
- import { existsSync as existsSync11, readFileSync as readFileSync12 } from "fs";
7895
+ import { existsSync as existsSync11, readFileSync as readFileSync13 } from "fs";
7838
7896
  import { join as join10 } from "path";
7839
7897
  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.
7840
7898
 
@@ -8042,7 +8100,7 @@ function codeSystemPrompt(rootDir, opts = {}) {
8042
8100
  if (existsSync11(gitignorePath)) {
8043
8101
  let content;
8044
8102
  try {
8045
- content = readFileSync12(gitignorePath, "utf8");
8103
+ content = readFileSync13(gitignorePath, "utf8");
8046
8104
  } catch {
8047
8105
  }
8048
8106
  if (content !== void 0) {
@@ -8073,37 +8131,37 @@ ${appendParts.join("\n\n")}`;
8073
8131
  }
8074
8132
 
8075
8133
  // src/config.ts
8076
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
8134
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync14, writeFileSync as writeFileSync5 } from "fs";
8077
8135
  import { homedir as homedir6 } from "os";
8078
8136
  import { dirname as dirname6, join as join11 } from "path";
8079
8137
  function defaultConfigPath() {
8080
8138
  return join11(homedir6(), ".reasonix", "config.json");
8081
8139
  }
8082
- function readConfig(path = defaultConfigPath()) {
8140
+ function readConfig(path2 = defaultConfigPath()) {
8083
8141
  try {
8084
- const raw = readFileSync13(path, "utf8");
8142
+ const raw = readFileSync14(path2, "utf8");
8085
8143
  const parsed = JSON.parse(raw);
8086
8144
  if (parsed && typeof parsed === "object") return parsed;
8087
8145
  } catch {
8088
8146
  }
8089
8147
  return {};
8090
8148
  }
8091
- function writeConfig(cfg, path = defaultConfigPath()) {
8092
- mkdirSync5(dirname6(path), { recursive: true });
8093
- writeFileSync5(path, JSON.stringify(cfg, null, 2), "utf8");
8149
+ function writeConfig(cfg, path2 = defaultConfigPath()) {
8150
+ mkdirSync5(dirname6(path2), { recursive: true });
8151
+ writeFileSync5(path2, JSON.stringify(cfg, null, 2), "utf8");
8094
8152
  try {
8095
- chmodSync2(path, 384);
8153
+ chmodSync2(path2, 384);
8096
8154
  } catch {
8097
8155
  }
8098
8156
  }
8099
- function loadApiKey(path = defaultConfigPath()) {
8157
+ function loadApiKey(path2 = defaultConfigPath()) {
8100
8158
  if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;
8101
- return readConfig(path).apiKey;
8159
+ return readConfig(path2).apiKey;
8102
8160
  }
8103
- function saveApiKey(key, path = defaultConfigPath()) {
8104
- const cfg = readConfig(path);
8161
+ function saveApiKey(key, path2 = defaultConfigPath()) {
8162
+ const cfg = readConfig(path2);
8105
8163
  cfg.apiKey = key.trim();
8106
- writeConfig(cfg, path);
8164
+ writeConfig(cfg, path2);
8107
8165
  }
8108
8166
  function isPlausibleKey(key) {
8109
8167
  const trimmed = key.trim();
@@ -8120,7 +8178,7 @@ import {
8120
8178
  appendFileSync as appendFileSync2,
8121
8179
  existsSync as existsSync12,
8122
8180
  mkdirSync as mkdirSync6,
8123
- readFileSync as readFileSync14,
8181
+ readFileSync as readFileSync15,
8124
8182
  statSync as statSync5,
8125
8183
  writeFileSync as writeFileSync6
8126
8184
  } from "fs";
@@ -8131,10 +8189,10 @@ function defaultUsageLogPath(homeDirOverride) {
8131
8189
  }
8132
8190
  var USAGE_COMPACTION_THRESHOLD_BYTES = 5 * 1024 * 1024;
8133
8191
  var USAGE_RETENTION_DAYS = 365;
8134
- function compactUsageLogIfLarge(path, now) {
8192
+ function compactUsageLogIfLarge(path2, now) {
8135
8193
  let size;
8136
8194
  try {
8137
- size = statSync5(path).size;
8195
+ size = statSync5(path2).size;
8138
8196
  } catch {
8139
8197
  return;
8140
8198
  }
@@ -8142,7 +8200,7 @@ function compactUsageLogIfLarge(path, now) {
8142
8200
  const cutoff = now - USAGE_RETENTION_DAYS * 24 * 60 * 60 * 1e3;
8143
8201
  let raw;
8144
8202
  try {
8145
- raw = readFileSync14(path, "utf8");
8203
+ raw = readFileSync15(path2, "utf8");
8146
8204
  } catch {
8147
8205
  return;
8148
8206
  }
@@ -8158,7 +8216,7 @@ function compactUsageLogIfLarge(path, now) {
8158
8216
  }
8159
8217
  if (kept.length === lines.filter((l) => l.trim()).length) return;
8160
8218
  try {
8161
- writeFileSync6(path, kept.length > 0 ? `${kept.join("\n")}
8219
+ writeFileSync6(path2, kept.length > 0 ? `${kept.join("\n")}
8162
8220
  ` : "", "utf8");
8163
8221
  } catch {
8164
8222
  }
@@ -8177,21 +8235,21 @@ function appendUsage(input) {
8177
8235
  };
8178
8236
  if (input.kind === "subagent") record.kind = "subagent";
8179
8237
  if (input.subagent) record.subagent = input.subagent;
8180
- const path = input.path ?? defaultUsageLogPath();
8238
+ const path2 = input.path ?? defaultUsageLogPath();
8181
8239
  try {
8182
- mkdirSync6(dirname7(path), { recursive: true });
8183
- appendFileSync2(path, `${JSON.stringify(record)}
8240
+ mkdirSync6(dirname7(path2), { recursive: true });
8241
+ appendFileSync2(path2, `${JSON.stringify(record)}
8184
8242
  `, "utf8");
8185
- compactUsageLogIfLarge(path, record.ts);
8243
+ compactUsageLogIfLarge(path2, record.ts);
8186
8244
  } catch {
8187
8245
  }
8188
8246
  return record;
8189
8247
  }
8190
- function readUsageLog(path = defaultUsageLogPath()) {
8191
- if (!existsSync12(path)) return [];
8248
+ function readUsageLog(path2 = defaultUsageLogPath()) {
8249
+ if (!existsSync12(path2)) return [];
8192
8250
  let raw;
8193
8251
  try {
8194
- raw = readFileSync14(path, "utf8");
8252
+ raw = readFileSync15(path2, "utf8");
8195
8253
  } catch {
8196
8254
  return [];
8197
8255
  }
@@ -8297,10 +8355,10 @@ function aggregateUsage(records, opts = {}) {
8297
8355
  subagents
8298
8356
  };
8299
8357
  }
8300
- function formatLogSize(path = defaultUsageLogPath()) {
8301
- if (!existsSync12(path)) return "";
8358
+ function formatLogSize(path2 = defaultUsageLogPath()) {
8359
+ if (!existsSync12(path2)) return "";
8302
8360
  try {
8303
- const s = statSync5(path);
8361
+ const s = statSync5(path2);
8304
8362
  const bytes = s.size;
8305
8363
  if (bytes < 1024) return `${bytes} B`;
8306
8364
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;